Clone of chromium aad1ce808763f59c7a3753e08f1500a104ecc6fd refs/remotes/origin/HEAD
diff --git a/mojo/public/BUILD.gn b/mojo/public/BUILD.gn
new file mode 100644
index 0000000..1874a6c
--- /dev/null
+++ b/mojo/public/BUILD.gn
@@ -0,0 +1,47 @@
+# Copyright 2014 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.
+
+group("public") {
+  # Meta-target, don't link into production code.
+  testonly = true
+  deps = [
+    ":libmojo_sdk",
+    ":sdk",
+    "//mojo/public/cpp/application:standalone",
+    "//mojo/public/cpp/bindings",
+    "//mojo/public/cpp/environment:standalone",
+    "//mojo/public/cpp/utility",
+    "//mojo/public/interfaces/bindings/tests:test_interfaces",
+  ]
+
+  if (is_linux) {
+    deps += [
+      "//mojo/public/python",
+    ]
+  }
+
+  if (is_android) {
+    deps += [
+      "//mojo/public/java:system",
+      "//mojo/public/java:bindings",
+    ]
+  }
+}
+
+group("sdk") {
+  deps = [
+    "//mojo/public/c/system",
+    "//mojo/public/cpp/application:standalone",
+    "//mojo/public/cpp/bindings",
+    "//mojo/public/cpp/environment:standalone",
+    "//mojo/public/cpp/utility",
+    "//mojo/public/interfaces/application",
+    "//mojo/public/js/bindings",
+  ]
+}
+
+static_library("libmojo_sdk") {
+  complete_static_lib = true
+  deps = [ ":sdk" ]
+}
diff --git a/mojo/public/DEPS b/mojo/public/DEPS
new file mode 100644
index 0000000..0c679b9
--- /dev/null
+++ b/mojo/public/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+  "-base",
+  "-build",
+  "-mojo",
+  "+mojo/public",
+]
diff --git a/mojo/public/README.md b/mojo/public/README.md
new file mode 100644
index 0000000..a31a8a8
--- /dev/null
+++ b/mojo/public/README.md
@@ -0,0 +1,43 @@
+Mojo Public API
+===============
+
+The Mojo Public API is a binary stable API to the Mojo system.
+
+It consists of support for a number of programming languages (with a directory
+for each support language), some "build" tools and build-time requirements, and
+interface definitions for Mojo services (specified using an IDL).
+
+Note that there are various subdirectories named tests/. These contain tests of
+the code in the enclosing directory, and are not meant for use by Mojo
+applications.
+
+C/CPP/JS
+--------
+
+The c/, cpp/, js/ subdirectories define the API for C, C++, and JavaScript,
+respectively.
+
+The basic principle for these directories is that they consist of the source
+files that one needs at build/deployment/run time (as appropriate for the
+language), organized in a natural way for the particular language.
+
+Interfaces
+----------
+
+The interfaces/ subdirectory contains Mojo IDL (a.k.a. .mojom) descriptions of
+standard Mojo services.
+
+Platform
+--------
+
+The platform/ subdirectory contains any build-time requirements (e.g., static
+libraries) that may be needed to produce a Mojo application for certain
+platforms, such as a native shared library or as a NaCl binary.
+
+Tools
+-----
+
+The tools/ subdirectory contains tools that are useful/necessary at
+build/deployment time. These tools may be needed (as a practical necessity) to
+use the API in any given language, e.g., to generate bindings from Mojo IDL
+files.
diff --git a/mojo/public/c/DEPS b/mojo/public/c/DEPS
new file mode 100644
index 0000000..5272770
--- /dev/null
+++ b/mojo/public/c/DEPS
@@ -0,0 +1,16 @@
+include_rules = [
+  # Require explicit dependencies in each directory.
+  "-mojo/public",
+  # But everyone can depend on the C system headers.
+  "+mojo/public/c/system",
+]
+
+specific_include_rules = {
+  r".*_(unit|perf)test\.cc": [
+    "+testing",
+    # Our test harness is C++, so allow the use of C++:
+    "+mojo/public/cpp/system",
+    "+mojo/public/cpp/test_support",
+    "+mojo/public/cpp/utility",
+  ],
+}
diff --git a/mojo/public/c/PRESUBMIT.py b/mojo/public/c/PRESUBMIT.py
new file mode 100644
index 0000000..4cba433
--- /dev/null
+++ b/mojo/public/c/PRESUBMIT.py
@@ -0,0 +1,16 @@
+# Copyright 2014 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.
+
+"""Presubmit script for mojo/public/c.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def CheckChangeOnUpload(input_api, output_api):
+  results = []
+  results += input_api.canned_checks.CheckChangeHasOnlyOneEol(input_api,
+                                                              output_api)
+  results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
+  return results
diff --git a/mojo/public/c/README.md b/mojo/public/c/README.md
new file mode 100644
index 0000000..8e11545
--- /dev/null
+++ b/mojo/public/c/README.md
@@ -0,0 +1,45 @@
+Mojo Public C API
+=================
+
+This directory contains C language bindings for the Mojo Public API.
+
+Environment
+-----------
+
+The environment/ subdirectory defines some common things that, while not part of
+the system API, may be required for GLES2 (for example). These are things that a
+Mojo application may be required to provide to the GLES2 (for example) library
+in order to use it. (However, the Mojo application may implement these things as
+it sees fit.)
+
+GLES2
+-----
+
+The gles2/ subdirectory defines the GLES2 C API that's available to Mojo
+applications. To use GLES2, Mojo applications must link against a dynamic
+library (the exact mechanism being platform-dependent) and use the header files
+in this directory as well as the standard Khronos GLES2 header files.
+
+The reason for this, rather than providing GLES2 using the standard Mojo IPC
+mechanism, is performance: The protocol (and transport mechanisms) used to
+communicate with the Mojo GLES2 service is not stable nor "public" (mainly for
+performance reasons), and using the dynamic library shields the application from
+changes to the underlying system.
+
+System
+------
+
+The system/ subdirectory provides definitions of the basic low-level API used by
+all Mojo applications (whether directly or indirectly). These consist primarily
+of the IPC primitives used to communicate with Mojo services.
+
+Though the message protocol is stable, the implementation of the transport is
+not, and access to the IPC mechanisms must be via the primitives defined in this
+directory.
+
+Test Support
+------------
+
+This directory contains a C API for running tests. This API is only available
+under special, specific test conditions. It is not meant for general use by Mojo
+applications.
diff --git a/mojo/public/c/environment/BUILD.gn b/mojo/public/c/environment/BUILD.gn
new file mode 100644
index 0000000..669da7d
--- /dev/null
+++ b/mojo/public/c/environment/BUILD.gn
@@ -0,0 +1,12 @@
+# Copyright 2014 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.
+
+source_set("environment") {
+  sources = [
+    "async_waiter.h",
+    "logger.h",
+  ]
+
+  deps = [ "//mojo/public/c/system" ]
+}
diff --git a/mojo/public/c/environment/async_waiter.h b/mojo/public/c/environment/async_waiter.h
new file mode 100644
index 0000000..b5a1f75
--- /dev/null
+++ b/mojo/public/c/environment/async_waiter.h
@@ -0,0 +1,65 @@
+// Copyright 2014 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_C_ENVIRONMENT_ASYNC_WAITER_H_
+#define MOJO_PUBLIC_C_ENVIRONMENT_ASYNC_WAITER_H_
+
+#include "mojo/public/c/system/types.h"
+
+typedef uintptr_t MojoAsyncWaitID;
+
+typedef void (*MojoAsyncWaitCallback)(void* closure, MojoResult result);
+
+// Functions for asynchronously waiting (and cancelling asynchronous waits) on a
+// handle.
+//
+// Thread-safety:
+//   - |CancelWait(wait_id)| may only be called on the same thread as the
+//     |AsyncWait()| that provided |wait_id| was called on.
+//   - A given |MojoAsyncWaiter|'s functions may only be called on the thread(s)
+//     that it is defined to be valid on (typically including the thread on
+//     which the |MojoAsyncWaiter| was provided). E.g., a library may require
+//     initialization with a single |MojoAsyncWaiter| and stipulate that it only
+//     be used on threads on which that |MojoAsyncWaiter| is valid.
+//   - If a |MojoAsyncWaiter| is valid on multiple threads, then its functions
+//     must be thread-safe (subject to the first restriction above).
+struct MojoAsyncWaiter {
+  // Arranges for |callback| to be called on the current thread at some future
+  // when |handle| satisfies |signals| or it is known that it will never satisfy
+  // |signals| (with the same behavior as |MojoWait()|).
+  //
+  // |callback| will not be called in the nested context of |AsyncWait()|, but
+  // only, e.g., from some run loop. |callback| is provided with the |closure|
+  // argument as well as the result of the wait. For each call to |AsyncWait()|,
+  // |callback| will be called at most once.
+  //
+  // |handle| must not be closed or transferred (via |MojoWriteMessage()|; this
+  // is equivalent to closing the handle) until either the callback has been
+  // executed or the async wait has been cancelled using the returned (nonzero)
+  // |MojoAsyncWaitID| (see |CancelWait()|). Otherwise, an invalid (or, worse,
+  // re-used) handle may be waited on by the implementation of this
+  // |MojoAsyncWaiter|.
+  //
+  // Note that once the callback has been called, the returned |MojoAsyncWaitID|
+  // becomes invalid.
+  MojoAsyncWaitID (*AsyncWait)(MojoHandle handle,
+                               MojoHandleSignals signals,
+                               MojoDeadline deadline,
+                               MojoAsyncWaitCallback callback,
+                               void* closure);
+
+  // Cancels an outstanding async wait (specified by |wait_id|) initiated by
+  // |AsyncWait()|. This may only be called from the same thread on which the
+  // corresponding |AsyncWait()| was called, and may only be called if the
+  // callback to |AsyncWait()| has not been called.
+  //
+  // Once this has been called, the callback provided to |AsyncWait()| will not
+  // be called. Moreover, it is then immediately safe to close or transfer the
+  // handle provided to |AsyncWait()|. (I.e., the implementation of this
+  // |MojoAsyncWaiter| will no longer wait on, or do anything else with, the
+  // handle.)
+  void (*CancelWait)(MojoAsyncWaitID wait_id);
+};
+
+#endif  // MOJO_PUBLIC_C_ENVIRONMENT_ASYNC_WAITER_H_
diff --git a/mojo/public/c/environment/logger.h b/mojo/public/c/environment/logger.h
new file mode 100644
index 0000000..c492a66
--- /dev/null
+++ b/mojo/public/c/environment/logger.h
@@ -0,0 +1,54 @@
+// Copyright 2014 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_C_ENVIRONMENT_LOGGER_H_
+#define MOJO_PUBLIC_C_ENVIRONMENT_LOGGER_H_
+
+#include <stdint.h>
+
+// |MojoLogLevel|: Used to specify the type of log message. Values are ordered
+// by severity (i.e., higher numerical values are more severe).
+
+typedef int32_t MojoLogLevel;
+
+#ifdef __cplusplus
+const MojoLogLevel MOJO_LOG_LEVEL_VERBOSE = -1;
+const MojoLogLevel MOJO_LOG_LEVEL_INFO = 0;
+const MojoLogLevel MOJO_LOG_LEVEL_WARNING = 1;
+const MojoLogLevel MOJO_LOG_LEVEL_ERROR = 2;
+const MojoLogLevel MOJO_LOG_LEVEL_FATAL = 3;
+#else
+#define MOJO_LOG_LEVEL_VERBOSE ((MojoLogLevel) - 1)
+#define MOJO_LOG_LEVEL_INFO ((MojoLogLevel)0)
+#define MOJO_LOG_LEVEL_WARNING ((MojoLogLevel)1)
+#define MOJO_LOG_LEVEL_ERROR ((MojoLogLevel)2)
+#define MOJO_LOG_LEVEL_FATAL ((MojoLogLevel)3)
+#endif
+
+// Structure with basic logging functions (on top of which more friendly logging
+// macros may be built). The functions are thread-safe, except for
+// |SetMinimumLogLevel()| (see below).
+struct MojoLogger {
+  // Logs |message| at level |log_level| if |log_level| is at least the current
+  // minimum log level. If |log_level| is |MOJO_LOG_LEVEL_FATAL| (or greater),
+  // aborts the application/process.
+  void (*LogMessage)(MojoLogLevel log_level, const char* message);
+
+  // Gets the minimum log level (see above), which will always be at most
+  // |MOJO_LOG_LEVEL_FATAL|. (Though |LogMessage()| will automatically avoid
+  // logging messages below the minimum log level, this may be used to avoid
+  // extra work.)
+  MojoLogLevel (*GetMinimumLogLevel)(void);
+
+  // Sets the minimum log level (see above) to the lesser of |minimum_log_level|
+  // and |MOJO_LOG_LEVEL_FATAL|.
+  //
+  // Warning: This function may not be thread-safe, and should not be called
+  // concurrently with other |MojoLogger| functions. (In some environments --
+  // such as Chromium -- that share a logger across applications, this may mean
+  // that it is almost never safe to call this.)
+  void (*SetMinimumLogLevel)(MojoLogLevel minimum_log_level);
+};
+
+#endif  // MOJO_PUBLIC_C_ENVIRONMENT_LOGGER_H_
diff --git a/mojo/public/c/gles2/BUILD.gn b/mojo/public/c/gles2/BUILD.gn
new file mode 100644
index 0000000..df0007b
--- /dev/null
+++ b/mojo/public/c/gles2/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2014 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.
+
+config("gles2_config") {
+  defines = [ "GLES2_USE_MOJO" ]
+}
+
+source_set("gles2") {
+  sources = [
+    "gles2.h",
+    "gles2_export.h",
+  ]
+
+  public_configs = [ ":gles2_config" ]
+
+  public_deps = [
+    "//mojo/public/c/environment",
+    "//mojo/public/c/system",
+  ]
+}
diff --git a/mojo/public/c/gles2/DEPS b/mojo/public/c/gles2/DEPS
new file mode 100644
index 0000000..3887457
--- /dev/null
+++ b/mojo/public/c/gles2/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+mojo/public/c/environment",
+]
diff --git a/mojo/public/c/gles2/chromium_sync_point.h b/mojo/public/c/gles2/chromium_sync_point.h
new file mode 100644
index 0000000..6369712
--- /dev/null
+++ b/mojo/public/c/gles2/chromium_sync_point.h
@@ -0,0 +1,30 @@
+// Copyright 2014 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_C_GLES2_CHROMIUM_SYNC_POINT_H_
+#define MOJO_PUBLIC_C_GLES2_CHROMIUM_SYNC_POINT_H_
+
+// Note: This header should be compilable as C.
+
+#include <stdint.h>
+#include <GLES2/gl2.h>
+
+#include "mojo/public/c/gles2/gles2_export.h"
+#include "mojo/public/c/gles2/gles2_types.h"
+#include "mojo/public/c/system/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) \
+  MOJO_GLES2_EXPORT ReturnType GL_APIENTRY gl##Function PARAMETERS;
+#include "mojo/public/c/gles2/gles2_call_visitor_chromium_sync_point_autogen.h"
+#undef VISIT_GL_CALL
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // MOJO_PUBLIC_C_GLES2_CHROMIUM_SYNC_POINT_H_
diff --git a/mojo/public/c/gles2/chromium_texture_mailbox.h b/mojo/public/c/gles2/chromium_texture_mailbox.h
new file mode 100644
index 0000000..177ebbb
--- /dev/null
+++ b/mojo/public/c/gles2/chromium_texture_mailbox.h
@@ -0,0 +1,30 @@
+// Copyright 2014 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_C_GLES2_CHROMIUM_TEXTURE_MAILBOX_H_
+#define MOJO_PUBLIC_C_GLES2_CHROMIUM_TEXTURE_MAILBOX_H_
+
+// Note: This header should be compilable as C.
+
+#include <stdint.h>
+#include <GLES2/gl2.h>
+
+#include "mojo/public/c/gles2/gles2_export.h"
+#include "mojo/public/c/gles2/gles2_types.h"
+#include "mojo/public/c/system/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) \
+  MOJO_GLES2_EXPORT ReturnType GL_APIENTRY gl##Function PARAMETERS;
+#include "mojo/public/c/gles2/gles2_call_visitor_chromium_texture_mailbox_autogen.h"
+#undef VISIT_GL_CALL
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // MOJO_PUBLIC_C_GLES2_CHROMIUM_TEXTURE_MAILBOX_H_
diff --git a/mojo/public/c/gles2/gles2.h b/mojo/public/c/gles2/gles2.h
new file mode 100644
index 0000000..36c6f7f
--- /dev/null
+++ b/mojo/public/c/gles2/gles2.h
@@ -0,0 +1,45 @@
+// Copyright 2013 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_C_GLES2_GLES2_H_
+#define MOJO_PUBLIC_C_GLES2_GLES2_H_
+
+// Note: This header should be compilable as C.
+
+#include <stdint.h>
+#include <GLES2/gl2.h>
+
+#include "mojo/public/c/environment/async_waiter.h"
+#include "mojo/public/c/gles2/gles2_export.h"
+#include "mojo/public/c/gles2/gles2_types.h"
+#include "mojo/public/c/system/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+MOJO_GLES2_EXPORT MojoGLES2Context
+    MojoGLES2CreateContext(MojoHandle handle,
+                           MojoGLES2ContextLost lost_callback,
+                           void* closure,
+                           const MojoAsyncWaiter* async_waiter);
+MOJO_GLES2_EXPORT void MojoGLES2DestroyContext(MojoGLES2Context context);
+MOJO_GLES2_EXPORT void MojoGLES2MakeCurrent(MojoGLES2Context context);
+MOJO_GLES2_EXPORT void MojoGLES2SwapBuffers(void);
+
+// TODO(piman): We shouldn't have to leak those 2 interfaces, especially in a
+// type-unsafe way.
+MOJO_GLES2_EXPORT void* MojoGLES2GetGLES2Interface(MojoGLES2Context context);
+MOJO_GLES2_EXPORT void* MojoGLES2GetContextSupport(MojoGLES2Context context);
+
+#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) \
+  MOJO_GLES2_EXPORT ReturnType GL_APIENTRY gl##Function PARAMETERS;
+#include "mojo/public/c/gles2/gles2_call_visitor_autogen.h"
+#undef VISIT_GL_CALL
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // MOJO_PUBLIC_C_GLES2_GLES2_H_
diff --git a/mojo/public/c/gles2/gles2_call_visitor_autogen.h b/mojo/public/c/gles2/gles2_call_visitor_autogen.h
new file mode 100644
index 0000000..72494c5
--- /dev/null
+++ b/mojo/public/c/gles2/gles2_call_visitor_autogen.h
@@ -0,0 +1,544 @@
+// Copyright 2014 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 is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// It's formatted by clang-format using chromium coding style:
+//    clang-format -i -style=chromium filename
+// DO NOT EDIT!
+
+VISIT_GL_CALL(ActiveTexture, void, (GLenum texture), (texture))
+VISIT_GL_CALL(AttachShader,
+              void,
+              (GLuint program, GLuint shader),
+              (program, shader))
+VISIT_GL_CALL(BindAttribLocation,
+              void,
+              (GLuint program, GLuint index, const char* name),
+              (program, index, name))
+VISIT_GL_CALL(BindBuffer,
+              void,
+              (GLenum target, GLuint buffer),
+              (target, buffer))
+VISIT_GL_CALL(BindFramebuffer,
+              void,
+              (GLenum target, GLuint framebuffer),
+              (target, framebuffer))
+VISIT_GL_CALL(BindRenderbuffer,
+              void,
+              (GLenum target, GLuint renderbuffer),
+              (target, renderbuffer))
+VISIT_GL_CALL(BindTexture,
+              void,
+              (GLenum target, GLuint texture),
+              (target, texture))
+VISIT_GL_CALL(BlendColor,
+              void,
+              (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha),
+              (red, green, blue, alpha))
+VISIT_GL_CALL(BlendEquation, void, (GLenum mode), (mode))
+VISIT_GL_CALL(BlendEquationSeparate,
+              void,
+              (GLenum modeRGB, GLenum modeAlpha),
+              (modeRGB, modeAlpha))
+VISIT_GL_CALL(BlendFunc,
+              void,
+              (GLenum sfactor, GLenum dfactor),
+              (sfactor, dfactor))
+VISIT_GL_CALL(BlendFuncSeparate,
+              void,
+              (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha),
+              (srcRGB, dstRGB, srcAlpha, dstAlpha))
+VISIT_GL_CALL(BufferData,
+              void,
+              (GLenum target, GLsizeiptr size, const void* data, GLenum usage),
+              (target, size, data, usage))
+VISIT_GL_CALL(
+    BufferSubData,
+    void,
+    (GLenum target, GLintptr offset, GLsizeiptr size, const void* data),
+    (target, offset, size, data))
+VISIT_GL_CALL(CheckFramebufferStatus, GLenum, (GLenum target), (target))
+VISIT_GL_CALL(Clear, void, (GLbitfield mask), (mask))
+VISIT_GL_CALL(ClearColor,
+              void,
+              (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha),
+              (red, green, blue, alpha))
+VISIT_GL_CALL(ClearDepthf, void, (GLclampf depth), (depth))
+VISIT_GL_CALL(ClearStencil, void, (GLint s), (s))
+VISIT_GL_CALL(ColorMask,
+              void,
+              (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha),
+              (red, green, blue, alpha))
+VISIT_GL_CALL(CompileShader, void, (GLuint shader), (shader))
+VISIT_GL_CALL(
+    CompressedTexImage2D,
+    void,
+    (GLenum target,
+     GLint level,
+     GLenum internalformat,
+     GLsizei width,
+     GLsizei height,
+     GLint border,
+     GLsizei imageSize,
+     const void* data),
+    (target, level, internalformat, width, height, border, imageSize, data))
+VISIT_GL_CALL(
+    CompressedTexSubImage2D,
+    void,
+    (GLenum target,
+     GLint level,
+     GLint xoffset,
+     GLint yoffset,
+     GLsizei width,
+     GLsizei height,
+     GLenum format,
+     GLsizei imageSize,
+     const void* data),
+    (target, level, xoffset, yoffset, width, height, format, imageSize, data))
+VISIT_GL_CALL(CopyTexImage2D,
+              void,
+              (GLenum target,
+               GLint level,
+               GLenum internalformat,
+               GLint x,
+               GLint y,
+               GLsizei width,
+               GLsizei height,
+               GLint border),
+              (target, level, internalformat, x, y, width, height, border))
+VISIT_GL_CALL(CopyTexSubImage2D,
+              void,
+              (GLenum target,
+               GLint level,
+               GLint xoffset,
+               GLint yoffset,
+               GLint x,
+               GLint y,
+               GLsizei width,
+               GLsizei height),
+              (target, level, xoffset, yoffset, x, y, width, height))
+VISIT_GL_CALL(CreateProgram, GLuint, (), ())
+VISIT_GL_CALL(CreateShader, GLuint, (GLenum type), (type))
+VISIT_GL_CALL(CullFace, void, (GLenum mode), (mode))
+VISIT_GL_CALL(DeleteBuffers,
+              void,
+              (GLsizei n, const GLuint* buffers),
+              (n, buffers))
+VISIT_GL_CALL(DeleteFramebuffers,
+              void,
+              (GLsizei n, const GLuint* framebuffers),
+              (n, framebuffers))
+VISIT_GL_CALL(DeleteProgram, void, (GLuint program), (program))
+VISIT_GL_CALL(DeleteRenderbuffers,
+              void,
+              (GLsizei n, const GLuint* renderbuffers),
+              (n, renderbuffers))
+VISIT_GL_CALL(DeleteShader, void, (GLuint shader), (shader))
+VISIT_GL_CALL(DeleteTextures,
+              void,
+              (GLsizei n, const GLuint* textures),
+              (n, textures))
+VISIT_GL_CALL(DepthFunc, void, (GLenum func), (func))
+VISIT_GL_CALL(DepthMask, void, (GLboolean flag), (flag))
+VISIT_GL_CALL(DepthRangef, void, (GLclampf zNear, GLclampf zFar), (zNear, zFar))
+VISIT_GL_CALL(DetachShader,
+              void,
+              (GLuint program, GLuint shader),
+              (program, shader))
+VISIT_GL_CALL(Disable, void, (GLenum cap), (cap))
+VISIT_GL_CALL(DisableVertexAttribArray, void, (GLuint index), (index))
+VISIT_GL_CALL(DrawArrays,
+              void,
+              (GLenum mode, GLint first, GLsizei count),
+              (mode, first, count))
+VISIT_GL_CALL(DrawElements,
+              void,
+              (GLenum mode, GLsizei count, GLenum type, const void* indices),
+              (mode, count, type, indices))
+VISIT_GL_CALL(Enable, void, (GLenum cap), (cap))
+VISIT_GL_CALL(EnableVertexAttribArray, void, (GLuint index), (index))
+VISIT_GL_CALL(Finish, void, (), ())
+VISIT_GL_CALL(Flush, void, (), ())
+VISIT_GL_CALL(FramebufferRenderbuffer,
+              void,
+              (GLenum target,
+               GLenum attachment,
+               GLenum renderbuffertarget,
+               GLuint renderbuffer),
+              (target, attachment, renderbuffertarget, renderbuffer))
+VISIT_GL_CALL(FramebufferTexture2D,
+              void,
+              (GLenum target,
+               GLenum attachment,
+               GLenum textarget,
+               GLuint texture,
+               GLint level),
+              (target, attachment, textarget, texture, level))
+VISIT_GL_CALL(FrontFace, void, (GLenum mode), (mode))
+VISIT_GL_CALL(GenBuffers, void, (GLsizei n, GLuint * buffers), (n, buffers))
+VISIT_GL_CALL(GenerateMipmap, void, (GLenum target), (target))
+VISIT_GL_CALL(GenFramebuffers,
+              void,
+              (GLsizei n, GLuint * framebuffers),
+              (n, framebuffers))
+VISIT_GL_CALL(GenRenderbuffers,
+              void,
+              (GLsizei n, GLuint * renderbuffers),
+              (n, renderbuffers))
+VISIT_GL_CALL(GenTextures, void, (GLsizei n, GLuint * textures), (n, textures))
+VISIT_GL_CALL(GetActiveAttrib,
+              void,
+              (GLuint program,
+               GLuint index,
+               GLsizei bufsize,
+               GLsizei * length,
+               GLint * size,
+               GLenum * type,
+               char* name),
+              (program, index, bufsize, length, size, type, name))
+VISIT_GL_CALL(GetActiveUniform,
+              void,
+              (GLuint program,
+               GLuint index,
+               GLsizei bufsize,
+               GLsizei * length,
+               GLint * size,
+               GLenum * type,
+               char* name),
+              (program, index, bufsize, length, size, type, name))
+VISIT_GL_CALL(
+    GetAttachedShaders,
+    void,
+    (GLuint program, GLsizei maxcount, GLsizei * count, GLuint * shaders),
+    (program, maxcount, count, shaders))
+VISIT_GL_CALL(GetAttribLocation,
+              GLint,
+              (GLuint program, const char* name),
+              (program, name))
+VISIT_GL_CALL(GetBooleanv,
+              void,
+              (GLenum pname, GLboolean * params),
+              (pname, params))
+VISIT_GL_CALL(GetBufferParameteriv,
+              void,
+              (GLenum target, GLenum pname, GLint * params),
+              (target, pname, params))
+VISIT_GL_CALL(GetError, GLenum, (), ())
+VISIT_GL_CALL(GetFloatv,
+              void,
+              (GLenum pname, GLfloat * params),
+              (pname, params))
+VISIT_GL_CALL(GetFramebufferAttachmentParameteriv,
+              void,
+              (GLenum target, GLenum attachment, GLenum pname, GLint * params),
+              (target, attachment, pname, params))
+VISIT_GL_CALL(GetIntegerv,
+              void,
+              (GLenum pname, GLint * params),
+              (pname, params))
+VISIT_GL_CALL(GetProgramiv,
+              void,
+              (GLuint program, GLenum pname, GLint * params),
+              (program, pname, params))
+VISIT_GL_CALL(
+    GetProgramInfoLog,
+    void,
+    (GLuint program, GLsizei bufsize, GLsizei * length, char* infolog),
+    (program, bufsize, length, infolog))
+VISIT_GL_CALL(GetRenderbufferParameteriv,
+              void,
+              (GLenum target, GLenum pname, GLint * params),
+              (target, pname, params))
+VISIT_GL_CALL(GetShaderiv,
+              void,
+              (GLuint shader, GLenum pname, GLint * params),
+              (shader, pname, params))
+VISIT_GL_CALL(GetShaderInfoLog,
+              void,
+              (GLuint shader, GLsizei bufsize, GLsizei * length, char* infolog),
+              (shader, bufsize, length, infolog))
+VISIT_GL_CALL(
+    GetShaderPrecisionFormat,
+    void,
+    (GLenum shadertype, GLenum precisiontype, GLint * range, GLint * precision),
+    (shadertype, precisiontype, range, precision))
+VISIT_GL_CALL(GetShaderSource,
+              void,
+              (GLuint shader, GLsizei bufsize, GLsizei * length, char* source),
+              (shader, bufsize, length, source))
+VISIT_GL_CALL(GetString, const GLubyte*, (GLenum name), (name))
+VISIT_GL_CALL(GetTexParameterfv,
+              void,
+              (GLenum target, GLenum pname, GLfloat * params),
+              (target, pname, params))
+VISIT_GL_CALL(GetTexParameteriv,
+              void,
+              (GLenum target, GLenum pname, GLint * params),
+              (target, pname, params))
+VISIT_GL_CALL(GetUniformfv,
+              void,
+              (GLuint program, GLint location, GLfloat * params),
+              (program, location, params))
+VISIT_GL_CALL(GetUniformiv,
+              void,
+              (GLuint program, GLint location, GLint * params),
+              (program, location, params))
+VISIT_GL_CALL(GetUniformLocation,
+              GLint,
+              (GLuint program, const char* name),
+              (program, name))
+VISIT_GL_CALL(GetVertexAttribfv,
+              void,
+              (GLuint index, GLenum pname, GLfloat * params),
+              (index, pname, params))
+VISIT_GL_CALL(GetVertexAttribiv,
+              void,
+              (GLuint index, GLenum pname, GLint * params),
+              (index, pname, params))
+VISIT_GL_CALL(GetVertexAttribPointerv,
+              void,
+              (GLuint index, GLenum pname, void** pointer),
+              (index, pname, pointer))
+VISIT_GL_CALL(Hint, void, (GLenum target, GLenum mode), (target, mode))
+VISIT_GL_CALL(IsBuffer, GLboolean, (GLuint buffer), (buffer))
+VISIT_GL_CALL(IsEnabled, GLboolean, (GLenum cap), (cap))
+VISIT_GL_CALL(IsFramebuffer, GLboolean, (GLuint framebuffer), (framebuffer))
+VISIT_GL_CALL(IsProgram, GLboolean, (GLuint program), (program))
+VISIT_GL_CALL(IsRenderbuffer, GLboolean, (GLuint renderbuffer), (renderbuffer))
+VISIT_GL_CALL(IsShader, GLboolean, (GLuint shader), (shader))
+VISIT_GL_CALL(IsTexture, GLboolean, (GLuint texture), (texture))
+VISIT_GL_CALL(LineWidth, void, (GLfloat width), (width))
+VISIT_GL_CALL(LinkProgram, void, (GLuint program), (program))
+VISIT_GL_CALL(PixelStorei, void, (GLenum pname, GLint param), (pname, param))
+VISIT_GL_CALL(PolygonOffset,
+              void,
+              (GLfloat factor, GLfloat units),
+              (factor, units))
+VISIT_GL_CALL(ReadPixels,
+              void,
+              (GLint x,
+               GLint y,
+               GLsizei width,
+               GLsizei height,
+               GLenum format,
+               GLenum type,
+               void* pixels),
+              (x, y, width, height, format, type, pixels))
+VISIT_GL_CALL(ReleaseShaderCompiler, void, (), ())
+VISIT_GL_CALL(
+    RenderbufferStorage,
+    void,
+    (GLenum target, GLenum internalformat, GLsizei width, GLsizei height),
+    (target, internalformat, width, height))
+VISIT_GL_CALL(SampleCoverage,
+              void,
+              (GLclampf value, GLboolean invert),
+              (value, invert))
+VISIT_GL_CALL(Scissor,
+              void,
+              (GLint x, GLint y, GLsizei width, GLsizei height),
+              (x, y, width, height))
+VISIT_GL_CALL(ShaderBinary,
+              void,
+              (GLsizei n,
+               const GLuint* shaders,
+               GLenum binaryformat,
+               const void* binary,
+               GLsizei length),
+              (n, shaders, binaryformat, binary, length))
+VISIT_GL_CALL(ShaderSource,
+              void,
+              (GLuint shader,
+               GLsizei count,
+               const GLchar* const* str,
+               const GLint* length),
+              (shader, count, str, length))
+VISIT_GL_CALL(StencilFunc,
+              void,
+              (GLenum func, GLint ref, GLuint mask),
+              (func, ref, mask))
+VISIT_GL_CALL(StencilFuncSeparate,
+              void,
+              (GLenum face, GLenum func, GLint ref, GLuint mask),
+              (face, func, ref, mask))
+VISIT_GL_CALL(StencilMask, void, (GLuint mask), (mask))
+VISIT_GL_CALL(StencilMaskSeparate,
+              void,
+              (GLenum face, GLuint mask),
+              (face, mask))
+VISIT_GL_CALL(StencilOp,
+              void,
+              (GLenum fail, GLenum zfail, GLenum zpass),
+              (fail, zfail, zpass))
+VISIT_GL_CALL(StencilOpSeparate,
+              void,
+              (GLenum face, GLenum fail, GLenum zfail, GLenum zpass),
+              (face, fail, zfail, zpass))
+VISIT_GL_CALL(TexImage2D,
+              void,
+              (GLenum target,
+               GLint level,
+               GLint internalformat,
+               GLsizei width,
+               GLsizei height,
+               GLint border,
+               GLenum format,
+               GLenum type,
+               const void* pixels),
+              (target,
+               level,
+               internalformat,
+               width,
+               height,
+               border,
+               format,
+               type,
+               pixels))
+VISIT_GL_CALL(TexParameterf,
+              void,
+              (GLenum target, GLenum pname, GLfloat param),
+              (target, pname, param))
+VISIT_GL_CALL(TexParameterfv,
+              void,
+              (GLenum target, GLenum pname, const GLfloat* params),
+              (target, pname, params))
+VISIT_GL_CALL(TexParameteri,
+              void,
+              (GLenum target, GLenum pname, GLint param),
+              (target, pname, param))
+VISIT_GL_CALL(TexParameteriv,
+              void,
+              (GLenum target, GLenum pname, const GLint* params),
+              (target, pname, params))
+VISIT_GL_CALL(
+    TexSubImage2D,
+    void,
+    (GLenum target,
+     GLint level,
+     GLint xoffset,
+     GLint yoffset,
+     GLsizei width,
+     GLsizei height,
+     GLenum format,
+     GLenum type,
+     const void* pixels),
+    (target, level, xoffset, yoffset, width, height, format, type, pixels))
+VISIT_GL_CALL(Uniform1f, void, (GLint location, GLfloat x), (location, x))
+VISIT_GL_CALL(Uniform1fv,
+              void,
+              (GLint location, GLsizei count, const GLfloat* v),
+              (location, count, v))
+VISIT_GL_CALL(Uniform1i, void, (GLint location, GLint x), (location, x))
+VISIT_GL_CALL(Uniform1iv,
+              void,
+              (GLint location, GLsizei count, const GLint* v),
+              (location, count, v))
+VISIT_GL_CALL(Uniform2f,
+              void,
+              (GLint location, GLfloat x, GLfloat y),
+              (location, x, y))
+VISIT_GL_CALL(Uniform2fv,
+              void,
+              (GLint location, GLsizei count, const GLfloat* v),
+              (location, count, v))
+VISIT_GL_CALL(Uniform2i,
+              void,
+              (GLint location, GLint x, GLint y),
+              (location, x, y))
+VISIT_GL_CALL(Uniform2iv,
+              void,
+              (GLint location, GLsizei count, const GLint* v),
+              (location, count, v))
+VISIT_GL_CALL(Uniform3f,
+              void,
+              (GLint location, GLfloat x, GLfloat y, GLfloat z),
+              (location, x, y, z))
+VISIT_GL_CALL(Uniform3fv,
+              void,
+              (GLint location, GLsizei count, const GLfloat* v),
+              (location, count, v))
+VISIT_GL_CALL(Uniform3i,
+              void,
+              (GLint location, GLint x, GLint y, GLint z),
+              (location, x, y, z))
+VISIT_GL_CALL(Uniform3iv,
+              void,
+              (GLint location, GLsizei count, const GLint* v),
+              (location, count, v))
+VISIT_GL_CALL(Uniform4f,
+              void,
+              (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w),
+              (location, x, y, z, w))
+VISIT_GL_CALL(Uniform4fv,
+              void,
+              (GLint location, GLsizei count, const GLfloat* v),
+              (location, count, v))
+VISIT_GL_CALL(Uniform4i,
+              void,
+              (GLint location, GLint x, GLint y, GLint z, GLint w),
+              (location, x, y, z, w))
+VISIT_GL_CALL(Uniform4iv,
+              void,
+              (GLint location, GLsizei count, const GLint* v),
+              (location, count, v))
+VISIT_GL_CALL(
+    UniformMatrix2fv,
+    void,
+    (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value),
+    (location, count, transpose, value))
+VISIT_GL_CALL(
+    UniformMatrix3fv,
+    void,
+    (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value),
+    (location, count, transpose, value))
+VISIT_GL_CALL(
+    UniformMatrix4fv,
+    void,
+    (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value),
+    (location, count, transpose, value))
+VISIT_GL_CALL(UseProgram, void, (GLuint program), (program))
+VISIT_GL_CALL(ValidateProgram, void, (GLuint program), (program))
+VISIT_GL_CALL(VertexAttrib1f, void, (GLuint indx, GLfloat x), (indx, x))
+VISIT_GL_CALL(VertexAttrib1fv,
+              void,
+              (GLuint indx, const GLfloat* values),
+              (indx, values))
+VISIT_GL_CALL(VertexAttrib2f,
+              void,
+              (GLuint indx, GLfloat x, GLfloat y),
+              (indx, x, y))
+VISIT_GL_CALL(VertexAttrib2fv,
+              void,
+              (GLuint indx, const GLfloat* values),
+              (indx, values))
+VISIT_GL_CALL(VertexAttrib3f,
+              void,
+              (GLuint indx, GLfloat x, GLfloat y, GLfloat z),
+              (indx, x, y, z))
+VISIT_GL_CALL(VertexAttrib3fv,
+              void,
+              (GLuint indx, const GLfloat* values),
+              (indx, values))
+VISIT_GL_CALL(VertexAttrib4f,
+              void,
+              (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w),
+              (indx, x, y, z, w))
+VISIT_GL_CALL(VertexAttrib4fv,
+              void,
+              (GLuint indx, const GLfloat* values),
+              (indx, values))
+VISIT_GL_CALL(VertexAttribPointer,
+              void,
+              (GLuint indx,
+               GLint size,
+               GLenum type,
+               GLboolean normalized,
+               GLsizei stride,
+               const void* ptr),
+              (indx, size, type, normalized, stride, ptr))
+VISIT_GL_CALL(Viewport,
+              void,
+              (GLint x, GLint y, GLsizei width, GLsizei height),
+              (x, y, width, height))
diff --git a/mojo/public/c/gles2/gles2_call_visitor_chromium_sync_point_autogen.h b/mojo/public/c/gles2/gles2_call_visitor_chromium_sync_point_autogen.h
new file mode 100644
index 0000000..3c3c4b9
--- /dev/null
+++ b/mojo/public/c/gles2/gles2_call_visitor_chromium_sync_point_autogen.h
@@ -0,0 +1,12 @@
+// Copyright 2014 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 is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// It's formatted by clang-format using chromium coding style:
+//    clang-format -i -style=chromium filename
+// DO NOT EDIT!
+
+VISIT_GL_CALL(InsertSyncPointCHROMIUM, GLuint, (), ())
+VISIT_GL_CALL(WaitSyncPointCHROMIUM, void, (GLuint sync_point), (sync_point))
diff --git a/mojo/public/c/gles2/gles2_call_visitor_chromium_texture_mailbox_autogen.h b/mojo/public/c/gles2/gles2_call_visitor_chromium_texture_mailbox_autogen.h
new file mode 100644
index 0000000..184c2f2
--- /dev/null
+++ b/mojo/public/c/gles2/gles2_call_visitor_chromium_texture_mailbox_autogen.h
@@ -0,0 +1,27 @@
+// Copyright 2014 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 is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// It's formatted by clang-format using chromium coding style:
+//    clang-format -i -style=chromium filename
+// DO NOT EDIT!
+
+VISIT_GL_CALL(GenMailboxCHROMIUM, void, (GLbyte * mailbox), (mailbox))
+VISIT_GL_CALL(ProduceTextureCHROMIUM,
+              void,
+              (GLenum target, const GLbyte* mailbox),
+              (target, mailbox))
+VISIT_GL_CALL(ProduceTextureDirectCHROMIUM,
+              void,
+              (GLuint texture, GLenum target, const GLbyte* mailbox),
+              (texture, target, mailbox))
+VISIT_GL_CALL(ConsumeTextureCHROMIUM,
+              void,
+              (GLenum target, const GLbyte* mailbox),
+              (target, mailbox))
+VISIT_GL_CALL(CreateAndConsumeTextureCHROMIUM,
+              GLuint,
+              (GLenum target, const GLbyte* mailbox),
+              (target, mailbox))
diff --git a/mojo/public/c/gles2/gles2_export.h b/mojo/public/c/gles2/gles2_export.h
new file mode 100644
index 0000000..60667b1
--- /dev/null
+++ b/mojo/public/c/gles2/gles2_export.h
@@ -0,0 +1,33 @@
+// Copyright 2014 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_C_GLES2_GLES2_EXPORT_H_
+#define MOJO_PUBLIC_C_GLES2_GLES2_EXPORT_H_
+
+#if defined(COMPONENT_BUILD) && defined(MOJO_USE_GLES2_IMPL)
+#if defined(WIN32)
+
+#if defined(MOJO_GLES2_IMPLEMENTATION)
+#define MOJO_GLES2_EXPORT __declspec(dllexport)
+#else
+#define MOJO_GLES2_EXPORT __declspec(dllimport)
+#endif
+
+#else  // !defined(WIN32)
+
+#if defined(MOJO_GLES2_IMPLEMENTATION)
+#define MOJO_GLES2_EXPORT __attribute__((visibility("default")))
+#else
+#define MOJO_GLES2_EXPORT
+#endif
+
+#endif  // defined(WIN32)
+
+#else  // !defined(COMPONENT_BUILD) || !defined(MOJO_USE_GLES2_IMPL)
+
+#define MOJO_GLES2_EXPORT
+
+#endif  // defined(COMPONENT_BUILD) && defined(MOJO_USE_GLES2_IMPL)
+
+#endif  // MOJO_PUBLIC_C_GLES2_GLES2_EXPORT_H_
diff --git a/mojo/public/c/gles2/gles2_types.h b/mojo/public/c/gles2/gles2_types.h
new file mode 100644
index 0000000..3ecf4db
--- /dev/null
+++ b/mojo/public/c/gles2/gles2_types.h
@@ -0,0 +1,25 @@
+// Copyright 2014 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_C_GLES2_GLES2_TYPES_H_
+#define MOJO_PUBLIC_C_GLES2_GLES2_TYPES_H_
+
+// Note: This header should be compilable as C.
+
+#include <stdint.h>
+
+#include "mojo/public/c/gles2/gles2_export.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct MojoGLES2ContextPrivate* MojoGLES2Context;
+typedef void (*MojoGLES2ContextLost)(void* closure);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // MOJO_PUBLIC_C_GLES2_GLES2_TYPES_H_
diff --git a/mojo/public/c/system/BUILD.gn b/mojo/public/c/system/BUILD.gn
new file mode 100644
index 0000000..b47b3da
--- /dev/null
+++ b/mojo/public/c/system/BUILD.gn
@@ -0,0 +1,48 @@
+# Copyright 2014 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.
+
+# Depend on this target to use the types etc defined in the system without
+# linking against a specific implementation of the system. To link against a
+# particular implementation, use the :for_component or
+# :for_shared_library targets, depending on the type of target you are.
+source_set("system") {
+  sources = [
+    "buffer.h",
+    "core.h",
+    "data_pipe.h",
+    "functions.h",
+    "macros.h",
+    "message_pipe.h",
+    "system_export.h",
+    "types.h",
+  ]
+}
+
+# In an is_component_build build, everything can link against //mojo/edk/system
+# because it is built as a shared library. However, in a static build,
+# //mojo/edk/system is linked into an executable (e.g., mojo_shell), and must be
+# injected into other shared libraries (i.e., Mojo Apps) that need the mojo
+# system API.
+#
+# For component targets, add //mojo/public/c/system:for_component to your deps
+# section.
+#
+# For shared_library targets (e.g., a Mojo App), add
+# //mojo/public/c/system:for_shared_library to your deps
+
+group("for_shared_library") {
+  public_deps = [ ":system" ]
+  if (is_component_build) {
+    deps = [ "//mojo/edk/system" ]
+  } else {
+    deps = [ "//mojo/public/platform/native:system_thunks" ]
+  }
+}
+
+group("for_component") {
+  public_deps = [ ":system" ]
+  if (is_component_build) {
+    deps = [ "//mojo/edk/system" ]
+  }
+}
diff --git a/mojo/public/c/system/buffer.h b/mojo/public/c/system/buffer.h
new file mode 100644
index 0000000..19e3c52
--- /dev/null
+++ b/mojo/public/c/system/buffer.h
@@ -0,0 +1,186 @@
+// Copyright 2014 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 types/constants and functions specific to buffers (and in
+// particular shared buffers).
+// TODO(vtl): Reorganize this file (etc.) to separate general buffer functions
+// from (shared) buffer creation.
+//
+// Note: This header should be compilable as C.
+
+#ifndef MOJO_PUBLIC_C_SYSTEM_BUFFER_H_
+#define MOJO_PUBLIC_C_SYSTEM_BUFFER_H_
+
+#include "mojo/public/c/system/macros.h"
+#include "mojo/public/c/system/system_export.h"
+#include "mojo/public/c/system/types.h"
+
+// |MojoCreateSharedBufferOptions|: Used to specify creation parameters for a
+// shared buffer to |MojoCreateSharedBuffer()|.
+//   |uint32_t struct_size|: Set to the size of the
+//       |MojoCreateSharedBufferOptions| struct. (Used to allow for future
+//       extensions.)
+//   |MojoCreateSharedBufferOptionsFlags flags|: Reserved for future use.
+//       |MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE|: No flags; default mode.
+//
+// TODO(vtl): Maybe add a flag to indicate whether the memory should be
+// executable or not?
+// TODO(vtl): Also a flag for discardable (ashmem-style) buffers.
+
+typedef uint32_t MojoCreateSharedBufferOptionsFlags;
+
+#ifdef __cplusplus
+const MojoCreateSharedBufferOptionsFlags
+    MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE = 0;
+#else
+#define MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE \
+  ((MojoCreateSharedBufferOptionsFlags)0)
+#endif
+
+MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int64_t) == 8, int64_t_has_weird_alignment);
+struct MOJO_ALIGNAS(8) MojoCreateSharedBufferOptions {
+  uint32_t struct_size;
+  MojoCreateSharedBufferOptionsFlags flags;
+};
+MOJO_COMPILE_ASSERT(sizeof(MojoCreateSharedBufferOptions) == 8,
+                    MojoCreateSharedBufferOptions_has_wrong_size);
+
+// |MojoDuplicateBufferHandleOptions|: Used to specify parameters in duplicating
+// access to a shared buffer to |MojoDuplicateBufferHandle()|.
+//   |uint32_t struct_size|: Set to the size of the
+//       |MojoDuplicateBufferHandleOptions| struct. (Used to allow for future
+//       extensions.)
+//   |MojoDuplicateBufferHandleOptionsFlags flags|: Reserved for future use.
+//       |MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE|: No flags; default
+//       mode.
+//
+// TODO(vtl): Add flags to remove writability (and executability)? Also, COW?
+
+typedef uint32_t MojoDuplicateBufferHandleOptionsFlags;
+
+#ifdef __cplusplus
+const MojoDuplicateBufferHandleOptionsFlags
+    MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE = 0;
+#else
+#define MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE \
+  ((MojoDuplicateBufferHandleOptionsFlags)0)
+#endif
+
+struct MojoDuplicateBufferHandleOptions {
+  uint32_t struct_size;
+  MojoDuplicateBufferHandleOptionsFlags flags;
+};
+MOJO_COMPILE_ASSERT(sizeof(MojoDuplicateBufferHandleOptions) == 8,
+                    MojoDuplicateBufferHandleOptions_has_wrong_size);
+
+// |MojoMapBufferFlags|: Used to specify different modes to |MojoMapBuffer()|.
+//   |MOJO_MAP_BUFFER_FLAG_NONE| - No flags; default mode.
+
+typedef uint32_t MojoMapBufferFlags;
+
+#ifdef __cplusplus
+const MojoMapBufferFlags MOJO_MAP_BUFFER_FLAG_NONE = 0;
+#else
+#define MOJO_MAP_BUFFER_FLAG_NONE ((MojoMapBufferFlags)0)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Note: See the comment in functions.h about the meaning of the "optional"
+// label for pointer parameters.
+
+// Creates a buffer of size |num_bytes| bytes that can be shared between
+// applications (by duplicating the handle -- see |MojoDuplicateBufferHandle()|
+// -- and passing it over a message pipe). To access the buffer, one must call
+// |MojoMapBuffer()|.
+//
+// |options| may be set to null for a shared buffer with the default options.
+//
+// On success, |*shared_buffer_handle| will be set to the handle for the shared
+// buffer. (On failure, it is not modified.)
+//
+// Note: While more than |num_bytes| bytes may apparently be
+// available/visible/readable/writable, trying to use those extra bytes is
+// undefined behavior.
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
+//       |*options| is invalid).
+//   |MOJO_RESULT_RESOURCE_EXHAUSTED| if a process/system/quota/etc. limit has
+//       been reached (e.g., if the requested size was too large, or if the
+//       maximum number of handles was exceeded).
+//   |MOJO_RESULT_UNIMPLEMENTED| if an unsupported flag was set in |*options|.
+MOJO_SYSTEM_EXPORT MojoResult MojoCreateSharedBuffer(
+    const struct MojoCreateSharedBufferOptions* options,  // Optional.
+    uint64_t num_bytes,                                   // In.
+    MojoHandle* shared_buffer_handle);                    // Out.
+
+// Duplicates the handle |buffer_handle| to a buffer. This creates another
+// handle (returned in |*new_buffer_handle| on success), which can then be sent
+// to another application over a message pipe, while retaining access to the
+// |buffer_handle| (and any mappings that it may have).
+//
+// |options| may be set to null to duplicate the buffer handle with the default
+// options.
+//
+// On success, |*shared_buffer_handle| will be set to the handle for the new
+// buffer handle. (On failure, it is not modified.)
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
+//       |buffer_handle| is not a valid buffer handle or |*options| is invalid).
+//   |MOJO_RESULT_UNIMPLEMENTED| if an unsupported flag was set in |*options|.
+MOJO_SYSTEM_EXPORT MojoResult MojoDuplicateBufferHandle(
+    MojoHandle buffer_handle,
+    const struct MojoDuplicateBufferHandleOptions* options,  // Optional.
+    MojoHandle* new_buffer_handle);                          // Out.
+
+// Maps the part (at offset |offset| of length |num_bytes|) of the buffer given
+// by |buffer_handle| into memory, with options specified by |flags|. |offset +
+// num_bytes| must be less than or equal to the size of the buffer. On success,
+// |*buffer| points to memory with the requested part of the buffer. (On
+// failure, it is not modified.)
+//
+// A single buffer handle may have multiple active mappings (possibly depending
+// on the buffer type). The permissions (e.g., writable or executable) of the
+// returned memory may depend on the properties of the buffer and properties
+// attached to the buffer handle as well as |flags|.
+//
+// Note: Though data outside the specified range may apparently be
+// available/visible/readable/writable, trying to use those extra bytes is
+// undefined behavior.
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
+//       |buffer_handle| is not a valid buffer handle or the range specified by
+//       |offset| and |num_bytes| is not valid).
+//   |MOJO_RESULT_RESOURCE_EXHAUSTED| if the mapping operation itself failed
+//       (e.g., due to not having appropriate address space available).
+MOJO_SYSTEM_EXPORT MojoResult MojoMapBuffer(MojoHandle buffer_handle,
+                                            uint64_t offset,
+                                            uint64_t num_bytes,
+                                            void** buffer,  // Out.
+                                            MojoMapBufferFlags flags);
+
+// Unmaps a buffer pointer that was mapped by |MojoMapBuffer()|. |buffer| must
+// have been the result of |MojoMapBuffer()| (not some pointer strictly inside
+// the mapped memory), and the entire mapping will be removed (partial unmapping
+// is not supported). A mapping may only be unmapped exactly once.
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if |buffer| is invalid (e.g., is not the
+//       result of |MojoMapBuffer()| or has already been unmapped).
+MOJO_SYSTEM_EXPORT MojoResult MojoUnmapBuffer(void* buffer);  // In.
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // MOJO_PUBLIC_C_SYSTEM_BUFFER_H_
diff --git a/mojo/public/c/system/core.h b/mojo/public/c/system/core.h
new file mode 100644
index 0000000..0e78786
--- /dev/null
+++ b/mojo/public/c/system/core.h
@@ -0,0 +1,21 @@
+// Copyright 2014 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 is a catch-all header that includes everything.
+//
+// Note: This header should be compilable as C.
+
+#ifndef MOJO_PUBLIC_C_SYSTEM_CORE_H_
+#define MOJO_PUBLIC_C_SYSTEM_CORE_H_
+
+#include "mojo/public/c/system/buffer.h"
+#include "mojo/public/c/system/data_pipe.h"
+#include "mojo/public/c/system/functions.h"
+#include "mojo/public/c/system/macros.h"
+#include "mojo/public/c/system/main.h"
+#include "mojo/public/c/system/message_pipe.h"
+#include "mojo/public/c/system/system_export.h"
+#include "mojo/public/c/system/types.h"
+
+#endif  // MOJO_PUBLIC_C_SYSTEM_CORE_H_
diff --git a/mojo/public/c/system/data_pipe.h b/mojo/public/c/system/data_pipe.h
new file mode 100644
index 0000000..c8087ea
--- /dev/null
+++ b/mojo/public/c/system/data_pipe.h
@@ -0,0 +1,364 @@
+// Copyright 2014 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 types/constants and functions specific to data pipes.
+//
+// Note: This header should be compilable as C.
+
+#ifndef MOJO_PUBLIC_C_SYSTEM_DATA_PIPE_H_
+#define MOJO_PUBLIC_C_SYSTEM_DATA_PIPE_H_
+
+#include "mojo/public/c/system/macros.h"
+#include "mojo/public/c/system/system_export.h"
+#include "mojo/public/c/system/types.h"
+
+// |MojoCreateDataPipeOptions|: Used to specify creation parameters for a data
+// pipe to |MojoCreateDataPipe()|.
+//   |uint32_t struct_size|: Set to the size of the |MojoCreateDataPipeOptions|
+//       struct. (Used to allow for future extensions.)
+//   |MojoCreateDataPipeOptionsFlags flags|: Used to specify different modes of
+//       operation.
+//     |MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE|: No flags; default mode.
+//     |MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD|: May discard data for
+//         whatever reason; best-effort delivery. In particular, if the capacity
+//         is reached, old data may be discard to make room for new data.
+//   |uint32_t element_num_bytes|: The size of an element, in bytes. All
+//       transactions and buffers will consist of an integral number of
+//       elements. Must be nonzero.
+//   |uint32_t capacity_num_bytes|: The capacity of the data pipe, in number of
+//       bytes; must be a multiple of |element_num_bytes|. The data pipe will
+//       always be able to queue AT LEAST this much data. Set to zero to opt for
+//       a system-dependent automatically-calculated capacity (which will always
+//       be at least one element).
+
+typedef uint32_t MojoCreateDataPipeOptionsFlags;
+
+#ifdef __cplusplus
+const MojoCreateDataPipeOptionsFlags MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE =
+    0;
+const MojoCreateDataPipeOptionsFlags
+    MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD = 1 << 0;
+#else
+#define MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE \
+  ((MojoCreateDataPipeOptionsFlags)0)
+#define MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD \
+  ((MojoCreateDataPipeOptionsFlags)1 << 0)
+#endif
+
+MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int64_t) == 8, int64_t_has_weird_alignment);
+struct MOJO_ALIGNAS(8) MojoCreateDataPipeOptions {
+  uint32_t struct_size;
+  MojoCreateDataPipeOptionsFlags flags;
+  uint32_t element_num_bytes;
+  uint32_t capacity_num_bytes;
+};
+MOJO_COMPILE_ASSERT(sizeof(MojoCreateDataPipeOptions) == 16,
+                    MojoCreateDataPipeOptions_has_wrong_size);
+
+// |MojoWriteDataFlags|: Used to specify different modes to |MojoWriteData()|
+// and |MojoBeginWriteData()|.
+//   |MOJO_WRITE_DATA_FLAG_NONE| - No flags; default mode.
+//   |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| - Write either all the elements
+//       requested or none of them.
+
+typedef uint32_t MojoWriteDataFlags;
+
+#ifdef __cplusplus
+const MojoWriteDataFlags MOJO_WRITE_DATA_FLAG_NONE = 0;
+const MojoWriteDataFlags MOJO_WRITE_DATA_FLAG_ALL_OR_NONE = 1 << 0;
+#else
+#define MOJO_WRITE_DATA_FLAG_NONE ((MojoWriteDataFlags)0)
+#define MOJO_WRITE_DATA_FLAG_ALL_OR_NONE ((MojoWriteDataFlags)1 << 0)
+#endif
+
+// |MojoReadDataFlags|: Used to specify different modes to |MojoReadData()| and
+// |MojoBeginReadData()|.
+//   |MOJO_READ_DATA_FLAG_NONE| - No flags; default mode.
+//   |MOJO_READ_DATA_FLAG_ALL_OR_NONE| - Read (or discard) either the requested
+//        number of elements or none.
+//   |MOJO_READ_DATA_FLAG_DISCARD| - Discard (up to) the requested number of
+//        elements.
+//   |MOJO_READ_DATA_FLAG_QUERY| - Query the number of elements available to
+//       read. For use with |MojoReadData()| only. Mutually exclusive with
+//       |MOJO_READ_DATA_FLAG_DISCARD| and |MOJO_READ_DATA_FLAG_ALL_OR_NONE| is
+//       ignored if this flag is set.
+
+typedef uint32_t MojoReadDataFlags;
+
+#ifdef __cplusplus
+const MojoReadDataFlags MOJO_READ_DATA_FLAG_NONE = 0;
+const MojoReadDataFlags MOJO_READ_DATA_FLAG_ALL_OR_NONE = 1 << 0;
+const MojoReadDataFlags MOJO_READ_DATA_FLAG_DISCARD = 1 << 1;
+const MojoReadDataFlags MOJO_READ_DATA_FLAG_QUERY = 1 << 2;
+#else
+#define MOJO_READ_DATA_FLAG_NONE ((MojoReadDataFlags)0)
+#define MOJO_READ_DATA_FLAG_ALL_OR_NONE ((MojoReadDataFlags)1 << 0)
+#define MOJO_READ_DATA_FLAG_DISCARD ((MojoReadDataFlags)1 << 1)
+#define MOJO_READ_DATA_FLAG_QUERY ((MojoReadDataFlags)1 << 2)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Note: See the comment in functions.h about the meaning of the "optional"
+// label for pointer parameters.
+
+// Creates a data pipe, which is a unidirectional communication channel for
+// unframed data, with the given options. Data is unframed, but must come as
+// (multiples of) discrete elements, of the size given in |options|. See
+// |MojoCreateDataPipeOptions| for a description of the different options
+// available for data pipes.
+//
+// |options| may be set to null for a data pipe with the default options (which
+// will have an element size of one byte and have some system-dependent
+// capacity).
+//
+// On success, |*data_pipe_producer_handle| will be set to the handle for the
+// producer and |*data_pipe_consumer_handle| will be set to the handle for the
+// consumer. (On failure, they are not modified.)
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
+//       |*options| is invalid).
+//   |MOJO_RESULT_RESOURCE_EXHAUSTED| if a process/system/quota/etc. limit has
+//       been reached (e.g., if the requested capacity was too large, or if the
+//       maximum number of handles was exceeded).
+//   |MOJO_RESULT_UNIMPLEMENTED| if an unsupported flag was set in |*options|.
+MOJO_SYSTEM_EXPORT MojoResult MojoCreateDataPipe(
+    const struct MojoCreateDataPipeOptions* options,  // Optional.
+    MojoHandle* data_pipe_producer_handle,            // Out.
+    MojoHandle* data_pipe_consumer_handle);           // Out.
+
+// Writes the given data to the data pipe producer given by
+// |data_pipe_producer_handle|. |elements| points to data of size |*num_bytes|;
+// |*num_bytes| should be a multiple of the data pipe's element size. If
+// |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| is set in |flags|, either all the data
+// will be written or none is.
+//
+// On success, |*num_bytes| is set to the amount of data that was actually
+// written.
+//
+// Note: If the data pipe has the "may discard" option flag (specified on
+// creation), this will discard as much data as required to write the given
+// data, starting with the earliest written data that has not been consumed.
+// However, even with "may discard", if |*num_bytes| is greater than the data
+// pipe's capacity (and |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| is not set), this
+// will write the maximum amount possible (namely, the data pipe's capacity) and
+// set |*num_bytes| to that amount. It will *not* discard data from |elements|.
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
+//       |data_pipe_producer_dispatcher| is not a handle to a data pipe
+//       producer or |*num_bytes| is not a multiple of the data pipe's element
+//       size).
+//   |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe consumer handle has been
+//       closed.
+//   |MOJO_RESULT_OUT_OF_RANGE| if |flags| has
+//       |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| set and the required amount of data
+//       (specified by |*num_bytes|) could not be written.
+//   |MOJO_RESULT_BUSY| if there is a two-phase write ongoing with
+//       |data_pipe_producer_handle| (i.e., |MojoBeginWriteData()| has been
+//       called, but not yet the matching |MojoEndWriteData()|).
+//   |MOJO_RESULT_SHOULD_WAIT| if no data can currently be written (and the
+//       consumer is still open) and |flags| does *not* have
+//       |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| set.
+//
+// TODO(vtl): Should there be a way of querying how much data can be written?
+MOJO_SYSTEM_EXPORT MojoResult
+    MojoWriteData(MojoHandle data_pipe_producer_handle,
+                  const void* elements,
+                  uint32_t* num_bytes,  // In/out.
+                  MojoWriteDataFlags flags);
+
+// Begins a two-phase write to the data pipe producer given by
+// |data_pipe_producer_handle|. On success, |*buffer| will be a pointer to which
+// the caller can write |*buffer_num_bytes| bytes of data. If flags has
+// |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| set, then the output value
+// |*buffer_num_bytes| will be at least as large as its input value, which must
+// also be a multiple of the element size (if |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE|
+// is not set, the input value of |*buffer_num_bytes| is ignored).
+//
+// During a two-phase write, |data_pipe_producer_handle| is *not* writable.
+// E.g., if another thread tries to write to it, it will get |MOJO_RESULT_BUSY|;
+// that thread can then wait for |data_pipe_producer_handle| to become writable
+// again.
+//
+// Once the caller has finished writing data to |*buffer|, it should call
+// |MojoEndWriteData()| to specify the amount written and to complete the
+// two-phase write.
+//
+// Note: If the data pipe has the "may discard" option flag (specified on
+// creation) and |flags| has |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| set, this may
+// discard some data.
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
+//       |data_pipe_producer_handle| is not a handle to a data pipe producer or
+//       flags has |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| set and
+//       |*buffer_num_bytes| is not a multiple of the element size).
+//   |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe consumer handle has been
+//       closed.
+//   |MOJO_RESULT_OUT_OF_RANGE| if |flags| has
+//       |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| set and the required amount of data
+//       (specified by |*buffer_num_bytes|) cannot be written contiguously at
+//       this time. (Note that there may be space available for the required
+//       amount of data, but the "next" write position may not be large enough.)
+//   |MOJO_RESULT_BUSY| if there is already a two-phase write ongoing with
+//       |data_pipe_producer_handle| (i.e., |MojoBeginWriteData()| has been
+//       called, but not yet the matching |MojoEndWriteData()|).
+//   |MOJO_RESULT_SHOULD_WAIT| if no data can currently be written (and the
+//       consumer is still open).
+MOJO_SYSTEM_EXPORT MojoResult
+    MojoBeginWriteData(MojoHandle data_pipe_producer_handle,
+                       void** buffer,               // Out.
+                       uint32_t* buffer_num_bytes,  // In/out.
+                       MojoWriteDataFlags flags);
+
+// Ends a two-phase write to the data pipe producer given by
+// |data_pipe_producer_handle| that was begun by a call to
+// |MojoBeginWriteData()| on the same handle. |num_bytes_written| should
+// indicate the amount of data actually written; it must be less than or equal
+// to the value of |*buffer_num_bytes| output by |MojoBeginWriteData()| and must
+// be a multiple of the element size. The buffer given by |*buffer| from
+// |MojoBeginWriteData()| must have been filled with exactly |num_bytes_written|
+// bytes of data.
+//
+// On failure, the two-phase write (if any) is ended (so the handle may become
+// writable again, if there's space available) but no data written to |*buffer|
+// is "put into" the data pipe.
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
+//       |data_pipe_producer_handle| is not a handle to a data pipe producer or
+//       |num_bytes_written| is invalid (greater than the maximum value provided
+//       by |MojoBeginWriteData()| or not a multiple of the element size).
+//   |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe producer is not in a
+//       two-phase write (e.g., |MojoBeginWriteData()| was not called or
+//       |MojoEndWriteData()| has already been called).
+MOJO_SYSTEM_EXPORT MojoResult
+    MojoEndWriteData(MojoHandle data_pipe_producer_handle,
+                     uint32_t num_bytes_written);
+
+// Reads data from the data pipe consumer given by |data_pipe_consumer_handle|.
+// May also be used to discard data or query the amount of data available.
+//
+// If |flags| has neither |MOJO_READ_DATA_FLAG_DISCARD| nor
+// |MOJO_READ_DATA_FLAG_QUERY| set, this tries to read up to |*num_bytes| (which
+// must be a multiple of the data pipe's element size) bytes of data to
+// |elements| and set |*num_bytes| to the amount actually read. If flags has
+// |MOJO_READ_DATA_FLAG_ALL_OR_NONE| set, it will either read exactly
+// |*num_bytes| bytes of data or none.
+//
+// If flags has |MOJO_READ_DATA_FLAG_DISCARD| set, it discards up to
+// |*num_bytes| (which again be a multiple of the element size) bytes of data,
+// setting |*num_bytes| to the amount actually discarded. If flags has
+// |MOJO_READ_DATA_FLAG_ALL_OR_NONE|, it will either discard exactly
+// |*num_bytes| bytes of data or none. In this case, |MOJO_READ_DATA_FLAG_QUERY|
+// must not be set, and |elements| is ignored (and should typically be set to
+// null).
+//
+// If flags has |MOJO_READ_DATA_FLAG_QUERY| set, it queries the amount of data
+// available, setting |*num_bytes| to the number of bytes available. In this
+// case, |MOJO_READ_DATA_FLAG_DISCARD| must not be set, and
+// |MOJO_READ_DATA_FLAG_ALL_OR_NONE| is ignored, as are |elements| and the input
+// value of |*num_bytes|.
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success (see above for a description of the different
+//       operations).
+//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
+//       |data_pipe_consumer_handle| is invalid, the combination of flags in
+//       |flags| is invalid, etc.).
+//   |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe producer handle has been
+//       closed and data (or the required amount of data) was not available to
+//       be read or discarded.
+//   |MOJO_RESULT_OUT_OF_RANGE| if |flags| has |MOJO_READ_DATA_FLAG_ALL_OR_NONE|
+//       set and the required amount of data is not available to be read or
+//       discarded (and the producer is still open).
+//   |MOJO_RESULT_BUSY| if there is a two-phase read ongoing with
+//       |data_pipe_consumer_handle| (i.e., |MojoBeginReadData()| has been
+//       called, but not yet the matching |MojoEndReadData()|).
+//   |MOJO_RESULT_SHOULD_WAIT| if there is no data to be read or discarded (and
+//       the producer is still open) and |flags| does *not* have
+//       |MOJO_READ_DATA_FLAG_ALL_OR_NONE| set.
+MOJO_SYSTEM_EXPORT MojoResult MojoReadData(MojoHandle data_pipe_consumer_handle,
+                                           void* elements,       // Out.
+                                           uint32_t* num_bytes,  // In/out.
+                                           MojoReadDataFlags flags);
+
+// Begins a two-phase read from the data pipe consumer given by
+// |data_pipe_consumer_handle|. On success, |*buffer| will be a pointer from
+// which the caller can read |*buffer_num_bytes| bytes of data. If flags has
+// |MOJO_READ_DATA_FLAG_ALL_OR_NONE| set, then the output value
+// |*buffer_num_bytes| will be at least as large as its input value, which must
+// also be a multiple of the element size (if |MOJO_READ_DATA_FLAG_ALL_OR_NONE|
+// is not set, the input value of |*buffer_num_bytes| is ignored). |flags| must
+// not have |MOJO_READ_DATA_FLAG_DISCARD| or |MOJO_READ_DATA_FLAG_QUERY| set.
+//
+// During a two-phase read, |data_pipe_consumer_handle| is *not* readable.
+// E.g., if another thread tries to read from it, it will get
+// |MOJO_RESULT_BUSY|; that thread can then wait for |data_pipe_consumer_handle|
+// to become readable again.
+//
+// Once the caller has finished reading data from |*buffer|, it should call
+// |MojoEndReadData()| to specify the amount read and to complete the two-phase
+// read.
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
+//       |data_pipe_consumer_handle| is not a handle to a data pipe consumer,
+//       |flags| has |MOJO_READ_DATA_FLAG_ALL_OR_NONE| set and
+//       |*buffer_num_bytes| is not a multiple of the element size, or |flags|
+//       has invalid flags set).
+//   |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe producer handle has been
+//       closed.
+//   |MOJO_RESULT_OUT_OF_RANGE| if |flags| has |MOJO_READ_DATA_FLAG_ALL_OR_NONE|
+//       set and the required amount of data (specified by |*buffer_num_bytes|)
+//       cannot be read from a contiguous buffer at this time. (Note that there
+//       may be the required amount of data, but it may not be contiguous.)
+//   |MOJO_RESULT_BUSY| if there is already a two-phase read ongoing with
+//       |data_pipe_consumer_handle| (i.e., |MojoBeginReadData()| has been
+//       called, but not yet the matching |MojoEndReadData()|).
+//   |MOJO_RESULT_SHOULD_WAIT| if no data can currently be read (and the
+//       producer is still open).
+MOJO_SYSTEM_EXPORT MojoResult
+    MojoBeginReadData(MojoHandle data_pipe_consumer_handle,
+                      const void** buffer,         // Out.
+                      uint32_t* buffer_num_bytes,  // In/out.
+                      MojoReadDataFlags flags);
+
+// Ends a two-phase read from the data pipe consumer given by
+// |data_pipe_consumer_handle| that was begun by a call to |MojoBeginReadData()|
+// on the same handle. |num_bytes_read| should indicate the amount of data
+// actually read; it must be less than or equal to the value of
+// |*buffer_num_bytes| output by |MojoBeginReadData()| and must be a multiple of
+// the element size.
+//
+// On failure, the two-phase read (if any) is ended (so the handle may become
+// readable again) but no data is "removed" from the data pipe.
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
+//       |data_pipe_consumer_handle| is not a handle to a data pipe consumer or
+//       |num_bytes_written| is greater than the maximum value provided by
+//       |MojoBeginReadData()| or not a multiple of the element size).
+//   |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe consumer is not in a
+//       two-phase read (e.g., |MojoBeginReadData()| was not called or
+//       |MojoEndReadData()| has already been called).
+MOJO_SYSTEM_EXPORT MojoResult
+    MojoEndReadData(MojoHandle data_pipe_consumer_handle,
+                    uint32_t num_bytes_read);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // MOJO_PUBLIC_C_SYSTEM_DATA_PIPE_H_
diff --git a/mojo/public/c/system/functions.h b/mojo/public/c/system/functions.h
new file mode 100644
index 0000000..6045f2f
--- /dev/null
+++ b/mojo/public/c/system/functions.h
@@ -0,0 +1,108 @@
+// Copyright 2014 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 basic functions common to different Mojo system APIs.
+//
+// Note: This header should be compilable as C.
+
+#ifndef MOJO_PUBLIC_C_SYSTEM_FUNCTIONS_H_
+#define MOJO_PUBLIC_C_SYSTEM_FUNCTIONS_H_
+
+// Note: This header should be compilable as C.
+
+#include "mojo/public/c/system/system_export.h"
+#include "mojo/public/c/system/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Note: Pointer parameters that are labelled "optional" may be null (at least
+// under some circumstances). Non-const pointer parameters are also labeled
+// "in", "out", or "in/out", to indicate how they are used. (Note that how/if
+// such a parameter is used may depend on other parameters or the requested
+// operation's success/failure. E.g., a separate |flags| parameter may control
+// whether a given "in/out" parameter is used for input, output, or both.)
+
+// Platform-dependent monotonically increasing tick count representing "right
+// now." The resolution of this clock is ~1-15ms.  Resolution varies depending
+// on hardware/operating system configuration.
+MOJO_SYSTEM_EXPORT MojoTimeTicks MojoGetTimeTicksNow(void);
+
+// Closes the given |handle|.
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if |handle| is not a valid handle.
+//
+// Concurrent operations on |handle| may succeed (or fail as usual) if they
+// happen before the close, be cancelled with result |MOJO_RESULT_CANCELLED| if
+// they properly overlap (this is likely the case with |MojoWait()|, etc.), or
+// fail with |MOJO_RESULT_INVALID_ARGUMENT| if they happen after.
+MOJO_SYSTEM_EXPORT MojoResult MojoClose(MojoHandle handle);
+
+// Waits on the given handle until a signal indicated by |signals| is satisfied,
+// it becomes known that no signal indicated by |signals| will ever be satisfied
+// (see the description of the |MOJO_RESULT_CANCELLED| and
+// |MOJO_RESULT_FAILED_PRECONDITION| return values below), or until |deadline|
+// has passed.
+//
+// If |deadline| is |MOJO_DEADLINE_INDEFINITE|, this will wait "forever" (until
+// one of the other wait termination conditions is satisfied). If |deadline| is
+// 0, this will return |MOJO_RESULT_DEADLINE_EXCEEDED| only if one of the other
+// termination conditions (e.g., a signal is satisfied, or all signals are
+// unsatisfiable) is not already satisfied.
+//
+// Returns:
+//   |MOJO_RESULT_OK| if some signal in |signals| was satisfied (or is already
+//       satisfied).
+//   |MOJO_RESULT_CANCELLED| if |handle| was closed (necessarily from another
+//       thread) during the wait.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if |handle| is not a valid handle (e.g., if
+//       it has already been closed).
+//   |MOJO_RESULT_DEADLINE_EXCEEDED| if the deadline has passed without any of
+//       the signals being satisfied.
+//   |MOJO_RESULT_FAILED_PRECONDITION| if it becomes known that none of the
+//       signals in |signals| can ever be satisfied (e.g., when waiting on one
+//       end of a message pipe and the other end is closed).
+//
+// If there are multiple waiters (on different threads, obviously) waiting on
+// the same handle and signal, and that signal becomes is satisfied, all waiters
+// will be awoken.
+MOJO_SYSTEM_EXPORT MojoResult MojoWait(MojoHandle handle,
+                                       MojoHandleSignals signals,
+                                       MojoDeadline deadline);
+
+// Waits on |handles[0]|, ..., |handles[num_handles-1]| until (at least) one
+// satisfies a signal indicated in its respective |signals[0]|, ...,
+// |signals[num_handles-1]|, it becomes known that no signal in some
+// |signals[i]| will ever be satisfied, or until |deadline| has passed.
+//
+// This means that |MojoWaitMany()| behaves as if |MojoWait()| were called on
+// each handle/signals pair simultaneously, completing when the first
+// |MojoWait()| would complete.
+//
+// See |MojoWait()| for more details about |deadline|.
+//
+// Returns:
+//   The index |i| (from 0 to |num_handles-1|) if |handle[i]| satisfies a signal
+//       from |signals[i]|.
+//   |MOJO_RESULT_CANCELLED| if some |handle[i]| was closed (necessarily from
+//       another thread) during the wait.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if some |handle[i]| is not a valid handle
+//       (e.g., if it has already been closed).
+//   |MOJO_RESULT_DEADLINE_EXCEEDED| if the deadline has passed without any of
+//       handles satisfying any of its signals.
+//   |MOJO_RESULT_FAILED_PRECONDITION| if it is or becomes impossible that SOME
+//       |handle[i]| will ever satisfy any of the signals in |signals[i]|.
+MOJO_SYSTEM_EXPORT MojoResult MojoWaitMany(const MojoHandle* handles,
+                                           const MojoHandleSignals* signals,
+                                           uint32_t num_handles,
+                                           MojoDeadline deadline);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // MOJO_PUBLIC_C_SYSTEM_FUNCTIONS_H_
diff --git a/mojo/public/c/system/macros.h b/mojo/public/c/system/macros.h
new file mode 100644
index 0000000..564ee60
--- /dev/null
+++ b/mojo/public/c/system/macros.h
@@ -0,0 +1,89 @@
+// Copyright 2014 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_C_SYSTEM_MACROS_H_
+#define MOJO_PUBLIC_C_SYSTEM_MACROS_H_
+
+#include <stddef.h>
+
+// Annotate a variable indicating it's okay if it's unused.
+// Use like:
+//   int x MOJO_ALLOW_UNUSED = ...;
+#if defined(__GNUC__)
+#define MOJO_ALLOW_UNUSED __attribute__((unused))
+#else
+#define MOJO_ALLOW_UNUSED
+#endif
+
+// Annotate a function indicating that the caller must examine the return value.
+// Use like:
+//   int foo() MOJO_WARN_UNUSED_RESULT;
+// Note that it can only be used on the prototype, and not the definition.
+#if defined(__GNUC__)
+#define MOJO_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#define MOJO_WARN_UNUSED_RESULT
+#endif
+
+#ifdef __cplusplus
+// Used to explicitly mark the return value of a function as unused. If you are
+// really sure you don't want to do anything with the return value of a function
+// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example:
+//
+//   scoped_ptr<MyType> my_var = ...;
+//   if (TakeOwnership(my_var.get()) == SUCCESS)
+//     mojo_ignore_result(my_var.release());
+//
+template <typename T>
+inline void mojo_ignore_result(const T&) {
+}
+#endif
+
+// Assert things at compile time. (|msg| should be a valid identifier name.)
+// This macro is currently C++-only, but we want to use it in the C core.h.
+// Use like:
+//   MOJO_COMPILE_ASSERT(sizeof(Foo) == 12, Foo_has_invalid_size);
+#if __cplusplus >= 201103L
+#define MOJO_COMPILE_ASSERT(expr, msg) static_assert(expr, #msg)
+#elif defined(__cplusplus)
+namespace mojo {
+template <bool>
+struct CompileAssert {};
+}
+#define MOJO_COMPILE_ASSERT(expr, msg) \
+  typedef ::mojo::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+#else
+#define MOJO_COMPILE_ASSERT(expr, msg)
+#endif
+
+// Like the C++11 |alignof| operator.
+#if __cplusplus >= 201103L
+#define MOJO_ALIGNOF(type) alignof(type)
+#elif defined(__GNUC__)
+#define MOJO_ALIGNOF(type) __alignof__(type)
+#elif defined(_MSC_VER)
+// The use of |sizeof| is to work around a bug in MSVC 2010 (see
+// http://goo.gl/isH0C; supposedly fixed since then).
+#define MOJO_ALIGNOF(type) (sizeof(type) - sizeof(type) + __alignof(type))
+#else
+#error "Please define MOJO_ALIGNOF() for your compiler."
+#endif
+
+// Specify the alignment of a |struct|, etc.
+// Use like:
+//   struct MOJO_ALIGNAS(8) Foo { ... };
+// Unlike the C++11 |alignas()|, |alignment| must be an integer. It may not be a
+// type, nor can it be an expression like |MOJO_ALIGNOF(type)| (due to the
+// non-C++11 MSVS version).
+#if __cplusplus >= 201103L
+#define MOJO_ALIGNAS(alignment) alignas(alignment)
+#elif defined(__GNUC__)
+#define MOJO_ALIGNAS(alignment) __attribute__((aligned(alignment)))
+#elif defined(_MSC_VER)
+#define MOJO_ALIGNAS(alignment) __declspec(align(alignment))
+#else
+#error "Please define MOJO_ALIGNAS() for your compiler."
+#endif
+
+#endif  // MOJO_PUBLIC_C_SYSTEM_MACROS_H_
diff --git a/mojo/public/c/system/main.h b/mojo/public/c/system/main.h
new file mode 100644
index 0000000..31e2012
--- /dev/null
+++ b/mojo/public/c/system/main.h
@@ -0,0 +1,35 @@
+// Copyright 2014 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_C_SYSTEM_MAIN_H_
+#define MOJO_PUBLIC_C_SYSTEM_MAIN_H_
+
+#include "mojo/public/c/system/types.h"
+
+// Implement MojoMain directly as the entry point for an application.
+//
+// MojoResult MojoMain(MojoHandle service_provider_handle) {
+//   ...
+// }
+//
+// TODO(davemoore): Establish this as part of our SDK for third party mojo
+// application writers.
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if defined(WIN32)
+__declspec(dllexport) MojoResult
+    __cdecl MojoMain(MojoHandle service_provider_handle);
+#else  // !defined(WIN32)
+__attribute__((visibility("default"))) MojoResult
+    MojoMain(MojoHandle service_provider_handle);
+#endif  // defined(WIN32)
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // MOJO_PUBLIC_C_SYSTEM_MAIN_H_
diff --git a/mojo/public/c/system/message_pipe.h b/mojo/public/c/system/message_pipe.h
new file mode 100644
index 0000000..b08ba75
--- /dev/null
+++ b/mojo/public/c/system/message_pipe.h
@@ -0,0 +1,179 @@
+// Copyright 2014 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 types/constants and functions specific to message pipes.
+//
+// Note: This header should be compilable as C.
+
+#ifndef MOJO_PUBLIC_C_SYSTEM_MESSAGE_PIPE_H_
+#define MOJO_PUBLIC_C_SYSTEM_MESSAGE_PIPE_H_
+
+#include "mojo/public/c/system/macros.h"
+#include "mojo/public/c/system/system_export.h"
+#include "mojo/public/c/system/types.h"
+
+// |MojoCreateMessagePipeOptions|: Used to specify creation parameters for a
+// message pipe to |MojoCreateMessagePipe()|.
+//   |uint32_t struct_size|: Set to the size of the
+//       |MojoCreateMessagePipeOptions| struct. (Used to allow for future
+//       extensions.)
+//   |MojoCreateMessagePipeOptionsFlags flags|: Reserved for future use.
+//       |MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE|: No flags; default mode.
+
+typedef uint32_t MojoCreateMessagePipeOptionsFlags;
+
+#ifdef __cplusplus
+const MojoCreateMessagePipeOptionsFlags
+    MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE = 0;
+#else
+#define MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE \
+  ((MojoCreateMessagePipeOptionsFlags)0)
+#endif
+
+MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int64_t) == 8, int64_t_has_weird_alignment);
+struct MOJO_ALIGNAS(8) MojoCreateMessagePipeOptions {
+  uint32_t struct_size;
+  MojoCreateMessagePipeOptionsFlags flags;
+};
+MOJO_COMPILE_ASSERT(sizeof(MojoCreateMessagePipeOptions) == 8,
+                    MojoCreateMessagePipeOptions_has_wrong_size);
+
+// |MojoWriteMessageFlags|: Used to specify different modes to
+// |MojoWriteMessage()|.
+//   |MOJO_WRITE_MESSAGE_FLAG_NONE| - No flags; default mode.
+
+typedef uint32_t MojoWriteMessageFlags;
+
+#ifdef __cplusplus
+const MojoWriteMessageFlags MOJO_WRITE_MESSAGE_FLAG_NONE = 0;
+#else
+#define MOJO_WRITE_MESSAGE_FLAG_NONE ((MojoWriteMessageFlags)0)
+#endif
+
+// |MojoReadMessageFlags|: Used to specify different modes to
+// |MojoReadMessage()|.
+//   |MOJO_READ_MESSAGE_FLAG_NONE| - No flags; default mode.
+//   |MOJO_READ_MESSAGE_FLAG_MAY_DISCARD| - If the message is unable to be read
+//       for whatever reason (e.g., the caller-supplied buffer is too small),
+//       discard the message (i.e., simply dequeue it).
+
+typedef uint32_t MojoReadMessageFlags;
+
+#ifdef __cplusplus
+const MojoReadMessageFlags MOJO_READ_MESSAGE_FLAG_NONE = 0;
+const MojoReadMessageFlags MOJO_READ_MESSAGE_FLAG_MAY_DISCARD = 1 << 0;
+#else
+#define MOJO_READ_MESSAGE_FLAG_NONE ((MojoReadMessageFlags)0)
+#define MOJO_READ_MESSAGE_FLAG_MAY_DISCARD ((MojoReadMessageFlags)1 << 0)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Note: See the comment in functions.h about the meaning of the "optional"
+// label for pointer parameters.
+
+// Creates a message pipe, which is a bidirectional communication channel for
+// framed data (i.e., messages). Messages can contain plain data and/or Mojo
+// handles.
+//
+// |options| may be set to null for a message pipe with the default options.
+//
+// On success, |*message_pipe_handle0| and |*message_pipe_handle1| are set to
+// handles for the two endpoints (ports) for the message pipe.
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
+//       |*options| is invalid).
+//   |MOJO_RESULT_RESOURCE_EXHAUSTED| if a process/system/quota/etc. limit has
+//       been reached.
+//
+// TODO(vtl): Add an options struct pointer argument.
+MOJO_SYSTEM_EXPORT MojoResult MojoCreateMessagePipe(
+    const struct MojoCreateMessagePipeOptions* options,  // Optional.
+    MojoHandle* message_pipe_handle0,                    // Out.
+    MojoHandle* message_pipe_handle1);                   // Out.
+
+// Writes a message to the message pipe endpoint given by |message_pipe_handle|,
+// with message data specified by |bytes| of size |num_bytes| and attached
+// handles specified by |handles| of count |num_handles|, and options specified
+// by |flags|. If there is no message data, |bytes| may be null, in which case
+// |num_bytes| must be zero. If there are no attached handles, |handles| may be
+// null, in which case |num_handles| must be zero.
+//
+// If handles are attached, on success the handles will no longer be valid (the
+// receiver will receive equivalent, but logically different, handles). Handles
+// to be sent should not be in simultaneous use (e.g., on another thread).
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success (i.e., the message was enqueued).
+//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g., if
+//       |message_pipe_handle| is not a valid handle, or some of the
+//       requirements above are not satisfied).
+//   |MOJO_RESULT_RESOURCE_EXHAUSTED| if some system limit has been reached, or
+//       the number of handles to send is too large (TODO(vtl): reconsider the
+//       latter case).
+//   |MOJO_RESULT_FAILED_PRECONDITION| if the other endpoint has been closed.
+//       Note that closing an endpoint is not necessarily synchronous (e.g.,
+//       across processes), so this function may be succeed even if the other
+//       endpoint has been closed (in which case the message would be dropped).
+//   |MOJO_RESULT_UNIMPLEMENTED| if an unsupported flag was set in |*options|.
+//   |MOJO_RESULT_BUSY| if some handle to be sent is currently in use.
+//
+// TODO(vtl): Add a notion of capacity for message pipes, and return
+// |MOJO_RESULT_SHOULD_WAIT| if the message pipe is full.
+MOJO_SYSTEM_EXPORT MojoResult
+    MojoWriteMessage(MojoHandle message_pipe_handle,
+                     const void* bytes,  // Optional.
+                     uint32_t num_bytes,
+                     const MojoHandle* handles,  // Optional.
+                     uint32_t num_handles,
+                     MojoWriteMessageFlags flags);
+
+// Reads a message from the message pipe endpoint given by
+// |message_pipe_handle|; also usable to query the size of the next message or
+// discard the next message. |bytes|/|*num_bytes| indicate the buffer/buffer
+// size to receive the message data (if any) and |handles|/|*num_handles|
+// indicate the buffer/maximum handle count to receive the attached handles (if
+// any).
+//
+// |num_bytes| and |num_handles| are optional "in-out" parameters. If non-null,
+// on return |*num_bytes| and |*num_handles| will usually indicate the number
+// of bytes and number of attached handles in the "next" message, respectively,
+// whether that message was read or not. (If null, the number of bytes/handles
+// is treated as zero.)
+//
+// If |bytes| is null, then |*num_bytes| must be zero, and similarly for
+// |handles| and |*num_handles|.
+//
+// Partial reads are NEVER done. Either a full read is done and |MOJO_RESULT_OK|
+// returned, or the read is NOT done and |MOJO_RESULT_RESOURCE_EXHAUSTED| is
+// returned (if |MOJO_READ_MESSAGE_FLAG_MAY_DISCARD| was set, the message is
+// also discarded in this case).
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success (i.e., a message was actually read).
+//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid.
+//   |MOJO_RESULT_FAILED_PRECONDITION| if the other endpoint has been closed.
+//   |MOJO_RESULT_RESOURCE_EXHAUSTED| if one of the buffers to receive the
+//       message/attached handles (|bytes|/|*num_bytes| or
+//       |handles|/|*num_handles|) was too small. (TODO(vtl): Reconsider this
+//       error code; should distinguish this from the hitting-system-limits
+//       case.)
+//   |MOJO_RESULT_SHOULD_WAIT| if no message was available to be read.
+MOJO_SYSTEM_EXPORT MojoResult
+    MojoReadMessage(MojoHandle message_pipe_handle,
+                    void* bytes,            // Optional out.
+                    uint32_t* num_bytes,    // Optional in/out.
+                    MojoHandle* handles,    // Optional out.
+                    uint32_t* num_handles,  // Optional in/out.
+                    MojoReadMessageFlags flags);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // MOJO_PUBLIC_C_SYSTEM_MESSAGE_PIPE_H_
diff --git a/mojo/public/c/system/system_export.h b/mojo/public/c/system/system_export.h
new file mode 100644
index 0000000..bc3b459
--- /dev/null
+++ b/mojo/public/c/system/system_export.h
@@ -0,0 +1,33 @@
+// Copyright 2014 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_C_SYSTEM_SYSTEM_EXPORT_H_
+#define MOJO_PUBLIC_C_SYSTEM_SYSTEM_EXPORT_H_
+
+#if defined(COMPONENT_BUILD) && defined(MOJO_USE_SYSTEM_IMPL)
+#if defined(WIN32)
+
+#if defined(MOJO_SYSTEM_IMPLEMENTATION)
+#define MOJO_SYSTEM_EXPORT __declspec(dllexport)
+#else
+#define MOJO_SYSTEM_EXPORT __declspec(dllimport)
+#endif
+
+#else  // !defined(WIN32)
+
+#if defined(MOJO_SYSTEM_IMPLEMENTATION)
+#define MOJO_SYSTEM_EXPORT __attribute__((visibility("default")))
+#else
+#define MOJO_SYSTEM_EXPORT
+#endif
+
+#endif  // defined(WIN32)
+
+#else  // !defined(COMPONENT_BUILD) || !defined(MOJO_USE_SYSTEM_IMPL)
+
+#define MOJO_SYSTEM_EXPORT
+
+#endif  // defined(COMPONENT_BUILD) && defined(MOJO_USE_SYSTEM_IMPL)
+
+#endif  // MOJO_PUBLIC_C_SYSTEM_SYSTEM_EXPORT_H_
diff --git a/mojo/public/c/system/tests/BUILD.gn b/mojo/public/c/system/tests/BUILD.gn
new file mode 100644
index 0000000..e9aa06f
--- /dev/null
+++ b/mojo/public/c/system/tests/BUILD.gn
@@ -0,0 +1,40 @@
+# Copyright 2014 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.
+
+source_set("tests") {
+  testonly = true
+  visibility = [ "//mojo/public/cpp/system/tests:mojo_public_system_unittests" ]
+
+  deps = [
+    "//mojo/public/c/environment",
+    "//mojo/public/c/system",
+    "//testing/gtest",
+  ]
+
+  sources = [
+    "core_unittest.cc",
+    "core_unittest_pure_c.c",
+    "macros_unittest.cc",
+  ]
+}
+
+# GYP version: mojo/mojo_public_tests.gypi:mojo_public_system_perftests
+executable("perftests") {
+  testonly = true
+  output_name = "mojo_public_system_perftests"
+
+  sources = [
+    "core_perftest.cc",
+  ]
+
+  deps = [
+    "//base",
+    "//mojo/common/test:run_all_perftests",
+    "//mojo/public/c/environment",
+    "//mojo/public/cpp/system",
+    "//mojo/public/cpp/test_support:test_utils",
+    "//mojo/public/cpp/utility",
+    "//testing/gtest",
+  ]
+}
diff --git a/mojo/public/c/system/tests/core_perftest.cc b/mojo/public/c/system/tests/core_perftest.cc
new file mode 100644
index 0000000..b9a8114
--- /dev/null
+++ b/mojo/public/c/system/tests/core_perftest.cc
@@ -0,0 +1,339 @@
+// Copyright 2013 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 tests the performance of the C API.
+
+#include "mojo/public/c/system/core.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "mojo/public/cpp/system/macros.h"
+#include "mojo/public/cpp/test_support/test_support.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// TODO(vtl): (here and below) crbug.com/342893
+#if !defined(WIN32)
+#include <time.h>
+#include "mojo/public/cpp/utility/thread.h"
+#endif  // !defined(WIN32)
+
+namespace {
+
+#if !defined(WIN32)
+class MessagePipeWriterThread : public mojo::Thread {
+ public:
+  MessagePipeWriterThread(MojoHandle handle, uint32_t num_bytes)
+      : handle_(handle), num_bytes_(num_bytes), num_writes_(0) {}
+  virtual ~MessagePipeWriterThread() {}
+
+  virtual void Run() override {
+    char buffer[10000];
+    assert(num_bytes_ <= sizeof(buffer));
+
+    // TODO(vtl): Should I throttle somehow?
+    for (;;) {
+      MojoResult result = MojoWriteMessage(
+          handle_, buffer, num_bytes_, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
+      if (result == MOJO_RESULT_OK) {
+        num_writes_++;
+        continue;
+      }
+
+      // We failed to write.
+      // Either |handle_| or its peer was closed.
+      assert(result == MOJO_RESULT_INVALID_ARGUMENT ||
+             result == MOJO_RESULT_FAILED_PRECONDITION);
+      break;
+    }
+  }
+
+  // Use only after joining the thread.
+  int64_t num_writes() const { return num_writes_; }
+
+ private:
+  const MojoHandle handle_;
+  const uint32_t num_bytes_;
+  int64_t num_writes_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipeWriterThread);
+};
+
+class MessagePipeReaderThread : public mojo::Thread {
+ public:
+  explicit MessagePipeReaderThread(MojoHandle handle)
+      : handle_(handle), num_reads_(0) {}
+  virtual ~MessagePipeReaderThread() {}
+
+  virtual void Run() override {
+    char buffer[10000];
+
+    for (;;) {
+      uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer));
+      MojoResult result = MojoReadMessage(
+          handle_, buffer, &num_bytes, NULL, NULL, MOJO_READ_MESSAGE_FLAG_NONE);
+      if (result == MOJO_RESULT_OK) {
+        num_reads_++;
+        continue;
+      }
+
+      if (result == MOJO_RESULT_SHOULD_WAIT) {
+        result = MojoWait(
+            handle_, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE);
+        if (result == MOJO_RESULT_OK) {
+          // Go to the top of the loop to read again.
+          continue;
+        }
+      }
+
+      // We failed to read and possibly failed to wait.
+      // Either |handle_| or its peer was closed.
+      assert(result == MOJO_RESULT_INVALID_ARGUMENT ||
+             result == MOJO_RESULT_FAILED_PRECONDITION);
+      break;
+    }
+  }
+
+  // Use only after joining the thread.
+  int64_t num_reads() const { return num_reads_; }
+
+ private:
+  const MojoHandle handle_;
+  int64_t num_reads_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipeReaderThread);
+};
+#endif  // !defined(WIN32)
+
+class CorePerftest : public testing::Test {
+ public:
+  CorePerftest() : buffer_(NULL), num_bytes_(0) {}
+  virtual ~CorePerftest() {}
+
+  static void NoOp(void* /*closure*/) {}
+
+  static void MessagePipe_CreateAndClose(void* closure) {
+    CorePerftest* self = static_cast<CorePerftest*>(closure);
+    MojoResult result MOJO_ALLOW_UNUSED;
+    result = MojoCreateMessagePipe(NULL, &self->h0_, &self->h1_);
+    assert(result == MOJO_RESULT_OK);
+    result = MojoClose(self->h0_);
+    assert(result == MOJO_RESULT_OK);
+    result = MojoClose(self->h1_);
+    assert(result == MOJO_RESULT_OK);
+  }
+
+  static void MessagePipe_WriteAndRead(void* closure) {
+    CorePerftest* self = static_cast<CorePerftest*>(closure);
+    MojoResult result MOJO_ALLOW_UNUSED;
+    result = MojoWriteMessage(self->h0_,
+                              self->buffer_,
+                              self->num_bytes_,
+                              NULL,
+                              0,
+                              MOJO_WRITE_MESSAGE_FLAG_NONE);
+    assert(result == MOJO_RESULT_OK);
+    uint32_t read_bytes = self->num_bytes_;
+    result = MojoReadMessage(self->h1_,
+                             self->buffer_,
+                             &read_bytes,
+                             NULL,
+                             NULL,
+                             MOJO_READ_MESSAGE_FLAG_NONE);
+    assert(result == MOJO_RESULT_OK);
+  }
+
+  static void MessagePipe_EmptyRead(void* closure) {
+    CorePerftest* self = static_cast<CorePerftest*>(closure);
+    MojoResult result MOJO_ALLOW_UNUSED;
+    result = MojoReadMessage(
+        self->h0_, NULL, NULL, NULL, NULL, MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
+    assert(result == MOJO_RESULT_SHOULD_WAIT);
+  }
+
+ protected:
+#if !defined(WIN32)
+  void DoMessagePipeThreadedTest(unsigned num_writers,
+                                 unsigned num_readers,
+                                 uint32_t num_bytes) {
+    static const int64_t kPerftestTimeMicroseconds = 3 * 1000000;
+
+    assert(num_writers > 0);
+    assert(num_readers > 0);
+
+    MojoResult result MOJO_ALLOW_UNUSED;
+    result = MojoCreateMessagePipe(NULL, &h0_, &h1_);
+    assert(result == MOJO_RESULT_OK);
+
+    std::vector<MessagePipeWriterThread*> writers;
+    for (unsigned i = 0; i < num_writers; i++)
+      writers.push_back(new MessagePipeWriterThread(h0_, num_bytes));
+
+    std::vector<MessagePipeReaderThread*> readers;
+    for (unsigned i = 0; i < num_readers; i++)
+      readers.push_back(new MessagePipeReaderThread(h1_));
+
+    // Start time here, just before we fire off the threads.
+    const MojoTimeTicks start_time = MojoGetTimeTicksNow();
+
+    // Interleave the starts.
+    for (unsigned i = 0; i < num_writers || i < num_readers; i++) {
+      if (i < num_writers)
+        writers[i]->Start();
+      if (i < num_readers)
+        readers[i]->Start();
+    }
+
+    Sleep(kPerftestTimeMicroseconds);
+
+    // Close both handles to make writers and readers stop immediately.
+    result = MojoClose(h0_);
+    assert(result == MOJO_RESULT_OK);
+    result = MojoClose(h1_);
+    assert(result == MOJO_RESULT_OK);
+
+    // Join everything.
+    for (unsigned i = 0; i < num_writers; i++)
+      writers[i]->Join();
+    for (unsigned i = 0; i < num_readers; i++)
+      readers[i]->Join();
+
+    // Stop time here.
+    MojoTimeTicks end_time = MojoGetTimeTicksNow();
+
+    // Add up write and read counts, and destroy the threads.
+    int64_t num_writes = 0;
+    for (unsigned i = 0; i < num_writers; i++) {
+      num_writes += writers[i]->num_writes();
+      delete writers[i];
+    }
+    writers.clear();
+    int64_t num_reads = 0;
+    for (unsigned i = 0; i < num_readers; i++) {
+      num_reads += readers[i]->num_reads();
+      delete readers[i];
+    }
+    readers.clear();
+
+    char test_name[200];
+    sprintf(test_name,
+            "MessagePipe_Threaded_Writes_%uw_%ur_%ubytes",
+            num_writers,
+            num_readers,
+            static_cast<unsigned>(num_bytes));
+    mojo::test::LogPerfResult(
+        test_name,
+        1000000.0 * static_cast<double>(num_writes) / (end_time - start_time),
+        "writes/second");
+    sprintf(test_name,
+            "MessagePipe_Threaded_Reads_%uw_%ur_%ubytes",
+            num_writers,
+            num_readers,
+            static_cast<unsigned>(num_bytes));
+    mojo::test::LogPerfResult(
+        test_name,
+        1000000.0 * static_cast<double>(num_reads) / (end_time - start_time),
+        "reads/second");
+  }
+#endif  // !defined(WIN32)
+
+  MojoHandle h0_;
+  MojoHandle h1_;
+
+  void* buffer_;
+  uint32_t num_bytes_;
+
+ private:
+#if !defined(WIN32)
+  void Sleep(int64_t microseconds) {
+    struct timespec req = {
+        static_cast<time_t>(microseconds / 1000000),       // Seconds.
+        static_cast<long>(microseconds % 1000000) * 1000L  // Nanoseconds.
+    };
+    int rv MOJO_ALLOW_UNUSED;
+    rv = nanosleep(&req, NULL);
+    assert(rv == 0);
+  }
+#endif  // !defined(WIN32)
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(CorePerftest);
+};
+
+// A no-op test so we can compare performance.
+TEST_F(CorePerftest, NoOp) {
+  mojo::test::IterateAndReportPerf("NoOp", &CorePerftest::NoOp, this);
+}
+
+TEST_F(CorePerftest, MessagePipe_CreateAndClose) {
+  mojo::test::IterateAndReportPerf("MessagePipe_CreateAndClose",
+                                   &CorePerftest::MessagePipe_CreateAndClose,
+                                   this);
+}
+
+TEST_F(CorePerftest, MessagePipe_WriteAndRead) {
+  MojoResult result MOJO_ALLOW_UNUSED;
+  result = MojoCreateMessagePipe(NULL, &h0_, &h1_);
+  assert(result == MOJO_RESULT_OK);
+  char buffer[10000] = {0};
+  buffer_ = buffer;
+  num_bytes_ = 10u;
+  mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_10bytes",
+                                   &CorePerftest::MessagePipe_WriteAndRead,
+                                   this);
+  num_bytes_ = 100u;
+  mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_100bytes",
+                                   &CorePerftest::MessagePipe_WriteAndRead,
+                                   this);
+  num_bytes_ = 1000u;
+  mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_1000bytes",
+                                   &CorePerftest::MessagePipe_WriteAndRead,
+                                   this);
+  num_bytes_ = 10000u;
+  mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_10000bytes",
+                                   &CorePerftest::MessagePipe_WriteAndRead,
+                                   this);
+  result = MojoClose(h0_);
+  assert(result == MOJO_RESULT_OK);
+  result = MojoClose(h1_);
+  assert(result == MOJO_RESULT_OK);
+}
+
+TEST_F(CorePerftest, MessagePipe_EmptyRead) {
+  MojoResult result MOJO_ALLOW_UNUSED;
+  result = MojoCreateMessagePipe(NULL, &h0_, &h1_);
+  assert(result == MOJO_RESULT_OK);
+  mojo::test::IterateAndReportPerf(
+      "MessagePipe_EmptyRead", &CorePerftest::MessagePipe_EmptyRead, this);
+  result = MojoClose(h0_);
+  assert(result == MOJO_RESULT_OK);
+  result = MojoClose(h1_);
+  assert(result == MOJO_RESULT_OK);
+}
+
+#if !defined(WIN32)
+TEST_F(CorePerftest, MessagePipe_Threaded) {
+  DoMessagePipeThreadedTest(1u, 1u, 100u);
+  DoMessagePipeThreadedTest(2u, 2u, 100u);
+  DoMessagePipeThreadedTest(3u, 3u, 100u);
+  DoMessagePipeThreadedTest(10u, 10u, 100u);
+  DoMessagePipeThreadedTest(10u, 1u, 100u);
+  DoMessagePipeThreadedTest(1u, 10u, 100u);
+
+  // For comparison of overhead:
+  DoMessagePipeThreadedTest(1u, 1u, 10u);
+  // 100 was done above.
+  DoMessagePipeThreadedTest(1u, 1u, 1000u);
+  DoMessagePipeThreadedTest(1u, 1u, 10000u);
+
+  DoMessagePipeThreadedTest(3u, 3u, 10u);
+  // 100 was done above.
+  DoMessagePipeThreadedTest(3u, 3u, 1000u);
+  DoMessagePipeThreadedTest(3u, 3u, 10000u);
+}
+#endif  // !defined(WIN32)
+
+}  // namespace
diff --git a/mojo/public/c/system/tests/core_unittest.cc b/mojo/public/c/system/tests/core_unittest.cc
new file mode 100644
index 0000000..d071f48
--- /dev/null
+++ b/mojo/public/c/system/tests/core_unittest.cc
@@ -0,0 +1,298 @@
+// Copyright 2013 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 tests the C API.
+
+#include "mojo/public/c/system/core.h"
+
+#include <string.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+TEST(CoreTest, GetTimeTicksNow) {
+  const MojoTimeTicks start = MojoGetTimeTicksNow();
+  EXPECT_NE(static_cast<MojoTimeTicks>(0), start)
+      << "MojoGetTimeTicksNow should return nonzero value";
+}
+
+// The only handle that's guaranteed to be invalid is |MOJO_HANDLE_INVALID|.
+// Tests that everything that takes a handle properly recognizes it.
+TEST(CoreTest, InvalidHandle) {
+  MojoHandle h0, h1;
+  MojoHandleSignals sig;
+  char buffer[10] = {0};
+  uint32_t buffer_size;
+  void* write_pointer;
+  const void* read_pointer;
+
+  // Close:
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(MOJO_HANDLE_INVALID));
+
+  // Wait:
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+            MojoWait(MOJO_HANDLE_INVALID, ~MOJO_HANDLE_SIGNAL_NONE, 1000000));
+  h0 = MOJO_HANDLE_INVALID;
+  sig = ~MOJO_HANDLE_SIGNAL_NONE;
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+            MojoWaitMany(&h0, &sig, 1, MOJO_DEADLINE_INDEFINITE));
+
+  // Message pipe:
+  EXPECT_EQ(
+      MOJO_RESULT_INVALID_ARGUMENT,
+      MojoWriteMessage(h0, buffer, 3, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE));
+  buffer_size = static_cast<uint32_t>(sizeof(buffer));
+  EXPECT_EQ(
+      MOJO_RESULT_INVALID_ARGUMENT,
+      MojoReadMessage(
+          h0, buffer, &buffer_size, NULL, NULL, MOJO_READ_MESSAGE_FLAG_NONE));
+
+  // Data pipe:
+  buffer_size = static_cast<uint32_t>(sizeof(buffer));
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+            MojoWriteData(h0, buffer, &buffer_size, MOJO_WRITE_DATA_FLAG_NONE));
+  write_pointer = NULL;
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+            MojoBeginWriteData(
+                h0, &write_pointer, &buffer_size, MOJO_WRITE_DATA_FLAG_NONE));
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoEndWriteData(h0, 1));
+  buffer_size = static_cast<uint32_t>(sizeof(buffer));
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+            MojoReadData(h0, buffer, &buffer_size, MOJO_READ_DATA_FLAG_NONE));
+  read_pointer = NULL;
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+            MojoBeginReadData(
+                h0, &read_pointer, &buffer_size, MOJO_READ_DATA_FLAG_NONE));
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoEndReadData(h0, 1));
+
+  // Shared buffer:
+  h1 = MOJO_HANDLE_INVALID;
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+            MojoDuplicateBufferHandle(h0, NULL, &h1));
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+            MojoMapBuffer(h0, 0, 1, &write_pointer, MOJO_MAP_BUFFER_FLAG_NONE));
+}
+
+TEST(CoreTest, BasicMessagePipe) {
+  MojoHandle h0, h1;
+  MojoHandleSignals sig;
+  char buffer[10] = {0};
+  uint32_t buffer_size;
+
+  h0 = MOJO_HANDLE_INVALID;
+  h1 = MOJO_HANDLE_INVALID;
+  EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(NULL, &h0, &h1));
+  EXPECT_NE(h0, MOJO_HANDLE_INVALID);
+  EXPECT_NE(h1, MOJO_HANDLE_INVALID);
+
+  // Shouldn't be readable.
+  EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
+            MojoWait(h0, MOJO_HANDLE_SIGNAL_READABLE, 0));
+
+  // Should be writable.
+  EXPECT_EQ(MOJO_RESULT_OK, MojoWait(h0, MOJO_HANDLE_SIGNAL_WRITABLE, 0));
+
+  // Try to read.
+  buffer_size = static_cast<uint32_t>(sizeof(buffer));
+  EXPECT_EQ(
+      MOJO_RESULT_SHOULD_WAIT,
+      MojoReadMessage(
+          h0, buffer, &buffer_size, NULL, NULL, MOJO_READ_MESSAGE_FLAG_NONE));
+
+  // Write to |h1|.
+  static const char kHello[] = "hello";
+  buffer_size = static_cast<uint32_t>(sizeof(kHello));
+  EXPECT_EQ(
+      MOJO_RESULT_OK,
+      MojoWriteMessage(
+          h1, kHello, buffer_size, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE));
+
+  // |h0| should be readable.
+  sig = MOJO_HANDLE_SIGNAL_READABLE;
+  EXPECT_EQ(MOJO_RESULT_OK,
+            MojoWaitMany(&h0, &sig, 1, MOJO_DEADLINE_INDEFINITE));
+
+  // Read from |h0|.
+  buffer_size = static_cast<uint32_t>(sizeof(buffer));
+  EXPECT_EQ(
+      MOJO_RESULT_OK,
+      MojoReadMessage(
+          h0, buffer, &buffer_size, NULL, NULL, MOJO_READ_MESSAGE_FLAG_NONE));
+  EXPECT_EQ(static_cast<uint32_t>(sizeof(kHello)), buffer_size);
+  EXPECT_STREQ(kHello, buffer);
+
+  // |h0| should no longer be readable.
+  EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
+            MojoWait(h0, MOJO_HANDLE_SIGNAL_READABLE, 10));
+
+  // Close |h0|.
+  EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h0));
+
+  // |h1| should no longer be readable or writable.
+  EXPECT_EQ(
+      MOJO_RESULT_FAILED_PRECONDITION,
+      MojoWait(
+          h1, MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, 1000));
+
+  EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h1));
+}
+
+// TODO(ncbray): enable these tests once NaCl supports the corresponding APIs.
+#ifdef __native_client__
+#define MAYBE_BasicDataPipe DISABLED_BasicDataPipe
+#define MAYBE_BasicSharedBuffer DISABLED_BasicSharedBuffer
+#else
+#define MAYBE_BasicDataPipe BasicDataPipe
+#define MAYBE_BasicSharedBuffer BasicSharedBuffer
+#endif
+
+TEST(CoreTest, MAYBE_BasicDataPipe) {
+  MojoHandle hp, hc;
+  MojoHandleSignals sig;
+  char buffer[20] = {0};
+  uint32_t buffer_size;
+  void* write_pointer;
+  const void* read_pointer;
+
+  hp = MOJO_HANDLE_INVALID;
+  hc = MOJO_HANDLE_INVALID;
+  EXPECT_EQ(MOJO_RESULT_OK, MojoCreateDataPipe(NULL, &hp, &hc));
+  EXPECT_NE(hp, MOJO_HANDLE_INVALID);
+  EXPECT_NE(hc, MOJO_HANDLE_INVALID);
+
+  // The consumer |hc| shouldn't be readable.
+  EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
+            MojoWait(hc, MOJO_HANDLE_SIGNAL_READABLE, 0));
+
+  // The producer |hp| should be writable.
+  EXPECT_EQ(MOJO_RESULT_OK, MojoWait(hp, MOJO_HANDLE_SIGNAL_WRITABLE, 0));
+
+  // Try to read from |hc|.
+  buffer_size = static_cast<uint32_t>(sizeof(buffer));
+  EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
+            MojoReadData(hc, buffer, &buffer_size, MOJO_READ_DATA_FLAG_NONE));
+
+  // Try to begin a two-phase read from |hc|.
+  read_pointer = NULL;
+  EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
+            MojoBeginReadData(
+                hc, &read_pointer, &buffer_size, MOJO_READ_DATA_FLAG_NONE));
+
+  // Write to |hp|.
+  static const char kHello[] = "hello ";
+  // Don't include terminating null.
+  buffer_size = static_cast<uint32_t>(strlen(kHello));
+  EXPECT_EQ(
+      MOJO_RESULT_OK,
+      MojoWriteData(hp, kHello, &buffer_size, MOJO_WRITE_MESSAGE_FLAG_NONE));
+
+  // |hc| should be(come) readable.
+  sig = MOJO_HANDLE_SIGNAL_READABLE;
+  EXPECT_EQ(MOJO_RESULT_OK,
+            MojoWaitMany(&hc, &sig, 1, MOJO_DEADLINE_INDEFINITE));
+
+  // Do a two-phase write to |hp|.
+  EXPECT_EQ(MOJO_RESULT_OK,
+            MojoBeginWriteData(
+                hp, &write_pointer, &buffer_size, MOJO_WRITE_DATA_FLAG_NONE));
+  static const char kWorld[] = "world";
+  ASSERT_GE(buffer_size, sizeof(kWorld));
+  // Include the terminating null.
+  memcpy(write_pointer, kWorld, sizeof(kWorld));
+  EXPECT_EQ(MOJO_RESULT_OK,
+            MojoEndWriteData(hp, static_cast<uint32_t>(sizeof(kWorld))));
+
+  // Read one character from |hc|.
+  memset(buffer, 0, sizeof(buffer));
+  buffer_size = 1;
+  EXPECT_EQ(MOJO_RESULT_OK,
+            MojoReadData(hc, buffer, &buffer_size, MOJO_READ_DATA_FLAG_NONE));
+
+  // Close |hp|.
+  EXPECT_EQ(MOJO_RESULT_OK, MojoClose(hp));
+
+  // |hc| should still be readable.
+  EXPECT_EQ(MOJO_RESULT_OK, MojoWait(hc, MOJO_HANDLE_SIGNAL_READABLE, 0));
+
+  // Do a two-phase read from |hc|.
+  read_pointer = NULL;
+  EXPECT_EQ(MOJO_RESULT_OK,
+            MojoBeginReadData(
+                hc, &read_pointer, &buffer_size, MOJO_READ_DATA_FLAG_NONE));
+  ASSERT_LE(buffer_size, sizeof(buffer) - 1);
+  memcpy(&buffer[1], read_pointer, buffer_size);
+  EXPECT_EQ(MOJO_RESULT_OK, MojoEndReadData(hc, buffer_size));
+  EXPECT_STREQ("hello world", buffer);
+
+  // |hc| should no longer be readable.
+  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+            MojoWait(hc, MOJO_HANDLE_SIGNAL_READABLE, 1000));
+
+  EXPECT_EQ(MOJO_RESULT_OK, MojoClose(hc));
+
+  // TODO(vtl): Test the other way around -- closing the consumer should make
+  // the producer never-writable?
+}
+
+TEST(CoreTest, MAYBE_BasicSharedBuffer) {
+  MojoHandle h0, h1;
+  void* pointer;
+
+  // Create a shared buffer (|h0|).
+  h0 = MOJO_HANDLE_INVALID;
+  EXPECT_EQ(MOJO_RESULT_OK, MojoCreateSharedBuffer(NULL, 100, &h0));
+  EXPECT_NE(h0, MOJO_HANDLE_INVALID);
+
+  // Map everything.
+  pointer = NULL;
+  EXPECT_EQ(MOJO_RESULT_OK,
+            MojoMapBuffer(h0, 0, 100, &pointer, MOJO_MAP_BUFFER_FLAG_NONE));
+  ASSERT_TRUE(pointer);
+  static_cast<char*>(pointer)[50] = 'x';
+
+  // Duplicate |h0| to |h1|.
+  h1 = MOJO_HANDLE_INVALID;
+  EXPECT_EQ(MOJO_RESULT_OK, MojoDuplicateBufferHandle(h0, NULL, &h1));
+  EXPECT_NE(h1, MOJO_HANDLE_INVALID);
+
+  // Close |h0|.
+  EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h0));
+
+  // The mapping should still be good.
+  static_cast<char*>(pointer)[51] = 'y';
+
+  // Unmap it.
+  EXPECT_EQ(MOJO_RESULT_OK, MojoUnmapBuffer(pointer));
+
+  // Map half of |h1|.
+  pointer = NULL;
+  EXPECT_EQ(MOJO_RESULT_OK,
+            MojoMapBuffer(h1, 50, 50, &pointer, MOJO_MAP_BUFFER_FLAG_NONE));
+  ASSERT_TRUE(pointer);
+
+  // It should have what we wrote.
+  EXPECT_EQ('x', static_cast<char*>(pointer)[0]);
+  EXPECT_EQ('y', static_cast<char*>(pointer)[1]);
+
+  // Unmap it.
+  EXPECT_EQ(MOJO_RESULT_OK, MojoUnmapBuffer(pointer));
+
+  EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h1));
+}
+
+// Defined in core_unittest_pure_c.c.
+extern "C" const char* MinimalCTest(void);
+
+// This checks that things actually work in C (not C++).
+TEST(CoreTest, MinimalCTest) {
+  const char* failure = MinimalCTest();
+  EXPECT_TRUE(failure == NULL) << failure;
+}
+
+// TODO(vtl): Add multi-threaded tests.
+
+}  // namespace
+}  // namespace mojo
diff --git a/mojo/public/c/system/tests/core_unittest_pure_c.c b/mojo/public/c/system/tests/core_unittest_pure_c.c
new file mode 100644
index 0000000..33de688
--- /dev/null
+++ b/mojo/public/c/system/tests/core_unittest_pure_c.c
@@ -0,0 +1,96 @@
+// Copyright 2014 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.
+
+#ifdef __cplusplus
+#error "This file should be compiled as C, not C++."
+#endif
+
+#include <stddef.h>
+#include <string.h>
+
+// Include all the header files that are meant to be compilable as C. Start with
+// core.h, since it's the most important one.
+#include "mojo/public/c/environment/async_waiter.h"
+#include "mojo/public/c/system/core.h"
+#include "mojo/public/c/system/macros.h"
+
+// The joys of the C preprocessor....
+#define STRINGIFY(x) #x
+#define STRINGIFY2(x) STRINGIFY(x)
+#define FAILURE(message) \
+  __FILE__ "(" STRINGIFY2(__LINE__) "): Failure: " message
+
+// Poor man's gtest.
+#define EXPECT_EQ(a, b)                                                  \
+  do {                                                                   \
+    if ((a) != (b))                                                      \
+      return FAILURE(STRINGIFY(a) " != " STRINGIFY(b) " (expected ==)"); \
+  } while (0)
+#define EXPECT_NE(a, b)                                                  \
+  do {                                                                   \
+    if ((a) == (b))                                                      \
+      return FAILURE(STRINGIFY(a) " == " STRINGIFY(b) " (expected !=)"); \
+  } while (0)
+
+// This function exists mainly to be compiled and linked. We do some cursory
+// checks and call it from a unit test, to make sure that link problems aren't
+// missed due to deadstripping. Returns null on success and a string on failure
+// (describing the failure).
+const char* MinimalCTest(void) {
+  // MSVS before 2013 *really* only supports C90: All variables must be declared
+  // at the top. (MSVS 2013 is more reasonable.)
+  MojoTimeTicks ticks;
+  MojoHandle handle0, handle1;
+  MojoHandleSignals signals;
+  const char kHello[] = "hello";
+  char buffer[200] = {0};
+  uint32_t num_bytes;
+
+  ticks = MojoGetTimeTicksNow();
+  EXPECT_NE(ticks, 0);
+
+  handle0 = MOJO_HANDLE_INVALID;
+  EXPECT_NE(MOJO_RESULT_OK, MojoClose(handle0));
+
+  EXPECT_EQ(
+      MOJO_RESULT_INVALID_ARGUMENT,
+      MojoWait(handle0, ~MOJO_HANDLE_SIGNAL_NONE, MOJO_DEADLINE_INDEFINITE));
+
+  handle1 = MOJO_HANDLE_INVALID;
+  EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(NULL, &handle0, &handle1));
+
+  signals = MOJO_HANDLE_SIGNAL_READABLE;
+  EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
+            MojoWaitMany(&handle0, &signals, 1, 1));
+
+  EXPECT_EQ(MOJO_RESULT_OK,
+            MojoWriteMessage(handle0,
+                             kHello,
+                             (uint32_t)sizeof(kHello),
+                             NULL,
+                             0u,
+                             MOJO_WRITE_DATA_FLAG_NONE));
+
+  EXPECT_EQ(
+      MOJO_RESULT_OK,
+      MojoWait(handle1, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
+
+  num_bytes = (uint32_t)sizeof(buffer);
+  EXPECT_EQ(MOJO_RESULT_OK,
+            MojoReadMessage(handle1,
+                            buffer,
+                            &num_bytes,
+                            NULL,
+                            NULL,
+                            MOJO_READ_MESSAGE_FLAG_NONE));
+  EXPECT_EQ((uint32_t)sizeof(kHello), num_bytes);
+  EXPECT_EQ(0, memcmp(buffer, kHello, sizeof(kHello)));
+
+  EXPECT_EQ(MOJO_RESULT_OK, MojoClose(handle0));
+  EXPECT_EQ(MOJO_RESULT_OK, MojoClose(handle1));
+
+  // TODO(vtl): data pipe
+
+  return NULL;
+}
diff --git a/mojo/public/c/system/tests/macros_unittest.cc b/mojo/public/c/system/tests/macros_unittest.cc
new file mode 100644
index 0000000..6a694b8
--- /dev/null
+++ b/mojo/public/c/system/tests/macros_unittest.cc
@@ -0,0 +1,83 @@
+// Copyright 2014 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 tests the C Mojo system macros and consists of "positive" tests,
+// i.e., those verifying that things work (without compile errors, or even
+// warnings if warnings are treated as errors).
+// TODO(vtl): Fix no-compile tests (which are all disabled; crbug.com/105388)
+// and write some "negative" tests.
+
+#include "mojo/public/c/system/macros.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+TEST(MacrosTest, AllowUnused) {
+  // Test that no warning/error is issued even though |x| is unused.
+  int x MOJO_ALLOW_UNUSED = 123;
+}
+
+int MustUseReturnedResult() MOJO_WARN_UNUSED_RESULT;
+int MustUseReturnedResult() {
+  return 456;
+}
+
+TEST(MacrosTest, WarnUnusedResult) {
+  if (!MustUseReturnedResult())
+    abort();
+}
+
+// First test |MOJO_COMPILE_ASSERT()| in a global scope.
+MOJO_COMPILE_ASSERT(sizeof(int64_t) == 2 * sizeof(int32_t),
+                    bad_compile_assert_failure_in_global_scope);
+
+TEST(MacrosTest, CompileAssert) {
+  // Then in a local scope.
+  MOJO_COMPILE_ASSERT(sizeof(int32_t) == 2 * sizeof(int16_t),
+                      bad_compile_assert_failure);
+}
+
+TEST(MacrosTest, Alignof) {
+  // Strictly speaking, this isn't a portable test, but I think it'll pass on
+  // all the platforms we currently support.
+  EXPECT_EQ(1u, MOJO_ALIGNOF(char));
+  EXPECT_EQ(4u, MOJO_ALIGNOF(int32_t));
+  EXPECT_EQ(8u, MOJO_ALIGNOF(int64_t));
+  EXPECT_EQ(8u, MOJO_ALIGNOF(double));
+}
+
+// These structs are used in the Alignas test. Define them globally to avoid
+// MSVS warnings/errors.
+#if defined(_MSC_VER)
+#pragma warning(push)
+// Disable the warning "structure was padded due to __declspec(align())".
+#pragma warning(disable : 4324)
+#endif
+struct MOJO_ALIGNAS(1) StructAlignas1 {
+  char x;
+};
+struct MOJO_ALIGNAS(4) StructAlignas4 {
+  char x;
+};
+struct MOJO_ALIGNAS(8) StructAlignas8 {
+  char x;
+};
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+TEST(MacrosTest, Alignas) {
+  EXPECT_EQ(1u, MOJO_ALIGNOF(StructAlignas1));
+  EXPECT_EQ(4u, MOJO_ALIGNOF(StructAlignas4));
+  EXPECT_EQ(8u, MOJO_ALIGNOF(StructAlignas8));
+}
+
+}  // namespace
+}  // namespace mojo
diff --git a/mojo/public/c/system/types.h b/mojo/public/c/system/types.h
new file mode 100644
index 0000000..5a72d2f
--- /dev/null
+++ b/mojo/public/c/system/types.h
@@ -0,0 +1,176 @@
+// Copyright 2014 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 types and constants/macros common to different Mojo system
+// APIs.
+//
+// Note: This header should be compilable as C.
+
+#ifndef MOJO_PUBLIC_C_SYSTEM_TYPES_H_
+#define MOJO_PUBLIC_C_SYSTEM_TYPES_H_
+
+#include <stdint.h>
+
+#include "mojo/public/c/system/macros.h"
+
+// TODO(vtl): Notes: Use of undefined flags will lead to undefined behavior
+// (typically they'll be ignored), not necessarily an error.
+
+// |MojoTimeTicks|: Used to specify time ticks. Value is in microseconds.
+
+typedef int64_t MojoTimeTicks;
+
+// |MojoHandle|: Handles to Mojo objects.
+//   |MOJO_HANDLE_INVALID| - A value that is never a valid handle.
+
+typedef uint32_t MojoHandle;
+
+#ifdef __cplusplus
+const MojoHandle MOJO_HANDLE_INVALID = 0;
+#else
+#define MOJO_HANDLE_INVALID ((MojoHandle)0)
+#endif
+
+// |MojoResult|: Result codes for Mojo operations. Non-negative values are
+// success codes; negative values are error/failure codes.
+//   |MOJO_RESULT_OK| - Not an error; returned on success. Note that positive
+//       |MojoResult|s may also be used to indicate success.
+//   |MOJO_RESULT_CANCELLED| - Operation was cancelled, typically by the caller.
+//   |MOJO_RESULT_UNKNOWN| - Unknown error (e.g., if not enough information is
+//       available for a more specific error).
+//   |MOJO_RESULT_INVALID_ARGUMENT| - Caller specified an invalid argument. This
+//       differs from |MOJO_RESULT_FAILED_PRECONDITION| in that the former
+//       indicates arguments that are invalid regardless of the state of the
+//       system.
+//   |MOJO_RESULT_DEADLINE_EXCEEDED| - Deadline expired before the operation
+//       could complete.
+//   |MOJO_RESULT_NOT_FOUND| - Some requested entity was not found (i.e., does
+//       not exist).
+//   |MOJO_RESULT_ALREADY_EXISTS| - Some entity or condition that we attempted
+//       to create already exists.
+//   |MOJO_RESULT_PERMISSION_DENIED| - The caller does not have permission to
+//       for the operation (use |MOJO_RESULT_RESOURCE_EXHAUSTED| for rejections
+//       caused by exhausting some resource instead).
+//   |MOJO_RESULT_RESOURCE_EXHAUSTED| - Some resource required for the call
+//       (possibly some quota) has been exhausted.
+//   |MOJO_RESULT_FAILED_PRECONDITION| - The system is not in a state required
+//       for the operation (use this if the caller must do something to rectify
+//       the state before retrying).
+//   |MOJO_RESULT_ABORTED| - The operation was aborted by the system, possibly
+//       due to a concurrency issue (use this if the caller may retry at a
+//       higher level).
+//   |MOJO_RESULT_OUT_OF_RANGE| - The operation was attempted past the valid
+//       range. Unlike |MOJO_RESULT_INVALID_ARGUMENT|, this indicates that the
+//       operation may be/become valid depending on the system state. (This
+//       error is similar to |MOJO_RESULT_FAILED_PRECONDITION|, but is more
+//       specific.)
+//   |MOJO_RESULT_UNIMPLEMENTED| - The operation is not implemented, supported,
+//       or enabled.
+//   |MOJO_RESULT_INTERNAL| - Internal error: this should never happen and
+//       indicates that some invariant expected by the system has been broken.
+//   |MOJO_RESULT_UNAVAILABLE| - The operation is (temporarily) currently
+//       unavailable. The caller may simply retry the operation (possibly with a
+//       backoff).
+//   |MOJO_RESULT_DATA_LOSS| - Unrecoverable data loss or corruption.
+//   |MOJO_RESULT_BUSY| - One of the resources involved is currently being used
+//       (possibly on another thread) in a way that prevents the current
+//       operation from proceeding, e.g., if the other operation may result in
+//       the resource being invalidated.
+//   |MOJO_RESULT_SHOULD_WAIT| - The request cannot currently be completed
+//       (e.g., if the data requested is not yet available). The caller should
+//       wait for it to be feasible using |MojoWait()| or |MojoWaitMany()|.
+//
+// Note that positive values are also available as success codes.
+//
+// The codes from |MOJO_RESULT_OK| to |MOJO_RESULT_DATA_LOSS| come from
+// Google3's canonical error codes.
+//
+// TODO(vtl): Add a |MOJO_RESULT_UNSATISFIABLE|?
+
+typedef int32_t MojoResult;
+
+#ifdef __cplusplus
+const MojoResult MOJO_RESULT_OK = 0;
+const MojoResult MOJO_RESULT_CANCELLED = -1;
+const MojoResult MOJO_RESULT_UNKNOWN = -2;
+const MojoResult MOJO_RESULT_INVALID_ARGUMENT = -3;
+const MojoResult MOJO_RESULT_DEADLINE_EXCEEDED = -4;
+const MojoResult MOJO_RESULT_NOT_FOUND = -5;
+const MojoResult MOJO_RESULT_ALREADY_EXISTS = -6;
+const MojoResult MOJO_RESULT_PERMISSION_DENIED = -7;
+const MojoResult MOJO_RESULT_RESOURCE_EXHAUSTED = -8;
+const MojoResult MOJO_RESULT_FAILED_PRECONDITION = -9;
+const MojoResult MOJO_RESULT_ABORTED = -10;
+const MojoResult MOJO_RESULT_OUT_OF_RANGE = -11;
+const MojoResult MOJO_RESULT_UNIMPLEMENTED = -12;
+const MojoResult MOJO_RESULT_INTERNAL = -13;
+const MojoResult MOJO_RESULT_UNAVAILABLE = -14;
+const MojoResult MOJO_RESULT_DATA_LOSS = -15;
+const MojoResult MOJO_RESULT_BUSY = -16;
+const MojoResult MOJO_RESULT_SHOULD_WAIT = -17;
+#else
+#define MOJO_RESULT_OK ((MojoResult)0)
+#define MOJO_RESULT_CANCELLED ((MojoResult) - 1)
+#define MOJO_RESULT_UNKNOWN ((MojoResult) - 2)
+#define MOJO_RESULT_INVALID_ARGUMENT ((MojoResult) - 3)
+#define MOJO_RESULT_DEADLINE_EXCEEDED ((MojoResult) - 4)
+#define MOJO_RESULT_NOT_FOUND ((MojoResult) - 5)
+#define MOJO_RESULT_ALREADY_EXISTS ((MojoResult) - 6)
+#define MOJO_RESULT_PERMISSION_DENIED ((MojoResult) - 7)
+#define MOJO_RESULT_RESOURCE_EXHAUSTED ((MojoResult) - 8)
+#define MOJO_RESULT_FAILED_PRECONDITION ((MojoResult) - 9)
+#define MOJO_RESULT_ABORTED ((MojoResult) - 10)
+#define MOJO_RESULT_OUT_OF_RANGE ((MojoResult) - 11)
+#define MOJO_RESULT_UNIMPLEMENTED ((MojoResult) - 12)
+#define MOJO_RESULT_INTERNAL ((MojoResult) - 13)
+#define MOJO_RESULT_UNAVAILABLE ((MojoResult) - 14)
+#define MOJO_RESULT_DATA_LOSS ((MojoResult) - 15)
+#define MOJO_RESULT_BUSY ((MojoResult) - 16)
+#define MOJO_RESULT_SHOULD_WAIT ((MojoResult) - 17)
+#endif
+
+// |MojoDeadline|: Used to specify deadlines (timeouts), in microseconds (except
+// for |MOJO_DEADLINE_INDEFINITE|).
+//   |MOJO_DEADLINE_INDEFINITE| - Used to indicate "forever".
+
+typedef uint64_t MojoDeadline;
+
+#ifdef __cplusplus
+const MojoDeadline MOJO_DEADLINE_INDEFINITE = static_cast<MojoDeadline>(-1);
+#else
+#define MOJO_DEADLINE_INDEFINITE ((MojoDeadline) - 1)
+#endif
+
+// |MojoHandleSignals|: Used to specify signals that can be waited on for a
+// handle (and which can be triggered), e.g., the ability to read or write to
+// the handle.
+//   |MOJO_HANDLE_SIGNAL_NONE| - No flags. |MojoWait()|, etc. will return
+//       |MOJO_RESULT_FAILED_PRECONDITION| if you attempt to wait on this.
+//   |MOJO_HANDLE_SIGNAL_READABLE| - Can read (e.g., a message) from the handle.
+//   |MOJO_HANDLE_SIGNAL_WRITABLE| - Can write (e.g., a message) to the handle.
+
+typedef uint32_t MojoHandleSignals;
+
+#ifdef __cplusplus
+const MojoHandleSignals MOJO_HANDLE_SIGNAL_NONE = 0;
+const MojoHandleSignals MOJO_HANDLE_SIGNAL_READABLE = 1 << 0;
+const MojoHandleSignals MOJO_HANDLE_SIGNAL_WRITABLE = 1 << 1;
+#else
+#define MOJO_HANDLE_SIGNAL_NONE ((MojoHandleSignals)0)
+#define MOJO_HANDLE_SIGNAL_READABLE ((MojoHandleSignals)1 << 0)
+#define MOJO_HANDLE_SIGNAL_WRITABLE ((MojoHandleSignals)1 << 1)
+#endif
+
+// TODO(vtl): Add out parameters with this to MojoWait/MojoWaitMany.
+// Note: This struct is not extensible (and only has 32-bit quantities), so it's
+// 32-bit-aligned.
+MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int32_t) == 4, int32_t_has_weird_alignment);
+struct MOJO_ALIGNAS(4) MojoHandleSignalsState {
+  MojoHandleSignals satisfied_signals;
+  MojoHandleSignals satisfiable_signals;
+};
+MOJO_COMPILE_ASSERT(sizeof(MojoHandleSignalsState) == 8,
+                    MojoHandleSignalsState_has_wrong_size);
+
+#endif  // MOJO_PUBLIC_C_SYSTEM_TYPES_H_
diff --git a/mojo/public/c/test_support/BUILD.gn b/mojo/public/c/test_support/BUILD.gn
new file mode 100644
index 0000000..42db434
--- /dev/null
+++ b/mojo/public/c/test_support/BUILD.gn
@@ -0,0 +1,24 @@
+# Copyright 2014 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.
+
+# GYP version: mojo/mojo_public_tests.gypi:mojo_test_support
+shared_library("test_support") {
+  output_name = "mojo_test_support"
+
+  defines = [ "MOJO_TEST_SUPPORT_IMPLEMENTATION" ]
+
+  sources = [
+    "test_support.h",
+    "test_support_export.h",
+    # TODO(vtl): Convert this to thunks http://crbug.com/386799
+    "../../tests/test_support_private.cc",
+    "../../tests/test_support_private.h",
+  ]
+
+  if (is_mac) {
+# TODO(GYP)
+#   # Make it a run-path dependent library.
+#   'DYLIB_INSTALL_NAME_BASE': '@loader_path',
+  }
+}
diff --git a/mojo/public/c/test_support/test_support.h b/mojo/public/c/test_support/test_support.h
new file mode 100644
index 0000000..2b686b2
--- /dev/null
+++ b/mojo/public/c/test_support/test_support.h
@@ -0,0 +1,48 @@
+// Copyright 2014 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_C_TEST_SUPPORT_TEST_SUPPORT_H_
+#define MOJO_PUBLIC_C_TEST_SUPPORT_TEST_SUPPORT_H_
+
+// Note: This header should be compilable as C.
+
+#include <stdio.h>
+
+#include "mojo/public/c/test_support/test_support_export.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+MOJO_TEST_SUPPORT_EXPORT void MojoTestSupportLogPerfResult(
+    const char* test_name,
+    double value,
+    const char* units);
+
+// Opens a "/"-delimited file path relative to the source root.
+MOJO_TEST_SUPPORT_EXPORT FILE* MojoTestSupportOpenSourceRootRelativeFile(
+    const char* source_root_relative_path);
+
+// Enumerates a "/"-delimited directory path relative to the source root.
+// Returns only regular files. The return value is a heap-allocated array of
+// heap-allocated strings. Each must be free'd separately.
+//
+// The return value is built like so:
+//
+//   char** rv = (char**) calloc(N + 1, sizeof(char*));
+//   rv[0] = strdup("a");
+//   rv[1] = strdup("b");
+//   rv[2] = strdup("c");
+//   ...
+//   rv[N] = NULL;
+//
+MOJO_TEST_SUPPORT_EXPORT
+char** MojoTestSupportEnumerateSourceRootRelativeDirectory(
+    const char* source_root_relative_path);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // MOJO_PUBLIC_C_TEST_SUPPORT_TEST_SUPPORT_H_
diff --git a/mojo/public/c/test_support/test_support_export.h b/mojo/public/c/test_support/test_support_export.h
new file mode 100644
index 0000000..e22a9e3
--- /dev/null
+++ b/mojo/public/c/test_support/test_support_export.h
@@ -0,0 +1,26 @@
+// Copyright 2014 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_C_TEST_SUPPORT_TEST_SUPPORT_EXPORT_H_
+#define MOJO_PUBLIC_C_TEST_SUPPORT_TEST_SUPPORT_EXPORT_H_
+
+#if defined(WIN32)
+
+#if defined(MOJO_TEST_SUPPORT_IMPLEMENTATION)
+#define MOJO_TEST_SUPPORT_EXPORT __declspec(dllexport)
+#else
+#define MOJO_TEST_SUPPORT_EXPORT __declspec(dllimport)
+#endif
+
+#else  // !defined(WIN32)
+
+#if defined(MOJO_TEST_SUPPORT_IMPLEMENTATION)
+#define MOJO_TEST_SUPPORT_EXPORT __attribute__((visibility("default")))
+#else
+#define MOJO_TEST_SUPPORT_EXPORT
+#endif
+
+#endif  // defined(WIN32)
+
+#endif  // MOJO_PUBLIC_C_TEST_SUPPORT_TEST_SUPPORT_EXPORT_H_
diff --git a/mojo/public/cpp/DEPS b/mojo/public/cpp/DEPS
new file mode 100644
index 0000000..74acd7c
--- /dev/null
+++ b/mojo/public/cpp/DEPS
@@ -0,0 +1,18 @@
+include_rules = [
+  # Require explicit dependencies in each directory.
+  "-mojo/public",
+  # But everyone can depend on the C and C++ system headers.
+  "+mojo/public/c/system",
+  "+mojo/public/cpp/system",
+  # Ditto for the C environment headers (but not the C++ environment, since it
+  # has dependencies of its own).
+  "+mojo/public/c/environment",
+]
+
+specific_include_rules = {
+  r".*_(unit|perf)test\.cc": [
+    "+testing",
+    "+mojo/public/cpp/test_support",
+    "+mojo/public/cpp/utility",
+  ],
+}
diff --git a/mojo/public/cpp/README.md b/mojo/public/cpp/README.md
new file mode 100644
index 0000000..8f03d98
--- /dev/null
+++ b/mojo/public/cpp/README.md
@@ -0,0 +1,71 @@
+Mojo Public C++ API
+===================
+
+This directory contains C++ language bindings for the Mojo Public API.
+
+A number of subdirectories provide wrappers for the lower-level C APIs (in
+subdirectories of the same name, under mojo/public/c/). Typically, these
+wrappers provide increased convenience and/or type-safety.
+
+Other subdirectories provide support (static) libraries of various sorts. In
+this case, the organization is to have the public interface for the library in
+defined in header files in the subdirectory itself and the implementation of the
+library at a lower level, under a lib (sub)subdirectory. A developer should be
+able to substitute their own implementation of any such support library, and
+expect other support libraries, which may depend on that library, to work
+properly.
+
+Bindings
+--------
+
+The bindings/ subdirectory contains a support (static) library needed by the
+code generated by the bindings generator tool (in mojo/public/tools/bindings/),
+which translates Mojo IDL (.mojom) files into idiomatic C++ (among other
+languages).
+
+This library depends on the Environment library.
+
+Environment
+-----------
+
+The environment/ subdirectory contains a support (static) library that
+represents shared state needed to support the Bindings and GLES2 libraries.
+
+This library depends on the Utility library.
+
+
+GLES2
+-----
+
+The gles2/ subdirectory contains C++ wrappers (and some additional helpers) of
+the API defined in mojo/public/c/gles2/ (which provides access to GLES2).
+
+These wrappers depend on the Environment library.
+
+Shell
+-----
+
+The shell/ subdirectory contains a support (static) library that aids in writing
+Mojo applications and interacting with the Shell service.
+
+System
+------
+
+The system/ subdirectory contains C++ wrappers (and some additional helpers) of
+the API defined in mojo/public/c/system/, which defines the basic, "core" API,
+especially used to communicate with Mojo services.
+
+Test Support
+------------
+
+The test_support/ subdirectory contains C++ wrappers of the test-only API
+defined in mojo/public/c/test_support/. It is not meant for general use by Mojo
+applications.
+
+Utility
+-------
+
+The utility/ subdirectory contains a support (static) library that provides
+various basic functionality. Most notably, it provides an implementation of a
+RunLoop based on MojoWaitMany() that applications may use as the basis for
+asynchronous message processing.
diff --git a/mojo/public/cpp/application/BUILD.gn b/mojo/public/cpp/application/BUILD.gn
new file mode 100644
index 0000000..900edef
--- /dev/null
+++ b/mojo/public/cpp/application/BUILD.gn
@@ -0,0 +1,47 @@
+# Copyright 2014 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.
+
+# GYP version: mojo/mojo_public.gypi:mojo_application_base
+source_set("application") {
+  sources = [
+    "application_connection.h",
+    "application_delegate.h",
+    "application_impl.h",
+    "connect.h",
+    "service_provider_impl.h",
+    "interface_factory.h",
+    "interface_factory_impl.h",
+    "lib/application_connection.cc",
+    "lib/application_delegate.cc",
+    "lib/application_impl.cc",
+    "lib/service_provider_impl.cc",
+    "lib/service_connector.cc",
+    "lib/service_connector.h",
+    "lib/service_registry.cc",
+    "lib/service_registry.h",
+    "lib/weak_service_provider.cc",
+    "lib/weak_service_provider.h",
+  ]
+
+  deps = [
+    "//mojo/public/cpp/bindings",
+    "//mojo/public/cpp/environment",
+    "//mojo/public/cpp/system",
+    "//mojo/public/interfaces/application",
+  ]
+}
+
+# GYP version: mojo/mojo_public.gypi:mojo_application_standalone
+source_set("standalone") {
+  sources = [
+    "lib/application_runner.cc"
+  ]
+
+  public_deps = [ ":application" ]
+
+  deps = [
+    "//mojo/public/cpp/environment:standalone",
+    "//mojo/public/cpp/utility",
+  ]
+}
diff --git a/mojo/public/cpp/application/DEPS b/mojo/public/cpp/application/DEPS
new file mode 100644
index 0000000..dcd8e6f
--- /dev/null
+++ b/mojo/public/cpp/application/DEPS
@@ -0,0 +1,17 @@
+include_rules = [
+  "+mojo/public/cpp/bindings",
+  "+mojo/public/cpp/environment",
+  "+mojo/public/interfaces/application",
+  "+mojo/public/interfaces/service_provider",
+]
+
+specific_include_rules = {
+  r"application_runner_chromium.*": [
+    "+base",
+    "+mojo/common",
+    "+mojo/public/cpp"
+  ],
+  r"application_runner.*": [
+    "+mojo/public/cpp"
+  ],
+}
diff --git a/mojo/public/cpp/application/application_connection.h b/mojo/public/cpp/application/application_connection.h
new file mode 100644
index 0000000..d5d6dde
--- /dev/null
+++ b/mojo/public/cpp/application/application_connection.h
@@ -0,0 +1,82 @@
+// Copyright 2014 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_APPLICATION_APPLICATION_CONNECTION_H_
+#define MOJO_PUBLIC_APPLICATION_APPLICATION_CONNECTION_H_
+
+#include <string>
+
+#include "mojo/public/cpp/application/lib/service_connector.h"
+#include "mojo/public/interfaces/application/service_provider.mojom.h"
+
+namespace mojo {
+
+// An instance of this class is passed to
+// ApplicationDelegate's ConfigureIncomingConnection() method each time a
+// connection is made to this app, and to ApplicationDelegate's
+// ConfigureOutgoingConnection() method when the app connects to
+// another.
+//
+// To use define a class that implements your specific service api, e.g. FooImpl
+// to implement a service named Foo.
+// That class must subclass an InterfaceImpl specialization.
+//
+// Then implement an InterfaceFactory<Foo> that binds instances of FooImpl to
+// InterfaceRequest<Foo>s and register that on the connection.
+//
+// connection->AddService(&factory);
+//
+// Or if you have multiple factories implemented by the same type, explicitly
+// specify the interface to register the factory for:
+//
+// connection->AddService<Foo>(&my_foo_and_bar_factory_);
+// connection->AddService<Bar>(&my_foo_and_bar_factory_);
+//
+// The InterfaceFactory must outlive the ApplicationConnection.
+class ApplicationConnection {
+ public:
+  virtual ~ApplicationConnection();
+
+  template <typename Interface>
+  void AddService(InterfaceFactory<Interface>* factory) {
+    AddServiceConnector(
+        new internal::InterfaceFactoryConnector<Interface>(factory));
+  }
+
+  // Connect to the service implementing |Interface|.
+  template <typename Interface>
+  void ConnectToService(InterfacePtr<Interface>* ptr) {
+    MessagePipe pipe;
+    ptr->Bind(pipe.handle0.Pass());
+    GetServiceProvider()->ConnectToService(Interface::Name_,
+                                           pipe.handle1.Pass());
+  }
+
+  // The url identifying the application on the other end of this connection.
+  virtual const std::string& GetRemoteApplicationURL() = 0;
+
+  // Establishes a new connection to an application.
+  // TODO(davemoore): Would it be better to expose the ApplicationImpl?
+  virtual ApplicationConnection* ConnectToApplication(
+      const std::string& url) = 0;
+
+  // Connect to application identified by |application_url| and connect to
+  // the service implementation of the interface identified by |Interface|.
+  template <typename Interface>
+  void ConnectToService(const std::string& application_url,
+                        InterfacePtr<Interface>* ptr) {
+    ConnectToApplication(application_url)->ConnectToService(ptr);
+  }
+
+  // Raw ServiceProvider interface to remote application.
+  virtual ServiceProvider* GetServiceProvider() = 0;
+
+ private:
+  virtual void AddServiceConnector(
+      internal::ServiceConnectorBase* service_connector) = 0;
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_APPLICATION_APPLICATION_CONNECTION_H_
diff --git a/mojo/public/cpp/application/application_delegate.h b/mojo/public/cpp/application/application_delegate.h
new file mode 100644
index 0000000..cb67308
--- /dev/null
+++ b/mojo/public/cpp/application/application_delegate.h
@@ -0,0 +1,44 @@
+// Copyright 2014 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_APPLICATION_APPLICATION_DELEGATE_H_
+#define MOJO_PUBLIC_APPLICATION_APPLICATION_DELEGATE_H_
+
+#include <string>
+
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+
+class ApplicationConnection;
+class ApplicationImpl;
+
+class ApplicationDelegate {
+ public:
+  ApplicationDelegate();
+  virtual ~ApplicationDelegate();
+
+  // Implement this method to create the specific subclass of
+  // ApplicationDelegate. Ownership is taken by the caller. It will be deleted.
+  static ApplicationDelegate* Create();
+
+  virtual void Initialize(ApplicationImpl* app);
+
+  // Override this method to configure what services a connection supports when
+  // being connected to from an app.
+  // return false to reject the connection entirely.
+  virtual bool ConfigureIncomingConnection(ApplicationConnection* connection);
+
+  // Override this method to configure what services a connection supports when
+  // connecting to another app.
+  // return false to reject the connection entirely.
+  virtual bool ConfigureOutgoingConnection(ApplicationConnection* connection);
+
+ private:
+  MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationDelegate);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_APPLICATION_APPLICATION_DELEGATE_H_
diff --git a/mojo/public/cpp/application/application_impl.h b/mojo/public/cpp/application/application_impl.h
new file mode 100644
index 0000000..4b4cb93
--- /dev/null
+++ b/mojo/public/cpp/application/application_impl.h
@@ -0,0 +1,110 @@
+// Copyright 2014 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_APPLICATION_APPLICATION_IMPL_H_
+#define MOJO_PUBLIC_APPLICATION_APPLICATION_IMPL_H_
+#include <vector>
+
+#include "mojo/public/cpp/application/application_connection.h"
+#include "mojo/public/cpp/application/lib/service_connector.h"
+#include "mojo/public/cpp/application/lib/service_registry.h"
+#include "mojo/public/cpp/system/core.h"
+#include "mojo/public/interfaces/application/application.mojom.h"
+#include "mojo/public/interfaces/application/shell.mojom.h"
+
+namespace mojo {
+
+class ApplicationDelegate;
+
+// Utility class for communicating with the Shell, and providing Services
+// to clients.
+//
+// To use define a class that implements your specific server api, e.g. FooImpl
+// to implement a service named Foo.
+// That class must subclass an InterfaceImpl specialization.
+//
+// If there is context that is to be shared amongst all instances, define a
+// constructor with that class as its only argument, otherwise define an empty
+// constructor.
+//
+// class FooImpl : public InterfaceImpl<Foo> {
+//  public:
+//   FooImpl(ApplicationContext* app_context) {}
+// };
+//
+// or
+//
+// class BarImpl : public InterfaceImpl<Bar> {
+//  public:
+//   // contexts will remain valid for the lifetime of BarImpl.
+//   BarImpl(ApplicationContext* app_context, BarContext* service_context)
+//          : app_context_(app_context), servicecontext_(context) {}
+//
+// Create an ApplicationImpl instance that collects any service implementations.
+//
+// ApplicationImpl app(service_provider_handle);
+// app.AddService<FooImpl>();
+//
+// BarContext context;
+// app.AddService<BarImpl>(&context);
+//
+//
+class ApplicationImpl : public InterfaceImpl<Application> {
+ public:
+  ApplicationImpl(ApplicationDelegate* delegate,
+                  ScopedMessagePipeHandle shell_handle);
+  ApplicationImpl(ApplicationDelegate* delegate,
+                  MojoHandle shell_handle);
+  virtual ~ApplicationImpl();
+
+  Shell* shell() const { return shell_.get(); }
+
+  // Returns any initial configuration arguments, passed by the Shell.
+  const Array<String>& args() { return args_; }
+
+  // Establishes a new connection to an application. Caller does not own.
+  ApplicationConnection* ConnectToApplication(const String& application_url);
+
+  // Connect to application identified by |application_url| and connect to the
+  // service implementation of the interface identified by |Interface|.
+  template <typename Interface>
+  void ConnectToService(const std::string& application_url,
+                        InterfacePtr<Interface>* ptr) {
+    ConnectToApplication(application_url)->ConnectToService(ptr);
+  }
+
+ private:
+  class ShellPtrWatcher;
+
+  void BindShell(ScopedMessagePipeHandle shell_handle);
+  void ClearConnections();
+  void OnShellError() {
+    ClearConnections();
+    Terminate();
+  };
+
+  // Quits the main run loop for this application.
+  static void Terminate();
+
+  // Application implementation.
+  virtual void Initialize(Array<String> args) override;
+  virtual void AcceptConnection(const String& requestor_url,
+                                ServiceProviderPtr provider) override;
+
+  typedef std::vector<internal::ServiceRegistry*> ServiceRegistryList;
+
+  bool initialized_;
+  ServiceRegistryList incoming_service_registries_;
+  ServiceRegistryList outgoing_service_registries_;
+  ApplicationDelegate* delegate_;
+  ShellPtr shell_;
+  ShellPtrWatcher* shell_watch_;
+  Array<String> args_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationImpl);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_APPLICATION_APPLICATION_IMPL_H_
diff --git a/mojo/public/cpp/application/application_runner.h b/mojo/public/cpp/application/application_runner.h
new file mode 100644
index 0000000..b88ec8e
--- /dev/null
+++ b/mojo/public/cpp/application/application_runner.h
@@ -0,0 +1,44 @@
+// Copyright 2014 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_APPLICATION_APPLICATION_RUNNER_H_
+#define MOJO_PUBLIC_APPLICATION_APPLICATION_RUNNER_H_
+
+#include "mojo/public/cpp/system/core.h"
+
+namespace mojo {
+
+class ApplicationDelegate;
+
+// A utility for running an Application. The typical use case is to use
+// when writing your MojoMain:
+//
+//  MojoResult MojoMain(MojoHandle shell_handle) {
+//    mojo::ApplicationRunner runner(new MyApplicationDelegate());
+//    return runner.Run(shell_handle);
+//  }
+//
+// ApplicationRunner takes care of mojo environment initialization and
+// shutdown, and starting a RunLoop from which your application can run and
+// ultimately Quit().
+class ApplicationRunner {
+ public:
+  // Takes ownership of |delegate|.
+  explicit ApplicationRunner(ApplicationDelegate* delegate);
+  ~ApplicationRunner();
+
+  // Once the various parameters have been set above, use Run to initialize an
+  // ApplicationImpl wired to the provided delegate, and run a RunLoop until
+  // the application exits.
+  MojoResult Run(MojoHandle shell_handle);
+
+ private:
+  ApplicationDelegate* delegate_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationRunner);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_APPLICATION_APPLICATION_RUNNER_H_
diff --git a/mojo/public/cpp/application/connect.h b/mojo/public/cpp/application/connect.h
new file mode 100644
index 0000000..a41c028
--- /dev/null
+++ b/mojo/public/cpp/application/connect.h
@@ -0,0 +1,22 @@
+// Copyright 2014 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_CPP_APPLICATION_CONNECT_H_
+#define MOJO_PUBLIC_CPP_APPLICATION_CONNECT_H_
+
+#include "mojo/public/interfaces/application/service_provider.mojom.h"
+
+namespace mojo {
+
+template <typename Interface>
+inline void ConnectToService(ServiceProvider* service_provider,
+                             InterfacePtr<Interface>* ptr) {
+  MessagePipe pipe;
+  ptr->Bind(pipe.handle0.Pass());
+  service_provider->ConnectToService(Interface::Name_, pipe.handle1.Pass());
+}
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_APPLICATION_CONNECT_H_
diff --git a/mojo/public/cpp/application/interface_factory.h b/mojo/public/cpp/application/interface_factory.h
new file mode 100644
index 0000000..90abd13
--- /dev/null
+++ b/mojo/public/cpp/application/interface_factory.h
@@ -0,0 +1,30 @@
+// Copyright 2014 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_CPP_APPLICATION_INTERFACE_FACTORY_H_
+#define MOJO_PUBLIC_CPP_APPLICATION_INTERFACE_FACTORY_H_
+
+#include "mojo/public/cpp/bindings/interface_impl.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+
+namespace mojo {
+
+class ApplicationConnection;
+template <typename Interface> class InterfaceRequest;
+
+// Implement this class to provide implementations of a given interface and
+// bind them to incoming requests. The implementation of this class is
+// responsible for managing the lifetime of the implementations of the
+// interface.
+template <typename Interface>
+class InterfaceFactory {
+ public:
+  virtual ~InterfaceFactory() {}
+  virtual void Create(ApplicationConnection* connection,
+                      InterfaceRequest<Interface> request) = 0;
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_APPLICATION_INTERFACE_FACTORY_H_
diff --git a/mojo/public/cpp/application/interface_factory_impl.h b/mojo/public/cpp/application/interface_factory_impl.h
new file mode 100644
index 0000000..72d3254
--- /dev/null
+++ b/mojo/public/cpp/application/interface_factory_impl.h
@@ -0,0 +1,49 @@
+// Copyright 2014 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_CPP_APPLICATION_INTERFACE_FACTORY_IMPL_H_
+#define MOJO_PUBLIC_CPP_APPLICATION_INTERFACE_FACTORY_IMPL_H_
+
+#include "mojo/public/cpp/application/interface_factory.h"
+
+namespace mojo {
+
+// Use this class to allocate and bind instances of Impl to interface requests.
+// The lifetime of the constructed Impl is bound to the pipe.
+template <typename Impl,
+          typename Interface = typename Impl::ImplementedInterface>
+class InterfaceFactoryImpl : public InterfaceFactory<Interface> {
+ public:
+  virtual ~InterfaceFactoryImpl() {}
+
+  virtual void Create(ApplicationConnection* connection,
+                      InterfaceRequest<Interface> request) override {
+    BindToRequest(new Impl(), &request);
+  }
+};
+
+// Use this class to allocate and bind instances of Impl constructed with a
+// context parameter to interface requests. The lifetime of the constructed
+// Impl is bound to the pipe.
+template <typename Impl,
+          typename Context,
+          typename Interface = typename Impl::ImplementedInterface>
+class InterfaceFactoryImplWithContext : public InterfaceFactory<Interface> {
+ public:
+  explicit InterfaceFactoryImplWithContext(Context* context)
+      : context_(context) {}
+  virtual ~InterfaceFactoryImplWithContext() {}
+
+  virtual void Create(ApplicationConnection* connection,
+                      InterfaceRequest<Interface> request) override {
+    BindToRequest(new Impl(context_), &request);
+  }
+
+ private:
+  Context* context_;
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_APPLICATION_INTERFACE_FACTORY_IMPL_H_
diff --git a/mojo/public/cpp/application/lazy_interface_ptr.h b/mojo/public/cpp/application/lazy_interface_ptr.h
new file mode 100644
index 0000000..1f4b973
--- /dev/null
+++ b/mojo/public/cpp/application/lazy_interface_ptr.h
@@ -0,0 +1,46 @@
+// Copyright 2014 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_CPP_APPLICATION_LAZY_INTERFACE_PTR_H_
+#define MOJO_PUBLIC_CPP_APPLICATION_LAZY_INTERFACE_PTR_H_
+
+#include "mojo/public/cpp/application/connect.h"
+#include "mojo/public/interfaces/application/service_provider.mojom.h"
+
+namespace mojo {
+
+template<typename Interface>
+class LazyInterfacePtr : public InterfacePtr<Interface> {
+ public:
+  LazyInterfacePtr() : service_provider_(nullptr) {}
+
+  LazyInterfacePtr(ServiceProvider* service_provider)
+      : service_provider_(service_provider) {
+  }
+
+  void set_service_provider(ServiceProvider* service_provider) {
+    if (service_provider != service_provider_) {
+      InterfacePtr<Interface>::reset();
+    }
+    service_provider_ = service_provider;
+  }
+
+  Interface* get() const {
+    if (!InterfacePtr<Interface>::get()) {
+      mojo::ConnectToService<Interface>(
+          service_provider_,
+          const_cast<LazyInterfacePtr<Interface>*>(this));
+    }
+    return InterfacePtr<Interface>::get();
+  }
+  Interface* operator->() const { return get(); }
+  Interface& operator*() const { return *get(); }
+
+ private:
+  ServiceProvider* service_provider_;
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_APPLICATION_LAZY_INTERFACE_PTR_H_
diff --git a/mojo/public/cpp/application/lib/application_connection.cc b/mojo/public/cpp/application/lib/application_connection.cc
new file mode 100644
index 0000000..4978a35
--- /dev/null
+++ b/mojo/public/cpp/application/lib/application_connection.cc
@@ -0,0 +1,12 @@
+// Copyright 2014 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/cpp/application/application_connection.h"
+
+namespace mojo {
+
+ApplicationConnection::~ApplicationConnection() {}
+
+}  // namespace mojo
+
diff --git a/mojo/public/cpp/application/lib/application_delegate.cc b/mojo/public/cpp/application/lib/application_delegate.cc
new file mode 100644
index 0000000..715daa0
--- /dev/null
+++ b/mojo/public/cpp/application/lib/application_delegate.cc
@@ -0,0 +1,24 @@
+// Copyright 2014 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/cpp/application/application_delegate.h"
+
+namespace mojo {
+
+ApplicationDelegate::ApplicationDelegate() {}
+ApplicationDelegate::~ApplicationDelegate() {}
+
+void ApplicationDelegate::Initialize(ApplicationImpl* app) {}
+
+bool ApplicationDelegate::ConfigureIncomingConnection(
+    ApplicationConnection* connection) {
+  return true;
+}
+
+bool ApplicationDelegate::ConfigureOutgoingConnection(
+    ApplicationConnection* connection) {
+  return true;
+}
+
+}  // namespace mojo
diff --git a/mojo/public/cpp/application/lib/application_impl.cc b/mojo/public/cpp/application/lib/application_impl.cc
new file mode 100644
index 0000000..0c86356
--- /dev/null
+++ b/mojo/public/cpp/application/lib/application_impl.cc
@@ -0,0 +1,98 @@
+// Copyright 2014 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/cpp/application/application_impl.h"
+
+#include "mojo/public/cpp/application/application_delegate.h"
+#include "mojo/public/cpp/application/lib/service_registry.h"
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/public/cpp/environment/logging.h"
+
+namespace mojo {
+
+class ApplicationImpl::ShellPtrWatcher : public ErrorHandler {
+ public:
+  ShellPtrWatcher(ApplicationImpl* impl)
+    : impl_(impl) {}
+
+  virtual ~ShellPtrWatcher() {}
+
+  virtual void OnConnectionError() override { impl_->OnShellError(); }
+
+ private:
+  ApplicationImpl* impl_;
+  MOJO_DISALLOW_COPY_AND_ASSIGN(ShellPtrWatcher);
+};
+
+ApplicationImpl::ApplicationImpl(ApplicationDelegate* delegate,
+                                 ScopedMessagePipeHandle shell_handle)
+    : initialized_(false), delegate_(delegate), shell_watch_(nullptr) {
+  BindShell(shell_handle.Pass());
+}
+
+ApplicationImpl::ApplicationImpl(ApplicationDelegate* delegate,
+                                 MojoHandle shell_handle)
+    : initialized_(false), delegate_(delegate), shell_watch_(nullptr) {
+  BindShell(MakeScopedHandle(MessagePipeHandle(shell_handle)));
+}
+
+void ApplicationImpl::ClearConnections() {
+  for (ServiceRegistryList::iterator i(incoming_service_registries_.begin());
+      i != incoming_service_registries_.end(); ++i)
+    delete *i;
+  for (ServiceRegistryList::iterator i(outgoing_service_registries_.begin());
+      i != outgoing_service_registries_.end(); ++i)
+    delete *i;
+  incoming_service_registries_.clear();
+  outgoing_service_registries_.clear();
+}
+
+ApplicationImpl::~ApplicationImpl() {
+  ClearConnections();
+  delete shell_watch_;
+}
+
+void ApplicationImpl::Initialize(Array<String> args) {
+  MOJO_CHECK(!initialized_);
+  initialized_ = true;
+  args_ = args.Pass();
+  delegate_->Initialize(this);
+}
+
+ApplicationConnection* ApplicationImpl::ConnectToApplication(
+    const String& application_url) {
+  MOJO_CHECK(initialized_);
+  ServiceProviderPtr out_service_provider;
+  shell_->ConnectToApplication(application_url, Get(&out_service_provider));
+  internal::ServiceRegistry* registry = new internal::ServiceRegistry(
+      this,
+      application_url,
+      out_service_provider.Pass());
+  if (!delegate_->ConfigureOutgoingConnection(registry)) {
+    delete registry;
+    return nullptr;
+  }
+  outgoing_service_registries_.push_back(registry);
+  return registry;
+}
+
+void ApplicationImpl::BindShell(ScopedMessagePipeHandle shell_handle) {
+  shell_watch_ = new ShellPtrWatcher(this);
+  shell_.Bind(shell_handle.Pass());
+  shell_.set_client(this);
+  shell_.set_error_handler(shell_watch_);
+}
+
+void ApplicationImpl::AcceptConnection(const String& requestor_url,
+                                       ServiceProviderPtr service_provider) {
+  internal::ServiceRegistry* registry = new internal::ServiceRegistry(
+      this, requestor_url, service_provider.Pass());
+  if (!delegate_->ConfigureIncomingConnection(registry)) {
+    delete registry;
+    return;
+  }
+  incoming_service_registries_.push_back(registry);
+}
+
+}  // namespace mojo
diff --git a/mojo/public/cpp/application/lib/application_runner.cc b/mojo/public/cpp/application/lib/application_runner.cc
new file mode 100644
index 0000000..b451a90
--- /dev/null
+++ b/mojo/public/cpp/application/lib/application_runner.cc
@@ -0,0 +1,36 @@
+// Copyright 2014 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/cpp/application/application_runner.h"
+
+#include "mojo/public/cpp/application/application_delegate.h"
+#include "mojo/public/cpp/application/application_impl.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/utility/run_loop.h"
+
+namespace mojo {
+
+// static
+void ApplicationImpl::Terminate() {
+  RunLoop::current()->Quit();
+}
+
+ApplicationRunner::ApplicationRunner(ApplicationDelegate* delegate)
+    : delegate_(delegate) {}
+ApplicationRunner::~ApplicationRunner() { assert(!delegate_); }
+
+MojoResult ApplicationRunner::Run(MojoHandle shell_handle) {
+  Environment env;
+  {
+    RunLoop loop;
+    ApplicationImpl app(delegate_, shell_handle);
+    loop.Run();
+  }
+
+  delete delegate_;
+  delegate_ = nullptr;
+  return MOJO_RESULT_OK;
+}
+
+}  // namespace mojo
diff --git a/mojo/public/cpp/application/lib/service_connector.cc b/mojo/public/cpp/application/lib/service_connector.cc
new file mode 100644
index 0000000..51e7d84
--- /dev/null
+++ b/mojo/public/cpp/application/lib/service_connector.cc
@@ -0,0 +1,18 @@
+// Copyright 2014 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/cpp/application/lib/service_connector.h"
+
+namespace mojo {
+namespace internal {
+
+ServiceConnectorBase::ServiceConnectorBase(const std::string& name)
+    : name_(name),
+      application_connection_(nullptr) {
+}
+
+ServiceConnectorBase::~ServiceConnectorBase() {}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/application/lib/service_connector.h b/mojo/public/cpp/application/lib/service_connector.h
new file mode 100644
index 0000000..9ddaeb7
--- /dev/null
+++ b/mojo/public/cpp/application/lib/service_connector.h
@@ -0,0 +1,54 @@
+// Copyright 2014 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_CPP_APPLICATION_LIB_SERVICE_CONNECTOR_H_
+#define MOJO_PUBLIC_CPP_APPLICATION_LIB_SERVICE_CONNECTOR_H_
+
+#include "mojo/public/cpp/application/interface_factory.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+
+namespace mojo {
+class ApplicationConnection;
+
+namespace internal {
+
+class ServiceConnectorBase {
+ public:
+  ServiceConnectorBase(const std::string& name);
+  virtual ~ServiceConnectorBase();
+  virtual void ConnectToService(const std::string& name,
+                                ScopedMessagePipeHandle client_handle) = 0;
+  std::string name() const { return name_; }
+  void set_application_connection(ApplicationConnection* connection) {
+      application_connection_ = connection; }
+
+ protected:
+  std::string name_;
+  ApplicationConnection* application_connection_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceConnectorBase);
+};
+
+template <typename Interface>
+class InterfaceFactoryConnector : public ServiceConnectorBase {
+ public:
+  explicit InterfaceFactoryConnector(InterfaceFactory<Interface>* factory)
+      : ServiceConnectorBase(Interface::Name_), factory_(factory) {}
+  virtual ~InterfaceFactoryConnector() {}
+
+  virtual void ConnectToService(const std::string& name,
+                                ScopedMessagePipeHandle client_handle) {
+    factory_->Create(application_connection_,
+                     MakeRequest<Interface>(client_handle.Pass()));
+  }
+
+ private:
+  InterfaceFactory<Interface>* factory_;
+  MOJO_DISALLOW_COPY_AND_ASSIGN(InterfaceFactoryConnector);
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_APPLICATION_LIB_SERVICE_CONNECTOR_H_
diff --git a/mojo/public/cpp/application/lib/service_provider_impl.cc b/mojo/public/cpp/application/lib/service_provider_impl.cc
new file mode 100644
index 0000000..08a0648
--- /dev/null
+++ b/mojo/public/cpp/application/lib/service_provider_impl.cc
@@ -0,0 +1,69 @@
+// Copyright 2014 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/cpp/application/service_provider_impl.h"
+
+#include "mojo/public/cpp/application/lib/service_connector.h"
+#include "mojo/public/cpp/application/lib/weak_service_provider.h"
+#include "mojo/public/cpp/environment/logging.h"
+
+namespace mojo {
+
+ServiceProviderImpl::ServiceProviderImpl() : remote_(nullptr) {
+}
+
+ServiceProviderImpl::~ServiceProviderImpl() {
+}
+
+ServiceProvider* ServiceProviderImpl::CreateRemoteServiceProvider() {
+  // TODO(beng): it sure would be nice if this method could return a scoped_ptr.
+  MOJO_DCHECK(!remote_);
+  remote_ = new internal::WeakServiceProvider(this, client());
+  return remote_;
+}
+
+void ServiceProviderImpl::ConnectToService(
+    const String& service_name,
+    ScopedMessagePipeHandle client_handle) {
+  if (service_connectors_.find(service_name) == service_connectors_.end()) {
+    client_handle.reset();
+    return;
+  }
+
+  internal::ServiceConnectorBase* service_connector =
+      service_connectors_[service_name];
+  return service_connector->ConnectToService(service_name,
+                                             client_handle.Pass());
+}
+
+void ServiceProviderImpl::OnConnectionError() {
+  ClearRemote();
+}
+
+void ServiceProviderImpl::AddServiceConnector(
+    internal::ServiceConnectorBase* service_connector) {
+  RemoveServiceConnector(service_connector);
+  service_connectors_[service_connector->name()] = service_connector;
+  // TODO(beng): perhaps take app connection thru ctor??
+  service_connector->set_application_connection(nullptr);
+}
+
+void ServiceProviderImpl::RemoveServiceConnector(
+    internal::ServiceConnectorBase* service_connector) {
+  NameToServiceConnectorMap::iterator it =
+      service_connectors_.find(service_connector->name());
+  if (it == service_connectors_.end())
+    return;
+  delete it->second;
+  service_connectors_.erase(it);
+}
+
+void ServiceProviderImpl::ClearRemote() {
+  if (remote_) {
+    remote_->Clear();
+    remote_ = nullptr;
+  }
+}
+
+}  // namespace mojo
diff --git a/mojo/public/cpp/application/lib/service_registry.cc b/mojo/public/cpp/application/lib/service_registry.cc
new file mode 100644
index 0000000..c83e84f
--- /dev/null
+++ b/mojo/public/cpp/application/lib/service_registry.cc
@@ -0,0 +1,86 @@
+// Copyright 2014 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/cpp/application/lib/service_registry.h"
+
+#include "mojo/public/cpp/application/application_connection.h"
+#include "mojo/public/cpp/application/application_impl.h"
+#include "mojo/public/cpp/application/lib/service_connector.h"
+
+namespace mojo {
+namespace internal {
+
+ServiceRegistry::ServiceRegistry(ApplicationImpl* application_impl,
+                                 const std::string& url,
+                                 ServiceProviderPtr service_provider)
+    : application_impl_(application_impl),
+      url_(url),
+      remote_service_provider_(service_provider.Pass()) {
+  remote_service_provider_.set_client(this);
+}
+
+ServiceRegistry::ServiceRegistry() : application_impl_(nullptr) {}
+
+ServiceRegistry::~ServiceRegistry() {
+  for (NameToServiceConnectorMap::iterator i =
+           name_to_service_connector_.begin();
+       i != name_to_service_connector_.end(); ++i) {
+    delete i->second;
+  }
+  name_to_service_connector_.clear();
+}
+
+void ServiceRegistry::AddServiceConnector(
+    ServiceConnectorBase* service_connector) {
+  RemoveServiceConnectorInternal(service_connector);
+  name_to_service_connector_[service_connector->name()] = service_connector;
+  service_connector->set_application_connection(this);
+}
+
+void ServiceRegistry::RemoveServiceConnector(
+    ServiceConnectorBase* service_connector) {
+  RemoveServiceConnectorInternal(service_connector);
+  if (name_to_service_connector_.empty())
+    remote_service_provider_.reset();
+}
+
+bool ServiceRegistry::RemoveServiceConnectorInternal(
+    ServiceConnectorBase* service_connector) {
+  NameToServiceConnectorMap::iterator it =
+      name_to_service_connector_.find(service_connector->name());
+  if (it == name_to_service_connector_.end())
+    return false;
+  delete it->second;
+  name_to_service_connector_.erase(it);
+  return true;
+}
+
+const std::string& ServiceRegistry::GetRemoteApplicationURL() {
+  return url_;
+}
+
+ServiceProvider* ServiceRegistry::GetServiceProvider() {
+  return remote_service_provider_.get();
+}
+
+ApplicationConnection* ServiceRegistry::ConnectToApplication(
+    const std::string& url) {
+  return application_impl_->ConnectToApplication(url);
+}
+
+void ServiceRegistry::ConnectToService(const mojo::String& service_name,
+                                       ScopedMessagePipeHandle client_handle) {
+  if (name_to_service_connector_.find(service_name) ==
+      name_to_service_connector_.end()) {
+    client_handle.reset();
+    return;
+  }
+  internal::ServiceConnectorBase* service_connector =
+      name_to_service_connector_[service_name];
+  return service_connector->ConnectToService(service_name,
+                                             client_handle.Pass());
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/application/lib/service_registry.h b/mojo/public/cpp/application/lib/service_registry.h
new file mode 100644
index 0000000..32d4b2b
--- /dev/null
+++ b/mojo/public/cpp/application/lib/service_registry.h
@@ -0,0 +1,65 @@
+// Copyright 2014 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_CPP_APPLICATION_LIB_SERVICE_REGISTRY_H_
+#define MOJO_PUBLIC_CPP_APPLICATION_LIB_SERVICE_REGISTRY_H_
+
+#include "mojo/public/cpp/application/application_connection.h"
+#include "mojo/public/interfaces/application/service_provider.mojom.h"
+
+namespace mojo {
+
+class Application;
+class ApplicationImpl;
+
+namespace internal {
+
+class ServiceConnectorBase;
+
+// A ServiceRegistry represents each half of a connection between two
+// applications, allowing customization of which services are published to the
+// other.
+class ServiceRegistry : public ServiceProvider, public ApplicationConnection {
+ public:
+  ServiceRegistry();
+  ServiceRegistry(ApplicationImpl* application_impl,
+                  const std::string& url,
+                  ServiceProviderPtr service_provider);
+  virtual ~ServiceRegistry();
+
+  // ApplicationConnection overrides.
+  virtual void AddServiceConnector(
+      ServiceConnectorBase* service_connector) override;
+  virtual const std::string& GetRemoteApplicationURL() override;
+  virtual ApplicationConnection* ConnectToApplication(
+      const std::string& url) override;
+  virtual ServiceProvider* GetServiceProvider() override;
+
+  virtual void RemoveServiceConnector(ServiceConnectorBase* service_connector);
+
+ private:
+  // ServiceProvider method.
+  virtual void ConnectToService(const mojo::String& service_name,
+                                ScopedMessagePipeHandle client_handle) override;
+
+  ApplicationImpl* application_impl_;
+  const std::string url_;
+
+ private:
+  bool RemoveServiceConnectorInternal(
+      ServiceConnectorBase* service_connector);
+
+  Application* application_;
+  typedef std::map<std::string, ServiceConnectorBase*>
+      NameToServiceConnectorMap;
+  NameToServiceConnectorMap name_to_service_connector_;
+  ServiceProviderPtr remote_service_provider_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceRegistry);
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_APPLICATION_LIB_SERVICE_REGISTRY_H_
diff --git a/mojo/public/cpp/application/lib/weak_service_provider.cc b/mojo/public/cpp/application/lib/weak_service_provider.cc
new file mode 100644
index 0000000..b0d2511
--- /dev/null
+++ b/mojo/public/cpp/application/lib/weak_service_provider.cc
@@ -0,0 +1,36 @@
+// Copyright 2014 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/cpp/application/lib/weak_service_provider.h"
+
+#include "mojo/public/cpp/application/service_provider_impl.h"
+#include "mojo/public/interfaces/application/service_provider.mojom.h"
+
+namespace mojo {
+namespace internal {
+
+WeakServiceProvider::WeakServiceProvider(ServiceProviderImpl* creator,
+                                         ServiceProvider* service_provider)
+      : creator_(creator),
+        service_provider_(service_provider) {}
+
+WeakServiceProvider::~WeakServiceProvider() {
+  if (creator_)
+    creator_->ClearRemote();
+}
+
+void WeakServiceProvider::Clear() {
+  creator_ = nullptr;
+  service_provider_ = nullptr;
+}
+
+void WeakServiceProvider::ConnectToService(
+    const String& service_name,
+    ScopedMessagePipeHandle client_handle) {
+  if (service_provider_)
+    service_provider_->ConnectToService(service_name, client_handle.Pass());
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/application/lib/weak_service_provider.h b/mojo/public/cpp/application/lib/weak_service_provider.h
new file mode 100644
index 0000000..05ce939
--- /dev/null
+++ b/mojo/public/cpp/application/lib/weak_service_provider.h
@@ -0,0 +1,41 @@
+// Copyright 2014 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_APPLICATION_LIB_WEAK_SERVICE_PROVIDER_H_
+#define MOJO_PUBLIC_APPLICATION_LIB_WEAK_SERVICE_PROVIDER_H_
+
+#include "mojo/public/interfaces/application/service_provider.mojom.h"
+
+namespace mojo {
+class ServiceProviderImpl;
+namespace internal {
+class ServiceConnectorBase;
+
+// Implements a weak pointer to a ServiceProvider. Necessary as the lifetime of
+// the ServiceProviderImpl is bound to that of its pipe, but code may continue
+// to reference a remote service provider beyond the lifetime of said pipe.
+// Calls to ConnectToService() are silently dropped when the pipe is closed.
+class WeakServiceProvider : public ServiceProvider {
+ public:
+  WeakServiceProvider(ServiceProviderImpl* creator,
+                      ServiceProvider* service_provider);
+  virtual ~WeakServiceProvider();
+
+  void Clear();
+
+ private:
+  // Overridden from ServiceProvider:
+  virtual void ConnectToService(const String& service_name,
+                                ScopedMessagePipeHandle client_handle) override;
+
+  ServiceProviderImpl* creator_;
+  ServiceProvider* service_provider_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(WeakServiceProvider);
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_APPLICATION_LIB_WEAK_SERVICE_PROVIDER_H_
diff --git a/mojo/public/cpp/application/service_provider_impl.h b/mojo/public/cpp/application/service_provider_impl.h
new file mode 100644
index 0000000..f388511
--- /dev/null
+++ b/mojo/public/cpp/application/service_provider_impl.h
@@ -0,0 +1,67 @@
+// Copyright 2014 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_APPLICATION_SERVICE_PROVIDER_IMPL_H_
+#define MOJO_PUBLIC_APPLICATION_SERVICE_PROVIDER_IMPL_H_
+
+#include "mojo/public/cpp/application/lib/service_connector.h"
+#include "mojo/public/interfaces/application/service_provider.mojom.h"
+
+namespace mojo {
+namespace internal {
+class WeakServiceProvider;
+class ServiceConnectorBase;
+}
+
+// Implements a registry that can be used to expose services to another app.
+class ServiceProviderImpl : public InterfaceImpl<ServiceProvider> {
+ public:
+  ServiceProviderImpl();
+  virtual ~ServiceProviderImpl();
+
+  template <typename Interface>
+  void AddService(InterfaceFactory<Interface>* factory) {
+    AddServiceConnector(
+        new internal::InterfaceFactoryConnector<Interface>(factory));
+  }
+
+  // Returns an instance of a ServiceProvider that weakly wraps this impl's
+  // connection to some other app. Whereas the lifetime of an instance of
+  // ServiceProviderImpl is bound to the lifetime of the pipe it
+  // encapsulates, the lifetime of the ServiceProvider instance returned by this
+  // method is assumed by the caller. After the pipe is closed
+  // ConnectToService() calls on this object will be silently dropped.
+  // This method must only be called once per ServiceProviderImpl.
+  ServiceProvider* CreateRemoteServiceProvider();
+
+ private:
+  typedef std::map<std::string, internal::ServiceConnectorBase*>
+      NameToServiceConnectorMap;
+
+  friend class internal::WeakServiceProvider;
+
+  // Overridden from ServiceProvider:
+  virtual void ConnectToService(const String& service_name,
+                                ScopedMessagePipeHandle client_handle) override;
+
+  // Overridden from InterfaceImpl:
+  virtual void OnConnectionError() override;
+
+  void AddServiceConnector(
+      internal::ServiceConnectorBase* service_connector);
+  void RemoveServiceConnector(
+      internal::ServiceConnectorBase* service_connector);
+
+  void ClearRemote();
+
+  NameToServiceConnectorMap service_connectors_;
+
+  internal::WeakServiceProvider* remote_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceProviderImpl);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_APPLICATION_SERVICE_PROVIDER_IMPL_H_
diff --git a/mojo/public/cpp/application/tests/BUILD.gn b/mojo/public/cpp/application/tests/BUILD.gn
new file mode 100644
index 0000000..4c22c19
--- /dev/null
+++ b/mojo/public/cpp/application/tests/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2014 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.
+
+# GYP version: mojo/mojo_public_tests.gypi:mojo_public_application_unittests
+test("mojo_public_application_unittests") {
+  deps = [
+    "//base",
+    "//mojo/common/test:run_all_unittests",
+    "//mojo/public/cpp/application:standalone",
+    "//mojo/public/cpp/environment:standalone",
+    "//mojo/public/cpp/utility",
+    "//testing/gtest",
+  ]
+
+  sources = [ "service_registry_unittest.cc" ]
+}
diff --git a/mojo/public/cpp/application/tests/service_registry_unittest.cc b/mojo/public/cpp/application/tests/service_registry_unittest.cc
new file mode 100644
index 0000000..a0511ff
--- /dev/null
+++ b/mojo/public/cpp/application/tests/service_registry_unittest.cc
@@ -0,0 +1,66 @@
+// Copyright 2014 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/cpp/application/lib/service_registry.h"
+
+#include "mojo/public/cpp/application/lib/service_connector.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace internal {
+namespace {
+
+class TestConnector : public ServiceConnectorBase {
+ public:
+  TestConnector(const std::string& name, int* delete_count)
+      : ServiceConnectorBase(name), delete_count_(delete_count) {}
+  virtual ~TestConnector() { (*delete_count_)++; }
+  virtual void ConnectToService(
+      const std::string& name,
+      ScopedMessagePipeHandle client_handle) override {}
+
+ private:
+  int* delete_count_;
+};
+
+TEST(ServiceRegistryTest, Ownership) {
+  int delete_count = 0;
+
+  // Destruction.
+  {
+    ServiceRegistry registry;
+    registry.AddServiceConnector(new TestConnector("TC1", &delete_count));
+  }
+  EXPECT_EQ(1, delete_count);
+
+  // Removal.
+  {
+    ServiceRegistry registry;
+    ServiceConnectorBase* c = new TestConnector("TC1", &delete_count);
+    registry.AddServiceConnector(c);
+    registry.RemoveServiceConnector(c);
+    EXPECT_EQ(2, delete_count);
+  }
+
+  // Multiple.
+  {
+    ServiceRegistry registry;
+    registry.AddServiceConnector(new TestConnector("TC1", &delete_count));
+    registry.AddServiceConnector(new TestConnector("TC2", &delete_count));
+  }
+  EXPECT_EQ(4, delete_count);
+
+  // Re-addition.
+  {
+    ServiceRegistry registry;
+    registry.AddServiceConnector(new TestConnector("TC1", &delete_count));
+    registry.AddServiceConnector(new TestConnector("TC1", &delete_count));
+    EXPECT_EQ(5, delete_count);
+  }
+  EXPECT_EQ(6, delete_count);
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
new file mode 100644
index 0000000..dad10d8
--- /dev/null
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -0,0 +1,66 @@
+# Copyright 2014 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.
+
+source_set("bindings") {
+  sources = [
+    "array.h",
+    "error_handler.h",
+    "interface_ptr.h",
+    "message.h",
+    "message_filter.h",
+    "no_interface.h",
+    "string.h",
+    "struct_ptr.h",
+    "type_converter.h",
+    "lib/array_internal.cc",
+    "lib/array_internal.h",
+    "lib/array_serialization.h",
+    "lib/bindings_internal.h",
+    "lib/bindings_serialization.cc",
+    "lib/bindings_serialization.h",
+    "lib/bounds_checker.cc",
+    "lib/bounds_checker.h",
+    "lib/buffer.h",
+    "lib/connector.cc",
+    "lib/connector.h",
+    "lib/filter_chain.cc",
+    "lib/filter_chain.h",
+    "lib/fixed_buffer.cc",
+    "lib/fixed_buffer.h",
+    "lib/message.cc",
+    "lib/message_builder.cc",
+    "lib/message_builder.h",
+    "lib/message_filter.cc",
+    "lib/message_header_validator.cc",
+    "lib/message_header_validator.h",
+    "lib/message_internal.h",
+    "lib/message_queue.cc",
+    "lib/message_queue.h",
+    "lib/no_interface.cc",
+    "lib/router.cc",
+    "lib/router.h",
+    "lib/string_serialization.cc",
+    "lib/string_serialization.h",
+    "lib/validation_errors.cc",
+    "lib/validation_errors.h",
+  ]
+
+  deps = [
+    ":callback",
+    "//mojo/public/cpp/environment",
+    "//mojo/public/cpp/system",
+  ]
+}
+
+source_set("callback") {
+  sources = [
+    "callback.h",
+    "lib/callback_internal.h",
+    "lib/template_util.h",
+    "lib/shared_data.h",
+    "lib/shared_ptr.h",
+  ]
+
+  deps = [ "//mojo/public/cpp/system" ]
+}
diff --git a/mojo/public/cpp/bindings/DEPS b/mojo/public/cpp/bindings/DEPS
new file mode 100644
index 0000000..2a0496e
--- /dev/null
+++ b/mojo/public/cpp/bindings/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+mojo/public/cpp/environment",
+]
diff --git a/mojo/public/cpp/bindings/array.h b/mojo/public/cpp/bindings/array.h
new file mode 100644
index 0000000..53c8c18
--- /dev/null
+++ b/mojo/public/cpp/bindings/array.h
@@ -0,0 +1,159 @@
+// Copyright 2013 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_CPP_BINDINGS_ARRAY_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_
+
+#include <string.h>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+#include "mojo/public/cpp/bindings/type_converter.h"
+
+namespace mojo {
+
+// Provides read-only access to array data.
+template <typename T>
+class Array {
+  MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(Array, RValue)
+ public:
+  typedef internal::ArrayTraits<T, internal::IsMoveOnlyType<T>::value>
+      Traits;
+  typedef typename Traits::ConstRefType ConstRefType;
+  typedef typename Traits::RefType RefType;
+  typedef typename Traits::StorageType StorageType;
+  typedef typename Traits::ForwardType ForwardType;
+
+  typedef internal::Array_Data<typename internal::WrapperTraits<T>::DataType>
+      Data_;
+
+  Array() : is_null_(true) {}
+  explicit Array(size_t size) : vec_(size), is_null_(false) {
+    Traits::Initialize(&vec_);
+  }
+  ~Array() { Traits::Finalize(&vec_); }
+
+  Array(RValue other) : is_null_(true) { Take(other.object); }
+  Array& operator=(RValue other) {
+    Take(other.object);
+    return *this;
+  }
+
+  static Array New(size_t size) {
+    return Array(size).Pass();
+  }
+
+  template <typename U>
+  static Array From(const U& other) {
+    return TypeConverter<Array, U>::Convert(other);
+  }
+
+  template <typename U>
+  U To() const {
+    return TypeConverter<U, Array>::Convert(*this);
+  }
+
+  void reset() {
+    if (!vec_.empty()) {
+      Traits::Finalize(&vec_);
+      vec_.clear();
+    }
+    is_null_ = true;
+  }
+
+  bool is_null() const { return is_null_; }
+
+  ConstRefType front() const { return vec_.front(); }
+  RefType front() { return vec_.front(); }
+
+  size_t size() const { return vec_.size(); }
+
+  ConstRefType at(size_t offset) const { return Traits::at(&vec_, offset); }
+  ConstRefType operator[](size_t offset) const { return at(offset); }
+
+  RefType at(size_t offset) { return Traits::at(&vec_, offset); }
+  RefType operator[](size_t offset) { return at(offset); }
+
+  void push_back(ForwardType value) {
+    is_null_ = false;
+    Traits::PushBack(&vec_, value);
+  }
+
+  void resize(size_t size) {
+    is_null_ = false;
+    Traits::Resize(&vec_, size);
+  }
+
+  const std::vector<StorageType>& storage() const {
+    return vec_;
+  }
+  operator const std::vector<StorageType>&() const {
+    return vec_;
+  }
+
+  void Swap(Array* other) {
+    std::swap(is_null_, other->is_null_);
+    vec_.swap(other->vec_);
+  }
+  void Swap(std::vector<StorageType>* other) {
+    is_null_ = false;
+    vec_.swap(*other);
+  }
+
+  // Please note that calling this method will fail compilation if the element
+  // type cannot be cloned (which usually means that it is a Mojo handle type or
+  // a type contains Mojo handles).
+  Array Clone() const {
+    Array result;
+    result.is_null_ = is_null_;
+    Traits::Clone(vec_, &result.vec_);
+    return result.Pass();
+  }
+
+ private:
+  typedef std::vector<StorageType> Array::*Testable;
+
+ public:
+  operator Testable() const { return is_null_ ? 0 : &Array::vec_; }
+
+ private:
+  void Take(Array* other) {
+    reset();
+    Swap(other);
+  }
+
+  std::vector<StorageType> vec_;
+  bool is_null_;
+};
+
+template <typename T, typename E>
+struct TypeConverter<Array<T>, std::vector<E> > {
+  static Array<T> Convert(const std::vector<E>& input) {
+    Array<T> result(input.size());
+    for (size_t i = 0; i < input.size(); ++i)
+      result[i] = TypeConverter<T, E>::Convert(input[i]);
+    return result.Pass();
+  }
+};
+
+template <typename E, typename T>
+struct TypeConverter<std::vector<E>, Array<T> > {
+  static std::vector<E> Convert(const Array<T>& input) {
+    std::vector<E> result;
+    if (!input.is_null()) {
+      result.resize(input.size());
+      for (size_t i = 0; i < input.size(); ++i)
+        result[i] = TypeConverter<E, T>::Convert(input[i]);
+    }
+    return result;
+  }
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_
diff --git a/mojo/public/cpp/bindings/callback.h b/mojo/public/cpp/bindings/callback.h
new file mode 100644
index 0000000..0cd4924
--- /dev/null
+++ b/mojo/public/cpp/bindings/callback.h
@@ -0,0 +1,522 @@
+// This file was GENERATED by command:
+//     pump.py callback.h.pump
+// DO NOT EDIT BY HAND!!!
+
+
+
+// Copyright 2014 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_CPP_BINDINGS_CALLBACK_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_
+
+#include "mojo/public/cpp/bindings/lib/callback_internal.h"
+#include "mojo/public/cpp/bindings/lib/shared_ptr.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+
+namespace mojo {
+
+template <typename Sig>
+class Callback;
+
+template <>
+class Callback<void()> {
+ public:
+  struct Runnable {
+    virtual ~Runnable() {}
+    virtual void Run() const = 0;
+  };
+
+  Callback() {}
+
+  // The Callback assumes ownership of |runnable|.
+  explicit Callback(Runnable* runnable) : sink_(runnable) {}
+
+  // Any class that is copy-constructable and has a compatible Run method may
+  // be adapted to a Callback using this constructor.
+  template <typename Sink>
+  Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {}
+
+  void Run() const {
+    if (sink_.get())
+      sink_->Run();
+  }
+
+  bool is_null() const {
+    return !sink_.get();
+  }
+
+  void reset() {
+    sink_.reset();
+  }
+
+ private:
+  template <typename Sink>
+  struct Adapter : public Runnable {
+    explicit Adapter(const Sink& sink) : sink(sink) {}
+    virtual void Run() const override { sink.Run(); }
+    Sink sink;
+  };
+
+  internal::SharedPtr<Runnable> sink_;
+};
+
+template <typename A1>
+class Callback<void(A1)> {
+ public:
+  struct Runnable {
+    virtual ~Runnable() {}
+    virtual void Run(
+        typename internal::Callback_ParamTraits<A1>::ForwardType a1) const = 0;
+  };
+
+  Callback() {}
+
+  // The Callback assumes ownership of |runnable|.
+  explicit Callback(Runnable* runnable) : sink_(runnable) {}
+
+  // Any class that is copy-constructable and has a compatible Run method may
+  // be adapted to a Callback using this constructor.
+  template <typename Sink>
+  Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {}
+
+  void Run(typename internal::Callback_ParamTraits<A1>::ForwardType a1) const {
+    if (sink_.get())
+      sink_->Run(internal::Forward(a1));
+  }
+
+  bool is_null() const {
+    return !sink_.get();
+  }
+
+  void reset() {
+    sink_.reset();
+  }
+
+ private:
+  template <typename Sink>
+  struct Adapter : public Runnable {
+    explicit Adapter(const Sink& sink) : sink(sink) {}
+    virtual void Run(typename internal::Callback_ParamTraits<A1>::ForwardType
+                         a1) const override {
+      sink.Run(internal::Forward(a1));
+    }
+    Sink sink;
+  };
+
+  internal::SharedPtr<Runnable> sink_;
+};
+
+template <typename A1, typename A2>
+class Callback<void(A1, A2)> {
+ public:
+  struct Runnable {
+    virtual ~Runnable() {}
+    virtual void Run(
+        typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+        typename internal::Callback_ParamTraits<A2>::ForwardType a2) const = 0;
+  };
+
+  Callback() {}
+
+  // The Callback assumes ownership of |runnable|.
+  explicit Callback(Runnable* runnable) : sink_(runnable) {}
+
+  // Any class that is copy-constructable and has a compatible Run method may
+  // be adapted to a Callback using this constructor.
+  template <typename Sink>
+  Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {}
+
+  void Run(
+      typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+      typename internal::Callback_ParamTraits<A2>::ForwardType a2) const {
+    if (sink_.get())
+      sink_->Run(
+          internal::Forward(a1),
+          internal::Forward(a2));
+  }
+
+  bool is_null() const {
+    return !sink_.get();
+  }
+
+  void reset() {
+    sink_.reset();
+  }
+
+ private:
+  template <typename Sink>
+  struct Adapter : public Runnable {
+    explicit Adapter(const Sink& sink) : sink(sink) {}
+    virtual void Run(
+        typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+        typename internal::Callback_ParamTraits<A2>::ForwardType a2)
+        const override {
+      sink.Run(
+          internal::Forward(a1),
+          internal::Forward(a2));
+    }
+    Sink sink;
+  };
+
+  internal::SharedPtr<Runnable> sink_;
+};
+
+template <typename A1, typename A2, typename A3>
+class Callback<void(A1, A2, A3)> {
+ public:
+  struct Runnable {
+    virtual ~Runnable() {}
+    virtual void Run(
+        typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+        typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+        typename internal::Callback_ParamTraits<A3>::ForwardType a3) const = 0;
+  };
+
+  Callback() {}
+
+  // The Callback assumes ownership of |runnable|.
+  explicit Callback(Runnable* runnable) : sink_(runnable) {}
+
+  // Any class that is copy-constructable and has a compatible Run method may
+  // be adapted to a Callback using this constructor.
+  template <typename Sink>
+  Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {}
+
+  void Run(
+      typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+      typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+      typename internal::Callback_ParamTraits<A3>::ForwardType a3) const {
+    if (sink_.get())
+      sink_->Run(
+          internal::Forward(a1),
+          internal::Forward(a2),
+          internal::Forward(a3));
+  }
+
+  bool is_null() const {
+    return !sink_.get();
+  }
+
+  void reset() {
+    sink_.reset();
+  }
+
+ private:
+  template <typename Sink>
+  struct Adapter : public Runnable {
+    explicit Adapter(const Sink& sink) : sink(sink) {}
+    virtual void Run(
+        typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+        typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+        typename internal::Callback_ParamTraits<A3>::ForwardType a3)
+        const override {
+      sink.Run(
+          internal::Forward(a1),
+          internal::Forward(a2),
+          internal::Forward(a3));
+    }
+    Sink sink;
+  };
+
+  internal::SharedPtr<Runnable> sink_;
+};
+
+template <typename A1, typename A2, typename A3, typename A4>
+class Callback<void(A1, A2, A3, A4)> {
+ public:
+  struct Runnable {
+    virtual ~Runnable() {}
+    virtual void Run(
+        typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+        typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+        typename internal::Callback_ParamTraits<A3>::ForwardType a3,
+        typename internal::Callback_ParamTraits<A4>::ForwardType a4) const = 0;
+  };
+
+  Callback() {}
+
+  // The Callback assumes ownership of |runnable|.
+  explicit Callback(Runnable* runnable) : sink_(runnable) {}
+
+  // Any class that is copy-constructable and has a compatible Run method may
+  // be adapted to a Callback using this constructor.
+  template <typename Sink>
+  Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {}
+
+  void Run(
+      typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+      typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+      typename internal::Callback_ParamTraits<A3>::ForwardType a3,
+      typename internal::Callback_ParamTraits<A4>::ForwardType a4) const {
+    if (sink_.get())
+      sink_->Run(
+          internal::Forward(a1),
+          internal::Forward(a2),
+          internal::Forward(a3),
+          internal::Forward(a4));
+  }
+
+  bool is_null() const {
+    return !sink_.get();
+  }
+
+  void reset() {
+    sink_.reset();
+  }
+
+ private:
+  template <typename Sink>
+  struct Adapter : public Runnable {
+    explicit Adapter(const Sink& sink) : sink(sink) {}
+    virtual void Run(
+        typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+        typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+        typename internal::Callback_ParamTraits<A3>::ForwardType a3,
+        typename internal::Callback_ParamTraits<A4>::ForwardType a4)
+        const override {
+      sink.Run(
+          internal::Forward(a1),
+          internal::Forward(a2),
+          internal::Forward(a3),
+          internal::Forward(a4));
+    }
+    Sink sink;
+  };
+
+  internal::SharedPtr<Runnable> sink_;
+};
+
+template <typename A1, typename A2, typename A3, typename A4, typename A5>
+class Callback<void(A1, A2, A3, A4, A5)> {
+ public:
+  struct Runnable {
+    virtual ~Runnable() {}
+    virtual void Run(
+        typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+        typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+        typename internal::Callback_ParamTraits<A3>::ForwardType a3,
+        typename internal::Callback_ParamTraits<A4>::ForwardType a4,
+        typename internal::Callback_ParamTraits<A5>::ForwardType a5) const = 0;
+  };
+
+  Callback() {}
+
+  // The Callback assumes ownership of |runnable|.
+  explicit Callback(Runnable* runnable) : sink_(runnable) {}
+
+  // Any class that is copy-constructable and has a compatible Run method may
+  // be adapted to a Callback using this constructor.
+  template <typename Sink>
+  Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {}
+
+  void Run(
+      typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+      typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+      typename internal::Callback_ParamTraits<A3>::ForwardType a3,
+      typename internal::Callback_ParamTraits<A4>::ForwardType a4,
+      typename internal::Callback_ParamTraits<A5>::ForwardType a5) const {
+    if (sink_.get())
+      sink_->Run(
+          internal::Forward(a1),
+          internal::Forward(a2),
+          internal::Forward(a3),
+          internal::Forward(a4),
+          internal::Forward(a5));
+  }
+
+  bool is_null() const {
+    return !sink_.get();
+  }
+
+  void reset() {
+    sink_.reset();
+  }
+
+ private:
+  template <typename Sink>
+  struct Adapter : public Runnable {
+    explicit Adapter(const Sink& sink) : sink(sink) {}
+    virtual void Run(
+        typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+        typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+        typename internal::Callback_ParamTraits<A3>::ForwardType a3,
+        typename internal::Callback_ParamTraits<A4>::ForwardType a4,
+        typename internal::Callback_ParamTraits<A5>::ForwardType a5)
+        const override {
+      sink.Run(
+          internal::Forward(a1),
+          internal::Forward(a2),
+          internal::Forward(a3),
+          internal::Forward(a4),
+          internal::Forward(a5));
+    }
+    Sink sink;
+  };
+
+  internal::SharedPtr<Runnable> sink_;
+};
+
+template <typename A1, typename A2, typename A3, typename A4, typename A5,
+    typename A6>
+class Callback<void(A1, A2, A3, A4, A5, A6)> {
+ public:
+  struct Runnable {
+    virtual ~Runnable() {}
+    virtual void Run(
+        typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+        typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+        typename internal::Callback_ParamTraits<A3>::ForwardType a3,
+        typename internal::Callback_ParamTraits<A4>::ForwardType a4,
+        typename internal::Callback_ParamTraits<A5>::ForwardType a5,
+        typename internal::Callback_ParamTraits<A6>::ForwardType a6) const = 0;
+  };
+
+  Callback() {}
+
+  // The Callback assumes ownership of |runnable|.
+  explicit Callback(Runnable* runnable) : sink_(runnable) {}
+
+  // Any class that is copy-constructable and has a compatible Run method may
+  // be adapted to a Callback using this constructor.
+  template <typename Sink>
+  Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {}
+
+  void Run(
+      typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+      typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+      typename internal::Callback_ParamTraits<A3>::ForwardType a3,
+      typename internal::Callback_ParamTraits<A4>::ForwardType a4,
+      typename internal::Callback_ParamTraits<A5>::ForwardType a5,
+      typename internal::Callback_ParamTraits<A6>::ForwardType a6) const {
+    if (sink_.get())
+      sink_->Run(
+          internal::Forward(a1),
+          internal::Forward(a2),
+          internal::Forward(a3),
+          internal::Forward(a4),
+          internal::Forward(a5),
+          internal::Forward(a6));
+  }
+
+  bool is_null() const {
+    return !sink_.get();
+  }
+
+  void reset() {
+    sink_.reset();
+  }
+
+ private:
+  template <typename Sink>
+  struct Adapter : public Runnable {
+    explicit Adapter(const Sink& sink) : sink(sink) {}
+    virtual void Run(
+        typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+        typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+        typename internal::Callback_ParamTraits<A3>::ForwardType a3,
+        typename internal::Callback_ParamTraits<A4>::ForwardType a4,
+        typename internal::Callback_ParamTraits<A5>::ForwardType a5,
+        typename internal::Callback_ParamTraits<A6>::ForwardType a6)
+        const override {
+      sink.Run(
+          internal::Forward(a1),
+          internal::Forward(a2),
+          internal::Forward(a3),
+          internal::Forward(a4),
+          internal::Forward(a5),
+          internal::Forward(a6));
+    }
+    Sink sink;
+  };
+
+  internal::SharedPtr<Runnable> sink_;
+};
+
+template <typename A1, typename A2, typename A3, typename A4, typename A5,
+    typename A6, typename A7>
+class Callback<void(A1, A2, A3, A4, A5, A6, A7)> {
+ public:
+  struct Runnable {
+    virtual ~Runnable() {}
+    virtual void Run(
+        typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+        typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+        typename internal::Callback_ParamTraits<A3>::ForwardType a3,
+        typename internal::Callback_ParamTraits<A4>::ForwardType a4,
+        typename internal::Callback_ParamTraits<A5>::ForwardType a5,
+        typename internal::Callback_ParamTraits<A6>::ForwardType a6,
+        typename internal::Callback_ParamTraits<A7>::ForwardType a7) const = 0;
+  };
+
+  Callback() {}
+
+  // The Callback assumes ownership of |runnable|.
+  explicit Callback(Runnable* runnable) : sink_(runnable) {}
+
+  // Any class that is copy-constructable and has a compatible Run method may
+  // be adapted to a Callback using this constructor.
+  template <typename Sink>
+  Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {}
+
+  void Run(
+      typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+      typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+      typename internal::Callback_ParamTraits<A3>::ForwardType a3,
+      typename internal::Callback_ParamTraits<A4>::ForwardType a4,
+      typename internal::Callback_ParamTraits<A5>::ForwardType a5,
+      typename internal::Callback_ParamTraits<A6>::ForwardType a6,
+      typename internal::Callback_ParamTraits<A7>::ForwardType a7) const {
+    if (sink_.get())
+      sink_->Run(
+          internal::Forward(a1),
+          internal::Forward(a2),
+          internal::Forward(a3),
+          internal::Forward(a4),
+          internal::Forward(a5),
+          internal::Forward(a6),
+          internal::Forward(a7));
+  }
+
+  bool is_null() const {
+    return !sink_.get();
+  }
+
+  void reset() {
+    sink_.reset();
+  }
+
+ private:
+  template <typename Sink>
+  struct Adapter : public Runnable {
+    explicit Adapter(const Sink& sink) : sink(sink) {}
+    virtual void Run(
+        typename internal::Callback_ParamTraits<A1>::ForwardType a1,
+        typename internal::Callback_ParamTraits<A2>::ForwardType a2,
+        typename internal::Callback_ParamTraits<A3>::ForwardType a3,
+        typename internal::Callback_ParamTraits<A4>::ForwardType a4,
+        typename internal::Callback_ParamTraits<A5>::ForwardType a5,
+        typename internal::Callback_ParamTraits<A6>::ForwardType a6,
+        typename internal::Callback_ParamTraits<A7>::ForwardType a7)
+        const override {
+      sink.Run(
+          internal::Forward(a1),
+          internal::Forward(a2),
+          internal::Forward(a3),
+          internal::Forward(a4),
+          internal::Forward(a5),
+          internal::Forward(a6),
+          internal::Forward(a7));
+    }
+    Sink sink;
+  };
+
+  internal::SharedPtr<Runnable> sink_;
+};
+
+typedef Callback<void()> Closure;
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_
diff --git a/mojo/public/cpp/bindings/callback.h.pump b/mojo/public/cpp/bindings/callback.h.pump
new file mode 100644
index 0000000..856e85b
--- /dev/null
+++ b/mojo/public/cpp/bindings/callback.h.pump
@@ -0,0 +1,95 @@
+$$ This is a pump file for generating file templates.  Pump is a python
+$$ script that is part of the Google Test suite of utilities.  Description
+$$ can be found here:
+$$
+$$ http://code.google.com/p/googletest/wiki/PumpManual
+$$
+
+$var MAX_ARITY = 7
+
+// Copyright 2014 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_CPP_BINDINGS_CALLBACK_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_
+
+#include "mojo/public/cpp/bindings/lib/callback_internal.h"
+#include "mojo/public/cpp/bindings/lib/shared_ptr.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+
+namespace mojo {
+
+template <typename Sig>
+class Callback;
+
+$range ARITY 0..MAX_ARITY
+$for ARITY [[
+$range ARG 1..ARITY
+
+template <$for ARG , [[typename A$(ARG)]]>
+class Callback<void($for ARG , [[A$(ARG)]])> {
+ public:
+  struct Runnable {
+    virtual ~Runnable() {}
+    virtual void Run($if ARITY > 0 [[
+
+        ]]$for ARG ,
+        [[typename internal::Callback_ParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) const = 0;
+  };
+
+  Callback() {}
+
+  // The Callback assumes ownership of |runnable|.
+  explicit Callback(Runnable* runnable) : sink_(runnable) {}
+
+  // Any class that is copy-constructable and has a compatible Run method may
+  // be adapted to a Callback using this constructor.
+  template <typename Sink>
+  Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {}
+
+  void Run($if ARITY > 1 [[
+
+      ]]$for ARG ,
+      [[typename internal::Callback_ParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) const {
+    if (sink_.get())
+      sink_->Run($if ARITY > 1 [[
+
+          ]]$for ARG ,
+          [[internal::Forward(a$(ARG))]]);
+  }
+
+  bool is_null() const {
+    return !sink_.get();
+  }
+
+  void reset() {
+    sink_.reset();
+  }
+
+ private:
+  template <typename Sink>
+  struct Adapter : public Runnable {
+    explicit Adapter(const Sink& sink) : sink(sink) {}
+    virtual void Run($if ARITY > 0 [[
+
+        ]]$for ARG ,
+        [[typename internal::Callback_ParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) const override {
+      sink.Run($if ARITY > 1 [[
+
+          ]]$for ARG ,
+          [[internal::Forward(a$(ARG))]]);
+    }
+    Sink sink;
+  };
+
+  internal::SharedPtr<Runnable> sink_;
+};
+
+]]  $$ for ARITY
+
+typedef Callback<void()> Closure;
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_
diff --git a/mojo/public/cpp/bindings/error_handler.h b/mojo/public/cpp/bindings/error_handler.h
new file mode 100644
index 0000000..8ce1af2
--- /dev/null
+++ b/mojo/public/cpp/bindings/error_handler.h
@@ -0,0 +1,19 @@
+// Copyright 2014 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_CPP_BINDINGS_ERROR_HANDLER_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_ERROR_HANDLER_H_
+
+namespace mojo {
+
+// This interface is used to report connection errors.
+class ErrorHandler {
+ public:
+  virtual ~ErrorHandler() {}
+  virtual void OnConnectionError() = 0;
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_ERROR_HANDLER_H_
diff --git a/mojo/public/cpp/bindings/interface_impl.h b/mojo/public/cpp/bindings/interface_impl.h
new file mode 100644
index 0000000..da1055d
--- /dev/null
+++ b/mojo/public/cpp/bindings/interface_impl.h
@@ -0,0 +1,152 @@
+// Copyright 2014 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_CPP_BINDINGS_INTERFACE_IMPL_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_IMPL_H_
+
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/lib/interface_impl_internal.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+
+// InterfaceImpl<..> is designed to be the base class of an interface
+// implementation. It may be bound to a pipe or a proxy, see BindToPipe and
+// BindToProxy.
+template <typename Interface>
+class InterfaceImpl : public internal::InterfaceImplBase<Interface> {
+ public:
+  typedef typename Interface::Client Client;
+  typedef Interface ImplementedInterface;
+
+  InterfaceImpl() : internal_state_(this) {}
+  virtual ~InterfaceImpl() {}
+
+  // Returns a proxy to the client interface. This is null upon construction,
+  // and becomes non-null after OnClientConnected. NOTE: It remains non-null
+  // until this instance is deleted.
+  Client* client() { return internal_state_.client(); }
+
+  // Blocks the current thread for the first incoming method call, i.e., either
+  // a call to a method or a client callback method. Returns |true| if a method
+  // has been called, |false| in case of error. It must only be called on a
+  // bound object.
+  bool WaitForIncomingMethodCall() {
+    return internal_state_.WaitForIncomingMethodCall();
+  }
+
+  // Called when the client has connected to this instance.
+  virtual void OnConnectionEstablished() {}
+
+  // Called when the client is no longer connected to this instance. NOTE: The
+  // client() method continues to return a non-null pointer after this method
+  // is called. After this method is called, any method calls made on client()
+  // will be silently ignored.
+  virtual void OnConnectionError() {}
+
+  // DO NOT USE. Exposed only for internal use and for testing.
+  internal::InterfaceImplState<Interface>* internal_state() {
+    return &internal_state_;
+  }
+
+ private:
+  internal::InterfaceImplState<Interface> internal_state_;
+  MOJO_DISALLOW_COPY_AND_ASSIGN(InterfaceImpl);
+};
+
+// Takes an instance of an InterfaceImpl<..> subclass and binds it to the given
+// MessagePipe. The instance is returned for convenience in member initializer
+// lists, etc.
+//
+// If the pipe is closed, the instance's OnConnectionError method will be called
+// and then the instance will be deleted.
+//
+// The instance is also bound to the current thread. Its methods will only be
+// called on the current thread, and if the current thread exits, then the end
+// point of the pipe will be closed and the error handler's OnConnectionError
+// method will be called.
+//
+// Before returning, the instance's OnConnectionEstablished method is called.
+template <typename Impl>
+Impl* BindToPipe(
+    Impl* instance,
+    ScopedMessagePipeHandle handle,
+    const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) {
+  instance->internal_state()->Bind(handle.Pass(), true, waiter);
+  return instance;
+}
+
+// Like BindToPipe but does not delete the instance after a channel error.
+template <typename Impl>
+Impl* WeakBindToPipe(
+    Impl* instance,
+    ScopedMessagePipeHandle handle,
+    const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) {
+  instance->internal_state()->Bind(handle.Pass(), false, waiter);
+  return instance;
+}
+
+// Takes an instance of an InterfaceImpl<..> subclass and binds it to the given
+// InterfacePtr<..>. The instance is returned for convenience in member
+// initializer lists, etc. If the pipe is closed, the instance's
+// OnConnectionError method will be called and then the instance will be
+// deleted.
+//
+// The instance is also bound to the current thread. Its methods will only be
+// called on the current thread, and if the current thread exits, then it will
+// also be deleted, and along with it, its end point of the pipe will be closed.
+//
+// Before returning, the instance's OnConnectionEstablished method is called.
+template <typename Impl, typename Interface>
+Impl* BindToProxy(
+    Impl* instance,
+    InterfacePtr<Interface>* ptr,
+    const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) {
+  instance->internal_state()->BindProxy(ptr, true, waiter);
+  return instance;
+}
+
+// Like BindToProxy but does not delete the instance after a channel error.
+template <typename Impl, typename Interface>
+Impl* WeakBindToProxy(
+    Impl* instance,
+    InterfacePtr<Interface>* ptr,
+    const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) {
+  instance->internal_state()->BindProxy(ptr, false, waiter);
+  return instance;
+}
+
+// Takes an instance of an InterfaceImpl<..> subclass and binds it to the given
+// InterfaceRequest<..>. The instance is returned for convenience in member
+// initializer lists, etc. If the pipe is closed, the instance's
+// OnConnectionError method will be called and then the instance will be
+// deleted.
+//
+// The instance is also bound to the current thread. Its methods will only be
+// called on the current thread, and if the current thread exits, then it will
+// also be deleted, and along with it, its end point of the pipe will be closed.
+//
+// Before returning, the instance will receive a SetClient call, providing it
+// with a proxy to the client on the other end of the pipe.
+template <typename Impl, typename Interface>
+Impl* BindToRequest(
+    Impl* instance,
+    InterfaceRequest<Interface>* request,
+    const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) {
+  return BindToPipe(instance, request->PassMessagePipe(), waiter);
+}
+
+// Like BindToRequest but does not delete the instance after a channel error.
+template <typename Impl, typename Interface>
+Impl* WeakBindToRequest(
+    Impl* instance,
+    InterfaceRequest<Interface>* request,
+    const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) {
+  return WeakBindToPipe(instance, request->PassMessagePipe(), waiter);
+}
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_IMPL_H_
diff --git a/mojo/public/cpp/bindings/interface_ptr.h b/mojo/public/cpp/bindings/interface_ptr.h
new file mode 100644
index 0000000..8dfd465
--- /dev/null
+++ b/mojo/public/cpp/bindings/interface_ptr.h
@@ -0,0 +1,138 @@
+// Copyright 2014 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_CPP_BINDINGS_INTERFACE_PTR_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_
+
+#include <algorithm>
+
+#include "mojo/public/cpp/bindings/error_handler.h"
+#include "mojo/public/cpp/bindings/lib/interface_ptr_internal.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+class ErrorHandler;
+
+// InterfacePtr represents a proxy to a remote instance of an interface.
+template <typename Interface>
+class InterfacePtr {
+  MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InterfacePtr, RValue)
+ public:
+  InterfacePtr() {}
+
+  InterfacePtr(RValue other) {
+    internal_state_.Swap(&other.object->internal_state_);
+  }
+  InterfacePtr& operator=(RValue other) {
+    reset();
+    internal_state_.Swap(&other.object->internal_state_);
+    return *this;
+  }
+
+  ~InterfacePtr() {}
+
+  Interface* get() const {
+    return internal_state_.instance();
+  }
+  Interface* operator->() const { return get(); }
+  Interface& operator*() const { return *get(); }
+
+  void reset() {
+    State doomed;
+    internal_state_.Swap(&doomed);
+  }
+
+  // Blocks the current thread for the first incoming method call, i.e., either
+  // a call to a client method or a callback method. Returns |true| if a method
+  // has been called, |false| in case of error. It must only be called on a
+  // bound object.
+  bool WaitForIncomingMethodCall() {
+    return internal_state_.WaitForIncomingMethodCall();
+  }
+
+  // This method configures the InterfacePtr<..> to be a proxy to a remote
+  // object on the other end of the given pipe.
+  //
+  // The proxy is bound to the current thread, which means its methods may
+  // only be called on the current thread.
+  //
+  // To move a bound InterfacePtr<..> to another thread, call PassMessagePipe().
+  // Then create a new InterfacePtr<..> on another thread, and bind the new
+  // InterfacePtr<..> to the message pipe on that thread.
+  void Bind(
+      ScopedMessagePipeHandle handle,
+      const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) {
+    reset();
+    internal_state_.Bind(handle.Pass(), waiter);
+  }
+
+  // The client interface may only be set after this InterfacePtr<..> is bound.
+  void set_client(typename Interface::Client* client) {
+    internal_state_.set_client(client);
+  }
+
+  // This method may be called to query if the underlying pipe has encountered
+  // an error. If true, this means method calls made on this interface will be
+  // dropped (and may have already been dropped) on the floor.
+  bool encountered_error() const {
+    return internal_state_.encountered_error();
+  }
+
+  // This method may be called to register an ErrorHandler to observe a
+  // connection error on the underlying pipe. It must only be called on a bound
+  // object.
+  // The callback runs asynchronously from the current message loop.
+  void set_error_handler(ErrorHandler* error_handler) {
+    internal_state_.set_error_handler(error_handler);
+  }
+
+  // Returns the underlying message pipe handle (if any) and resets the
+  // InterfacePtr<..> to its uninitialized state. This method is helpful if you
+  // need to move a proxy to another thread. See related notes for Bind.
+  ScopedMessagePipeHandle PassMessagePipe() {
+    State state;
+    internal_state_.Swap(&state);
+    return state.PassMessagePipe();
+  }
+
+  // DO NOT USE. Exposed only for internal use and for testing.
+  internal::InterfacePtrState<Interface>* internal_state() {
+    return &internal_state_;
+  }
+
+  // Allow InterfacePtr<> to be used in boolean expressions, but not
+  // implicitly convertible to a real bool (which is dangerous).
+ private:
+  typedef internal::InterfacePtrState<Interface> InterfacePtr::*Testable;
+
+ public:
+  operator Testable() const {
+    return internal_state_.is_bound() ? &InterfacePtr::internal_state_
+                                      : nullptr;
+  }
+
+ private:
+  typedef internal::InterfacePtrState<Interface> State;
+  mutable State internal_state_;
+};
+
+// Takes a handle to the proxy end-point of a pipe. On the other end is
+// presumed to be an interface implementation of type |Interface|. Returns a
+// generated proxy to that interface, which may be used on the current thread.
+// It is valid to call set_client on the returned InterfacePtr<..> to set an
+// instance of Interface::Client.
+template <typename Interface>
+InterfacePtr<Interface> MakeProxy(
+    ScopedMessagePipeHandle handle,
+    const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) {
+  InterfacePtr<Interface> ptr;
+  if (handle.is_valid())
+    ptr.Bind(handle.Pass(), waiter);
+  return ptr.Pass();
+}
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_
diff --git a/mojo/public/cpp/bindings/interface_request.h b/mojo/public/cpp/bindings/interface_request.h
new file mode 100644
index 0000000..6b7d303
--- /dev/null
+++ b/mojo/public/cpp/bindings/interface_request.h
@@ -0,0 +1,76 @@
+// Copyright 2014 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_CPP_BINDINGS_INTERFACE_REQUEST_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_
+
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+
+namespace mojo {
+
+// Used in methods that return instances of remote objects.
+template <typename Interface>
+class InterfaceRequest {
+  MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InterfaceRequest, RValue)
+ public:
+  InterfaceRequest() {}
+
+  InterfaceRequest(RValue other) {
+    handle_ = other.object->handle_.Pass();
+  }
+  InterfaceRequest& operator=(RValue other) {
+    handle_ = other.object->handle_.Pass();
+    return *this;
+  }
+
+  // Returns true if the request has yet to be completed.
+  bool is_pending() const { return handle_.is_valid(); }
+
+  void Bind(ScopedMessagePipeHandle handle) {
+    handle_ = handle.Pass();
+  }
+
+  ScopedMessagePipeHandle PassMessagePipe() {
+    return handle_.Pass();
+  }
+
+ private:
+  ScopedMessagePipeHandle handle_;
+};
+
+template <typename Interface>
+InterfaceRequest<Interface> MakeRequest(ScopedMessagePipeHandle handle) {
+  InterfaceRequest<Interface> request;
+  request.Bind(handle.Pass());
+  return request.Pass();
+}
+
+// Used to construct a request that synchronously binds an InterfacePtr<..>,
+// making it immediately usable upon return. The resulting request object may
+// then be later bound to an InterfaceImpl<..> via BindToRequest.
+//
+// Given the following interface:
+//
+//   interface Foo {
+//     CreateBar(Bar& bar);
+//   }
+//
+// The caller of CreateBar would have code similar to the following:
+//
+//   InterfacePtr<Foo> foo = ...;
+//   InterfacePtr<Bar> bar;
+//   foo->CreateBar(Get(&bar));
+//
+// Upon return from CreateBar, |bar| is ready to have methods called on it.
+//
+template <typename Interface>
+InterfaceRequest<Interface> Get(InterfacePtr<Interface>* ptr) {
+  MessagePipe pipe;
+  ptr->Bind(pipe.handle0.Pass());
+  return MakeRequest<Interface>(pipe.handle1.Pass());
+}
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_
diff --git a/mojo/public/cpp/bindings/lib/DEPS b/mojo/public/cpp/bindings/lib/DEPS
new file mode 100644
index 0000000..b809b58
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+  "+mojo/public/cpp/bindings",
+  "+mojo/public/cpp/environment",
+  "+mojo/public/cpp/system",
+]
diff --git a/mojo/public/cpp/bindings/lib/TODO b/mojo/public/cpp/bindings/lib/TODO
new file mode 100644
index 0000000..21bcb6f
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/TODO
@@ -0,0 +1,6 @@
+TODOs:
+ - Ensure validation checks are solid
+ - Add tests of validation logic
+ - Optimize Buffer classes?
+ - Add compile-time asserts to verify object packing and padding.
+ - Investigate making arrays of objects not be arrays of pointers.
diff --git a/mojo/public/cpp/bindings/lib/array_internal.cc b/mojo/public/cpp/bindings/lib/array_internal.cc
new file mode 100644
index 0000000..9f62aa2
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/array_internal.cc
@@ -0,0 +1,75 @@
+// Copyright 2013 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/cpp/bindings/lib/array_internal.h"
+
+#include <sstream>
+
+namespace mojo {
+namespace internal {
+
+std::string MakeMessageWithArrayIndex(const char* message,
+                                      size_t size,
+                                      size_t index) {
+  std::ostringstream stream;
+  stream << message << ": array size - " << size << "; index - " << index;
+  return stream.str();
+}
+
+std::string MakeMessageWithExpectedArraySize(const char* message,
+                                             size_t size,
+                                             size_t expected_size) {
+  std::ostringstream stream;
+  stream << message << ": array size - " << size << "; expected size - "
+         << expected_size;
+  return stream.str();
+}
+
+ArrayDataTraits<bool>::BitRef::~BitRef() {
+}
+
+ArrayDataTraits<bool>::BitRef::BitRef(uint8_t* storage, uint8_t mask)
+    : storage_(storage),
+      mask_(mask) {
+}
+
+ArrayDataTraits<bool>::BitRef&
+ArrayDataTraits<bool>::BitRef::operator=(bool value) {
+  if (value) {
+    *storage_ |= mask_;
+  } else {
+    *storage_ &= ~mask_;
+  }
+  return *this;
+}
+
+ArrayDataTraits<bool>::BitRef&
+ArrayDataTraits<bool>::BitRef::operator=(const BitRef& value) {
+  return (*this) = static_cast<bool>(value);
+}
+
+ArrayDataTraits<bool>::BitRef::operator bool() const {
+  return (*storage_ & mask_) != 0;
+}
+
+// static
+void ArraySerializationHelper<Handle, true>::EncodePointersAndHandles(
+    const ArrayHeader* header,
+    ElementType* elements,
+    std::vector<Handle>* handles) {
+  for (uint32_t i = 0; i < header->num_elements; ++i)
+    EncodeHandle(&elements[i], handles);
+}
+
+// static
+void ArraySerializationHelper<Handle, true>::DecodePointersAndHandles(
+    const ArrayHeader* header,
+    ElementType* elements,
+    std::vector<Handle>* handles) {
+  for (uint32_t i = 0; i < header->num_elements; ++i)
+    DecodeHandle(&elements[i], handles);
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/array_internal.h b/mojo/public/cpp/bindings/lib/array_internal.h
new file mode 100644
index 0000000..3681d8e
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/array_internal.h
@@ -0,0 +1,521 @@
+// Copyright 2013 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_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
+
+#include <new>
+#include <vector>
+
+#include "mojo/public/c/system/macros.h"
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
+#include "mojo/public/cpp/bindings/lib/bounds_checker.h"
+#include "mojo/public/cpp/bindings/lib/buffer.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+#include "mojo/public/cpp/bindings/lib/validation_errors.h"
+#include "mojo/public/cpp/environment/logging.h"
+
+namespace mojo {
+template <typename T> class Array;
+class String;
+
+namespace internal {
+
+// std::numeric_limits<uint32_t>::max() is not a compile-time constant (until
+// C++11).
+const uint32_t kMaxUint32 = 0xFFFFFFFF;
+
+std::string MakeMessageWithArrayIndex(const char* message,
+                                      size_t size,
+                                      size_t index);
+
+std::string MakeMessageWithExpectedArraySize(const char* message,
+                                             size_t size,
+                                             size_t expected_size);
+
+template <typename T>
+struct ArrayDataTraits {
+  typedef T StorageType;
+  typedef T& Ref;
+  typedef T const& ConstRef;
+
+  static const uint32_t kMaxNumElements =
+      (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
+
+  static uint32_t GetStorageSize(uint32_t num_elements) {
+    MOJO_DCHECK(num_elements <= kMaxNumElements);
+    return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
+  }
+  static Ref ToRef(StorageType* storage, size_t offset) {
+    return storage[offset];
+  }
+  static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
+    return storage[offset];
+  }
+};
+
+template <typename P>
+struct ArrayDataTraits<P*> {
+  typedef StructPointer<P> StorageType;
+  typedef P*& Ref;
+  typedef P* const& ConstRef;
+
+  static const uint32_t kMaxNumElements =
+      (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
+
+  static uint32_t GetStorageSize(uint32_t num_elements) {
+    MOJO_DCHECK(num_elements <= kMaxNumElements);
+    return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
+  }
+  static Ref ToRef(StorageType* storage, size_t offset) {
+    return storage[offset].ptr;
+  }
+  static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
+    return storage[offset].ptr;
+  }
+};
+
+template <typename T>
+struct ArrayDataTraits<Array_Data<T>*> {
+  typedef ArrayPointer<T> StorageType;
+  typedef Array_Data<T>*& Ref;
+  typedef Array_Data<T>* const& ConstRef;
+
+  static const uint32_t kMaxNumElements =
+      (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
+
+  static uint32_t GetStorageSize(uint32_t num_elements) {
+    MOJO_DCHECK(num_elements <= kMaxNumElements);
+    return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
+  }
+  static Ref ToRef(StorageType* storage, size_t offset) {
+    return storage[offset].ptr;
+  }
+  static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
+    return storage[offset].ptr;
+  }
+};
+
+// Specialization of Arrays for bools, optimized for space. It has the
+// following differences from a generalized Array:
+// * Each element takes up a single bit of memory.
+// * Accessing a non-const single element uses a helper class |BitRef|, which
+// emulates a reference to a bool.
+template <>
+struct ArrayDataTraits<bool> {
+  // Helper class to emulate a reference to a bool, used for direct element
+  // access.
+  class BitRef {
+   public:
+    ~BitRef();
+    BitRef& operator=(bool value);
+    BitRef& operator=(const BitRef& value);
+    operator bool() const;
+   private:
+    friend struct ArrayDataTraits<bool>;
+    BitRef(uint8_t* storage, uint8_t mask);
+    BitRef();
+    uint8_t* storage_;
+    uint8_t mask_;
+  };
+
+  // Because each element consumes only 1/8 byte.
+  static const uint32_t kMaxNumElements = kMaxUint32;
+
+  typedef uint8_t StorageType;
+  typedef BitRef Ref;
+  typedef bool ConstRef;
+
+  static uint32_t GetStorageSize(uint32_t num_elements) {
+    return sizeof(ArrayHeader) + ((num_elements + 7) / 8);
+  }
+  static BitRef ToRef(StorageType* storage, size_t offset) {
+    return BitRef(&storage[offset / 8], 1 << (offset % 8));
+  }
+  static bool ToConstRef(const StorageType* storage, size_t offset) {
+    return (storage[offset / 8] & (1 << (offset % 8))) != 0;
+  }
+};
+
+// Array type information needed for valdiation.
+template <uint32_t in_expected_num_elements,
+          bool in_element_is_nullable,
+          typename InElementValidateParams>
+class ArrayValidateParams {
+ public:
+  // Validation information for elements. It is either another specialization of
+  // ArrayValidateParams (if elements are arrays) or NoValidateParams.
+  typedef InElementValidateParams ElementValidateParams;
+
+  // If |expected_num_elements| is not 0, the array is expected to have exactly
+  // that number of elements.
+  static const uint32_t expected_num_elements = in_expected_num_elements;
+  // Whether the elements are nullable.
+  static const bool element_is_nullable = in_element_is_nullable;
+};
+
+// NoValidateParams is used to indicate the end of an ArrayValidateParams chain.
+class NoValidateParams {
+};
+
+// What follows is code to support the serialization of Array_Data<T>. There
+// are two interesting cases: arrays of primitives and arrays of objects.
+// Arrays of objects are represented as arrays of pointers to objects.
+
+template <typename T, bool is_handle> struct ArraySerializationHelper;
+
+template <typename T>
+struct ArraySerializationHelper<T, false> {
+  typedef typename ArrayDataTraits<T>::StorageType ElementType;
+
+  static void EncodePointersAndHandles(const ArrayHeader* header,
+                                       ElementType* elements,
+                                       std::vector<Handle>* handles) {
+  }
+
+  static void DecodePointersAndHandles(const ArrayHeader* header,
+                                       ElementType* elements,
+                                       std::vector<Handle>* handles) {
+  }
+
+  template <bool element_is_nullable, typename ElementValidateParams>
+  static bool ValidateElements(const ArrayHeader* header,
+                               const ElementType* elements,
+                               BoundsChecker* bounds_checker) {
+    MOJO_COMPILE_ASSERT(!element_is_nullable,
+                        Primitive_type_should_be_non_nullable);
+    MOJO_COMPILE_ASSERT(
+        (IsSame<ElementValidateParams, NoValidateParams>::value),
+        Primitive_type_should_not_have_array_validate_params);
+    return true;
+  }
+};
+
+template <>
+struct ArraySerializationHelper<Handle, true> {
+  typedef ArrayDataTraits<Handle>::StorageType ElementType;
+
+  static void EncodePointersAndHandles(const ArrayHeader* header,
+                                       ElementType* elements,
+                                       std::vector<Handle>* handles);
+
+  static void DecodePointersAndHandles(const ArrayHeader* header,
+                                       ElementType* elements,
+                                       std::vector<Handle>* handles);
+
+  template <bool element_is_nullable, typename ElementValidateParams>
+  static bool ValidateElements(const ArrayHeader* header,
+                               const ElementType* elements,
+                               BoundsChecker* bounds_checker) {
+    MOJO_COMPILE_ASSERT(
+        (IsSame<ElementValidateParams, NoValidateParams>::value),
+        Handle_type_should_not_have_array_validate_params);
+
+    for (uint32_t i = 0; i < header->num_elements; ++i) {
+      if (!element_is_nullable &&
+          elements[i].value() == kEncodedInvalidHandleValue) {
+        ReportValidationError(
+            VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
+            MakeMessageWithArrayIndex(
+                "invalid handle in array expecting valid handles",
+                header->num_elements, i).c_str());
+        return false;
+      }
+      if (!bounds_checker->ClaimHandle(elements[i])) {
+        ReportValidationError(VALIDATION_ERROR_ILLEGAL_HANDLE);
+        return false;
+      }
+    }
+    return true;
+  }
+};
+
+template <typename H>
+struct ArraySerializationHelper<H, true> {
+  typedef typename ArrayDataTraits<H>::StorageType ElementType;
+
+  static void EncodePointersAndHandles(const ArrayHeader* header,
+                                       ElementType* elements,
+                                       std::vector<Handle>* handles) {
+    ArraySerializationHelper<Handle, true>::EncodePointersAndHandles(
+        header, elements, handles);
+  }
+
+  static void DecodePointersAndHandles(const ArrayHeader* header,
+                                       ElementType* elements,
+                                       std::vector<Handle>* handles) {
+    ArraySerializationHelper<Handle, true>::DecodePointersAndHandles(
+        header, elements, handles);
+  }
+
+  template <bool element_is_nullable, typename ElementValidateParams>
+  static bool ValidateElements(const ArrayHeader* header,
+                               const ElementType* elements,
+                               BoundsChecker* bounds_checker) {
+    return ArraySerializationHelper<Handle, true>::
+        ValidateElements<element_is_nullable, ElementValidateParams>(
+            header, elements, bounds_checker);
+  }
+};
+
+template <typename P>
+struct ArraySerializationHelper<P*, false> {
+  typedef typename ArrayDataTraits<P*>::StorageType ElementType;
+
+  static void EncodePointersAndHandles(const ArrayHeader* header,
+                                       ElementType* elements,
+                                       std::vector<Handle>* handles) {
+    for (uint32_t i = 0; i < header->num_elements; ++i)
+      Encode(&elements[i], handles);
+  }
+
+  static void DecodePointersAndHandles(const ArrayHeader* header,
+                                       ElementType* elements,
+                                       std::vector<Handle>* handles) {
+    for (uint32_t i = 0; i < header->num_elements; ++i)
+      Decode(&elements[i], handles);
+  }
+
+  template <bool element_is_nullable, typename ElementValidateParams>
+  static bool ValidateElements(const ArrayHeader* header,
+                               const ElementType* elements,
+                               BoundsChecker* bounds_checker) {
+    for (uint32_t i = 0; i < header->num_elements; ++i) {
+      if (!element_is_nullable && !elements[i].offset) {
+        ReportValidationError(
+            VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
+            MakeMessageWithArrayIndex(
+                "null in array expecting valid pointers",
+                header->num_elements, i).c_str());
+        return false;
+      }
+      if (!ValidateEncodedPointer(&elements[i].offset)) {
+        ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER);
+        return false;
+      }
+      if (!ValidateCaller<P, ElementValidateParams>::Run(
+              DecodePointerRaw(&elements[i].offset), bounds_checker)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private:
+  template <typename T, typename Params>
+  struct ValidateCaller {
+    static bool Run(const void* data, BoundsChecker* bounds_checker) {
+      MOJO_COMPILE_ASSERT(
+          (IsSame<Params, NoValidateParams>::value),
+          Struct_type_should_not_have_array_validate_params);
+
+      return T::Validate(data, bounds_checker);
+    }
+  };
+
+  template <typename T, typename Params>
+  struct ValidateCaller<Array_Data<T>, Params> {
+    static bool Run(const void* data, BoundsChecker* bounds_checker) {
+      return Array_Data<T>::template Validate<Params>(data, bounds_checker);
+    }
+  };
+};
+
+template <typename T>
+class Array_Data {
+ public:
+  typedef ArrayDataTraits<T> Traits;
+  typedef typename Traits::StorageType StorageType;
+  typedef typename Traits::Ref Ref;
+  typedef typename Traits::ConstRef ConstRef;
+  typedef ArraySerializationHelper<T, IsHandle<T>::value> Helper;
+
+  // Returns null if |num_elements| or the corresponding storage size cannot be
+  // stored in uint32_t.
+  static Array_Data<T>* New(size_t num_elements, Buffer* buf) {
+    if (num_elements > Traits::kMaxNumElements)
+      return nullptr;
+
+    uint32_t num_bytes =
+        Traits::GetStorageSize(static_cast<uint32_t>(num_elements));
+    return new (buf->Allocate(num_bytes)) Array_Data<T>(
+        num_bytes, static_cast<uint32_t>(num_elements));
+  }
+
+  template <typename Params>
+  static bool Validate(const void* data, BoundsChecker* bounds_checker) {
+    if (!data)
+      return true;
+    if (!IsAligned(data)) {
+      ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT);
+      return false;
+    }
+    if (!bounds_checker->IsValidRange(data, sizeof(ArrayHeader))) {
+      ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
+      return false;
+    }
+    const ArrayHeader* header = static_cast<const ArrayHeader*>(data);
+    if (header->num_elements > Traits::kMaxNumElements ||
+        header->num_bytes < Traits::GetStorageSize(header->num_elements)) {
+      ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER);
+      return false;
+    }
+    if (Params::expected_num_elements != 0 &&
+        header->num_elements != Params::expected_num_elements) {
+      ReportValidationError(
+          VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER,
+          MakeMessageWithExpectedArraySize(
+              "fixed-size array has wrong number of elements",
+              header->num_elements, Params::expected_num_elements).c_str());
+      return false;
+    }
+    if (!bounds_checker->ClaimMemory(data, header->num_bytes)) {
+      ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
+      return false;
+    }
+
+    const Array_Data<T>* object = static_cast<const Array_Data<T>*>(data);
+    return Helper::template ValidateElements<
+        Params::element_is_nullable, typename Params::ElementValidateParams>(
+            &object->header_, object->storage(), bounds_checker);
+  }
+
+  size_t size() const { return header_.num_elements; }
+
+  Ref at(size_t offset) {
+    MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements));
+    return Traits::ToRef(storage(), offset);
+  }
+
+  ConstRef at(size_t offset) const {
+    MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements));
+    return Traits::ToConstRef(storage(), offset);
+  }
+
+  StorageType* storage() {
+    return reinterpret_cast<StorageType*>(
+        reinterpret_cast<char*>(this) + sizeof(*this));
+  }
+
+  const StorageType* storage() const {
+    return reinterpret_cast<const StorageType*>(
+        reinterpret_cast<const char*>(this) + sizeof(*this));
+  }
+
+  void EncodePointersAndHandles(std::vector<Handle>* handles) {
+    Helper::EncodePointersAndHandles(&header_, storage(), handles);
+  }
+
+  void DecodePointersAndHandles(std::vector<Handle>* handles) {
+    Helper::DecodePointersAndHandles(&header_, storage(), handles);
+  }
+
+ private:
+  Array_Data(uint32_t num_bytes, uint32_t num_elements) {
+    header_.num_bytes = num_bytes;
+    header_.num_elements = num_elements;
+  }
+  ~Array_Data() {}
+
+  internal::ArrayHeader header_;
+
+  // Elements of type internal::ArrayDataTraits<T>::StorageType follow.
+};
+MOJO_COMPILE_ASSERT(sizeof(Array_Data<char>) == 8, bad_sizeof_Array_Data);
+
+// UTF-8 encoded
+typedef Array_Data<char> String_Data;
+
+template <typename T, bool kIsMoveOnlyType> struct ArrayTraits {};
+
+template <typename T> struct ArrayTraits<T, false> {
+  typedef T StorageType;
+  typedef typename std::vector<T>::reference RefType;
+  typedef typename std::vector<T>::const_reference ConstRefType;
+  typedef ConstRefType ForwardType;
+  static inline void Initialize(std::vector<T>* vec) {
+  }
+  static inline void Finalize(std::vector<T>* vec) {
+  }
+  static inline ConstRefType at(const std::vector<T>* vec, size_t offset) {
+    return vec->at(offset);
+  }
+  static inline RefType at(std::vector<T>* vec, size_t offset) {
+    return vec->at(offset);
+  }
+  static inline void Resize(std::vector<T>* vec, size_t size) {
+    vec->resize(size);
+  }
+  static inline void PushBack(std::vector<T>* vec, ForwardType value) {
+    vec->push_back(value);
+  }
+  static inline void Clone(const std::vector<T>& src_vec,
+                           std::vector<T>* dest_vec) {
+    dest_vec->assign(src_vec.begin(), src_vec.end());
+  }
+};
+
+template <typename T> struct ArrayTraits<T, true> {
+  struct StorageType {
+    char buf[sizeof(T) + (8 - (sizeof(T) % 8)) % 8];  // Make 8-byte aligned.
+  };
+  typedef T& RefType;
+  typedef const T& ConstRefType;
+  typedef T ForwardType;
+  static inline void Initialize(std::vector<StorageType>* vec) {
+    for (size_t i = 0; i < vec->size(); ++i)
+      new (vec->at(i).buf) T();
+  }
+  static inline void Finalize(std::vector<StorageType>* vec) {
+    for (size_t i = 0; i < vec->size(); ++i)
+      reinterpret_cast<T*>(vec->at(i).buf)->~T();
+  }
+  static inline ConstRefType at(const std::vector<StorageType>* vec,
+                                size_t offset) {
+    return *reinterpret_cast<const T*>(vec->at(offset).buf);
+  }
+  static inline RefType at(std::vector<StorageType>* vec, size_t offset) {
+    return *reinterpret_cast<T*>(vec->at(offset).buf);
+  }
+  static inline void Resize(std::vector<StorageType>* vec, size_t size) {
+    size_t old_size = vec->size();
+    for (size_t i = size; i < old_size; i++)
+      reinterpret_cast<T*>(vec->at(i).buf)->~T();
+    ResizeStorage(vec, size);
+    for (size_t i = old_size; i < vec->size(); i++)
+      new (vec->at(i).buf) T();
+  }
+  static inline void PushBack(std::vector<StorageType>* vec, RefType value) {
+    size_t old_size = vec->size();
+    ResizeStorage(vec, old_size + 1);
+    new (vec->at(old_size).buf) T(value.Pass());
+  }
+  static inline void ResizeStorage(std::vector<StorageType>* vec, size_t size) {
+    if (size <= vec->capacity()) {
+      vec->resize(size);
+      return;
+    }
+    std::vector<StorageType> new_storage(size);
+    for (size_t i = 0; i < vec->size(); i++)
+      new (new_storage.at(i).buf) T(at(vec, i).Pass());
+    vec->swap(new_storage);
+    Finalize(&new_storage);
+  }
+  static inline void Clone(const std::vector<StorageType>& src_vec,
+                           std::vector<StorageType>* dest_vec) {
+    Resize(dest_vec, src_vec.size());
+    for (size_t i = 0; i < src_vec.size(); ++i)
+      at(dest_vec, i) = at(&src_vec, i).Clone();
+  }
+};
+
+template <> struct WrapperTraits<String, false> {
+  typedef String_Data* DataType;
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
diff --git a/mojo/public/cpp/bindings/lib/array_serialization.h b/mojo/public/cpp/bindings/lib/array_serialization.h
new file mode 100644
index 0000000..4407de8
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/array_serialization.h
@@ -0,0 +1,262 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_
+
+#include <string.h>  // For |memcpy()|.
+
+#include <vector>
+
+#include "mojo/public/c/system/macros.h"
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/lib/string_serialization.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+#include "mojo/public/cpp/bindings/lib/validation_errors.h"
+
+namespace mojo {
+
+template <typename E>
+inline size_t GetSerializedSize_(const Array<E>& input);
+
+// Because ValidateParams requires explicit argument specification, the
+// argument-dependent loopup technique used to omit namespace when calling
+// Serialize_() doesn't seem to work. Therefore, this function is named
+// differently from those Serialize_() overloads.
+template <typename ValidateParams, typename E, typename F>
+inline void SerializeArray_(Array<E> input, internal::Buffer* buf,
+                            internal::Array_Data<F>** output);
+
+template <typename E, typename F>
+inline void Deserialize_(internal::Array_Data<F>* data, Array<E>* output);
+
+namespace internal {
+
+template <typename E, typename F, bool move_only = IsMoveOnlyType<E>::value>
+struct ArraySerializer;
+
+template <typename E, typename F> struct ArraySerializer<E, F, false> {
+  MOJO_COMPILE_ASSERT(sizeof(E) == sizeof(F), wrong_array_serializer);
+  static size_t GetSerializedSize(const Array<E>& input) {
+    return sizeof(Array_Data<F>) + Align(input.size() * sizeof(E));
+  }
+  template <bool element_is_nullable, typename ElementValidateParams>
+  static void SerializeElements(
+      Array<E> input, Buffer* buf, Array_Data<F>* output) {
+    MOJO_COMPILE_ASSERT(!element_is_nullable,
+                        Primitive_type_should_be_non_nullable);
+    MOJO_COMPILE_ASSERT(
+        (IsSame<ElementValidateParams, NoValidateParams>::value),
+        Primitive_type_should_not_have_array_validate_params);
+
+    memcpy(output->storage(), &input.storage()[0], input.size() * sizeof(E));
+  }
+  static void DeserializeElements(
+      Array_Data<F>* input, Array<E>* output) {
+    std::vector<E> result(input->size());
+    memcpy(&result[0], input->storage(), input->size() * sizeof(E));
+    output->Swap(&result);
+  }
+};
+
+template <> struct ArraySerializer<bool, bool, false> {
+  static size_t GetSerializedSize(const Array<bool>& input) {
+    return sizeof(Array_Data<bool>) + Align((input.size() + 7) / 8);
+  }
+  template <bool element_is_nullable, typename ElementValidateParams>
+  static void SerializeElements(
+      Array<bool> input, Buffer* buf, Array_Data<bool>* output) {
+    MOJO_COMPILE_ASSERT(!element_is_nullable,
+                        Primitive_type_should_be_non_nullable);
+    MOJO_COMPILE_ASSERT(
+        (IsSame<ElementValidateParams, NoValidateParams>::value),
+        Primitive_type_should_not_have_array_validate_params);
+
+    // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy?
+    for (size_t i = 0; i < input.size(); ++i)
+      output->at(i) = input[i];
+  }
+  static void DeserializeElements(
+      Array_Data<bool>* input, Array<bool>* output) {
+    Array<bool> result(input->size());
+    // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy?
+    for (size_t i = 0; i < input->size(); ++i)
+      result.at(i) = input->at(i);
+    output->Swap(&result);
+  }
+};
+
+template <typename H> struct ArraySerializer<ScopedHandleBase<H>, H, true> {
+  static size_t GetSerializedSize(const Array<ScopedHandleBase<H> >& input) {
+    return sizeof(Array_Data<H>) + Align(input.size() * sizeof(H));
+  }
+  template <bool element_is_nullable, typename ElementValidateParams>
+  static void SerializeElements(Array<ScopedHandleBase<H> > input,
+                                Buffer* buf,
+                                Array_Data<H>* output) {
+    MOJO_COMPILE_ASSERT(
+        (IsSame<ElementValidateParams, NoValidateParams>::value),
+        Handle_type_should_not_have_array_validate_params);
+
+    for (size_t i = 0; i < input.size(); ++i) {
+      output->at(i) = input[i].release();  // Transfer ownership of the handle.
+      MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
+          !element_is_nullable && !output->at(i).is_valid(),
+          VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
+          MakeMessageWithArrayIndex(
+              "invalid handle in array expecting valid handles",
+              input.size(), i));
+    }
+  }
+  static void DeserializeElements(
+      Array_Data<H>* input, Array<ScopedHandleBase<H> >* output) {
+    Array<ScopedHandleBase<H> > result(input->size());
+    for (size_t i = 0; i < input->size(); ++i)
+      result.at(i) = MakeScopedHandle(FetchAndReset(&input->at(i)));
+    output->Swap(&result);
+  }
+};
+
+template <typename S> struct ArraySerializer<S, typename S::Data_*, true> {
+  static size_t GetSerializedSize(const Array<S>& input) {
+    size_t size = sizeof(Array_Data<typename S::Data_*>) +
+        input.size() * sizeof(internal::StructPointer<typename S::Data_>);
+    for (size_t i = 0; i < input.size(); ++i)
+      size += GetSerializedSize_(input[i]);
+    return size;
+  }
+  template <bool element_is_nullable, typename ElementValidateParams>
+  static void SerializeElements(Array<S> input,
+                                Buffer* buf,
+                                Array_Data<typename S::Data_*>* output) {
+    for (size_t i = 0; i < input.size(); ++i) {
+      typename S::Data_* element;
+      SerializeCaller<S, ElementValidateParams>::Run(
+          input[i].Pass(), buf, &element);
+      output->at(i) = element;
+      MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
+          !element_is_nullable && !element,
+          VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
+          MakeMessageWithArrayIndex(
+              "null in array expecting valid pointers", input.size(), i));
+    }
+  }
+  static void DeserializeElements(
+      Array_Data<typename S::Data_*>* input, Array<S>* output) {
+    Array<S> result(input->size());
+    for (size_t i = 0; i < input->size(); ++i) {
+      S element;
+      Deserialize_(input->at(i), &element);
+      result[i] = element.Pass();
+    }
+    output->Swap(&result);
+  }
+
+ private:
+  template <typename T, typename Params>
+  struct SerializeCaller {
+    static void Run(T input, Buffer* buf, typename T::Data_** output) {
+      MOJO_COMPILE_ASSERT((IsSame<Params, NoValidateParams>::value),
+                          Struct_type_should_not_have_array_validate_params);
+
+      Serialize_(input.Pass(), buf, output);
+    }
+  };
+
+  template <typename T, typename Params>
+  struct SerializeCaller<Array<T>, Params> {
+    static void Run(Array<T> input,
+                    Buffer* buf,
+                    typename Array<T>::Data_** output) {
+      SerializeArray_<Params>(input.Pass(), buf, output);
+    }
+  };
+};
+
+template <> struct ArraySerializer<String, String_Data*, false> {
+  static size_t GetSerializedSize(const Array<String>& input) {
+    size_t size = sizeof(Array_Data<String_Data*>) +
+        input.size() * sizeof(internal::StringPointer);
+    for (size_t i = 0; i < input.size(); ++i)
+      size += GetSerializedSize_(input[i]);
+    return size;
+  }
+  template <bool element_is_nullable, typename ElementValidateParams>
+  static void SerializeElements(
+      Array<String> input,
+      Buffer* buf,
+      Array_Data<String_Data*>* output) {
+    MOJO_COMPILE_ASSERT(
+        (IsSame<ElementValidateParams,
+                ArrayValidateParams<0, false, NoValidateParams> >::value),
+        String_type_has_unexpected_array_validate_params);
+
+    for (size_t i = 0; i < input.size(); ++i) {
+      String_Data* element;
+      Serialize_(input[i], buf, &element);
+      output->at(i) = element;
+      MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
+          !element_is_nullable && !element,
+          VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
+          MakeMessageWithArrayIndex(
+              "null in array expecting valid strings", input.size(), i));
+    }
+  }
+  static void DeserializeElements(
+      Array_Data<String_Data*>* input, Array<String>* output) {
+    Array<String> result(input->size());
+    for (size_t i = 0; i < input->size(); ++i)
+      Deserialize_(input->at(i), &result[i]);
+    output->Swap(&result);
+  }
+};
+
+}  // namespace internal
+
+template <typename E>
+inline size_t GetSerializedSize_(const Array<E>& input) {
+  if (!input)
+    return 0;
+  typedef typename internal::WrapperTraits<E>::DataType F;
+  return internal::ArraySerializer<E, F>::GetSerializedSize(input);
+}
+
+template <typename ValidateParams, typename E, typename F>
+inline void SerializeArray_(Array<E> input, internal::Buffer* buf,
+                            internal::Array_Data<F>** output) {
+  if (input) {
+    MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
+        ValidateParams::expected_num_elements != 0 &&
+            input.size() != ValidateParams::expected_num_elements,
+        internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER,
+        internal::MakeMessageWithExpectedArraySize(
+            "fixed-size array has wrong number of elements",
+            input.size(), ValidateParams::expected_num_elements));
+
+    internal::Array_Data<F>* result =
+        internal::Array_Data<F>::New(input.size(), buf);
+    if (result) {
+      internal::ArraySerializer<E, F>::template SerializeElements<
+          ValidateParams::element_is_nullable,
+          typename ValidateParams::ElementValidateParams>(
+              internal::Forward(input), buf, result);
+    }
+    *output = result;
+  } else {
+    *output = nullptr;
+  }
+}
+
+template <typename E, typename F>
+inline void Deserialize_(internal::Array_Data<F>* input, Array<E>* output) {
+  if (input) {
+    internal::ArraySerializer<E, F>::DeserializeElements(input, output);
+  } else {
+    output->reset();
+  }
+}
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_
diff --git a/mojo/public/cpp/bindings/lib/bindings_internal.h b/mojo/public/cpp/bindings/lib/bindings_internal.h
new file mode 100644
index 0000000..f12be10
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/bindings_internal.h
@@ -0,0 +1,86 @@
+// Copyright 2013 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_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_
+
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+#include "mojo/public/cpp/system/core.h"
+
+namespace mojo {
+class String;
+
+namespace internal {
+template <typename T> class Array_Data;
+
+#pragma pack(push, 1)
+
+struct StructHeader {
+  uint32_t num_bytes;
+  uint32_t num_fields;
+};
+MOJO_COMPILE_ASSERT(sizeof(StructHeader) == 8, bad_sizeof_StructHeader);
+
+struct ArrayHeader {
+  uint32_t num_bytes;
+  uint32_t num_elements;
+};
+MOJO_COMPILE_ASSERT(sizeof(ArrayHeader) == 8, bad_sizeof_ArrayHeader);
+
+template <typename T>
+union StructPointer {
+  uint64_t offset;
+  T* ptr;
+};
+MOJO_COMPILE_ASSERT(sizeof(StructPointer<char>) == 8, bad_sizeof_StructPointer);
+
+template <typename T>
+union ArrayPointer {
+  uint64_t offset;
+  Array_Data<T>* ptr;
+};
+MOJO_COMPILE_ASSERT(sizeof(ArrayPointer<char>) == 8, bad_sizeof_ArrayPointer);
+
+union StringPointer {
+  uint64_t offset;
+  Array_Data<char>* ptr;
+};
+MOJO_COMPILE_ASSERT(sizeof(StringPointer) == 8, bad_sizeof_StringPointer);
+
+#pragma pack(pop)
+
+template <typename T>
+void ResetIfNonNull(T* ptr) {
+  if (ptr)
+    *ptr = T();
+}
+
+template <typename T>
+T FetchAndReset(T* ptr) {
+  T temp = *ptr;
+  *ptr = T();
+  return temp;
+}
+
+template <typename H> struct IsHandle {
+  enum { value = IsBaseOf<Handle, H>::value };
+};
+
+template <typename T, bool move_only = IsMoveOnlyType<T>::value>
+struct WrapperTraits;
+
+template <typename T> struct WrapperTraits<T, false> {
+  typedef T DataType;
+};
+template <typename H> struct WrapperTraits<ScopedHandleBase<H>, true> {
+  typedef H DataType;
+};
+template <typename S> struct WrapperTraits<S, true> {
+  typedef typename S::Data_* DataType;
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_
diff --git a/mojo/public/cpp/bindings/lib/bindings_serialization.cc b/mojo/public/cpp/bindings/lib/bindings_serialization.cc
new file mode 100644
index 0000000..7161efe
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/bindings_serialization.cc
@@ -0,0 +1,117 @@
+// Copyright 2013 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/cpp/bindings/lib/bindings_serialization.h"
+
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/bounds_checker.h"
+#include "mojo/public/cpp/bindings/lib/validation_errors.h"
+#include "mojo/public/cpp/environment/logging.h"
+
+namespace mojo {
+namespace internal {
+
+namespace {
+
+const size_t kAlignment = 8;
+
+template<typename T>
+T AlignImpl(T t) {
+  return t + (kAlignment - (t % kAlignment)) % kAlignment;
+}
+
+}  // namespace
+
+size_t Align(size_t size) {
+  return AlignImpl(size);
+}
+
+char* AlignPointer(char* ptr) {
+  return reinterpret_cast<char*>(AlignImpl(reinterpret_cast<uintptr_t>(ptr)));
+}
+
+bool IsAligned(const void* ptr) {
+  return !(reinterpret_cast<uintptr_t>(ptr) % kAlignment);
+}
+
+void EncodePointer(const void* ptr, uint64_t* offset) {
+  if (!ptr) {
+    *offset = 0;
+    return;
+  }
+
+  const char* p_obj = reinterpret_cast<const char*>(ptr);
+  const char* p_slot = reinterpret_cast<const char*>(offset);
+  MOJO_DCHECK(p_obj > p_slot);
+
+  *offset = static_cast<uint64_t>(p_obj - p_slot);
+}
+
+const void* DecodePointerRaw(const uint64_t* offset) {
+  if (!*offset)
+    return nullptr;
+  return reinterpret_cast<const char*>(offset) + *offset;
+}
+
+bool ValidateEncodedPointer(const uint64_t* offset) {
+  // Cast to uintptr_t so overflow behavior is well defined.
+  return reinterpret_cast<uintptr_t>(offset) + *offset >=
+      reinterpret_cast<uintptr_t>(offset);
+}
+
+void EncodeHandle(Handle* handle, std::vector<Handle>* handles) {
+  if (handle->is_valid()) {
+    handles->push_back(*handle);
+    handle->set_value(static_cast<MojoHandle>(handles->size() - 1));
+  } else {
+    handle->set_value(kEncodedInvalidHandleValue);
+  }
+}
+
+void DecodeHandle(Handle* handle, std::vector<Handle>* handles) {
+  if (handle->value() == kEncodedInvalidHandleValue) {
+    *handle = Handle();
+    return;
+  }
+  MOJO_DCHECK(handle->value() < handles->size());
+  // Just leave holes in the vector so we don't screw up other indices.
+  *handle = FetchAndReset(&handles->at(handle->value()));
+}
+
+bool ValidateStructHeader(const void* data,
+                          uint32_t min_num_bytes,
+                          uint32_t min_num_fields,
+                          BoundsChecker* bounds_checker) {
+  MOJO_DCHECK(min_num_bytes >= sizeof(StructHeader));
+
+  if (!IsAligned(data)) {
+    ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT);
+    return false;
+  }
+  if (!bounds_checker->IsValidRange(data, sizeof(StructHeader))) {
+    ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
+    return false;
+  }
+
+  const StructHeader* header = static_cast<const StructHeader*>(data);
+
+  // TODO(yzshen): Currently our binding code cannot handle structs of smaller
+  // size or with fewer fields than the version that it sees. That needs to be
+  // changed in order to provide backward compatibility.
+  if (header->num_bytes < min_num_bytes ||
+      header->num_fields < min_num_fields) {
+    ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
+    return false;
+  }
+
+  if (!bounds_checker->ClaimMemory(data, header->num_bytes)) {
+    ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/bindings_serialization.h b/mojo/public/cpp/bindings/lib/bindings_serialization.h
new file mode 100644
index 0000000..6bebf90
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/bindings_serialization.h
@@ -0,0 +1,83 @@
+// Copyright 2013 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_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_
+
+#include <vector>
+
+#include "mojo/public/cpp/system/core.h"
+
+namespace mojo {
+namespace internal {
+
+class BoundsChecker;
+
+// Please note that this is a different value than |mojo::kInvalidHandleValue|,
+// which is the "decoded" invalid handle.
+const MojoHandle kEncodedInvalidHandleValue = static_cast<MojoHandle>(-1);
+
+size_t Align(size_t size);
+char* AlignPointer(char* ptr);
+
+bool IsAligned(const void* ptr);
+
+// Pointers are encoded as relative offsets. The offsets are relative to the
+// address of where the offset value is stored, such that the pointer may be
+// recovered with the expression:
+//
+//   ptr = reinterpret_cast<char*>(offset) + *offset
+//
+// A null pointer is encoded as an offset value of 0.
+//
+void EncodePointer(const void* ptr, uint64_t* offset);
+// Note: This function doesn't validate the encoded pointer value.
+const void* DecodePointerRaw(const uint64_t* offset);
+
+// Note: This function doesn't validate the encoded pointer value.
+template <typename T>
+inline void DecodePointer(const uint64_t* offset, T** ptr) {
+  *ptr = reinterpret_cast<T*>(const_cast<void*>(DecodePointerRaw(offset)));
+}
+
+// Checks whether decoding the pointer will overflow and produce a pointer
+// smaller than |offset|.
+bool ValidateEncodedPointer(const uint64_t* offset);
+
+// Handles are encoded as indices into a vector of handles. These functions
+// manipulate the value of |handle|, mapping it to and from an index.
+void EncodeHandle(Handle* handle, std::vector<Handle>* handles);
+// Note: This function doesn't validate the encoded handle value.
+void DecodeHandle(Handle* handle, std::vector<Handle>* handles);
+
+// The following 2 functions are used to encode/decode all objects (structs and
+// arrays) in a consistent manner.
+
+template <typename T>
+inline void Encode(T* obj, std::vector<Handle>* handles) {
+  if (obj->ptr)
+    obj->ptr->EncodePointersAndHandles(handles);
+  EncodePointer(obj->ptr, &obj->offset);
+}
+
+// Note: This function doesn't validate the encoded pointer and handle values.
+template <typename T>
+inline void Decode(T* obj, std::vector<Handle>* handles) {
+  DecodePointer(&obj->offset, &obj->ptr);
+  if (obj->ptr)
+    obj->ptr->DecodePointersAndHandles(handles);
+}
+
+// If returns true, this function also claims the memory range of the size
+// specified in the struct header, starting from |data|.
+// Note: |min_num_bytes| must be no less than sizeof(StructHeader).
+bool ValidateStructHeader(const void* data,
+                          uint32_t min_num_bytes,
+                          uint32_t min_num_fields,
+                          BoundsChecker* bounds_checker);
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_
diff --git a/mojo/public/cpp/bindings/lib/bounds_checker.cc b/mojo/public/cpp/bindings/lib/bounds_checker.cc
new file mode 100644
index 0000000..87f5b7c
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/bounds_checker.cc
@@ -0,0 +1,76 @@
+// Copyright 2014 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/cpp/bindings/lib/bounds_checker.h"
+
+#include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
+#include "mojo/public/cpp/environment/logging.h"
+#include "mojo/public/cpp/system/handle.h"
+
+namespace mojo {
+namespace internal {
+
+BoundsChecker::BoundsChecker(const void* data, uint32_t data_num_bytes,
+                             size_t num_handles)
+    : data_begin_(reinterpret_cast<uintptr_t>(data)),
+      data_end_(data_begin_ + data_num_bytes),
+      handle_begin_(0),
+      handle_end_(static_cast<uint32_t>(num_handles)) {
+  if (data_end_ < data_begin_) {
+    // The calculation of |data_end_| overflowed.
+    // It shouldn't happen but if it does, set the range to empty so
+    // IsValidRange() and ClaimMemory() always fail.
+    MOJO_DCHECK(false) << "Not reached";
+    data_end_ = data_begin_;
+  }
+  if (handle_end_ < num_handles) {
+    // Assigning |num_handles| to |handle_end_| overflowed.
+    // It shouldn't happen but if it does, set the handle index range to empty.
+    MOJO_DCHECK(false) << "Not reached";
+    handle_end_ = 0;
+  }
+}
+
+BoundsChecker::~BoundsChecker() {
+}
+
+bool BoundsChecker::ClaimMemory(const void* position, uint32_t num_bytes) {
+  uintptr_t begin = reinterpret_cast<uintptr_t>(position);
+  uintptr_t end = begin + num_bytes;
+
+  if (!InternalIsValidRange(begin, end))
+    return false;
+
+  data_begin_ = end;
+  return true;
+}
+
+bool BoundsChecker::ClaimHandle(const Handle& encoded_handle) {
+  uint32_t index = encoded_handle.value();
+  if (index == kEncodedInvalidHandleValue)
+    return true;
+
+  if (index < handle_begin_ || index >= handle_end_)
+    return false;
+
+  // |index| + 1 shouldn't overflow, because |index| is not the max value of
+  // uint32_t (it is less than |handle_end_|).
+  handle_begin_ = index + 1;
+  return true;
+}
+
+bool BoundsChecker::IsValidRange(const void* position,
+                                 uint32_t num_bytes) const {
+  uintptr_t begin = reinterpret_cast<uintptr_t>(position);
+  uintptr_t end = begin + num_bytes;
+
+  return InternalIsValidRange(begin, end);
+}
+
+bool BoundsChecker::InternalIsValidRange(uintptr_t begin, uintptr_t end) const {
+  return end > begin && begin >= data_begin_ && end <= data_end_;
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/bounds_checker.h b/mojo/public/cpp/bindings/lib/bounds_checker.h
new file mode 100644
index 0000000..6c47230
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/bounds_checker.h
@@ -0,0 +1,64 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_BOUNDS_CHECKER_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BOUNDS_CHECKER_H_
+
+#include <stdint.h>
+
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+
+class Handle;
+
+namespace internal {
+
+// BoundsChecker is used to validate object sizes, pointers and handle indices
+// for payload of incoming messages.
+class BoundsChecker {
+ public:
+  // [data, data + data_num_bytes) specifies the initial valid memory range.
+  // [0, num_handles) specifies the initial valid range of handle indices.
+  BoundsChecker(const void* data, uint32_t data_num_bytes,
+                size_t num_handles);
+
+  ~BoundsChecker();
+
+  // Claims the specified memory range.
+  // The method succeeds if the range is valid to claim. (Please see
+  // the comments for IsValidRange().)
+  // On success, the valid memory range is shrinked to begin right after the end
+  // of the claimed range.
+  bool ClaimMemory(const void* position, uint32_t num_bytes);
+
+  // Claims the specified encoded handle (which is basically a handle index).
+  // The method succeeds if:
+  // - |encoded_handle|'s value is |kEncodedInvalidHandleValue|.
+  // - the handle is contained inside the valid range of handle indices. In this
+  // case, the valid range is shinked to begin right after the claimed handle.
+  bool ClaimHandle(const Handle& encoded_handle);
+
+  // Returns true if the specified range is not empty, and the range is
+  // contained inside the valid memory range.
+  bool IsValidRange(const void* position, uint32_t num_bytes) const;
+
+ private:
+  bool InternalIsValidRange(uintptr_t begin, uintptr_t end) const;
+
+  // [data_begin_, data_end_) is the valid memory range.
+  uintptr_t data_begin_;
+  uintptr_t data_end_;
+
+  // [handle_begin_, handle_end_) is the valid handle index range.
+  uint32_t handle_begin_;
+  uint32_t handle_end_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(BoundsChecker);
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_BOUNDS_CHECKER_H_
diff --git a/mojo/public/cpp/bindings/lib/buffer.h b/mojo/public/cpp/bindings/lib/buffer.h
new file mode 100644
index 0000000..c3b570e
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/buffer.h
@@ -0,0 +1,24 @@
+// Copyright 2013 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_CPP_BINDINGS_LIB_BUFFER_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BUFFER_H_
+
+#include <stddef.h>
+
+namespace mojo {
+namespace internal {
+
+// Buffer provides a way to allocate memory. Allocations are 8-byte aligned and
+// zero-initialized. Allocations remain valid for the lifetime of the Buffer.
+class Buffer {
+ public:
+  virtual ~Buffer() {}
+  virtual void* Allocate(size_t num_bytes) = 0;
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_BUFFER_H_
diff --git a/mojo/public/cpp/bindings/lib/callback_internal.h b/mojo/public/cpp/bindings/lib/callback_internal.h
new file mode 100644
index 0000000..f76ebef
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/callback_internal.h
@@ -0,0 +1,26 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_CALLBACK_INTERNAL_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_CALLBACK_INTERNAL_H_
+
+namespace mojo {
+class String;
+
+namespace internal {
+
+template <typename T>
+struct Callback_ParamTraits {
+  typedef T ForwardType;
+};
+
+template <>
+struct Callback_ParamTraits<String> {
+  typedef const String& ForwardType;
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_CALLBACK_INTERNAL_H_
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc
new file mode 100644
index 0000000..c0b70b8
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -0,0 +1,205 @@
+// Copyright 2013 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/cpp/bindings/lib/connector.h"
+
+#include "mojo/public/cpp/bindings/error_handler.h"
+#include "mojo/public/cpp/environment/logging.h"
+
+namespace mojo {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+
+Connector::Connector(ScopedMessagePipeHandle message_pipe,
+                     const MojoAsyncWaiter* waiter)
+    : error_handler_(nullptr),
+      waiter_(waiter),
+      message_pipe_(message_pipe.Pass()),
+      incoming_receiver_(nullptr),
+      async_wait_id_(0),
+      error_(false),
+      drop_writes_(false),
+      enforce_errors_from_incoming_receiver_(true),
+      destroyed_flag_(nullptr) {
+  // Even though we don't have an incoming receiver, we still want to monitor
+  // the message pipe to know if is closed or encounters an error.
+  WaitToReadMore();
+}
+
+Connector::~Connector() {
+  if (destroyed_flag_)
+    *destroyed_flag_ = true;
+
+  CancelWait();
+}
+
+void Connector::CloseMessagePipe() {
+  CancelWait();
+  Close(message_pipe_.Pass());
+}
+
+ScopedMessagePipeHandle Connector::PassMessagePipe() {
+  CancelWait();
+  return message_pipe_.Pass();
+}
+
+bool Connector::WaitForIncomingMessage() {
+  if (error_)
+    return false;
+
+  MojoResult rv = Wait(message_pipe_.get(),
+                       MOJO_HANDLE_SIGNAL_READABLE,
+                       MOJO_DEADLINE_INDEFINITE);
+  if (rv != MOJO_RESULT_OK) {
+    NotifyError();
+    return false;
+  }
+  mojo_ignore_result(ReadSingleMessage(&rv));
+  return (rv == MOJO_RESULT_OK);
+}
+
+bool Connector::Accept(Message* message) {
+  MOJO_CHECK(message_pipe_.is_valid());
+
+  if (error_)
+    return false;
+
+  if (drop_writes_)
+    return true;
+
+  MojoResult rv = WriteMessageRaw(
+      message_pipe_.get(),
+      message->data(),
+      message->data_num_bytes(),
+      message->mutable_handles()->empty() ? nullptr :
+          reinterpret_cast<const MojoHandle*>(
+              &message->mutable_handles()->front()),
+      static_cast<uint32_t>(message->mutable_handles()->size()),
+      MOJO_WRITE_MESSAGE_FLAG_NONE);
+
+  switch (rv) {
+    case MOJO_RESULT_OK:
+      // The handles were successfully transferred, so we don't need the message
+      // to track their lifetime any longer.
+      message->mutable_handles()->clear();
+      break;
+    case MOJO_RESULT_FAILED_PRECONDITION:
+      // There's no point in continuing to write to this pipe since the other
+      // end is gone. Avoid writing any future messages. Hide write failures
+      // from the caller since we'd like them to continue consuming any backlog
+      // of incoming messages before regarding the message pipe as closed.
+      drop_writes_ = true;
+      break;
+    case MOJO_RESULT_BUSY:
+      // We'd get a "busy" result if one of the message's handles is:
+      //   - |message_pipe_|'s own handle;
+      //   - simultaneously being used on another thread; or
+      //   - in a "busy" state that prohibits it from being transferred (e.g.,
+      //     a data pipe handle in the middle of a two-phase read/write,
+      //     regardless of which thread that two-phase read/write is happening
+      //     on).
+      // TODO(vtl): I wonder if this should be a |MOJO_DCHECK()|. (But, until
+      // crbug.com/389666, etc. are resolved, this will make tests fail quickly
+      // rather than hanging.)
+      MOJO_CHECK(false) << "Race condition or other bug detected";
+      return false;
+    default:
+      // This particular write was rejected, presumably because of bad input.
+      // The pipe is not necessarily in a bad state.
+      return false;
+  }
+  return true;
+}
+
+// static
+void Connector::CallOnHandleReady(void* closure, MojoResult result) {
+  Connector* self = static_cast<Connector*>(closure);
+  self->OnHandleReady(result);
+}
+
+void Connector::OnHandleReady(MojoResult result) {
+  MOJO_CHECK(async_wait_id_ != 0);
+  async_wait_id_ = 0;
+  if (result != MOJO_RESULT_OK) {
+    NotifyError();
+    return;
+  }
+  ReadAllAvailableMessages();
+  // At this point, this object might have been deleted. Return.
+}
+
+void Connector::WaitToReadMore() {
+  MOJO_CHECK(!async_wait_id_);
+  async_wait_id_ = waiter_->AsyncWait(message_pipe_.get().value(),
+                                      MOJO_HANDLE_SIGNAL_READABLE,
+                                      MOJO_DEADLINE_INDEFINITE,
+                                      &Connector::CallOnHandleReady,
+                                      this);
+}
+
+bool Connector::ReadSingleMessage(MojoResult* read_result) {
+  bool receiver_result = false;
+
+  // Detect if |this| was destroyed during message dispatch. Allow for the
+  // possibility of re-entering ReadMore() through message dispatch.
+  bool was_destroyed_during_dispatch = false;
+  bool* previous_destroyed_flag = destroyed_flag_;
+  destroyed_flag_ = &was_destroyed_during_dispatch;
+
+  MojoResult rv = ReadAndDispatchMessage(
+      message_pipe_.get(), incoming_receiver_, &receiver_result);
+  if (read_result)
+    *read_result = rv;
+
+  if (was_destroyed_during_dispatch) {
+    if (previous_destroyed_flag)
+      *previous_destroyed_flag = true;  // Propagate flag.
+    return false;
+  }
+  destroyed_flag_ = previous_destroyed_flag;
+
+  if (rv == MOJO_RESULT_SHOULD_WAIT)
+    return true;
+
+  if (rv != MOJO_RESULT_OK ||
+      (enforce_errors_from_incoming_receiver_ && !receiver_result)) {
+    NotifyError();
+    return false;
+  }
+  return true;
+}
+
+void Connector::ReadAllAvailableMessages() {
+  while (!error_) {
+    MojoResult rv;
+
+    // Return immediately if |this| was destroyed. Do not touch any members!
+    if (!ReadSingleMessage(&rv))
+      return;
+
+    if (rv == MOJO_RESULT_SHOULD_WAIT) {
+      WaitToReadMore();
+      break;
+    }
+  }
+}
+
+void Connector::CancelWait() {
+  if (!async_wait_id_)
+    return;
+
+  waiter_->CancelWait(async_wait_id_);
+  async_wait_id_ = 0;
+}
+
+void Connector::NotifyError() {
+  error_ = true;
+  CancelWait();
+  if (error_handler_)
+    error_handler_->OnConnectionError();
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/connector.h b/mojo/public/cpp/bindings/lib/connector.h
new file mode 100644
index 0000000..dc598a6
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/connector.h
@@ -0,0 +1,113 @@
+// Copyright 2013 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_CPP_BINDINGS_LIB_CONNECTOR_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_CONNECTOR_H_
+
+#include "mojo/public/c/environment/async_waiter.h"
+#include "mojo/public/cpp/bindings/lib/message_queue.h"
+#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/system/core.h"
+
+namespace mojo {
+class ErrorHandler;
+
+namespace internal {
+
+// The Connector class is responsible for performing read/write operations on a
+// MessagePipe. It writes messages it receives through the MessageReceiver
+// interface that it subclasses, and it forwards messages it reads through the
+// MessageReceiver interface assigned as its incoming receiver.
+//
+// NOTE: MessagePipe I/O is non-blocking.
+//
+class Connector : public MessageReceiver {
+ public:
+  // The Connector takes ownership of |message_pipe|.
+  explicit Connector(
+      ScopedMessagePipeHandle message_pipe,
+      const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter());
+  virtual ~Connector();
+
+  // Sets the receiver to handle messages read from the message pipe.  The
+  // Connector will read messages from the pipe regardless of whether or not an
+  // incoming receiver has been set.
+  void set_incoming_receiver(MessageReceiver* receiver) {
+    incoming_receiver_ = receiver;
+  }
+
+  // Errors from incoming receivers will force the connector into an error
+  // state, where no more messages will be processed. This method is used
+  // during testing to prevent that from happening.
+  void set_enforce_errors_from_incoming_receiver(bool enforce) {
+    enforce_errors_from_incoming_receiver_ = enforce;
+  }
+
+  // Sets the error handler to receive notifications when an error is
+  // encountered while reading from the pipe or waiting to read from the pipe.
+  void set_error_handler(ErrorHandler* error_handler) {
+    error_handler_ = error_handler;
+  }
+
+  // Returns true if an error was encountered while reading from the pipe or
+  // waiting to read from the pipe.
+  bool encountered_error() const { return error_; }
+
+  // Closes the pipe, triggering the error state. Connector is put into a
+  // quiescent state.
+  void CloseMessagePipe();
+
+  // Releases the pipe, not triggering the error state. Connector is put into
+  // a quiescent state.
+  ScopedMessagePipeHandle PassMessagePipe();
+
+  // Waits for the next message on the pipe, blocking until one arrives or an
+  // error happens. Returns |true| if a message has been delivered, |false|
+  // otherwise.
+  bool WaitForIncomingMessage();
+
+  // MessageReceiver implementation:
+  virtual bool Accept(Message* message) override;
+
+ private:
+  static void CallOnHandleReady(void* closure, MojoResult result);
+  void OnHandleReady(MojoResult result);
+
+  void WaitToReadMore();
+
+  // Returns false if |this| was destroyed during message dispatch.
+  MOJO_WARN_UNUSED_RESULT bool ReadSingleMessage(MojoResult* read_result);
+
+  // |this| can be destroyed during message dispatch.
+  void ReadAllAvailableMessages();
+
+  void NotifyError();
+
+  // Cancels any calls made to |waiter_|.
+  void CancelWait();
+
+  ErrorHandler* error_handler_;
+  const MojoAsyncWaiter* waiter_;
+
+  ScopedMessagePipeHandle message_pipe_;
+  MessageReceiver* incoming_receiver_;
+
+  MojoAsyncWaitID async_wait_id_;
+  bool error_;
+  bool drop_writes_;
+  bool enforce_errors_from_incoming_receiver_;
+
+  // If non-null, this will be set to true when the Connector is destroyed.  We
+  // use this flag to allow for the Connector to be destroyed as a side-effect
+  // of dispatching an incoming message.
+  bool* destroyed_flag_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(Connector);
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_CONNECTOR_H_
diff --git a/mojo/public/cpp/bindings/lib/filter_chain.cc b/mojo/public/cpp/bindings/lib/filter_chain.cc
new file mode 100644
index 0000000..6634562
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/filter_chain.cc
@@ -0,0 +1,49 @@
+// Copyright 2014 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/cpp/bindings/lib/filter_chain.h"
+
+#include <algorithm>
+
+#include "mojo/public/cpp/environment/logging.h"
+
+namespace mojo {
+namespace internal {
+
+FilterChain::FilterChain(MessageReceiver* sink) : sink_(sink) {
+}
+
+FilterChain::FilterChain(RValue other) : sink_(other.object->sink_) {
+  other.object->sink_ = nullptr;
+  filters_.swap(other.object->filters_);
+}
+
+FilterChain& FilterChain::operator=(RValue other) {
+  std::swap(sink_, other.object->sink_);
+  filters_.swap(other.object->filters_);
+  return *this;
+}
+
+FilterChain::~FilterChain() {
+  for (std::vector<MessageFilter*>::iterator iter = filters_.begin();
+       iter != filters_.end();
+       ++iter) {
+    delete *iter;
+  }
+}
+
+void FilterChain::SetSink(MessageReceiver* sink) {
+  MOJO_DCHECK(!sink_);
+  sink_ = sink;
+  if (!filters_.empty())
+    filters_.back()->set_sink(sink);
+}
+
+MessageReceiver* FilterChain::GetHead() {
+  MOJO_DCHECK(sink_);
+  return filters_.empty() ? sink_ : filters_.front();
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/filter_chain.h b/mojo/public/cpp/bindings/lib/filter_chain.h
new file mode 100644
index 0000000..fc66642
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/filter_chain.h
@@ -0,0 +1,66 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_FILTER_CHAIN_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_FILTER_CHAIN_H_
+
+#include <vector>
+
+#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/bindings/message_filter.h"
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+namespace internal {
+
+class FilterChain {
+  MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(FilterChain, RValue)
+
+ public:
+  // Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while
+  // this object is alive.
+  explicit FilterChain(MessageReceiver* sink = nullptr);
+
+  // Move-only constructor and operator=.
+  FilterChain(RValue other);
+  FilterChain& operator=(RValue other);
+
+  ~FilterChain();
+
+  template <typename FilterType>
+  inline void Append();
+
+  // Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while
+  // this object is alive.
+  void SetSink(MessageReceiver* sink);
+
+  // Returns a receiver to accept messages. Messages flow through all filters in
+  // the same order as they were appended to the chain. If all filters allow a
+  // message to pass, it will be forwarded to |sink_|.
+  // The returned value is invalidated when this object goes away.
+  MessageReceiver* GetHead();
+
+ private:
+  // Owned by this object.
+  std::vector<MessageFilter*> filters_;
+
+  MessageReceiver* sink_;
+};
+
+template <typename FilterType>
+inline void FilterChain::Append() {
+  FilterType* filter = new FilterType(sink_);
+  if (!filters_.empty())
+    filters_.back()->set_sink(filter);
+  filters_.push_back(filter);
+}
+
+template <>
+inline void FilterChain::Append<PassThroughFilter>() {
+}
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_FILTER_CHAIN_H_
diff --git a/mojo/public/cpp/bindings/lib/fixed_buffer.cc b/mojo/public/cpp/bindings/lib/fixed_buffer.cc
new file mode 100644
index 0000000..9542ef8
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/fixed_buffer.cc
@@ -0,0 +1,52 @@
+// Copyright 2014 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/cpp/bindings/lib/fixed_buffer.h"
+
+#include <stdlib.h>
+
+#include <algorithm>
+
+#include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
+#include "mojo/public/cpp/environment/logging.h"
+
+namespace mojo {
+namespace internal {
+
+FixedBuffer::FixedBuffer(size_t size)
+    : ptr_(nullptr),
+      cursor_(0),
+      size_(internal::Align(size)) {
+  // calloc() required to zero memory and thus avoid info leaks.
+  ptr_ = static_cast<char*>(calloc(size_, 1));
+}
+
+FixedBuffer::~FixedBuffer() {
+  free(ptr_);
+}
+
+void* FixedBuffer::Allocate(size_t delta) {
+  delta = internal::Align(delta);
+
+  if (delta == 0 || delta > size_ - cursor_) {
+    MOJO_DCHECK(false) << "Not reached";
+    return nullptr;
+  }
+
+  char* result = ptr_ + cursor_;
+  cursor_ += delta;
+
+  return result;
+}
+
+void* FixedBuffer::Leak() {
+  char* ptr = ptr_;
+  ptr_ = nullptr;
+  cursor_ = 0;
+  size_ = 0;
+  return ptr;
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/fixed_buffer.h b/mojo/public/cpp/bindings/lib/fixed_buffer.h
new file mode 100644
index 0000000..d23f664
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/fixed_buffer.h
@@ -0,0 +1,67 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_FIXED_BUFFER_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_FIXED_BUFFER_H_
+
+#include "mojo/public/cpp/bindings/lib/buffer.h"
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+namespace internal {
+
+// FixedBuffer provides a simple way to allocate objects within a fixed chunk
+// of memory. Objects are allocated by calling the |Allocate| method, which
+// extends the buffer accordingly. Objects allocated in this way are not freed
+// explicitly. Instead, they remain valid so long as the FixedBuffer remains
+// valid.  The Leak method may be used to steal the underlying memory from the
+// FixedBuffer.
+//
+// Typical usage:
+//
+//   {
+//     FixedBuffer buf(8 + 8);
+//
+//     int* a = static_cast<int*>(buf->Allocate(sizeof(int)));
+//     *a = 2;
+//
+//     double* b = static_cast<double*>(buf->Allocate(sizeof(double)));
+//     *b = 3.14f;
+//
+//     void* data = buf.Leak();
+//     Process(data);
+//
+//     free(data);
+//   }
+//
+class FixedBuffer : public Buffer {
+ public:
+  explicit FixedBuffer(size_t size);
+  virtual ~FixedBuffer();
+
+  // Grows the buffer by |num_bytes| and returns a pointer to the start of the
+  // addition. The resulting address is 8-byte aligned, and the content of the
+  // memory is zero-filled.
+  virtual void* Allocate(size_t num_bytes) override;
+
+  size_t size() const { return size_; }
+
+  // Returns the internal memory owned by the Buffer to the caller. The Buffer
+  // relinquishes its pointer, effectively resetting the state of the Buffer
+  // and leaving the caller responsible for freeing the returned memory address
+  // when no longer needed.
+  void* Leak();
+
+ private:
+  char* ptr_;
+  size_t cursor_;
+  size_t size_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(FixedBuffer);
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_FIXED_BUFFER_H_
diff --git a/mojo/public/cpp/bindings/lib/interface_impl_internal.h b/mojo/public/cpp/bindings/lib/interface_impl_internal.h
new file mode 100644
index 0000000..492b182
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/interface_impl_internal.h
@@ -0,0 +1,128 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_INTERFACE_IMPL_INTERNAL_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_IMPL_INTERNAL_H_
+
+#include "mojo/public/cpp/bindings/error_handler.h"
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/public/cpp/bindings/lib/filter_chain.h"
+#include "mojo/public/cpp/bindings/lib/message_header_validator.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/environment/logging.h"
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+namespace internal {
+
+template <typename Interface>
+class InterfaceImplBase : public Interface {
+ public:
+  virtual ~InterfaceImplBase() {}
+  virtual void OnConnectionEstablished() = 0;
+  virtual void OnConnectionError() = 0;
+};
+
+template <typename Interface>
+class InterfaceImplState : public ErrorHandler {
+ public:
+  typedef typename Interface::Client Client;
+
+  explicit InterfaceImplState(InterfaceImplBase<Interface>* instance)
+      : router_(nullptr),
+        proxy_(nullptr),
+        instance_bound_to_pipe_(false)
+#ifndef NDEBUG
+        ,
+        deleting_instance_due_to_error_(false)
+#endif
+  {
+    MOJO_DCHECK(instance);
+    stub_.set_sink(instance);
+  }
+
+  virtual ~InterfaceImplState() {
+#ifndef NDEBUG
+    MOJO_DCHECK(!instance_bound_to_pipe_ || deleting_instance_due_to_error_);
+#endif
+    delete proxy_;
+    if (router_) {
+      router_->set_error_handler(nullptr);
+      delete router_;
+    }
+  }
+
+  void BindProxy(
+      InterfacePtr<Interface>* ptr,
+      bool instance_bound_to_pipe,
+      const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) {
+    MessagePipe pipe;
+    ptr->Bind(pipe.handle0.Pass(), waiter);
+    Bind(pipe.handle1.Pass(), instance_bound_to_pipe, waiter);
+  }
+
+  void Bind(ScopedMessagePipeHandle handle,
+            bool instance_bound_to_pipe,
+            const MojoAsyncWaiter* waiter) {
+    MOJO_CHECK(!router_);
+
+    FilterChain filters;
+    filters.Append<MessageHeaderValidator>();
+    filters.Append<typename Interface::RequestValidator_>();
+    filters.Append<typename Interface::Client::ResponseValidator_>();
+
+    router_ = new Router(handle.Pass(), filters.Pass(), waiter);
+    router_->set_incoming_receiver(&stub_);
+    router_->set_error_handler(this);
+
+    proxy_ = new typename Client::Proxy_(router_);
+
+    instance_bound_to_pipe_ = instance_bound_to_pipe;
+
+    instance()->OnConnectionEstablished();
+  }
+
+  bool WaitForIncomingMethodCall() {
+    MOJO_DCHECK(router_);
+    return router_->WaitForIncomingMessage();
+  }
+
+  Router* router() { return router_; }
+  Client* client() { return proxy_; }
+
+ private:
+  InterfaceImplBase<Interface>* instance() {
+    return static_cast<InterfaceImplBase<Interface>*>(stub_.sink());
+  }
+
+  virtual void OnConnectionError() override {
+    // If the the instance is not bound to the pipe, the instance might choose
+    // to delete itself in the OnConnectionError handler, which would in turn
+    // delete this.  Save the error behavior before invoking the error handler
+    // so we can correctly decide what to do.
+    bool bound = instance_bound_to_pipe_;
+    instance()->OnConnectionError();
+    if (!bound)
+      return;
+#ifndef NDEBUG
+    deleting_instance_due_to_error_ = true;
+#endif
+    delete instance();
+  }
+
+  Router* router_;
+  typename Client::Proxy_* proxy_;
+  typename Interface::Stub_ stub_;
+  bool instance_bound_to_pipe_;
+#ifndef NDEBUG
+  bool deleting_instance_due_to_error_;
+#endif
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(InterfaceImplState);
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_IMPL_INTERNAL_H_
diff --git a/mojo/public/cpp/bindings/lib/interface_ptr_internal.h b/mojo/public/cpp/bindings/lib/interface_ptr_internal.h
new file mode 100644
index 0000000..77386fa
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/interface_ptr_internal.h
@@ -0,0 +1,151 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_INTERFACE_PTR_INTERNAL_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_INTERNAL_H_
+
+#include <algorithm>  // For |std::swap()|.
+
+#include "mojo/public/cpp/bindings/lib/filter_chain.h"
+#include "mojo/public/cpp/bindings/lib/message_header_validator.h"
+#include "mojo/public/cpp/bindings/lib/router.h"
+#include "mojo/public/cpp/environment/logging.h"
+
+struct MojoAsyncWaiter;
+
+namespace mojo {
+namespace internal {
+
+template <typename Interface>
+class InterfacePtrState {
+ public:
+  InterfacePtrState() : proxy_(nullptr), router_(nullptr), waiter_(nullptr) {}
+
+  ~InterfacePtrState() {
+    // Destruction order matters here. We delete |proxy_| first, even though
+    // |router_| may have a reference to it, so that |~Interface| may have a
+    // shot at generating new outbound messages (ie, invoking client methods).
+    delete proxy_;
+    delete router_;
+  }
+
+  Interface* instance() {
+    ConfigureProxyIfNecessary();
+
+    // This will be null if the object is not bound.
+    return proxy_;
+  }
+
+  void Swap(InterfacePtrState* other) {
+    std::swap(other->proxy_, proxy_);
+    std::swap(other->router_, router_);
+    handle_.swap(other->handle_);
+    std::swap(other->waiter_, waiter_);
+  }
+
+  void Bind(ScopedMessagePipeHandle handle, const MojoAsyncWaiter* waiter) {
+    MOJO_DCHECK(!proxy_);
+    MOJO_DCHECK(!router_);
+    MOJO_DCHECK(!handle_.is_valid());
+    MOJO_DCHECK(!waiter_);
+
+    handle_ = handle.Pass();
+    waiter_ = waiter;
+  }
+
+  bool WaitForIncomingMethodCall() {
+    ConfigureProxyIfNecessary();
+
+    MOJO_DCHECK(router_);
+    return router_->WaitForIncomingMessage();
+  }
+
+  ScopedMessagePipeHandle PassMessagePipe() {
+    if (router_)
+      return router_->PassMessagePipe();
+
+    waiter_ = nullptr;
+    return handle_.Pass();
+  }
+
+  bool is_bound() const {
+    return handle_.is_valid() || router_;
+  }
+
+  void set_client(typename Interface::Client* client) {
+    ConfigureProxyIfNecessary();
+
+    MOJO_DCHECK(proxy_);
+    proxy_->stub.set_sink(client);
+  }
+
+  bool encountered_error() const {
+    return router_ ? router_->encountered_error() : false;
+  }
+
+  void set_error_handler(ErrorHandler* error_handler) {
+    ConfigureProxyIfNecessary();
+
+    MOJO_DCHECK(router_);
+    router_->set_error_handler(error_handler);
+  }
+
+  Router* router_for_testing() {
+    ConfigureProxyIfNecessary();
+    return router_;
+  }
+
+ private:
+  class ProxyWithStub : public Interface::Proxy_ {
+   public:
+    explicit ProxyWithStub(MessageReceiverWithResponder* receiver)
+        : Interface::Proxy_(receiver) {
+    }
+    typename Interface::Client::Stub_ stub;
+   private:
+    MOJO_DISALLOW_COPY_AND_ASSIGN(ProxyWithStub);
+  };
+
+  void ConfigureProxyIfNecessary() {
+    // The proxy has been configured.
+    if (proxy_) {
+      MOJO_DCHECK(router_);
+      return;
+    }
+    // The object hasn't been bound.
+    if (!waiter_) {
+      MOJO_DCHECK(!handle_.is_valid());
+      return;
+    }
+
+    FilterChain filters;
+    filters.Append<MessageHeaderValidator>();
+    filters.Append<typename Interface::Client::RequestValidator_>();
+    filters.Append<typename Interface::ResponseValidator_>();
+
+    router_ = new Router(handle_.Pass(), filters.Pass(), waiter_);
+    waiter_ = nullptr;
+
+    ProxyWithStub* proxy = new ProxyWithStub(router_);
+    router_->set_incoming_receiver(&proxy->stub);
+
+    proxy_ = proxy;
+  }
+
+  ProxyWithStub* proxy_;
+  Router* router_;
+
+  // |proxy_| and |router_| are not initialized until read/write with the
+  // message pipe handle is needed. Before that, |handle_| and |waiter_| store
+  // the arguments of Bind().
+  ScopedMessagePipeHandle handle_;
+  const MojoAsyncWaiter* waiter_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(InterfacePtrState);
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_INTERNAL_H_
diff --git a/mojo/public/cpp/bindings/lib/message.cc b/mojo/public/cpp/bindings/lib/message.cc
new file mode 100644
index 0000000..cec60c0
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/message.cc
@@ -0,0 +1,82 @@
+// Copyright 2013 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/cpp/bindings/message.h"
+
+#include <stdlib.h>
+
+#include <algorithm>
+
+#include "mojo/public/cpp/environment/logging.h"
+
+namespace mojo {
+
+Message::Message()
+    : data_num_bytes_(0),
+      data_(nullptr) {
+}
+
+Message::~Message() {
+  free(data_);
+
+  for (std::vector<Handle>::iterator it = handles_.begin();
+       it != handles_.end(); ++it) {
+    if (it->is_valid())
+      CloseRaw(*it);
+  }
+}
+
+void Message::AllocUninitializedData(uint32_t num_bytes) {
+  MOJO_DCHECK(!data_);
+  data_num_bytes_ = num_bytes;
+  data_ = static_cast<internal::MessageData*>(malloc(num_bytes));
+}
+
+void Message::AdoptData(uint32_t num_bytes, internal::MessageData* data) {
+  MOJO_DCHECK(!data_);
+  data_num_bytes_ = num_bytes;
+  data_ = data;
+}
+
+void Message::Swap(Message* other) {
+  std::swap(data_num_bytes_, other->data_num_bytes_);
+  std::swap(data_, other->data_);
+  std::swap(handles_, other->handles_);
+}
+
+MojoResult ReadAndDispatchMessage(MessagePipeHandle handle,
+                                  MessageReceiver* receiver,
+                                  bool* receiver_result) {
+  MojoResult rv;
+
+  uint32_t num_bytes = 0, num_handles = 0;
+  rv = ReadMessageRaw(handle,
+                      nullptr,
+                      &num_bytes,
+                      nullptr,
+                      &num_handles,
+                      MOJO_READ_MESSAGE_FLAG_NONE);
+  if (rv != MOJO_RESULT_RESOURCE_EXHAUSTED)
+    return rv;
+
+  Message message;
+  message.AllocUninitializedData(num_bytes);
+  message.mutable_handles()->resize(num_handles);
+
+  rv = ReadMessageRaw(handle,
+                      message.mutable_data(),
+                      &num_bytes,
+                      message.mutable_handles()->empty()
+                          ? nullptr
+                          : reinterpret_cast<MojoHandle*>(
+                                &message.mutable_handles()->front()),
+                      &num_handles,
+                      MOJO_READ_MESSAGE_FLAG_NONE);
+  if (receiver && rv == MOJO_RESULT_OK)
+    *receiver_result = receiver->Accept(&message);
+
+  return rv;
+}
+
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/message_builder.cc b/mojo/public/cpp/bindings/lib/message_builder.cc
new file mode 100644
index 0000000..c746644
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/message_builder.cc
@@ -0,0 +1,52 @@
+// Copyright 2013 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/cpp/bindings/lib/message_builder.h"
+
+#include "mojo/public/cpp/bindings/message.h"
+
+namespace mojo {
+namespace internal {
+
+template <typename Header>
+void Allocate(Buffer* buf, Header** header) {
+  *header = static_cast<Header*>(buf->Allocate(sizeof(Header)));
+  (*header)->num_bytes = sizeof(Header);
+}
+
+MessageBuilder::MessageBuilder(uint32_t name, size_t payload_size)
+    : buf_(sizeof(MessageHeader) + payload_size) {
+  MessageHeader* header;
+  Allocate(&buf_, &header);
+  header->num_fields = 2;
+  header->name = name;
+}
+
+MessageBuilder::~MessageBuilder() {
+}
+
+void MessageBuilder::Finish(Message* message) {
+  uint32_t num_bytes = static_cast<uint32_t>(buf_.size());
+  message->AdoptData(num_bytes, static_cast<MessageData*>(buf_.Leak()));
+}
+
+MessageBuilder::MessageBuilder(size_t size)
+    : buf_(size) {
+}
+
+MessageWithRequestIDBuilder::MessageWithRequestIDBuilder(uint32_t name,
+                                                         size_t payload_size,
+                                                         uint32_t flags,
+                                                         uint64_t request_id)
+    : MessageBuilder(sizeof(MessageHeaderWithRequestID) + payload_size) {
+  MessageHeaderWithRequestID* header;
+  Allocate(&buf_, &header);
+  header->num_fields = 3;
+  header->name = name;
+  header->flags = flags;
+  header->request_id = request_id;
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/message_builder.h b/mojo/public/cpp/bindings/lib/message_builder.h
new file mode 100644
index 0000000..b4988ff
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/message_builder.h
@@ -0,0 +1,63 @@
+// Copyright 2013 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_CPP_BINDINGS_LIB_MESSAGE_BUILDER_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_BUILDER_H_
+
+#include <stdint.h>
+
+#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
+#include "mojo/public/cpp/bindings/lib/message_internal.h"
+
+namespace mojo {
+class Message;
+
+namespace internal {
+
+class MessageBuilder {
+ public:
+  MessageBuilder(uint32_t name, size_t payload_size);
+  ~MessageBuilder();
+
+  Buffer* buffer() { return &buf_; }
+
+  // Call Finish when done making allocations in |buffer()|. Upon return,
+  // |message| will contain the message data, and |buffer()| will no longer be
+  // valid to reference.
+  void Finish(Message* message);
+
+ protected:
+  explicit MessageBuilder(size_t size);
+  FixedBuffer buf_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(MessageBuilder);
+};
+
+class MessageWithRequestIDBuilder : public MessageBuilder {
+ public:
+  MessageWithRequestIDBuilder(uint32_t name, size_t payload_size,
+                              uint32_t flags, uint64_t request_id);
+};
+
+class RequestMessageBuilder : public MessageWithRequestIDBuilder {
+ public:
+  RequestMessageBuilder(uint32_t name, size_t payload_size)
+      : MessageWithRequestIDBuilder(name, payload_size, kMessageExpectsResponse,
+                                    0) {
+  }
+};
+
+class ResponseMessageBuilder : public MessageWithRequestIDBuilder {
+ public:
+  ResponseMessageBuilder(uint32_t name, size_t payload_size,
+                         uint64_t request_id)
+      : MessageWithRequestIDBuilder(name, payload_size, kMessageIsResponse,
+                                    request_id) {
+  }
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_BUILDER_H_
diff --git a/mojo/public/cpp/bindings/lib/message_filter.cc b/mojo/public/cpp/bindings/lib/message_filter.cc
new file mode 100644
index 0000000..b09f40d
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/message_filter.cc
@@ -0,0 +1,23 @@
+// Copyright 2014 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/cpp/bindings/message_filter.h"
+
+namespace mojo {
+
+MessageFilter::MessageFilter(MessageReceiver* sink) : sink_(sink) {
+}
+
+MessageFilter::~MessageFilter() {
+}
+
+PassThroughFilter::PassThroughFilter(MessageReceiver* sink)
+    : MessageFilter(sink) {
+}
+
+bool PassThroughFilter::Accept(Message* message) {
+  return sink_->Accept(message);
+}
+
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/message_header_validator.cc b/mojo/public/cpp/bindings/lib/message_header_validator.cc
new file mode 100644
index 0000000..a55917a
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/message_header_validator.cc
@@ -0,0 +1,81 @@
+// Copyright 2014 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/cpp/bindings/lib/message_header_validator.h"
+
+#include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
+#include "mojo/public/cpp/bindings/lib/bounds_checker.h"
+#include "mojo/public/cpp/bindings/lib/validation_errors.h"
+
+namespace mojo {
+namespace internal {
+namespace {
+
+bool IsValidMessageHeader(const MessageHeader* header) {
+  // NOTE: Our goal is to preserve support for future extension of the message
+  // header. If we encounter fields we do not understand, we must ignore them.
+
+  // Extra validation of the struct header:
+  if (header->num_fields == 2) {
+    if (header->num_bytes != sizeof(MessageHeader)) {
+      ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
+      return false;
+    }
+  } else if (header->num_fields == 3) {
+    if (header->num_bytes != sizeof(MessageHeaderWithRequestID)) {
+      ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
+      return false;
+    }
+  } else if (header->num_fields > 3) {
+    if (header->num_bytes < sizeof(MessageHeaderWithRequestID)) {
+      ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
+      return false;
+    }
+  }
+
+  // Validate flags (allow unknown bits):
+
+  // These flags require a RequestID.
+  if (header->num_fields < 3 &&
+        ((header->flags & kMessageExpectsResponse) ||
+         (header->flags & kMessageIsResponse))) {
+    ReportValidationError(VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID);
+    return false;
+  }
+
+  // These flags are mutually exclusive.
+  if ((header->flags & kMessageExpectsResponse) &&
+      (header->flags & kMessageIsResponse)) {
+    ReportValidationError(
+        VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION);
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+MessageHeaderValidator::MessageHeaderValidator(MessageReceiver* sink)
+    : MessageFilter(sink) {
+}
+
+bool MessageHeaderValidator::Accept(Message* message) {
+  // Pass 0 as number of handles because we don't expect any in the header, even
+  // if |message| contains handles.
+  BoundsChecker bounds_checker(message->data(), message->data_num_bytes(), 0);
+
+  if (!ValidateStructHeader(message->data(), sizeof(MessageHeader), 2,
+                            &bounds_checker)) {
+    return false;
+  }
+
+  if (!IsValidMessageHeader(message->header()))
+    return false;
+
+  return sink_->Accept(message);
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/message_header_validator.h b/mojo/public/cpp/bindings/lib/message_header_validator.h
new file mode 100644
index 0000000..790aa9b
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/message_header_validator.h
@@ -0,0 +1,24 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_MESSAGE_HEADER_VALIDATOR_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_HEADER_VALIDATOR_H_
+
+#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/bindings/message_filter.h"
+
+namespace mojo {
+namespace internal {
+
+class MessageHeaderValidator : public MessageFilter {
+ public:
+  explicit MessageHeaderValidator(MessageReceiver* sink = nullptr);
+
+  virtual bool Accept(Message* message) override;
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_HEADER_VALIDATOR_H_
diff --git a/mojo/public/cpp/bindings/lib/message_internal.h b/mojo/public/cpp/bindings/lib/message_internal.h
new file mode 100644
index 0000000..3c67902
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/message_internal.h
@@ -0,0 +1,44 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_MESSAGE_INTERNAL_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_INTERNAL_H_
+
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+
+namespace mojo {
+namespace internal {
+
+#pragma pack(push, 1)
+
+enum {
+  kMessageExpectsResponse = 1 << 0,
+  kMessageIsResponse      = 1 << 1
+};
+
+struct MessageHeader : internal::StructHeader {
+  uint32_t name;
+  uint32_t flags;
+};
+MOJO_COMPILE_ASSERT(sizeof(MessageHeader) == 16, bad_sizeof_MessageHeader);
+
+struct MessageHeaderWithRequestID : MessageHeader {
+  uint64_t request_id;
+};
+MOJO_COMPILE_ASSERT(sizeof(MessageHeaderWithRequestID) == 24,
+                    bad_sizeof_MessageHeaderWithRequestID);
+
+struct MessageData {
+  MessageHeader header;
+};
+
+MOJO_COMPILE_ASSERT(sizeof(MessageData) == sizeof(MessageHeader),
+                    bad_sizeof_MessageData);
+
+#pragma pack(pop)
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_INTERNAL_H_
diff --git a/mojo/public/cpp/bindings/lib/message_queue.cc b/mojo/public/cpp/bindings/lib/message_queue.cc
new file mode 100644
index 0000000..fd701e9
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/message_queue.cc
@@ -0,0 +1,48 @@
+// Copyright 2013 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/cpp/bindings/lib/message_queue.h"
+
+#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/environment/logging.h"
+
+namespace mojo {
+namespace internal {
+
+MessageQueue::MessageQueue() {
+}
+
+MessageQueue::~MessageQueue() {
+  while (!queue_.empty())
+    Pop();
+}
+
+bool MessageQueue::IsEmpty() const {
+  return queue_.empty();
+}
+
+Message* MessageQueue::Peek() {
+  MOJO_DCHECK(!queue_.empty());
+  return queue_.front();
+}
+
+void MessageQueue::Push(Message* message) {
+  queue_.push(new Message());
+  queue_.back()->Swap(message);
+}
+
+void MessageQueue::Pop(Message* message) {
+  MOJO_DCHECK(!queue_.empty());
+  queue_.front()->Swap(message);
+  Pop();
+}
+
+void MessageQueue::Pop() {
+  MOJO_DCHECK(!queue_.empty());
+  delete queue_.front();
+  queue_.pop();
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/message_queue.h b/mojo/public/cpp/bindings/lib/message_queue.h
new file mode 100644
index 0000000..4e46b54
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/message_queue.h
@@ -0,0 +1,47 @@
+// Copyright 2013 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_CPP_BINDINGS_LIB_MESSAGE_QUEUE_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_QUEUE_H_
+
+#include <queue>
+
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+class Message;
+
+namespace internal {
+
+// A queue for Message objects.
+class MessageQueue {
+ public:
+  MessageQueue();
+  ~MessageQueue();
+
+  bool IsEmpty() const;
+  Message* Peek();
+
+  // This method transfers ownership of |message->data| and |message->handles|
+  // to the message queue, resetting |message| in the process.
+  void Push(Message* message);
+
+  // Removes the next message from the queue, transferring ownership of its
+  // data and handles to the given |message|.
+  void Pop(Message* message);
+
+  // Removes the next message from the queue, discarding its data and handles.
+  // This is meant to be used in conjunction with |Peek|.
+  void Pop();
+
+ private:
+  std::queue<Message*> queue_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(MessageQueue);
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_QUEUE_H_
diff --git a/mojo/public/cpp/bindings/lib/no_interface.cc b/mojo/public/cpp/bindings/lib/no_interface.cc
new file mode 100644
index 0000000..9e0945c
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/no_interface.cc
@@ -0,0 +1,20 @@
+// Copyright 2014 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/cpp/bindings/no_interface.h"
+
+namespace mojo {
+
+const char* NoInterface::Name_ = "mojo::NoInterface";
+
+bool NoInterfaceStub::Accept(Message* message) {
+  return false;
+}
+
+bool NoInterfaceStub::AcceptWithResponder(Message* message,
+                                          MessageReceiver* responder) {
+  return false;
+}
+
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/router.cc b/mojo/public/cpp/bindings/lib/router.cc
new file mode 100644
index 0000000..3478840
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/router.cc
@@ -0,0 +1,142 @@
+// Copyright 2014 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/cpp/bindings/lib/router.h"
+
+#include "mojo/public/cpp/environment/logging.h"
+
+namespace mojo {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+
+class ResponderThunk : public MessageReceiver {
+ public:
+  explicit ResponderThunk(const SharedData<Router*>& router)
+      : router_(router) {
+  }
+  virtual ~ResponderThunk() {
+  }
+
+  // MessageReceiver implementation:
+  virtual bool Accept(Message* message) override {
+    MOJO_DCHECK(message->has_flag(kMessageIsResponse));
+
+    bool result = false;
+
+    Router* router = router_.value();
+    if (router)
+      result = router->Accept(message);
+
+    return result;
+  }
+
+ private:
+  SharedData<Router*> router_;
+};
+
+// ----------------------------------------------------------------------------
+
+Router::HandleIncomingMessageThunk::HandleIncomingMessageThunk(Router* router)
+    : router_(router) {
+}
+
+Router::HandleIncomingMessageThunk::~HandleIncomingMessageThunk() {
+}
+
+bool Router::HandleIncomingMessageThunk::Accept(Message* message) {
+  return router_->HandleIncomingMessage(message);
+}
+
+// ----------------------------------------------------------------------------
+
+Router::Router(ScopedMessagePipeHandle message_pipe,
+               FilterChain filters,
+               const MojoAsyncWaiter* waiter)
+    : thunk_(this),
+      filters_(filters.Pass()),
+      connector_(message_pipe.Pass(), waiter),
+      weak_self_(this),
+      incoming_receiver_(nullptr),
+      next_request_id_(0),
+      testing_mode_(false) {
+  filters_.SetSink(&thunk_);
+  connector_.set_incoming_receiver(filters_.GetHead());
+}
+
+Router::~Router() {
+  weak_self_.set_value(nullptr);
+
+  for (ResponderMap::const_iterator i = responders_.begin();
+       i != responders_.end(); ++i) {
+    delete i->second;
+  }
+}
+
+bool Router::Accept(Message* message) {
+  MOJO_DCHECK(!message->has_flag(kMessageExpectsResponse));
+  return connector_.Accept(message);
+}
+
+bool Router::AcceptWithResponder(Message* message,
+                                 MessageReceiver* responder) {
+  MOJO_DCHECK(message->has_flag(kMessageExpectsResponse));
+
+  // Reserve 0 in case we want it to convey special meaning in the future.
+  uint64_t request_id = next_request_id_++;
+  if (request_id == 0)
+    request_id = next_request_id_++;
+
+  message->set_request_id(request_id);
+  if (!connector_.Accept(message))
+    return false;
+
+  // We assume ownership of |responder|.
+  responders_[request_id] = responder;
+  return true;
+}
+
+void Router::EnableTestingMode() {
+  testing_mode_ = true;
+  connector_.set_enforce_errors_from_incoming_receiver(false);
+}
+
+bool Router::HandleIncomingMessage(Message* message) {
+  if (message->has_flag(kMessageExpectsResponse)) {
+    if (incoming_receiver_) {
+      MessageReceiver* responder = new ResponderThunk(weak_self_);
+      bool ok = incoming_receiver_->AcceptWithResponder(message, responder);
+      if (!ok)
+        delete responder;
+      return ok;
+    }
+
+    // If we receive a request expecting a response when the client is not
+    // listening, then we have no choice but to tear down the pipe.
+    connector_.CloseMessagePipe();
+  } else if (message->has_flag(kMessageIsResponse)) {
+    uint64_t request_id = message->request_id();
+    ResponderMap::iterator it = responders_.find(request_id);
+    if (it == responders_.end()) {
+      MOJO_DCHECK(testing_mode_);
+      return false;
+    }
+    MessageReceiver* responder = it->second;
+    responders_.erase(it);
+    bool ok = responder->Accept(message);
+    delete responder;
+    return ok;
+  } else {
+    if (incoming_receiver_)
+      return incoming_receiver_->Accept(message);
+    // OK to drop message on the floor.
+  }
+
+  return false;
+}
+
+// ----------------------------------------------------------------------------
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/router.h b/mojo/public/cpp/bindings/lib/router.h
new file mode 100644
index 0000000..ebd4928
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/router.h
@@ -0,0 +1,97 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_ROUTER_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_
+
+#include <map>
+
+#include "mojo/public/cpp/bindings/lib/connector.h"
+#include "mojo/public/cpp/bindings/lib/filter_chain.h"
+#include "mojo/public/cpp/bindings/lib/shared_data.h"
+#include "mojo/public/cpp/environment/environment.h"
+
+namespace mojo {
+namespace internal {
+
+class Router : public MessageReceiverWithResponder {
+ public:
+  Router(ScopedMessagePipeHandle message_pipe,
+         FilterChain filters,
+         const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter());
+  virtual ~Router();
+
+  // Sets the receiver to handle messages read from the message pipe that do
+  // not have the kMessageIsResponse flag set.
+  void set_incoming_receiver(MessageReceiverWithResponder* receiver) {
+    incoming_receiver_ = receiver;
+  }
+
+  // Sets the error handler to receive notifications when an error is
+  // encountered while reading from the pipe or waiting to read from the pipe.
+  void set_error_handler(ErrorHandler* error_handler) {
+    connector_.set_error_handler(error_handler);
+  }
+
+  // Returns true if an error was encountered while reading from the pipe or
+  // waiting to read from the pipe.
+  bool encountered_error() const { return connector_.encountered_error(); }
+
+  void CloseMessagePipe() {
+    connector_.CloseMessagePipe();
+  }
+
+  ScopedMessagePipeHandle PassMessagePipe() {
+    return connector_.PassMessagePipe();
+  }
+
+  // MessageReceiver implementation:
+  virtual bool Accept(Message* message) override;
+  virtual bool AcceptWithResponder(Message* message,
+                                   MessageReceiver* responder) override;
+
+  // Blocks the current thread for the first incoming method call, i.e., either
+  // a call to a client method or a callback method.
+  bool WaitForIncomingMessage() {
+    return connector_.WaitForIncomingMessage();
+  }
+
+  // Sets this object to testing mode.
+  // In testing mode:
+  // - the object is more tolerant of unrecognized response messages;
+  // - the connector continues working after seeing errors from its incoming
+  //   receiver.
+  void EnableTestingMode();
+
+ private:
+  typedef std::map<uint64_t, MessageReceiver*> ResponderMap;
+
+  class HandleIncomingMessageThunk : public MessageReceiver {
+   public:
+    HandleIncomingMessageThunk(Router* router);
+    virtual ~HandleIncomingMessageThunk();
+
+    // MessageReceiver implementation:
+    virtual bool Accept(Message* message) override;
+
+   private:
+    Router* router_;
+  };
+
+  bool HandleIncomingMessage(Message* message);
+
+  HandleIncomingMessageThunk thunk_;
+  FilterChain filters_;
+  Connector connector_;
+  SharedData<Router*> weak_self_;
+  MessageReceiverWithResponder* incoming_receiver_;
+  ResponderMap responders_;
+  uint64_t next_request_id_;
+  bool testing_mode_;
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_
diff --git a/mojo/public/cpp/bindings/lib/shared_data.h b/mojo/public/cpp/bindings/lib/shared_data.h
new file mode 100644
index 0000000..c7bd54f
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/shared_data.h
@@ -0,0 +1,84 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_SHARED_DATA_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_DATA_H_
+
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+namespace internal {
+
+// Used to allocate an instance of T that can be shared via reference counting.
+template <typename T>
+class SharedData {
+ public:
+  ~SharedData() {
+    holder_->Release();
+  }
+
+  SharedData() : holder_(new Holder()) {
+  }
+
+  explicit SharedData(const T& value) : holder_(new Holder(value)) {
+  }
+
+  SharedData(const SharedData<T>& other) : holder_(other.holder_) {
+    holder_->Retain();
+  }
+
+  SharedData<T>& operator=(const SharedData<T>& other) {
+    if (other.holder_ == holder_)
+      return *this;
+    holder_->Release();
+    holder_ = other.holder_;
+    holder_->Retain();
+    return *this;
+  }
+
+  void reset() {
+    holder_->Release();
+    holder_ = new Holder();
+  }
+
+  void reset(const T& value) {
+    holder_->Release();
+    holder_ = new Holder(value);
+  }
+
+  void set_value(const T& value) {
+    holder_->value = value;
+  }
+  T* mutable_value() {
+    return &holder_->value;
+  }
+  const T& value() const {
+    return holder_->value;
+  }
+
+ private:
+  class Holder {
+   public:
+    Holder() : value(), ref_count_(1) {
+    }
+    Holder(const T& value) : value(value), ref_count_(1) {
+    }
+
+    void Retain() { ++ref_count_; }
+    void Release() { if (--ref_count_ == 0) delete this; }
+
+    T value;
+
+   private:
+    int ref_count_;
+    MOJO_DISALLOW_COPY_AND_ASSIGN(Holder);
+  };
+
+  Holder* holder_;
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_DATA_H_
diff --git a/mojo/public/cpp/bindings/lib/shared_ptr.h b/mojo/public/cpp/bindings/lib/shared_ptr.h
new file mode 100644
index 0000000..899e792
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/shared_ptr.h
@@ -0,0 +1,67 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_SHARED_PTR_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_PTR_H_
+
+#include "mojo/public/cpp/bindings/lib/shared_data.h"
+
+namespace mojo {
+namespace internal {
+
+// Used to manage a heap-allocated instance of P that can be shared via
+// reference counting. When the last reference is dropped, the instance is
+// deleted.
+template <typename P>
+class SharedPtr {
+ public:
+  SharedPtr() {}
+
+  explicit SharedPtr(P* ptr) {
+    impl_.mutable_value()->ptr = ptr;
+  }
+
+  // Default copy-constructor and assignment operator are OK.
+
+  P* get() {
+    return impl_.value().ptr;
+  }
+  const P* get() const {
+    return impl_.value().ptr;
+  }
+
+  void reset() {
+    impl_.reset();
+  }
+
+  P* operator->() { return get(); }
+  const P* operator->() const { return get(); }
+
+ private:
+  class Impl {
+   public:
+    ~Impl() {
+      if (ptr)
+        delete ptr;
+    }
+
+    Impl() : ptr(nullptr) {
+    }
+
+    Impl(P* ptr) : ptr(ptr) {
+    }
+
+    P* ptr;
+
+   private:
+    MOJO_DISALLOW_COPY_AND_ASSIGN(Impl);
+  };
+
+  SharedData<Impl> impl_;
+};
+
+}  // namespace mojo
+}  // namespace internal
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_PTR_H_
diff --git a/mojo/public/cpp/bindings/lib/string_serialization.cc b/mojo/public/cpp/bindings/lib/string_serialization.cc
new file mode 100644
index 0000000..a0544c0
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/string_serialization.cc
@@ -0,0 +1,39 @@
+// Copyright 2014 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/cpp/bindings/lib/string_serialization.h"
+
+#include <string.h>
+
+namespace mojo {
+
+size_t GetSerializedSize_(const String& input) {
+  if (!input)
+    return 0;
+  return internal::Align(sizeof(internal::String_Data) + input.size());
+}
+
+void Serialize_(const String& input, internal::Buffer* buf,
+                internal::String_Data** output) {
+  if (input) {
+    internal::String_Data* result =
+        internal::String_Data::New(input.size(), buf);
+    if (result)
+      memcpy(result->storage(), input.data(), input.size());
+    *output = result;
+  } else {
+    *output = nullptr;
+  }
+}
+
+void Deserialize_(internal::String_Data* input, String* output) {
+  if (input) {
+    String result(input->storage(), input->size());
+    result.Swap(output);
+  } else {
+    output->reset();
+  }
+}
+
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/string_serialization.h b/mojo/public/cpp/bindings/lib/string_serialization.h
new file mode 100644
index 0000000..bad2a0c
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/string_serialization.h
@@ -0,0 +1,20 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_STRING_SERIALIZATION_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_STRING_SERIALIZATION_H_
+
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/string.h"
+
+namespace mojo {
+
+size_t GetSerializedSize_(const String& input);
+void Serialize_(const String& input, internal::Buffer* buffer,
+                internal::String_Data** output);
+void Deserialize_(internal::String_Data* input, String* output);
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_STRING_SERIALIZATION_H_
diff --git a/mojo/public/cpp/bindings/lib/template_util.h b/mojo/public/cpp/bindings/lib/template_util.h
new file mode 100644
index 0000000..5991266
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/template_util.h
@@ -0,0 +1,89 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_TEMPLATE_UTIL_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_TEMPLATE_UTIL_H_
+
+namespace mojo {
+namespace internal {
+
+template<class T, T v>
+struct IntegralConstant {
+  static const T value = v;
+};
+
+template <class T, T v> const T IntegralConstant<T, v>::value;
+
+typedef IntegralConstant<bool, true> TrueType;
+typedef IntegralConstant<bool, false> FalseType;
+
+template <class T> struct IsConst : FalseType {};
+template <class T> struct IsConst<const T> : TrueType {};
+
+template<bool B, typename T = void>
+struct EnableIf {};
+
+template<typename T>
+struct EnableIf<true, T> { typedef T type; };
+
+// Types YesType and NoType are guaranteed such that sizeof(YesType) <
+// sizeof(NoType).
+typedef char YesType;
+
+struct NoType {
+  YesType dummy[2];
+};
+
+// A helper template to determine if given type is non-const move-only-type,
+// i.e. if a value of the given type should be passed via .Pass() in a
+// destructive way.
+template <typename T> struct IsMoveOnlyType {
+  template <typename U>
+  static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
+
+  template <typename U>
+  static NoType Test(...);
+
+  static const bool value = sizeof(Test<T>(0)) == sizeof(YesType) &&
+                            !IsConst<T>::value;
+};
+
+template <typename T>
+typename EnableIf<!IsMoveOnlyType<T>::value, T>::type& Forward(T& t) {
+  return t;
+}
+
+template <typename T>
+typename EnableIf<IsMoveOnlyType<T>::value, T>::type Forward(T& t) {
+  return t.Pass();
+}
+
+// This goop is a trick used to implement a template that can be used to
+// determine if a given class is the base class of another given class.
+template<typename, typename> struct IsSame {
+  static bool const value = false;
+};
+template<typename A> struct IsSame<A, A> {
+  static bool const value = true;
+};
+template<typename Base, typename Derived> struct IsBaseOf {
+ private:
+  // This class doesn't work correctly with forward declarations.
+  // Because sizeof cannot be applied to incomplete types, this line prevents us
+  // from passing in forward declarations.
+  typedef char (*EnsureTypesAreComplete)[sizeof(Base) + sizeof(Derived)];
+
+  static Derived* CreateDerived();
+  static char (&Check(Base*))[1];
+  static char (&Check(...))[2];
+
+ public:
+  static bool const value = sizeof Check(CreateDerived()) == 1 &&
+                            !IsSame<Base const, void const>::value;
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_TEMPLATE_UTIL_H_
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.cc b/mojo/public/cpp/bindings/lib/validation_errors.cc
new file mode 100644
index 0000000..47bcf02
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/validation_errors.cc
@@ -0,0 +1,92 @@
+// Copyright 2014 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/cpp/bindings/lib/validation_errors.h"
+
+#include "mojo/public/cpp/environment/logging.h"
+
+namespace mojo {
+namespace internal {
+namespace {
+
+ValidationErrorObserverForTesting* g_validation_error_observer = nullptr;
+SerializationWarningObserverForTesting* g_serialization_warning_observer =
+    nullptr;
+
+}  // namespace
+
+const char* ValidationErrorToString(ValidationError error) {
+  switch (error) {
+    case VALIDATION_ERROR_NONE:
+      return "VALIDATION_ERROR_NONE";
+    case VALIDATION_ERROR_MISALIGNED_OBJECT:
+      return "VALIDATION_ERROR_MISALIGNED_OBJECT";
+    case VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE:
+      return "VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE";
+    case VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER:
+      return "VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER";
+    case VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER:
+      return "VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER";
+    case VALIDATION_ERROR_ILLEGAL_HANDLE:
+      return "VALIDATION_ERROR_ILLEGAL_HANDLE";
+    case VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE:
+      return "VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE";
+    case VALIDATION_ERROR_ILLEGAL_POINTER:
+      return "VALIDATION_ERROR_ILLEGAL_POINTER";
+    case VALIDATION_ERROR_UNEXPECTED_NULL_POINTER:
+      return "VALIDATION_ERROR_UNEXPECTED_NULL_POINTER";
+    case VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION:
+      return "VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION";
+    case VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID:
+      return "VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID";
+  }
+
+  return "Unknown error";
+}
+
+void ReportValidationError(ValidationError error, const char* description) {
+  if (g_validation_error_observer) {
+    g_validation_error_observer->set_last_error(error);
+  } else if (description) {
+    MOJO_LOG(ERROR) << "Invalid message: " << ValidationErrorToString(error)
+                    << " (" << description << ")";
+  } else {
+    MOJO_LOG(ERROR) << "Invalid message: " << ValidationErrorToString(error);
+  }
+}
+
+ValidationErrorObserverForTesting::ValidationErrorObserverForTesting()
+    : last_error_(VALIDATION_ERROR_NONE) {
+  MOJO_DCHECK(!g_validation_error_observer);
+  g_validation_error_observer = this;
+}
+
+ValidationErrorObserverForTesting::~ValidationErrorObserverForTesting() {
+  MOJO_DCHECK(g_validation_error_observer == this);
+  g_validation_error_observer = nullptr;
+}
+
+bool ReportSerializationWarning(ValidationError error) {
+  if (g_serialization_warning_observer) {
+    g_serialization_warning_observer->set_last_warning(error);
+    return true;
+  }
+
+  return false;
+}
+
+SerializationWarningObserverForTesting::SerializationWarningObserverForTesting()
+    : last_warning_(VALIDATION_ERROR_NONE) {
+  MOJO_DCHECK(!g_serialization_warning_observer);
+  g_serialization_warning_observer = this;
+}
+
+SerializationWarningObserverForTesting::
+~SerializationWarningObserverForTesting() {
+  MOJO_DCHECK(g_serialization_warning_observer == this);
+  g_serialization_warning_observer = nullptr;
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.h b/mojo/public/cpp/bindings/lib/validation_errors.h
new file mode 100644
index 0000000..6152e60
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/validation_errors.h
@@ -0,0 +1,111 @@
+// Copyright 2014 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_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_
+
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+namespace internal {
+
+enum ValidationError {
+  // There is no validation error.
+  VALIDATION_ERROR_NONE,
+  // An object (struct or array) is not 8-byte aligned.
+  VALIDATION_ERROR_MISALIGNED_OBJECT,
+  // An object is not contained inside the message data, or it overlaps other
+  // objects.
+  VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE,
+  // A struct header doesn't make sense, for example:
+  // - |num_bytes| is smaller than the size of the oldest version that we
+  // support.
+  // - |num_fields| is smaller than the field number of the oldest version that
+  // we support.
+  // - |num_bytes| and |num_fields| don't match.
+  VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER,
+  // An array header doesn't make sense, for example:
+  // - |num_bytes| is smaller than the size of the header plus the size required
+  // to store |num_elements| elements.
+  // - For fixed-size arrays, |num_elements| is different than the specified
+  // size.
+  VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER,
+  // An encoded handle is illegal.
+  VALIDATION_ERROR_ILLEGAL_HANDLE,
+  // A non-nullable handle field is set to invalid handle.
+  VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
+  // An encoded pointer is illegal.
+  VALIDATION_ERROR_ILLEGAL_POINTER,
+  // A non-nullable pointer field is set to null.
+  VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
+  // |flags| in the message header is an invalid flag combination.
+  VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION,
+  // |flags| in the message header indicates that a request ID is required but
+  // there isn't one.
+  VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID,
+};
+
+const char* ValidationErrorToString(ValidationError error);
+
+void ReportValidationError(ValidationError error,
+                           const char* description = nullptr);
+
+// Only used by validation tests and when there is only one thread doing message
+// validation.
+class ValidationErrorObserverForTesting {
+ public:
+  ValidationErrorObserverForTesting();
+  ~ValidationErrorObserverForTesting();
+
+  ValidationError last_error() const { return last_error_; }
+  void set_last_error(ValidationError error) { last_error_ = error; }
+
+ private:
+  ValidationError last_error_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(ValidationErrorObserverForTesting);
+};
+
+// Used only by MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING. Don't use it directly.
+//
+// The function returns true if the error is recorded (by a
+// SerializationWarningObserverForTesting object), false otherwise.
+bool ReportSerializationWarning(ValidationError error);
+
+// Only used by serialization tests and when there is only one thread doing
+// message serialization.
+class SerializationWarningObserverForTesting {
+ public:
+  SerializationWarningObserverForTesting();
+  ~SerializationWarningObserverForTesting();
+
+  ValidationError last_warning() const { return last_warning_; }
+  void set_last_warning(ValidationError error) { last_warning_ = error; }
+
+ private:
+  ValidationError last_warning_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(SerializationWarningObserverForTesting);
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+// In debug build, logs a serialization warning if |condition| evaluates to
+// true:
+//   - if there is a SerializationWarningObserverForTesting object alive,
+//     records |error| in it;
+//   - otherwise, logs a fatal-level message.
+// |error| is the validation error that will be triggered by the receiver
+// of the serialzation result.
+//
+// In non-debug build, does nothing (not even compiling |condition|).
+#define MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( \
+    condition, error, description) \
+  MOJO_DLOG_IF(FATAL, (condition) && !ReportSerializationWarning(error)) \
+      << "The outgoing message will trigger " \
+      << ValidationErrorToString(error) << " at the receiving side (" \
+      << description << ").";
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_
diff --git a/mojo/public/cpp/bindings/message.h b/mojo/public/cpp/bindings/message.h
new file mode 100644
index 0000000..62801f1
--- /dev/null
+++ b/mojo/public/cpp/bindings/message.h
@@ -0,0 +1,122 @@
+// Copyright 2014 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_CPP_BINDINGS_MESSAGE_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_H_
+
+#include <vector>
+
+#include "mojo/public/cpp/bindings/lib/message_internal.h"
+#include "mojo/public/cpp/environment/logging.h"
+
+namespace mojo {
+
+// Message is a holder for the data and handles to be sent over a MessagePipe.
+// Message owns its data and handles, but a consumer of Message is free to
+// mutate the data and handles. The message's data is comprised of a header
+// followed by payload.
+class Message {
+ public:
+  Message();
+  ~Message();
+
+  // These may only be called on a newly created Message object.
+  void AllocUninitializedData(uint32_t num_bytes);
+  void AdoptData(uint32_t num_bytes, internal::MessageData* data);
+
+  // Swaps data and handles between this Message and another.
+  void Swap(Message* other);
+
+  uint32_t data_num_bytes() const { return data_num_bytes_; }
+
+  // Access the raw bytes of the message.
+  const uint8_t* data() const { return
+    reinterpret_cast<const uint8_t*>(data_);
+  }
+  uint8_t* mutable_data() { return reinterpret_cast<uint8_t*>(data_); }
+
+  // Access the header.
+  const internal::MessageHeader* header() const { return &data_->header; }
+
+  uint32_t name() const { return data_->header.name; }
+  bool has_flag(uint32_t flag) const { return !!(data_->header.flags & flag); }
+
+  // Access the request_id field (if present).
+  bool has_request_id() const { return data_->header.num_fields >= 3; }
+  uint64_t request_id() const {
+    MOJO_DCHECK(has_request_id());
+    return static_cast<const internal::MessageHeaderWithRequestID*>(
+        &data_->header)->request_id;
+  }
+  void set_request_id(uint64_t request_id) {
+    MOJO_DCHECK(has_request_id());
+    static_cast<internal::MessageHeaderWithRequestID*>(&data_->header)->
+        request_id = request_id;
+  }
+
+  // Access the payload.
+  const uint8_t* payload() const {
+    return reinterpret_cast<const uint8_t*>(data_) + data_->header.num_bytes;
+  }
+  uint8_t* mutable_payload() {
+    return reinterpret_cast<uint8_t*>(data_) + data_->header.num_bytes;
+  }
+  uint32_t payload_num_bytes() const {
+    MOJO_DCHECK(data_num_bytes_ >= data_->header.num_bytes);
+    return data_num_bytes_ - data_->header.num_bytes;
+  }
+
+  // Access the handles.
+  const std::vector<Handle>* handles() const { return &handles_; }
+  std::vector<Handle>* mutable_handles() { return &handles_; }
+
+ private:
+  uint32_t data_num_bytes_;
+  internal::MessageData* data_;  // Heap-allocated using malloc.
+  std::vector<Handle> handles_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(Message);
+};
+
+class MessageReceiver {
+ public:
+  virtual ~MessageReceiver() {}
+
+  // The receiver may mutate the given message.  Returns true if the message
+  // was accepted and false otherwise, indicating that the message was invalid
+  // or malformed.
+  virtual bool Accept(Message* message) MOJO_WARN_UNUSED_RESULT = 0;
+};
+
+class MessageReceiverWithResponder : public MessageReceiver {
+ public:
+  virtual ~MessageReceiverWithResponder() {}
+
+  // A variant on Accept that registers a MessageReceiver (known as the
+  // responder) to handle the response message generated from the given
+  // message. The responder's Accept method may be called during
+  // AcceptWithResponder or some time after its return.
+  //
+  // NOTE: Upon returning true, AcceptWithResponder assumes ownership of
+  // |responder| and will delete it after calling |responder->Accept| or upon
+  // its own destruction.
+  //
+  virtual bool AcceptWithResponder(
+      Message* message, MessageReceiver* responder) MOJO_WARN_UNUSED_RESULT = 0;
+};
+
+// Read a single message from the pipe and dispatch to the given receiver.  The
+// receiver may be null, in which case the message is simply discarded.
+// Returns MOJO_RESULT_SHOULD_WAIT if the caller should wait on the handle to
+// become readable. Returns MOJO_RESULT_OK if a message was dispatched and
+// otherwise returns an error code if something went wrong.
+//
+// NOTE: The message hasn't been validated and may be malformed!
+MojoResult ReadAndDispatchMessage(MessagePipeHandle handle,
+                                  MessageReceiver* receiver,
+                                  bool* receiver_result);
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_H_
diff --git a/mojo/public/cpp/bindings/message_filter.h b/mojo/public/cpp/bindings/message_filter.h
new file mode 100644
index 0000000..f4faafb
--- /dev/null
+++ b/mojo/public/cpp/bindings/message_filter.h
@@ -0,0 +1,39 @@
+// Copyright 2014 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_CPP_BINDINGS_MESSAGE_FILTER_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_FILTER_H_
+
+#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+
+// This class is the base class for message filters. Subclasses should
+// implement the pure virtual method Accept() inherited from MessageReceiver to
+// process messages and/or forward them to |sink_|.
+class MessageFilter : public MessageReceiver {
+ public:
+  // Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while
+  // this object is alive.
+  explicit MessageFilter(MessageReceiver* sink = nullptr);
+  virtual ~MessageFilter();
+
+  void set_sink(MessageReceiver* sink) { sink_ = sink; }
+
+ protected:
+  MessageReceiver* sink_;
+};
+
+// A trivial filter that simply forwards every message it receives to |sink_|.
+class PassThroughFilter : public MessageFilter {
+ public:
+  explicit PassThroughFilter(MessageReceiver* sink = nullptr);
+
+  virtual bool Accept(Message* message) override;
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_FILTER_H_
diff --git a/mojo/public/cpp/bindings/no_interface.h b/mojo/public/cpp/bindings/no_interface.h
new file mode 100644
index 0000000..07587bd
--- /dev/null
+++ b/mojo/public/cpp/bindings/no_interface.h
@@ -0,0 +1,54 @@
+// Copyright 2014 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_CPP_BINDINGS_NO_INTERFACE_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_NO_INTERFACE_H_
+
+#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/bindings/message_filter.h"
+#include "mojo/public/cpp/system/core.h"
+
+namespace mojo {
+
+// NoInterface is for use in cases when a non-existent or empty interface is
+// needed (e.g., when the Mojom "Peer" attribute is not present).
+
+class NoInterfaceProxy;
+class NoInterfaceStub;
+
+class NoInterface {
+ public:
+  static const char* Name_;
+  typedef NoInterfaceProxy Proxy_;
+  typedef NoInterfaceStub Stub_;
+  typedef PassThroughFilter RequestValidator_;
+  typedef PassThroughFilter ResponseValidator_;
+  typedef NoInterface Client;
+  virtual ~NoInterface() {}
+};
+
+class NoInterfaceProxy : public NoInterface {
+ public:
+  explicit NoInterfaceProxy(MessageReceiver* receiver) {}
+};
+
+class NoInterfaceStub : public MessageReceiverWithResponder {
+ public:
+  NoInterfaceStub() {}
+  void set_sink(NoInterface* sink) {}
+  NoInterface* sink() { return nullptr; }
+  virtual bool Accept(Message* message) override;
+  virtual bool AcceptWithResponder(Message* message,
+                                   MessageReceiver* responder) override;
+};
+
+
+// AnyInterface is for use in cases where any interface would do (e.g., see the
+// Shell::Connect method).
+
+typedef NoInterface AnyInterface;
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_NO_INTERFACE_H_
diff --git a/mojo/public/cpp/bindings/string.h b/mojo/public/cpp/bindings/string.h
new file mode 100644
index 0000000..cd7db26
--- /dev/null
+++ b/mojo/public/cpp/bindings/string.h
@@ -0,0 +1,150 @@
+// Copyright 2014 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_CPP_BINDINGS_STRING_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_STRING_H_
+
+#include <string>
+
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/type_converter.h"
+#include "mojo/public/cpp/environment/logging.h"
+
+namespace mojo {
+
+class String {
+ public:
+  typedef internal::String_Data Data_;
+
+  String() : is_null_(true) {}
+  String(const std::string& str) : value_(str), is_null_(false) {}
+  String(const char* chars) : is_null_(!chars) {
+    if (chars)
+      value_ = chars;
+  }
+  String(const char* chars, size_t num_chars)
+      : value_(chars, num_chars),
+        is_null_(false) {
+  }
+  template <size_t N>
+  String(const char chars[N]) : value_(chars, N-1), is_null_(false) {}
+
+  template <typename U>
+  static String From(const U& other) {
+    return TypeConverter<String, U>::Convert(other);
+  }
+
+  template <typename U>
+  U To() const {
+    return TypeConverter<U, String>::Convert(*this);
+  }
+
+  String& operator=(const std::string& str) {
+    value_ = str;
+    is_null_ = false;
+    return *this;
+  }
+  String& operator=(const char* chars) {
+    is_null_ = !chars;
+    if (chars) {
+      value_ = chars;
+    } else {
+      value_.clear();
+    }
+    return *this;
+  }
+
+  void reset() {
+    value_.clear();
+    is_null_ = true;
+  }
+
+  bool is_null() const { return is_null_; }
+
+  size_t size() const { return value_.size(); }
+
+  const char* data() const { return value_.data(); }
+
+  const char& at(size_t offset) const { return value_.at(offset); }
+  const char& operator[](size_t offset) const { return value_[offset]; }
+
+  const std::string& get() const { return value_; }
+  operator const std::string&() const { return value_; }
+
+  void Swap(String* other) {
+    std::swap(is_null_, other->is_null_);
+    value_.swap(other->value_);
+  }
+
+  void Swap(std::string* other) {
+    is_null_ = false;
+    value_.swap(*other);
+  }
+
+ private:
+  typedef std::string String::*Testable;
+
+ public:
+  operator Testable() const { return is_null_ ? 0 : &String::value_; }
+
+ private:
+  std::string value_;
+  bool is_null_;
+};
+
+inline bool operator==(const String& a, const String& b) {
+  return a.is_null() == b.is_null() && a.get() == b.get();
+}
+inline bool operator==(const char* a, const String& b) {
+  return !b.is_null() && a == b.get();
+}
+inline bool operator==(const String& a, const char* b) {
+  return !a.is_null() && a.get() == b;
+}
+inline bool operator!=(const String& a, const String& b) { return !(a == b); }
+inline bool operator!=(const char* a, const String& b) { return !(a == b); }
+inline bool operator!=(const String& a, const char* b) { return !(a == b); }
+
+inline std::ostream& operator<<(std::ostream& out, const String& s) {
+  return out << s.get();
+}
+
+// TODO(darin): Add similar variants of operator<,<=,>,>=
+
+template <>
+struct TypeConverter<String, std::string> {
+  static String Convert(const std::string& input) { return String(input); }
+};
+
+template <>
+struct TypeConverter<std::string, String> {
+  static std::string Convert(const String& input) { return input; }
+};
+
+template <size_t N>
+struct TypeConverter<String, char[N]> {
+  static String Convert(const char input[N]) {
+    MOJO_DCHECK(input);
+    return String(input, N-1);
+  }
+};
+
+// Appease MSVC.
+template <size_t N>
+struct TypeConverter<String, const char[N]> {
+  static String Convert(const char input[N]) {
+    MOJO_DCHECK(input);
+    return String(input, N-1);
+  }
+};
+
+template <>
+struct TypeConverter<String, const char*> {
+  // |input| may be null, in which case a null String will be returned.
+  static String Convert(const char* input) { return String(input); }
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_STRING_H_
diff --git a/mojo/public/cpp/bindings/struct_ptr.h b/mojo/public/cpp/bindings/struct_ptr.h
new file mode 100644
index 0000000..46729dd
--- /dev/null
+++ b/mojo/public/cpp/bindings/struct_ptr.h
@@ -0,0 +1,167 @@
+// Copyright 2014 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_CPP_BINDINGS_STRUCT_PTR_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
+
+#include <new>
+
+#include "mojo/public/cpp/environment/logging.h"
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+namespace internal {
+
+template <typename Struct>
+class StructHelper {
+ public:
+  template <typename Ptr>
+  static void Initialize(Ptr* ptr) { ptr->Initialize(); }
+};
+
+}  // namespace internal
+
+template <typename Struct>
+class StructPtr {
+  MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(StructPtr, RValue);
+ public:
+  typedef typename Struct::Data_ Data_;
+
+  StructPtr() : ptr_(nullptr) {}
+  ~StructPtr() {
+    delete ptr_;
+  }
+
+  StructPtr(RValue other) : ptr_(nullptr) { Take(other.object); }
+  StructPtr& operator=(RValue other) {
+    Take(other.object);
+    return *this;
+  }
+
+  template <typename U>
+  U To() const {
+    return TypeConverter<U, StructPtr>::Convert(*this);
+  }
+
+  void reset() {
+    if (ptr_) {
+      delete ptr_;
+      ptr_ = nullptr;
+    }
+  }
+
+  bool is_null() const { return ptr_ == nullptr; }
+
+  Struct& operator*() const {
+    MOJO_DCHECK(ptr_);
+    return *ptr_;
+  }
+  Struct* operator->() const {
+    MOJO_DCHECK(ptr_);
+    return ptr_;
+  }
+  Struct* get() const { return ptr_; }
+
+  void Swap(StructPtr* other) {
+    std::swap(ptr_, other->ptr_);
+  }
+
+  // Please note that calling this method will fail compilation if the value
+  // type |Struct| doesn't have a Clone() method defined (which usually means
+  // that it contains Mojo handles).
+  StructPtr Clone() const {
+    return is_null() ? StructPtr() : ptr_->Clone();
+  }
+
+ private:
+  typedef Struct* StructPtr::*Testable;
+
+ public:
+  operator Testable() const { return ptr_ ? &StructPtr::ptr_ : 0; }
+
+ private:
+  friend class internal::StructHelper<Struct>;
+  void Initialize() {
+    MOJO_DCHECK(!ptr_);
+    ptr_ = new Struct();
+  }
+
+  void Take(StructPtr* other) {
+    reset();
+    Swap(other);
+  }
+
+  Struct* ptr_;
+};
+
+// Designed to be used when Struct is small and copyable.
+template <typename Struct>
+class InlinedStructPtr {
+  MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InlinedStructPtr, RValue);
+ public:
+  typedef typename Struct::Data_ Data_;
+
+  InlinedStructPtr() : is_null_(true) {}
+  ~InlinedStructPtr() {}
+
+  InlinedStructPtr(RValue other) : is_null_(true) { Take(other.object); }
+  InlinedStructPtr& operator=(RValue other) {
+    Take(other.object);
+    return *this;
+  }
+
+  template <typename U>
+  U To() const {
+    return TypeConverter<U, InlinedStructPtr>::Convert(*this);
+  }
+
+  void reset() {
+    is_null_ = true;
+    value_.~Struct();
+    new (&value_) Struct();
+  }
+
+  bool is_null() const { return is_null_; }
+
+  Struct& operator*() const {
+    MOJO_DCHECK(!is_null_);
+    return value_;
+  }
+  Struct* operator->() const {
+    MOJO_DCHECK(!is_null_);
+    return &value_;
+  }
+  Struct* get() const { return &value_; }
+
+  void Swap(InlinedStructPtr* other) {
+    std::swap(value_, other->value_);
+    std::swap(is_null_, other->is_null_);
+  }
+
+  InlinedStructPtr Clone() const {
+    return is_null() ? InlinedStructPtr() : value_.Clone();
+  }
+
+ private:
+  typedef Struct InlinedStructPtr::*Testable;
+
+ public:
+  operator Testable() const { return is_null_ ? 0 : &InlinedStructPtr::value_; }
+
+ private:
+  friend class internal::StructHelper<Struct>;
+  void Initialize() { is_null_ = false; }
+
+  void Take(InlinedStructPtr* other) {
+    reset();
+    Swap(other);
+  }
+
+  mutable Struct value_;
+  bool is_null_;
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
diff --git a/mojo/public/cpp/bindings/tests/BUILD.gn b/mojo/public/cpp/bindings/tests/BUILD.gn
new file mode 100644
index 0000000..6a4b2df
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/BUILD.gn
@@ -0,0 +1,46 @@
+# Copyright 2014 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.
+
+# GYP version: mojo/mojo_public_tests.gypi:mojo_public_bindings_unittests
+test("mojo_public_bindings_unittests") {
+  sources = [
+    "array_unittest.cc",
+    "bounds_checker_unittest.cc",
+    "buffer_unittest.cc",
+    "connector_unittest.cc",
+    "handle_passing_unittest.cc",
+    "interface_ptr_unittest.cc",
+    "request_response_unittest.cc",
+    "router_unittest.cc",
+    "sample_service_unittest.cc",
+    "serialization_warning_unittest.cc",
+    "string_unittest.cc",
+    "struct_unittest.cc",
+    "type_conversion_unittest.cc",
+    "validation_unittest.cc",
+  ]
+
+  deps = [
+    "//mojo/common/test:run_all_unittests",
+    "//mojo/public/cpp/bindings",
+    "//mojo/public/cpp/environment:standalone",
+    "//mojo/public/cpp/system",
+    "//mojo/public/cpp/test_support:test_utils",
+    "//mojo/public/cpp/utility",
+    "//mojo/public/interfaces/bindings/tests:test_interfaces",
+    "//testing/gtest",
+    ":mojo_public_bindings_test_utils",
+  ]
+}
+
+source_set("mojo_public_bindings_test_utils") {
+  sources = [
+    "validation_test_input_parser.cc",
+    "validation_test_input_parser.h",
+  ]
+
+  deps = [
+    "//mojo/public/c/system",
+  ]
+}
diff --git a/mojo/public/cpp/bindings/tests/DEPS b/mojo/public/cpp/bindings/tests/DEPS
new file mode 100644
index 0000000..b99d520
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+mojo/public/cpp/environment",
+  "+mojo/public/interfaces/bindings/tests",
+]
diff --git a/mojo/public/cpp/bindings/tests/array_unittest.cc b/mojo/public/cpp/bindings/tests/array_unittest.cc
new file mode 100644
index 0000000..82a705f
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/array_unittest.cc
@@ -0,0 +1,486 @@
+// Copyright 2014 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/cpp/bindings/array.h"
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/lib/array_serialization.h"
+#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+namespace {
+
+using mojo::internal::Array_Data;
+using mojo::internal::ArrayValidateParams;
+using mojo::internal::FixedBuffer;
+using mojo::internal::NoValidateParams;
+using mojo::internal::String_Data;
+
+class CopyableType {
+ public:
+  CopyableType() : copied_(false), ptr_(this) { num_instances_++; }
+  CopyableType(const CopyableType& other) : copied_(true), ptr_(other.ptr()) {
+    num_instances_++;
+  }
+  CopyableType& operator=(const CopyableType& other) {
+    copied_ = true;
+    ptr_ = other.ptr();
+    return *this;
+  }
+  ~CopyableType() { num_instances_--; }
+
+  bool copied() const { return copied_; }
+  static size_t num_instances() { return num_instances_; }
+  CopyableType* ptr() const { return ptr_; }
+  void ResetCopied() { copied_ = false; }
+
+ private:
+  bool copied_;
+  static size_t num_instances_;
+  CopyableType* ptr_;
+};
+
+size_t CopyableType::num_instances_ = 0;
+
+class MoveOnlyType {
+  MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(MoveOnlyType, RValue)
+ public:
+  typedef MoveOnlyType Data_;
+  MoveOnlyType() : moved_(false), ptr_(this) { num_instances_++; }
+  MoveOnlyType(RValue other) : moved_(true), ptr_(other.object->ptr()) {
+    num_instances_++;
+  }
+  MoveOnlyType& operator=(RValue other) {
+    moved_ = true;
+    ptr_ = other.object->ptr();
+    return *this;
+  }
+  ~MoveOnlyType() { num_instances_--; }
+
+  bool moved() const { return moved_; }
+  static size_t num_instances() { return num_instances_; }
+  MoveOnlyType* ptr() const { return ptr_; }
+  void ResetMoved() { moved_ = false; }
+
+ private:
+  bool moved_;
+  static size_t num_instances_;
+  MoveOnlyType* ptr_;
+};
+
+size_t MoveOnlyType::num_instances_ = 0;
+
+class ArrayTest : public testing::Test {
+ public:
+  virtual ~ArrayTest() {}
+
+ private:
+  Environment env_;
+};
+
+// Tests that basic Array operations work.
+TEST_F(ArrayTest, Basic) {
+  Array<char> array(8);
+  for (size_t i = 0; i < array.size(); ++i) {
+    char val = static_cast<char>(i*2);
+    array[i] = val;
+    EXPECT_EQ(val, array.at(i));
+  }
+}
+
+// Tests that basic Array<bool> operations work.
+TEST_F(ArrayTest, Bool) {
+  Array<bool> array(64);
+  for (size_t i = 0; i < array.size(); ++i) {
+    bool val = i % 3 == 0;
+    array[i] = val;
+    EXPECT_EQ(val, array.at(i));
+  }
+}
+
+// Tests that Array<ScopedMessagePipeHandle> supports transferring handles.
+TEST_F(ArrayTest, Handle) {
+  MessagePipe pipe;
+  Array<ScopedMessagePipeHandle> handles(2);
+  handles[0] = pipe.handle0.Pass();
+  handles[1].reset(pipe.handle1.release());
+
+  EXPECT_FALSE(pipe.handle0.is_valid());
+  EXPECT_FALSE(pipe.handle1.is_valid());
+
+  Array<ScopedMessagePipeHandle> handles2 = handles.Pass();
+  EXPECT_TRUE(handles2[0].is_valid());
+  EXPECT_TRUE(handles2[1].is_valid());
+
+  ScopedMessagePipeHandle pipe_handle = handles2[0].Pass();
+  EXPECT_TRUE(pipe_handle.is_valid());
+  EXPECT_FALSE(handles2[0].is_valid());
+}
+
+// Tests that Array<ScopedMessagePipeHandle> supports closing handles.
+TEST_F(ArrayTest, HandlesAreClosed) {
+  MessagePipe pipe;
+  MojoHandle pipe0_value = pipe.handle0.get().value();
+  MojoHandle pipe1_value = pipe.handle0.get().value();
+
+  {
+    Array<ScopedMessagePipeHandle> handles(2);
+    handles[0] = pipe.handle0.Pass();
+    handles[1].reset(pipe.handle0.release());
+  }
+
+  // We expect the pipes to have been closed.
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe0_value));
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe1_value));
+}
+
+TEST_F(ArrayTest, Clone) {
+  {
+    // Test POD.
+    Array<int32_t> array(3);
+    for (size_t i = 0; i < array.size(); ++i)
+      array[i] = static_cast<int32_t>(i);
+
+    Array<int32_t> clone_array = array.Clone();
+    EXPECT_EQ(array.size(), clone_array.size());
+    for (size_t i = 0; i < array.size(); ++i)
+      EXPECT_EQ(array[i], clone_array[i]);
+  }
+
+  {
+    // Test copyable object.
+    Array<String> array(2);
+    array[0] = "hello";
+    array[1] = "world";
+
+    Array<String> clone_array = array.Clone();
+    EXPECT_EQ(array.size(), clone_array.size());
+    for (size_t i = 0; i < array.size(); ++i)
+      EXPECT_EQ(array[i], clone_array[i]);
+  }
+
+  {
+    // Test struct.
+    Array<RectPtr> array(2);
+    array[1] = Rect::New();
+    array[1]->x = 1;
+    array[1]->y = 2;
+    array[1]->width = 3;
+    array[1]->height = 4;
+
+    Array<RectPtr> clone_array = array.Clone();
+    EXPECT_EQ(array.size(), clone_array.size());
+    EXPECT_TRUE(clone_array[0].is_null());
+    EXPECT_EQ(array[1]->x, clone_array[1]->x);
+    EXPECT_EQ(array[1]->y, clone_array[1]->y);
+    EXPECT_EQ(array[1]->width, clone_array[1]->width);
+    EXPECT_EQ(array[1]->height, clone_array[1]->height);
+  }
+
+  {
+    // Test array of array.
+    Array<Array<int8_t>> array(2);
+    array[1] = Array<int8_t>(2);
+    array[1][0] = 0;
+    array[1][1] = 1;
+
+    Array<Array<int8_t>> clone_array = array.Clone();
+    EXPECT_EQ(array.size(), clone_array.size());
+    EXPECT_TRUE(clone_array[0].is_null());
+    EXPECT_EQ(array[1].size(), clone_array[1].size());
+    EXPECT_EQ(array[1][0], clone_array[1][0]);
+    EXPECT_EQ(array[1][1], clone_array[1][1]);
+  }
+
+  {
+    // Test that array of handles still works although Clone() is not available.
+    Array<ScopedMessagePipeHandle> array(10);
+    EXPECT_FALSE(array[0].is_valid());
+  }
+}
+
+TEST_F(ArrayTest, Serialization_ArrayOfPOD) {
+  Array<int32_t> array(4);
+  for (size_t i = 0; i < array.size(); ++i)
+    array[i] = static_cast<int32_t>(i);
+
+  size_t size = GetSerializedSize_(array);
+  EXPECT_EQ(8U + 4*4U, size);
+
+  FixedBuffer buf(size);
+  Array_Data<int32_t>* data;
+  SerializeArray_<ArrayValidateParams<0, false, NoValidateParams>>(
+      array.Pass(), &buf, &data);
+
+  Array<int32_t> array2;
+  Deserialize_(data, &array2);
+
+  EXPECT_EQ(4U, array2.size());
+  for (size_t i = 0; i < array2.size(); ++i)
+    EXPECT_EQ(static_cast<int32_t>(i), array2[i]);
+}
+
+TEST_F(ArrayTest, Serialization_ArrayOfArrayOfPOD) {
+  Array<Array<int32_t>> array(2);
+  for (size_t j = 0; j < array.size(); ++j) {
+    Array<int32_t> inner(4);
+    for (size_t i = 0; i < inner.size(); ++i)
+      inner[i] = static_cast<int32_t>(i + (j * 10));
+    array[j] = inner.Pass();
+  }
+
+  size_t size = GetSerializedSize_(array);
+  EXPECT_EQ(8U + 2*8U + 2*(8U + 4*4U), size);
+
+  FixedBuffer buf(size);
+  Array_Data<Array_Data<int32_t>*>* data;
+  SerializeArray_<ArrayValidateParams<0, false,
+                  ArrayValidateParams<0, false,
+                  NoValidateParams>>>(
+      array.Pass(), &buf, &data);
+
+  Array<Array<int32_t>> array2;
+  Deserialize_(data, &array2);
+
+  EXPECT_EQ(2U, array2.size());
+  for (size_t j = 0; j < array2.size(); ++j) {
+    const Array<int32_t>& inner = array2[j];
+    EXPECT_EQ(4U, inner.size());
+    for (size_t i = 0; i < inner.size(); ++i)
+      EXPECT_EQ(static_cast<int32_t>(i + (j * 10)), inner[i]);
+  }
+}
+
+TEST_F(ArrayTest, Serialization_ArrayOfBool) {
+  Array<bool> array(10);
+  for (size_t i = 0; i < array.size(); ++i)
+    array[i] = i % 2 ? true : false;
+
+  size_t size = GetSerializedSize_(array);
+  EXPECT_EQ(8U + 8U, size);
+
+  FixedBuffer buf(size);
+  Array_Data<bool>* data;
+  SerializeArray_<ArrayValidateParams<0, false, NoValidateParams>>(
+      array.Pass(), &buf, &data);
+
+  Array<bool> array2;
+  Deserialize_(data, &array2);
+
+  EXPECT_EQ(10U, array2.size());
+  for (size_t i = 0; i < array2.size(); ++i)
+    EXPECT_EQ(i % 2 ? true : false, array2[i]);
+}
+
+TEST_F(ArrayTest, Serialization_ArrayOfString) {
+  Array<String> array(10);
+  for (size_t i = 0; i < array.size(); ++i) {
+    char c = 'A' + static_cast<char>(i);
+    array[i] = String(&c, 1);
+  }
+
+  size_t size = GetSerializedSize_(array);
+  EXPECT_EQ(8U +     // array header
+            10*8U +  // array payload (10 pointers)
+            10*(8U +  // string header
+                8U),  // string length of 1 padded to 8
+            size);
+
+  FixedBuffer buf(size);
+  Array_Data<String_Data*>* data;
+  SerializeArray_<ArrayValidateParams<0, false,
+                  ArrayValidateParams<0, false,
+                  NoValidateParams>>>(
+      array.Pass(), &buf, &data);
+
+  Array<String> array2;
+  Deserialize_(data, &array2);
+
+  EXPECT_EQ(10U, array2.size());
+  for (size_t i = 0; i < array2.size(); ++i) {
+    char c = 'A' + static_cast<char>(i);
+    EXPECT_EQ(String(&c, 1), array2[i]);
+  }
+}
+
+TEST_F(ArrayTest, Resize_Copyable) {
+  ASSERT_EQ(0u, CopyableType::num_instances());
+  mojo::Array<CopyableType> array(3);
+  std::vector<CopyableType*> value_ptrs;
+  value_ptrs.push_back(array[0].ptr());
+  value_ptrs.push_back(array[1].ptr());
+
+  for (size_t i = 0; i < array.size(); i++)
+    array[i].ResetCopied();
+
+  array.resize(2);
+  ASSERT_EQ(2u, array.size());
+  EXPECT_EQ(array.size(), CopyableType::num_instances());
+  for (size_t i = 0; i < array.size(); i++) {
+    EXPECT_FALSE(array[i].copied());
+    EXPECT_EQ(value_ptrs[i], array[i].ptr());
+  }
+
+  array.resize(3);
+  array[2].ResetCopied();
+  ASSERT_EQ(3u, array.size());
+  EXPECT_EQ(array.size(), CopyableType::num_instances());
+  for (size_t i = 0; i < array.size(); i++)
+    EXPECT_FALSE(array[i].copied());
+  value_ptrs.push_back(array[2].ptr());
+
+  size_t capacity = array.storage().capacity();
+  array.resize(capacity);
+  ASSERT_EQ(capacity, array.size());
+  EXPECT_EQ(array.size(), CopyableType::num_instances());
+  for (size_t i = 0; i < 3; i++)
+    EXPECT_FALSE(array[i].copied());
+  for (size_t i = 3; i < array.size(); i++) {
+    array[i].ResetCopied();
+    value_ptrs.push_back(array[i].ptr());
+  }
+
+  array.resize(capacity + 2);
+  ASSERT_EQ(capacity + 2, array.size());
+  EXPECT_EQ(array.size(), CopyableType::num_instances());
+  for (size_t i = 0; i < capacity; i++) {
+    EXPECT_TRUE(array[i].copied());
+    EXPECT_EQ(value_ptrs[i], array[i].ptr());
+  }
+  array.reset();
+  EXPECT_EQ(0u, CopyableType::num_instances());
+  EXPECT_FALSE(array);
+  array.resize(0);
+  EXPECT_EQ(0u, CopyableType::num_instances());
+  EXPECT_TRUE(array);
+}
+
+TEST_F(ArrayTest, Resize_MoveOnly) {
+  ASSERT_EQ(0u, MoveOnlyType::num_instances());
+  mojo::Array<MoveOnlyType> array(3);
+  std::vector<MoveOnlyType*> value_ptrs;
+  value_ptrs.push_back(array[0].ptr());
+  value_ptrs.push_back(array[1].ptr());
+
+  for (size_t i = 0; i < array.size(); i++)
+    EXPECT_FALSE(array[i].moved());
+
+  array.resize(2);
+  ASSERT_EQ(2u, array.size());
+  EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
+  for (size_t i = 0; i < array.size(); i++) {
+    EXPECT_FALSE(array[i].moved());
+    EXPECT_EQ(value_ptrs[i], array[i].ptr());
+  }
+
+  array.resize(3);
+  ASSERT_EQ(3u, array.size());
+  EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
+  for (size_t i = 0; i < array.size(); i++)
+    EXPECT_FALSE(array[i].moved());
+  value_ptrs.push_back(array[2].ptr());
+
+  size_t capacity = array.storage().capacity();
+  array.resize(capacity);
+  ASSERT_EQ(capacity, array.size());
+  EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
+  for (size_t i = 0; i < array.size(); i++)
+    EXPECT_FALSE(array[i].moved());
+  for (size_t i = 3; i < array.size(); i++)
+    value_ptrs.push_back(array[i].ptr());
+
+  array.resize(capacity + 2);
+  ASSERT_EQ(capacity + 2, array.size());
+  EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
+  for (size_t i = 0; i < capacity; i++) {
+    EXPECT_TRUE(array[i].moved());
+    EXPECT_EQ(value_ptrs[i], array[i].ptr());
+  }
+  for (size_t i = capacity; i < array.size(); i++)
+    EXPECT_FALSE(array[i].moved());
+
+  array.reset();
+  EXPECT_EQ(0u, MoveOnlyType::num_instances());
+  EXPECT_FALSE(array);
+  array.resize(0);
+  EXPECT_EQ(0u, MoveOnlyType::num_instances());
+  EXPECT_TRUE(array);
+}
+
+TEST_F(ArrayTest, PushBack_Copyable) {
+  ASSERT_EQ(0u, CopyableType::num_instances());
+  mojo::Array<CopyableType> array(2);
+  array.reset();
+  std::vector<CopyableType*> value_ptrs;
+  size_t capacity = array.storage().capacity();
+  for (size_t i = 0; i < capacity; i++) {
+    CopyableType value;
+    value_ptrs.push_back(value.ptr());
+    array.push_back(value);
+    ASSERT_EQ(i + 1, array.size());
+    ASSERT_EQ(i + 1, value_ptrs.size());
+    EXPECT_EQ(array.size() + 1, CopyableType::num_instances());
+    EXPECT_TRUE(array[i].copied());
+    EXPECT_EQ(value_ptrs[i], array[i].ptr());
+    array[i].ResetCopied();
+    EXPECT_TRUE(array);
+  }
+  {
+    CopyableType value;
+    value_ptrs.push_back(value.ptr());
+    array.push_back(value);
+    EXPECT_EQ(array.size() + 1, CopyableType::num_instances());
+  }
+  ASSERT_EQ(capacity + 1, array.size());
+  EXPECT_EQ(array.size(), CopyableType::num_instances());
+
+  for (size_t i = 0; i < array.size(); i++) {
+    EXPECT_TRUE(array[i].copied());
+    EXPECT_EQ(value_ptrs[i], array[i].ptr());
+  }
+  array.reset();
+  EXPECT_EQ(0u, CopyableType::num_instances());
+}
+
+TEST_F(ArrayTest, PushBack_MoveOnly) {
+  ASSERT_EQ(0u, MoveOnlyType::num_instances());
+  mojo::Array<MoveOnlyType> array(2);
+  array.reset();
+  std::vector<MoveOnlyType*> value_ptrs;
+  size_t capacity = array.storage().capacity();
+  for (size_t i = 0; i < capacity; i++) {
+    MoveOnlyType value;
+    value_ptrs.push_back(value.ptr());
+    array.push_back(value.Pass());
+    ASSERT_EQ(i + 1, array.size());
+    ASSERT_EQ(i + 1, value_ptrs.size());
+    EXPECT_EQ(array.size() + 1, MoveOnlyType::num_instances());
+    EXPECT_TRUE(array[i].moved());
+    EXPECT_EQ(value_ptrs[i], array[i].ptr());
+    array[i].ResetMoved();
+    EXPECT_TRUE(array);
+  }
+  {
+    MoveOnlyType value;
+    value_ptrs.push_back(value.ptr());
+    array.push_back(value.Pass());
+    EXPECT_EQ(array.size() + 1, MoveOnlyType::num_instances());
+  }
+  ASSERT_EQ(capacity + 1, array.size());
+  EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
+
+  for (size_t i = 0; i < array.size(); i++) {
+    EXPECT_TRUE(array[i].moved());
+    EXPECT_EQ(value_ptrs[i], array[i].ptr());
+  }
+  array.reset();
+  EXPECT_EQ(0u, MoveOnlyType::num_instances());
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/bounds_checker_unittest.cc b/mojo/public/cpp/bindings/tests/bounds_checker_unittest.cc
new file mode 100644
index 0000000..8378cdd
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/bounds_checker_unittest.cc
@@ -0,0 +1,209 @@
+// Copyright 2014 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 <limits>
+
+#include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
+#include "mojo/public/cpp/bindings/lib/bounds_checker.h"
+#include "mojo/public/cpp/system/core.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+namespace {
+
+const void* ToPtr(uintptr_t ptr) {
+  return reinterpret_cast<const void*>(ptr);
+}
+
+#ifdef NDEBUG
+TEST(BoundsCheckerTest, ConstructorRangeOverflow) {
+  {
+    // Test memory range overflow.
+    internal::BoundsChecker
+        checker(ToPtr(std::numeric_limits<uintptr_t>::max() - 3000), 5000, 0);
+
+    EXPECT_FALSE(checker.IsValidRange(
+        ToPtr(std::numeric_limits<uintptr_t>::max() - 3000), 1));
+    EXPECT_FALSE(checker.ClaimMemory(
+        ToPtr(std::numeric_limits<uintptr_t>::max() - 3000), 1));
+  }
+
+  if (sizeof(size_t) > sizeof(uint32_t)) {
+    // Test handle index range overflow.
+    size_t num_handles =
+        static_cast<size_t>(std::numeric_limits<uint32_t>::max()) + 5;
+    internal::BoundsChecker checker(ToPtr(0), 0, num_handles);
+
+    EXPECT_FALSE(checker.ClaimHandle(Handle(0)));
+    EXPECT_FALSE(
+        checker.ClaimHandle(Handle(std::numeric_limits<uint32_t>::max() - 1)));
+
+    EXPECT_TRUE(
+        checker.ClaimHandle(Handle(internal::kEncodedInvalidHandleValue)));
+  }
+}
+#endif
+
+TEST(BoundsCheckerTest, IsValidRange) {
+  {
+    internal::BoundsChecker checker(ToPtr(1234), 100, 0);
+
+    // Basics.
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(100), 5));
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(1230), 50));
+    EXPECT_TRUE(checker.IsValidRange(ToPtr(1234), 5));
+    EXPECT_TRUE(checker.IsValidRange(ToPtr(1240), 50));
+    EXPECT_TRUE(checker.IsValidRange(ToPtr(1234), 100));
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(1234), 101));
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(1240), 100));
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(1333), 5));
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(2234), 5));
+
+    // ClaimMemory() updates the valid range.
+    EXPECT_TRUE(checker.ClaimMemory(ToPtr(1254), 10));
+
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(1234), 1));
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(1254), 10));
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(1263), 1));
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(1263), 10));
+    EXPECT_TRUE(checker.IsValidRange(ToPtr(1264), 10));
+    EXPECT_TRUE(checker.IsValidRange(ToPtr(1264), 70));
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(1264), 71));
+  }
+
+  {
+    internal::BoundsChecker checker(ToPtr(1234), 100, 0);
+    // Should return false for empty ranges.
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(0), 0));
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(1200), 0));
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(1234), 0));
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(1240), 0));
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(2234), 0));
+  }
+
+  {
+    // The valid memory range is empty.
+    internal::BoundsChecker checker(ToPtr(1234), 0, 0);
+
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(1234), 1));
+    EXPECT_FALSE(checker.IsValidRange(ToPtr(1234), 0));
+  }
+
+  {
+    internal::BoundsChecker
+        checker(ToPtr(std::numeric_limits<uintptr_t>::max() - 2000), 1000, 0);
+
+    // Test overflow.
+    EXPECT_FALSE(checker.IsValidRange(
+        ToPtr(std::numeric_limits<uintptr_t>::max() - 1500), 4000));
+    EXPECT_FALSE(checker.IsValidRange(
+        ToPtr(std::numeric_limits<uintptr_t>::max() - 1500),
+        std::numeric_limits<uint32_t>::max()));
+
+    // This should be fine.
+    EXPECT_TRUE(checker.IsValidRange(
+        ToPtr(std::numeric_limits<uintptr_t>::max() - 1500), 200));
+  }
+}
+
+TEST(BoundsCheckerTest, ClaimHandle) {
+  {
+    internal::BoundsChecker checker(ToPtr(0), 0, 10);
+
+    // Basics.
+    EXPECT_TRUE(checker.ClaimHandle(Handle(0)));
+    EXPECT_FALSE(checker.ClaimHandle(Handle(0)));
+
+    EXPECT_TRUE(checker.ClaimHandle(Handle(9)));
+    EXPECT_FALSE(checker.ClaimHandle(Handle(10)));
+
+    // Should fail because it is smaller than the max index that has been
+    // claimed.
+    EXPECT_FALSE(checker.ClaimHandle(Handle(8)));
+
+    // Should return true for invalid handle.
+    EXPECT_TRUE(
+        checker.ClaimHandle(Handle(internal::kEncodedInvalidHandleValue)));
+    EXPECT_TRUE(
+        checker.ClaimHandle(Handle(internal::kEncodedInvalidHandleValue)));
+  }
+
+  {
+    // No handle to claim.
+    internal::BoundsChecker checker(ToPtr(0), 0, 0);
+
+    EXPECT_FALSE(checker.ClaimHandle(Handle(0)));
+
+    // Should still return true for invalid handle.
+    EXPECT_TRUE(
+        checker.ClaimHandle(Handle(internal::kEncodedInvalidHandleValue)));
+  }
+
+  {
+    // Test the case that |num_handles| is the same value as
+    // |internal::kEncodedInvalidHandleValue|.
+    EXPECT_EQ(internal::kEncodedInvalidHandleValue,
+              std::numeric_limits<uint32_t>::max());
+    internal::BoundsChecker checker(ToPtr(0), 0,
+                                    std::numeric_limits<uint32_t>::max());
+
+    EXPECT_TRUE(
+        checker.ClaimHandle(Handle(std::numeric_limits<uint32_t>::max() - 1)));
+    EXPECT_FALSE(
+        checker.ClaimHandle(Handle(std::numeric_limits<uint32_t>::max() - 1)));
+    EXPECT_FALSE(checker.ClaimHandle(Handle(0)));
+
+    // Should still return true for invalid handle.
+    EXPECT_TRUE(
+        checker.ClaimHandle(Handle(internal::kEncodedInvalidHandleValue)));
+  }
+}
+
+TEST(BoundsCheckerTest, ClaimMemory) {
+  {
+    internal::BoundsChecker checker(ToPtr(1000), 2000, 0);
+
+    // Basics.
+    EXPECT_FALSE(checker.ClaimMemory(ToPtr(500), 100));
+    EXPECT_FALSE(checker.ClaimMemory(ToPtr(800), 300));
+    EXPECT_TRUE(checker.ClaimMemory(ToPtr(1000), 100));
+    EXPECT_FALSE(checker.ClaimMemory(ToPtr(1099), 100));
+    EXPECT_TRUE(checker.ClaimMemory(ToPtr(1100), 200));
+    EXPECT_FALSE(checker.ClaimMemory(ToPtr(2000), 1001));
+    EXPECT_TRUE(checker.ClaimMemory(ToPtr(2000), 500));
+    EXPECT_FALSE(checker.ClaimMemory(ToPtr(2000), 500));
+    EXPECT_FALSE(checker.ClaimMemory(ToPtr(1400), 100));
+    EXPECT_FALSE(checker.ClaimMemory(ToPtr(3000), 1));
+    EXPECT_TRUE(checker.ClaimMemory(ToPtr(2500), 500));
+  }
+
+  {
+    // No memory to claim.
+    internal::BoundsChecker checker(ToPtr(10000), 0, 0);
+
+    EXPECT_FALSE(checker.ClaimMemory(ToPtr(10000), 1));
+    EXPECT_FALSE(checker.ClaimMemory(ToPtr(10000), 0));
+  }
+
+  {
+    internal::BoundsChecker
+        checker(ToPtr(std::numeric_limits<uintptr_t>::max() - 1000), 500, 0);
+
+    // Test overflow.
+    EXPECT_FALSE(checker.ClaimMemory(
+        ToPtr(std::numeric_limits<uintptr_t>::max() - 750), 4000));
+    EXPECT_FALSE(checker.ClaimMemory(
+        ToPtr(std::numeric_limits<uintptr_t>::max() - 750),
+        std::numeric_limits<uint32_t>::max()));
+
+    // This should be fine.
+    EXPECT_TRUE(checker.ClaimMemory(
+        ToPtr(std::numeric_limits<uintptr_t>::max() - 750), 200));
+  }
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/buffer_unittest.cc b/mojo/public/cpp/bindings/tests/buffer_unittest.cc
new file mode 100644
index 0000000..61424c0
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/buffer_unittest.cc
@@ -0,0 +1,91 @@
+// Copyright 2014 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 <limits>
+
+#include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
+#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+namespace {
+
+bool IsZero(void* p_buf, size_t size) {
+  char* buf = reinterpret_cast<char*>(p_buf);
+  for (size_t i = 0; i < size; ++i) {
+    if (buf[i] != 0)
+      return false;
+  }
+  return true;
+}
+
+// Tests that FixedBuffer allocates memory aligned to 8 byte boundaries.
+TEST(FixedBufferTest, Alignment) {
+  internal::FixedBuffer buf(internal::Align(10) * 2);
+  ASSERT_EQ(buf.size(), 16u * 2);
+
+  void* a = buf.Allocate(10);
+  ASSERT_TRUE(a);
+  EXPECT_TRUE(IsZero(a, 10));
+  EXPECT_EQ(0, reinterpret_cast<ptrdiff_t>(a) % 8);
+
+  void* b = buf.Allocate(10);
+  ASSERT_TRUE(b);
+  EXPECT_TRUE(IsZero(b, 10));
+  EXPECT_EQ(0, reinterpret_cast<ptrdiff_t>(b) % 8);
+
+  // Any more allocations would result in an assert, but we can't test that.
+}
+
+// Tests that FixedBuffer::Leak passes ownership to the caller.
+TEST(FixedBufferTest, Leak) {
+  void* ptr = nullptr;
+  void* buf_ptr = nullptr;
+  {
+    internal::FixedBuffer buf(8);
+    ASSERT_EQ(8u, buf.size());
+
+    ptr = buf.Allocate(8);
+    ASSERT_TRUE(ptr);
+    buf_ptr = buf.Leak();
+
+    // The buffer should point to the first element allocated.
+    // TODO(mpcomplete): Is this a reasonable expectation?
+    EXPECT_EQ(ptr, buf_ptr);
+
+    // The FixedBuffer should be empty now.
+    EXPECT_EQ(0u, buf.size());
+    EXPECT_FALSE(buf.Leak());
+  }
+
+  // Since we called Leak, ptr is still writable after FixedBuffer went out of
+  // scope.
+  memset(ptr, 1, 8);
+  free(buf_ptr);
+}
+
+#ifdef NDEBUG
+TEST(FixedBufferTest, TooBig) {
+  internal::FixedBuffer buf(24);
+
+  // A little bit too large.
+  EXPECT_EQ(reinterpret_cast<void*>(0), buf.Allocate(32));
+
+  // Move the cursor forward.
+  EXPECT_NE(reinterpret_cast<void*>(0), buf.Allocate(16));
+
+  // A lot too large.
+  EXPECT_EQ(reinterpret_cast<void*>(0),
+            buf.Allocate(std::numeric_limits<size_t>::max() - 1024u));
+
+  // A lot too large, leading to possible integer overflow.
+  EXPECT_EQ(reinterpret_cast<void*>(0),
+            buf.Allocate(std::numeric_limits<size_t>::max() - 8u));
+}
+#endif
+
+}  // namespace
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/connector_unittest.cc b/mojo/public/cpp/bindings/tests/connector_unittest.cc
new file mode 100644
index 0000000..317f4c8
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/connector_unittest.cc
@@ -0,0 +1,402 @@
+// Copyright 2013 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 <stdlib.h>
+#include <string.h>
+
+#include "mojo/public/cpp/bindings/lib/connector.h"
+#include "mojo/public/cpp/bindings/lib/message_builder.h"
+#include "mojo/public/cpp/bindings/lib/message_queue.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/system/macros.h"
+#include "mojo/public/cpp/utility/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+namespace {
+
+class MessageAccumulator : public MessageReceiver {
+ public:
+  MessageAccumulator() {
+  }
+
+  virtual bool Accept(Message* message) override {
+    queue_.Push(message);
+    return true;
+  }
+
+  bool IsEmpty() const {
+    return queue_.IsEmpty();
+  }
+
+  void Pop(Message* message) {
+    queue_.Pop(message);
+  }
+
+ private:
+  internal::MessageQueue queue_;
+};
+
+class ConnectorDeletingMessageAccumulator : public MessageAccumulator {
+ public:
+  ConnectorDeletingMessageAccumulator(internal::Connector** connector)
+      : connector_(connector) {}
+
+  virtual bool Accept(Message* message) override {
+    delete *connector_;
+    *connector_ = 0;
+    return MessageAccumulator::Accept(message);
+  }
+
+ private:
+  internal::Connector** connector_;
+};
+
+class ReentrantMessageAccumulator : public MessageAccumulator {
+ public:
+  ReentrantMessageAccumulator(internal::Connector* connector)
+      : connector_(connector), number_of_calls_(0) {}
+
+  virtual bool Accept(Message* message) override {
+    if (!MessageAccumulator::Accept(message))
+      return false;
+    number_of_calls_++;
+    if (number_of_calls_ == 1) {
+      return connector_->WaitForIncomingMessage();
+    }
+    return true;
+  }
+
+  int number_of_calls() { return number_of_calls_; }
+
+ private:
+  internal::Connector* connector_;
+  int number_of_calls_;
+};
+
+class ConnectorTest : public testing::Test {
+ public:
+  ConnectorTest() {
+  }
+
+  virtual void SetUp() override {
+    CreateMessagePipe(nullptr, &handle0_, &handle1_);
+  }
+
+  virtual void TearDown() override {}
+
+  void AllocMessage(const char* text, Message* message) {
+    size_t payload_size = strlen(text) + 1;  // Plus null terminator.
+    internal::MessageBuilder builder(1, payload_size);
+    memcpy(builder.buffer()->Allocate(payload_size), text, payload_size);
+    builder.Finish(message);
+  }
+
+  void PumpMessages() {
+    loop_.RunUntilIdle();
+  }
+
+ protected:
+  ScopedMessagePipeHandle handle0_;
+  ScopedMessagePipeHandle handle1_;
+
+ private:
+  Environment env_;
+  RunLoop loop_;
+};
+
+TEST_F(ConnectorTest, Basic) {
+  internal::Connector connector0(handle0_.Pass());
+  internal::Connector connector1(handle1_.Pass());
+
+  const char kText[] = "hello world";
+
+  Message message;
+  AllocMessage(kText, &message);
+
+  connector0.Accept(&message);
+
+  MessageAccumulator accumulator;
+  connector1.set_incoming_receiver(&accumulator);
+
+  PumpMessages();
+
+  ASSERT_FALSE(accumulator.IsEmpty());
+
+  Message message_received;
+  accumulator.Pop(&message_received);
+
+  EXPECT_EQ(
+      std::string(kText),
+      std::string(reinterpret_cast<const char*>(message_received.payload())));
+}
+
+TEST_F(ConnectorTest, Basic_Synchronous) {
+  internal::Connector connector0(handle0_.Pass());
+  internal::Connector connector1(handle1_.Pass());
+
+  const char kText[] = "hello world";
+
+  Message message;
+  AllocMessage(kText, &message);
+
+  connector0.Accept(&message);
+
+  MessageAccumulator accumulator;
+  connector1.set_incoming_receiver(&accumulator);
+
+  connector1.WaitForIncomingMessage();
+
+  ASSERT_FALSE(accumulator.IsEmpty());
+
+  Message message_received;
+  accumulator.Pop(&message_received);
+
+  EXPECT_EQ(
+      std::string(kText),
+      std::string(reinterpret_cast<const char*>(message_received.payload())));
+}
+
+TEST_F(ConnectorTest, Basic_EarlyIncomingReceiver) {
+  internal::Connector connector0(handle0_.Pass());
+  internal::Connector connector1(handle1_.Pass());
+
+  MessageAccumulator accumulator;
+  connector1.set_incoming_receiver(&accumulator);
+
+  const char kText[] = "hello world";
+
+  Message message;
+  AllocMessage(kText, &message);
+
+  connector0.Accept(&message);
+
+  PumpMessages();
+
+  ASSERT_FALSE(accumulator.IsEmpty());
+
+  Message message_received;
+  accumulator.Pop(&message_received);
+
+  EXPECT_EQ(
+      std::string(kText),
+      std::string(reinterpret_cast<const char*>(message_received.payload())));
+}
+
+TEST_F(ConnectorTest, Basic_TwoMessages) {
+  internal::Connector connector0(handle0_.Pass());
+  internal::Connector connector1(handle1_.Pass());
+
+  const char* kText[] = { "hello", "world" };
+
+  for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) {
+    Message message;
+    AllocMessage(kText[i], &message);
+
+    connector0.Accept(&message);
+  }
+
+  MessageAccumulator accumulator;
+  connector1.set_incoming_receiver(&accumulator);
+
+  PumpMessages();
+
+  for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) {
+    ASSERT_FALSE(accumulator.IsEmpty());
+
+    Message message_received;
+    accumulator.Pop(&message_received);
+
+    EXPECT_EQ(
+        std::string(kText[i]),
+        std::string(reinterpret_cast<const char*>(message_received.payload())));
+  }
+}
+
+TEST_F(ConnectorTest, Basic_TwoMessages_Synchronous) {
+  internal::Connector connector0(handle0_.Pass());
+  internal::Connector connector1(handle1_.Pass());
+
+  const char* kText[] = { "hello", "world" };
+
+  for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) {
+    Message message;
+    AllocMessage(kText[i], &message);
+
+    connector0.Accept(&message);
+  }
+
+  MessageAccumulator accumulator;
+  connector1.set_incoming_receiver(&accumulator);
+
+  connector1.WaitForIncomingMessage();
+
+  ASSERT_FALSE(accumulator.IsEmpty());
+
+  Message message_received;
+  accumulator.Pop(&message_received);
+
+  EXPECT_EQ(
+      std::string(kText[0]),
+      std::string(reinterpret_cast<const char*>(message_received.payload())));
+
+  ASSERT_TRUE(accumulator.IsEmpty());
+}
+
+TEST_F(ConnectorTest, WriteToClosedPipe) {
+  internal::Connector connector0(handle0_.Pass());
+
+  const char kText[] = "hello world";
+
+  Message message;
+  AllocMessage(kText, &message);
+
+  // Close the other end of the pipe.
+  handle1_.reset();
+
+  // Not observed yet because we haven't spun the RunLoop yet.
+  EXPECT_FALSE(connector0.encountered_error());
+
+  // Write failures are not reported.
+  bool ok = connector0.Accept(&message);
+  EXPECT_TRUE(ok);
+
+  // Still not observed.
+  EXPECT_FALSE(connector0.encountered_error());
+
+  // Spin the RunLoop, and then we should start observing the closed pipe.
+  PumpMessages();
+
+  EXPECT_TRUE(connector0.encountered_error());
+}
+
+TEST_F(ConnectorTest, MessageWithHandles) {
+  internal::Connector connector0(handle0_.Pass());
+  internal::Connector connector1(handle1_.Pass());
+
+  const char kText[] = "hello world";
+
+  Message message1;
+  AllocMessage(kText, &message1);
+
+  MessagePipe pipe;
+  message1.mutable_handles()->push_back(pipe.handle0.release());
+
+  connector0.Accept(&message1);
+
+  // The message should have been transferred, releasing the handles.
+  EXPECT_TRUE(message1.handles()->empty());
+
+  MessageAccumulator accumulator;
+  connector1.set_incoming_receiver(&accumulator);
+
+  PumpMessages();
+
+  ASSERT_FALSE(accumulator.IsEmpty());
+
+  Message message_received;
+  accumulator.Pop(&message_received);
+
+  EXPECT_EQ(
+      std::string(kText),
+      std::string(reinterpret_cast<const char*>(message_received.payload())));
+  ASSERT_EQ(1U, message_received.handles()->size());
+
+  // Now send a message to the transferred handle and confirm it's sent through
+  // to the orginal pipe.
+  // TODO(vtl): Do we need a better way of "downcasting" the handle types?
+  ScopedMessagePipeHandle smph;
+  smph.reset(MessagePipeHandle(message_received.handles()->front().value()));
+  message_received.mutable_handles()->front() = Handle();
+  // |smph| now owns this handle.
+
+  internal::Connector connector_received(smph.Pass());
+  internal::Connector connector_original(pipe.handle1.Pass());
+
+  Message message2;
+  AllocMessage(kText, &message2);
+
+  connector_received.Accept(&message2);
+  connector_original.set_incoming_receiver(&accumulator);
+  PumpMessages();
+
+  ASSERT_FALSE(accumulator.IsEmpty());
+
+  accumulator.Pop(&message_received);
+
+  EXPECT_EQ(
+      std::string(kText),
+      std::string(reinterpret_cast<const char*>(message_received.payload())));
+}
+
+TEST_F(ConnectorTest, WaitForIncomingMessageWithError) {
+  internal::Connector connector0(handle0_.Pass());
+  // Close the other end of the pipe.
+  handle1_.reset();
+  ASSERT_FALSE(connector0.WaitForIncomingMessage());
+}
+
+TEST_F(ConnectorTest, WaitForIncomingMessageWithDeletion) {
+  internal::Connector connector0(handle0_.Pass());
+  internal::Connector* connector1 = new internal::Connector(handle1_.Pass());
+
+  const char kText[] = "hello world";
+
+  Message message;
+  AllocMessage(kText, &message);
+
+  connector0.Accept(&message);
+
+  ConnectorDeletingMessageAccumulator accumulator(&connector1);
+  connector1->set_incoming_receiver(&accumulator);
+
+  connector1->WaitForIncomingMessage();
+
+  ASSERT_FALSE(connector1);
+  ASSERT_FALSE(accumulator.IsEmpty());
+
+  Message message_received;
+  accumulator.Pop(&message_received);
+
+  EXPECT_EQ(
+      std::string(kText),
+      std::string(reinterpret_cast<const char*>(message_received.payload())));
+}
+
+TEST_F(ConnectorTest, WaitForIncomingMessageWithReentrancy) {
+  internal::Connector connector0(handle0_.Pass());
+  internal::Connector connector1(handle1_.Pass());
+
+  const char* kText[] = { "hello", "world" };
+
+  for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) {
+    Message message;
+    AllocMessage(kText[i], &message);
+
+    connector0.Accept(&message);
+  }
+
+  ReentrantMessageAccumulator accumulator(&connector1);
+  connector1.set_incoming_receiver(&accumulator);
+
+  PumpMessages();
+
+  for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) {
+    ASSERT_FALSE(accumulator.IsEmpty());
+
+    Message message_received;
+    accumulator.Pop(&message_received);
+
+    EXPECT_EQ(
+        std::string(kText[i]),
+        std::string(reinterpret_cast<const char*>(message_received.payload())));
+  }
+
+  ASSERT_EQ(2, accumulator.number_of_calls());
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc b/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc
new file mode 100644
index 0000000..d4cffb4
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc
@@ -0,0 +1,350 @@
+// Copyright 2013 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/cpp/environment/environment.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
+#include "mojo/public/cpp/utility/run_loop.h"
+#include "mojo/public/interfaces/bindings/tests/sample_factory.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+namespace {
+
+const char kText1[] = "hello";
+const char kText2[] = "world";
+
+class StringRecorder {
+ public:
+  explicit StringRecorder(std::string* buf) : buf_(buf) {
+  }
+  void Run(const String& a) const {
+    *buf_ = a.To<std::string>();
+  }
+ private:
+  std::string* buf_;
+};
+
+class ImportedInterfaceImpl
+    : public InterfaceImpl<imported::ImportedInterface> {
+ public:
+  virtual void DoSomething() override { do_something_count_++; }
+
+  static int do_something_count() { return do_something_count_; }
+
+ private:
+  static int do_something_count_;
+};
+int ImportedInterfaceImpl::do_something_count_ = 0;
+
+class SampleNamedObjectImpl : public InterfaceImpl<sample::NamedObject> {
+ public:
+  virtual void SetName(const mojo::String& name) override { name_ = name; }
+
+  virtual void GetName(
+      const mojo::Callback<void(mojo::String)>& callback) override {
+    callback.Run(name_);
+  }
+
+ private:
+  std::string name_;
+};
+
+class SampleFactoryImpl : public InterfaceImpl<sample::Factory> {
+ public:
+  virtual void DoStuff(sample::RequestPtr request,
+                       ScopedMessagePipeHandle pipe) override {
+    std::string text1;
+    if (pipe.is_valid())
+      EXPECT_TRUE(ReadTextMessage(pipe.get(), &text1));
+
+    std::string text2;
+    if (request->pipe.is_valid()) {
+      EXPECT_TRUE(ReadTextMessage(request->pipe.get(), &text2));
+
+      // Ensure that simply accessing request->pipe does not close it.
+      EXPECT_TRUE(request->pipe.is_valid());
+    }
+
+    ScopedMessagePipeHandle pipe0;
+    if (!text2.empty()) {
+      CreateMessagePipe(nullptr, &pipe0, &pipe1_);
+      EXPECT_TRUE(WriteTextMessage(pipe1_.get(), text2));
+    }
+
+    sample::ResponsePtr response(sample::Response::New());
+    response->x = 2;
+    response->pipe = pipe0.Pass();
+    client()->DidStuff(response.Pass(), text1);
+
+    if (request->obj)
+      request->obj->DoSomething();
+  }
+
+  virtual void DoStuff2(ScopedDataPipeConsumerHandle pipe) override {
+    // Read the data from the pipe, writing the response (as a string) to
+    // DidStuff2().
+    ASSERT_TRUE(pipe.is_valid());
+    uint32_t data_size = 0;
+    ASSERT_EQ(MOJO_RESULT_OK,
+              ReadDataRaw(pipe.get(), nullptr, &data_size,
+                          MOJO_READ_DATA_FLAG_QUERY));
+    ASSERT_NE(0, static_cast<int>(data_size));
+    char data[64];
+    ASSERT_LT(static_cast<int>(data_size), 64);
+    ASSERT_EQ(MOJO_RESULT_OK,
+              ReadDataRaw(pipe.get(), data, &data_size,
+                          MOJO_READ_DATA_FLAG_ALL_OR_NONE));
+
+    client()->DidStuff2(data);
+  }
+
+  virtual void CreateNamedObject(
+      InterfaceRequest<sample::NamedObject> object_request) override {
+    EXPECT_TRUE(object_request.is_pending());
+    BindToRequest(new SampleNamedObjectImpl(), &object_request);
+  }
+
+  // These aren't called or implemented, but exist here to test that the
+  // methods are generated with the correct argument types for imported
+  // interfaces.
+  virtual void RequestImportedInterface(
+      InterfaceRequest<imported::ImportedInterface> imported,
+      const mojo::Callback<void(InterfaceRequest<imported::ImportedInterface>)>&
+          callback) override {}
+  virtual void TakeImportedInterface(
+      imported::ImportedInterfacePtr imported,
+      const mojo::Callback<void(imported::ImportedInterfacePtr)>& callback)
+      override {}
+
+ private:
+  ScopedMessagePipeHandle pipe1_;
+};
+
+class SampleFactoryClientImpl : public sample::FactoryClient {
+ public:
+  SampleFactoryClientImpl() : got_response_(false) {
+  }
+
+  void set_expected_text_reply(const std::string& expected_text_reply) {
+    expected_text_reply_ = expected_text_reply;
+  }
+
+  bool got_response() const {
+    return got_response_;
+  }
+
+  virtual void DidStuff(sample::ResponsePtr response,
+                        const String& text_reply) override {
+    EXPECT_EQ(expected_text_reply_, text_reply);
+
+    if (response->pipe.is_valid()) {
+      std::string text2;
+      EXPECT_TRUE(ReadTextMessage(response->pipe.get(), &text2));
+
+      // Ensure that simply accessing response.pipe does not close it.
+      EXPECT_TRUE(response->pipe.is_valid());
+
+      EXPECT_EQ(std::string(kText2), text2);
+
+      // Do some more tests of handle passing:
+      ScopedMessagePipeHandle p = response->pipe.Pass();
+      EXPECT_TRUE(p.is_valid());
+      EXPECT_FALSE(response->pipe.is_valid());
+    }
+
+    got_response_ = true;
+  }
+
+  virtual void DidStuff2(const String& text_reply) override {
+    got_response_ = true;
+    EXPECT_EQ(expected_text_reply_, text_reply);
+  }
+
+ private:
+  ScopedMessagePipeHandle pipe1_;
+  ScopedMessagePipeHandle pipe3_;
+  std::string expected_text_reply_;
+  bool got_response_;
+};
+
+class HandlePassingTest : public testing::Test {
+ public:
+  virtual void TearDown() {
+    PumpMessages();
+  }
+
+  void PumpMessages() {
+    loop_.RunUntilIdle();
+  }
+
+ private:
+  Environment env_;
+  RunLoop loop_;
+};
+
+TEST_F(HandlePassingTest, Basic) {
+  sample::FactoryPtr factory;
+  BindToProxy(new SampleFactoryImpl(), &factory);
+
+  SampleFactoryClientImpl factory_client;
+  factory_client.set_expected_text_reply(kText1);
+
+  factory.set_client(&factory_client);
+
+  MessagePipe pipe0;
+  EXPECT_TRUE(WriteTextMessage(pipe0.handle1.get(), kText1));
+
+  MessagePipe pipe1;
+  EXPECT_TRUE(WriteTextMessage(pipe1.handle1.get(), kText2));
+
+  imported::ImportedInterfacePtr imported;
+  BindToProxy(new ImportedInterfaceImpl(), &imported);
+
+  sample::RequestPtr request(sample::Request::New());
+  request->x = 1;
+  request->pipe = pipe1.handle0.Pass();
+  request->obj = imported.Pass();
+  factory->DoStuff(request.Pass(), pipe0.handle0.Pass());
+
+  EXPECT_FALSE(factory_client.got_response());
+  int count_before = ImportedInterfaceImpl::do_something_count();
+
+  PumpMessages();
+
+  EXPECT_TRUE(factory_client.got_response());
+  EXPECT_EQ(1, ImportedInterfaceImpl::do_something_count() - count_before);
+}
+
+TEST_F(HandlePassingTest, PassInvalid) {
+  sample::FactoryPtr factory;
+  BindToProxy(new SampleFactoryImpl(), &factory);
+
+  SampleFactoryClientImpl factory_client;
+  factory.set_client(&factory_client);
+
+  sample::RequestPtr request(sample::Request::New());
+  request->x = 1;
+  factory->DoStuff(request.Pass(), ScopedMessagePipeHandle().Pass());
+
+  EXPECT_FALSE(factory_client.got_response());
+
+  PumpMessages();
+
+  EXPECT_TRUE(factory_client.got_response());
+}
+
+// Verifies DataPipeConsumer can be passed and read from.
+TEST_F(HandlePassingTest, DataPipe) {
+  sample::FactoryPtr factory;
+  BindToProxy(new SampleFactoryImpl(), &factory);
+
+  SampleFactoryClientImpl factory_client;
+  factory.set_client(&factory_client);
+
+  // Writes a string to a data pipe and passes the data pipe (consumer) to the
+  // factory.
+  ScopedDataPipeProducerHandle producer_handle;
+  ScopedDataPipeConsumerHandle consumer_handle;
+  MojoCreateDataPipeOptions options = {
+      sizeof(MojoCreateDataPipeOptions),
+      MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE,
+      1,
+      1024};
+  ASSERT_EQ(MOJO_RESULT_OK,
+            CreateDataPipe(&options, &producer_handle, &consumer_handle));
+  std::string expected_text_reply = "got it";
+  factory_client.set_expected_text_reply(expected_text_reply);
+  // +1 for \0.
+  uint32_t data_size = static_cast<uint32_t>(expected_text_reply.size() + 1);
+  ASSERT_EQ(MOJO_RESULT_OK,
+            WriteDataRaw(producer_handle.get(), expected_text_reply.c_str(),
+                         &data_size, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
+
+  factory->DoStuff2(consumer_handle.Pass());
+
+  EXPECT_FALSE(factory_client.got_response());
+
+  PumpMessages();
+
+  EXPECT_TRUE(factory_client.got_response());
+}
+
+TEST_F(HandlePassingTest, PipesAreClosed) {
+  sample::FactoryPtr factory;
+  BindToProxy(new SampleFactoryImpl(), &factory);
+
+  SampleFactoryClientImpl factory_client;
+  factory.set_client(&factory_client);
+
+  MessagePipe extra_pipe;
+
+  MojoHandle handle0_value = extra_pipe.handle0.get().value();
+  MojoHandle handle1_value = extra_pipe.handle1.get().value();
+
+  {
+    Array<ScopedMessagePipeHandle> pipes(2);
+    pipes[0] = extra_pipe.handle0.Pass();
+    pipes[1] = extra_pipe.handle1.Pass();
+
+    sample::RequestPtr request(sample::Request::New());
+    request->more_pipes = pipes.Pass();
+
+    factory->DoStuff(request.Pass(), ScopedMessagePipeHandle());
+  }
+
+  // We expect the pipes to have been closed.
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(handle0_value));
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(handle1_value));
+}
+
+TEST_F(HandlePassingTest, IsHandle) {
+  // Validate that mojo::internal::IsHandle<> works as expected since this.
+  // template is key to ensuring that we don't leak handles.
+  EXPECT_TRUE(internal::IsHandle<Handle>::value);
+  EXPECT_TRUE(internal::IsHandle<MessagePipeHandle>::value);
+  EXPECT_TRUE(internal::IsHandle<DataPipeConsumerHandle>::value);
+  EXPECT_TRUE(internal::IsHandle<DataPipeProducerHandle>::value);
+  EXPECT_TRUE(internal::IsHandle<SharedBufferHandle>::value);
+
+  // Basic sanity checks...
+  EXPECT_FALSE(internal::IsHandle<int>::value);
+  EXPECT_FALSE(internal::IsHandle<sample::FactoryPtr>::value);
+  EXPECT_FALSE(internal::IsHandle<String>::value);
+}
+
+TEST_F(HandlePassingTest, CreateNamedObject) {
+  sample::FactoryPtr factory;
+  BindToProxy(new SampleFactoryImpl(), &factory);
+
+  sample::NamedObjectPtr object1;
+  EXPECT_FALSE(object1);
+
+  InterfaceRequest<sample::NamedObject> object1_request = Get(&object1);
+  EXPECT_TRUE(object1_request.is_pending());
+  factory->CreateNamedObject(object1_request.Pass());
+  EXPECT_FALSE(object1_request.is_pending());  // We've passed the request.
+
+  ASSERT_TRUE(object1);
+  object1->SetName("object1");
+
+  sample::NamedObjectPtr object2;
+  factory->CreateNamedObject(Get(&object2));
+  object2->SetName("object2");
+
+  std::string name1;
+  object1->GetName(StringRecorder(&name1));
+
+  std::string name2;
+  object2->GetName(StringRecorder(&name2));
+
+  PumpMessages();  // Yield for results.
+
+  EXPECT_EQ(std::string("object1"), name1);
+  EXPECT_EQ(std::string("object2"), name2);
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc b/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
new file mode 100644
index 0000000..ded6d47
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
@@ -0,0 +1,384 @@
+// Copyright 2013 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/cpp/bindings/error_handler.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/utility/run_loop.h"
+#include "mojo/public/interfaces/bindings/tests/math_calculator.mojom.h"
+#include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+namespace {
+
+class ErrorObserver : public ErrorHandler {
+ public:
+  ErrorObserver() : encountered_error_(false) {
+  }
+
+  bool encountered_error() const { return encountered_error_; }
+
+  virtual void OnConnectionError() override { encountered_error_ = true; }
+
+ private:
+  bool encountered_error_;
+};
+
+class MathCalculatorImpl : public InterfaceImpl<math::Calculator> {
+ public:
+  virtual ~MathCalculatorImpl() {}
+
+  MathCalculatorImpl()
+      : total_(0.0),
+        got_connection_(false) {
+  }
+
+  virtual void OnConnectionEstablished() override { got_connection_ = true; }
+
+  virtual void Clear() override { client()->Output(total_); }
+
+  virtual void Add(double value) override {
+    total_ += value;
+    client()->Output(total_);
+  }
+
+  virtual void Multiply(double value) override {
+    total_ *= value;
+    client()->Output(total_);
+  }
+
+  bool got_connection() const {
+    return got_connection_;
+  }
+
+ private:
+  double total_;
+  bool got_connection_;
+};
+
+class MathCalculatorUIImpl : public math::CalculatorUI {
+ public:
+  explicit MathCalculatorUIImpl(math::CalculatorPtr calculator)
+      : calculator_(calculator.Pass()),
+        output_(0.0) {
+    calculator_.set_client(this);
+  }
+
+  bool WaitForIncomingMethodCall() {
+    return calculator_.WaitForIncomingMethodCall();
+  }
+
+  bool encountered_error() const {
+    return calculator_.encountered_error();
+  }
+
+  void Add(double value) {
+    calculator_->Add(value);
+  }
+
+  void Subtract(double value) {
+    calculator_->Add(-value);
+  }
+
+  void Multiply(double value) {
+    calculator_->Multiply(value);
+  }
+
+  void Divide(double value) {
+    calculator_->Multiply(1.0 / value);
+  }
+
+  double GetOutput() const {
+    return output_;
+  }
+
+ private:
+  // math::CalculatorUI implementation:
+  virtual void Output(double value) override { output_ = value; }
+
+  math::CalculatorPtr calculator_;
+  double output_;
+};
+
+class SelfDestructingMathCalculatorUIImpl : public math::CalculatorUI {
+ public:
+  explicit SelfDestructingMathCalculatorUIImpl(math::CalculatorPtr calculator)
+      : calculator_(calculator.Pass()),
+        nesting_level_(0) {
+    ++num_instances_;
+    calculator_.set_client(this);
+  }
+
+  void BeginTest(bool nested) {
+    nesting_level_ = nested ? 2 : 1;
+    calculator_->Add(1.0);
+  }
+
+  static int num_instances() { return num_instances_; }
+
+ private:
+  virtual ~SelfDestructingMathCalculatorUIImpl() {
+    --num_instances_;
+  }
+
+  virtual void Output(double value) override {
+    if (--nesting_level_ > 0) {
+      // Add some more and wait for re-entrant call to Output!
+      calculator_->Add(1.0);
+      RunLoop::current()->RunUntilIdle();
+    } else {
+      delete this;
+    }
+  }
+
+  math::CalculatorPtr calculator_;
+  int nesting_level_;
+  static int num_instances_;
+};
+
+// static
+int SelfDestructingMathCalculatorUIImpl::num_instances_ = 0;
+
+class ReentrantServiceImpl : public InterfaceImpl<sample::Service> {
+ public:
+  virtual ~ReentrantServiceImpl() {}
+
+  ReentrantServiceImpl()
+      : got_connection_(false), call_depth_(0), max_call_depth_(0) {}
+
+  virtual void OnConnectionEstablished() override { got_connection_ = true; }
+
+  bool got_connection() const {
+    return got_connection_;
+  }
+
+  int max_call_depth() { return max_call_depth_; }
+
+  virtual void Frobinate(sample::FooPtr foo,
+                         sample::Service::BazOptions baz,
+                         sample::PortPtr port) override {
+    max_call_depth_ = std::max(++call_depth_, max_call_depth_);
+    if (call_depth_ == 1) {
+      EXPECT_TRUE(WaitForIncomingMethodCall());
+    }
+    call_depth_--;
+  }
+
+  virtual void GetPort(mojo::InterfaceRequest<sample::Port> port) override {}
+
+ private:
+  bool got_connection_;
+  int call_depth_;
+  int max_call_depth_;
+};
+
+class InterfacePtrTest : public testing::Test {
+ public:
+  virtual ~InterfacePtrTest() {
+    loop_.RunUntilIdle();
+  }
+
+  void PumpMessages() {
+    loop_.RunUntilIdle();
+  }
+
+ private:
+  Environment env_;
+  RunLoop loop_;
+};
+
+TEST_F(InterfacePtrTest, EndToEnd) {
+  math::CalculatorPtr calc;
+  MathCalculatorImpl* impl = BindToProxy(new MathCalculatorImpl(), &calc);
+  EXPECT_TRUE(impl->got_connection());
+
+  // Suppose this is instantiated in a process that has pipe1_.
+  MathCalculatorUIImpl calculator_ui(calc.Pass());
+
+  calculator_ui.Add(2.0);
+  calculator_ui.Multiply(5.0);
+
+  PumpMessages();
+
+  EXPECT_EQ(10.0, calculator_ui.GetOutput());
+}
+
+TEST_F(InterfacePtrTest, EndToEnd_Synchronous) {
+  math::CalculatorPtr calc;
+  MathCalculatorImpl* impl = BindToProxy(new MathCalculatorImpl(), &calc);
+  EXPECT_TRUE(impl->got_connection());
+
+  // Suppose this is instantiated in a process that has pipe1_.
+  MathCalculatorUIImpl calculator_ui(calc.Pass());
+
+  EXPECT_EQ(0.0, calculator_ui.GetOutput());
+
+  calculator_ui.Add(2.0);
+  EXPECT_EQ(0.0, calculator_ui.GetOutput());
+  impl->WaitForIncomingMethodCall();
+  calculator_ui.WaitForIncomingMethodCall();
+  EXPECT_EQ(2.0, calculator_ui.GetOutput());
+
+  calculator_ui.Multiply(5.0);
+  EXPECT_EQ(2.0, calculator_ui.GetOutput());
+  impl->WaitForIncomingMethodCall();
+  calculator_ui.WaitForIncomingMethodCall();
+  EXPECT_EQ(10.0, calculator_ui.GetOutput());
+}
+
+TEST_F(InterfacePtrTest, Movable) {
+  math::CalculatorPtr a;
+  math::CalculatorPtr b;
+  BindToProxy(new MathCalculatorImpl(), &b);
+
+  EXPECT_TRUE(!a);
+  EXPECT_FALSE(!b);
+
+  a = b.Pass();
+
+  EXPECT_FALSE(!a);
+  EXPECT_TRUE(!b);
+}
+
+TEST_F(InterfacePtrTest, Resettable) {
+  math::CalculatorPtr a;
+
+  EXPECT_TRUE(!a);
+
+  MessagePipe pipe;
+
+  // Save this so we can test it later.
+  Handle handle = pipe.handle0.get();
+
+  a = MakeProxy<math::Calculator>(pipe.handle0.Pass());
+
+  EXPECT_FALSE(!a);
+
+  a.reset();
+
+  EXPECT_TRUE(!a);
+  EXPECT_FALSE(a.internal_state()->router_for_testing());
+
+  // Test that handle was closed.
+  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, CloseRaw(handle));
+}
+
+TEST_F(InterfacePtrTest, EncounteredError) {
+  math::CalculatorPtr proxy;
+  MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy);
+
+  MathCalculatorUIImpl calculator_ui(proxy.Pass());
+
+  calculator_ui.Add(2.0);
+  PumpMessages();
+  EXPECT_EQ(2.0, calculator_ui.GetOutput());
+  EXPECT_FALSE(calculator_ui.encountered_error());
+
+  calculator_ui.Multiply(5.0);
+  EXPECT_FALSE(calculator_ui.encountered_error());
+
+  // Close the server.
+  server->internal_state()->router()->CloseMessagePipe();
+
+  // The state change isn't picked up locally yet.
+  EXPECT_FALSE(calculator_ui.encountered_error());
+
+  PumpMessages();
+
+  // OK, now we see the error.
+  EXPECT_TRUE(calculator_ui.encountered_error());
+}
+
+TEST_F(InterfacePtrTest, EncounteredErrorCallback) {
+  math::CalculatorPtr proxy;
+  MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy);
+
+  ErrorObserver error_observer;
+  proxy.set_error_handler(&error_observer);
+
+  MathCalculatorUIImpl calculator_ui(proxy.Pass());
+
+  calculator_ui.Add(2.0);
+  PumpMessages();
+  EXPECT_EQ(2.0, calculator_ui.GetOutput());
+  EXPECT_FALSE(calculator_ui.encountered_error());
+
+  calculator_ui.Multiply(5.0);
+  EXPECT_FALSE(calculator_ui.encountered_error());
+
+  // Close the server.
+  server->internal_state()->router()->CloseMessagePipe();
+
+  // The state change isn't picked up locally yet.
+  EXPECT_FALSE(calculator_ui.encountered_error());
+
+  PumpMessages();
+
+  // OK, now we see the error.
+  EXPECT_TRUE(calculator_ui.encountered_error());
+
+  // We should have also been able to observe the error through the
+  // ErrorHandler interface.
+  EXPECT_TRUE(error_observer.encountered_error());
+}
+
+TEST_F(InterfacePtrTest, NoClientAttribute) {
+  // This is a test to ensure the following compiles. The sample::Port interface
+  // does not have an explicit Client attribute.
+  sample::PortPtr port;
+  MessagePipe pipe;
+  port.Bind(pipe.handle0.Pass());
+}
+
+TEST_F(InterfacePtrTest, DestroyInterfacePtrOnClientMethod) {
+  math::CalculatorPtr proxy;
+  BindToProxy(new MathCalculatorImpl(), &proxy);
+
+  EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
+
+  SelfDestructingMathCalculatorUIImpl* impl =
+      new SelfDestructingMathCalculatorUIImpl(proxy.Pass());
+  impl->BeginTest(false);
+
+  PumpMessages();
+
+  EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
+}
+
+TEST_F(InterfacePtrTest, NestedDestroyInterfacePtrOnClientMethod) {
+  math::CalculatorPtr proxy;
+  BindToProxy(new MathCalculatorImpl(), &proxy);
+
+  EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
+
+  SelfDestructingMathCalculatorUIImpl* impl =
+      new SelfDestructingMathCalculatorUIImpl(proxy.Pass());
+  impl->BeginTest(true);
+
+  PumpMessages();
+
+  EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
+}
+
+TEST_F(InterfacePtrTest, ReentrantWaitForIncomingMethodCall) {
+  sample::ServicePtr proxy;
+  ReentrantServiceImpl* impl = BindToProxy(new ReentrantServiceImpl(), &proxy);
+  EXPECT_TRUE(impl->got_connection());
+
+  proxy->Frobinate(sample::FooPtr(),
+                   sample::Service::BAZ_OPTIONS_REGULAR,
+                   sample::PortPtr());
+  proxy->Frobinate(sample::FooPtr(),
+                   sample::Service::BAZ_OPTIONS_REGULAR,
+                   sample::PortPtr());
+
+  PumpMessages();
+
+  EXPECT_EQ(2, impl->max_call_depth());
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/request_response_unittest.cc b/mojo/public/cpp/bindings/tests/request_response_unittest.cc
new file mode 100644
index 0000000..3755e64
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/request_response_unittest.cc
@@ -0,0 +1,151 @@
+// Copyright 2014 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/cpp/environment/environment.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
+#include "mojo/public/cpp/utility/run_loop.h"
+#include "mojo/public/interfaces/bindings/tests/sample_import.mojom.h"
+#include "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+namespace {
+
+class ProviderImpl : public InterfaceImpl<sample::Provider> {
+ public:
+  virtual void EchoString(const String& a,
+                          const Callback<void(String)>& callback) override {
+    Callback<void(String)> callback_copy;
+    // Make sure operator= is used.
+    callback_copy = callback;
+    callback_copy.Run(a);
+  }
+
+  virtual void EchoStrings(
+      const String& a,
+      const String& b,
+      const Callback<void(String, String)>& callback) override {
+    callback.Run(a, b);
+  }
+
+  virtual void EchoMessagePipeHandle(
+      ScopedMessagePipeHandle a,
+      const Callback<void(ScopedMessagePipeHandle)>& callback) override {
+    callback.Run(a.Pass());
+  }
+
+  virtual void EchoEnum(sample::Enum a,
+                        const Callback<void(sample::Enum)>& callback) override {
+    callback.Run(a);
+  }
+};
+
+class StringRecorder {
+ public:
+  explicit StringRecorder(std::string* buf) : buf_(buf) {
+  }
+  void Run(const String& a) const {
+    *buf_ = a;
+  }
+  void Run(const String& a, const String& b) const {
+    *buf_ = a.get() + b.get();
+  }
+ private:
+  std::string* buf_;
+};
+
+class EnumRecorder {
+ public:
+  explicit EnumRecorder(sample::Enum* value) : value_(value) {
+  }
+  void Run(sample::Enum a) const {
+    *value_ = a;
+  }
+ private:
+  sample::Enum* value_;
+};
+
+class MessagePipeWriter {
+ public:
+  explicit MessagePipeWriter(const char* text) : text_(text) {
+  }
+  void Run(ScopedMessagePipeHandle handle) const {
+    WriteTextMessage(handle.get(), text_);
+  }
+ private:
+  std::string text_;
+};
+
+class RequestResponseTest : public testing::Test {
+ public:
+  virtual ~RequestResponseTest() {
+    loop_.RunUntilIdle();
+  }
+
+  void PumpMessages() {
+    loop_.RunUntilIdle();
+  }
+
+ private:
+  Environment env_;
+  RunLoop loop_;
+};
+
+TEST_F(RequestResponseTest, EchoString) {
+  sample::ProviderPtr provider;
+  BindToProxy(new ProviderImpl(), &provider);
+
+  std::string buf;
+  provider->EchoString(String::From("hello"), StringRecorder(&buf));
+
+  PumpMessages();
+
+  EXPECT_EQ(std::string("hello"), buf);
+}
+
+TEST_F(RequestResponseTest, EchoStrings) {
+  sample::ProviderPtr provider;
+  BindToProxy(new ProviderImpl(), &provider);
+
+  std::string buf;
+  provider->EchoStrings(
+      String::From("hello"), String::From(" world"), StringRecorder(&buf));
+
+  PumpMessages();
+
+  EXPECT_EQ(std::string("hello world"), buf);
+}
+
+TEST_F(RequestResponseTest, EchoMessagePipeHandle) {
+  sample::ProviderPtr provider;
+  BindToProxy(new ProviderImpl(), &provider);
+
+  MessagePipe pipe2;
+  provider->EchoMessagePipeHandle(pipe2.handle1.Pass(),
+                                  MessagePipeWriter("hello"));
+
+  PumpMessages();
+
+  std::string value;
+  ReadTextMessage(pipe2.handle0.get(), &value);
+
+  EXPECT_EQ(std::string("hello"), value);
+}
+
+TEST_F(RequestResponseTest, EchoEnum) {
+  sample::ProviderPtr provider;
+  BindToProxy(new ProviderImpl(), &provider);
+
+  sample::Enum value;
+  provider->EchoEnum(sample::ENUM_VALUE, EnumRecorder(&value));
+
+  PumpMessages();
+
+  EXPECT_EQ(sample::ENUM_VALUE, value);
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/router_unittest.cc b/mojo/public/cpp/bindings/tests/router_unittest.cc
new file mode 100644
index 0000000..d74e525
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/router_unittest.cc
@@ -0,0 +1,227 @@
+// Copyright 2014 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 <stdlib.h>
+#include <string.h>
+
+#include "mojo/public/cpp/bindings/lib/message_builder.h"
+#include "mojo/public/cpp/bindings/lib/message_queue.h"
+#include "mojo/public/cpp/bindings/lib/router.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/system/macros.h"
+#include "mojo/public/cpp/utility/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+namespace {
+
+void AllocRequestMessage(uint32_t name, const char* text, Message* message) {
+  size_t payload_size = strlen(text) + 1;  // Plus null terminator.
+  internal::RequestMessageBuilder builder(name, payload_size);
+  memcpy(builder.buffer()->Allocate(payload_size), text, payload_size);
+  builder.Finish(message);
+}
+
+void AllocResponseMessage(uint32_t name, const char* text,
+                          uint64_t request_id, Message* message) {
+  size_t payload_size = strlen(text) + 1;  // Plus null terminator.
+  internal::ResponseMessageBuilder builder(name, payload_size, request_id);
+  memcpy(builder.buffer()->Allocate(payload_size), text, payload_size);
+  builder.Finish(message);
+}
+
+class MessageAccumulator : public MessageReceiver {
+ public:
+  explicit MessageAccumulator(internal::MessageQueue* queue) : queue_(queue) {
+  }
+
+  virtual bool Accept(Message* message) override {
+    queue_->Push(message);
+    return true;
+  }
+
+ private:
+  internal::MessageQueue* queue_;
+};
+
+class ResponseGenerator : public MessageReceiverWithResponder {
+ public:
+  ResponseGenerator() {
+  }
+
+  virtual bool Accept(Message* message) override { return false; }
+
+  virtual bool AcceptWithResponder(Message* message,
+                                   MessageReceiver* responder) override {
+    EXPECT_TRUE(message->has_flag(internal::kMessageExpectsResponse));
+
+    return SendResponse(message->name(), message->request_id(), responder);
+  }
+
+  bool SendResponse(uint32_t name, uint64_t request_id,
+                    MessageReceiver* responder) {
+    Message response;
+    AllocResponseMessage(name, "world", request_id, &response);
+
+    bool result = responder->Accept(&response);
+    delete responder;
+    return result;
+  }
+};
+
+class LazyResponseGenerator : public ResponseGenerator {
+ public:
+  LazyResponseGenerator() : responder_(nullptr), name_(0), request_id_(0) {
+  }
+
+  virtual ~LazyResponseGenerator() {
+    delete responder_;
+  }
+
+  virtual bool AcceptWithResponder(Message* message,
+                                   MessageReceiver* responder) override {
+    name_ = message->name();
+    request_id_ = message->request_id();
+    responder_ = responder;
+    return true;
+  }
+
+  bool has_responder() const { return !!responder_; }
+
+  void Complete() {
+    SendResponse(name_, request_id_, responder_);
+    responder_ = nullptr;
+  }
+
+ private:
+  MessageReceiver* responder_;
+  uint32_t name_;
+  uint32_t request_id_;
+};
+
+class RouterTest : public testing::Test {
+ public:
+  RouterTest() {
+  }
+
+  virtual void SetUp() override {
+    CreateMessagePipe(nullptr, &handle0_, &handle1_);
+  }
+
+  virtual void TearDown() override {}
+
+  void PumpMessages() {
+    loop_.RunUntilIdle();
+  }
+
+ protected:
+  ScopedMessagePipeHandle handle0_;
+  ScopedMessagePipeHandle handle1_;
+
+ private:
+  Environment env_;
+  RunLoop loop_;
+};
+
+TEST_F(RouterTest, BasicRequestResponse) {
+  internal::Router router0(handle0_.Pass(), internal::FilterChain());
+  internal::Router router1(handle1_.Pass(), internal::FilterChain());
+
+  ResponseGenerator generator;
+  router1.set_incoming_receiver(&generator);
+
+  Message request;
+  AllocRequestMessage(1, "hello", &request);
+
+  internal::MessageQueue message_queue;
+  router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue));
+
+  PumpMessages();
+
+  EXPECT_FALSE(message_queue.IsEmpty());
+
+  Message response;
+  message_queue.Pop(&response);
+
+  EXPECT_EQ(std::string("world"),
+            std::string(reinterpret_cast<const char*>(response.payload())));
+}
+
+TEST_F(RouterTest, BasicRequestResponse_Synchronous) {
+  internal::Router router0(handle0_.Pass(), internal::FilterChain());
+  internal::Router router1(handle1_.Pass(), internal::FilterChain());
+
+  ResponseGenerator generator;
+  router1.set_incoming_receiver(&generator);
+
+  Message request;
+  AllocRequestMessage(1, "hello", &request);
+
+  internal::MessageQueue message_queue;
+  router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue));
+
+  router1.WaitForIncomingMessage();
+  router0.WaitForIncomingMessage();
+
+  EXPECT_FALSE(message_queue.IsEmpty());
+
+  Message response;
+  message_queue.Pop(&response);
+
+  EXPECT_EQ(std::string("world"),
+            std::string(reinterpret_cast<const char*>(response.payload())));
+}
+
+TEST_F(RouterTest, RequestWithNoReceiver) {
+  internal::Router router0(handle0_.Pass(), internal::FilterChain());
+  internal::Router router1(handle1_.Pass(), internal::FilterChain());
+
+  // Without an incoming receiver set on router1, we expect router0 to observe
+  // an error as a result of sending a message.
+
+  Message request;
+  AllocRequestMessage(1, "hello", &request);
+
+  internal::MessageQueue message_queue;
+  router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue));
+
+  PumpMessages();
+
+  EXPECT_TRUE(router0.encountered_error());
+  EXPECT_TRUE(router1.encountered_error());
+  EXPECT_TRUE(message_queue.IsEmpty());
+}
+
+TEST_F(RouterTest, LateResponse) {
+  // Test that things won't blow up if we try to send a message to a
+  // MessageReceiver, which was given to us via AcceptWithResponder,
+  // after the router has gone away.
+
+  LazyResponseGenerator generator;
+  {
+    internal::Router router0(handle0_.Pass(), internal::FilterChain());
+    internal::Router router1(handle1_.Pass(), internal::FilterChain());
+
+    router1.set_incoming_receiver(&generator);
+
+    Message request;
+    AllocRequestMessage(1, "hello", &request);
+
+    internal::MessageQueue message_queue;
+    router0.AcceptWithResponder(&request,
+                                new MessageAccumulator(&message_queue));
+
+    PumpMessages();
+
+    EXPECT_TRUE(generator.has_responder());
+
+  }
+
+  generator.Complete();  // This should end up doing nothing.
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/sample_service_unittest.cc b/mojo/public/cpp/bindings/tests/sample_service_unittest.cc
new file mode 100644
index 0000000..2385772
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/sample_service_unittest.cc
@@ -0,0 +1,377 @@
+// Copyright 2014 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 <algorithm>
+#include <ostream>
+#include <string>
+
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/system/macros.h"
+#include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+
+template <>
+struct TypeConverter<int32_t, sample::BarPtr> {
+  static int32_t Convert(const sample::BarPtr& bar) {
+    return static_cast<int32_t>(bar->alpha) << 16 |
+           static_cast<int32_t>(bar->beta) << 8 |
+           static_cast<int32_t>(bar->gamma);
+  }
+};
+
+}  // namespace mojo
+
+namespace sample {
+namespace {
+
+// Set this variable to true to print the message in hex.
+bool g_dump_message_as_hex = false;
+
+// Set this variable to true to print the message in human readable form.
+bool g_dump_message_as_text = false;
+
+// Make a sample |Foo|.
+FooPtr MakeFoo() {
+  mojo::String name("foopy");
+
+  BarPtr bar(Bar::New());
+  bar->alpha = 20;
+  bar->beta = 40;
+  bar->gamma = 60;
+  bar->type = Bar::TYPE_VERTICAL;
+
+  mojo::Array<BarPtr> extra_bars(3);
+  for (size_t i = 0; i < extra_bars.size(); ++i) {
+    Bar::Type type = i % 2 == 0 ? Bar::TYPE_VERTICAL : Bar::TYPE_HORIZONTAL;
+    BarPtr bar(Bar::New());
+    uint8_t base = static_cast<uint8_t>(i * 100);
+    bar->alpha = base;
+    bar->beta = base + 20;
+    bar->gamma = base + 40;
+    bar->type = type;
+    extra_bars[i] = bar.Pass();
+  }
+
+  mojo::Array<uint8_t> data(10);
+  for (size_t i = 0; i < data.size(); ++i)
+    data[i] = static_cast<uint8_t>(data.size() - i);
+
+  mojo::Array<mojo::ScopedDataPipeConsumerHandle> input_streams(2);
+  mojo::Array<mojo::ScopedDataPipeProducerHandle> output_streams(2);
+  for (size_t i = 0; i < input_streams.size(); ++i) {
+    MojoCreateDataPipeOptions options;
+    options.struct_size = sizeof(MojoCreateDataPipeOptions);
+    options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
+    options.element_num_bytes = 1;
+    options.capacity_num_bytes = 1024;
+    mojo::ScopedDataPipeProducerHandle producer;
+    mojo::ScopedDataPipeConsumerHandle consumer;
+    mojo::CreateDataPipe(&options, &producer, &consumer);
+    input_streams[i] = consumer.Pass();
+    output_streams[i] = producer.Pass();
+  }
+
+  mojo::Array<mojo::Array<bool> > array_of_array_of_bools(2);
+  for (size_t i = 0; i < 2; ++i) {
+    mojo::Array<bool> array_of_bools(2);
+    for (size_t j = 0; j < 2; ++j)
+      array_of_bools[j] = j;
+    array_of_array_of_bools[i] = array_of_bools.Pass();
+  }
+
+  mojo::MessagePipe pipe;
+  FooPtr foo(Foo::New());
+  foo->name = name;
+  foo->x = 1;
+  foo->y = 2;
+  foo->a = false;
+  foo->b = true;
+  foo->c = false;
+  foo->bar = bar.Pass();
+  foo->extra_bars = extra_bars.Pass();
+  foo->data = data.Pass();
+  foo->source = pipe.handle1.Pass();
+  foo->input_streams = input_streams.Pass();
+  foo->output_streams = output_streams.Pass();
+  foo->array_of_array_of_bools = array_of_array_of_bools.Pass();
+
+  return foo.Pass();
+}
+
+// Check that the given |Foo| is identical to the one made by |MakeFoo()|.
+void CheckFoo(const Foo& foo) {
+  const std::string kName("foopy");
+  ASSERT_FALSE(foo.name.is_null());
+  EXPECT_EQ(kName.size(), foo.name.size());
+  for (size_t i = 0; i < std::min(kName.size(), foo.name.size()); i++) {
+    // Test both |operator[]| and |at|.
+    EXPECT_EQ(kName[i], foo.name.at(i)) << i;
+    EXPECT_EQ(kName[i], foo.name[i]) << i;
+  }
+  EXPECT_EQ(kName, foo.name.get());
+
+  EXPECT_EQ(1, foo.x);
+  EXPECT_EQ(2, foo.y);
+  EXPECT_FALSE(foo.a);
+  EXPECT_TRUE(foo.b);
+  EXPECT_FALSE(foo.c);
+
+  EXPECT_EQ(20, foo.bar->alpha);
+  EXPECT_EQ(40, foo.bar->beta);
+  EXPECT_EQ(60, foo.bar->gamma);
+  EXPECT_EQ(Bar::TYPE_VERTICAL, foo.bar->type);
+
+  EXPECT_EQ(3u, foo.extra_bars.size());
+  for (size_t i = 0; i < foo.extra_bars.size(); i++) {
+    uint8_t base = static_cast<uint8_t>(i * 100);
+    Bar::Type type = i % 2 == 0 ? Bar::TYPE_VERTICAL : Bar::TYPE_HORIZONTAL;
+    EXPECT_EQ(base, foo.extra_bars[i]->alpha) << i;
+    EXPECT_EQ(base + 20, foo.extra_bars[i]->beta) << i;
+    EXPECT_EQ(base + 40, foo.extra_bars[i]->gamma) << i;
+    EXPECT_EQ(type, foo.extra_bars[i]->type) << i;
+  }
+
+  EXPECT_EQ(10u, foo.data.size());
+  for (size_t i = 0; i < foo.data.size(); ++i) {
+    EXPECT_EQ(static_cast<uint8_t>(foo.data.size() - i), foo.data[i]) << i;
+  }
+
+  EXPECT_FALSE(foo.input_streams.is_null());
+  EXPECT_EQ(2u, foo.input_streams.size());
+
+  EXPECT_FALSE(foo.output_streams.is_null());
+  EXPECT_EQ(2u, foo.output_streams.size());
+
+  EXPECT_EQ(2u, foo.array_of_array_of_bools.size());
+  for (size_t i = 0; i < foo.array_of_array_of_bools.size(); ++i) {
+    EXPECT_EQ(2u, foo.array_of_array_of_bools[i].size());
+    for (size_t j = 0; j < foo.array_of_array_of_bools[i].size(); ++j) {
+      EXPECT_EQ(bool(j), foo.array_of_array_of_bools[i][j]);
+    }
+  }
+}
+
+void PrintSpacer(int depth) {
+  for (int i = 0; i < depth; ++i)
+    std::cout << "   ";
+}
+
+void Print(int depth, const char* name, bool value) {
+  PrintSpacer(depth);
+  std::cout << name << ": " << (value ? "true" : "false") << std::endl;
+}
+
+void Print(int depth, const char* name, int32_t value) {
+  PrintSpacer(depth);
+  std::cout << name << ": " << value << std::endl;
+}
+
+void Print(int depth, const char* name, uint8_t value) {
+  PrintSpacer(depth);
+  std::cout << name << ": " << uint32_t(value) << std::endl;
+}
+
+template <typename H>
+void Print(int depth, const char* name,
+           const mojo::ScopedHandleBase<H>& value) {
+  PrintSpacer(depth);
+  std::cout << name << ": 0x" << std::hex << value.get().value() << std::endl;
+}
+
+void Print(int depth, const char* name, const mojo::String& str) {
+  PrintSpacer(depth);
+  std::cout << name << ": \"" << str.get() << "\"" << std::endl;
+}
+
+void Print(int depth, const char* name, const BarPtr& bar) {
+  PrintSpacer(depth);
+  std::cout << name << ":" << std::endl;
+  if (!bar.is_null()) {
+    ++depth;
+    Print(depth, "alpha", bar->alpha);
+    Print(depth, "beta", bar->beta);
+    Print(depth, "gamma", bar->gamma);
+    Print(depth, "packed", bar.To<int32_t>());
+    --depth;
+  }
+}
+
+template <typename T>
+void Print(int depth, const char* name, const mojo::Array<T>& array) {
+  PrintSpacer(depth);
+  std::cout << name << ":" << std::endl;
+  if (!array.is_null()) {
+    ++depth;
+    for (size_t i = 0; i < array.size(); ++i) {
+      std::stringstream buf;
+      buf << i;
+      Print(depth, buf.str().data(), array.at(i));
+    }
+    --depth;
+  }
+}
+
+void Print(int depth, const char* name, const FooPtr& foo) {
+  PrintSpacer(depth);
+  std::cout << name << ":" << std::endl;
+  if (!foo.is_null()) {
+    ++depth;
+    Print(depth, "name", foo->name);
+    Print(depth, "x", foo->x);
+    Print(depth, "y", foo->y);
+    Print(depth, "a", foo->a);
+    Print(depth, "b", foo->b);
+    Print(depth, "c", foo->c);
+    Print(depth, "bar", foo->bar);
+    Print(depth, "extra_bars", foo->extra_bars);
+    Print(depth, "data", foo->data);
+    Print(depth, "source", foo->source);
+    Print(depth, "input_streams", foo->input_streams);
+    Print(depth, "output_streams", foo->output_streams);
+    Print(depth, "array_of_array_of_bools", foo->array_of_array_of_bools);
+    --depth;
+  }
+}
+
+void DumpHex(const uint8_t* bytes, uint32_t num_bytes) {
+  for (uint32_t i = 0; i < num_bytes; ++i) {
+    std::cout << std::setw(2) << std::setfill('0') << std::hex <<
+        uint32_t(bytes[i]);
+
+    if (i % 16 == 15) {
+      std::cout << std::endl;
+      continue;
+    }
+
+    if (i % 2 == 1)
+      std::cout << " ";
+    if (i % 8 == 7)
+      std::cout << " ";
+  }
+}
+
+class ServiceImpl : public Service {
+ public:
+  virtual void Frobinate(FooPtr foo, BazOptions baz, PortPtr port) override {
+    // Users code goes here to handle the incoming Frobinate message.
+
+    // We mainly check that we're given the expected arguments.
+    EXPECT_FALSE(foo.is_null());
+    if (!foo.is_null())
+      CheckFoo(*foo);
+    EXPECT_EQ(BAZ_OPTIONS_EXTRA, baz);
+
+    if (g_dump_message_as_text) {
+      // Also dump the Foo structure and all of its members.
+      std::cout << "Frobinate:" << std::endl;
+      int depth = 1;
+      Print(depth, "foo", foo);
+      Print(depth, "baz", baz);
+      Print(depth, "port", port.get());
+    }
+  }
+
+  virtual void GetPort(mojo::InterfaceRequest<Port> port_request) override {}
+};
+
+class ServiceProxyImpl : public ServiceProxy {
+ public:
+  explicit ServiceProxyImpl(mojo::MessageReceiverWithResponder* receiver)
+      : ServiceProxy(receiver) {
+  }
+};
+
+class SimpleMessageReceiver : public mojo::MessageReceiverWithResponder {
+ public:
+  virtual bool Accept(mojo::Message* message) override {
+    // Imagine some IPC happened here.
+
+    if (g_dump_message_as_hex) {
+      DumpHex(reinterpret_cast<const uint8_t*>(message->data()),
+              message->data_num_bytes());
+    }
+
+    // In the receiving process, an implementation of ServiceStub is known to
+    // the system. It receives the incoming message.
+    ServiceImpl impl;
+
+    ServiceStub stub;
+    stub.set_sink(&impl);
+    return stub.Accept(message);
+  }
+
+  virtual bool AcceptWithResponder(mojo::Message* message,
+                                   mojo::MessageReceiver* responder) override {
+    return false;
+  }
+};
+
+class BindingsSampleTest : public testing::Test {
+ public:
+  BindingsSampleTest() {}
+  virtual ~BindingsSampleTest() {}
+
+ private:
+  mojo::Environment env_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(BindingsSampleTest);
+};
+
+TEST_F(BindingsSampleTest, Basic) {
+  SimpleMessageReceiver receiver;
+
+  // User has a proxy to a Service somehow.
+  Service* service = new ServiceProxyImpl(&receiver);
+
+  // User constructs a message to send.
+
+  // Notice that it doesn't matter in what order the structs / arrays are
+  // allocated. Here, the various members of Foo are allocated before Foo is
+  // allocated.
+
+  FooPtr foo = MakeFoo();
+  CheckFoo(*foo);
+
+  PortPtr port;
+  service->Frobinate(foo.Pass(), Service::BAZ_OPTIONS_EXTRA, port.Pass());
+
+  delete service;
+}
+
+TEST_F(BindingsSampleTest, DefaultValues) {
+  DefaultsTestPtr defaults(DefaultsTest::New());
+  EXPECT_EQ(-12, defaults->a0);
+  EXPECT_EQ(kTwelve, defaults->a1);
+  EXPECT_EQ(1234, defaults->a2);
+  EXPECT_EQ(34567U, defaults->a3);
+  EXPECT_EQ(123456, defaults->a4);
+  EXPECT_EQ(3456789012U, defaults->a5);
+  EXPECT_EQ(-111111111111LL, defaults->a6);
+  EXPECT_EQ(9999999999999999999ULL, defaults->a7);
+  EXPECT_EQ(0x12345, defaults->a8);
+  EXPECT_EQ(-0x12345, defaults->a9);
+  EXPECT_EQ(1234, defaults->a10);
+  EXPECT_TRUE(defaults->a11);
+  EXPECT_FALSE(defaults->a12);
+  EXPECT_FLOAT_EQ(123.25f, defaults->a13);
+  EXPECT_DOUBLE_EQ(1234567890.123, defaults->a14);
+  EXPECT_DOUBLE_EQ(1E10, defaults->a15);
+  EXPECT_DOUBLE_EQ(-1.2E+20, defaults->a16);
+  EXPECT_DOUBLE_EQ(1.23E-20, defaults->a17);
+  EXPECT_TRUE(defaults->a18.is_null());
+  EXPECT_TRUE(defaults->a19.is_null());
+  EXPECT_EQ(Bar::TYPE_BOTH, defaults->a20);
+  EXPECT_TRUE(defaults->a21.is_null());
+  ASSERT_FALSE(defaults->a22.is_null());
+  EXPECT_EQ(imported::SHAPE_RECTANGLE, defaults->a22->shape);
+  EXPECT_EQ(imported::COLOR_BLACK, defaults->a22->color);
+  EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, defaults->a23);
+  EXPECT_EQ(0x123456789, defaults->a24);
+  EXPECT_EQ(-0x123456789, defaults->a25);
+}
+
+}  // namespace
+}  // namespace sample
diff --git a/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc b/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc
new file mode 100644
index 0000000..8709460
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc
@@ -0,0 +1,210 @@
+// Copyright 2014 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.
+
+// Serialization warnings are only recorded in debug build.
+#ifndef NDEBUG
+
+#include "mojo/public/cpp/bindings/array.h"
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/lib/array_serialization.h"
+#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
+#include "mojo/public/cpp/bindings/lib/validation_errors.h"
+#include "mojo/public/cpp/bindings/string.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "mojo/public/interfaces/bindings/tests/serialization_test_structs.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+namespace {
+
+using mojo::internal::ArrayValidateParams;
+using mojo::internal::NoValidateParams;
+
+// Creates an array of arrays of handles (2 X 3) for testing.
+Array<Array<ScopedHandle> > CreateTestNestedHandleArray() {
+  Array<Array<ScopedHandle> > array(2);
+  for (size_t i = 0; i < array.size(); ++i) {
+    Array<ScopedHandle> nested_array(3);
+    for (size_t j = 0; j < nested_array.size(); ++j) {
+      MessagePipe pipe;
+      nested_array[j] = ScopedHandle::From(pipe.handle1.Pass());
+    }
+    array[i] = nested_array.Pass();
+  }
+
+  return array.Pass();
+}
+
+class SerializationWarningTest : public testing::Test {
+ public:
+  virtual ~SerializationWarningTest() {}
+
+ protected:
+  template <typename T>
+  void TestWarning(T obj, mojo::internal::ValidationError expected_warning) {
+    warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE);
+
+    mojo::internal::FixedBuffer buf(GetSerializedSize_(obj));
+    typename T::Data_* data;
+    Serialize_(obj.Pass(), &buf, &data);
+
+    EXPECT_EQ(expected_warning, warning_observer_.last_warning());
+  }
+
+  template <typename ValidateParams, typename T>
+  void TestArrayWarning(T obj,
+                        mojo::internal::ValidationError expected_warning) {
+    warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE);
+
+    mojo::internal::FixedBuffer buf(GetSerializedSize_(obj));
+    typename T::Data_* data;
+    SerializeArray_<ValidateParams>(obj.Pass(), &buf, &data);
+
+    EXPECT_EQ(expected_warning, warning_observer_.last_warning());
+  }
+
+  mojo::internal::SerializationWarningObserverForTesting warning_observer_;
+  Environment env_;
+};
+
+TEST_F(SerializationWarningTest, HandleInStruct) {
+  Struct2Ptr test_struct(Struct2::New());
+  EXPECT_FALSE(test_struct->hdl.is_valid());
+
+  TestWarning(test_struct.Pass(),
+              mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE);
+
+  test_struct = Struct2::New();
+  MessagePipe pipe;
+  test_struct->hdl = ScopedHandle::From(pipe.handle1.Pass());
+
+  TestWarning(test_struct.Pass(), mojo::internal::VALIDATION_ERROR_NONE);
+}
+
+TEST_F(SerializationWarningTest, StructInStruct) {
+  Struct3Ptr test_struct(Struct3::New());
+  EXPECT_TRUE(!test_struct->struct_1);
+
+  TestWarning(test_struct.Pass(),
+              mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER);
+
+  test_struct = Struct3::New();
+  test_struct->struct_1 = Struct1::New();
+
+  TestWarning(test_struct.Pass(), mojo::internal::VALIDATION_ERROR_NONE);
+}
+
+TEST_F(SerializationWarningTest, ArrayOfStructsInStruct) {
+  Struct4Ptr test_struct(Struct4::New());
+  EXPECT_TRUE(!test_struct->data);
+
+  TestWarning(test_struct.Pass(),
+              mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER);
+
+  test_struct = Struct4::New();
+  test_struct->data.resize(1);
+
+  TestWarning(test_struct.Pass(),
+              mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER);
+
+  test_struct = Struct4::New();
+  test_struct->data.resize(0);
+
+  TestWarning(test_struct.Pass(), mojo::internal::VALIDATION_ERROR_NONE);
+
+  test_struct = Struct4::New();
+  test_struct->data.resize(1);
+  test_struct->data[0] = Struct1::New();
+
+  TestWarning(test_struct.Pass(), mojo::internal::VALIDATION_ERROR_NONE);
+}
+
+TEST_F(SerializationWarningTest, FixedArrayOfStructsInStruct) {
+  Struct5Ptr test_struct(Struct5::New());
+  EXPECT_TRUE(!test_struct->pair);
+
+  TestWarning(test_struct.Pass(),
+              mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER);
+
+  test_struct = Struct5::New();
+  test_struct->pair.resize(1);
+  test_struct->pair[0] = Struct1::New();
+
+  TestWarning(test_struct.Pass(),
+              mojo::internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER);
+
+  test_struct = Struct5::New();
+  test_struct->pair.resize(2);
+  test_struct->pair[0] = Struct1::New();
+  test_struct->pair[1] = Struct1::New();
+
+  TestWarning(test_struct.Pass(), mojo::internal::VALIDATION_ERROR_NONE);
+}
+
+TEST_F(SerializationWarningTest, StringInStruct) {
+  Struct6Ptr test_struct(Struct6::New());
+  EXPECT_TRUE(!test_struct->str);
+
+  TestWarning(test_struct.Pass(),
+              mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER);
+
+  test_struct = Struct6::New();
+  test_struct->str = "hello world";
+
+  TestWarning(test_struct.Pass(), mojo::internal::VALIDATION_ERROR_NONE);
+}
+
+TEST_F(SerializationWarningTest, ArrayOfArraysOfHandles) {
+  Array<Array<ScopedHandle> > test_array = CreateTestNestedHandleArray();
+  test_array[0] = Array<ScopedHandle>();
+  test_array[1][0] = ScopedHandle();
+
+  TestArrayWarning<ArrayValidateParams<0, true,
+                   ArrayValidateParams<0, true, NoValidateParams> > >(
+      test_array.Pass(), mojo::internal::VALIDATION_ERROR_NONE);
+
+  test_array = CreateTestNestedHandleArray();
+  test_array[0] = Array<ScopedHandle>();
+  TestArrayWarning<ArrayValidateParams<0, false,
+                   ArrayValidateParams<0, true, NoValidateParams> > >(
+      test_array.Pass(),
+      mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER);
+
+  test_array = CreateTestNestedHandleArray();
+  test_array[1][0] = ScopedHandle();
+  TestArrayWarning<ArrayValidateParams<0, true,
+                   ArrayValidateParams<0, false, NoValidateParams> > >(
+      test_array.Pass(),
+      mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE);
+}
+
+TEST_F(SerializationWarningTest, ArrayOfStrings) {
+  Array<String> test_array(3);
+  for (size_t i = 0; i < test_array.size(); ++i)
+    test_array[i] = "hello";
+
+  TestArrayWarning<ArrayValidateParams<0, true,
+                   ArrayValidateParams<0, false, NoValidateParams> > >(
+      test_array.Pass(), mojo::internal::VALIDATION_ERROR_NONE);
+
+  test_array = Array<String>(3);
+  TestArrayWarning<ArrayValidateParams<0, false,
+                   ArrayValidateParams<0, false, NoValidateParams> > >(
+      test_array.Pass(),
+      mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER);
+
+  test_array = Array<String>(2);
+  TestArrayWarning<ArrayValidateParams<3, true,
+                   ArrayValidateParams<0, false, NoValidateParams> > >(
+      test_array.Pass(),
+      mojo::internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER);
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace mojo
+
+#endif
diff --git a/mojo/public/cpp/bindings/tests/string_unittest.cc b/mojo/public/cpp/bindings/tests/string_unittest.cc
new file mode 100644
index 0000000..6f85443
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/string_unittest.cc
@@ -0,0 +1,65 @@
+// Copyright 2014 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/cpp/bindings/string.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+
+TEST(StringTest, DefaultIsNull) {
+  String s;
+  EXPECT_TRUE(s.is_null());
+}
+
+TEST(StringTest, ConstructedWithNULL) {
+  String s(nullptr);
+  EXPECT_TRUE(s.is_null());
+}
+
+TEST(StringTest, ConstructedWithNullCharPointer) {
+  const char* null = nullptr;
+  String s(null);
+  EXPECT_TRUE(s.is_null());
+}
+
+TEST(StringTest, AssignedNULL) {
+  String s("");
+  EXPECT_FALSE(s.is_null());
+  s = nullptr;
+  EXPECT_TRUE(s.is_null());
+}
+
+TEST(StringTest, Empty) {
+  String s("");
+  EXPECT_FALSE(s.is_null());
+  EXPECT_TRUE(s.get().empty());
+}
+
+TEST(StringTest, Basic) {
+  String s("hello world");
+  EXPECT_EQ(std::string("hello world"), s.get());
+}
+
+TEST(StringTest, Assignment) {
+  String s("hello world");
+  String t = s;  // Makes a copy.
+  EXPECT_FALSE(t.is_null());
+  EXPECT_EQ(std::string("hello world"), t.get());
+  EXPECT_FALSE(s.is_null());
+}
+
+TEST(StringTest, Equality) {
+  String s("hello world");
+  String t("hello world");
+  EXPECT_EQ(s, t);
+  EXPECT_TRUE(s == t);
+  EXPECT_TRUE("hello world" == s);
+  EXPECT_TRUE(s == "hello world");
+  EXPECT_TRUE("not" != s);
+  EXPECT_TRUE(s != "not");
+}
+
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/struct_unittest.cc b/mojo/public/cpp/bindings/tests/struct_unittest.cc
new file mode 100644
index 0000000..7d74498
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/struct_unittest.cc
@@ -0,0 +1,177 @@
+// Copyright 2014 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/cpp/bindings/lib/fixed_buffer.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+namespace {
+
+RectPtr MakeRect(int32_t factor = 1) {
+  RectPtr rect(Rect::New());
+  rect->x = 1 * factor;
+  rect->y = 2 * factor;
+  rect->width = 10 * factor;
+  rect->height = 20 * factor;
+  return rect.Pass();
+}
+
+void CheckRect(const Rect& rect, int32_t factor = 1) {
+  EXPECT_EQ(1 * factor, rect.x);
+  EXPECT_EQ(2 * factor, rect.y);
+  EXPECT_EQ(10 * factor, rect.width);
+  EXPECT_EQ(20 * factor, rect.height);
+}
+
+class StructTest : public testing::Test {
+ public:
+  virtual ~StructTest() {}
+
+ private:
+  Environment env_;
+};
+
+}  // namespace
+
+TEST_F(StructTest, Rect) {
+  RectPtr rect;
+  EXPECT_TRUE(rect.is_null());
+  EXPECT_TRUE(!rect);
+  EXPECT_FALSE(rect);
+
+  rect = MakeRect();
+  EXPECT_FALSE(rect.is_null());
+  EXPECT_FALSE(!rect);
+  EXPECT_TRUE(rect);
+
+  CheckRect(*rect);
+}
+
+TEST_F(StructTest, Clone) {
+  NamedRegionPtr region;
+
+  NamedRegionPtr clone_region = region.Clone();
+  EXPECT_TRUE(clone_region.is_null());
+
+  region = NamedRegion::New();
+  clone_region = region.Clone();
+  EXPECT_TRUE(clone_region->name.is_null());
+  EXPECT_TRUE(clone_region->rects.is_null());
+
+  region->name = "hello world";
+  clone_region = region.Clone();
+  EXPECT_EQ(region->name, clone_region->name);
+
+  region->rects = Array<RectPtr>(2);
+  region->rects[1] = MakeRect();
+  clone_region = region.Clone();
+  EXPECT_EQ(2u, clone_region->rects.size());
+  EXPECT_TRUE(clone_region->rects[0].is_null());
+  CheckRect(*clone_region->rects[1]);
+
+  // NoDefaultFieldValues contains handles, so Clone() is not available, but
+  // NoDefaultFieldValuesPtr should still compile.
+  NoDefaultFieldValuesPtr no_default_field_values(NoDefaultFieldValues::New());
+  EXPECT_FALSE(no_default_field_values->f13.is_valid());
+}
+
+// Serialization test of a struct with no pointer or handle members.
+TEST_F(StructTest, Serialization_Basic) {
+  RectPtr rect(MakeRect());
+
+  size_t size = GetSerializedSize_(rect);
+  EXPECT_EQ(8U + 16U, size);
+
+  mojo::internal::FixedBuffer buf(size);
+  internal::Rect_Data* data;
+  Serialize_(rect.Pass(), &buf, &data);
+
+  RectPtr rect2;
+  Deserialize_(data, &rect2);
+
+  CheckRect(*rect2);
+}
+
+// Serialization test of a struct with struct pointers.
+TEST_F(StructTest, Serialization_StructPointers) {
+  RectPairPtr pair(RectPair::New());
+  pair->first = MakeRect();
+  pair->second = MakeRect();
+
+  size_t size = GetSerializedSize_(pair);
+  EXPECT_EQ(8U + 16U + 2*(8U + 16U), size);
+
+  mojo::internal::FixedBuffer buf(size);
+  internal::RectPair_Data* data;
+  Serialize_(pair.Pass(), &buf, &data);
+
+  RectPairPtr pair2;
+  Deserialize_(data, &pair2);
+
+  CheckRect(*pair2->first);
+  CheckRect(*pair2->second);
+}
+
+// Serialization test of a struct with an array member.
+TEST_F(StructTest, Serialization_ArrayPointers) {
+  NamedRegionPtr region(NamedRegion::New());
+  region->name = "region";
+  region->rects = Array<RectPtr>::New(4);
+  for (size_t i = 0; i < region->rects.size(); ++i)
+    region->rects[i] = MakeRect(static_cast<int32_t>(i) + 1);
+
+  size_t size = GetSerializedSize_(region);
+  EXPECT_EQ(8U +  // header
+            8U +  // name pointer
+            8U +  // rects pointer
+            8U +  // name header
+            8U +  // name payload (rounded up)
+            8U +    // rects header
+            4*8U +  // rects payload (four pointers)
+            4*(8U +   // rect header
+               16U),  // rect payload (four ints)
+            size);
+
+  mojo::internal::FixedBuffer buf(size);
+  internal::NamedRegion_Data* data;
+  Serialize_(region.Pass(), &buf, &data);
+
+  NamedRegionPtr region2;
+  Deserialize_(data, &region2);
+
+  EXPECT_EQ(String("region"), region2->name);
+
+  EXPECT_EQ(4U, region2->rects.size());
+  for (size_t i = 0; i < region2->rects.size(); ++i)
+    CheckRect(*region2->rects[i], static_cast<int32_t>(i) + 1);
+}
+
+// Serialization test of a struct with null array pointers.
+TEST_F(StructTest, Serialization_NullArrayPointers) {
+  NamedRegionPtr region(NamedRegion::New());
+  EXPECT_TRUE(region->name.is_null());
+  EXPECT_TRUE(region->rects.is_null());
+
+  size_t size = GetSerializedSize_(region);
+  EXPECT_EQ(8U +  // header
+            8U +  // name pointer
+            8U,   // rects pointer
+            size);
+
+  mojo::internal::FixedBuffer buf(size);
+  internal::NamedRegion_Data* data;
+  Serialize_(region.Pass(), &buf, &data);
+
+  NamedRegionPtr region2;
+  Deserialize_(data, &region2);
+
+  EXPECT_TRUE(region2->name.is_null());
+  EXPECT_TRUE(region2->rects.is_null());
+}
+
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/type_conversion_unittest.cc b/mojo/public/cpp/bindings/tests/type_conversion_unittest.cc
new file mode 100644
index 0000000..9500839
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/type_conversion_unittest.cc
@@ -0,0 +1,208 @@
+// Copyright 2013 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/cpp/environment/environment.h"
+#include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+struct RedmondRect {
+  int32_t left;
+  int32_t top;
+  int32_t right;
+  int32_t bottom;
+};
+
+struct RedmondNamedRegion {
+  std::string name;
+  std::vector<RedmondRect> rects;
+};
+
+bool AreEqualRectArrays(const Array<test::RectPtr>& rects1,
+                        const Array<test::RectPtr>& rects2) {
+  if (rects1.size() != rects2.size())
+    return false;
+
+  for (size_t i = 0; i < rects1.size(); ++i) {
+    if (rects1[i]->x != rects2[i]->x ||
+        rects1[i]->y != rects2[i]->y ||
+        rects1[i]->width != rects2[i]->width ||
+        rects1[i]->height != rects2[i]->height) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace
+
+template <>
+struct TypeConverter<test::RectPtr, RedmondRect> {
+  static test::RectPtr Convert(const RedmondRect& input) {
+    test::RectPtr rect(test::Rect::New());
+    rect->x = input.left;
+    rect->y = input.top;
+    rect->width = input.right - input.left;
+    rect->height = input.bottom - input.top;
+    return rect.Pass();
+  }
+};
+
+template <>
+struct TypeConverter<RedmondRect, test::RectPtr> {
+  static RedmondRect Convert(const test::RectPtr& input) {
+    RedmondRect rect;
+    rect.left = input->x;
+    rect.top = input->y;
+    rect.right = input->x + input->width;
+    rect.bottom = input->y + input->height;
+    return rect;
+  }
+};
+
+template <>
+struct TypeConverter<test::NamedRegionPtr, RedmondNamedRegion> {
+  static test::NamedRegionPtr Convert(const RedmondNamedRegion& input) {
+    test::NamedRegionPtr region(test::NamedRegion::New());
+    region->name = input.name;
+    region->rects = Array<test::RectPtr>::From(input.rects);
+    return region.Pass();
+  }
+};
+
+template <>
+struct TypeConverter<RedmondNamedRegion, test::NamedRegionPtr> {
+  static RedmondNamedRegion Convert(const test::NamedRegionPtr& input) {
+    RedmondNamedRegion region;
+    region.name = input->name;
+    region.rects = input->rects.To<std::vector<RedmondRect> >();
+    return region;
+  }
+};
+
+namespace test {
+namespace {
+
+TEST(TypeConversionTest, String) {
+  const char kText[6] = "hello";
+
+  String a = std::string(kText);
+  String b(kText);
+  String c(static_cast<const char*>(kText));
+
+  EXPECT_EQ(std::string(kText), a.To<std::string>());
+  EXPECT_EQ(std::string(kText), b.To<std::string>());
+  EXPECT_EQ(std::string(kText), c.To<std::string>());
+}
+
+TEST(TypeConversionTest, String_Null) {
+  String a;
+  EXPECT_TRUE(a.is_null());
+  EXPECT_EQ(std::string(), a.To<std::string>());
+
+  String b = String::From(static_cast<const char*>(nullptr));
+  EXPECT_TRUE(b.is_null());
+}
+
+TEST(TypeConversionTest, String_Empty) {
+  String a = "";
+  EXPECT_EQ(std::string(), a.To<std::string>());
+
+  String b = std::string();
+  EXPECT_FALSE(b.is_null());
+  EXPECT_EQ(std::string(), b.To<std::string>());
+}
+
+TEST(TypeConversionTest, StringWithEmbeddedNull) {
+  const std::string kText("hel\0lo", 6);
+
+  String a(kText);
+  EXPECT_EQ(kText, a.To<std::string>());
+
+  // Expect truncation:
+  String b(kText.c_str());
+  EXPECT_EQ(std::string("hel"), b.To<std::string>());
+}
+
+TEST(TypeConversionTest, CustomTypeConverter) {
+  RectPtr rect(Rect::New());
+  rect->x = 10;
+  rect->y = 20;
+  rect->width = 50;
+  rect->height = 45;
+
+  RedmondRect rr = rect.To<RedmondRect>();
+  EXPECT_EQ(10, rr.left);
+  EXPECT_EQ(20, rr.top);
+  EXPECT_EQ(60, rr.right);
+  EXPECT_EQ(65, rr.bottom);
+
+  RectPtr rect2(Rect::From(rr));
+  EXPECT_EQ(rect->x, rect2->x);
+  EXPECT_EQ(rect->y, rect2->y);
+  EXPECT_EQ(rect->width, rect2->width);
+  EXPECT_EQ(rect->height, rect2->height);
+}
+
+TEST(TypeConversionTest, CustomTypeConverter_Array_Null) {
+  Array<RectPtr> rects;
+
+  std::vector<RedmondRect> redmond_rects =
+      rects.To<std::vector<RedmondRect> >();
+
+  EXPECT_TRUE(redmond_rects.empty());
+}
+
+TEST(TypeConversionTest, CustomTypeConverter_Array) {
+  const RedmondRect kBase = { 10, 20, 30, 40 };
+
+  Array<RectPtr> rects(10);
+  for (size_t i = 0; i < rects.size(); ++i) {
+    RedmondRect rr = kBase;
+    rr.left += static_cast<int32_t>(i);
+    rr.top += static_cast<int32_t>(i);
+    rects[i] = Rect::From(rr);
+  }
+
+  std::vector<RedmondRect> redmond_rects =
+      rects.To<std::vector<RedmondRect> >();
+
+  Array<RectPtr> rects2 = Array<RectPtr>::From(redmond_rects);
+  EXPECT_TRUE(AreEqualRectArrays(rects, rects2));
+}
+
+TEST(TypeConversionTest, CustomTypeConverter_Nested) {
+  RedmondNamedRegion redmond_region;
+  redmond_region.name = "foopy";
+
+  const RedmondRect kBase = { 10, 20, 30, 40 };
+
+  for (size_t i = 0; i < 10; ++i) {
+    RedmondRect rect = kBase;
+    rect.left += static_cast<int32_t>(i);
+    rect.top += static_cast<int32_t>(i);
+    redmond_region.rects.push_back(rect);
+  }
+
+  // Round-trip through generated struct and TypeConverter.
+
+  NamedRegionPtr copy = NamedRegion::From(redmond_region);
+  RedmondNamedRegion redmond_region2 = copy.To<RedmondNamedRegion>();
+
+  EXPECT_EQ(redmond_region.name, redmond_region2.name);
+  EXPECT_EQ(redmond_region.rects.size(), redmond_region2.rects.size());
+  for (size_t i = 0; i < redmond_region.rects.size(); ++i) {
+    EXPECT_EQ(redmond_region.rects[i].left, redmond_region2.rects[i].left);
+    EXPECT_EQ(redmond_region.rects[i].top, redmond_region2.rects[i].top);
+    EXPECT_EQ(redmond_region.rects[i].right, redmond_region2.rects[i].right);
+    EXPECT_EQ(redmond_region.rects[i].bottom, redmond_region2.rects[i].bottom);
+  }
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/validation_test_input_parser.cc b/mojo/public/cpp/bindings/tests/validation_test_input_parser.cc
new file mode 100644
index 0000000..f5b5a01
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/validation_test_input_parser.cc
@@ -0,0 +1,406 @@
+// Copyright 2014 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/cpp/bindings/tests/validation_test_input_parser.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <limits>
+#include <map>
+#include <set>
+#include <utility>
+
+#include "mojo/public/c/system/macros.h"
+
+namespace mojo {
+namespace test {
+namespace {
+
+class ValidationTestInputParser {
+ public:
+  ValidationTestInputParser(const std::string& input,
+                            std::vector<uint8_t>* data,
+                            size_t* num_handles,
+                            std::string* error_message);
+  ~ValidationTestInputParser();
+
+  bool Run();
+
+ private:
+  struct DataType;
+
+  typedef std::pair<const char*, const char*> Range;
+
+  typedef bool (ValidationTestInputParser::*ParseDataFunc)(
+      const DataType& type, const std::string& value_string);
+
+  struct DataType {
+    const char* name;
+    size_t name_size;
+    size_t data_size;
+    ParseDataFunc parse_data_func;
+  };
+
+  // A dist4/8 item that hasn't been matched with an anchr item.
+  struct PendingDistanceItem {
+    // Where this data item is located in |data_|.
+    size_t pos;
+    // Either 4 or 8 (bytes).
+    size_t data_size;
+  };
+
+  bool GetNextItem(Range* range);
+
+  bool ParseItem(const Range& range);
+
+  bool ParseUnsignedInteger(const DataType& type,
+                            const std::string& value_string);
+  bool ParseSignedInteger(const DataType& type,
+                          const std::string& value_string);
+  bool ParseFloat(const DataType& type, const std::string& value_string);
+  bool ParseDouble(const DataType& type, const std::string& value_string);
+  bool ParseBinarySequence(const DataType& type,
+                           const std::string& value_string);
+  bool ParseDistance(const DataType& type, const std::string& value_string);
+  bool ParseAnchor(const DataType& type, const std::string& value_string);
+  bool ParseHandles(const DataType& type, const std::string& value_string);
+
+  bool StartsWith(const Range& range, const char* prefix, size_t prefix_length);
+
+  bool ConvertToUnsignedInteger(const std::string& value_string,
+                                unsigned long long int* value);
+
+  template <typename T>
+  void AppendData(T data) {
+    size_t pos = data_->size();
+    data_->resize(pos + sizeof(T));
+    memcpy(&(*data_)[pos], &data, sizeof(T));
+  }
+
+  template <typename TargetType, typename InputType>
+  bool ConvertAndAppendData(InputType value) {
+    if (value > std::numeric_limits<TargetType>::max() ||
+        value < std::numeric_limits<TargetType>::min()) {
+      return false;
+    }
+    AppendData(static_cast<TargetType>(value));
+    return true;
+  }
+
+  template <typename TargetType, typename InputType>
+  bool ConvertAndFillData(size_t pos, InputType value) {
+    if (value > std::numeric_limits<TargetType>::max() ||
+        value < std::numeric_limits<TargetType>::min()) {
+      return false;
+    }
+    TargetType target_value = static_cast<TargetType>(value);
+    assert(pos + sizeof(TargetType) <= data_->size());
+    memcpy(&(*data_)[pos], &target_value, sizeof(TargetType));
+    return true;
+  }
+
+  static const DataType kDataTypes[];
+  static const size_t kDataTypeCount;
+
+  const std::string& input_;
+  size_t input_cursor_;
+
+  std::vector<uint8_t>* data_;
+  size_t* num_handles_;
+  std::string* error_message_;
+
+  std::map<std::string, PendingDistanceItem> pending_distance_items_;
+  std::set<std::string> anchors_;
+};
+
+#define DATA_TYPE(name, data_size, parse_data_func) \
+    {name, sizeof(name) - 1, data_size, parse_data_func}
+
+const ValidationTestInputParser::DataType
+    ValidationTestInputParser::kDataTypes[] = {
+  DATA_TYPE("[u1]", 1, &ValidationTestInputParser::ParseUnsignedInteger),
+  DATA_TYPE("[u2]", 2, &ValidationTestInputParser::ParseUnsignedInteger),
+  DATA_TYPE("[u4]", 4, &ValidationTestInputParser::ParseUnsignedInteger),
+  DATA_TYPE("[u8]", 8, &ValidationTestInputParser::ParseUnsignedInteger),
+  DATA_TYPE("[s1]", 1, &ValidationTestInputParser::ParseSignedInteger),
+  DATA_TYPE("[s2]", 2, &ValidationTestInputParser::ParseSignedInteger),
+  DATA_TYPE("[s4]", 4, &ValidationTestInputParser::ParseSignedInteger),
+  DATA_TYPE("[s8]", 8, &ValidationTestInputParser::ParseSignedInteger),
+  DATA_TYPE("[b]", 1, &ValidationTestInputParser::ParseBinarySequence),
+  DATA_TYPE("[f]", 4, &ValidationTestInputParser::ParseFloat),
+  DATA_TYPE("[d]", 8, &ValidationTestInputParser::ParseDouble),
+  DATA_TYPE("[dist4]", 4, &ValidationTestInputParser::ParseDistance),
+  DATA_TYPE("[dist8]", 8, &ValidationTestInputParser::ParseDistance),
+  DATA_TYPE("[anchr]", 0, &ValidationTestInputParser::ParseAnchor),
+  DATA_TYPE("[handles]", 0, &ValidationTestInputParser::ParseHandles)
+};
+
+const size_t ValidationTestInputParser::kDataTypeCount =
+    sizeof(ValidationTestInputParser::kDataTypes) /
+    sizeof(ValidationTestInputParser::kDataTypes[0]);
+
+ValidationTestInputParser::ValidationTestInputParser(
+    const std::string& input,
+    std::vector<uint8_t>* data,
+    size_t* num_handles,
+    std::string* error_message)
+    : input_(input),
+      input_cursor_(0),
+      data_(data),
+      num_handles_(num_handles),
+      error_message_(error_message) {
+  assert(data_);
+  assert(num_handles_);
+  assert(error_message_);
+  data_->clear();
+  *num_handles_ = 0;
+  error_message_->clear();
+}
+
+ValidationTestInputParser::~ValidationTestInputParser() {
+}
+
+bool ValidationTestInputParser::Run() {
+  Range range;
+  bool result = true;
+  while (result && GetNextItem(&range))
+    result = ParseItem(range);
+
+  if (!result) {
+    *error_message_ = "Error occurred when parsing " +
+        std::string(range.first, range.second);
+  } else if (!pending_distance_items_.empty()) {
+    // We have parsed all the contents in |input_| successfully, but there are
+    // unmatched dist4/8 items.
+    *error_message_ = "Error occurred when matching [dist4/8] and [anchr].";
+    result = false;
+  }
+  if (!result) {
+    data_->clear();
+    *num_handles_ = 0;
+  } else {
+    assert(error_message_->empty());
+  }
+
+  return result;
+}
+
+bool ValidationTestInputParser::GetNextItem(Range* range) {
+  const char kWhitespaceChars[] = " \t\n\r";
+  const char kItemDelimiters[] = " \t\n\r/";
+  const char kEndOfLineChars[] = "\n\r";
+  while (true) {
+    // Skip leading whitespaces.
+    // If there are no non-whitespace characters left, |input_cursor_| will be
+    // set to std::npos.
+    input_cursor_ = input_.find_first_not_of(kWhitespaceChars, input_cursor_);
+
+    if (input_cursor_ >= input_.size())
+      return false;
+
+    if (StartsWith(Range(&input_[0] + input_cursor_,
+                         &input_[0] + input_.size()),
+                   "//", 2)) {
+      // Skip contents until the end of the line.
+      input_cursor_ = input_.find_first_of(kEndOfLineChars, input_cursor_);
+    } else {
+      range->first = &input_[0] + input_cursor_;
+      input_cursor_ = input_.find_first_of(kItemDelimiters, input_cursor_);
+      range->second = input_cursor_ >= input_.size() ?
+          &input_[0] + input_.size() : &input_[0] + input_cursor_;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool ValidationTestInputParser::ParseItem(const Range& range) {
+  for (size_t i = 0; i < kDataTypeCount; ++i) {
+    if (StartsWith(range, kDataTypes[i].name, kDataTypes[i].name_size)) {
+      return (this->*kDataTypes[i].parse_data_func)(
+          kDataTypes[i],
+          std::string(range.first + kDataTypes[i].name_size, range.second));
+    }
+  }
+
+  // "[u1]" is optional.
+  return ParseUnsignedInteger(kDataTypes[0],
+                              std::string(range.first, range.second));
+}
+
+bool ValidationTestInputParser::ParseUnsignedInteger(
+    const DataType& type, const std::string& value_string) {
+  unsigned long long int value;
+  if (!ConvertToUnsignedInteger(value_string, &value))
+    return false;
+
+  switch (type.data_size) {
+    case 1:
+      return ConvertAndAppendData<uint8_t>(value);
+    case 2:
+      return ConvertAndAppendData<uint16_t>(value);
+    case 4:
+      return ConvertAndAppendData<uint32_t>(value);
+    case 8:
+      return ConvertAndAppendData<uint64_t>(value);
+    default:
+      assert(false);
+      return false;
+  }
+}
+
+bool ValidationTestInputParser::ParseSignedInteger(
+    const DataType& type, const std::string& value_string) {
+  long long int value;
+  if (sscanf(value_string.c_str(), "%lli", &value) != 1)
+    return false;
+
+  switch (type.data_size) {
+    case 1:
+      return ConvertAndAppendData<int8_t>(value);
+    case 2:
+      return ConvertAndAppendData<int16_t>(value);
+    case 4:
+      return ConvertAndAppendData<int32_t>(value);
+    case 8:
+      return ConvertAndAppendData<int64_t>(value);
+    default:
+      assert(false);
+      return false;
+  }
+}
+
+bool ValidationTestInputParser::ParseFloat(
+    const DataType& type, const std::string& value_string) {
+  MOJO_COMPILE_ASSERT(sizeof(float) == 4, float_size_is_not_4);
+
+  float value;
+  if (sscanf(value_string.c_str(), "%f", &value) != 1)
+    return false;
+
+  AppendData(value);
+  return true;
+}
+
+bool ValidationTestInputParser::ParseDouble(const DataType& type,
+                                            const std::string& value_string) {
+  MOJO_COMPILE_ASSERT(sizeof(double) == 8, double_size_is_not_8);
+
+  double value;
+  if (sscanf(value_string.c_str(), "%lf", &value) != 1)
+    return false;
+
+  AppendData(value);
+  return true;
+}
+
+bool ValidationTestInputParser::ParseBinarySequence(
+    const DataType& type, const std::string& value_string) {
+  if (value_string.size() != 8)
+    return false;
+
+  uint8_t value = 0;
+  for (std::string::const_iterator iter = value_string.begin();
+       iter != value_string.end();
+       ++iter) {
+    value <<= 1;
+    if (*iter == '1')
+      value++;
+    else if (*iter != '0')
+      return false;
+  }
+  AppendData(value);
+  return true;
+}
+
+bool ValidationTestInputParser::ParseDistance(const DataType& type,
+                                              const std::string& value_string) {
+  if (pending_distance_items_.find(value_string) !=
+      pending_distance_items_.end())
+    return false;
+
+  PendingDistanceItem item = {data_->size(), type.data_size};
+  data_->resize(data_->size() + type.data_size);
+  pending_distance_items_[value_string] = item;
+
+  return true;
+}
+
+bool ValidationTestInputParser::ParseAnchor(const DataType& type,
+                                            const std::string& value_string) {
+  if (anchors_.find(value_string) != anchors_.end())
+    return false;
+  anchors_.insert(value_string);
+
+  std::map<std::string, PendingDistanceItem>::iterator iter =
+      pending_distance_items_.find(value_string);
+  if (iter == pending_distance_items_.end())
+    return false;
+
+  PendingDistanceItem dist_item = iter->second;
+  pending_distance_items_.erase(iter);
+
+  size_t distance = data_->size() - dist_item.pos;
+  switch (dist_item.data_size) {
+    case 4:
+      return ConvertAndFillData<uint32_t>(dist_item.pos, distance);
+    case 8:
+      return ConvertAndFillData<uint64_t>(dist_item.pos, distance);
+    default:
+      assert(false);
+      return false;
+  }
+}
+
+bool ValidationTestInputParser::ParseHandles(const DataType& type,
+                                             const std::string& value_string) {
+  // It should be the first item.
+  if (!data_->empty())
+    return false;
+
+  unsigned long long int value;
+  if (!ConvertToUnsignedInteger(value_string, &value))
+    return false;
+
+  if (value > std::numeric_limits<size_t>::max())
+    return false;
+
+  *num_handles_ = static_cast<size_t>(value);
+  return true;
+}
+
+bool ValidationTestInputParser::StartsWith(const Range& range,
+                                           const char* prefix,
+                                           size_t prefix_length) {
+  if (static_cast<size_t>(range.second - range.first) < prefix_length)
+    return false;
+
+  return memcmp(range.first, prefix, prefix_length) == 0;
+}
+
+bool ValidationTestInputParser::ConvertToUnsignedInteger(
+    const std::string& value_string,
+    unsigned long long int* value) {
+  const char* format = nullptr;
+  if (value_string.find_first_of("xX") != std::string::npos)
+    format = "%llx";
+  else
+    format = "%llu";
+  return sscanf(value_string.c_str(), format, value) == 1;
+}
+
+}  // namespace
+
+bool ParseValidationTestInput(const std::string& input,
+                              std::vector<uint8_t>* data,
+                              size_t* num_handles,
+                              std::string* error_message) {
+  ValidationTestInputParser parser(input, data, num_handles, error_message);
+  return parser.Run();
+}
+
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/validation_test_input_parser.h b/mojo/public/cpp/bindings/tests/validation_test_input_parser.h
new file mode 100644
index 0000000..c8821cd
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/validation_test_input_parser.h
@@ -0,0 +1,120 @@
+// Copyright 2014 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_CPP_BINDINGS_TESTS_VALIDATION_TEST_INPUT_PARSER_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_TESTS_VALIDATION_TEST_INPUT_PARSER_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+namespace mojo {
+namespace test {
+
+// Input Format of Mojo Message Validation Tests.
+//
+// Data items are separated by whitespaces:
+//   - ' ' (0x20) space;
+//   - '\t' (0x09) horizontal tab;
+//   - '\n' (0x0a) newline;
+//   - '\r' (0x0d) carriage return.
+// A comment starts with //, extending to the end of the line.
+// Each data item is of the format [<type>]<value>. The types defined and the
+// corresponding value formats are described below.
+//
+// Type: u1 / u2 / u4 / u8
+// Description: Little-endian 1/2/4/8-byte unsigned integer.
+// Value Format:
+//   - Decimal integer: 0|[1-9][0-9]*
+//   - Hexadecimal integer: 0[xX][0-9a-fA-F]+
+//   - The type prefix (including the square brackets) of 1-byte unsigned
+//   integer is optional.
+//
+// Type: s1 / s2 / s4 / s8
+// Description: Little-endian 1/2/4/8-byte signed integer.
+// Value Format:
+//   - Decimal integer: [-+]?(0|[1-9][0-9]*)
+//   - Hexadecimal integer: [-+]?0[xX][0-9a-fA-F]+
+//
+// Type: b
+// Description: Binary sequence of 1 byte.
+// Value Format: [01]{8}
+//
+// Type: f / d
+// Description: Little-endian IEEE-754 format of float (4 bytes) and double (8
+// bytes).
+// Value Format: [-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?
+//
+// Type: dist4 / dist8
+// Description: Little-endian 4/8-byte unsigned integer. The actual value is set
+// to the byte distance from the location of this integer to the location of the
+// anchr item with the same ID. A dist8 and anchr pair can be used to easily
+// represent an encoded pointer. A dist4 and anchr pair can be used to easily
+// calculate struct/array size.
+// Value Format: The value is an ID: [0-9a-zA-Z_]+
+//
+// Type: anchr
+// Description: Mark an anchor location. It doesn’t translate into any actual
+// data.
+// Value Format: The value is an ID of the same format as that of dist4/8.
+//
+// Type: handles
+// Description: The number of handles that are associated with the message. This
+// special item is not part of the message data. If specified, it should be the
+// first item.
+// Value Format: The same format as u1/2/4/8.
+//
+// EXAMPLE:
+//
+// Suppose you have the following Mojo types defined:
+//   struct Bar {
+//     int32 a;
+//     bool b;
+//     bool c;
+//   };
+//   struct Foo {
+//     Bar x;
+//     uint32 y;
+//   };
+//
+// The following describes a valid message whose payload is a Foo struct:
+//   // message header
+//   [dist4]message_header   // num_bytes
+//   [u4]3                   // num_fields
+//   [u4]0                   // type
+//   [u4]1                   // flags
+//   [u8]1234                // request_id
+//   [anchr]message_header
+//
+//   // payload
+//   [dist4]foo      // num_bytes
+//   [u4]2           // num_fields
+//   [dist8]bar_ptr  // x
+//   [u4]0xABCD      // y
+//   [u4]0           // padding
+//   [anchr]foo
+//
+//   [anchr]bar_ptr
+//   [dist4]bar   // num_bytes
+//   [u4]3        // num_fields
+//   [s4]-1       // a
+//   [b]00000010  // b and c
+//   0 0 0        // padding
+//   [anchr]bar
+
+// Parses validation test input.
+// On success, |data| and |num_handles| store the parsing result,
+// |error_message| is cleared; on failure, |error_message| is set to a message
+// describing the error, |data| is cleared and |num_handles| set to 0.
+// Note: For now, this method only works on little-endian platforms.
+bool ParseValidationTestInput(const std::string& input,
+                              std::vector<uint8_t>* data,
+                              size_t* num_handles,
+                              std::string* error_message);
+
+}  // namespace test
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_TESTS_VALIDATION_TEST_INPUT_PARSER_H_
diff --git a/mojo/public/cpp/bindings/tests/validation_unittest.cc b/mojo/public/cpp/bindings/tests/validation_unittest.cc
new file mode 100644
index 0000000..bf0894c
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/validation_unittest.cc
@@ -0,0 +1,434 @@
+// Copyright 2014 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 <stdio.h>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "mojo/public/c/system/macros.h"
+#include "mojo/public/cpp/bindings/interface_impl.h"
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/public/cpp/bindings/lib/connector.h"
+#include "mojo/public/cpp/bindings/lib/filter_chain.h"
+#include "mojo/public/cpp/bindings/lib/message_header_validator.h"
+#include "mojo/public/cpp/bindings/lib/router.h"
+#include "mojo/public/cpp/bindings/lib/validation_errors.h"
+#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/bindings/tests/validation_test_input_parser.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/system/core.h"
+#include "mojo/public/cpp/test_support/test_support.h"
+#include "mojo/public/cpp/utility/run_loop.h"
+#include "mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+namespace {
+
+template <typename T>
+void Append(std::vector<uint8_t>* data_vector, T data) {
+  size_t pos = data_vector->size();
+  data_vector->resize(pos + sizeof(T));
+  memcpy(&(*data_vector)[pos], &data, sizeof(T));
+}
+
+bool TestInputParser(const std::string& input,
+                     bool expected_result,
+                     const std::vector<uint8_t>& expected_data,
+                     size_t expected_num_handles) {
+  std::vector<uint8_t> data;
+  size_t num_handles;
+  std::string error_message;
+
+  bool result = ParseValidationTestInput(input, &data, &num_handles,
+                                         &error_message);
+  if (expected_result) {
+    if (result && error_message.empty() &&
+        expected_data == data && expected_num_handles == num_handles) {
+      return true;
+    }
+
+    // Compare with an empty string instead of checking |error_message.empty()|,
+    // so that the message will be printed out if the two are not equal.
+    EXPECT_EQ(std::string(), error_message);
+    EXPECT_EQ(expected_data, data);
+    EXPECT_EQ(expected_num_handles, num_handles);
+    return false;
+  }
+
+  EXPECT_FALSE(error_message.empty());
+  return !result && !error_message.empty();
+}
+
+std::vector<std::string> GetMatchingTests(const std::vector<std::string>& names,
+                                          const std::string& prefix) {
+  const std::string suffix = ".data";
+  std::vector<std::string> tests;
+  for (size_t i = 0; i < names.size(); ++i) {
+    if (names[i].size() >= suffix.size() &&
+        names[i].substr(0, prefix.size()) == prefix &&
+        names[i].substr(names[i].size() - suffix.size()) == suffix)
+      tests.push_back(names[i].substr(0, names[i].size() - suffix.size()));
+  }
+  return tests;
+}
+
+bool ReadFile(const std::string& path, std::string* result) {
+  FILE* fp = OpenSourceRootRelativeFile(path.c_str());
+  if (!fp) {
+    ADD_FAILURE() << "File not found: " << path;
+    return false;
+  }
+  fseek(fp, 0, SEEK_END);
+  size_t size = static_cast<size_t>(ftell(fp));
+  if (size == 0) {
+    result->clear();
+    fclose(fp);
+    return true;
+  }
+  fseek(fp, 0, SEEK_SET);
+  result->resize(size);
+  size_t size_read = fread(&result->at(0), 1, size, fp);
+  fclose(fp);
+  return size == size_read;
+}
+
+bool ReadAndParseDataFile(const std::string& path,
+                          std::vector<uint8_t>* data,
+                          size_t* num_handles) {
+  std::string input;
+  if (!ReadFile(path, &input))
+    return false;
+
+  std::string error_message;
+  if (!ParseValidationTestInput(input, data, num_handles, &error_message)) {
+    ADD_FAILURE() << error_message;
+    return false;
+  }
+
+  return true;
+}
+
+bool ReadResultFile(const std::string& path, std::string* result) {
+  if (!ReadFile(path, result))
+    return false;
+
+  // Result files are new-line delimited text files. Remove any CRs.
+  result->erase(std::remove(result->begin(), result->end(), '\r'),
+                result->end());
+
+  // Remove trailing LFs.
+  size_t pos = result->find_last_not_of('\n');
+  if (pos == std::string::npos)
+    result->clear();
+  else
+    result->resize(pos + 1);
+
+  return true;
+}
+
+std::string GetPath(const std::string& root, const std::string& suffix) {
+  return "mojo/public/interfaces/bindings/tests/data/validation/" +
+      root + suffix;
+}
+
+// |message| should be a newly created object.
+bool ReadTestCase(const std::string& test,
+                  Message* message,
+                  std::string* expected) {
+  std::vector<uint8_t> data;
+  size_t num_handles;
+  if (!ReadAndParseDataFile(GetPath(test, ".data"), &data, &num_handles) ||
+      !ReadResultFile(GetPath(test, ".expected"), expected)) {
+    return false;
+  }
+
+  message->AllocUninitializedData(static_cast<uint32_t>(data.size()));
+  if (!data.empty())
+    memcpy(message->mutable_data(), &data[0], data.size());
+  message->mutable_handles()->resize(num_handles);
+
+  return true;
+}
+
+void RunValidationTests(const std::string& prefix,
+                        MessageReceiver* test_message_receiver) {
+  std::vector<std::string> names =
+      EnumerateSourceRootRelativeDirectory(GetPath("", ""));
+  std::vector<std::string> tests = GetMatchingTests(names, prefix);
+
+  for (size_t i = 0; i < tests.size(); ++i) {
+    Message message;
+    std::string expected;
+    ASSERT_TRUE(ReadTestCase(tests[i], &message, &expected));
+
+    std::string result;
+    mojo::internal::ValidationErrorObserverForTesting observer;
+    bool unused MOJO_ALLOW_UNUSED = test_message_receiver->Accept(&message);
+    if (observer.last_error() == mojo::internal::VALIDATION_ERROR_NONE)
+      result = "PASS";
+    else
+      result = mojo::internal::ValidationErrorToString(observer.last_error());
+
+    EXPECT_EQ(expected, result) << "failed test: " << tests[i];
+  }
+}
+
+class DummyMessageReceiver : public MessageReceiver {
+ public:
+  virtual bool Accept(Message* message) override {
+    return true;  // Any message is OK.
+  }
+};
+
+class ValidationTest : public testing::Test {
+ public:
+  virtual ~ValidationTest() {
+  }
+
+ private:
+  Environment env_;
+};
+
+class ValidationIntegrationTest : public ValidationTest {
+ public:
+  ValidationIntegrationTest() : test_message_receiver_(nullptr) {
+  }
+
+  virtual ~ValidationIntegrationTest() {
+  }
+
+  virtual void SetUp() override {
+    ScopedMessagePipeHandle tester_endpoint;
+    ASSERT_EQ(MOJO_RESULT_OK,
+              CreateMessagePipe(nullptr, &tester_endpoint, &testee_endpoint_));
+    test_message_receiver_ =
+        new TestMessageReceiver(this, tester_endpoint.Pass());
+  }
+
+  virtual void TearDown() override {
+    delete test_message_receiver_;
+    test_message_receiver_ = nullptr;
+
+    // Make sure that the other end receives the OnConnectionError()
+    // notification.
+    PumpMessages();
+  }
+
+  MessageReceiver* test_message_receiver() {
+    return test_message_receiver_;
+  }
+
+  ScopedMessagePipeHandle testee_endpoint() {
+    return testee_endpoint_.Pass();
+  }
+
+ private:
+  class TestMessageReceiver : public MessageReceiver {
+   public:
+    TestMessageReceiver(ValidationIntegrationTest* owner,
+                        ScopedMessagePipeHandle handle)
+        : owner_(owner),
+          connector_(handle.Pass()) {
+    }
+    virtual ~TestMessageReceiver() {
+    }
+
+    virtual bool Accept(Message* message) override {
+      bool rv = connector_.Accept(message);
+      owner_->PumpMessages();
+      return rv;
+    }
+
+   public:
+    ValidationIntegrationTest* owner_;
+    mojo::internal::Connector connector_;
+  };
+
+  void PumpMessages() {
+    loop_.RunUntilIdle();
+  }
+
+  RunLoop loop_;
+  TestMessageReceiver* test_message_receiver_;
+  ScopedMessagePipeHandle testee_endpoint_;
+};
+
+class IntegrationTestInterface1Client : public IntegrationTestInterface1 {
+ public:
+  virtual ~IntegrationTestInterface1Client() {
+  }
+
+  virtual void Method0(BasicStructPtr param0) override {}
+};
+
+class IntegrationTestInterface1Impl
+    : public InterfaceImpl<IntegrationTestInterface1> {
+ public:
+  virtual ~IntegrationTestInterface1Impl() {
+  }
+
+  virtual void Method0(BasicStructPtr param0) override {}
+};
+
+TEST_F(ValidationTest, InputParser) {
+  {
+    // The parser, as well as Append() defined above, assumes that this code is
+    // running on a little-endian platform. Test whether that is true.
+    uint16_t x = 1;
+    ASSERT_EQ(1, *(reinterpret_cast<char*>(&x)));
+  }
+  {
+    // Test empty input.
+    std::string input;
+    std::vector<uint8_t> expected;
+
+    EXPECT_TRUE(TestInputParser(input, true, expected, 0));
+  }
+  {
+    // Test input that only consists of comments and whitespaces.
+    std::string input = "    \t  // hello world \n\r \t// the answer is 42   ";
+    std::vector<uint8_t> expected;
+
+    EXPECT_TRUE(TestInputParser(input, true, expected, 0));
+  }
+  {
+    std::string input = "[u1]0x10// hello world !! \n\r  \t [u2]65535 \n"
+                        "[u4]65536 [u8]0xFFFFFFFFFFFFFFFF 0 0Xff";
+    std::vector<uint8_t> expected;
+    Append(&expected, static_cast<uint8_t>(0x10));
+    Append(&expected, static_cast<uint16_t>(65535));
+    Append(&expected, static_cast<uint32_t>(65536));
+    Append(&expected, static_cast<uint64_t>(0xffffffffffffffff));
+    Append(&expected, static_cast<uint8_t>(0));
+    Append(&expected, static_cast<uint8_t>(0xff));
+
+    EXPECT_TRUE(TestInputParser(input, true, expected, 0));
+  }
+  {
+    std::string input = "[s8]-0x800 [s1]-128\t[s2]+0 [s4]-40";
+    std::vector<uint8_t> expected;
+    Append(&expected, -static_cast<int64_t>(0x800));
+    Append(&expected, static_cast<int8_t>(-128));
+    Append(&expected, static_cast<int16_t>(0));
+    Append(&expected, static_cast<int32_t>(-40));
+
+    EXPECT_TRUE(TestInputParser(input, true, expected, 0));
+  }
+  {
+    std::string input = "[b]00001011 [b]10000000  // hello world\r [b]00000000";
+    std::vector<uint8_t> expected;
+    Append(&expected, static_cast<uint8_t>(11));
+    Append(&expected, static_cast<uint8_t>(128));
+    Append(&expected, static_cast<uint8_t>(0));
+
+    EXPECT_TRUE(TestInputParser(input, true, expected, 0));
+  }
+  {
+    std::string input = "[f]+.3e9 [d]-10.03";
+    std::vector<uint8_t> expected;
+    Append(&expected, +.3e9f);
+    Append(&expected, -10.03);
+
+    EXPECT_TRUE(TestInputParser(input, true, expected, 0));
+  }
+  {
+    std::string input = "[dist4]foo 0 [dist8]bar 0 [anchr]foo [anchr]bar";
+    std::vector<uint8_t> expected;
+    Append(&expected, static_cast<uint32_t>(14));
+    Append(&expected, static_cast<uint8_t>(0));
+    Append(&expected, static_cast<uint64_t>(9));
+    Append(&expected, static_cast<uint8_t>(0));
+
+    EXPECT_TRUE(TestInputParser(input, true, expected, 0));
+  }
+  {
+    std::string input = "// This message has handles! \n[handles]50 [u8]2";
+    std::vector<uint8_t> expected;
+    Append(&expected, static_cast<uint64_t>(2));
+
+    EXPECT_TRUE(TestInputParser(input, true, expected, 50));
+  }
+
+  // Test some failure cases.
+  {
+    const char* error_inputs[] = {
+      "/ hello world",
+      "[u1]x",
+      "[u2]-1000",
+      "[u1]0x100",
+      "[s2]-0x8001",
+      "[b]1",
+      "[b]1111111k",
+      "[dist4]unmatched",
+      "[anchr]hello [dist8]hello",
+      "[dist4]a [dist4]a [anchr]a",
+      "[dist4]a [anchr]a [dist4]a [anchr]a",
+      "0 [handles]50",
+      nullptr
+    };
+
+    for (size_t i = 0; error_inputs[i]; ++i) {
+      std::vector<uint8_t> expected;
+      if (!TestInputParser(error_inputs[i], false, expected, 0))
+        ADD_FAILURE() << "Unexpected test result for: " << error_inputs[i];
+    }
+  }
+}
+
+TEST_F(ValidationTest, Conformance) {
+  DummyMessageReceiver dummy_receiver;
+  mojo::internal::FilterChain validators(&dummy_receiver);
+  validators.Append<mojo::internal::MessageHeaderValidator>();
+  validators.Append<ConformanceTestInterface::RequestValidator_>();
+
+  RunValidationTests("conformance_", validators.GetHead());
+}
+
+TEST_F(ValidationTest, NotImplemented) {
+  DummyMessageReceiver dummy_receiver;
+  mojo::internal::FilterChain validators(&dummy_receiver);
+  validators.Append<mojo::internal::MessageHeaderValidator>();
+  validators.Append<ConformanceTestInterface::RequestValidator_>();
+
+  RunValidationTests("not_implemented_", validators.GetHead());
+}
+
+TEST_F(ValidationIntegrationTest, InterfacePtr) {
+  // Test that InterfacePtr<X> applies the correct validators and they don't
+  // conflict with each other:
+  //   - MessageHeaderValidator
+  //   - X::Client::RequestValidator_
+  //   - X::ResponseValidator_
+
+  IntegrationTestInterface1Client interface1_client;
+  IntegrationTestInterface2Ptr interface2_ptr =
+      MakeProxy<IntegrationTestInterface2>(testee_endpoint().Pass());
+  interface2_ptr.set_client(&interface1_client);
+  interface2_ptr.internal_state()->router_for_testing()->EnableTestingMode();
+
+  RunValidationTests("integration_", test_message_receiver());
+}
+
+TEST_F(ValidationIntegrationTest, InterfaceImpl) {
+  // Test that InterfaceImpl<X> applies the correct validators and they don't
+  // conflict with each other:
+  //   - MessageHeaderValidator
+  //   - X::RequestValidator_
+  //   - X::Client::ResponseValidator_
+
+  // |interface1_impl| will delete itself when the pipe is closed.
+  IntegrationTestInterface1Impl* interface1_impl =
+      BindToPipe(new IntegrationTestInterface1Impl(), testee_endpoint().Pass());
+  interface1_impl->internal_state()->router()->EnableTestingMode();
+
+  RunValidationTests("integration_", test_message_receiver());
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/type_converter.h b/mojo/public/cpp/bindings/type_converter.h
new file mode 100644
index 0000000..ff94cda
--- /dev/null
+++ b/mojo/public/cpp/bindings/type_converter.h
@@ -0,0 +1,92 @@
+// Copyright 2014 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_CPP_BINDINGS_TYPE_CONVERTER_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_TYPE_CONVERTER_H_
+
+namespace mojo {
+
+// Specialize the following class:
+//   template <typename T, typename U> struct TypeConverter;
+// to perform type conversion for Mojom-defined structs and arrays. Here, T is
+// the target type; U is the input type.
+//
+// Specializations should implement the following interfaces:
+//   namespace mojo {
+//   template <>
+//   struct TypeConverter<X, Y> {
+//     static X Convert(const Y& input);
+//   };
+//   template <>
+//   struct TypeConverter<Y, X> {
+//     static Y Convert(const X& input);
+//   };
+//   }
+//
+// EXAMPLE:
+//
+// Suppose you have the following Mojom-defined struct:
+//
+//   module geometry {
+//   struct Point {
+//     int32 x;
+//     int32 y;
+//   };
+//   }
+//
+// Now, imagine you wanted to write a TypeConverter specialization for
+// gfx::Point. It might look like this:
+//
+//   namespace mojo {
+//   template <>
+//   struct TypeConverter<geometry::PointPtr, gfx::Point> {
+//     static geometry::PointPtr Convert(const gfx::Point& input) {
+//       geometry::PointPtr result;
+//       result->x = input.x();
+//       result->y = input.y();
+//       return result.Pass();
+//     }
+//   };
+//   template <>
+//   struct TypeConverter<gfx::Point, geometry::PointPtr> {
+//     static gfx::Point Convert(const geometry::PointPtr& input) {
+//       return input ? gfx::Point(input->x, input->y) : gfx::Point();
+//     }
+//   };
+//   }
+//
+// With the above TypeConverter defined, it is possible to write code like this:
+//
+//   void AcceptPoint(const geometry::PointPtr& input) {
+//     // With an explicit cast using the .To<> method.
+//     gfx::Point pt = input.To<gfx::Point>();
+//
+//     // With an explicit cast using the static From() method.
+//     geometry::PointPtr output = geometry::Point::From(pt);
+//
+//     // Inferring the input type using the ConvertTo helper function.
+//     gfx::Point pt2 = ConvertTo<gfx::Point>(input);
+//   }
+//
+template <typename T, typename U>
+struct TypeConverter;
+
+// The following specialization is useful when you are converting between
+// Array<POD> and std::vector<POD>.
+template <typename T>
+struct TypeConverter<T, T> {
+  static T Convert(const T& obj) { return obj; }
+};
+
+// The following helper function is useful for shorthand. The compiler can infer
+// the input type, so you can write:
+//   OutputType out = ConvertTo<OutputType>(input);
+template <typename T, typename U>
+inline T ConvertTo(const U& obj) {
+  return TypeConverter<T, U>::Convert(obj);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_TYPE_CONVERTER_H_
diff --git a/mojo/public/cpp/environment/BUILD.gn b/mojo/public/cpp/environment/BUILD.gn
new file mode 100644
index 0000000..a0d6ca7
--- /dev/null
+++ b/mojo/public/cpp/environment/BUILD.gn
@@ -0,0 +1,32 @@
+# Copyright 2014 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.
+
+source_set("environment") {
+  sources = [
+    "logging.h",
+    "environment.h",
+  ]
+
+  public_deps = [ "//mojo/public/c/environment" ]
+
+  deps = [ "//mojo/public/cpp/system" ]
+}
+
+source_set("standalone") {
+  sources = [
+    "lib/default_async_waiter.cc",
+    "lib/default_async_waiter.h",
+    "lib/default_logger.cc",
+    "lib/default_logger.h",
+    "lib/environment.cc",
+    "lib/logging.cc",
+  ]
+
+  public_deps = [ ":environment" ]
+
+  deps = [
+    "//mojo/public/c/environment",
+    "//mojo/public/cpp/utility",
+  ]
+}
diff --git a/mojo/public/cpp/environment/environment.h b/mojo/public/cpp/environment/environment.h
new file mode 100644
index 0000000..48f4c26
--- /dev/null
+++ b/mojo/public/cpp/environment/environment.h
@@ -0,0 +1,41 @@
+// Copyright 2014 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_CPP_ENVIRONMENT_ENVIRONMENT_H_
+#define MOJO_PUBLIC_CPP_ENVIRONMENT_ENVIRONMENT_H_
+
+#include "mojo/public/cpp/system/macros.h"
+
+struct MojoAsyncWaiter;
+struct MojoLogger;
+
+namespace mojo {
+
+// Other parts of the Mojo C++ APIs use the *static* methods of this class.
+//
+// The "standalone" implementation of this class requires that this class (in
+// the lib/ subdirectory) be instantiated (and remain so) while using the Mojo
+// C++ APIs. I.e., the static methods depend on things set up by the constructor
+// and torn down by the destructor.
+//
+// Other implementations may not have this requirement.
+class Environment {
+ public:
+  Environment();
+  // This constructor allows the standard implementations to be overridden (set
+  // a parameter to null to get the standard implementation).
+  Environment(const MojoAsyncWaiter* default_async_waiter,
+              const MojoLogger* default_logger);
+  ~Environment();
+
+  static const MojoAsyncWaiter* GetDefaultAsyncWaiter();
+  static const MojoLogger* GetDefaultLogger();
+
+ private:
+  MOJO_DISALLOW_COPY_AND_ASSIGN(Environment);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_ENVIRONMENT_ENVIRONMENT_H_
diff --git a/mojo/public/cpp/environment/lib/DEPS b/mojo/public/cpp/environment/lib/DEPS
new file mode 100644
index 0000000..1889e1f
--- /dev/null
+++ b/mojo/public/cpp/environment/lib/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+mojo/public/cpp/environment",
+  "+mojo/public/cpp/utility",
+]
diff --git a/mojo/public/cpp/environment/lib/default_async_waiter.cc b/mojo/public/cpp/environment/lib/default_async_waiter.cc
new file mode 100644
index 0000000..b03623e
--- /dev/null
+++ b/mojo/public/cpp/environment/lib/default_async_waiter.cc
@@ -0,0 +1,93 @@
+// Copyright 2014 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/cpp/environment/lib/default_async_waiter.h"
+
+#include <assert.h>
+
+#include "mojo/public/c/environment/async_waiter.h"
+#include "mojo/public/cpp/utility/run_loop.h"
+#include "mojo/public/cpp/utility/run_loop_handler.h"
+
+namespace mojo {
+
+namespace {
+
+// RunLoopHandler implementation used for a request to AsyncWait(). There are
+// two ways RunLoopHandlerImpl is deleted:
+// . when the handle is ready (or errored).
+// . when CancelWait() is invoked.
+class RunLoopHandlerImpl : public RunLoopHandler {
+ public:
+  RunLoopHandlerImpl(const Handle& handle,
+                     MojoAsyncWaitCallback callback,
+                     void* closure)
+      : handle_(handle),
+        callback_(callback),
+        closure_(closure) {
+  }
+
+  virtual ~RunLoopHandlerImpl() {
+    RunLoop::current()->RemoveHandler(handle_);
+  }
+
+  // RunLoopHandler:
+  virtual void OnHandleReady(const Handle& handle) override {
+    NotifyCallback(MOJO_RESULT_OK);
+  }
+
+  virtual void OnHandleError(const Handle& handle, MojoResult result) override {
+    NotifyCallback(result);
+  }
+
+ private:
+  void NotifyCallback(MojoResult result) {
+    // Delete this to unregister the handle. That way if the callback
+    // reregisters everything is ok.
+    MojoAsyncWaitCallback callback = callback_;
+    void* closure = closure_;
+    delete this;
+
+    callback(closure, result);
+  }
+
+  const Handle handle_;
+  MojoAsyncWaitCallback callback_;
+  void* closure_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoopHandlerImpl);
+};
+
+MojoAsyncWaitID AsyncWait(MojoHandle handle,
+                          MojoHandleSignals signals,
+                          MojoDeadline deadline,
+                          MojoAsyncWaitCallback callback,
+                          void* closure) {
+  RunLoop* run_loop = RunLoop::current();
+  assert(run_loop);
+
+  // |run_loop_handler| is destroyed either when the handle is ready or if
+  // CancelWait is invoked.
+  RunLoopHandlerImpl* run_loop_handler =
+      new RunLoopHandlerImpl(Handle(handle), callback, closure);
+  run_loop->AddHandler(run_loop_handler, Handle(handle), signals, deadline);
+  return reinterpret_cast<MojoAsyncWaitID>(run_loop_handler);
+}
+
+void CancelWait(MojoAsyncWaitID wait_id) {
+  delete reinterpret_cast<RunLoopHandlerImpl*>(wait_id);
+}
+
+}  // namespace
+
+namespace internal {
+
+const MojoAsyncWaiter kDefaultAsyncWaiter = {
+  AsyncWait,
+  CancelWait
+};
+
+}  // namespace internal
+
+}  // namespace mojo
diff --git a/mojo/public/cpp/environment/lib/default_async_waiter.h b/mojo/public/cpp/environment/lib/default_async_waiter.h
new file mode 100644
index 0000000..49ce233
--- /dev/null
+++ b/mojo/public/cpp/environment/lib/default_async_waiter.h
@@ -0,0 +1,18 @@
+// Copyright 2014 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_CPP_ENVIRONMENT_LIB_DEFAULT_ASYNC_WAITER_H_
+#define MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_ASYNC_WAITER_H_
+
+struct MojoAsyncWaiter;
+
+namespace mojo {
+namespace internal {
+
+extern const MojoAsyncWaiter kDefaultAsyncWaiter;
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_ASYNC_WAITER_H_
diff --git a/mojo/public/cpp/environment/lib/default_logger.cc b/mojo/public/cpp/environment/lib/default_logger.cc
new file mode 100644
index 0000000..af4a628
--- /dev/null
+++ b/mojo/public/cpp/environment/lib/default_logger.cc
@@ -0,0 +1,71 @@
+// Copyright 2014 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/cpp/environment/lib/default_logger.h"
+
+#include <stdio.h>
+#include <stdlib.h>  // For |abort()|.
+
+#include <algorithm>
+
+#include "mojo/public/c/environment/logger.h"
+
+namespace mojo {
+
+namespace {
+
+MojoLogLevel g_minimum_log_level = MOJO_LOG_LEVEL_INFO;
+
+const char* GetLogLevelString(MojoLogLevel log_level) {
+  if (log_level <= MOJO_LOG_LEVEL_VERBOSE-3)
+    return "VERBOSE4+";
+  switch (log_level) {
+    case MOJO_LOG_LEVEL_VERBOSE-2:
+      return "VERBOSE3";
+    case MOJO_LOG_LEVEL_VERBOSE-1:
+      return "VERBOSE2";
+    case MOJO_LOG_LEVEL_VERBOSE:
+      return "VERBOSE1";
+    case MOJO_LOG_LEVEL_INFO:
+      return "INFO";
+    case MOJO_LOG_LEVEL_WARNING:
+      return "WARNING";
+    case MOJO_LOG_LEVEL_ERROR:
+      return "ERROR";
+  }
+  // Consider everything higher to be fatal.
+  return "FATAL";
+}
+
+void LogMessage(MojoLogLevel log_level, const char* message) {
+  if (log_level < g_minimum_log_level)
+    return;
+
+  // TODO(vtl): Add timestamp also?
+  fprintf(stderr, "%s: %s\n", GetLogLevelString(log_level), message);
+  if (log_level >= MOJO_LOG_LEVEL_FATAL)
+    abort();
+}
+
+MojoLogLevel GetMinimumLogLevel() {
+  return g_minimum_log_level;
+}
+
+void SetMinimumLogLevel(MojoLogLevel minimum_log_level) {
+  g_minimum_log_level = std::min(minimum_log_level, MOJO_LOG_LEVEL_FATAL);
+}
+
+}  // namespace
+
+namespace internal {
+
+const MojoLogger kDefaultLogger = {
+  LogMessage,
+  GetMinimumLogLevel,
+  SetMinimumLogLevel
+};
+
+}  // namespace internal
+
+}  // namespace mojo
diff --git a/mojo/public/cpp/environment/lib/default_logger.h b/mojo/public/cpp/environment/lib/default_logger.h
new file mode 100644
index 0000000..4db3233
--- /dev/null
+++ b/mojo/public/cpp/environment/lib/default_logger.h
@@ -0,0 +1,18 @@
+// Copyright 2014 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_CPP_ENVIRONMENT_LIB_DEFAULT_LOGGER_H_
+#define MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_LOGGER_H_
+
+struct MojoLogger;
+
+namespace mojo {
+namespace internal {
+
+extern const MojoLogger kDefaultLogger;
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_LOGGER_H_
diff --git a/mojo/public/cpp/environment/lib/environment.cc b/mojo/public/cpp/environment/lib/environment.cc
new file mode 100644
index 0000000..5fde8f7
--- /dev/null
+++ b/mojo/public/cpp/environment/lib/environment.cc
@@ -0,0 +1,64 @@
+// Copyright 2014 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/cpp/environment/environment.h"
+
+#include <assert.h>
+
+#include "mojo/public/c/environment/logger.h"
+#include "mojo/public/cpp/environment/lib/default_async_waiter.h"
+#include "mojo/public/cpp/environment/lib/default_logger.h"
+#include "mojo/public/cpp/utility/run_loop.h"
+
+namespace mojo {
+
+namespace {
+
+const MojoAsyncWaiter* g_default_async_waiter = nullptr;
+const MojoLogger* g_default_logger = nullptr;
+
+void Init(const MojoAsyncWaiter* default_async_waiter,
+          const MojoLogger* default_logger) {
+  g_default_async_waiter =
+      default_async_waiter ? default_async_waiter :
+                             &internal::kDefaultAsyncWaiter;
+  g_default_logger = default_logger ? default_logger :
+                                      &internal::kDefaultLogger;
+
+  RunLoop::SetUp();
+}
+
+}  // namespace
+
+Environment::Environment() {
+  Init(nullptr, nullptr);
+}
+
+Environment::Environment(const MojoAsyncWaiter* default_async_waiter,
+                         const MojoLogger* default_logger) {
+  Init(default_async_waiter, default_logger);
+}
+
+Environment::~Environment() {
+  RunLoop::TearDown();
+
+  // TODO(vtl): Maybe we should allow nesting, and restore previous default
+  // async waiters and loggers?
+  g_default_async_waiter = nullptr;
+  g_default_logger = nullptr;
+}
+
+// static
+const MojoAsyncWaiter* Environment::GetDefaultAsyncWaiter() {
+  assert(g_default_async_waiter);  // Fails if not "inside" |Environment|.
+  return g_default_async_waiter;
+}
+
+// static
+const MojoLogger* Environment::GetDefaultLogger() {
+  assert(g_default_logger);  // Fails if not "inside" |Environment|.
+  return g_default_logger;
+}
+
+}  // namespace mojo
diff --git a/mojo/public/cpp/environment/lib/logging.cc b/mojo/public/cpp/environment/lib/logging.cc
new file mode 100644
index 0000000..990626d
--- /dev/null
+++ b/mojo/public/cpp/environment/lib/logging.cc
@@ -0,0 +1,45 @@
+// Copyright 2014 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/cpp/environment/logging.h"
+
+#include "mojo/public/cpp/environment/environment.h"
+
+namespace mojo {
+namespace internal {
+
+namespace {
+
+// Gets a pointer to the filename portion of |s|. Assumes that the filename
+// follows the last slash or backslash in |s|, or is |s| if no slash or
+// backslash is present.
+//
+// E.g., a pointer to "foo.cc" is returned for the following inputs: "foo.cc",
+// "./foo.cc", ".\foo.cc", "/absolute/path/to/foo.cc",
+// "relative/path/to/foo.cc", "C:\absolute\path\to\foo.cc", etc.
+const char* GetFilename(const char* s) {
+  const char* rv = s;
+  while (*s) {
+    if (*s == '/' || *s == '\\')
+      rv = s + 1;
+    s++;
+  }
+  return rv;
+}
+
+}  // namespace
+
+LogMessage::LogMessage(const char* file, int line, MojoLogLevel log_level)
+    : log_level_(log_level) {
+  // Note: Don't include the log level in the message, since that's passed on.
+  stream_ << GetFilename(file) << '(' << line << "): ";
+}
+
+LogMessage::~LogMessage() {
+  Environment::GetDefaultLogger()->LogMessage(log_level_,
+                                              stream_.str().c_str());
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/environment/logging.h b/mojo/public/cpp/environment/logging.h
new file mode 100644
index 0000000..a3e2cef
--- /dev/null
+++ b/mojo/public/cpp/environment/logging.h
@@ -0,0 +1,87 @@
+// Copyright 2014 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.
+
+// Logging macros, similar to Chromium's base/logging.h, except with |MOJO_|
+// prefixes and missing some features (notably |CHECK_EQ()|, etc.).
+
+// TODO(vtl): It's weird that this is in the environment directory, since its
+// implementation (in environment/lib) is meant to be used by any implementation
+// of the environment.
+
+#ifndef MOJO_PUBLIC_CPP_ENVIRONMENT_LOGGING_H_
+#define MOJO_PUBLIC_CPP_ENVIRONMENT_LOGGING_H_
+
+#include <sstream>
+
+#include "mojo/public/c/environment/logger.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/system/macros.h"
+
+#define MOJO_LOG_STREAM(level) \
+    ::mojo::internal::LogMessage(__FILE__, __LINE__, \
+                                 MOJO_LOG_LEVEL_ ## level).stream()
+
+#define MOJO_LAZY_LOG_STREAM(level, condition) \
+    !(condition) ? \
+        (void) 0 : \
+        ::mojo::internal::VoidifyOstream() & MOJO_LOG_STREAM(level)
+
+#define MOJO_SHOULD_LOG(level) \
+    (MOJO_LOG_LEVEL_ ## level >= \
+     ::mojo::Environment::GetDefaultLogger()->GetMinimumLogLevel())
+
+#define MOJO_LOG(level) \
+    MOJO_LAZY_LOG_STREAM(level, MOJO_SHOULD_LOG(level))
+
+#define MOJO_LOG_IF(level, condition) \
+    MOJO_LAZY_LOG_STREAM(level, MOJO_SHOULD_LOG(level) && (condition))
+
+#define MOJO_CHECK(condition) \
+    MOJO_LAZY_LOG_STREAM(FATAL, !(condition)) \
+        << "Check failed: " #condition ". "
+
+// Note: For non-debug builds, |MOJO_DLOG_IF()| *eliminates* (i.e., doesn't
+// compile) the condition, whereas |MOJO_DCHECK()| "neuters" the condition
+// (i.e., compiles, but doesn't evaluate).
+#ifdef NDEBUG
+
+#define MOJO_DLOG(level) MOJO_LAZY_LOG_STREAM(level, false)
+#define MOJO_DLOG_IF(level, condition) MOJO_LAZY_LOG_STREAM(level, false)
+#define MOJO_DCHECK(condition) MOJO_LAZY_LOG_STREAM(FATAL, false && (condition))
+
+#else
+
+#define MOJO_DLOG(level) MOJO_LOG(level)
+#define MOJO_DLOG_IF(level, condition) MOJO_LOG_IF(level, condition)
+#define MOJO_DCHECK(condition) MOJO_CHECK(condition)
+
+#endif  // NDEBUG
+
+namespace mojo {
+namespace internal {
+
+class LogMessage {
+ public:
+  LogMessage(const char* file, int line, MojoLogLevel log_level);
+  ~LogMessage();
+
+  std::ostream& stream() { return stream_; }
+
+ private:
+  const MojoLogLevel log_level_;
+  std::ostringstream stream_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(LogMessage);
+};
+
+// Used to ignore a stream.
+struct VoidifyOstream {
+  // Use & since it has precedence lower than << but higher than ?:.
+  void operator&(std::ostream&) {}
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_ENVIRONMENT_LOGGING_H_
diff --git a/mojo/public/cpp/environment/tests/BUILD.gn b/mojo/public/cpp/environment/tests/BUILD.gn
new file mode 100644
index 0000000..55ded10
--- /dev/null
+++ b/mojo/public/cpp/environment/tests/BUILD.gn
@@ -0,0 +1,22 @@
+# Copyright 2014 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.
+
+# GYP version: mojo/mojo_public_tests.gypi:mojo_public_environment_unittests
+test("mojo_public_environment_unittests") {
+  sources = [
+    "async_waiter_unittest.cc",
+    "logger_unittest.cc",
+    "logging_unittest.cc",
+  ]
+
+  deps = [
+    "//mojo/common/test:run_all_unittests",
+    "//mojo/public/c/environment",
+    "//mojo/public/cpp/environment:standalone",
+    "//mojo/public/cpp/system",
+    "//mojo/public/cpp/test_support:test_utils",
+    "//mojo/public/cpp/utility",
+    "//testing/gtest",
+  ]
+}
diff --git a/mojo/public/cpp/environment/tests/async_waiter_unittest.cc b/mojo/public/cpp/environment/tests/async_waiter_unittest.cc
new file mode 100644
index 0000000..0992f89
--- /dev/null
+++ b/mojo/public/cpp/environment/tests/async_waiter_unittest.cc
@@ -0,0 +1,120 @@
+// Copyright 2014 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 <string>
+
+#include "mojo/public/c/environment/async_waiter.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/system/core.h"
+#include "mojo/public/cpp/system/macros.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
+#include "mojo/public/cpp/utility/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+class TestAsyncWaitCallback {
+ public:
+  TestAsyncWaitCallback() : result_count_(0), last_result_(MOJO_RESULT_OK) {
+  }
+  virtual ~TestAsyncWaitCallback() {}
+
+  int result_count() const { return result_count_; }
+
+  MojoResult last_result() const { return last_result_; }
+
+  // MojoAsyncWaitCallback:
+  static void OnHandleReady(void* closure, MojoResult result) {
+    TestAsyncWaitCallback* self = static_cast<TestAsyncWaitCallback*>(closure);
+    self->result_count_++;
+    self->last_result_ = result;
+  }
+
+ private:
+  int result_count_;
+  MojoResult last_result_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(TestAsyncWaitCallback);
+};
+
+MojoAsyncWaitID CallAsyncWait(const Handle& handle,
+                              MojoHandleSignals signals,
+                              TestAsyncWaitCallback* callback) {
+  return Environment::GetDefaultAsyncWaiter()->AsyncWait(
+      handle.value(),
+      signals,
+      MOJO_DEADLINE_INDEFINITE,
+      &TestAsyncWaitCallback::OnHandleReady,
+      callback);
+}
+
+void CallCancelWait(MojoAsyncWaitID wait_id) {
+  Environment::GetDefaultAsyncWaiter()->CancelWait(wait_id);
+}
+
+class AsyncWaiterTest : public testing::Test {
+ public:
+  AsyncWaiterTest() {}
+
+ private:
+  Environment environment_;
+  RunLoop run_loop_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(AsyncWaiterTest);
+};
+
+// Verifies AsyncWaitCallback is notified when pipe is ready.
+TEST_F(AsyncWaiterTest, CallbackNotified) {
+  TestAsyncWaitCallback callback;
+  MessagePipe test_pipe;
+  EXPECT_TRUE(test::WriteTextMessage(test_pipe.handle1.get(), std::string()));
+
+  CallAsyncWait(test_pipe.handle0.get(),
+                MOJO_HANDLE_SIGNAL_READABLE,
+                &callback);
+  RunLoop::current()->Run();
+  EXPECT_EQ(1, callback.result_count());
+  EXPECT_EQ(MOJO_RESULT_OK, callback.last_result());
+}
+
+// Verifies 2 AsyncWaitCallbacks are notified when there pipes are ready.
+TEST_F(AsyncWaiterTest, TwoCallbacksNotified) {
+  TestAsyncWaitCallback callback1;
+  TestAsyncWaitCallback callback2;
+  MessagePipe test_pipe1;
+  MessagePipe test_pipe2;
+  EXPECT_TRUE(test::WriteTextMessage(test_pipe1.handle1.get(), std::string()));
+  EXPECT_TRUE(test::WriteTextMessage(test_pipe2.handle1.get(), std::string()));
+
+  CallAsyncWait(test_pipe1.handle0.get(),
+                MOJO_HANDLE_SIGNAL_READABLE,
+                &callback1);
+  CallAsyncWait(test_pipe2.handle0.get(),
+                MOJO_HANDLE_SIGNAL_READABLE,
+                &callback2);
+
+  RunLoop::current()->Run();
+  EXPECT_EQ(1, callback1.result_count());
+  EXPECT_EQ(MOJO_RESULT_OK, callback1.last_result());
+  EXPECT_EQ(1, callback2.result_count());
+  EXPECT_EQ(MOJO_RESULT_OK, callback2.last_result());
+}
+
+// Verifies cancel works.
+TEST_F(AsyncWaiterTest, CancelCallback) {
+  TestAsyncWaitCallback callback;
+  MessagePipe test_pipe;
+  EXPECT_TRUE(test::WriteTextMessage(test_pipe.handle1.get(), std::string()));
+
+  CallCancelWait(
+      CallAsyncWait(test_pipe.handle0.get(),
+                    MOJO_HANDLE_SIGNAL_READABLE,
+                    &callback));
+  RunLoop::current()->Run();
+  EXPECT_EQ(0, callback.result_count());
+}
+
+}  // namespace
+}  // namespace mojo
diff --git a/mojo/public/cpp/environment/tests/logger_unittest.cc b/mojo/public/cpp/environment/tests/logger_unittest.cc
new file mode 100644
index 0000000..e30a84b
--- /dev/null
+++ b/mojo/public/cpp/environment/tests/logger_unittest.cc
@@ -0,0 +1,56 @@
+// Copyright 2014 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/c/environment/logger.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+TEST(LoggerTest, Basic) {
+  Environment environment;
+  const MojoLogger* const logger = Environment::GetDefaultLogger();
+
+  logger->LogMessage(MOJO_LOG_LEVEL_VERBOSE-1, "Logged at VERBOSE-1 level");
+  logger->LogMessage(MOJO_LOG_LEVEL_VERBOSE, "Logged at VERBOSE level");
+  logger->LogMessage(MOJO_LOG_LEVEL_INFO, "Logged at INFO level");
+  logger->LogMessage(MOJO_LOG_LEVEL_WARNING, "Logged at WARNING level");
+  logger->LogMessage(MOJO_LOG_LEVEL_ERROR, "Logged at ERROR level");
+
+  // This should kill us:
+  EXPECT_DEATH_IF_SUPPORTED({
+    logger->LogMessage(MOJO_LOG_LEVEL_FATAL, "Logged at FATAL level");
+  }, "");
+}
+
+TEST(LoggerTest, LogLevels) {
+  Environment environment;
+  const MojoLogger* const logger = Environment::GetDefaultLogger();
+
+  for (MojoLogLevel log_level = MOJO_LOG_LEVEL_VERBOSE-1;
+       log_level <= MOJO_LOG_LEVEL_FATAL+1;
+       log_level++) {
+    logger->SetMinimumLogLevel(log_level);
+
+    if (log_level <= MOJO_LOG_LEVEL_FATAL)
+      EXPECT_EQ(log_level, logger->GetMinimumLogLevel());
+    else
+      EXPECT_EQ(MOJO_LOG_LEVEL_FATAL, logger->GetMinimumLogLevel());
+
+    logger->LogMessage(MOJO_LOG_LEVEL_VERBOSE-1, "Logged at VERBOSE-1 level");
+    logger->LogMessage(MOJO_LOG_LEVEL_VERBOSE, "Logged at VERBOSE level");
+    logger->LogMessage(MOJO_LOG_LEVEL_INFO, "Logged at INFO level");
+    logger->LogMessage(MOJO_LOG_LEVEL_WARNING, "Logged at WARNING level");
+    logger->LogMessage(MOJO_LOG_LEVEL_ERROR, "Logged at ERROR level");
+
+    // This should kill us:
+    EXPECT_DEATH_IF_SUPPORTED({
+      logger->LogMessage(MOJO_LOG_LEVEL_FATAL, "Logged at FATAL level");
+    }, "");
+  }
+}
+
+}  // namespace
+}  // namespace mojo
diff --git a/mojo/public/cpp/environment/tests/logging_unittest.cc b/mojo/public/cpp/environment/tests/logging_unittest.cc
new file mode 100644
index 0000000..45f527e
--- /dev/null
+++ b/mojo/public/cpp/environment/tests/logging_unittest.cc
@@ -0,0 +1,474 @@
+// Copyright 2014 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 <stdlib.h>
+
+#include <sstream>
+#include <string>
+
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/environment/logging.h"
+#include "mojo/public/cpp/system/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// A macro, so it can be automatically joined with other string literals. (Not
+// simply __FILE__, since that may contain a path.)
+#define OUR_FILENAME "logging_unittest.cc"
+
+namespace mojo {
+namespace {
+
+class PtrToMemberHelper {
+ public:
+  int member;
+};
+
+bool DcheckTestHelper(bool* was_called) {
+  *was_called = true;
+  return false;
+}
+
+class LoggingTest : public testing::Test {
+ public:
+  LoggingTest() : environment_(nullptr, &kMockLogger) {
+    minimum_log_level_ = MOJO_LOG_LEVEL_INFO;
+    ResetMockLogger();
+  }
+  virtual ~LoggingTest() {}
+
+ protected:
+  // Note: Does not reset |minimum_log_level_|.
+  static void ResetMockLogger() {
+    log_message_was_called_ = false;
+    last_log_level_ = MOJO_LOG_LEVEL_INFO;
+    last_message_.clear();
+  }
+
+  // A function returning |bool| that shouldn't be called.
+  static bool NotCalledCondition() {
+    not_called_condition_was_called_ = true;
+    return false;
+  }
+
+  static bool log_message_was_called() { return log_message_was_called_; }
+  static MojoLogLevel last_log_level() { return last_log_level_; }
+  static const std::string& last_message() { return last_message_; }
+  static bool not_called_condition_was_called() {
+    return not_called_condition_was_called_;
+  }
+
+ private:
+  // Note: We record calls even if |log_level| is below |minimum_log_level_|
+  // (since the macros should mostly avoid this, and we want to be able to check
+  // that they do).
+  static void MockLogMessage(MojoLogLevel log_level, const char* message) {
+    log_message_was_called_ = true;
+    last_log_level_ = log_level;
+    last_message_ = message;
+  }
+
+  static MojoLogLevel MockGetMinimumLogLevel() {
+    return minimum_log_level_;
+  }
+
+  static void MockSetMinimumLogLevel(MojoLogLevel minimum_log_level) {
+    minimum_log_level_ = minimum_log_level;
+  }
+
+  Environment environment_;
+
+  static const MojoLogger kMockLogger;
+  static MojoLogLevel minimum_log_level_;
+  static bool log_message_was_called_;
+  static MojoLogLevel last_log_level_;
+  static std::string last_message_;
+  static bool not_called_condition_was_called_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(LoggingTest);
+};
+
+// static
+const MojoLogger LoggingTest::kMockLogger = {
+  &LoggingTest::MockLogMessage,
+  &LoggingTest::MockGetMinimumLogLevel,
+  &LoggingTest::MockSetMinimumLogLevel
+};
+
+// static
+MojoLogLevel LoggingTest::minimum_log_level_ = MOJO_LOG_LEVEL_INFO;
+
+// static
+bool LoggingTest::log_message_was_called_ = MOJO_LOG_LEVEL_INFO;
+
+// static
+MojoLogLevel LoggingTest::last_log_level_ = MOJO_LOG_LEVEL_INFO;
+
+// static
+std::string LoggingTest::last_message_;
+
+// static
+bool LoggingTest::not_called_condition_was_called_ = false;
+
+std::string ExpectedLogMessage(int line, const char* message) {
+  std::ostringstream s;
+  s << OUR_FILENAME "(" << line << "): " << message;
+  return s.str();
+}
+
+TEST_F(LoggingTest, InternalLogMessage) {
+  internal::LogMessage("foo.cc", 123, MOJO_LOG_LEVEL_INFO).stream()
+      << "hello " << "world";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_INFO, last_log_level());
+  EXPECT_EQ("foo.cc(123): hello world", last_message());
+
+  ResetMockLogger();
+
+  internal::LogMessage("./path/to/foo.cc", 123, MOJO_LOG_LEVEL_WARNING).stream()
+      << "hello " << "world";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_WARNING, last_log_level());
+  EXPECT_EQ("foo.cc(123): hello world", last_message());
+
+  ResetMockLogger();
+
+  internal::LogMessage("/path/to/foo.cc", 123, MOJO_LOG_LEVEL_ERROR).stream()
+      << "hello " << "world";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_ERROR, last_log_level());
+  EXPECT_EQ("foo.cc(123): hello world", last_message());
+
+  ResetMockLogger();
+
+  internal::LogMessage("path/to/foo.cc", 123, MOJO_LOG_LEVEL_FATAL).stream()
+      << "hello " << "world";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_FATAL, last_log_level());
+  EXPECT_EQ("foo.cc(123): hello world", last_message());
+
+  ResetMockLogger();
+
+  internal::LogMessage(".\\xy\\foo.cc", 123, MOJO_LOG_LEVEL_VERBOSE).stream()
+      << "hello " << "world";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_VERBOSE, last_log_level());
+  EXPECT_EQ("foo.cc(123): hello world", last_message());
+
+  ResetMockLogger();
+
+  internal::LogMessage("xy\\foo.cc", 123, MOJO_LOG_LEVEL_VERBOSE-1).stream()
+      << "hello " << "world";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_VERBOSE-1, last_log_level());
+  EXPECT_EQ("foo.cc(123): hello world", last_message());
+
+  ResetMockLogger();
+
+  internal::LogMessage("C:\\xy\\foo.cc", 123, MOJO_LOG_LEVEL_VERBOSE-9).stream()
+      << "hello " << "world";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_VERBOSE-9, last_log_level());
+  EXPECT_EQ("foo.cc(123): hello world", last_message());
+
+  ResetMockLogger();
+
+  internal::LogMessage(__FILE__, 123, MOJO_LOG_LEVEL_INFO).stream()
+      << "hello " << "world";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_INFO, last_log_level());
+  EXPECT_EQ(OUR_FILENAME "(123): hello world", last_message());
+}
+
+TEST_F(LoggingTest, LogStream) {
+  MOJO_LOG_STREAM(INFO) << "hello";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_INFO, last_log_level());
+  EXPECT_EQ(ExpectedLogMessage(__LINE__ - 3, "hello"), last_message());
+
+  ResetMockLogger();
+
+  MOJO_LOG_STREAM(ERROR) << "hi " << 123;
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_ERROR, last_log_level());
+  EXPECT_EQ(ExpectedLogMessage(__LINE__ - 3, "hi 123"), last_message());
+}
+
+TEST_F(LoggingTest, LazyLogStream) {
+  MOJO_LAZY_LOG_STREAM(INFO, true) << "hello";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_INFO, last_log_level());
+  EXPECT_EQ(ExpectedLogMessage(__LINE__ - 3, "hello"), last_message());
+
+  ResetMockLogger();
+
+  MOJO_LAZY_LOG_STREAM(ERROR, true) << "hi " << 123;
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_ERROR, last_log_level());
+  EXPECT_EQ(ExpectedLogMessage(__LINE__ - 3, "hi 123"), last_message());
+
+  ResetMockLogger();
+
+  MOJO_LAZY_LOG_STREAM(INFO, false) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  MOJO_LAZY_LOG_STREAM(FATAL, false) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  PtrToMemberHelper helper;
+  helper.member = 1;
+  int PtrToMemberHelper::*member_ptr = &PtrToMemberHelper::member;
+
+  // This probably fails to compile if we forget to parenthesize the condition
+  // in the macro (.* has lower precedence than !, which can't apply to
+  // |helper|).
+  MOJO_LAZY_LOG_STREAM(ERROR, helper.*member_ptr == 1) << "hello";
+  EXPECT_TRUE(log_message_was_called());
+
+  ResetMockLogger();
+
+  MOJO_LAZY_LOG_STREAM(WARNING, helper.*member_ptr == 0) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+}
+
+TEST_F(LoggingTest, ShouldLog) {
+  // We start at |MOJO_LOG_LEVEL_INFO|.
+  EXPECT_FALSE(MOJO_SHOULD_LOG(VERBOSE));
+  EXPECT_TRUE(MOJO_SHOULD_LOG(INFO));
+  EXPECT_TRUE(MOJO_SHOULD_LOG(WARNING));
+  EXPECT_TRUE(MOJO_SHOULD_LOG(ERROR));
+  EXPECT_TRUE(MOJO_SHOULD_LOG(FATAL));
+
+  Environment::GetDefaultLogger()->SetMinimumLogLevel(MOJO_LOG_LEVEL_ERROR);
+  EXPECT_FALSE(MOJO_SHOULD_LOG(VERBOSE));
+  EXPECT_FALSE(MOJO_SHOULD_LOG(INFO));
+  EXPECT_FALSE(MOJO_SHOULD_LOG(WARNING));
+  EXPECT_TRUE(MOJO_SHOULD_LOG(ERROR));
+  EXPECT_TRUE(MOJO_SHOULD_LOG(FATAL));
+
+  Environment::GetDefaultLogger()->SetMinimumLogLevel(MOJO_LOG_LEVEL_VERBOSE-1);
+  EXPECT_TRUE(MOJO_SHOULD_LOG(VERBOSE));
+  EXPECT_TRUE(MOJO_SHOULD_LOG(INFO));
+  EXPECT_TRUE(MOJO_SHOULD_LOG(WARNING));
+  EXPECT_TRUE(MOJO_SHOULD_LOG(ERROR));
+  EXPECT_TRUE(MOJO_SHOULD_LOG(FATAL));
+}
+
+TEST_F(LoggingTest, Log) {
+  // We start at |MOJO_LOG_LEVEL_INFO|.
+  MOJO_LOG(VERBOSE) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  MOJO_LOG(INFO) << "hello";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_INFO, last_log_level());
+  EXPECT_EQ(ExpectedLogMessage(__LINE__ - 3, "hello"), last_message());
+
+  ResetMockLogger();
+
+  MOJO_LOG(ERROR) << "hello";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_ERROR, last_log_level());
+  EXPECT_EQ(ExpectedLogMessage(__LINE__ - 3, "hello"), last_message());
+
+  ResetMockLogger();
+
+  Environment::GetDefaultLogger()->SetMinimumLogLevel(MOJO_LOG_LEVEL_ERROR);
+
+  MOJO_LOG(VERBOSE) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  MOJO_LOG(INFO) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  MOJO_LOG(ERROR) << "hello";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_ERROR, last_log_level());
+  EXPECT_EQ(ExpectedLogMessage(__LINE__ - 3, "hello"), last_message());
+}
+
+TEST_F(LoggingTest, LogIf) {
+  // We start at |MOJO_LOG_LEVEL_INFO|.
+  MOJO_LOG_IF(VERBOSE, true) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  MOJO_LOG_IF(VERBOSE, false) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+  Environment::GetDefaultLogger()->SetMinimumLogLevel(MOJO_LOG_LEVEL_ERROR);
+
+  bool x = true;
+  // Also try to make sure that we parenthesize the condition properly.
+  MOJO_LOG_IF(INFO, false || x) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  MOJO_LOG_IF(INFO, 0 != 1) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  MOJO_LOG_IF(WARNING, 1 + 1 == 2) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  MOJO_LOG_IF(ERROR, 1 * 2 == 2) << "hello";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_ERROR, last_log_level());
+  EXPECT_EQ(ExpectedLogMessage(__LINE__ - 3, "hello"), last_message());
+
+  ResetMockLogger();
+
+  MOJO_LOG_IF(FATAL, 1 * 2 == 3) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  // |MOJO_LOG_IF()| shouldn't evaluate its condition if the level is below the
+  // minimum.
+  MOJO_LOG_IF(INFO, NotCalledCondition()) << "hello";
+  EXPECT_FALSE(not_called_condition_was_called());
+  EXPECT_FALSE(log_message_was_called());
+}
+
+TEST_F(LoggingTest, Check) {
+  MOJO_CHECK(true) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  PtrToMemberHelper helper;
+  helper.member = 0;
+  int PtrToMemberHelper::*member_ptr = &PtrToMemberHelper::member;
+
+  // Also try to make sure that we parenthesize the condition properly.
+  MOJO_CHECK(helper.*member_ptr == 1) << "hello";
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_FATAL, last_log_level());
+  // Different compilers have different ideas about the line number of a split
+  // line.
+  int line = __LINE__;
+  EXPECT_EQ(ExpectedLogMessage(line - 5,
+                               "Check failed: helper.*member_ptr == 1. hello"),
+            last_message());
+
+  ResetMockLogger();
+
+  // Also test a "naked" |MOJO_CHECK()|s.
+  MOJO_CHECK(1 + 2 == 3);
+  EXPECT_FALSE(log_message_was_called());
+}
+
+TEST_F(LoggingTest, Dlog) {
+  // We start at |MOJO_LOG_LEVEL_INFO|.
+  MOJO_DLOG(VERBOSE) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  MOJO_DLOG(INFO) << "hello";
+#ifdef NDEBUG
+  EXPECT_FALSE(log_message_was_called());
+#else
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_INFO, last_log_level());
+  EXPECT_EQ(ExpectedLogMessage(__LINE__ - 6, "hello"), last_message());
+#endif
+}
+
+TEST_F(LoggingTest, DlogIf) {
+  // We start at |MOJO_LOG_LEVEL_INFO|. It shouldn't evaluate the condition in
+  // this case.
+  MOJO_DLOG_IF(VERBOSE, NotCalledCondition()) << "hello";
+  EXPECT_FALSE(not_called_condition_was_called());
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  MOJO_DLOG_IF(INFO, 1 == 0) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  MOJO_DLOG_IF(INFO, 1 == 1) << "hello";
+#ifdef NDEBUG
+  EXPECT_FALSE(log_message_was_called());
+#else
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_INFO, last_log_level());
+  EXPECT_EQ(ExpectedLogMessage(__LINE__ - 6, "hello"), last_message());
+#endif
+
+  ResetMockLogger();
+
+  // |MOJO_DLOG_IF()| shouldn't compile its condition for non-debug builds.
+#ifndef NDEBUG
+  bool debug_only = true;
+#endif
+  MOJO_DLOG_IF(WARNING, debug_only) << "hello";
+#ifdef NDEBUG
+  EXPECT_FALSE(log_message_was_called());
+#else
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_WARNING, last_log_level());
+  EXPECT_EQ(ExpectedLogMessage(__LINE__ - 6, "hello"), last_message());
+#endif
+}
+
+TEST_F(LoggingTest, Dcheck) {
+  MOJO_DCHECK(true);
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  MOJO_DCHECK(true) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+
+  ResetMockLogger();
+
+  // |MOJO_DCHECK()| should compile (but not evaluate) its condition even for
+  // non-debug builds. (Hopefully, we'll get an unused variable error if it
+  // fails to compile the condition.)
+  bool was_called = false;
+  MOJO_DCHECK(DcheckTestHelper(&was_called)) << "hello";
+#ifdef NDEBUG
+  EXPECT_FALSE(was_called);
+  EXPECT_FALSE(log_message_was_called());
+#else
+  EXPECT_TRUE(was_called);
+  EXPECT_TRUE(log_message_was_called());
+  EXPECT_EQ(MOJO_LOG_LEVEL_FATAL, last_log_level());
+  // Different compilers have different ideas about the line number of a split
+  // line.
+  int line = __LINE__;
+  EXPECT_EQ(
+      ExpectedLogMessage(line - 10,
+                         "Check failed: DcheckTestHelper(&was_called). hello"),
+      last_message());
+#endif
+
+  ResetMockLogger();
+
+  // Also try to make sure that we parenthesize the condition properly.
+  bool x = true;
+  MOJO_DCHECK(false || x) << "hello";
+  EXPECT_FALSE(log_message_was_called());
+}
+
+}  // namespace
+}  // namespace mojo
diff --git a/mojo/public/cpp/system/BUILD.gn b/mojo/public/cpp/system/BUILD.gn
new file mode 100644
index 0000000..046ede0
--- /dev/null
+++ b/mojo/public/cpp/system/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2014 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.
+
+source_set("system") {
+  sources = [
+    "buffer.h",
+    "core.h",
+    "data_pipe.h",
+    "functions.h",
+    "handle.h",
+    "macros.h",
+    "message_pipe.h"
+  ]
+
+  public_deps = [ "//mojo/public/c/system" ]
+}
diff --git a/mojo/public/cpp/system/buffer.h b/mojo/public/cpp/system/buffer.h
new file mode 100644
index 0000000..ad9966a
--- /dev/null
+++ b/mojo/public/cpp/system/buffer.h
@@ -0,0 +1,113 @@
+// Copyright 2014 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_CPP_SYSTEM_BUFFER_H_
+#define MOJO_PUBLIC_CPP_SYSTEM_BUFFER_H_
+
+#include <assert.h>
+
+#include "mojo/public/c/system/buffer.h"
+#include "mojo/public/cpp/system/handle.h"
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+
+// SharedBufferHandle ----------------------------------------------------------
+
+class SharedBufferHandle : public Handle {
+ public:
+  SharedBufferHandle() {}
+  explicit SharedBufferHandle(MojoHandle value) : Handle(value) {}
+
+  // Copying and assignment allowed.
+};
+
+MOJO_COMPILE_ASSERT(sizeof(SharedBufferHandle) == sizeof(Handle),
+                    bad_size_for_cpp_SharedBufferHandle);
+
+typedef ScopedHandleBase<SharedBufferHandle> ScopedSharedBufferHandle;
+MOJO_COMPILE_ASSERT(sizeof(ScopedSharedBufferHandle) ==
+                        sizeof(SharedBufferHandle),
+                    bad_size_for_cpp_ScopedSharedBufferHandle);
+
+inline MojoResult CreateSharedBuffer(
+    const MojoCreateSharedBufferOptions* options,
+    uint64_t num_bytes,
+    ScopedSharedBufferHandle* shared_buffer) {
+  assert(shared_buffer);
+  SharedBufferHandle handle;
+  MojoResult rv = MojoCreateSharedBuffer(options, num_bytes,
+                                         handle.mutable_value());
+  // Reset even on failure (reduces the chances that a "stale"/incorrect handle
+  // will be used).
+  shared_buffer->reset(handle);
+  return rv;
+}
+
+// TODO(vtl): This (and also the functions below) are templatized to allow for
+// future/other buffer types. A bit "safer" would be to overload this function
+// manually. (The template enforces that the in and out handles to be of the
+// same type.)
+template <class BufferHandleType>
+inline MojoResult DuplicateBuffer(
+    BufferHandleType buffer,
+    const MojoDuplicateBufferHandleOptions* options,
+    ScopedHandleBase<BufferHandleType>* new_buffer) {
+  assert(new_buffer);
+  BufferHandleType handle;
+  MojoResult rv = MojoDuplicateBufferHandle(
+      buffer.value(), options, handle.mutable_value());
+  // Reset even on failure (reduces the chances that a "stale"/incorrect handle
+  // will be used).
+  new_buffer->reset(handle);
+  return rv;
+}
+
+template <class BufferHandleType>
+inline MojoResult MapBuffer(BufferHandleType buffer,
+                            uint64_t offset,
+                            uint64_t num_bytes,
+                            void** pointer,
+                            MojoMapBufferFlags flags) {
+  assert(buffer.is_valid());
+  return MojoMapBuffer(buffer.value(), offset, num_bytes, pointer, flags);
+}
+
+inline MojoResult UnmapBuffer(void* pointer) {
+  assert(pointer);
+  return MojoUnmapBuffer(pointer);
+}
+
+// A wrapper class that automatically creates a shared buffer and owns the
+// handle.
+class SharedBuffer {
+ public:
+  explicit SharedBuffer(uint64_t num_bytes);
+  SharedBuffer(uint64_t num_bytes,
+               const MojoCreateSharedBufferOptions& options);
+  ~SharedBuffer();
+
+  ScopedSharedBufferHandle handle;
+};
+
+inline SharedBuffer::SharedBuffer(uint64_t num_bytes) {
+  MojoResult result MOJO_ALLOW_UNUSED =
+      CreateSharedBuffer(nullptr, num_bytes, &handle);
+  assert(result == MOJO_RESULT_OK);
+}
+
+inline SharedBuffer::SharedBuffer(
+    uint64_t num_bytes,
+    const MojoCreateSharedBufferOptions& options) {
+  MojoResult result MOJO_ALLOW_UNUSED =
+      CreateSharedBuffer(&options, num_bytes, &handle);
+  assert(result == MOJO_RESULT_OK);
+}
+
+inline SharedBuffer::~SharedBuffer() {
+}
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_SYSTEM_BUFFER_H_
diff --git a/mojo/public/cpp/system/core.h b/mojo/public/cpp/system/core.h
new file mode 100644
index 0000000..b08a5a6
--- /dev/null
+++ b/mojo/public/cpp/system/core.h
@@ -0,0 +1,15 @@
+// Copyright 2014 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_CPP_SYSTEM_CORE_H_
+#define MOJO_PUBLIC_CPP_SYSTEM_CORE_H_
+
+#include "mojo/public/cpp/system/buffer.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/functions.h"
+#include "mojo/public/cpp/system/handle.h"
+#include "mojo/public/cpp/system/macros.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+#endif  // MOJO_PUBLIC_CPP_SYSTEM_CORE_H_
diff --git a/mojo/public/cpp/system/data_pipe.h b/mojo/public/cpp/system/data_pipe.h
new file mode 100644
index 0000000..b2f6e68
--- /dev/null
+++ b/mojo/public/cpp/system/data_pipe.h
@@ -0,0 +1,138 @@
+// Copyright 2014 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_CPP_SYSTEM_DATA_PIPE_H_
+#define MOJO_PUBLIC_CPP_SYSTEM_DATA_PIPE_H_
+
+#include <assert.h>
+
+#include "mojo/public/c/system/data_pipe.h"
+#include "mojo/public/cpp/system/handle.h"
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+
+// DataPipeProducerHandle and DataPipeConsumerHandle ---------------------------
+
+class DataPipeProducerHandle : public Handle {
+ public:
+  DataPipeProducerHandle() {}
+  explicit DataPipeProducerHandle(MojoHandle value) : Handle(value) {}
+
+  // Copying and assignment allowed.
+};
+
+MOJO_COMPILE_ASSERT(sizeof(DataPipeProducerHandle) == sizeof(Handle),
+                    bad_size_for_cpp_DataPipeProducerHandle);
+
+typedef ScopedHandleBase<DataPipeProducerHandle> ScopedDataPipeProducerHandle;
+MOJO_COMPILE_ASSERT(sizeof(ScopedDataPipeProducerHandle) ==
+                        sizeof(DataPipeProducerHandle),
+                    bad_size_for_cpp_ScopedDataPipeProducerHandle);
+
+class DataPipeConsumerHandle : public Handle {
+ public:
+  DataPipeConsumerHandle() {}
+  explicit DataPipeConsumerHandle(MojoHandle value) : Handle(value) {}
+
+  // Copying and assignment allowed.
+};
+
+MOJO_COMPILE_ASSERT(sizeof(DataPipeConsumerHandle) == sizeof(Handle),
+                    bad_size_for_cpp_DataPipeConsumerHandle);
+
+typedef ScopedHandleBase<DataPipeConsumerHandle> ScopedDataPipeConsumerHandle;
+MOJO_COMPILE_ASSERT(sizeof(ScopedDataPipeConsumerHandle) ==
+                        sizeof(DataPipeConsumerHandle),
+                    bad_size_for_cpp_ScopedDataPipeConsumerHandle);
+
+inline MojoResult CreateDataPipe(
+    const MojoCreateDataPipeOptions* options,
+    ScopedDataPipeProducerHandle* data_pipe_producer,
+    ScopedDataPipeConsumerHandle* data_pipe_consumer) {
+  assert(data_pipe_producer);
+  assert(data_pipe_consumer);
+  DataPipeProducerHandle producer_handle;
+  DataPipeConsumerHandle consumer_handle;
+  MojoResult rv = MojoCreateDataPipe(options, producer_handle.mutable_value(),
+                                     consumer_handle.mutable_value());
+  // Reset even on failure (reduces the chances that a "stale"/incorrect handle
+  // will be used).
+  data_pipe_producer->reset(producer_handle);
+  data_pipe_consumer->reset(consumer_handle);
+  return rv;
+}
+
+inline MojoResult WriteDataRaw(DataPipeProducerHandle data_pipe_producer,
+                               const void* elements,
+                               uint32_t* num_bytes,
+                               MojoWriteDataFlags flags) {
+  return MojoWriteData(data_pipe_producer.value(), elements, num_bytes, flags);
+}
+
+inline MojoResult BeginWriteDataRaw(DataPipeProducerHandle data_pipe_producer,
+                                    void** buffer,
+                                    uint32_t* buffer_num_bytes,
+                                    MojoWriteDataFlags flags) {
+  return MojoBeginWriteData(data_pipe_producer.value(), buffer,
+                            buffer_num_bytes, flags);
+}
+
+inline MojoResult EndWriteDataRaw(DataPipeProducerHandle data_pipe_producer,
+                                  uint32_t num_bytes_written) {
+  return MojoEndWriteData(data_pipe_producer.value(), num_bytes_written);
+}
+
+inline MojoResult ReadDataRaw(DataPipeConsumerHandle data_pipe_consumer,
+                              void* elements,
+                              uint32_t* num_bytes,
+                              MojoReadDataFlags flags) {
+  return MojoReadData(data_pipe_consumer.value(), elements, num_bytes, flags);
+}
+
+inline MojoResult BeginReadDataRaw(DataPipeConsumerHandle data_pipe_consumer,
+                                   const void** buffer,
+                                   uint32_t* buffer_num_bytes,
+                                   MojoReadDataFlags flags) {
+  return MojoBeginReadData(data_pipe_consumer.value(), buffer, buffer_num_bytes,
+                           flags);
+}
+
+inline MojoResult EndReadDataRaw(DataPipeConsumerHandle data_pipe_consumer,
+                                 uint32_t num_bytes_read) {
+  return MojoEndReadData(data_pipe_consumer.value(), num_bytes_read);
+}
+
+// A wrapper class that automatically creates a data pipe and owns both handles.
+// TODO(vtl): Make an even more friendly version? (Maybe templatized for a
+// particular type instead of some "element"? Maybe functions that take
+// vectors?)
+class DataPipe {
+ public:
+  DataPipe();
+  explicit DataPipe(const MojoCreateDataPipeOptions& options);
+  ~DataPipe();
+
+  ScopedDataPipeProducerHandle producer_handle;
+  ScopedDataPipeConsumerHandle consumer_handle;
+};
+
+inline DataPipe::DataPipe() {
+  MojoResult result MOJO_ALLOW_UNUSED =
+      CreateDataPipe(nullptr, &producer_handle, &consumer_handle);
+  assert(result == MOJO_RESULT_OK);
+}
+
+inline DataPipe::DataPipe(const MojoCreateDataPipeOptions& options) {
+  MojoResult result MOJO_ALLOW_UNUSED =
+      CreateDataPipe(&options, &producer_handle, &consumer_handle);
+  assert(result == MOJO_RESULT_OK);
+}
+
+inline DataPipe::~DataPipe() {
+}
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_SYSTEM_DATA_PIPE_H_
diff --git a/mojo/public/cpp/system/functions.h b/mojo/public/cpp/system/functions.h
new file mode 100644
index 0000000..d73d27a
--- /dev/null
+++ b/mojo/public/cpp/system/functions.h
@@ -0,0 +1,20 @@
+// Copyright 2014 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_CPP_SYSTEM_FUNCTIONS_H_
+#define MOJO_PUBLIC_CPP_SYSTEM_FUNCTIONS_H_
+
+#include "mojo/public/c/system/functions.h"
+
+namespace mojo {
+
+// Standalone functions --------------------------------------------------------
+
+inline MojoTimeTicks GetTimeTicksNow() {
+  return MojoGetTimeTicksNow();
+}
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_SYSTEM_FUNCTIONS_H_
diff --git a/mojo/public/cpp/system/handle.h b/mojo/public/cpp/system/handle.h
new file mode 100644
index 0000000..72b14c8
--- /dev/null
+++ b/mojo/public/cpp/system/handle.h
@@ -0,0 +1,246 @@
+// Copyright 2014 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_CPP_SYSTEM_HANDLE_H_
+#define MOJO_PUBLIC_CPP_SYSTEM_HANDLE_H_
+
+#include <assert.h>
+#include <limits>
+
+#include "mojo/public/c/system/functions.h"
+#include "mojo/public/c/system/types.h"
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+
+// OVERVIEW
+//
+// |Handle| and |...Handle|:
+//
+// |Handle| is a simple, copyable wrapper for the C type |MojoHandle| (which is
+// just an integer). Its purpose is to increase type-safety, not provide
+// lifetime management. For the same purpose, we have trivial *subclasses* of
+// |Handle|, e.g., |MessagePipeHandle| and |DataPipeProducerHandle|. |Handle|
+// and its subclasses impose *no* extra overhead over using |MojoHandle|s
+// directly.
+//
+// Note that though we provide constructors for |Handle|/|...Handle| from a
+// |MojoHandle|, we do not provide, e.g., a constructor for |MessagePipeHandle|
+// from a |Handle|. This is for type safety: If we did, you'd then be able to
+// construct a |MessagePipeHandle| from, e.g., a |DataPipeProducerHandle| (since
+// it's a |Handle|).
+//
+// |ScopedHandleBase| and |Scoped...Handle|:
+//
+// |ScopedHandleBase<HandleType>| is a templated scoped wrapper, for the handle
+// types above (in the same sense that a C++11 |unique_ptr<T>| is a scoped
+// wrapper for a |T*|). It provides lifetime management, closing its owned
+// handle on destruction. It also provides (emulated) move semantics, again
+// along the lines of C++11's |unique_ptr| (and exactly like Chromium's
+// |scoped_ptr|).
+//
+// |ScopedHandle| is just (a typedef of) a |ScopedHandleBase<Handle>|.
+// Similarly, |ScopedMessagePipeHandle| is just a
+// |ScopedHandleBase<MessagePipeHandle>|. Etc. Note that a
+// |ScopedMessagePipeHandle| is *not* a (subclass of) |ScopedHandle|.
+//
+// Wrapper functions:
+//
+// We provide simple wrappers for the |Mojo...()| functions (in
+// mojo/public/c/system/core.h -- see that file for details on individual
+// functions).
+//
+// The general guideline is functions that imply ownership transfer of a handle
+// should take (or produce) an appropriate |Scoped...Handle|, while those that
+// don't take a |...Handle|. For example, |CreateMessagePipe()| has two
+// |ScopedMessagePipe| "out" parameters, whereas |Wait()| and |WaitMany()| take
+// |Handle| parameters. Some, have both: e.g., |DuplicatedBuffer()| takes a
+// suitable (unscoped) handle (e.g., |SharedBufferHandle|) "in" parameter and
+// produces a suitable scoped handle (e.g., |ScopedSharedBufferHandle| a.k.a.
+// |ScopedHandleBase<SharedBufferHandle>|) as an "out" parameter.
+//
+// An exception are some of the |...Raw()| functions. E.g., |CloseRaw()| takes a
+// |Handle|, leaving the user to discard the handle.
+//
+// More significantly, |WriteMessageRaw()| exposes the full API complexity of
+// |MojoWriteMessage()| (but doesn't require any extra overhead). It takes a raw
+// array of |Handle|s as input, and takes ownership of them (i.e., invalidates
+// them) on *success* (but not on failure). There are a number of reasons for
+// this. First, C++03 |std::vector|s cannot contain the move-only
+// |Scoped...Handle|s. Second, |std::vector|s impose extra overhead
+// (necessitating heap-allocation of the buffer). Third, |std::vector|s wouldn't
+// provide the desired level of flexibility/safety: a vector of handles would
+// have to be all of the same type (probably |Handle|/|ScopedHandle|). Fourth,
+// it's expected to not be used directly, but instead be used by generated
+// bindings.
+//
+// Other |...Raw()| functions expose similar rough edges, e.g., dealing with raw
+// pointers (and lengths) instead of taking |std::vector|s or similar.
+
+// ScopedHandleBase ------------------------------------------------------------
+
+// Scoper for the actual handle types defined further below. It's move-only,
+// like the C++11 |unique_ptr|.
+template <class HandleType>
+class ScopedHandleBase {
+  MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(ScopedHandleBase, RValue)
+
+ public:
+  ScopedHandleBase() {}
+  explicit ScopedHandleBase(HandleType handle) : handle_(handle) {}
+  ~ScopedHandleBase() { CloseIfNecessary(); }
+
+  template <class CompatibleHandleType>
+  explicit ScopedHandleBase(ScopedHandleBase<CompatibleHandleType> other)
+      : handle_(other.release()) {
+  }
+
+  // Move-only constructor and operator=.
+  ScopedHandleBase(RValue other) : handle_(other.object->release()) {}
+  ScopedHandleBase& operator=(RValue other) {
+    if (other.object != this) {
+      CloseIfNecessary();
+      handle_ = other.object->release();
+    }
+    return *this;
+  }
+
+  const HandleType& get() const { return handle_; }
+
+  template <typename PassedHandleType>
+  static ScopedHandleBase<HandleType> From(
+      ScopedHandleBase<PassedHandleType> other) {
+    MOJO_COMPILE_ASSERT(
+        sizeof(static_cast<PassedHandleType*>(static_cast<HandleType*>(0))),
+        HandleType_is_not_a_subtype_of_PassedHandleType);
+    return ScopedHandleBase<HandleType>(
+        static_cast<HandleType>(other.release().value()));
+  }
+
+  void swap(ScopedHandleBase& other) {
+    handle_.swap(other.handle_);
+  }
+
+  HandleType release() MOJO_WARN_UNUSED_RESULT {
+    HandleType rv;
+    rv.swap(handle_);
+    return rv;
+  }
+
+  void reset(HandleType handle = HandleType()) {
+    CloseIfNecessary();
+    handle_ = handle;
+  }
+
+  bool is_valid() const {
+    return handle_.is_valid();
+  }
+
+ private:
+  void CloseIfNecessary() {
+    if (!handle_.is_valid())
+      return;
+    MojoResult result MOJO_ALLOW_UNUSED = MojoClose(handle_.value());
+    assert(result == MOJO_RESULT_OK);
+  }
+
+  HandleType handle_;
+};
+
+template <typename HandleType>
+inline ScopedHandleBase<HandleType> MakeScopedHandle(HandleType handle) {
+  return ScopedHandleBase<HandleType>(handle);
+}
+
+// Handle ----------------------------------------------------------------------
+
+const MojoHandle kInvalidHandleValue = MOJO_HANDLE_INVALID;
+
+// Wrapper base class for |MojoHandle|.
+class Handle {
+ public:
+  Handle() : value_(kInvalidHandleValue) {}
+  explicit Handle(MojoHandle value) : value_(value) {}
+  ~Handle() {}
+
+  void swap(Handle& other) {
+    MojoHandle temp = value_;
+    value_ = other.value_;
+    other.value_ = temp;
+  }
+
+  bool is_valid() const {
+    return value_ != kInvalidHandleValue;
+  }
+
+  const MojoHandle& value() const { return value_; }
+  MojoHandle* mutable_value() { return &value_; }
+  void set_value(MojoHandle value) { value_ = value; }
+
+ private:
+  MojoHandle value_;
+
+  // Copying and assignment allowed.
+};
+
+// Should have zero overhead.
+MOJO_COMPILE_ASSERT(sizeof(Handle) == sizeof(MojoHandle),
+                    bad_size_for_cpp_Handle);
+
+// The scoper should also impose no more overhead.
+typedef ScopedHandleBase<Handle> ScopedHandle;
+MOJO_COMPILE_ASSERT(sizeof(ScopedHandle) == sizeof(Handle),
+                    bad_size_for_cpp_ScopedHandle);
+
+inline MojoResult Wait(Handle handle,
+                       MojoHandleSignals signals,
+                       MojoDeadline deadline) {
+  return MojoWait(handle.value(), signals, deadline);
+}
+
+// |HandleVectorType| and |FlagsVectorType| should be similar enough to
+// |std::vector<Handle>| and |std::vector<MojoHandleSignals>|, respectively:
+//  - They should have a (const) |size()| method that returns an unsigned type.
+//  - They must provide contiguous storage, with access via (const) reference to
+//    that storage provided by a (const) |operator[]()| (by reference).
+template <class HandleVectorType, class FlagsVectorType>
+inline MojoResult WaitMany(const HandleVectorType& handles,
+                           const FlagsVectorType& signals,
+                           MojoDeadline deadline) {
+  if (signals.size() != handles.size())
+    return MOJO_RESULT_INVALID_ARGUMENT;
+  if (handles.size() > std::numeric_limits<uint32_t>::max())
+    return MOJO_RESULT_OUT_OF_RANGE;
+
+  if (handles.size() == 0)
+    return MojoWaitMany(nullptr, nullptr, 0, deadline);
+
+  const Handle& first_handle = handles[0];
+  const MojoHandleSignals& first_signals = signals[0];
+  return MojoWaitMany(
+      reinterpret_cast<const MojoHandle*>(&first_handle),
+      reinterpret_cast<const MojoHandleSignals*>(&first_signals),
+      static_cast<uint32_t>(handles.size()),
+      deadline);
+}
+
+// |Close()| takes ownership of the handle, since it'll invalidate it.
+// Note: There's nothing to do, since the argument will be destroyed when it
+// goes out of scope.
+template <class HandleType>
+inline void Close(ScopedHandleBase<HandleType> /*handle*/) {}
+
+// Most users should typically use |Close()| (above) instead.
+inline MojoResult CloseRaw(Handle handle) {
+  return MojoClose(handle.value());
+}
+
+// Strict weak ordering, so that |Handle|s can be used as keys in |std::map|s,
+inline bool operator<(const Handle a, const Handle b) {
+  return a.value() < b.value();
+}
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_SYSTEM_HANDLE_H_
diff --git a/mojo/public/cpp/system/macros.h b/mojo/public/cpp/system/macros.h
new file mode 100644
index 0000000..605906e
--- /dev/null
+++ b/mojo/public/cpp/system/macros.h
@@ -0,0 +1,48 @@
+// Copyright 2014 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_CPP_SYSTEM_MACROS_H_
+#define MOJO_PUBLIC_CPP_SYSTEM_MACROS_H_
+
+#include "mojo/public/c/system/macros.h"
+
+// Define a set of C++ specific macros.
+// Mojo C++ API users can assume that mojo/public/cpp/system/macros.h
+// includes mojo/public/c/system/macros.h.
+
+// A macro to disallow the copy constructor and operator= functions.
+// This should be used in the private: declarations for a class.
+#define MOJO_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+    TypeName(const TypeName&); \
+    void operator=(const TypeName&)
+
+// Used to calculate the number of elements in an array.
+// (See |arraysize()| in Chromium's base/basictypes.h for more details.)
+namespace mojo {
+template <typename T, size_t N>
+char (&ArraySizeHelper(T (&array)[N]))[N];
+#if !defined(_MSC_VER)
+template <typename T, size_t N>
+char (&ArraySizeHelper(const T (&array)[N]))[N];
+#endif
+}  // namespace mojo
+#define MOJO_ARRAYSIZE(array) (sizeof(::mojo::ArraySizeHelper(array)))
+
+// Used to make a type move-only in C++03. See Chromium's base/move.h for more
+// details.
+#define MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \
+   private: \
+    struct rvalue_type { \
+      explicit rvalue_type(type* object) : object(object) {} \
+      type* object; \
+    }; \
+    type(type&); \
+    void operator=(type&); \
+   public: \
+    operator rvalue_type() { return rvalue_type(this); } \
+    type Pass() { return type(rvalue_type(this)); } \
+    typedef void MoveOnlyTypeForCPP03; \
+   private:
+
+#endif  // MOJO_PUBLIC_CPP_SYSTEM_MACROS_H_
diff --git a/mojo/public/cpp/system/message_pipe.h b/mojo/public/cpp/system/message_pipe.h
new file mode 100644
index 0000000..7ef6314
--- /dev/null
+++ b/mojo/public/cpp/system/message_pipe.h
@@ -0,0 +1,103 @@
+// Copyright 2014 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_CPP_SYSTEM_MESSAGE_PIPE_H_
+#define MOJO_PUBLIC_CPP_SYSTEM_MESSAGE_PIPE_H_
+
+#include <assert.h>
+
+#include "mojo/public/c/system/message_pipe.h"
+#include "mojo/public/cpp/system/handle.h"
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+
+// MessagePipeHandle -----------------------------------------------------------
+
+class MessagePipeHandle : public Handle {
+ public:
+  MessagePipeHandle() {}
+  explicit MessagePipeHandle(MojoHandle value) : Handle(value) {}
+
+  // Copying and assignment allowed.
+};
+
+MOJO_COMPILE_ASSERT(sizeof(MessagePipeHandle) == sizeof(Handle),
+                    bad_size_for_cpp_MessagePipeHandle);
+
+typedef ScopedHandleBase<MessagePipeHandle> ScopedMessagePipeHandle;
+MOJO_COMPILE_ASSERT(sizeof(ScopedMessagePipeHandle) ==
+                        sizeof(MessagePipeHandle),
+                    bad_size_for_cpp_ScopedMessagePipeHandle);
+
+inline MojoResult CreateMessagePipe(const MojoCreateMessagePipeOptions* options,
+                                    ScopedMessagePipeHandle* message_pipe0,
+                                    ScopedMessagePipeHandle* message_pipe1) {
+  assert(message_pipe0);
+  assert(message_pipe1);
+  MessagePipeHandle handle0;
+  MessagePipeHandle handle1;
+  MojoResult rv = MojoCreateMessagePipe(options,
+                                        handle0.mutable_value(),
+                                        handle1.mutable_value());
+  // Reset even on failure (reduces the chances that a "stale"/incorrect handle
+  // will be used).
+  message_pipe0->reset(handle0);
+  message_pipe1->reset(handle1);
+  return rv;
+}
+
+// These "raw" versions fully expose the underlying API, but don't help with
+// ownership of handles (especially when writing messages).
+// TODO(vtl): Write "baked" versions.
+inline MojoResult WriteMessageRaw(MessagePipeHandle message_pipe,
+                                  const void* bytes,
+                                  uint32_t num_bytes,
+                                  const MojoHandle* handles,
+                                  uint32_t num_handles,
+                                  MojoWriteMessageFlags flags) {
+  return MojoWriteMessage(message_pipe.value(), bytes, num_bytes, handles,
+                          num_handles, flags);
+}
+
+inline MojoResult ReadMessageRaw(MessagePipeHandle message_pipe,
+                                 void* bytes,
+                                 uint32_t* num_bytes,
+                                 MojoHandle* handles,
+                                 uint32_t* num_handles,
+                                 MojoReadMessageFlags flags) {
+  return MojoReadMessage(message_pipe.value(), bytes, num_bytes, handles,
+                         num_handles, flags);
+}
+
+// A wrapper class that automatically creates a message pipe and owns both
+// handles.
+class MessagePipe {
+ public:
+  MessagePipe();
+  explicit MessagePipe(const MojoCreateMessagePipeOptions& options);
+  ~MessagePipe();
+
+  ScopedMessagePipeHandle handle0;
+  ScopedMessagePipeHandle handle1;
+};
+
+inline MessagePipe::MessagePipe() {
+  MojoResult result MOJO_ALLOW_UNUSED =
+      CreateMessagePipe(nullptr, &handle0, &handle1);
+  assert(result == MOJO_RESULT_OK);
+}
+
+inline MessagePipe::MessagePipe(const MojoCreateMessagePipeOptions& options) {
+  MojoResult result MOJO_ALLOW_UNUSED =
+      CreateMessagePipe(&options, &handle0, &handle1);
+  assert(result == MOJO_RESULT_OK);
+}
+
+inline MessagePipe::~MessagePipe() {
+}
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_SYSTEM_MESSAGE_PIPE_H_
diff --git a/mojo/public/cpp/system/tests/BUILD.gn b/mojo/public/cpp/system/tests/BUILD.gn
new file mode 100644
index 0000000..3226662
--- /dev/null
+++ b/mojo/public/cpp/system/tests/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2014 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.
+
+# GYP version: mojo/mojo_public_tests.gypi:mojo_public_system_unittests
+test("mojo_public_system_unittests") {
+  deps = [
+    "//mojo/common/test:run_all_unittests",
+    "//mojo/public/c/system/tests",
+    "//mojo/public/cpp/system",
+    "//mojo/public/cpp/test_support:test_utils",
+    "//testing/gtest",
+  ]
+
+  sources = [
+    "core_unittest.cc",
+    "macros_unittest.cc",
+  ]
+}
diff --git a/mojo/public/cpp/system/tests/core_unittest.cc b/mojo/public/cpp/system/tests/core_unittest.cc
new file mode 100644
index 0000000..a44bc07
--- /dev/null
+++ b/mojo/public/cpp/system/tests/core_unittest.cc
@@ -0,0 +1,419 @@
+// Copyright 2014 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 tests the C++ Mojo system core wrappers.
+// TODO(vtl): Maybe rename "CoreCppTest" -> "CoreTest" if/when this gets
+// compiled into a different binary from the C API tests.
+
+#include "mojo/public/cpp/system/core.h"
+
+#include <map>
+
+#include "mojo/public/cpp/system/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+TEST(CoreCppTest, GetTimeTicksNow) {
+  const MojoTimeTicks start = GetTimeTicksNow();
+  EXPECT_NE(static_cast<MojoTimeTicks>(0), start)
+      << "GetTimeTicksNow should return nonzero value";
+}
+
+TEST(CoreCppTest, Basic) {
+  // Basic |Handle| implementation:
+  {
+    EXPECT_EQ(MOJO_HANDLE_INVALID, kInvalidHandleValue);
+
+    Handle h0;
+    EXPECT_EQ(kInvalidHandleValue, h0.value());
+    EXPECT_EQ(kInvalidHandleValue, *h0.mutable_value());
+    EXPECT_FALSE(h0.is_valid());
+
+    Handle h1(static_cast<MojoHandle>(123));
+    EXPECT_EQ(static_cast<MojoHandle>(123), h1.value());
+    EXPECT_EQ(static_cast<MojoHandle>(123), *h1.mutable_value());
+    EXPECT_TRUE(h1.is_valid());
+    *h1.mutable_value() = static_cast<MojoHandle>(456);
+    EXPECT_EQ(static_cast<MojoHandle>(456), h1.value());
+    EXPECT_TRUE(h1.is_valid());
+
+    h1.swap(h0);
+    EXPECT_EQ(static_cast<MojoHandle>(456), h0.value());
+    EXPECT_TRUE(h0.is_valid());
+    EXPECT_FALSE(h1.is_valid());
+
+    h1.set_value(static_cast<MojoHandle>(789));
+    h0.swap(h1);
+    EXPECT_EQ(static_cast<MojoHandle>(789), h0.value());
+    EXPECT_TRUE(h0.is_valid());
+    EXPECT_EQ(static_cast<MojoHandle>(456), h1.value());
+    EXPECT_TRUE(h1.is_valid());
+
+    // Make sure copy constructor works.
+    Handle h2(h0);
+    EXPECT_EQ(static_cast<MojoHandle>(789), h2.value());
+    // And assignment.
+    h2 = h1;
+    EXPECT_EQ(static_cast<MojoHandle>(456), h2.value());
+
+    // Make sure that we can put |Handle|s into |std::map|s.
+    h0 = Handle(static_cast<MojoHandle>(987));
+    h1 = Handle(static_cast<MojoHandle>(654));
+    h2 = Handle(static_cast<MojoHandle>(321));
+    Handle h3;
+    std::map<Handle, int> handle_to_int;
+    handle_to_int[h0] = 0;
+    handle_to_int[h1] = 1;
+    handle_to_int[h2] = 2;
+    handle_to_int[h3] = 3;
+
+    EXPECT_EQ(4u, handle_to_int.size());
+    EXPECT_FALSE(handle_to_int.find(h0) == handle_to_int.end());
+    EXPECT_EQ(0, handle_to_int[h0]);
+    EXPECT_FALSE(handle_to_int.find(h1) == handle_to_int.end());
+    EXPECT_EQ(1, handle_to_int[h1]);
+    EXPECT_FALSE(handle_to_int.find(h2) == handle_to_int.end());
+    EXPECT_EQ(2, handle_to_int[h2]);
+    EXPECT_FALSE(handle_to_int.find(h3) == handle_to_int.end());
+    EXPECT_EQ(3, handle_to_int[h3]);
+    EXPECT_TRUE(handle_to_int.find(Handle(static_cast<MojoHandle>(13579))) ==
+                    handle_to_int.end());
+
+    // TODO(vtl): With C++11, support |std::unordered_map|s, etc. (Or figure out
+    // how to support the variations of |hash_map|.)
+  }
+
+  // |Handle|/|ScopedHandle| functions:
+  {
+    ScopedHandle h;
+
+    EXPECT_EQ(kInvalidHandleValue, h.get().value());
+
+    // This should be a no-op.
+    Close(h.Pass());
+
+    // It should still be invalid.
+    EXPECT_EQ(kInvalidHandleValue, h.get().value());
+
+    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+              Wait(h.get(), ~MOJO_HANDLE_SIGNAL_NONE, 1000000));
+
+    std::vector<Handle> wh;
+    wh.push_back(h.get());
+    std::vector<MojoHandleSignals> sigs;
+    sigs.push_back(~MOJO_HANDLE_SIGNAL_NONE);
+    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+              WaitMany(wh, sigs, MOJO_DEADLINE_INDEFINITE));
+  }
+
+  // |MakeScopedHandle| (just compilation tests):
+  {
+    EXPECT_FALSE(MakeScopedHandle(Handle()).is_valid());
+    EXPECT_FALSE(MakeScopedHandle(MessagePipeHandle()).is_valid());
+    EXPECT_FALSE(MakeScopedHandle(DataPipeProducerHandle()).is_valid());
+    EXPECT_FALSE(MakeScopedHandle(DataPipeConsumerHandle()).is_valid());
+    EXPECT_FALSE(MakeScopedHandle(SharedBufferHandle()).is_valid());
+  }
+
+  // |MessagePipeHandle|/|ScopedMessagePipeHandle| functions:
+  {
+    MessagePipeHandle h_invalid;
+    EXPECT_FALSE(h_invalid.is_valid());
+    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+              WriteMessageRaw(h_invalid,
+                              nullptr, 0,
+                              nullptr, 0,
+                              MOJO_WRITE_MESSAGE_FLAG_NONE));
+    char buffer[10] = { 0 };
+    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+              WriteMessageRaw(h_invalid,
+                              buffer, sizeof(buffer),
+                              nullptr, 0,
+                              MOJO_WRITE_MESSAGE_FLAG_NONE));
+    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+              ReadMessageRaw(h_invalid,
+                             nullptr, nullptr,
+                             nullptr, nullptr,
+                             MOJO_READ_MESSAGE_FLAG_NONE));
+    uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
+    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+              ReadMessageRaw(h_invalid,
+                             buffer, &buffer_size,
+                             nullptr, nullptr,
+                             MOJO_READ_MESSAGE_FLAG_NONE));
+
+    // Basic tests of waiting and closing.
+    MojoHandle hv0 = kInvalidHandleValue;
+    {
+      ScopedMessagePipeHandle h0;
+      ScopedMessagePipeHandle h1;
+      EXPECT_FALSE(h0.get().is_valid());
+      EXPECT_FALSE(h1.get().is_valid());
+
+      CreateMessagePipe(nullptr, &h0, &h1);
+      EXPECT_TRUE(h0.get().is_valid());
+      EXPECT_TRUE(h1.get().is_valid());
+      EXPECT_NE(h0.get().value(), h1.get().value());
+      // Save the handle values, so we can check that things got closed
+      // correctly.
+      hv0 = h0.get().value();
+      MojoHandle hv1 = h1.get().value();
+
+      EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
+                Wait(h0.get(), MOJO_HANDLE_SIGNAL_READABLE, 0));
+      std::vector<Handle> wh;
+      wh.push_back(h0.get());
+      wh.push_back(h1.get());
+      std::vector<MojoHandleSignals> sigs;
+      sigs.push_back(MOJO_HANDLE_SIGNAL_READABLE);
+      sigs.push_back(MOJO_HANDLE_SIGNAL_WRITABLE);
+      EXPECT_EQ(1, WaitMany(wh, sigs, 1000));
+
+      // Test closing |h1| explicitly.
+      Close(h1.Pass());
+      EXPECT_FALSE(h1.get().is_valid());
+
+      // Make sure |h1| is closed.
+      EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+                MojoWait(hv1, ~MOJO_HANDLE_SIGNAL_NONE,
+                         MOJO_DEADLINE_INDEFINITE));
+
+      EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+                Wait(h0.get(), MOJO_HANDLE_SIGNAL_READABLE,
+                     MOJO_DEADLINE_INDEFINITE));
+    }
+    // |hv0| should have been closed when |h0| went out of scope, so this close
+    // should fail.
+    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(hv0));
+
+    // Actually test writing/reading messages.
+    {
+      ScopedMessagePipeHandle h0;
+      ScopedMessagePipeHandle h1;
+      CreateMessagePipe(nullptr, &h0, &h1);
+
+      const char kHello[] = "hello";
+      const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello));
+      EXPECT_EQ(MOJO_RESULT_OK,
+                WriteMessageRaw(h0.get(),
+                                kHello, kHelloSize,
+                                nullptr, 0,
+                                MOJO_WRITE_MESSAGE_FLAG_NONE));
+      EXPECT_EQ(MOJO_RESULT_OK,
+                Wait(h1.get(), MOJO_HANDLE_SIGNAL_READABLE,
+                     MOJO_DEADLINE_INDEFINITE));
+      char buffer[10] = { 0 };
+      uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
+      EXPECT_EQ(MOJO_RESULT_OK,
+                ReadMessageRaw(h1.get(),
+                               buffer, &buffer_size,
+                               nullptr, nullptr,
+                               MOJO_READ_MESSAGE_FLAG_NONE));
+      EXPECT_EQ(kHelloSize, buffer_size);
+      EXPECT_STREQ(kHello, buffer);
+
+      // Send a handle over the previously-establish message pipe. Use the
+      // |MessagePipe| wrapper (to test it), which automatically creates a
+      // message pipe.
+      MessagePipe mp;
+
+      // Write a message to |mp.handle0|, before we send |mp.handle1|.
+      const char kWorld[] = "world!";
+      const uint32_t kWorldSize = static_cast<uint32_t>(sizeof(kWorld));
+      EXPECT_EQ(MOJO_RESULT_OK,
+                WriteMessageRaw(mp.handle0.get(),
+                                kWorld, kWorldSize,
+                                nullptr, 0,
+                                MOJO_WRITE_MESSAGE_FLAG_NONE));
+
+      // Send |mp.handle1| over |h1| to |h0|.
+      MojoHandle handles[5];
+      handles[0] = mp.handle1.release().value();
+      EXPECT_NE(kInvalidHandleValue, handles[0]);
+      EXPECT_FALSE(mp.handle1.get().is_valid());
+      uint32_t handles_count = 1;
+      EXPECT_EQ(MOJO_RESULT_OK,
+                WriteMessageRaw(h1.get(),
+                                kHello, kHelloSize,
+                                handles, handles_count,
+                                MOJO_WRITE_MESSAGE_FLAG_NONE));
+      // |handles[0]| should actually be invalid now.
+      EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(handles[0]));
+
+      // Read "hello" and the sent handle.
+      EXPECT_EQ(MOJO_RESULT_OK,
+                Wait(h0.get(), MOJO_HANDLE_SIGNAL_READABLE,
+                     MOJO_DEADLINE_INDEFINITE));
+      memset(buffer, 0, sizeof(buffer));
+      buffer_size = static_cast<uint32_t>(sizeof(buffer));
+      for (size_t i = 0; i < MOJO_ARRAYSIZE(handles); i++)
+        handles[i] = kInvalidHandleValue;
+      handles_count = static_cast<uint32_t>(MOJO_ARRAYSIZE(handles));
+      EXPECT_EQ(MOJO_RESULT_OK,
+                ReadMessageRaw(h0.get(),
+                               buffer, &buffer_size,
+                               handles, &handles_count,
+                               MOJO_READ_MESSAGE_FLAG_NONE));
+      EXPECT_EQ(kHelloSize, buffer_size);
+      EXPECT_STREQ(kHello, buffer);
+      EXPECT_EQ(1u, handles_count);
+      EXPECT_NE(kInvalidHandleValue, handles[0]);
+
+      // Read from the sent/received handle.
+      mp.handle1.reset(MessagePipeHandle(handles[0]));
+      // Save |handles[0]| to check that it gets properly closed.
+      hv0 = handles[0];
+      EXPECT_EQ(MOJO_RESULT_OK,
+                Wait(mp.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE,
+                     MOJO_DEADLINE_INDEFINITE));
+      memset(buffer, 0, sizeof(buffer));
+      buffer_size = static_cast<uint32_t>(sizeof(buffer));
+      for (size_t i = 0; i < MOJO_ARRAYSIZE(handles); i++)
+        handles[i] = kInvalidHandleValue;
+      handles_count = static_cast<uint32_t>(MOJO_ARRAYSIZE(handles));
+      EXPECT_EQ(MOJO_RESULT_OK,
+                ReadMessageRaw(mp.handle1.get(),
+                               buffer, &buffer_size,
+                               handles, &handles_count,
+                               MOJO_READ_MESSAGE_FLAG_NONE));
+      EXPECT_EQ(kWorldSize, buffer_size);
+      EXPECT_STREQ(kWorld, buffer);
+      EXPECT_EQ(0u, handles_count);
+    }
+    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(hv0));
+  }
+
+  // TODO(vtl): Test |CloseRaw()|.
+  // TODO(vtl): Test |reset()| more thoroughly?
+}
+
+TEST(CoreCppTest, TearDownWithMessagesEnqueued) {
+  // Tear down a message pipe which still has a message enqueued, with the
+  // message also having a valid message pipe handle.
+  {
+    ScopedMessagePipeHandle h0;
+    ScopedMessagePipeHandle h1;
+    CreateMessagePipe(nullptr, &h0, &h1);
+
+    // Send a handle over the previously-establish message pipe.
+    ScopedMessagePipeHandle h2;
+    ScopedMessagePipeHandle h3;
+    CreateMessagePipe(nullptr, &h2, &h3);
+
+    // Write a message to |h2|, before we send |h3|.
+    const char kWorld[] = "world!";
+    const uint32_t kWorldSize = static_cast<uint32_t>(sizeof(kWorld));
+    EXPECT_EQ(MOJO_RESULT_OK,
+              WriteMessageRaw(h2.get(),
+                              kWorld, kWorldSize,
+                              nullptr, 0,
+                              MOJO_WRITE_MESSAGE_FLAG_NONE));
+    // And also a message to |h3|.
+    EXPECT_EQ(MOJO_RESULT_OK,
+              WriteMessageRaw(h3.get(),
+                              kWorld, kWorldSize,
+                              nullptr, 0,
+                              MOJO_WRITE_MESSAGE_FLAG_NONE));
+
+    // Send |h3| over |h1| to |h0|.
+    const char kHello[] = "hello";
+    const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello));
+    MojoHandle h3_value;
+    h3_value = h3.release().value();
+    EXPECT_NE(kInvalidHandleValue, h3_value);
+    EXPECT_FALSE(h3.get().is_valid());
+    EXPECT_EQ(MOJO_RESULT_OK,
+              WriteMessageRaw(h1.get(),
+                              kHello, kHelloSize,
+                              &h3_value, 1,
+                              MOJO_WRITE_MESSAGE_FLAG_NONE));
+    // |h3_value| should actually be invalid now.
+    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(h3_value));
+
+    EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h0.release().value()));
+    EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h1.release().value()));
+    EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h2.release().value()));
+  }
+
+  // Do this in a different order: make the enqueued message pipe handle only
+  // half-alive.
+  {
+    ScopedMessagePipeHandle h0;
+    ScopedMessagePipeHandle h1;
+    CreateMessagePipe(nullptr, &h0, &h1);
+
+    // Send a handle over the previously-establish message pipe.
+    ScopedMessagePipeHandle h2;
+    ScopedMessagePipeHandle h3;
+    CreateMessagePipe(nullptr, &h2, &h3);
+
+    // Write a message to |h2|, before we send |h3|.
+    const char kWorld[] = "world!";
+    const uint32_t kWorldSize = static_cast<uint32_t>(sizeof(kWorld));
+    EXPECT_EQ(MOJO_RESULT_OK,
+              WriteMessageRaw(h2.get(),
+                              kWorld, kWorldSize,
+                              nullptr, 0,
+                              MOJO_WRITE_MESSAGE_FLAG_NONE));
+    // And also a message to |h3|.
+    EXPECT_EQ(MOJO_RESULT_OK,
+              WriteMessageRaw(h3.get(),
+                              kWorld, kWorldSize,
+                              nullptr, 0,
+                              MOJO_WRITE_MESSAGE_FLAG_NONE));
+
+    // Send |h3| over |h1| to |h0|.
+    const char kHello[] = "hello";
+    const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello));
+    MojoHandle h3_value;
+    h3_value = h3.release().value();
+    EXPECT_NE(kInvalidHandleValue, h3_value);
+    EXPECT_FALSE(h3.get().is_valid());
+    EXPECT_EQ(MOJO_RESULT_OK,
+              WriteMessageRaw(h1.get(),
+                              kHello, kHelloSize,
+                              &h3_value, 1,
+                              MOJO_WRITE_MESSAGE_FLAG_NONE));
+    // |h3_value| should actually be invalid now.
+    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(h3_value));
+
+    EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h2.release().value()));
+    EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h0.release().value()));
+    EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h1.release().value()));
+  }
+}
+
+TEST(CoreCppTest, ScopedHandleMoveCtor) {
+  ScopedSharedBufferHandle buffer1;
+  EXPECT_EQ(MOJO_RESULT_OK, CreateSharedBuffer(nullptr, 1024, &buffer1));
+  EXPECT_TRUE(buffer1.is_valid());
+
+  ScopedSharedBufferHandle buffer2;
+  EXPECT_EQ(MOJO_RESULT_OK, CreateSharedBuffer(nullptr, 1024, &buffer2));
+  EXPECT_TRUE(buffer2.is_valid());
+
+  // If this fails to close buffer1, ScopedHandleBase::CloseIfNecessary() will
+  // assert.
+  buffer1 = buffer2.Pass();
+
+  EXPECT_TRUE(buffer1.is_valid());
+  EXPECT_FALSE(buffer2.is_valid());
+}
+
+TEST(CoreCppTest, ScopedHandleMoveCtorSelf) {
+  ScopedSharedBufferHandle buffer1;
+  EXPECT_EQ(MOJO_RESULT_OK, CreateSharedBuffer(nullptr, 1024, &buffer1));
+  EXPECT_TRUE(buffer1.is_valid());
+
+  buffer1 = buffer1.Pass();
+
+  EXPECT_TRUE(buffer1.is_valid());
+}
+
+// TODO(vtl): Write data pipe tests.
+
+}  // namespace
+}  // namespace mojo
diff --git a/mojo/public/cpp/system/tests/macros_unittest.cc b/mojo/public/cpp/system/tests/macros_unittest.cc
new file mode 100644
index 0000000..49a8005
--- /dev/null
+++ b/mojo/public/cpp/system/tests/macros_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright 2014 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 tests the C++ Mojo system macros and consists of "positive" tests,
+// i.e., those verifying that things work (without compile errors, or even
+// warnings if warnings are treated as errors).
+// TODO(vtl): Maybe rename "MacrosCppTest" -> "MacrosTest" if/when this gets
+// compiled into a different binary from the C API tests.
+// TODO(vtl): Fix no-compile tests (which are all disabled; crbug.com/105388)
+// and write some "negative" tests.
+
+#include "mojo/public/cpp/system/macros.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+// Note: MSVS is very strict (and arguably buggy) about warnings for classes
+// defined in a local scope, so define these globally.
+struct TestOverrideBaseClass {
+  virtual ~TestOverrideBaseClass() {}
+  virtual void ToBeOverridden() {}
+  virtual void AlsoToBeOverridden() = 0;
+};
+
+struct TestOverrideSubclass : public TestOverrideBaseClass {
+  virtual ~TestOverrideSubclass() {}
+  virtual void ToBeOverridden() override {}
+  virtual void AlsoToBeOverridden() override {}
+};
+
+TEST(MacrosCppTest, Override) {
+  TestOverrideSubclass x;
+  x.ToBeOverridden();
+  x.AlsoToBeOverridden();
+}
+
+// Note: MSVS is very strict (and arguably buggy) about warnings for classes
+// defined in a local scope, so define these globally.
+class TestDisallowCopyAndAssignClass {
+ public:
+  TestDisallowCopyAndAssignClass() {}
+  explicit TestDisallowCopyAndAssignClass(int) {}
+  void NoOp() {}
+
+ private:
+  MOJO_DISALLOW_COPY_AND_ASSIGN(TestDisallowCopyAndAssignClass);
+};
+
+TEST(MacrosCppTest, DisallowCopyAndAssign) {
+  TestDisallowCopyAndAssignClass x;
+  x.NoOp();
+  TestDisallowCopyAndAssignClass y(789);
+  y.NoOp();
+}
+
+// Test that |MOJO_ARRAYSIZE()| works in a |MOJO_COMPILE_ASSERT()|.
+const int kGlobalArray[5] = { 1, 2, 3, 4, 5 };
+MOJO_COMPILE_ASSERT(MOJO_ARRAYSIZE(kGlobalArray) == 5u,
+                    mojo_array_size_failed_in_compile_assert);
+
+TEST(MacrosCppTest, ArraySize) {
+  double local_array[4] = { 6.7, 7.8, 8.9, 9.0 };
+  EXPECT_EQ(4u, MOJO_ARRAYSIZE(local_array));
+}
+
+// Note: MSVS is very strict (and arguably buggy) about warnings for classes
+// defined in a local scope, so define these globally.
+class MoveOnlyInt {
+  MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(MoveOnlyInt, RValue)
+
+ public:
+  MoveOnlyInt() : is_set_(false), value_() {}
+  explicit MoveOnlyInt(int value) : is_set_(true), value_(value) {}
+  ~MoveOnlyInt() {}
+
+  // Move-only constructor and operator=.
+  MoveOnlyInt(RValue other) { *this = other; }
+  MoveOnlyInt& operator=(RValue other) {
+    if (other.object != this) {
+      is_set_ = other.object->is_set_;
+      value_ = other.object->value_;
+      other.object->is_set_ = false;
+    }
+    return *this;
+  }
+
+  int value() const {
+    assert(is_set());
+    return value_;
+  }
+  bool is_set() const { return is_set_; }
+
+ private:
+  bool is_set_;
+  int value_;
+};
+
+TEST(MacrosCppTest, MoveOnlyTypeForCpp03) {
+  MoveOnlyInt x(123);
+  EXPECT_TRUE(x.is_set());
+  EXPECT_EQ(123, x.value());
+  MoveOnlyInt y;
+  EXPECT_FALSE(y.is_set());
+  y = x.Pass();
+  EXPECT_FALSE(x.is_set());
+  EXPECT_TRUE(y.is_set());
+  EXPECT_EQ(123, y.value());
+  MoveOnlyInt z(y.Pass());
+  EXPECT_FALSE(y.is_set());
+  EXPECT_TRUE(z.is_set());
+  EXPECT_EQ(123, z.value());
+  z = z.Pass();
+  EXPECT_TRUE(z.is_set());
+  EXPECT_EQ(123, z.value());
+}
+
+}  // namespace
+}  // namespace mojo
diff --git a/mojo/public/cpp/test_support/BUILD.gn b/mojo/public/cpp/test_support/BUILD.gn
new file mode 100644
index 0000000..6c73c29
--- /dev/null
+++ b/mojo/public/cpp/test_support/BUILD.gn
@@ -0,0 +1,20 @@
+# Copyright 2014 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.
+
+# GYP version: mojo/mojo_public_tests.gypi:mojo_public_test_utils
+source_set("test_utils") {
+  testonly = true
+  deps = [
+    "//base",
+    "//mojo/public/c/test_support",
+    "//mojo/public/cpp/system",
+    "//testing/gtest",
+  ]
+
+  sources = [
+    "lib/test_support.cc",
+    "lib/test_utils.cc",
+    "test_utils.h",
+  ]
+}
diff --git a/mojo/public/cpp/test_support/DEPS b/mojo/public/cpp/test_support/DEPS
new file mode 100644
index 0000000..6dc5394
--- /dev/null
+++ b/mojo/public/cpp/test_support/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+mojo/public/c/test_support",
+]
diff --git a/mojo/public/cpp/test_support/lib/test_support.cc b/mojo/public/cpp/test_support/lib/test_support.cc
new file mode 100644
index 0000000..0b6035b
--- /dev/null
+++ b/mojo/public/cpp/test_support/lib/test_support.cc
@@ -0,0 +1,26 @@
+// Copyright 2014 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/cpp/test_support/test_support.h"
+
+#include <stdlib.h>
+
+namespace mojo {
+namespace test {
+
+std::vector<std::string> EnumerateSourceRootRelativeDirectory(
+    const std::string& relative_path) {
+  char** names = MojoTestSupportEnumerateSourceRootRelativeDirectory(
+      relative_path.c_str());
+  std::vector<std::string> results;
+  for (char** ptr = names; *ptr != nullptr; ++ptr) {
+    results.push_back(*ptr);
+    free(*ptr);
+  }
+  free(names);
+  return results;
+}
+
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/test_support/lib/test_utils.cc b/mojo/public/cpp/test_support/lib/test_utils.cc
new file mode 100644
index 0000000..8491c4b
--- /dev/null
+++ b/mojo/public/cpp/test_support/lib/test_utils.cc
@@ -0,0 +1,91 @@
+// Copyright 2013 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/cpp/test_support/test_utils.h"
+
+#include "mojo/public/cpp/system/core.h"
+#include "mojo/public/cpp/test_support/test_support.h"
+
+namespace mojo {
+namespace test {
+
+bool WriteTextMessage(const MessagePipeHandle& handle,
+                      const std::string& text) {
+  MojoResult rv = WriteMessageRaw(handle,
+                                  text.data(),
+                                  static_cast<uint32_t>(text.size()),
+                                  nullptr,
+                                  0,
+                                  MOJO_WRITE_MESSAGE_FLAG_NONE);
+  return rv == MOJO_RESULT_OK;
+}
+
+bool ReadTextMessage(const MessagePipeHandle& handle, std::string* text) {
+  MojoResult rv;
+  bool did_wait = false;
+
+  uint32_t num_bytes = 0, num_handles = 0;
+  for (;;) {
+    rv = ReadMessageRaw(handle,
+                        nullptr,
+                        &num_bytes,
+                        nullptr,
+                        &num_handles,
+                        MOJO_READ_MESSAGE_FLAG_NONE);
+    if (rv == MOJO_RESULT_SHOULD_WAIT) {
+      if (did_wait) {
+        assert(false);  // Looping endlessly!?
+        return false;
+      }
+      rv = Wait(handle, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE);
+      if (rv != MOJO_RESULT_OK)
+        return false;
+      did_wait = true;
+    } else {
+      assert(!num_handles);
+      break;
+    }
+  }
+
+  text->resize(num_bytes);
+  rv = ReadMessageRaw(handle,
+                      &text->at(0),
+                      &num_bytes,
+                      nullptr,
+                      &num_handles,
+                      MOJO_READ_MESSAGE_FLAG_NONE);
+  return rv == MOJO_RESULT_OK;
+}
+
+bool DiscardMessage(const MessagePipeHandle& handle) {
+  MojoResult rv = ReadMessageRaw(handle, nullptr, nullptr, nullptr, nullptr,
+                                 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
+  return rv == MOJO_RESULT_OK;
+}
+
+void IterateAndReportPerf(const char* test_name,
+                          PerfTestSingleIteration single_iteration,
+                          void* closure) {
+  // TODO(vtl): These should be specifiable using command-line flags.
+  static const size_t kGranularity = 100;
+  static const MojoTimeTicks kPerftestTimeMicroseconds = 3 * 1000000;
+
+  const MojoTimeTicks start_time = GetTimeTicksNow();
+  MojoTimeTicks end_time;
+  size_t iterations = 0;
+  do {
+    for (size_t i = 0; i < kGranularity; i++)
+      (*single_iteration)(closure);
+    iterations += kGranularity;
+
+    end_time = GetTimeTicksNow();
+  } while (end_time - start_time < kPerftestTimeMicroseconds);
+
+  MojoTestSupportLogPerfResult(test_name,
+                               1000000.0 * iterations / (end_time - start_time),
+                               "iterations/second");
+}
+
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/cpp/test_support/test_support.h b/mojo/public/cpp/test_support/test_support.h
new file mode 100644
index 0000000..eb4d4be
--- /dev/null
+++ b/mojo/public/cpp/test_support/test_support.h
@@ -0,0 +1,34 @@
+// Copyright 2014 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_CPP_TEST_SUPPORT_TEST_SUPPORT_H_
+#define MOJO_PUBLIC_CPP_TEST_SUPPORT_TEST_SUPPORT_H_
+
+#include <string>
+#include <vector>
+
+#include "mojo/public/c/test_support/test_support.h"
+
+namespace mojo {
+namespace test {
+
+inline void LogPerfResult(const char* test_name,
+                          double value,
+                          const char* units) {
+  MojoTestSupportLogPerfResult(test_name, value, units);
+}
+
+// Opens text file relative to the source root for reading.
+inline FILE* OpenSourceRootRelativeFile(const std::string& relative_path) {
+  return MojoTestSupportOpenSourceRootRelativeFile(relative_path.c_str());
+}
+
+// Returns the list of regular files in a directory relative to the source root.
+std::vector<std::string> EnumerateSourceRootRelativeDirectory(
+    const std::string& relative_path);
+
+}  // namespace test
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_TEST_SUPPORT_TEST_SUPPORT_H_
diff --git a/mojo/public/cpp/test_support/test_utils.h b/mojo/public/cpp/test_support/test_utils.h
new file mode 100644
index 0000000..43a3ea9
--- /dev/null
+++ b/mojo/public/cpp/test_support/test_utils.h
@@ -0,0 +1,39 @@
+// Copyright 2013 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_CPP_TEST_SUPPORT_TEST_UTILS_H_
+#define MOJO_PUBLIC_CPP_TEST_SUPPORT_TEST_UTILS_H_
+
+#include <string>
+
+#include "mojo/public/cpp/system/core.h"
+
+namespace mojo {
+namespace test {
+
+// Writes a message to |handle| with message data |text|. Returns true on
+// success.
+bool WriteTextMessage(const MessagePipeHandle& handle, const std::string& text);
+
+// Reads a message from |handle|, putting its contents into |*text|. Returns
+// true on success. (This blocks if necessary and will call |MojoReadMessage()|
+// multiple times, e.g., to query the size of the message.)
+bool ReadTextMessage(const MessagePipeHandle& handle, std::string* text);
+
+// Discards a message from |handle|. Returns true on success. (This does not
+// block. It will fail if no message is available to discard.)
+bool DiscardMessage(const MessagePipeHandle& handle);
+
+// Run |single_iteration| an appropriate number of times and report its
+// performance appropriately. (This actually runs |single_iteration| for a fixed
+// amount of time and reports the number of iterations per unit time.)
+typedef void (*PerfTestSingleIteration)(void* closure);
+void IterateAndReportPerf(const char* test_name,
+                          PerfTestSingleIteration single_iteration,
+                          void* closure);
+
+}  // namespace test
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_TEST_SUPPORT_TEST_UTILS_H_
diff --git a/mojo/public/cpp/utility/BUILD.gn b/mojo/public/cpp/utility/BUILD.gn
new file mode 100644
index 0000000..a0898b9
--- /dev/null
+++ b/mojo/public/cpp/utility/BUILD.gn
@@ -0,0 +1,33 @@
+# Copyright 2014 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.
+
+source_set("utility") {
+  sources = [
+    "mutex.h",
+    "run_loop.h",
+    "run_loop_handler.h",
+    "thread.h",
+    "lib/mutex.cc",
+    "lib/run_loop.cc",
+    "lib/thread.cc",
+    "lib/thread_local.h",
+    "lib/thread_local_posix.cc",
+    "lib/thread_local_win.cc",
+  ]
+
+  deps = [
+    "//mojo/public/cpp/bindings:callback",
+    "//mojo/public/cpp/system",
+  ]
+
+  if (is_win) {
+    # See crbug.com/342893:
+    sources -= [
+      "mutex.h",
+      "thread.h",
+      "lib/mutex.cc",
+      "lib/thread.cc",
+    ]
+  }
+}
diff --git a/mojo/public/cpp/utility/DEPS b/mojo/public/cpp/utility/DEPS
new file mode 100644
index 0000000..a9dfbd1
--- /dev/null
+++ b/mojo/public/cpp/utility/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+mojo/public/cpp/bindings/callback.h"
+]
diff --git a/mojo/public/cpp/utility/lib/mutex.cc b/mojo/public/cpp/utility/lib/mutex.cc
new file mode 100644
index 0000000..23370e1
--- /dev/null
+++ b/mojo/public/cpp/utility/lib/mutex.cc
@@ -0,0 +1,52 @@
+// Copyright 2014 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/cpp/utility/mutex.h"
+
+#include <assert.h>
+#include <errno.h>
+
+namespace mojo {
+
+// Release builds have inlined (non-error-checking) definitions in the header.
+#if !defined(NDEBUG)
+Mutex::Mutex() {
+  pthread_mutexattr_t mutexattr;
+  int rv = pthread_mutexattr_init(&mutexattr);
+  assert(rv == 0);
+  rv = pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK);
+  assert(rv == 0);
+  rv = pthread_mutex_init(&mutex_, &mutexattr);
+  assert(rv == 0);
+  rv = pthread_mutexattr_destroy(&mutexattr);
+  assert(rv == 0);
+}
+
+Mutex::~Mutex() {
+  int rv = pthread_mutex_destroy(&mutex_);
+  assert(rv == 0);
+}
+
+void Mutex::Lock() {
+  int rv = pthread_mutex_lock(&mutex_);
+  assert(rv == 0);
+}
+
+void Mutex::Unlock() {
+  int rv = pthread_mutex_unlock(&mutex_);
+  assert(rv == 0);
+}
+
+bool Mutex::TryLock() {
+  int rv = pthread_mutex_trylock(&mutex_);
+  assert(rv == 0 || rv == EBUSY);
+  return rv == 0;
+}
+
+void Mutex::AssertHeld() {
+  assert(pthread_mutex_lock(&mutex_) == EDEADLK);
+}
+#endif  // !defined(NDEBUG)
+
+}  // namespace mojo
diff --git a/mojo/public/cpp/utility/lib/run_loop.cc b/mojo/public/cpp/utility/lib/run_loop.cc
new file mode 100644
index 0000000..bcbc623
--- /dev/null
+++ b/mojo/public/cpp/utility/lib/run_loop.cc
@@ -0,0 +1,278 @@
+// Copyright 2014 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/cpp/utility/run_loop.h"
+
+#include <assert.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "mojo/public/cpp/utility/lib/thread_local.h"
+#include "mojo/public/cpp/utility/run_loop_handler.h"
+
+namespace mojo {
+namespace {
+
+internal::ThreadLocalPointer<RunLoop> current_run_loop;
+
+const MojoTimeTicks kInvalidTimeTicks = static_cast<MojoTimeTicks>(0);
+
+}  // namespace
+
+// State needed for one iteration of WaitMany().
+struct RunLoop::WaitState {
+  WaitState() : deadline(MOJO_DEADLINE_INDEFINITE) {}
+
+  std::vector<Handle> handles;
+  std::vector<MojoHandleSignals> handle_signals;
+  MojoDeadline deadline;
+};
+
+struct RunLoop::RunState {
+  RunState() : should_quit(false) {}
+
+  bool should_quit;
+};
+
+RunLoop::RunLoop()
+    : run_state_(NULL), next_handler_id_(0), next_sequence_number_(0) {
+  assert(!current());
+  current_run_loop.Set(this);
+}
+
+RunLoop::~RunLoop() {
+  assert(current() == this);
+  NotifyHandlers(MOJO_RESULT_ABORTED, IGNORE_DEADLINE);
+  current_run_loop.Set(NULL);
+}
+
+// static
+void RunLoop::SetUp() {
+  current_run_loop.Allocate();
+}
+
+// static
+void RunLoop::TearDown() {
+  assert(!current());
+  current_run_loop.Free();
+}
+
+// static
+RunLoop* RunLoop::current() {
+  return current_run_loop.Get();
+}
+
+void RunLoop::AddHandler(RunLoopHandler* handler,
+                         const Handle& handle,
+                         MojoHandleSignals handle_signals,
+                         MojoDeadline deadline) {
+  assert(current() == this);
+  assert(handler);
+  assert(handle.is_valid());
+  // Assume it's an error if someone tries to reregister an existing handle.
+  assert(0u == handler_data_.count(handle));
+  HandlerData handler_data;
+  handler_data.handler = handler;
+  handler_data.handle_signals = handle_signals;
+  handler_data.deadline = (deadline == MOJO_DEADLINE_INDEFINITE) ?
+      kInvalidTimeTicks :
+      GetTimeTicksNow() + static_cast<MojoTimeTicks>(deadline);
+  handler_data.id = next_handler_id_++;
+  handler_data_[handle] = handler_data;
+}
+
+void RunLoop::RemoveHandler(const Handle& handle) {
+  assert(current() == this);
+  handler_data_.erase(handle);
+}
+
+bool RunLoop::HasHandler(const Handle& handle) const {
+  return handler_data_.find(handle) != handler_data_.end();
+}
+
+void RunLoop::Run() {
+  RunInternal(UNTIL_EMPTY);
+}
+
+void RunLoop::RunUntilIdle() {
+  RunInternal(UNTIL_IDLE);
+}
+
+void RunLoop::RunInternal(RunMode run_mode) {
+  assert(current() == this);
+  RunState* old_state = run_state_;
+  RunState run_state;
+  run_state_ = &run_state;
+  for (;;) {
+    bool did_work = DoDelayedWork();
+    if (run_state.should_quit)
+      break;
+    did_work |= Wait(run_mode == UNTIL_IDLE);
+    if (run_state.should_quit)
+      break;
+    if (!did_work && run_mode == UNTIL_IDLE)
+      break;
+  }
+  run_state_ = old_state;
+}
+
+bool RunLoop::DoDelayedWork() {
+  MojoTimeTicks now = GetTimeTicksNow();
+  if (!delayed_tasks_.empty() && delayed_tasks_.top().run_time <= now) {
+    PendingTask task = delayed_tasks_.top();
+    delayed_tasks_.pop();
+    task.task.Run();
+    return true;
+  }
+  return false;
+}
+
+void RunLoop::Quit() {
+  assert(current() == this);
+  if (run_state_)
+    run_state_->should_quit = true;
+}
+
+void RunLoop::PostDelayedTask(const Closure& task, MojoTimeTicks delay) {
+  assert(current() == this);
+  MojoTimeTicks run_time = delay + GetTimeTicksNow();
+  delayed_tasks_.push(PendingTask(task, run_time, next_sequence_number_++));
+}
+
+bool RunLoop::Wait(bool non_blocking) {
+  const WaitState wait_state = GetWaitState(non_blocking);
+  if (wait_state.handles.empty() && delayed_tasks_.empty()) {
+    Quit();
+    return false;
+  }
+
+  const MojoResult result = WaitMany(wait_state.handles,
+                                     wait_state.handle_signals,
+                                     wait_state.deadline);
+  if (result >= 0) {
+    const size_t index = static_cast<size_t>(result);
+    assert(handler_data_.find(wait_state.handles[index]) !=
+           handler_data_.end());
+    handler_data_[wait_state.handles[index]].handler->OnHandleReady(
+        wait_state.handles[index]);
+    return true;
+  }
+
+  switch (result) {
+    case MOJO_RESULT_INVALID_ARGUMENT:
+    case MOJO_RESULT_FAILED_PRECONDITION:
+      return RemoveFirstInvalidHandle(wait_state);
+    case MOJO_RESULT_DEADLINE_EXCEEDED:
+      return NotifyHandlers(MOJO_RESULT_DEADLINE_EXCEEDED, CHECK_DEADLINE);
+  }
+
+  assert(false);
+  return false;
+}
+
+bool RunLoop::NotifyHandlers(MojoResult error, CheckDeadline check) {
+  bool notified = false;
+
+  // Make a copy in case someone tries to add/remove new handlers as part of
+  // notifying.
+  const HandleToHandlerData cloned_handlers(handler_data_);
+  const MojoTimeTicks now(GetTimeTicksNow());
+  for (HandleToHandlerData::const_iterator i = cloned_handlers.begin();
+       i != cloned_handlers.end(); ++i) {
+    // Only check deadline exceeded if that's what we're notifying.
+    if (check == CHECK_DEADLINE && (i->second.deadline == kInvalidTimeTicks ||
+                                    i->second.deadline > now)) {
+      continue;
+    }
+
+    // Since we're iterating over a clone of the handlers, verify the handler
+    // is still valid before notifying.
+    if (handler_data_.find(i->first) == handler_data_.end() ||
+        handler_data_[i->first].id != i->second.id) {
+      continue;
+    }
+
+    RunLoopHandler* handler = i->second.handler;
+    handler_data_.erase(i->first);
+    handler->OnHandleError(i->first, error);
+    notified = true;
+  }
+
+  return notified;
+}
+
+bool RunLoop::RemoveFirstInvalidHandle(const WaitState& wait_state) {
+  for (size_t i = 0; i < wait_state.handles.size(); ++i) {
+    const MojoResult result =
+        mojo::Wait(wait_state.handles[i], wait_state.handle_signals[i],
+                   static_cast<MojoDeadline>(0));
+    if (result == MOJO_RESULT_INVALID_ARGUMENT ||
+        result == MOJO_RESULT_FAILED_PRECONDITION) {
+      // Remove the handle first, this way if OnHandleError() tries to remove
+      // the handle our iterator isn't invalidated.
+      assert(handler_data_.find(wait_state.handles[i]) != handler_data_.end());
+      RunLoopHandler* handler =
+          handler_data_[wait_state.handles[i]].handler;
+      handler_data_.erase(wait_state.handles[i]);
+      handler->OnHandleError(wait_state.handles[i], result);
+      return true;
+    }
+    assert(MOJO_RESULT_DEADLINE_EXCEEDED == result);
+  }
+  return false;
+}
+
+RunLoop::WaitState RunLoop::GetWaitState(bool non_blocking) const {
+  WaitState wait_state;
+  MojoTimeTicks min_time = kInvalidTimeTicks;
+  for (HandleToHandlerData::const_iterator i = handler_data_.begin();
+       i != handler_data_.end(); ++i) {
+    wait_state.handles.push_back(i->first);
+    wait_state.handle_signals.push_back(i->second.handle_signals);
+    if (!non_blocking && i->second.deadline != kInvalidTimeTicks &&
+        (min_time == kInvalidTimeTicks || i->second.deadline < min_time)) {
+      min_time = i->second.deadline;
+    }
+  }
+  if (!delayed_tasks_.empty()) {
+    MojoTimeTicks delayed_min_time = delayed_tasks_.top().run_time;
+    if (min_time == kInvalidTimeTicks)
+      min_time = delayed_min_time;
+    else
+      min_time = std::min(min_time, delayed_min_time);
+  }
+  if (non_blocking) {
+    wait_state.deadline = static_cast<MojoDeadline>(0);
+  } else if (min_time != kInvalidTimeTicks) {
+    const MojoTimeTicks now = GetTimeTicksNow();
+    if (min_time < now)
+      wait_state.deadline = static_cast<MojoDeadline>(0);
+    else
+      wait_state.deadline = static_cast<MojoDeadline>(min_time - now);
+  }
+  return wait_state;
+}
+
+RunLoop::PendingTask::PendingTask(const Closure& task,
+                                  MojoTimeTicks run_time,
+                                  uint64_t sequence_number)
+    : task(task), run_time(run_time), sequence_number(sequence_number) {
+}
+
+RunLoop::PendingTask::~PendingTask() {
+}
+
+bool RunLoop::PendingTask::operator<(const RunLoop::PendingTask& other) const {
+  if (run_time != other.run_time) {
+    // std::priority_queue<> puts the least element at the end of the queue. We
+    // want the soonest eligible task to be at the head of the queue, so
+    // run_times further in the future are considered lesser.
+    return run_time > other.run_time;
+  }
+
+  return sequence_number > other.sequence_number;
+}
+
+}  // namespace mojo
diff --git a/mojo/public/cpp/utility/lib/thread.cc b/mojo/public/cpp/utility/lib/thread.cc
new file mode 100644
index 0000000..da33497
--- /dev/null
+++ b/mojo/public/cpp/utility/lib/thread.cc
@@ -0,0 +1,69 @@
+// Copyright 2014 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/cpp/utility/thread.h"
+
+#include <assert.h>
+
+namespace mojo {
+
+Thread::Thread()
+    : options_(),
+      thread_(),
+      started_(false),
+      joined_(false) {
+}
+
+Thread::Thread(const Options& options)
+    : options_(options),
+      thread_(),
+      started_(false),
+      joined_(false) {
+}
+
+Thread::~Thread() {
+  // If it was started, it must have been joined.
+  assert(!started_ || joined_);
+}
+
+void Thread::Start() {
+  assert(!started_);
+  assert(!joined_);
+
+  pthread_attr_t attr;
+  int rv MOJO_ALLOW_UNUSED = pthread_attr_init(&attr);
+  assert(rv == 0);
+
+  // Non-default stack size?
+  if (options_.stack_size() != 0) {
+    rv = pthread_attr_setstacksize(&attr, options_.stack_size());
+    assert(rv == 0);
+  }
+
+  started_ = true;
+  rv = pthread_create(&thread_, &attr, &ThreadRunTrampoline, this);
+  assert(rv == 0);
+
+  rv = pthread_attr_destroy(&attr);
+  assert(rv == 0);
+}
+
+void Thread::Join() {
+  // Must have been started but not yet joined.
+  assert(started_);
+  assert(!joined_);
+
+  joined_ = true;
+  int rv MOJO_ALLOW_UNUSED = pthread_join(thread_, NULL);
+  assert(rv == 0);
+}
+
+// static
+void* Thread::ThreadRunTrampoline(void* arg) {
+  Thread* self = static_cast<Thread*>(arg);
+  self->Run();
+  return NULL;
+}
+
+}  // namespace mojo
diff --git a/mojo/public/cpp/utility/lib/thread_local.h b/mojo/public/cpp/utility/lib/thread_local.h
new file mode 100644
index 0000000..4c3625d
--- /dev/null
+++ b/mojo/public/cpp/utility/lib/thread_local.h
@@ -0,0 +1,61 @@
+// Copyright 2014 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_CPP_UTILITY_LIB_THREAD_LOCAL_H_
+#define MOJO_PUBLIC_CPP_UTILITY_LIB_THREAD_LOCAL_H_
+
+#ifndef _WIN32
+#include <pthread.h>
+#endif
+
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+namespace internal {
+
+// Helper functions that abstract the cross-platform APIs.
+struct ThreadLocalPlatform {
+#ifdef _WIN32
+  typedef unsigned long SlotType;
+#else
+  typedef pthread_key_t SlotType;
+#endif
+
+  static void AllocateSlot(SlotType* slot);
+  static void FreeSlot(SlotType slot);
+  static void* GetValueFromSlot(SlotType slot);
+  static void SetValueInSlot(SlotType slot, void* value);
+};
+
+// This class is intended to be statically allocated.
+template <typename P>
+class ThreadLocalPointer {
+ public:
+  ThreadLocalPointer() : slot_() {
+  }
+
+  void Allocate() {
+    ThreadLocalPlatform::AllocateSlot(&slot_);
+  }
+
+  void Free() {
+    ThreadLocalPlatform::FreeSlot(slot_);
+  }
+
+  P* Get() {
+    return static_cast<P*>(ThreadLocalPlatform::GetValueFromSlot(slot_));
+  }
+
+  void Set(P* value) {
+    ThreadLocalPlatform::SetValueInSlot(slot_, value);
+  }
+
+ private:
+  ThreadLocalPlatform::SlotType slot_;
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_UTILITY_LIB_THREAD_LOCAL_H_
diff --git a/mojo/public/cpp/utility/lib/thread_local_posix.cc b/mojo/public/cpp/utility/lib/thread_local_posix.cc
new file mode 100644
index 0000000..b33dfc6
--- /dev/null
+++ b/mojo/public/cpp/utility/lib/thread_local_posix.cc
@@ -0,0 +1,39 @@
+// Copyright 2014 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/cpp/utility/lib/thread_local.h"
+
+#include <assert.h>
+
+namespace mojo {
+namespace internal {
+
+// static
+void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
+  if (pthread_key_create(slot, NULL) != 0) {
+    assert(false);
+  }
+}
+
+// static
+void ThreadLocalPlatform::FreeSlot(SlotType slot) {
+  if (pthread_key_delete(slot) != 0) {
+    assert(false);
+  }
+}
+
+// static
+void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
+  return pthread_getspecific(slot);
+}
+
+// static
+void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
+  if (pthread_setspecific(slot, value) != 0) {
+    assert(false);
+  }
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/utility/lib/thread_local_win.cc b/mojo/public/cpp/utility/lib/thread_local_win.cc
new file mode 100644
index 0000000..98841f7
--- /dev/null
+++ b/mojo/public/cpp/utility/lib/thread_local_win.cc
@@ -0,0 +1,39 @@
+// Copyright 2014 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/cpp/utility/lib/thread_local.h"
+
+#include <assert.h>
+#include <windows.h>
+
+namespace mojo {
+namespace internal {
+
+// static
+void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
+  *slot = TlsAlloc();
+  assert(*slot != TLS_OUT_OF_INDEXES);
+}
+
+// static
+void ThreadLocalPlatform::FreeSlot(SlotType slot) {
+  if (!TlsFree(slot)) {
+    assert(false);
+  }
+}
+
+// static
+void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
+  return TlsGetValue(slot);
+}
+
+// static
+void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
+  if (!TlsSetValue(slot, value)) {
+    assert(false);
+  }
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/utility/mutex.h b/mojo/public/cpp/utility/mutex.h
new file mode 100644
index 0000000..35611c2
--- /dev/null
+++ b/mojo/public/cpp/utility/mutex.h
@@ -0,0 +1,70 @@
+// Copyright 2014 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_CPP_UTILITY_MUTEX_H_
+#define MOJO_PUBLIC_CPP_UTILITY_MUTEX_H_
+
+#ifdef _WIN32
+#error "Not implemented: See crbug.com/342893."
+#endif
+
+#include <pthread.h>
+
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+
+#ifdef NDEBUG
+// Note: Make a C++ constant for |PTHREAD_MUTEX_INITIALIZER|. (We can't directly
+// use the C macro in an initializer list, since it might expand to |{ ... }|.)
+namespace internal {
+const pthread_mutex_t kPthreadMutexInitializer = PTHREAD_MUTEX_INITIALIZER;
+}
+#endif
+
+class Mutex {
+ public:
+#ifdef NDEBUG
+  Mutex() : mutex_(internal::kPthreadMutexInitializer) {}
+  ~Mutex() { pthread_mutex_destroy(&mutex_); }
+
+  void Lock() { pthread_mutex_lock(&mutex_); }
+  void Unlock() { pthread_mutex_unlock(&mutex_); }
+  bool TryLock() { return pthread_mutex_trylock(&mutex_) == 0; }
+
+  void AssertHeld() {}
+#else
+  Mutex();
+  ~Mutex();
+
+  void Lock();
+  void Unlock();
+  bool TryLock();
+
+  void AssertHeld();
+#endif
+
+ private:
+  pthread_mutex_t mutex_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(Mutex);
+};
+
+class MutexLock {
+ public:
+  explicit MutexLock(Mutex* mutex) : mutex_(mutex) { mutex_->Lock(); }
+  ~MutexLock() { mutex_->Unlock(); }
+
+ private:
+  Mutex* const mutex_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(MutexLock);
+};
+
+// Catch bug where variable name is omitted (e.g., |MutexLock (&mu)|).
+#define MutexLock(x) MOJO_COMPILE_ASSERT(0, mutex_lock_missing_variable_name);
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_UTILITY_MUTEX_H_
diff --git a/mojo/public/cpp/utility/run_loop.h b/mojo/public/cpp/utility/run_loop.h
new file mode 100644
index 0000000..359208d
--- /dev/null
+++ b/mojo/public/cpp/utility/run_loop.h
@@ -0,0 +1,155 @@
+// Copyright 2013 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_CPP_UTILITY_RUN_LOOP_H_
+#define MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_
+
+#include <map>
+#include <queue>
+
+#include "mojo/public/cpp/bindings/callback.h"
+#include "mojo/public/cpp/system/core.h"
+
+namespace mojo {
+
+class RunLoopHandler;
+
+class RunLoop {
+ public:
+  RunLoop();
+  ~RunLoop();
+
+  // Sets up state needed for RunLoop. This must be invoked before creating a
+  // RunLoop.
+  static void SetUp();
+
+  // Cleans state created by Setup().
+  static void TearDown();
+
+  // Returns the RunLoop for the current thread. Returns NULL if not yet
+  // created.
+  static RunLoop* current();
+
+  // Registers a RunLoopHandler for the specified handle. Only one handler can
+  // be registered for a specified handle.
+  void AddHandler(RunLoopHandler* handler,
+                  const Handle& handle,
+                  MojoHandleSignals handle_signals,
+                  MojoDeadline deadline);
+  void RemoveHandler(const Handle& handle);
+  bool HasHandler(const Handle& handle) const;
+
+  // Runs the loop servicing handles and tasks as they are ready. This returns
+  // when Quit() is invoked, or there are no more handles nor tasks.
+  void Run();
+
+  // Runs the loop servicing any handles and tasks that are ready. Does not wait
+  // for handles or tasks to become ready before returning. Returns early if
+  // Quit() is invoked.
+  void RunUntilIdle();
+
+  void Quit();
+
+  // Adds a task to be performed after delay has elapsed. Must be posted to the
+  // current thread's RunLoop.
+  void PostDelayedTask(const Closure& task, MojoTimeTicks delay);
+
+ private:
+  struct RunState;
+  struct WaitState;
+
+  // Contains the data needed to track a request to AddHandler().
+  struct HandlerData {
+    HandlerData()
+        : handler(NULL),
+          handle_signals(MOJO_HANDLE_SIGNAL_NONE),
+          deadline(0),
+          id(0) {}
+
+    RunLoopHandler* handler;
+    MojoHandleSignals handle_signals;
+    MojoTimeTicks deadline;
+    // See description of |RunLoop::next_handler_id_| for details.
+    int id;
+  };
+
+  typedef std::map<Handle, HandlerData> HandleToHandlerData;
+
+  // Used for NotifyHandlers to specify whether HandlerData's |deadline|
+  // should be checked prior to notifying.
+  enum CheckDeadline {
+    CHECK_DEADLINE,
+    IGNORE_DEADLINE
+  };
+
+  // Mode of operation of the run loop.
+  enum RunMode {
+    UNTIL_EMPTY,
+    UNTIL_IDLE
+  };
+
+  // Runs the loop servicing any handles and tasks that are ready. If
+  // |run_mode| is |UNTIL_IDLE|, does not wait for handles or tasks to become
+  // ready before returning. Returns early if Quit() is invoked.
+  void RunInternal(RunMode run_mode);
+
+  // Do one unit of delayed work, if eligible. Returns true is a task was run.
+  bool DoDelayedWork();
+
+  // Waits for a handle to be ready or until the next task must be run. Returns
+  // after servicing at least one handle (or there are no more handles) unless
+  // a task must be run or |non_blocking| is true, in which case it will also
+  // return if no task is registered and servicing at least one handle would
+  // require blocking. Returns true if a RunLoopHandler was notified.
+  bool Wait(bool non_blocking);
+
+  // Notifies handlers of |error|.  If |check| == CHECK_DEADLINE, this will
+  // only notify handlers whose deadline has expired and skips the rest.
+  // Returns true if a RunLoopHandler was notified.
+  bool NotifyHandlers(MojoResult error, CheckDeadline check);
+
+  // Removes the first invalid handle. This is called if MojoWaitMany() finds an
+  // invalid handle. Returns true if a RunLoopHandler was notified.
+  bool RemoveFirstInvalidHandle(const WaitState& wait_state);
+
+  // Returns the state needed to pass to WaitMany().
+  WaitState GetWaitState(bool non_blocking) const;
+
+  HandleToHandlerData handler_data_;
+
+  // If non-NULL we're running (inside Run()). Member references a value on the
+  // stack.
+  RunState* run_state_;
+
+  // An ever increasing value assigned to each HandlerData::id. Used to detect
+  // uniqueness while notifying. That is, while notifying expired timers we copy
+  // |handler_data_| and only notify handlers whose id match. If the id does not
+  // match it means the handler was removed then added so that we shouldn't
+  // notify it.
+  int next_handler_id_;
+
+  struct PendingTask {
+    PendingTask(const Closure& task,
+                MojoTimeTicks runtime,
+                uint64_t sequence_number);
+    ~PendingTask();
+
+    bool operator<(const PendingTask& other) const;
+
+    Closure task;
+    MojoTimeTicks run_time;
+    uint64_t sequence_number;
+  };
+  // An ever increasing sequence number attached to each pending task in order
+  // to preserve relative order of tasks posted at the 'same' time.
+  uint64_t next_sequence_number_;
+  typedef std::priority_queue<PendingTask> DelayedTaskQueue;
+  DelayedTaskQueue delayed_tasks_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoop);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_
diff --git a/mojo/public/cpp/utility/run_loop_handler.h b/mojo/public/cpp/utility/run_loop_handler.h
new file mode 100644
index 0000000..69838d5
--- /dev/null
+++ b/mojo/public/cpp/utility/run_loop_handler.h
@@ -0,0 +1,25 @@
+// Copyright 2013 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_CPP_UTILITY_RUN_LOOP_HANDLER_H_
+#define MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_HANDLER_H_
+
+#include "mojo/public/cpp/system/core.h"
+
+namespace mojo {
+
+// Used by RunLoop to notify when a handle is either ready or has become
+// invalid.
+class RunLoopHandler {
+ public:
+  virtual void OnHandleReady(const Handle& handle) = 0;
+  virtual void OnHandleError(const Handle& handle, MojoResult result) = 0;
+
+ protected:
+  virtual ~RunLoopHandler() {}
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_HANDLER_H_
diff --git a/mojo/public/cpp/utility/tests/BUILD.gn b/mojo/public/cpp/utility/tests/BUILD.gn
new file mode 100644
index 0000000..225bf07
--- /dev/null
+++ b/mojo/public/cpp/utility/tests/BUILD.gn
@@ -0,0 +1,20 @@
+# Copyright 2014 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.
+
+# GYP version: mojo/mojo_public_tests.gypi:mojo_public_utility_unittests
+test("mojo_public_utility_unittests") {
+  deps = [
+    "//mojo/common/test:run_all_unittests",
+    "//mojo/public/cpp/system",
+    "//mojo/public/cpp/test_support:test_utils",
+    "//mojo/public/cpp/utility",
+    "//testing/gtest",
+  ]
+
+  sources = [
+    "mutex_unittest.cc",
+    "run_loop_unittest.cc",
+    "thread_unittest.cc",
+  ]
+}
diff --git a/mojo/public/cpp/utility/tests/mutex_unittest.cc b/mojo/public/cpp/utility/tests/mutex_unittest.cc
new file mode 100644
index 0000000..eb5a330
--- /dev/null
+++ b/mojo/public/cpp/utility/tests/mutex_unittest.cc
@@ -0,0 +1,260 @@
+// Copyright 2014 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/cpp/utility/mutex.h"
+
+#include <stdlib.h>  // For |rand()|.
+#include <time.h>  // For |nanosleep()| (defined by POSIX).
+
+#include <vector>
+
+#include "mojo/public/cpp/system/macros.h"
+#include "mojo/public/cpp/utility/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+TEST(MutexTest, TrivialSingleThreaded) {
+  Mutex mutex;
+
+  mutex.Lock();
+  mutex.AssertHeld();
+  mutex.Unlock();
+
+  EXPECT_TRUE(mutex.TryLock());
+  mutex.AssertHeld();
+  mutex.Unlock();
+
+  {
+    MutexLock lock(&mutex);
+    mutex.AssertHeld();
+  }
+
+  EXPECT_TRUE(mutex.TryLock());
+  mutex.Unlock();
+}
+
+class Fiddler {
+ public:
+  enum Type { kTypeLock, kTypeTry };
+  Fiddler(size_t times_to_lock,
+          Type type,
+          bool should_sleep,
+          Mutex* mutex,
+          int* shared_value)
+      : times_to_lock_(times_to_lock),
+        type_(type),
+        should_sleep_(should_sleep),
+        mutex_(mutex),
+        shared_value_(shared_value) {
+  }
+
+  ~Fiddler() {
+  }
+
+  void Fiddle() {
+    for (size_t i = 0; i < times_to_lock_;) {
+      switch (type_) {
+        case kTypeLock: {
+          mutex_->Lock();
+          int old_shared_value = *shared_value_;
+          if (should_sleep_)
+            SleepALittle();
+          *shared_value_ = old_shared_value + 1;
+          mutex_->Unlock();
+          i++;
+          break;
+        }
+        case kTypeTry:
+          if (mutex_->TryLock()) {
+            int old_shared_value = *shared_value_;
+            if (should_sleep_)
+              SleepALittle();
+            *shared_value_ = old_shared_value + 1;
+            mutex_->Unlock();
+            i++;
+          } else {
+            SleepALittle();  // Don't spin.
+          }
+          break;
+      }
+    }
+  }
+
+ private:
+  static void SleepALittle() {
+    static const long kNanosPerMilli = 1000000;
+    struct timespec req = {
+      0,  // Seconds.
+      (rand() % 10) * kNanosPerMilli // Nanoseconds.
+    };
+    int rv MOJO_ALLOW_UNUSED = nanosleep(&req, NULL);
+    assert(rv == 0);
+  }
+
+  const size_t times_to_lock_;
+  const Type type_;
+  const bool should_sleep_;
+  Mutex* const mutex_;
+  int* const shared_value_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(Fiddler);
+};
+
+class FiddlerThread : public Thread {
+ public:
+  // Takes ownership of |fiddler|.
+  FiddlerThread(Fiddler* fiddler)
+      : fiddler_(fiddler) {
+  }
+
+  virtual ~FiddlerThread() {
+    delete fiddler_;
+  }
+
+  virtual void Run() override { fiddler_->Fiddle(); }
+
+ private:
+  Fiddler* const fiddler_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(FiddlerThread);
+};
+
+// This does a stress test (that also checks exclusion).
+TEST(MutexTest, ThreadedStress) {
+  static const size_t kNumThreads = 20;
+  static const int kTimesToLockEach = 20;
+  assert(kNumThreads % 4 == 0);
+
+  Mutex mutex;
+  int shared_value = 0;
+
+  std::vector<FiddlerThread*> fiddler_threads;
+
+  for (size_t i = 0; i < kNumThreads; i += 4) {
+    fiddler_threads.push_back(new FiddlerThread(new Fiddler(
+        kTimesToLockEach, Fiddler::kTypeLock, false, &mutex, &shared_value)));
+    fiddler_threads.push_back(new FiddlerThread(new Fiddler(
+        kTimesToLockEach, Fiddler::kTypeTry, false, &mutex, &shared_value)));
+    fiddler_threads.push_back(new FiddlerThread(new Fiddler(
+        kTimesToLockEach, Fiddler::kTypeLock, true, &mutex, &shared_value)));
+    fiddler_threads.push_back(new FiddlerThread(new Fiddler(
+        kTimesToLockEach, Fiddler::kTypeTry, true, &mutex, &shared_value)));
+  }
+
+  for (size_t i = 0; i < kNumThreads; i++)
+    fiddler_threads[i]->Start();
+
+  // Do some fiddling ourselves.
+  Fiddler(kTimesToLockEach, Fiddler::kTypeLock, true, &mutex, &shared_value)
+      .Fiddle();
+
+  // Join.
+  for (size_t i = 0; i < kNumThreads; i++)
+    fiddler_threads[i]->Join();
+
+  EXPECT_EQ(static_cast<int>(kNumThreads + 1) * kTimesToLockEach, shared_value);
+
+  // Delete.
+  for (size_t i = 0; i < kNumThreads; i++)
+    delete fiddler_threads[i];
+  fiddler_threads.clear();
+}
+
+class TryThread : public Thread {
+ public:
+  explicit TryThread(Mutex* mutex) : mutex_(mutex), try_lock_succeeded_() {}
+  virtual ~TryThread() {}
+
+  virtual void Run() override {
+    try_lock_succeeded_ = mutex_->TryLock();
+    if (try_lock_succeeded_)
+      mutex_->Unlock();
+  }
+
+  bool try_lock_succeeded() const { return try_lock_succeeded_; }
+
+ private:
+  Mutex* const mutex_;
+  bool try_lock_succeeded_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(TryThread);
+};
+
+TEST(MutexTest, TryLock) {
+  Mutex mutex;
+
+  // |TryLock()| should succeed -- we don't have the lock.
+  {
+    TryThread thread(&mutex);
+    thread.Start();
+    thread.Join();
+    EXPECT_TRUE(thread.try_lock_succeeded());
+  }
+
+  // Take the lock.
+  ASSERT_TRUE(mutex.TryLock());
+
+  // Now it should fail.
+  {
+    TryThread thread(&mutex);
+    thread.Start();
+    thread.Join();
+    EXPECT_FALSE(thread.try_lock_succeeded());
+  }
+
+  // Release the lock.
+  mutex.Unlock();
+
+  // It should succeed again.
+  {
+    TryThread thread(&mutex);
+    thread.Start();
+    thread.Join();
+    EXPECT_TRUE(thread.try_lock_succeeded());
+  }
+}
+
+
+// Tests of assertions for Debug builds.
+#if !defined(NDEBUG)
+// Test |AssertHeld()| (which is an actual user API).
+TEST(MutexTest, DebugAssertHeldFailure) {
+  Mutex mutex;
+  EXPECT_DEATH_IF_SUPPORTED(mutex.AssertHeld(), "");
+}
+
+// Test other consistency checks.
+TEST(MutexTest, DebugAssertionFailures) {
+  // Unlock without lock held.
+  EXPECT_DEATH_IF_SUPPORTED({
+    Mutex mutex;
+    mutex.Unlock();
+  }, "");
+
+  // Lock with lock held (on same thread).
+  EXPECT_DEATH_IF_SUPPORTED({
+    Mutex mutex;
+    mutex.Lock();
+    mutex.Lock();
+  }, "");
+
+  // Try lock with lock held.
+  EXPECT_DEATH_IF_SUPPORTED({
+    Mutex mutex;
+    mutex.Lock();
+    mutex.TryLock();
+  }, "");
+
+  // Destroy lock with lock held.
+  EXPECT_DEATH_IF_SUPPORTED({
+    Mutex mutex;
+    mutex.Lock();
+  }, "");
+}
+#endif  // !defined(NDEBUG)
+
+}  // namespace
+}  // namespace mojo
diff --git a/mojo/public/cpp/utility/tests/run_loop_unittest.cc b/mojo/public/cpp/utility/tests/run_loop_unittest.cc
new file mode 100644
index 0000000..c6199d7
--- /dev/null
+++ b/mojo/public/cpp/utility/tests/run_loop_unittest.cc
@@ -0,0 +1,431 @@
+// Copyright 2014 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/cpp/utility/run_loop.h"
+
+#include <string>
+
+#include "mojo/public/cpp/system/core.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
+#include "mojo/public/cpp/utility/run_loop_handler.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+class TestRunLoopHandler : public RunLoopHandler {
+ public:
+  TestRunLoopHandler()
+      : ready_count_(0),
+        error_count_(0),
+        last_error_result_(MOJO_RESULT_OK) {
+  }
+  virtual ~TestRunLoopHandler() {}
+
+  void clear_ready_count() { ready_count_ = 0; }
+  int ready_count() const { return ready_count_; }
+
+  void clear_error_count() { error_count_ = 0; }
+  int error_count() const { return error_count_; }
+
+  MojoResult last_error_result() const { return last_error_result_; }
+
+  // RunLoopHandler:
+  virtual void OnHandleReady(const Handle& handle) override { ready_count_++; }
+  virtual void OnHandleError(const Handle& handle, MojoResult result) override {
+    error_count_++;
+    last_error_result_ = result;
+  }
+
+ private:
+  int ready_count_;
+  int error_count_;
+  MojoResult last_error_result_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(TestRunLoopHandler);
+};
+
+class RunLoopTest : public testing::Test {
+ public:
+  RunLoopTest() {}
+
+  virtual void SetUp() override {
+    Test::SetUp();
+    RunLoop::SetUp();
+  }
+  virtual void TearDown() override {
+    RunLoop::TearDown();
+    Test::TearDown();
+  }
+
+ private:
+  MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoopTest);
+};
+
+// Trivial test to verify Run() with no added handles returns.
+TEST_F(RunLoopTest, ExitsWithNoHandles) {
+  RunLoop run_loop;
+  run_loop.Run();
+}
+
+class RemoveOnReadyRunLoopHandler : public TestRunLoopHandler {
+ public:
+  RemoveOnReadyRunLoopHandler() : run_loop_(NULL) {
+  }
+  virtual ~RemoveOnReadyRunLoopHandler() {}
+
+  void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
+
+  // RunLoopHandler:
+  virtual void OnHandleReady(const Handle& handle) override {
+    run_loop_->RemoveHandler(handle);
+    TestRunLoopHandler::OnHandleReady(handle);
+  }
+
+ private:
+  RunLoop* run_loop_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(RemoveOnReadyRunLoopHandler);
+};
+
+// Verifies RunLoop quits when no more handles (handle is removed when ready).
+TEST_F(RunLoopTest, HandleReady) {
+  RemoveOnReadyRunLoopHandler handler;
+  MessagePipe test_pipe;
+  EXPECT_TRUE(test::WriteTextMessage(test_pipe.handle1.get(), std::string()));
+
+  RunLoop run_loop;
+  handler.set_run_loop(&run_loop);
+  run_loop.AddHandler(&handler, test_pipe.handle0.get(),
+                      MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE);
+  run_loop.Run();
+  EXPECT_EQ(1, handler.ready_count());
+  EXPECT_EQ(0, handler.error_count());
+  EXPECT_FALSE(run_loop.HasHandler(test_pipe.handle0.get()));
+}
+
+class QuitOnReadyRunLoopHandler : public TestRunLoopHandler {
+ public:
+  QuitOnReadyRunLoopHandler() : run_loop_(NULL) {
+  }
+  virtual ~QuitOnReadyRunLoopHandler() {}
+
+  void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
+
+  // RunLoopHandler:
+  virtual void OnHandleReady(const Handle& handle) override {
+    run_loop_->Quit();
+    TestRunLoopHandler::OnHandleReady(handle);
+  }
+
+ private:
+  RunLoop* run_loop_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(QuitOnReadyRunLoopHandler);
+};
+
+// Verifies Quit() from OnHandleReady() quits the loop.
+TEST_F(RunLoopTest, QuitFromReady) {
+  QuitOnReadyRunLoopHandler handler;
+  MessagePipe test_pipe;
+  EXPECT_TRUE(test::WriteTextMessage(test_pipe.handle1.get(), std::string()));
+
+  RunLoop run_loop;
+  handler.set_run_loop(&run_loop);
+  run_loop.AddHandler(&handler, test_pipe.handle0.get(),
+                      MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE);
+  run_loop.Run();
+  EXPECT_EQ(1, handler.ready_count());
+  EXPECT_EQ(0, handler.error_count());
+  EXPECT_TRUE(run_loop.HasHandler(test_pipe.handle0.get()));
+}
+
+class QuitOnErrorRunLoopHandler : public TestRunLoopHandler {
+ public:
+  QuitOnErrorRunLoopHandler() : run_loop_(NULL) {
+  }
+  virtual ~QuitOnErrorRunLoopHandler() {}
+
+  void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
+
+  // RunLoopHandler:
+  virtual void OnHandleError(const Handle& handle, MojoResult result) override {
+    run_loop_->Quit();
+    TestRunLoopHandler::OnHandleError(handle, result);
+  }
+
+ private:
+  RunLoop* run_loop_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(QuitOnErrorRunLoopHandler);
+};
+
+// Verifies Quit() when the deadline is reached works.
+TEST_F(RunLoopTest, QuitWhenDeadlineExpired) {
+  QuitOnErrorRunLoopHandler handler;
+  MessagePipe test_pipe;
+  RunLoop run_loop;
+  handler.set_run_loop(&run_loop);
+  run_loop.AddHandler(&handler, test_pipe.handle0.get(),
+                      MOJO_HANDLE_SIGNAL_READABLE,
+                      static_cast<MojoDeadline>(10000));
+  run_loop.Run();
+  EXPECT_EQ(0, handler.ready_count());
+  EXPECT_EQ(1, handler.error_count());
+  EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, handler.last_error_result());
+  EXPECT_FALSE(run_loop.HasHandler(test_pipe.handle0.get()));
+}
+
+// Test that handlers are notified of loop destruction.
+TEST_F(RunLoopTest, Destruction) {
+  TestRunLoopHandler handler;
+  MessagePipe test_pipe;
+  {
+    RunLoop run_loop;
+    run_loop.AddHandler(&handler,
+                        test_pipe.handle0.get(),
+                        MOJO_HANDLE_SIGNAL_READABLE,
+                        MOJO_DEADLINE_INDEFINITE);
+  }
+  EXPECT_EQ(1, handler.error_count());
+  EXPECT_EQ(MOJO_RESULT_ABORTED, handler.last_error_result());
+}
+
+class RemoveManyRunLoopHandler : public TestRunLoopHandler {
+ public:
+  RemoveManyRunLoopHandler() : run_loop_(NULL) {
+  }
+  virtual ~RemoveManyRunLoopHandler() {}
+
+  void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
+  void add_handle(const Handle& handle) { handles_.push_back(handle); }
+
+  // RunLoopHandler:
+  virtual void OnHandleError(const Handle& handle, MojoResult result) override {
+    for (size_t i = 0; i < handles_.size(); i++)
+      run_loop_->RemoveHandler(handles_[i]);
+    TestRunLoopHandler::OnHandleError(handle, result);
+  }
+
+ private:
+  std::vector<Handle> handles_;
+  RunLoop* run_loop_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(RemoveManyRunLoopHandler);
+};
+
+// Test that handlers are notified of loop destruction.
+TEST_F(RunLoopTest, MultipleHandleDestruction) {
+  RemoveManyRunLoopHandler odd_handler;
+  TestRunLoopHandler even_handler;
+  MessagePipe test_pipe1, test_pipe2, test_pipe3;
+  {
+    RunLoop run_loop;
+    odd_handler.set_run_loop(&run_loop);
+    odd_handler.add_handle(test_pipe1.handle0.get());
+    odd_handler.add_handle(test_pipe3.handle0.get());
+    run_loop.AddHandler(&odd_handler,
+                        test_pipe1.handle0.get(),
+                        MOJO_HANDLE_SIGNAL_READABLE,
+                        MOJO_DEADLINE_INDEFINITE);
+    run_loop.AddHandler(&even_handler,
+                        test_pipe2.handle0.get(),
+                        MOJO_HANDLE_SIGNAL_READABLE,
+                        MOJO_DEADLINE_INDEFINITE);
+    run_loop.AddHandler(&odd_handler,
+                        test_pipe3.handle0.get(),
+                        MOJO_HANDLE_SIGNAL_READABLE,
+                        MOJO_DEADLINE_INDEFINITE);
+  }
+  EXPECT_EQ(1, odd_handler.error_count());
+  EXPECT_EQ(1, even_handler.error_count());
+  EXPECT_EQ(MOJO_RESULT_ABORTED, odd_handler.last_error_result());
+  EXPECT_EQ(MOJO_RESULT_ABORTED, even_handler.last_error_result());
+}
+
+class AddHandlerOnErrorHandler : public TestRunLoopHandler {
+ public:
+  AddHandlerOnErrorHandler() : run_loop_(NULL) {
+  }
+  virtual ~AddHandlerOnErrorHandler() {}
+
+  void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
+
+  // RunLoopHandler:
+  virtual void OnHandleError(const Handle& handle, MojoResult result) override {
+    run_loop_->AddHandler(this, handle,
+                          MOJO_HANDLE_SIGNAL_READABLE,
+                          MOJO_DEADLINE_INDEFINITE);
+    TestRunLoopHandler::OnHandleError(handle, result);
+  }
+
+ private:
+  RunLoop* run_loop_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(AddHandlerOnErrorHandler);
+};
+
+TEST_F(RunLoopTest, AddHandlerOnError) {
+  AddHandlerOnErrorHandler handler;
+  MessagePipe test_pipe;
+  {
+    RunLoop run_loop;
+    handler.set_run_loop(&run_loop);
+    run_loop.AddHandler(&handler,
+                        test_pipe.handle0.get(),
+                        MOJO_HANDLE_SIGNAL_READABLE,
+                        MOJO_DEADLINE_INDEFINITE);
+  }
+  EXPECT_EQ(1, handler.error_count());
+  EXPECT_EQ(MOJO_RESULT_ABORTED, handler.last_error_result());
+}
+
+TEST_F(RunLoopTest, Current) {
+  EXPECT_TRUE(RunLoop::current() == NULL);
+  {
+    RunLoop run_loop;
+    EXPECT_EQ(&run_loop, RunLoop::current());
+  }
+  EXPECT_TRUE(RunLoop::current() == NULL);
+}
+
+class NestingRunLoopHandler : public TestRunLoopHandler {
+ public:
+  static const size_t kDepthLimit;
+  static const char kSignalMagic;
+
+  NestingRunLoopHandler()
+      : run_loop_(NULL),
+        pipe_(NULL),
+        depth_(0),
+        reached_depth_limit_(false) {}
+
+  virtual ~NestingRunLoopHandler() {}
+
+  void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
+  void set_pipe(MessagePipe* pipe) { pipe_ = pipe; }
+  bool reached_depth_limit() const { return reached_depth_limit_; }
+
+  // RunLoopHandler:
+  virtual void OnHandleReady(const Handle& handle) override {
+    TestRunLoopHandler::OnHandleReady(handle);
+    EXPECT_EQ(handle.value(), pipe_->handle0.get().value());
+
+    ReadSignal();
+    size_t current_depth = ++depth_;
+    if (current_depth < kDepthLimit) {
+      WriteSignal();
+      run_loop_->Run();
+      if (current_depth == kDepthLimit - 1) {
+        // The topmost loop Quit()-ed, so its parent takes back the
+        // control without exeeding deadline.
+        EXPECT_EQ(error_count(), 0);
+      } else {
+        EXPECT_EQ(error_count(), 1);
+      }
+
+    } else {
+      EXPECT_EQ(current_depth, kDepthLimit);
+      reached_depth_limit_ = true;
+      run_loop_->Quit();
+    }
+    --depth_;
+  }
+
+  void WriteSignal() {
+    char write_byte = kSignalMagic;
+    MojoResult write_result = WriteMessageRaw(
+        pipe_->handle1.get(),
+        &write_byte, 1, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
+    EXPECT_EQ(write_result, MOJO_RESULT_OK);
+  }
+
+  void ReadSignal() {
+    char read_byte = 0;
+    uint32_t bytes_read = 1;
+    uint32_t handles_read = 0;
+    MojoResult read_result = ReadMessageRaw(
+        pipe_->handle0.get(),
+        &read_byte, &bytes_read, NULL, &handles_read,
+        MOJO_READ_MESSAGE_FLAG_NONE);
+    EXPECT_EQ(read_result, MOJO_RESULT_OK);
+    EXPECT_EQ(read_byte, kSignalMagic);
+  }
+
+ private:
+  RunLoop* run_loop_;
+  MessagePipe* pipe_;
+  size_t depth_;
+  bool reached_depth_limit_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(NestingRunLoopHandler);
+};
+
+const size_t NestingRunLoopHandler::kDepthLimit = 10;
+const char NestingRunLoopHandler::kSignalMagic = 'X';
+
+TEST_F(RunLoopTest, NestedRun) {
+  NestingRunLoopHandler handler;
+  MessagePipe test_pipe;
+  RunLoop run_loop;
+  handler.set_run_loop(&run_loop);
+  handler.set_pipe(&test_pipe);
+  run_loop.AddHandler(&handler, test_pipe.handle0.get(),
+                      MOJO_HANDLE_SIGNAL_READABLE,
+                      static_cast<MojoDeadline>(10000));
+  handler.WriteSignal();
+  run_loop.Run();
+
+  EXPECT_TRUE(handler.reached_depth_limit());
+  // Got MOJO_RESULT_DEADLINE_EXCEEDED once then removed from the
+  // RunLoop's handler list.
+  EXPECT_EQ(handler.error_count(), 1);
+  EXPECT_EQ(handler.last_error_result(), MOJO_RESULT_DEADLINE_EXCEEDED);
+}
+
+struct Task {
+  Task(int num, std::vector<int>* sequence) : num(num), sequence(sequence) {}
+
+  void Run() const { sequence->push_back(num); }
+
+  int num;
+  std::vector<int>* sequence;
+};
+
+TEST_F(RunLoopTest, DelayedTaskOrder) {
+  std::vector<int> sequence;
+  RunLoop run_loop;
+  run_loop.PostDelayedTask(Closure(Task(1, &sequence)), 0);
+  run_loop.PostDelayedTask(Closure(Task(2, &sequence)), 0);
+  run_loop.PostDelayedTask(Closure(Task(3, &sequence)), 0);
+  run_loop.RunUntilIdle();
+
+  ASSERT_EQ(3u, sequence.size());
+  EXPECT_EQ(1, sequence[0]);
+  EXPECT_EQ(2, sequence[1]);
+  EXPECT_EQ(3, sequence[2]);
+}
+
+struct QuittingTask {
+  explicit QuittingTask(RunLoop* run_loop) : run_loop(run_loop) {}
+
+  void Run() const { run_loop->Quit(); }
+
+  RunLoop* run_loop;
+};
+
+TEST_F(RunLoopTest, QuitFromDelayedTask) {
+  TestRunLoopHandler handler;
+  MessagePipe test_pipe;
+  RunLoop run_loop;
+  run_loop.AddHandler(&handler,
+                      test_pipe.handle0.get(),
+                      MOJO_HANDLE_SIGNAL_READABLE,
+                      MOJO_DEADLINE_INDEFINITE);
+  run_loop.PostDelayedTask(Closure(QuittingTask(&run_loop)), 0);
+  run_loop.Run();
+}
+
+}  // namespace
+}  // namespace mojo
diff --git a/mojo/public/cpp/utility/tests/thread_unittest.cc b/mojo/public/cpp/utility/tests/thread_unittest.cc
new file mode 100644
index 0000000..0d81ef8
--- /dev/null
+++ b/mojo/public/cpp/utility/tests/thread_unittest.cc
@@ -0,0 +1,107 @@
+// Copyright 2014 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/cpp/utility/thread.h"
+
+#include "mojo/public/cpp/system/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+class SetIntThread : public Thread {
+ public:
+  SetIntThread(int* int_to_set, int value)
+      : int_to_set_(int_to_set),
+        value_(value) {
+  }
+  SetIntThread(const Options& options, int* int_to_set, int value)
+      : Thread(options),
+        int_to_set_(int_to_set),
+        value_(value) {
+  }
+
+  virtual ~SetIntThread() {
+  }
+
+  virtual void Run() override { *int_to_set_ = value_; }
+
+ private:
+  int* const int_to_set_;
+  const int value_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(SetIntThread);
+};
+
+TEST(ThreadTest, CreateAndJoin) {
+  int value = 0;
+
+  // Not starting the thread should result in a no-op.
+  {
+    SetIntThread thread(&value, 1234567);
+  }
+  EXPECT_EQ(0, value);
+
+  // Start and join.
+  {
+    SetIntThread thread(&value, 12345678);
+    thread.Start();
+    thread.Join();
+    EXPECT_EQ(12345678, value);
+  }
+
+  // Ditto, with non-default (but reasonable) stack size.
+  {
+    Thread::Options options;
+    options.set_stack_size(1024 * 1024);  // 1 MB.
+    SetIntThread thread(options, &value, 12345678);
+    thread.Start();
+    thread.Join();
+    EXPECT_EQ(12345678, value);
+  }
+}
+
+// Tests of assertions for Debug builds.
+// Note: It's okay to create threads, despite gtest having to fork. (The threads
+// are in the child process.)
+#if !defined(NDEBUG)
+TEST(ThreadTest, DebugAssertionFailures) {
+  // Can only start once.
+  EXPECT_DEATH_IF_SUPPORTED({
+    int value = 0;
+    SetIntThread thread(&value, 1);
+    thread.Start();
+    thread.Start();
+  }, "");
+
+  // Must join (if you start).
+  EXPECT_DEATH_IF_SUPPORTED({
+    int value = 0;
+    SetIntThread thread(&value, 2);
+    thread.Start();
+  }, "");
+
+  // Can only join once.
+  EXPECT_DEATH_IF_SUPPORTED({
+    int value = 0;
+    SetIntThread thread(&value, 3);
+    thread.Start();
+    thread.Join();
+    thread.Join();
+  }, "");
+
+  // Stack too big (we're making certain assumptions here).
+  EXPECT_DEATH_IF_SUPPORTED({
+    int value = 0;
+    Thread::Options options;
+    options.set_stack_size(static_cast<size_t>(-1));
+    SetIntThread thread(options, &value, 4);
+    thread.Start();
+    thread.Join();
+  }, "");
+}
+#endif  // !defined(NDEBUG)
+
+}  // namespace
+}  // namespace mojo
diff --git a/mojo/public/cpp/utility/thread.h b/mojo/public/cpp/utility/thread.h
new file mode 100644
index 0000000..b7d10ee
--- /dev/null
+++ b/mojo/public/cpp/utility/thread.h
@@ -0,0 +1,62 @@
+// Copyright 2014 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_CPP_UTILITY_THREAD_H_
+#define MOJO_PUBLIC_CPP_UTILITY_THREAD_H_
+
+#ifdef _WIN32
+#error "Not implemented: See crbug.com/342893."
+#endif
+
+#include <pthread.h>
+#include <stddef.h>
+
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+
+// This class is thread-friendly, not thread-safe (e.g., you mustn't call
+// |Join()| from multiple threads and/or simultaneously try to destroy the
+// object).
+class Thread {
+ public:
+  // TODO(vtl): Support non-joinable? priority?
+  class Options {
+   public:
+    Options() : stack_size_(0) {}
+
+    // A stack size of 0 means the default.
+    size_t stack_size() const { return stack_size_; }
+    void set_stack_size(size_t stack_size) { stack_size_ = stack_size; }
+
+   private:
+    size_t stack_size_;
+
+    // Copy and assign allowed.
+  };
+
+  // TODO(vtl): Add name or name prefix?
+  Thread();
+  explicit Thread(const Options& options);
+  virtual ~Thread();
+
+  void Start();
+  void Join();
+
+  virtual void Run() = 0;
+
+ private:
+  static void* ThreadRunTrampoline(void* arg);
+
+  const Options options_;
+  pthread_t thread_;
+  bool started_;
+  bool joined_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(Thread);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_UTILITY_THREAD_H_
diff --git a/mojo/public/gles2/BUILD.gn b/mojo/public/gles2/BUILD.gn
new file mode 100644
index 0000000..5c21e78
--- /dev/null
+++ b/mojo/public/gles2/BUILD.gn
@@ -0,0 +1,35 @@
+# Copyright 2014 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.
+
+# In an is_component_build build, everything can link against //mojo/gles2
+# because it is built as a shared library. However, in a static build,
+# //mojo/gles2 is linked into an executable (e.g., mojo_shell), and must be
+# injected into other shared libraries (i.e., Mojo Apps) that need the mojo
+# gles2 API.
+#
+# For component targets, add //mojo/public/gles2:for_component to your deps
+# section.
+#
+# For shared_library targets (e.g., a Mojo App), add
+# //mojo/public/gles2:for_shared_library to your deps
+
+group("for_shared_library") {
+  public_configs = [ "//third_party/khronos:khronos_headers" ]
+  public_deps = [ "//mojo/public/c/gles2" ]
+
+  if (is_component_build) {
+    deps = [ "//mojo/gles2" ]
+  } else {
+    deps = [ "//mojo/public/platform/native:gles2_thunks" ]
+  }
+}
+
+group("for_component") {
+  public_configs = [ "//third_party/khronos:khronos_headers" ]
+  public_deps = [ "//mojo/public/c/gles2" ]
+
+  if (is_component_build) {
+    deps = [ "//mojo/gles2" ]
+  }
+}
diff --git a/mojo/public/go/mojo/system/core.go b/mojo/public/go/mojo/system/core.go
new file mode 100644
index 0000000..8049d37
--- /dev/null
+++ b/mojo/public/go/mojo/system/core.go
@@ -0,0 +1,9 @@
+// Copyright 2014 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.
+
+package system;
+
+type Core interface {
+	GetTimeTicksNow() int64
+}
diff --git a/mojo/public/interfaces/application/BUILD.gn b/mojo/public/interfaces/application/BUILD.gn
new file mode 100644
index 0000000..91e2447
--- /dev/null
+++ b/mojo/public/interfaces/application/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2014 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+# GYP version: mojo/mojo_public.gypi:mojo_application_bindings
+mojom("application") {
+  sources = [
+    "application.mojom",
+    "service_provider.mojom",
+    "shell.mojom",
+  ]
+}
diff --git a/mojo/public/interfaces/application/application.mojom b/mojo/public/interfaces/application/application.mojom
new file mode 100644
index 0000000..758a053
--- /dev/null
+++ b/mojo/public/interfaces/application/application.mojom
@@ -0,0 +1,19 @@
+// Copyright 2014 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.
+
+import "mojo/public/interfaces/application/service_provider.mojom"
+
+module mojo {
+
+// Applications vend Services through the ServiceProvider interface. Services
+// implement Interfaces.
+[Client=Shell]
+interface Application {
+  // Initialize is guaranteed to be called before any AcceptConnection calls.
+  Initialize(array<string>? args);
+
+  AcceptConnection(string? requestor_url, ServiceProvider? provider);
+};
+
+}
diff --git a/mojo/public/interfaces/application/service_provider.mojom b/mojo/public/interfaces/application/service_provider.mojom
new file mode 100644
index 0000000..00eb057
--- /dev/null
+++ b/mojo/public/interfaces/application/service_provider.mojom
@@ -0,0 +1,16 @@
+// Copyright 2014 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.
+
+module mojo {
+
+// ServiceProvider is used to establish connections to services in a bi-
+// directional fashion between two applications.
+[Client=ServiceProvider]
+interface ServiceProvider {
+  // Connect the given message pipe handle to the named service. If the named
+  // service does not exist, then the handle will be closed.
+  ConnectToService(string? interface_name, handle<message_pipe>? pipe);
+};
+
+}
diff --git a/mojo/public/interfaces/application/shell.mojom b/mojo/public/interfaces/application/shell.mojom
new file mode 100644
index 0000000..a9ce05f
--- /dev/null
+++ b/mojo/public/interfaces/application/shell.mojom
@@ -0,0 +1,18 @@
+// Copyright 2014 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.
+
+import "mojo/public/interfaces/application/service_provider.mojom"
+
+module mojo {
+
+// The Shell is the finder and launcher of Applications. An Application uses
+// it's Shell interface to connect to other Applications.
+[Client=Application]
+interface Shell {
+  // Loads url. mojo:{service} will result in the user of the value of the
+  // --origin flag to the shell being used.
+  ConnectToApplication(string? application_url, ServiceProvider&? provider);
+};
+
+}
diff --git a/mojo/public/interfaces/bindings/tests/BUILD.gn b/mojo/public/interfaces/bindings/tests/BUILD.gn
new file mode 100644
index 0000000..e56f9b5
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/BUILD.gn
@@ -0,0 +1,23 @@
+# Copyright 2014 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("test_interfaces") {
+  testonly = true
+  sources = [
+    "math_calculator.mojom",
+    "no_module.mojom",
+    "rect.mojom",
+    "regression_tests.mojom",
+    "sample_factory.mojom",
+    "sample_import.mojom",
+    "sample_import2.mojom",
+    "sample_interfaces.mojom",
+    "sample_service.mojom",
+    "serialization_test_structs.mojom",
+    "test_structs.mojom",
+    "validation_test_interfaces.mojom",
+  ]
+}
diff --git a/mojo/public/interfaces/bindings/tests/data/message_data b/mojo/public/interfaces/bindings/tests/data/message_data
new file mode 100644
index 0000000..b288878
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/message_data
@@ -0,0 +1,25 @@
+// File generated by mojo_message_generator.
+0X10
+0X00
+0X00
+0X00
+0X02
+0X00
+0X00
+0X00
+0X15
+0X00
+0X00
+0X00
+0X00
+0X00
+0X00
+0X00
+0X09
+0X08
+0X07
+0X06
+0X00
+0X00
+0X00
+0X00
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_empty.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_empty.data
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_empty.data
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_empty.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_empty.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_empty.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_incomplete_struct.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_incomplete_struct.data
new file mode 100644
index 0000000..ee5ecdb
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_incomplete_struct.data
@@ -0,0 +1,2 @@
+[u4]16  // num_bytes: Bigger than the total size of the message.
+[u4]2   // num_fields
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_incomplete_struct.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_incomplete_struct.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_incomplete_struct.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_incomplete_struct_header.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_incomplete_struct_header.data
new file mode 100644
index 0000000..21e7fbc
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_incomplete_struct_header.data
@@ -0,0 +1 @@
+0x00
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_incomplete_struct_header.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_incomplete_struct_header.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_incomplete_struct_header.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_invalid_flags.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_invalid_flags.data
new file mode 100644
index 0000000..9d66188
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_invalid_flags.data
@@ -0,0 +1,6 @@
+[dist4]message_header  // num_bytes
+[u4]3                  // num_fields
+[u4]0x80000000         // name
+[u4]3                  // flags: This combination is illegal.
+[u8]1                  // request_id
+[anchr]message_header
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_invalid_flags.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_invalid_flags.expected
new file mode 100644
index 0000000..696c78d
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_invalid_flags.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_missing_request_id.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_missing_request_id.data
new file mode 100644
index 0000000..2414431
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_missing_request_id.data
@@ -0,0 +1,6 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]0x80000000         // name
+[u4]1                  // flags: This is a response message which expects to
+                       // have a request ID.
+[anchr]message_header
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_missing_request_id.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_missing_request_id.expected
new file mode 100644
index 0000000..083db1a
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_missing_request_id.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_huge.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_huge.data
new file mode 100644
index 0000000..ad3b005
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_huge.data
@@ -0,0 +1,4 @@
+[u4]0xFFFFFFFF  // num_bytes: Test whether a huge value will cause overflow.
+[u4]2           // num_fields
+[u4]0x80000000  // name
+[u4]0           // flags
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_huge.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_huge.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_huge.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_less_than_min_requirement.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_less_than_min_requirement.data
new file mode 100644
index 0000000..353b4e8
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_less_than_min_requirement.data
@@ -0,0 +1,4 @@
+[dist4]message_header  // num_bytes: Less than the minimal size of message
+                       // header.
+[u4]2                  // num_fields
+[anchr]message_header
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_less_than_min_requirement.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_less_than_min_requirement.expected
new file mode 100644
index 0000000..25aceee
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_less_than_min_requirement.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_less_than_struct_header.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_less_than_struct_header.data
new file mode 100644
index 0000000..3a94448
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_less_than_struct_header.data
@@ -0,0 +1,4 @@
+[u4]0           // num_bytes
+[u4]0           // num_fields
+[u4]0x80000000  // name
+[u4]0           // flags
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_less_than_struct_header.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_less_than_struct_header.expected
new file mode 100644
index 0000000..25aceee
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_less_than_struct_header.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_1.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_1.data
new file mode 100644
index 0000000..7e8a714
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_1.data
@@ -0,0 +1,7 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]0x80000000         // name
+[u4]0                  // flags
+[u8]0                  // Extra bytes that result in mismatched |num_bytes| and
+                       // |num_fields|.
+[anchr]message_header
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_1.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_1.expected
new file mode 100644
index 0000000..25aceee
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_1.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_2.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_2.data
new file mode 100644
index 0000000..fd8b4b4
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_2.data
@@ -0,0 +1,8 @@
+[dist4]message_header  // num_bytes
+[u4]3                  // num_fields
+[u4]0x80000000         // name
+[u4]0                  // flags
+[u8]0                  // request_id
+[u8]0                  // Extra bytes that result in mismatched |num_bytes| and
+                       // |num_fields|.
+[anchr]message_header
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_2.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_2.expected
new file mode 100644
index 0000000..25aceee
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_2.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_3.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_3.data
new file mode 100644
index 0000000..c4b46ab
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_3.data
@@ -0,0 +1,5 @@
+[dist4]message_header  // num_bytes
+[u4]8                  // num_fields: |num_bytes| is too small for |num_fields|.
+[u4]0x80000000         // name
+[u4]0                  // flags
+[anchr]message_header
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_3.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_3.expected
new file mode 100644
index 0000000..25aceee
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_bytes_num_fields_mismatch_3.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_fields_less_than_min_requirement.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_fields_less_than_min_requirement.data
new file mode 100644
index 0000000..a94e6ce
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_fields_less_than_min_requirement.data
@@ -0,0 +1,6 @@
+[dist4]message_header  // num_bytes
+[u4]1                  // num_fields: Less than the minimal number of fields
+                       // that we expect.
+[u4]0x80000000         // name
+[u4]0                  // flags
+[anchr]message_header
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_fields_less_than_min_requirement.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_fields_less_than_min_requirement.expected
new file mode 100644
index 0000000..25aceee
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_msghdr_num_fields_less_than_min_requirement.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_good.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_good.data
new file mode 100644
index 0000000..1a5603e
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_good.data
@@ -0,0 +1,11 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]0                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method0_params  // num_bytes
+[u4]1                  // num_fields
+[f]-1                  // param0
+[u4]0                  // padding
+[anchr]method0_params
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_good.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_good.expected
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_good.expected
@@ -0,0 +1 @@
+PASS
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_incomplete_struct.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_incomplete_struct.data
new file mode 100644
index 0000000..5556808
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_incomplete_struct.data
@@ -0,0 +1,9 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]0                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[u4]16  // num_bytes: Incomplete struct.
+[u4]1   // num_fields
+[f]-1   // param0
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_incomplete_struct.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_incomplete_struct.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_incomplete_struct.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_incomplete_struct_header.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_incomplete_struct_header.data
new file mode 100644
index 0000000..9a362f6
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_incomplete_struct_header.data
@@ -0,0 +1,7 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]0                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[u4]16  // num_bytes: Incomplete struct header.
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_incomplete_struct_header.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_incomplete_struct_header.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_incomplete_struct_header.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_huge.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_huge.data
new file mode 100644
index 0000000..52e4540
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_huge.data
@@ -0,0 +1,10 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]0                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[u4]0xFFFFFFFF  // num_bytes: Test whether a huge value will cause overflow.
+[u4]1           // num_fields
+[f]-1           // param0
+[u4]0           // padding
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_huge.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_huge.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_huge.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_less_than_min_requirement.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_less_than_min_requirement.data
new file mode 100644
index 0000000..7c966f8
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_less_than_min_requirement.data
@@ -0,0 +1,9 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]0                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method0_params  // num_bytes: Less than the minimal size that we expect.
+[u4]1                  // num_fields
+[anchr]method0_params
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_less_than_min_requirement.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_less_than_min_requirement.expected
new file mode 100644
index 0000000..25aceee
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_less_than_min_requirement.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_less_than_struct_header.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_less_than_struct_header.data
new file mode 100644
index 0000000..af20941
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_less_than_struct_header.data
@@ -0,0 +1,10 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]0                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[u4]4                  // num_bytes: Less than the size of struct header.
+[u4]1                  // num_fields
+[f]-1                  // param0
+[u4]0                  // padding
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_less_than_struct_header.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_less_than_struct_header.expected
new file mode 100644
index 0000000..25aceee
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd0_struct_num_bytes_less_than_struct_header.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_good.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_good.data
new file mode 100644
index 0000000..d67a72f
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_good.data
@@ -0,0 +1,16 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]1                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method1_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method1_params
+
+[anchr]param0_ptr
+[dist4]struct_a  // num_bytes
+[u4]1            // num_fields
+[u8]1234         // i
+[anchr]struct_a
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_good.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_good.expected
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_good.expected
@@ -0,0 +1 @@
+PASS
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_misaligned_struct.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_misaligned_struct.data
new file mode 100644
index 0000000..051dccc
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_misaligned_struct.data
@@ -0,0 +1,18 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]1                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method1_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method1_params
+
+[u1]0  // Causes the following struct to be misaligned.
+
+[anchr]param0_ptr
+[dist4]struct_a  // num_bytes
+[u4]1            // num_fields
+[u8]1234         // i
+[anchr]struct_a
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_misaligned_struct.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_misaligned_struct.expected
new file mode 100644
index 0000000..acca999
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_misaligned_struct.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_MISALIGNED_OBJECT
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_struct_pointer_overflow.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_struct_pointer_overflow.data
new file mode 100644
index 0000000..98a21c4
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_struct_pointer_overflow.data
@@ -0,0 +1,11 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]1                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method1_params   // num_bytes
+[u4]1                   // num_fields
+[u8]0xFFFFFFFFFFFFFFFF  // param0: Test whether decoding the pointer causes
+                        // overflow.
+[anchr]method1_params
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_struct_pointer_overflow.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_struct_pointer_overflow.expected
new file mode 100644
index 0000000..23abb8c
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_struct_pointer_overflow.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_POINTER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_unexpected_null_struct.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_unexpected_null_struct.data
new file mode 100644
index 0000000..c53a78b
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_unexpected_null_struct.data
@@ -0,0 +1,10 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]1                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method1_params  // num_bytes
+[u4]1                  // num_fields
+[u8]0                  // param0: An unexpected null pointer.
+[anchr]method1_params
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_unexpected_null_struct.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_unexpected_null_struct.expected
new file mode 100644
index 0000000..95d8db0
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd1_unexpected_null_struct.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_NULL_POINTER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_good.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_good.data
new file mode 100644
index 0000000..38e20ab
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_good.data
@@ -0,0 +1,32 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]2                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method2_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[dist8]param1_ptr      // param1
+[anchr]method2_params
+
+[anchr]param0_ptr
+[dist4]struct_b     // num_bytes
+[u4]1               // num_fields
+[dist8]struct_a_ptr // struct_a
+[anchr]struct_b
+
+[u8]0  // Having extra bytes in the middle is okay if the following objects are
+       // still properly alignmented.
+
+[anchr]struct_a_ptr
+[dist4]struct_a_member  // num_bytes
+[u4]1                   // num_fields
+[u8]12345               // i
+[anchr]struct_a_member
+
+[anchr]param1_ptr
+[dist4]struct_a_param  // num_bytes
+[u4]1                  // num_fields
+[u8]67890              // i
+[anchr]struct_a_param
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_good.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_good.expected
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_good.expected
@@ -0,0 +1 @@
+PASS
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_multiple_pointers_to_same_struct.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_multiple_pointers_to_same_struct.data
new file mode 100644
index 0000000..a12121b
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_multiple_pointers_to_same_struct.data
@@ -0,0 +1,25 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]2                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method2_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[dist8]param1_ptr      // param1
+[anchr]method2_params
+
+[anchr]param0_ptr
+[dist4]struct_b     // num_bytes
+[u4]1               // num_fields
+[dist8]struct_a_ptr // struct_a
+[anchr]struct_b
+
+// There are two pointers pointing to the same struct.
+[anchr]struct_a_ptr
+[anchr]param1_ptr
+[dist4]struct_a  // num_bytes
+[u4]1            // num_fields
+[u8]12345        // i
+[anchr]struct_a
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_multiple_pointers_to_same_struct.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_multiple_pointers_to_same_struct.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_multiple_pointers_to_same_struct.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_overlapped_objects.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_overlapped_objects.data
new file mode 100644
index 0000000..a916f03
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_overlapped_objects.data
@@ -0,0 +1,30 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]2                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method2_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[dist8]param1_ptr      // param1
+[anchr]method2_params
+
+[anchr]param0_ptr
+[dist4]struct_b     // num_bytes
+[u4]1               // num_fields
+[dist8]struct_a_ptr // struct_a
+[anchr]struct_b
+
+[anchr]struct_a_ptr
+[dist4]struct_a_member  // num_bytes
+[u4]1                   // num_fields
+
+[anchr]param1_ptr
+// The following |num_bytes| and |num_fields| fields are also the |i| field
+// of the previous struct.
+[dist4]struct_a_param   // num_bytes
+[u4]1                   // num_fields
+[anchr]struct_a_member
+[u8]67890               // i
+[anchr]struct_a_param
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_overlapped_objects.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_overlapped_objects.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_overlapped_objects.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_wrong_layout_order.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_wrong_layout_order.data
new file mode 100644
index 0000000..7145ccd
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_wrong_layout_order.data
@@ -0,0 +1,32 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]2                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method2_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[dist8]param1_ptr      // param1
+[anchr]method2_params
+
+[anchr]param0_ptr
+[dist4]struct_b     // num_bytes
+[u4]1               // num_fields
+[dist8]struct_a_ptr // struct_a
+[anchr]struct_b
+
+// The following two structs are arranged in wrong order.
+
+[anchr]param1_ptr
+[dist4]struct_a_param  // num_bytes
+[u4]1                  // num_fields
+[u8]67890              // i
+[anchr]struct_a_param
+
+[anchr]struct_a_ptr
+[dist4]struct_a_member  // num_bytes
+[u4]1                   // num_fields
+[u8]12345               // i
+[anchr]struct_a_member
+
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_wrong_layout_order.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_wrong_layout_order.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd2_wrong_layout_order.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_huge.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_huge.data
new file mode 100644
index 0000000..ca7651a
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_huge.data
@@ -0,0 +1,16 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]3                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method3_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method3_params
+
+[anchr]param0_ptr
+[u4]0xFFFFFFFF  // num_bytes: Test whether a huge value will cause overflow.
+[u4]12          // num_elements
+[b]01010101
+[b]00001111
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_huge.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_huge.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_huge.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_less_than_array_header.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_less_than_array_header.data
new file mode 100644
index 0000000..9bc1fc3
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_less_than_array_header.data
@@ -0,0 +1,16 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]3                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method3_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method3_params
+
+[anchr]param0_ptr
+[u4]7   // num_bytes: Less than the size of array header.
+[u4]12  // num_elements
+[b]01010101
+[b]00001111
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_less_than_array_header.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_less_than_array_header.expected
new file mode 100644
index 0000000..5a1ec4e
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_less_than_array_header.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_less_than_necessary_size.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_less_than_necessary_size.data
new file mode 100644
index 0000000..bed891c
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_less_than_necessary_size.data
@@ -0,0 +1,18 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]3                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method3_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method3_params
+
+[anchr]param0_ptr
+[dist4]array  // num_bytes: Less than the size needed (array header + 12 boolean
+              // values).
+[u4]12        // num_elements
+[b]01010101
+[anchr]array
+[b]00001111
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_less_than_necessary_size.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_less_than_necessary_size.expected
new file mode 100644
index 0000000..5a1ec4e
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_num_bytes_less_than_necessary_size.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_pointer_overflow.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_pointer_overflow.data
new file mode 100644
index 0000000..f8d7644
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_pointer_overflow.data
@@ -0,0 +1,11 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]3                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method3_params   // num_bytes
+[u4]1                   // num_fields
+[u8]0xFFFFFFFFFFFFFFFF  // param0: Test whether decoding the pointer causes
+                        // overflow.
+[anchr]method3_params
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_pointer_overflow.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_pointer_overflow.expected
new file mode 100644
index 0000000..23abb8c
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_array_pointer_overflow.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_POINTER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_good.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_good.data
new file mode 100644
index 0000000..cc7dd38
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_good.data
@@ -0,0 +1,17 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]3                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method3_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method3_params
+
+[anchr]param0_ptr
+[dist4]array  // num_bytes
+[u4]12        // num_elements
+[b]01010101
+[b]00001111
+[anchr]array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_good.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_good.expected
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_good.expected
@@ -0,0 +1 @@
+PASS
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_incomplete_array.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_incomplete_array.data
new file mode 100644
index 0000000..7850893
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_incomplete_array.data
@@ -0,0 +1,14 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]3                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method3_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method3_params
+
+[anchr]param0_ptr
+[u4]16  // num_bytes
+[u1]0   // num_elements: Incomplete array.
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_incomplete_array.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_incomplete_array.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_incomplete_array.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_incomplete_array_header.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_incomplete_array_header.data
new file mode 100644
index 0000000..5de9fe6
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_incomplete_array_header.data
@@ -0,0 +1,13 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]3                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method3_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method3_params
+
+[anchr]param0_ptr
+[u4]16  // num_bytes: Incomplete array header.
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_incomplete_array_header.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_incomplete_array_header.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_incomplete_array_header.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_misaligned_array.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_misaligned_array.data
new file mode 100644
index 0000000..40a13e0
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_misaligned_array.data
@@ -0,0 +1,19 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]3                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method3_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method3_params
+
+[u2]0  // Causes the following array to be misaligned.
+
+[anchr]param0_ptr
+[dist4]array  // num_bytes
+[u4]12        // num_elements
+[b]01010101
+[b]00001111
+[anchr]array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_misaligned_array.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_misaligned_array.expected
new file mode 100644
index 0000000..acca999
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_misaligned_array.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_MISALIGNED_OBJECT
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_unexpected_null_array.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_unexpected_null_array.data
new file mode 100644
index 0000000..0edab4b
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_unexpected_null_array.data
@@ -0,0 +1,10 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]3                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method3_params  // num_bytes
+[u4]1                  // num_fields
+[u8]0                  // param0: An unexpected null pointer.
+[anchr]method3_params
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_unexpected_null_array.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_unexpected_null_array.expected
new file mode 100644
index 0000000..95d8db0
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd3_unexpected_null_array.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_NULL_POINTER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_good.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_good.data
new file mode 100644
index 0000000..46f7502
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_good.data
@@ -0,0 +1,32 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]4                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method4_params  // num_bytes: Larger than what we know is okay.
+[u4]3                  // num_fields: Larger than what we know is okay.
+[dist8]param0_ptr      // param0
+[dist8]param1_ptr      // param1
+[u8]0                  // unknown
+[anchr]method4_params
+
+[anchr]param0_ptr
+[dist4]struct_c   // num_bytes
+[u4]1             // num_fields
+[dist8]array_ptr  // array
+[anchr]struct_c
+
+[anchr]array_ptr
+[dist4]array_member  // num_bytes
+[u4]3                // num_elements
+0 1 2
+[anchr]array_member
+
+[u4]0 [u1]0  // Padding to make the next array aligned properly.
+
+[anchr]param1_ptr
+[dist4]array_param  // num_bytes
+[u4]10              // num_elements
+0 1 2 3 4 5 6 7 8 9
+[anchr]array_param
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_good.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_good.expected
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_good.expected
@@ -0,0 +1 @@
+PASS
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_multiple_pointers_to_same_array.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_multiple_pointers_to_same_array.data
new file mode 100644
index 0000000..f3a0e9f
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_multiple_pointers_to_same_array.data
@@ -0,0 +1,24 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]4                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method4_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[dist8]param1_ptr      // param1
+[anchr]method4_params
+
+[anchr]param0_ptr
+[dist4]struct_c   // num_bytes
+[u4]1             // num_fields
+[dist8]array_ptr  // array
+[anchr]struct_c
+
+[anchr]param1_ptr
+[anchr]array_ptr
+[dist4]array_member  // num_bytes
+[u4]3                // num_elements
+0 1 2
+[anchr]array_member
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_multiple_pointers_to_same_array.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_multiple_pointers_to_same_array.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_multiple_pointers_to_same_array.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_overlapped_objects.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_overlapped_objects.data
new file mode 100644
index 0000000..d819857
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_overlapped_objects.data
@@ -0,0 +1,30 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]4                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method4_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[dist8]param1_ptr      // param1
+[anchr]method4_params
+
+[anchr]param0_ptr
+[dist4]struct_c   // num_bytes
+[u4]1             // num_fields
+[dist8]array_ptr  // array
+[anchr]struct_c
+
+[anchr]array_ptr
+[dist4]array_member  // num_bytes
+[u4]3                // num_elements
+
+[anchr]param1_ptr
+// The first three bytes of |num_bytes| are also the elements of the previous
+// array.
+[dist4]array_param  // num_bytes
+[u4]10              // num_elements
+0 1 2 3 4 5 6 7 8 9
+[anchr]array_param
+[anchr]array_member
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_overlapped_objects.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_overlapped_objects.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_overlapped_objects.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_wrong_layout_order.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_wrong_layout_order.data
new file mode 100644
index 0000000..fdc925f
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_wrong_layout_order.data
@@ -0,0 +1,33 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]4                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method4_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[dist8]param1_ptr      // param1
+[anchr]method4_params
+
+[anchr]param0_ptr
+[dist4]struct_c   // num_bytes
+[u4]1             // num_fields
+[dist8]array_ptr  // array
+[anchr]struct_c
+
+// The following two arrays are arranged in wrong order.
+
+[anchr]param1_ptr
+[dist4]array_param  // num_bytes
+[u4]10              // num_elements
+0 1 2 3 4 5 6 7 8 9
+[anchr]array_param
+
+[u4]0 [u2]0  // Padding to make the next array aligned properly.
+
+[anchr]array_ptr
+[dist4]array_member  // num_bytes
+[u4]3                // num_elements
+0 1 2
+[anchr]array_member
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_wrong_layout_order.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_wrong_layout_order.expected
new file mode 100644
index 0000000..779df88
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd4_wrong_layout_order.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_good.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_good.data
new file mode 100644
index 0000000..0518c14
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_good.data
@@ -0,0 +1,35 @@
+[handles]10  // Larger than the number of handles that we know about is okay.
+
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]5                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method5_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[u4]4                  // param1
+[u4]0                  // padding
+[anchr]method5_params
+
+[anchr]param0_ptr
+[dist4]struct_e      // num_bytes
+[u4]2                // num_fields
+[dist8]struct_d_ptr  // struct_d
+[u4]3                // data_pipe_consumer
+[u4]0                // padding
+[anchr]struct_e
+
+[anchr]struct_d_ptr
+[dist4]struct_d           // num_bytes
+[u4]1                     // num_fields
+[dist8]message_pipes_ptr  // message_pipes
+[anchr]struct_d
+
+[anchr]message_pipes_ptr
+[dist4]message_pipe_array  // num_bytes
+[u4]2                      // num_elements
+[u4]0
+[u4]1
+[anchr]message_pipe_array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_good.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_good.expected
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_good.expected
@@ -0,0 +1 @@
+PASS
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_handle_out_of_range.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_handle_out_of_range.data
new file mode 100644
index 0000000..43cad7c
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_handle_out_of_range.data
@@ -0,0 +1,36 @@
+[handles]10
+
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]5                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method5_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[u4]10                 // param1: It is outside of the valid encoded handle
+                       // range [0, 10).
+[u4]0                  // padding
+[anchr]method5_params
+
+[anchr]param0_ptr
+[dist4]struct_e      // num_bytes
+[u4]2                // num_fields
+[dist8]struct_d_ptr  // struct_d
+[u4]3                // data_pipe_consumer
+[u4]0                // padding
+[anchr]struct_e
+
+[anchr]struct_d_ptr
+[dist4]struct_d           // num_bytes
+[u4]1                     // num_fields
+[dist8]message_pipes_ptr  // message_pipes
+[anchr]struct_d
+
+[anchr]message_pipes_ptr
+[dist4]message_pipe_array  // num_bytes
+[u4]2                      // num_elements
+[u4]0
+[u4]1
+[anchr]message_pipe_array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_handle_out_of_range.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_handle_out_of_range.expected
new file mode 100644
index 0000000..eef8e38
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_handle_out_of_range.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_HANDLE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_multiple_handles_with_same_value_1.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_multiple_handles_with_same_value_1.data
new file mode 100644
index 0000000..8b39c00
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_multiple_handles_with_same_value_1.data
@@ -0,0 +1,35 @@
+[handles]10
+
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]5                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method5_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[u4]4                  // param1
+[u4]0                  // padding
+[anchr]method5_params
+
+[anchr]param0_ptr
+[dist4]struct_e      // num_bytes
+[u4]2                // num_fields
+[dist8]struct_d_ptr  // struct_d
+[u4]4                // data_pipe_consumer: The same value as |param1| above.
+[u4]0                // padding
+[anchr]struct_e
+
+[anchr]struct_d_ptr
+[dist4]struct_d           // num_bytes
+[u4]1                     // num_fields
+[dist8]message_pipes_ptr  // message_pipes
+[anchr]struct_d
+
+[anchr]message_pipes_ptr
+[dist4]message_pipe_array  // num_bytes
+[u4]2                      // num_elements
+[u4]0
+[u4]1
+[anchr]message_pipe_array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_multiple_handles_with_same_value_1.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_multiple_handles_with_same_value_1.expected
new file mode 100644
index 0000000..eef8e38
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_multiple_handles_with_same_value_1.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_HANDLE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_multiple_handles_with_same_value_2.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_multiple_handles_with_same_value_2.data
new file mode 100644
index 0000000..95a356b
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_multiple_handles_with_same_value_2.data
@@ -0,0 +1,35 @@
+[handles]10
+
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]5                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method5_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[u4]4                  // param1
+[u4]0                  // padding
+[anchr]method5_params
+
+[anchr]param0_ptr
+[dist4]struct_e      // num_bytes
+[u4]2                // num_fields
+[dist8]struct_d_ptr  // struct_d
+[u4]3                // data_pipe_consumer
+[u4]0                // padding
+[anchr]struct_e
+
+[anchr]struct_d_ptr
+[dist4]struct_d           // num_bytes
+[u4]1                     // num_fields
+[dist8]message_pipes_ptr  // message_pipes
+[anchr]struct_d
+
+[anchr]message_pipes_ptr
+[dist4]message_pipe_array  // num_bytes
+[u4]2                      // num_elements
+[u4]1                      // The two message pipe handles have the same value.
+[u4]1
+[anchr]message_pipe_array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_multiple_handles_with_same_value_2.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_multiple_handles_with_same_value_2.expected
new file mode 100644
index 0000000..eef8e38
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_multiple_handles_with_same_value_2.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_HANDLE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_unexpected_invalid_handle.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_unexpected_invalid_handle.data
new file mode 100644
index 0000000..ef49285
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_unexpected_invalid_handle.data
@@ -0,0 +1,34 @@
+[handles]5
+
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]5                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method5_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[u4]4                  // param1
+[u4]0                  // padding
+[anchr]method5_params
+
+[anchr]param0_ptr
+[dist4]struct_e      // num_bytes
+[u4]2                // num_fields
+[dist8]struct_d_ptr  // struct_d
+[s4]-1               // data_pipe_consumer: An unexpected invalid handle.
+[u4]0                // padding
+[anchr]struct_e
+
+[anchr]struct_d_ptr
+[dist4]struct_d           // num_bytes
+[u4]1                     // num_fields
+[dist8]message_pipes_ptr  // message_pipes
+[anchr]struct_d
+
+[anchr]message_pipes_ptr
+[dist4]message_pipe_array  // num_bytes
+[u4]1                      // num_elements
+[u4]2
+[anchr]message_pipe_array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_unexpected_invalid_handle.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_unexpected_invalid_handle.expected
new file mode 100644
index 0000000..6768236
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_unexpected_invalid_handle.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_wrong_handle_order.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_wrong_handle_order.data
new file mode 100644
index 0000000..c6fa8ea
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_wrong_handle_order.data
@@ -0,0 +1,36 @@
+[handles]10
+
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]5                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method5_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[u4]9                  // param1
+[u4]0                  // padding
+[anchr]method5_params
+
+[anchr]param0_ptr
+[dist4]struct_e      // num_bytes
+[u4]2                // num_fields
+[dist8]struct_d_ptr  // struct_d
+[u4]1                // data_pipe_consumer: It is smaller than those handles
+                     // in |message_pipe_array|, which is wrong.
+[u4]0                // padding
+[anchr]struct_e
+
+[anchr]struct_d_ptr
+[dist4]struct_d           // num_bytes
+[u4]1                     // num_fields
+[dist8]message_pipes_ptr  // message_pipes
+[anchr]struct_d
+
+[anchr]message_pipes_ptr
+[dist4]message_pipe_array  // num_bytes
+[u4]2                      // num_elements
+[u4]3
+[u4]4
+[anchr]message_pipe_array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_wrong_handle_order.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_wrong_handle_order.expected
new file mode 100644
index 0000000..eef8e38
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd5_wrong_handle_order.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_ILLEGAL_HANDLE
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd6_good.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd6_good.data
new file mode 100644
index 0000000..4f34c0b
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd6_good.data
@@ -0,0 +1,22 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]6                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method6_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method6_params
+
+[anchr]param0_ptr
+[dist4]array_param  // num_bytes
+[u4]1               // num_elements
+[dist8]element_ptr
+[anchr]array_param
+
+[anchr]element_ptr
+[dist4]array_element  // num_bytes
+[u4]10                // num_elements
+0 1 2 3 4 5 6 7 8 9
+[anchr]array_element
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd6_good.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd6_good.expected
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd6_good.expected
@@ -0,0 +1 @@
+PASS
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd6_nested_array_num_bytes_less_than_necessary_size.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd6_nested_array_num_bytes_less_than_necessary_size.data
new file mode 100644
index 0000000..a58396c
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd6_nested_array_num_bytes_less_than_necessary_size.data
@@ -0,0 +1,22 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]6                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method6_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method6_params
+
+[anchr]param0_ptr
+[dist4]array_param  // num_bytes
+[u4]1               // num_elements
+[dist8]element_ptr
+[anchr]array_param
+
+[anchr]element_ptr
+[dist4]array_element  // num_bytes: It is insufficient to store 12 elements.
+[u4]12                // num_elements
+0 1 2 3 4 5 6 7 8 9
+[anchr]array_element
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd6_nested_array_num_bytes_less_than_necessary_size.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd6_nested_array_num_bytes_less_than_necessary_size.expected
new file mode 100644
index 0000000..5a1ec4e
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd6_nested_array_num_bytes_less_than_necessary_size.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_good.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_good.data
new file mode 100644
index 0000000..d6562af
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_good.data
@@ -0,0 +1,32 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]7                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method7_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[dist8]param1_ptr      // param1
+[u8]0                  // unknown
+[anchr]method7_params
+
+[anchr]param0_ptr
+[dist4]struct_f        // num_bytes
+[u4]1                  // num_fields
+[dist8]array_ptr       // fixed_size_array
+[anchr]struct_f
+
+[anchr]array_ptr
+[dist4]array_member    // num_bytes
+[u4]3                  // num_elements
+0 1 2
+[anchr]array_member
+
+[u4]0 [u1]0            // Padding to make the next array aligned properly.
+
+[anchr]param1_ptr
+[dist4]array_param     // num_bytes
+[u4]5                  // num_elements
+0 1 2 3 4
+[anchr]array_param
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_good.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_good.expected
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_good.expected
@@ -0,0 +1 @@
+PASS
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_too_few_array_elements.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_too_few_array_elements.data
new file mode 100644
index 0000000..bf1ddd5
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_too_few_array_elements.data
@@ -0,0 +1,31 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]7                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method7_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[dist8]param1_ptr      // param1
+[anchr]method7_params
+
+[anchr]param0_ptr
+[dist4]struct_f        // num_bytes
+[u4]1                  // num_fields
+[dist8]array_ptr       // fixed_size_array
+[anchr]struct_f
+
+[anchr]array_ptr
+[dist4]array_member    // num_bytes
+[u4]2                  // num_elements: Too few elements.
+0 1
+[anchr]array_member
+
+[u4]0 [u1]0 [u1]0      // Padding for alignment of next array.
+
+[anchr]param1_ptr
+[dist4]array_param     // num_bytes
+[u4]5                  // num_elements
+0 1 2 3 4
+[anchr]array_param
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_too_few_array_elements.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_too_few_array_elements.expected
new file mode 100644
index 0000000..5a1ec4e
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_too_few_array_elements.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_unexpected_null_fixed_array.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_unexpected_null_fixed_array.data
new file mode 100644
index 0000000..ab69175
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_unexpected_null_fixed_array.data
@@ -0,0 +1,23 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]7                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method7_params  // num_bytes
+[u4]2                  // num_fields
+[dist8]param0_ptr      // param0
+[dist8]param1_ptr      // param1
+[anchr]method7_params
+
+[anchr]param0_ptr
+[dist4]struct_f        // num_bytes
+[u4]1                  // num_fields
+[u8]0                  // fixed_size_array: An unexpected null pointer.
+[anchr]struct_f
+
+[anchr]param1_ptr
+[dist4]array_param     // num_bytes
+[u4]5                  // num_elements
+0 1 2 3 4
+[anchr]array_param
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_unexpected_null_fixed_array.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_unexpected_null_fixed_array.expected
new file mode 100644
index 0000000..95d8db0
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd7_unexpected_null_fixed_array.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_NULL_POINTER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_array_num_bytes_overflow.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_array_num_bytes_overflow.data
new file mode 100644
index 0000000..059e538
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_array_num_bytes_overflow.data
@@ -0,0 +1,19 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]8                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method8_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method8_params
+
+[anchr]param0_ptr
+[dist4]array_param  // num_bytes
+[u4]0x20000001      // num_elements: The corresponding array size should be
+                    // 0x20000001 * 8 + 8 = 0x100000010 which is
+                    // 2^32 + 16 (base-10), while |num_bytes| is a 32-bit
+                    // unsigned integer and its value is 16.
+[u8]0
+[anchr]array_param
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_array_num_bytes_overflow.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_array_num_bytes_overflow.expected
new file mode 100644
index 0000000..5a1ec4e
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_array_num_bytes_overflow.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_good.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_good.data
new file mode 100644
index 0000000..fd5e174
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_good.data
@@ -0,0 +1,30 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]8                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method8_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method8_params
+
+[anchr]param0_ptr
+[dist4]array_param       // num_bytes
+[u4]3                    // num_elements
+[u8]0                    // A null pointer, which is okay.
+[dist8]nested_array_ptr
+[u8]0                    // A null pointer, which is okay.
+[anchr]array_param
+
+[anchr]nested_array_ptr
+[dist4]nested_array  // num_bytes
+[u4]1                // num_elements
+[dist8]string_ptr
+[anchr]nested_array
+
+[anchr]string_ptr
+[dist4]string  // num_bytes
+[u4]5          // num_elements
+0 1 2 3 4
+[anchr]string
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_good.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_good.expected
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_good.expected
@@ -0,0 +1 @@
+PASS
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_unexpected_null_array.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_unexpected_null_array.data
new file mode 100644
index 0000000..f1d8718
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_unexpected_null_array.data
@@ -0,0 +1,10 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]8                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method8_params  // num_bytes
+[u4]1                  // num_fields
+[u8]0                  // param0: An unexpected null pointer.
+[anchr]method8_params
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_unexpected_null_array.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_unexpected_null_array.expected
new file mode 100644
index 0000000..95d8db0
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_unexpected_null_array.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_NULL_POINTER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_unexpected_null_string.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_unexpected_null_string.data
new file mode 100644
index 0000000..104dddb
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_unexpected_null_string.data
@@ -0,0 +1,31 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]8                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method8_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method8_params
+
+[anchr]param0_ptr
+[dist4]array_param       // num_bytes
+[u4]3                    // num_elements
+[u8]0                    // A null pointer, which is okay.
+[dist8]nested_array_ptr
+[u8]0                    // A null pointer, which is okay.
+[anchr]array_param
+
+[anchr]nested_array_ptr
+[dist4]nested_array  // num_bytes
+[u4]2                // num_elements
+[dist8]string_ptr
+[u8]0                // An unexpected null pointer.
+[anchr]nested_array
+
+[anchr]string_ptr
+[dist4]string  // num_bytes
+[u4]5          // num_elements
+0 1 2 3 4
+[anchr]string
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_unexpected_null_string.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_unexpected_null_string.expected
new file mode 100644
index 0000000..95d8db0
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd8_unexpected_null_string.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_NULL_POINTER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_good.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_good.data
new file mode 100644
index 0000000..c548906
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_good.data
@@ -0,0 +1,34 @@
+[handles]4
+
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]9                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method9_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method9_params
+
+[anchr]param0_ptr
+[dist4]array_param         // num_bytes
+[u4]2                      // num_elements
+[dist8]nested_array_ptr_0
+[dist8]nested_array_ptr_1
+[anchr]array_param
+
+[anchr]nested_array_ptr_0
+[dist4]nested_array_0  // num_bytes
+[u4]2                  // num_elements
+[u4]0
+[s4]-1                 // An invalid handle, which is okay.
+[anchr]nested_array_0
+
+[anchr]nested_array_ptr_1
+[dist4]nested_array_1  // num_bytes
+[u4]3                  // num_elements
+[u4]2
+[s4]-1                 // An invalid handle, which is okay.
+[u4]3
+[anchr]nested_array_1
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_good.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_good.expected
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_good.expected
@@ -0,0 +1 @@
+PASS
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_good_null_array.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_good_null_array.data
new file mode 100644
index 0000000..f0967d5
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_good_null_array.data
@@ -0,0 +1,12 @@
+[handles]4
+
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]9                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method9_params  // num_bytes
+[u4]1                  // num_fields
+[u8]0                  // param0: A null pointer, which is okay.
+[anchr]method9_params
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_good_null_array.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_good_null_array.expected
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_good_null_array.expected
@@ -0,0 +1 @@
+PASS
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_unexpected_null_array.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_unexpected_null_array.data
new file mode 100644
index 0000000..9c8f478
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_unexpected_null_array.data
@@ -0,0 +1,25 @@
+[handles]4
+
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]9                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method9_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method9_params
+
+[anchr]param0_ptr
+[dist4]array_param         // num_bytes
+[u4]2                      // num_elements
+[dist8]nested_array_ptr_0
+[u8]0                      // An unexpected null pointer.
+[anchr]array_param
+
+[anchr]nested_array_ptr_0
+[dist4]nested_array_0  // num_bytes
+[u4]1                  // num_elements
+[u4]0
+[anchr]nested_array_0
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_unexpected_null_array.expected b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_unexpected_null_array.expected
new file mode 100644
index 0000000..95d8db0
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd9_unexpected_null_array.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_NULL_POINTER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.data b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.data
new file mode 100644
index 0000000..df7b7e8
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.data
@@ -0,0 +1,17 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]0                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method0_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method0_params
+
+[anchr]param0_ptr
+[dist4]basic_struct  // num_bytes
+[u4]1                // num_fields
+[s4]-1               // a
+[u4]0                // padding
+[anchr]basic_struct
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_good.expected
@@ -0,0 +1 @@
+PASS
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.data b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.data
new file mode 100644
index 0000000..3dcca9d
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.data
@@ -0,0 +1,14 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]0                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method0_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method0_params
+
+[anchr]param0_ptr
+[u4]0  // num_bytes: The struct size is too small.
+[u4]0  // num_fields
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.expected b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.expected
new file mode 100644
index 0000000..25aceee
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf1_mthd0_rqst_unexpected_struct_header.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_good.data b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_good.data
new file mode 100644
index 0000000..f4b6c40
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_good.data
@@ -0,0 +1,17 @@
+[dist4]message_header  // num_bytes
+[u4]3                  // num_fields
+[u4]0                  // name
+[u4]2                  // flags: Is response.
+[u8]1                  // request_id
+[anchr]message_header
+
+[dist4]method0_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method0_params
+
+[anchr]param0_ptr
+[dist4]uint8_array  // num_bytes
+[u4]1               // num_elements
+[u1]0
+[anchr]uint8_array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_good.expected b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_good.expected
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_good.expected
@@ -0,0 +1 @@
+PASS
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_unexpected_array_header.data b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_unexpected_array_header.data
new file mode 100644
index 0000000..a357013
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_unexpected_array_header.data
@@ -0,0 +1,17 @@
+[dist4]message_header  // num_bytes
+[u4]3                  // num_fields
+[u4]0                  // name
+[u4]2                  // flags: Is response.
+[u8]1                  // request_id
+[anchr]message_header
+
+[dist4]method0_params  // num_bytes
+[u4]1                  // num_fields
+[dist8]param0_ptr      // param0
+[anchr]method0_params
+
+[anchr]param0_ptr
+[dist4]uint8_array  // num_bytes
+[u4]2               // num_elements: The size is too small to hold 2 elements.
+[u1]0
+[anchr]uint8_array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_unexpected_array_header.expected b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_unexpected_array_header.expected
new file mode 100644
index 0000000..5a1ec4e
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/integration_intf2_mthd0_resp_unexpected_array_header.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/integration_msghdr_invalid_flags.data b/mojo/public/interfaces/bindings/tests/data/validation/integration_msghdr_invalid_flags.data
new file mode 100644
index 0000000..6d2cb4e
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/integration_msghdr_invalid_flags.data
@@ -0,0 +1,6 @@
+[dist4]message_header  // num_bytes
+[u4]3                  // num_fields
+[u4]0xffffffff         // name
+[u4]3                  // flags: This combination is illegal.
+[u8]1                  // request_id
+[anchr]message_header
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/integration_msghdr_invalid_flags.expected b/mojo/public/interfaces/bindings/tests/data/validation/integration_msghdr_invalid_flags.expected
new file mode 100644
index 0000000..696c78d
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/integration_msghdr_invalid_flags.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/not_implemented_mthd0_struct_num_fields_less_than_min_requirement.data b/mojo/public/interfaces/bindings/tests/data/validation/not_implemented_mthd0_struct_num_fields_less_than_min_requirement.data
new file mode 100644
index 0000000..ffcafd3
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/not_implemented_mthd0_struct_num_fields_less_than_min_requirement.data
@@ -0,0 +1,12 @@
+[dist4]message_header  // num_bytes
+[u4]2                  // num_fields
+[u4]0                  // name
+[u4]0                  // flags
+[anchr]message_header
+
+[dist4]method0_params  // num_bytes
+[u4]0                  // num_fields: Less than the minimal number of fields
+                       // that we expect.
+[f]-1                  // param0
+[u4]0                  // padding
+[anchr]method0_params
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/not_implemented_mthd0_struct_num_fields_less_than_min_requirement.expected b/mojo/public/interfaces/bindings/tests/data/validation/not_implemented_mthd0_struct_num_fields_less_than_min_requirement.expected
new file mode 100644
index 0000000..25aceee
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/data/validation/not_implemented_mthd0_struct_num_fields_less_than_min_requirement.expected
@@ -0,0 +1 @@
+VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER
diff --git a/mojo/public/interfaces/bindings/tests/math_calculator.mojom b/mojo/public/interfaces/bindings/tests/math_calculator.mojom
new file mode 100644
index 0000000..a18add1
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/math_calculator.mojom
@@ -0,0 +1,19 @@
+// Copyright 2013 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.
+
+[JavaPackage="org.chromium.mojo.bindings.test.mojom.math"]
+module math {
+
+[Client=CalculatorUI]
+interface Calculator {
+  Clear@0();
+  Add@1(double value@0);
+  Multiply@2(double value@0);
+};
+
+interface CalculatorUI {
+  Output@0(double value@0);
+};
+
+}
diff --git a/mojo/public/interfaces/bindings/tests/no_module.mojom b/mojo/public/interfaces/bindings/tests/no_module.mojom
new file mode 100644
index 0000000..f380011
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/no_module.mojom
@@ -0,0 +1,9 @@
+// Copyright 2014 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.
+
+// Entities without module
+
+enum EnumWithoutModule {
+  A
+};
diff --git a/mojo/public/interfaces/bindings/tests/rect.mojom b/mojo/public/interfaces/bindings/tests/rect.mojom
new file mode 100644
index 0000000..324ce48
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/rect.mojom
@@ -0,0 +1,15 @@
+// Copyright 2014 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.
+
+[JavaPackage="org.chromium.mojo.bindings.test.mojom.test_structs"]
+module mojo.test {
+
+struct Rect {
+  int32 x;
+  int32 y;
+  int32 width;
+  int32 height;
+};
+
+}
diff --git a/mojo/public/interfaces/bindings/tests/regression_tests.mojom b/mojo/public/interfaces/bindings/tests/regression_tests.mojom
new file mode 100644
index 0000000..49ab69a
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/regression_tests.mojom
@@ -0,0 +1,37 @@
+// Copyright 2014 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.
+
+// Module containing entities for regression tests of the generator. Entities
+// must never be modified, instead new entity must be added to add new tests.
+[JavaPackage="org.chromium.mojo.bindings.test.mojom.regression_tests"]
+module regression_tests {
+
+interface CheckMethodWithEmptyResponse {
+WithouParameterAndEmptyResponse() => ();
+WithParameterAndEmptyResponse(bool b) => ();
+};
+
+interface CheckNameCollision {
+WithNameCollision(bool message, bool response) => (bool message, bool response);
+};
+
+enum EnumWithReference {
+  k_STEREO_AND_KEYBOARD_MIC = 30,
+  k_MAX = k_STEREO_AND_KEYBOARD_MIC
+};
+
+enum EnumWithLowercase {
+  PlanarF16,
+  PlanarF32
+};
+
+enum EnumWithNumbers {
+  k_2_1 = 4
+};
+
+enum EnumWithK {
+  K = 0
+};
+
+}  // module imported
diff --git a/mojo/public/interfaces/bindings/tests/sample_factory.mojom b/mojo/public/interfaces/bindings/tests/sample_factory.mojom
new file mode 100644
index 0000000..567cf23
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/sample_factory.mojom
@@ -0,0 +1,48 @@
+// Copyright 2013 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.
+
+import "sample_import.mojom"
+
+[JavaPackage="org.chromium.mojo.bindings.test.mojom.sample"]
+module sample {
+
+// This sample shows how handles to MessagePipes can be sent as both parameters
+// to methods as well as fields on structs.
+
+struct Request {
+  int32 x;
+  handle<message_pipe>? pipe;
+  array<handle<message_pipe>>? more_pipes;
+
+  // Interfaces can be used as members.
+  imported.ImportedInterface? obj;
+};
+
+struct Response {
+  int32 x;
+  handle<message_pipe>? pipe;
+};
+
+interface NamedObject {
+  SetName(string name);
+  GetName() => (string name);
+};
+
+[Client=FactoryClient]
+interface Factory {
+  DoStuff(Request request, handle<message_pipe>? pipe);
+  DoStuff2(handle<data_pipe_consumer> pipe);
+  CreateNamedObject(NamedObject& obj);
+  RequestImportedInterface(
+      imported.ImportedInterface& obj) => (imported.ImportedInterface& obj);
+  TakeImportedInterface(
+      imported.ImportedInterface obj) => (imported.ImportedInterface obj);
+};
+
+interface FactoryClient {
+  DidStuff(Response response, string text);
+  DidStuff2(string text);
+};
+
+}  // module sample
diff --git a/mojo/public/interfaces/bindings/tests/sample_import.mojom b/mojo/public/interfaces/bindings/tests/sample_import.mojom
new file mode 100644
index 0000000..659b74d
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/sample_import.mojom
@@ -0,0 +1,40 @@
+// Copyright 2014 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.
+
+[JavaPackage="org.chromium.mojo.bindings.test.mojom.imported"]
+module imported {
+
+// This sample just defines some types that are imported into
+// sample_service.mojom, to show how import works.
+
+enum Shape {
+  RECTANGLE = 1,
+  CIRCLE,
+  TRIANGLE,
+  LAST = TRIANGLE,
+};
+
+// These enum values should not interfere with those of Shape above.
+enum AnotherShape {
+  RECTANGLE = 10,
+  CIRCLE,
+  TRIANGLE,
+};
+
+enum YetAnotherShape {
+  RECTANGLE = 20,
+  CIRCLE,
+  TRIANGLE,
+};
+
+struct Point {
+  int32 x;
+  int32 y;
+};
+
+interface ImportedInterface {
+  DoSomething();
+};
+
+}  // module imported
diff --git a/mojo/public/interfaces/bindings/tests/sample_import2.mojom b/mojo/public/interfaces/bindings/tests/sample_import2.mojom
new file mode 100644
index 0000000..63ddb5a
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/sample_import2.mojom
@@ -0,0 +1,30 @@
+// Copyright 2014 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.
+
+import "sample_import.mojom"
+
+[JavaPackage="org.chromium.mojo.bindings.test.mojom.imported"]
+module imported {
+
+// This sample adds more types and constants to the "imported" namespace,
+// to test a bug with importing multiple modules with the same namespace.
+
+enum Color {
+  RED,
+  BLACK,
+};
+
+struct Size {
+  int32 width;
+  int32 height;
+};
+
+struct Thing {
+  imported.Shape shape = RECTANGLE;
+  int32 color = Color.BLACK;
+  Point location;
+  Size size;
+};
+
+}  // module imported
diff --git a/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom b/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom
new file mode 100644
index 0000000..01e78ed
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom
@@ -0,0 +1,28 @@
+// Copyright 2014 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.
+
+[JavaPackage="org.chromium.mojo.bindings.test.mojom.sample",
+ JavaConstantsClassName="InterfaceConstants",
+ Foo = "hello world"]
+module sample {
+
+const uint64 kLong = 4405;
+
+enum Enum {
+  VALUE
+};
+
+[Client=ProviderClient]
+interface Provider {
+  EchoString(string a) => (string a);
+  EchoStrings(string a, string b) => (string a, string b);
+  EchoMessagePipeHandle(handle<message_pipe> a) => (handle<message_pipe> a);
+  EchoEnum(Enum a) => (Enum a);
+};
+
+// TODO(darin): We shouldn't need this, but JS bindings don't work without it.
+interface ProviderClient {
+};
+
+}
diff --git a/mojo/public/interfaces/bindings/tests/sample_service.mojom b/mojo/public/interfaces/bindings/tests/sample_service.mojom
new file mode 100644
index 0000000..baf03de
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/sample_service.mojom
@@ -0,0 +1,128 @@
+// Copyright 2013 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.
+
+import "sample_import.mojom"
+import "sample_import2.mojom"
+
+[JavaPackage="org.chromium.mojo.bindings.test.mojom.sample"]
+module sample {
+
+const uint8 kTwelve = 12;
+const uint64 kTooBigForSignedInt64 = 9999999999999999999;
+
+const double kDoubleInfinity = double.INFINITY;
+const double kDoubleNegativeInfinity = double.NEGATIVE_INFINITY;
+const double kDoubleNaN = double.NAN;
+
+const float kFloatInfinity = float.INFINITY;
+const float kFloatNegativeInfinity = float.NEGATIVE_INFINITY;
+const float kFloatNaN = float.NAN;
+
+struct Bar {
+  enum Type {
+    VERTICAL = 1,
+    HORIZONTAL,
+    BOTH,
+    INVALID
+  };
+  uint8 alpha@0 = 0xff;
+  uint8 beta@1;
+  uint8 gamma@2;
+  Type type@3 = sample.Bar.Type.VERTICAL;
+};
+
+[RequiredFields=7]
+struct Foo {
+  const string kFooby = "Fooby";
+  string name@8 = kFooby;
+  int32 x@0;
+  int32 y@1;
+  bool a@2 = true;
+  bool b@3;
+  bool c@4;
+  Bar? bar@5;
+  array<Bar>? extra_bars@7;
+  array<uint8>? data@6;
+  handle<message_pipe>? source@9;
+  array<handle<data_pipe_consumer>>? input_streams@10;
+  array<handle<data_pipe_producer>>? output_streams@11;
+  array<array<bool>>? array_of_array_of_bools@12;
+  array<array<array<string>>>? multi_array_of_strings@13;
+  array<bool>? array_of_bools@14;
+};
+
+struct DefaultsTest {
+  int8 a0@0 = -12;
+  uint8 a1@1 = sample.kTwelve;
+  int16 a2@2 = 1234;
+  uint16 a3@3 = 34567;
+  int32 a4@4 = 123456;
+  uint32 a5@5 = 3456789012;
+  int64 a6@6 = -111111111111;
+  uint64 a7@7 = 9999999999999999999;
+  int32 a8@8 = 0x12345;
+  int32 a9@9 = -0x12345;
+  int32 a10@10 = +1234;
+  bool a11@11 = true;
+  bool a12@12 = false;
+  float a13@13 = 123.25;
+  double a14@14 = 1234567890.123;
+  double a15@15 = 1E10;
+  double a16@16 = -1.2E+20;
+  double a17@17 = +1.23E-20;
+
+  // TODO(vtl): Add tests for default vs null when those are implemented (for
+  // structs, arrays, and strings).
+  array<uint8> a18@18;
+  string a19@19;
+
+  Bar.Type a20@20 = BOTH;
+  imported.Point a21@21;
+  imported.Thing a22@22 = default;
+
+  uint64 a23@23 = 0xFFFFFFFFFFFFFFFF;
+  int64 a24@24 = 0x123456789;
+  int64 a25@25 = -0x123456789;
+
+  double a26@26 = double.INFINITY;
+  double a27@27 = double.NEGATIVE_INFINITY;
+  double a28@28 = double.NAN;
+  float a29@29 = float.INFINITY;
+  float a30@30 = float.NEGATIVE_INFINITY;
+  float a31@31 = float.NAN;
+};
+
+struct StructWithHoleV1 {
+  int32 v1 = 1;
+  int64 v2 = 2;
+};
+
+struct StructWithHoleV2 {
+  int32 v1 = 1;
+  int64 v2 = 2;
+  int32 v3 = 3;
+};
+
+[Client=ServiceClient]
+interface Service {
+  enum BazOptions {
+    REGULAR = 0,
+    EXTRA
+  };
+  const uint8 kFavoriteBaz = 1;
+  Frobinate@0(Foo? foo@0, BazOptions baz@1, Port? port@2);
+  GetPort@1(Port& port @0);
+};
+
+interface ServiceClient {
+  DidFrobinate@0(int32 result@0);
+};
+
+// This interface is referenced above where it is defined. It also refers to
+// itself from a method.
+interface Port {
+  PostMessage@0(string message_text@0, Port port@1);
+};
+
+}
diff --git a/mojo/public/interfaces/bindings/tests/serialization_test_structs.mojom b/mojo/public/interfaces/bindings/tests/serialization_test_structs.mojom
new file mode 100644
index 0000000..f51c197
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/serialization_test_structs.mojom
@@ -0,0 +1,38 @@
+// Copyright 2014 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.
+
+[JavaPackage="org.chromium.mojo.bindings.test.mojom.mojo"]
+module mojo.test {
+
+struct Struct1 {
+  uint8 i;
+};
+
+struct Struct2 {
+  handle hdl;
+};
+
+struct Struct3 {
+  Struct1 struct_1;
+};
+
+struct Struct4 {
+  array<Struct1> data;
+};
+
+struct Struct5 {
+  array<Struct1, 2> pair;
+};
+
+struct Struct6 {
+  string str;
+};
+
+struct StructOfNullables {
+  handle? hdl;
+  Struct1? struct_1;
+  string? str;
+};
+
+}
diff --git a/mojo/public/interfaces/bindings/tests/test_structs.mojom b/mojo/public/interfaces/bindings/tests/test_structs.mojom
new file mode 100644
index 0000000..d361da7
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/test_structs.mojom
@@ -0,0 +1,85 @@
+// Copyright 2013 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.
+
+import "mojo/public/interfaces/bindings/tests/rect.mojom"
+
+[JavaPackage="org.chromium.mojo.bindings.test.mojom.test_structs"]
+module mojo.test {
+
+struct NamedRegion {
+  string? name;
+  array<Rect>? rects;
+};
+
+struct RectPair {
+  Rect? first;
+  Rect? second;
+};
+
+struct EmptyStruct {
+};
+
+// Used to verify that struct fields which don't specify a deafult are
+// initialized to: false for bool, 0 for numbers, and null for strings,
+// handles, and structs. The "?" nullable suffix shouldn't have any 
+// impact on initial field values.
+
+struct NoDefaultFieldValues {
+  bool f0;
+  int8 f1;
+  uint8 f2;
+  int16 f3;
+  uint16 f4;
+  int32 f5;
+  uint32 f6;
+  int64 f7;
+  uint64 f8;
+  float f9;
+  double f10;
+  string f11;
+  string? f12;
+  handle<message_pipe> f13;
+  handle<data_pipe_consumer> f14;
+  handle<data_pipe_producer> f15;
+  handle<message_pipe>? f16;
+  handle<data_pipe_consumer>? f17;
+  handle<data_pipe_producer>? f18;
+  handle f19;
+  handle? f20;
+  handle<shared_buffer> f21;
+  handle<shared_buffer>? f22;
+  array<string> f23;
+  array<string?> f24;
+  array<string>? f25;
+  array<string?>? f26;
+  EmptyStruct f27;
+  EmptyStruct? f28;
+};
+
+// Used to verify that struct fields with an explicit default value
+// are initialized correctly. The "?" nullable suffix shouldn't have any 
+// impact on initial field values.
+
+struct DefaultFieldValues {
+  const string kFoo = "foo";
+  bool f0 = true;
+  int8 f1 = 100;
+  uint8 f2 = 100;
+  int16 f3 = 100;
+  uint16 f4 = 100;
+  int32 f5 = 100;
+  uint32 f6 = 100;
+  int64 f7 = 100;
+  uint64 f8 = 100;
+  float f9 = 100;
+  float f10 = 100.0;
+  double f11 = 100;
+  double f12 = 100.0;
+  string f13 = kFoo;
+  string? f14 = kFoo;
+  Rect f15 = default;
+  Rect? f16 = default;
+};
+
+}
diff --git a/mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom b/mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom
new file mode 100644
index 0000000..5cd9d0b
--- /dev/null
+++ b/mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom
@@ -0,0 +1,61 @@
+// Copyright 2014 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.
+
+
+[JavaPackage="org.chromium.mojo.bindings.test.mojom.mojo"]
+module mojo.test {
+
+struct StructA {
+  uint64 i;
+};
+
+struct StructB {
+  StructA struct_a;
+};
+
+struct StructC {
+  array<uint8> data;
+};
+
+struct StructD {
+  array<handle<message_pipe>> message_pipes;
+};
+
+struct StructE {
+  StructD struct_d;
+  handle<data_pipe_consumer> data_pipe_consumer;
+};
+
+struct StructF {
+  array<uint8, 3> fixed_size_array;
+};
+
+interface ConformanceTestInterface {
+  Method0(float param0);
+  Method1(StructA param0);
+  Method2(StructB param0, StructA param1);
+  Method3(array<bool> param0);
+  Method4(StructC param0, array<uint8> param1);
+  Method5(StructE param0, handle<data_pipe_producer> param1);
+  Method6(array<array<uint8>> param0);
+  Method7(StructF param0, array<uint8, 5> param1);
+  Method8(array<array<string>?> param0);
+  Method9(array<array<handle?>>? param0);
+};
+
+struct BasicStruct {
+  int32 a;
+};
+
+[Client=IntegrationTestInterface2]
+interface IntegrationTestInterface1 {
+  Method0(BasicStruct param0);
+};
+
+[Client=IntegrationTestInterface1]
+interface IntegrationTestInterface2 {
+  Method0() => (array<uint8> param0);
+};
+
+}
diff --git a/mojo/public/java/BUILD.gn b/mojo/public/java/BUILD.gn
new file mode 100644
index 0000000..6f5d8e9
--- /dev/null
+++ b/mojo/public/java/BUILD.gn
@@ -0,0 +1,53 @@
+# Copyright 2014 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.
+
+import("//build/config/android/rules.gni")
+ 
+android_library("system") {
+  java_files = [
+    "system/src/org/chromium/mojo/system/AsyncWaiter.java",
+    "system/src/org/chromium/mojo/system/Core.java",
+    "system/src/org/chromium/mojo/system/DataPipe.java",
+    "system/src/org/chromium/mojo/system/Flags.java",
+    "system/src/org/chromium/mojo/system/Handle.java",
+    "system/src/org/chromium/mojo/system/InvalidHandle.java",
+    "system/src/org/chromium/mojo/system/MessagePipeHandle.java",
+    "system/src/org/chromium/mojo/system/MojoException.java",
+    "system/src/org/chromium/mojo/system/MojoResult.java",
+    "system/src/org/chromium/mojo/system/Pair.java",
+    "system/src/org/chromium/mojo/system/SharedBufferHandle.java",
+    "system/src/org/chromium/mojo/system/UntypedHandle.java",
+  ]
+}
+
+android_library("bindings") {
+  java_files = [
+    "bindings/src/org/chromium/mojo/bindings/AutoCloseableRouter.java",
+    "bindings/src/org/chromium/mojo/bindings/BindingsHelper.java",
+    "bindings/src/org/chromium/mojo/bindings/Callbacks.java",
+    "bindings/src/org/chromium/mojo/bindings/ConnectionErrorHandler.java",
+    "bindings/src/org/chromium/mojo/bindings/Connector.java",
+    "bindings/src/org/chromium/mojo/bindings/Decoder.java",
+    "bindings/src/org/chromium/mojo/bindings/DelegatingConnectionErrorHandler.java",
+    "bindings/src/org/chromium/mojo/bindings/DeserializationException.java",
+    "bindings/src/org/chromium/mojo/bindings/Encoder.java",
+    "bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java",
+    "bindings/src/org/chromium/mojo/bindings/HandleOwner.java",
+    "bindings/src/org/chromium/mojo/bindings/Interface.java",
+    "bindings/src/org/chromium/mojo/bindings/InterfaceRequest.java",
+    "bindings/src/org/chromium/mojo/bindings/InterfaceWithClient.java",
+    "bindings/src/org/chromium/mojo/bindings/MessageHeader.java",
+    "bindings/src/org/chromium/mojo/bindings/Message.java",
+    "bindings/src/org/chromium/mojo/bindings/MessageReceiver.java",
+    "bindings/src/org/chromium/mojo/bindings/MessageReceiverWithResponder.java",
+    "bindings/src/org/chromium/mojo/bindings/RouterImpl.java",
+    "bindings/src/org/chromium/mojo/bindings/Router.java",
+    "bindings/src/org/chromium/mojo/bindings/SerializationException.java",
+    "bindings/src/org/chromium/mojo/bindings/ServiceMessage.java",
+    "bindings/src/org/chromium/mojo/bindings/SideEffectFreeCloseable.java",
+    "bindings/src/org/chromium/mojo/bindings/Struct.java",
+  ]
+
+  deps = [ ":system" ]
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/AutoCloseableRouter.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/AutoCloseableRouter.java
new file mode 100644
index 0000000..8a83be9
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/AutoCloseableRouter.java
@@ -0,0 +1,116 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.Core;
+import org.chromium.mojo.system.MessagePipeHandle;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Wrapper around {@link Router} that will close the connection when not referenced anymore.
+ */
+class AutoCloseableRouter implements Router {
+
+    /**
+     * The underlying router.
+     */
+    private final Router mRouter;
+
+    /**
+     * The executor to close the underlying router.
+     */
+    private final Executor mExecutor;
+
+    /**
+     * Flags to keep track if this router has been correctly closed.
+     */
+    private boolean mClosed;
+
+    /**
+     * Constructor.
+     */
+    public AutoCloseableRouter(Core core, Router router) {
+        mRouter = router;
+        mExecutor = ExecutorFactory.getExecutorForCurrentThread(core);
+    }
+
+    /**
+     * @see Router#setIncomingMessageReceiver(MessageReceiverWithResponder)
+     */
+    @Override
+    public void setIncomingMessageReceiver(MessageReceiverWithResponder incomingMessageReceiver) {
+        mRouter.setIncomingMessageReceiver(incomingMessageReceiver);
+    }
+
+    /**
+     * @see HandleOwner#passHandle()
+     */
+    @Override
+    public MessagePipeHandle passHandle() {
+        return mRouter.passHandle();
+    }
+
+    /**
+     * @see MessageReceiver#accept(Message)
+     */
+    @Override
+    public boolean accept(Message message) {
+        return mRouter.accept(message);
+    }
+
+    /**
+     * @see MessageReceiverWithResponder#acceptWithResponder(Message, MessageReceiver)
+     */
+    @Override
+    public boolean acceptWithResponder(Message message, MessageReceiver responder) {
+        return mRouter.acceptWithResponder(message, responder);
+
+    }
+
+    /**
+     * @see Router#start()
+     */
+    @Override
+    public void start() {
+        mRouter.start();
+    }
+
+    /**
+     * @see Router#setErrorHandler(ConnectionErrorHandler)
+     */
+    @Override
+    public void setErrorHandler(ConnectionErrorHandler errorHandler) {
+        mRouter.setErrorHandler(errorHandler);
+    }
+
+    /**
+     * @see java.io.Closeable#close()
+     */
+    @Override
+    public void close() {
+        mRouter.close();
+        mClosed = true;
+    }
+
+    /**
+     * @see Object#finalize()
+     */
+    @Override
+    protected void finalize() throws Throwable {
+        if (!mClosed) {
+            mExecutor.execute(new Runnable() {
+
+                @Override
+                public void run() {
+                    close();
+                }
+            });
+            throw new IllegalStateException("Warning: Router objects should be explicitly closed " +
+                    "when no longer required otherwise you may leak handles.");
+        }
+        super.finalize();
+    }
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/BindingsHelper.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/BindingsHelper.java
new file mode 100644
index 0000000..b18e5c5
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/BindingsHelper.java
@@ -0,0 +1,127 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.AsyncWaiter;
+import org.chromium.mojo.system.Handle;
+
+/**
+ * Helper functions.
+ */
+public class BindingsHelper {
+    /**
+     * Alignment in bytes for mojo serialization.
+     */
+    public static final int ALIGNMENT = 8;
+
+    /**
+     * The size, in bytes, of a serialized handle. A handle is serialized as an int representing the
+     * offset of the handle in the list of handles.
+     */
+    public static final int SERIALIZED_HANDLE_SIZE = 4;
+
+    /**
+     * The size, in bytes, of a serialized pointer. A pointer is serializaed as an unsigned long
+     * representing the offset from its position to the pointed elemnt.
+     */
+    public static final int POINTER_SIZE = 8;
+
+    /**
+     * The value used for the expected length of a non-fixed size array.
+     */
+    public static final int UNSPECIFIED_ARRAY_LENGTH = -1;
+
+    /**
+     * Align |size| on {@link BindingsHelper#ALIGNMENT}.
+     */
+    public static int align(int size) {
+        return (size + ALIGNMENT - 1) & ~(ALIGNMENT - 1);
+    }
+
+    /**
+     * Passed as |arrayNullability| when neither the array nor its elements are nullable.
+     */
+    public static final int NOTHING_NULLABLE = 0;
+
+    /**
+     * "Array bit" of |arrayNullability| is set iff the array itself is nullable.
+     */
+    public static final int ARRAY_NULLABLE = (1 << 0);
+
+    /**
+     * "Element bit" of |arrayNullability| is set iff the array elements are nullable.
+     */
+    public static final int ELEMENT_NULLABLE = (1 << 1);
+
+    public static boolean isArrayNullable(int arrayNullability) {
+        return (arrayNullability & ARRAY_NULLABLE) > 0;
+    }
+
+    public static boolean isElementNullable(int arrayNullability) {
+        return (arrayNullability & ELEMENT_NULLABLE) > 0;
+    }
+
+    /**
+     * Align |size| on {@link BindingsHelper#ALIGNMENT}.
+     */
+    public static long align(long size) {
+        return (size + ALIGNMENT - 1) & ~(ALIGNMENT - 1);
+    }
+
+    /**
+     * Compute the size in bytes of the given string encoded as utf8.
+     */
+    public static int utf8StringSizeInBytes(String s) {
+        int res = 0;
+        for (int i = 0; i < s.length(); ++i) {
+            char c = s.charAt(i);
+            int codepoint = c;
+            if (isSurrogate(c)) {
+                i++;
+                char c2 = s.charAt(i);
+                codepoint = Character.toCodePoint(c, c2);
+            }
+            res += 1;
+            if (codepoint > 0x7f) {
+                res += 1;
+                if (codepoint > 0x7ff) {
+                    res += 1;
+                    if (codepoint > 0xffff) {
+                        res += 1;
+                        if (codepoint > 0x1fffff) {
+                            res += 1;
+                            if (codepoint > 0x3ffffff) {
+                                res += 1;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return res;
+    }
+
+    /**
+     * Determines if the given {@code char} value is a Unicode <i>surrogate code unit</i>. See
+     * {@link Character#isSurrogate}. Extracting here because the method only exists at API level
+     * 19.
+     */
+    private static boolean isSurrogate(char c) {
+        return c >= Character.MIN_SURROGATE && c < (Character.MAX_SURROGATE + 1);
+    }
+
+    /**
+     * Returns an {@link AsyncWaiter} to use with the given handle, or <code>null</code> if none if
+     * available.
+     */
+    static AsyncWaiter getDefaultAsyncWaiterForHandle(Handle handle) {
+        if (handle.getCore() != null) {
+            return handle.getCore().getDefaultAsyncWaiter();
+        } else {
+            return null;
+        }
+    }
+
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Callbacks.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Callbacks.java
new file mode 100644
index 0000000..c6b14c1
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Callbacks.java
@@ -0,0 +1,130 @@
+// Copyright 2014 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 was generated using
+//     mojo/tools/generate_java_callback_interfaces.py
+
+package org.chromium.mojo.bindings;
+
+/**
+ * Contains a generic interface for callbacks.
+ */
+public interface Callbacks {
+
+    /**
+     * A generic callback.
+     */
+    interface Callback0 {
+        /**
+         * Call the callback.
+         */
+        public void call();
+    }
+
+    /**
+     * A generic 1-argument callback.
+     *
+     * @param <T1> the type of argument 1.
+     */
+    interface Callback1<T1> {
+        /**
+         * Call the callback.
+         */
+        public void call(T1 arg1);
+    }
+
+    /**
+     * A generic 2-argument callback.
+     *
+     * @param <T1> the type of argument 1.
+      * @param <T2> the type of argument 2.
+     */
+    interface Callback2<T1, T2> {
+        /**
+         * Call the callback.
+         */
+        public void call(T1 arg1, T2 arg2);
+    }
+
+    /**
+     * A generic 3-argument callback.
+     *
+     * @param <T1> the type of argument 1.
+      * @param <T2> the type of argument 2.
+      * @param <T3> the type of argument 3.
+     */
+    interface Callback3<T1, T2, T3> {
+        /**
+         * Call the callback.
+         */
+        public void call(T1 arg1, T2 arg2, T3 arg3);
+    }
+
+    /**
+     * A generic 4-argument callback.
+     *
+     * @param <T1> the type of argument 1.
+      * @param <T2> the type of argument 2.
+      * @param <T3> the type of argument 3.
+      * @param <T4> the type of argument 4.
+     */
+    interface Callback4<T1, T2, T3, T4> {
+        /**
+         * Call the callback.
+         */
+        public void call(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
+    }
+
+    /**
+     * A generic 5-argument callback.
+     *
+     * @param <T1> the type of argument 1.
+      * @param <T2> the type of argument 2.
+      * @param <T3> the type of argument 3.
+      * @param <T4> the type of argument 4.
+      * @param <T5> the type of argument 5.
+     */
+    interface Callback5<T1, T2, T3, T4, T5> {
+        /**
+         * Call the callback.
+         */
+        public void call(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
+    }
+
+    /**
+     * A generic 6-argument callback.
+     *
+     * @param <T1> the type of argument 1.
+      * @param <T2> the type of argument 2.
+      * @param <T3> the type of argument 3.
+      * @param <T4> the type of argument 4.
+      * @param <T5> the type of argument 5.
+      * @param <T6> the type of argument 6.
+     */
+    interface Callback6<T1, T2, T3, T4, T5, T6> {
+        /**
+         * Call the callback.
+         */
+        public void call(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
+    }
+
+    /**
+     * A generic 7-argument callback.
+     *
+     * @param <T1> the type of argument 1.
+      * @param <T2> the type of argument 2.
+      * @param <T3> the type of argument 3.
+      * @param <T4> the type of argument 4.
+      * @param <T5> the type of argument 5.
+      * @param <T6> the type of argument 6.
+      * @param <T7> the type of argument 7.
+     */
+    interface Callback7<T1, T2, T3, T4, T5, T6, T7> {
+        /**
+         * Call the callback.
+         */
+        public void call(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
+    }
+
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ConnectionErrorHandler.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ConnectionErrorHandler.java
new file mode 100644
index 0000000..abb0bdf
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ConnectionErrorHandler.java
@@ -0,0 +1,15 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.MojoException;
+
+/**
+ * A {@link ConnectionErrorHandler} is notified of an error happening while using the bindings over
+ * message pipes.
+ */
+interface ConnectionErrorHandler {
+    public void onConnectionError(MojoException e);
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java
new file mode 100644
index 0000000..cbb1924
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java
@@ -0,0 +1,241 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.AsyncWaiter;
+import org.chromium.mojo.system.Core;
+import org.chromium.mojo.system.MessagePipeHandle;
+import org.chromium.mojo.system.MessagePipeHandle.ReadMessageResult;
+import org.chromium.mojo.system.MojoException;
+import org.chromium.mojo.system.MojoResult;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A {@link Connector} owns a {@link MessagePipeHandle} and will send any received messages to the
+ * registered {@link MessageReceiver}. It also acts as a {@link MessageReceiver} and will send any
+ * message through the handle.
+ * <p>
+ * The method |start| must be called before the {@link Connector} will start listening to incoming
+ * messages.
+ */
+public class Connector implements MessageReceiver, HandleOwner<MessagePipeHandle> {
+
+    /**
+     * The callback that is notified when the state of the owned handle changes.
+     */
+    private final AsyncWaiterCallback mAsyncWaiterCallback = new AsyncWaiterCallback();
+
+    /**
+     * The owned message pipe.
+     */
+    private final MessagePipeHandle mMessagePipeHandle;
+
+    /**
+     * A waiter which is notified when a new message is available on the owned message pipe.
+     */
+    private final AsyncWaiter mAsyncWaiter;
+
+    /**
+     * The {@link MessageReceiver} to which received messages are sent.
+     */
+    private MessageReceiver mIncomingMessageReceiver;
+
+    /**
+     * The Cancellable for the current wait. Is |null| when not currently waiting for new messages.
+     */
+    private AsyncWaiter.Cancellable mCancellable;
+
+    /**
+     * The error handler to notify of errors.
+     */
+    private ConnectionErrorHandler mErrorHandler;
+
+    /**
+     * Create a new connector over a |messagePipeHandle|. The created connector will use the default
+     * {@link AsyncWaiter} from the {@link Core} implementation of |messagePipeHandle|.
+     */
+    public Connector(MessagePipeHandle messagePipeHandle) {
+        this(messagePipeHandle, BindingsHelper.getDefaultAsyncWaiterForHandle(messagePipeHandle));
+    }
+
+    /**
+     * Create a new connector over a |messagePipeHandle| using the given {@link AsyncWaiter} to get
+     * notified of changes on the handle.
+     */
+    public Connector(MessagePipeHandle messagePipeHandle, AsyncWaiter asyncWaiter) {
+        mCancellable = null;
+        mMessagePipeHandle = messagePipeHandle;
+        mAsyncWaiter = asyncWaiter;
+    }
+
+    /**
+     * Set the {@link MessageReceiver} that will receive message from the owned message pipe.
+     */
+    public void setIncomingMessageReceiver(MessageReceiver incomingMessageReceiver) {
+        mIncomingMessageReceiver = incomingMessageReceiver;
+    }
+
+    /**
+     * Set the {@link ConnectionErrorHandler} that will be notified of errors on the owned message
+     * pipe.
+     */
+    public void setErrorHandler(ConnectionErrorHandler errorHandler) {
+        mErrorHandler = errorHandler;
+    }
+
+    /**
+     * Start listening for incoming messages.
+     */
+    public void start() {
+        assert mCancellable == null;
+        registerAsyncWaiterForRead();
+    }
+
+    /**
+     * @see MessageReceiver#accept(Message)
+     */
+    @Override
+    public boolean accept(Message message) {
+        try {
+            mMessagePipeHandle.writeMessage(message.getData(),
+                    message.getHandles(), MessagePipeHandle.WriteFlags.NONE);
+            return true;
+        } catch (MojoException e) {
+            onError(e);
+            return false;
+        }
+    }
+
+    /**
+     * Pass the owned handle of the connector. After this, the connector is disconnected. It cannot
+     * accept new message and it isn't listening to the handle anymore.
+     *
+     * @see org.chromium.mojo.bindings.HandleOwner#passHandle()
+     */
+    @Override
+    public MessagePipeHandle passHandle() {
+        cancelIfActive();
+        MessagePipeHandle handle = mMessagePipeHandle.pass();
+        if (mIncomingMessageReceiver != null) {
+            mIncomingMessageReceiver.close();
+        }
+        return handle;
+    }
+
+    /**
+     * @see java.io.Closeable#close()
+     */
+    @Override
+    public void close() {
+        cancelIfActive();
+        mMessagePipeHandle.close();
+        if (mIncomingMessageReceiver != null) {
+            mIncomingMessageReceiver.close();
+        }
+    }
+
+    private class AsyncWaiterCallback implements AsyncWaiter.Callback {
+
+        /**
+         * @see org.chromium.mojo.system.AsyncWaiter.Callback#onResult(int)
+         */
+        @Override
+        public void onResult(int result) {
+            Connector.this.onAsyncWaiterResult(result);
+        }
+
+        /**
+         * @see org.chromium.mojo.system.AsyncWaiter.Callback#onError(MojoException)
+         */
+        @Override
+        public void onError(MojoException exception) {
+            Connector.this.onError(exception);
+        }
+
+    }
+
+    /**
+     * @see org.chromium.mojo.system.AsyncWaiter.Callback#onResult(int)
+     */
+    private void onAsyncWaiterResult(int result) {
+        mCancellable = null;
+        if (result == MojoResult.OK) {
+            readOutstandingMessages();
+        } else {
+            onError(new MojoException(result));
+        }
+    }
+
+    private void onError(MojoException exception) {
+        mCancellable = null;
+        close();
+        if (mErrorHandler != null) {
+            mErrorHandler.onConnectionError(exception);
+        }
+    }
+
+    /**
+     * Register to be called back when a new message is available on the owned message pipe.
+     */
+    private void registerAsyncWaiterForRead() {
+        assert mCancellable == null;
+        if (mAsyncWaiter != null) {
+            mCancellable = mAsyncWaiter.asyncWait(mMessagePipeHandle, Core.HandleSignals.READABLE,
+                    Core.DEADLINE_INFINITE, mAsyncWaiterCallback);
+        } else {
+            onError(new MojoException(MojoResult.INVALID_ARGUMENT));
+        }
+    }
+
+    /**
+     * Read all available messages on the owned message pipe.
+     */
+    private void readOutstandingMessages() {
+        int result;
+        do {
+            try {
+                result = readAndDispatchMessage(mMessagePipeHandle, mIncomingMessageReceiver);
+            } catch (MojoException e) {
+                onError(e);
+                return;
+            }
+        } while (result == MojoResult.OK);
+        if (result == MojoResult.SHOULD_WAIT) {
+            registerAsyncWaiterForRead();
+        } else {
+            onError(new MojoException(result));
+        }
+    }
+
+    private void cancelIfActive() {
+        if (mCancellable != null) {
+            mCancellable.cancel();
+            mCancellable = null;
+        }
+    }
+
+    /**
+     * Read a message, and pass it to the given |MessageReceiver| if not null. If the
+     * |MessageReceiver| is null, the message is lost.
+     *
+     * @param receiver The {@link MessageReceiver} that will receive the read {@link Message}. Can
+     *            be <code>null</code>, in which case the message is discarded.
+     */
+    static int readAndDispatchMessage(MessagePipeHandle handle, MessageReceiver receiver) {
+        // TODO(qsr) Allow usage of a pool of pre-allocated buffer for performance.
+        ReadMessageResult result = handle.readMessage(null, 0, MessagePipeHandle.ReadFlags.NONE);
+        if (result.getMojoResult() != MojoResult.RESOURCE_EXHAUSTED) {
+            return result.getMojoResult();
+        }
+        ByteBuffer buffer = ByteBuffer.allocateDirect(result.getMessageSize());
+        result = handle.readMessage(buffer, result.getHandlesCount(),
+                MessagePipeHandle.ReadFlags.NONE);
+        if (receiver != null && result.getMojoResult() == MojoResult.OK) {
+            receiver.accept(new Message(buffer, result.getHandles()));
+        }
+        return result.getMojoResult();
+    }
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java
new file mode 100644
index 0000000..efb9842
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java
@@ -0,0 +1,630 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.bindings.Interface.Proxy;
+import org.chromium.mojo.bindings.Struct.DataHeader;
+import org.chromium.mojo.system.DataPipe;
+import org.chromium.mojo.system.Handle;
+import org.chromium.mojo.system.InvalidHandle;
+import org.chromium.mojo.system.MessagePipeHandle;
+import org.chromium.mojo.system.SharedBufferHandle;
+import org.chromium.mojo.system.UntypedHandle;
+
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+/**
+ * A Decoder is a helper class for deserializing a mojo struct. It enables deserialization of basic
+ * types from a {@link Message} object at a given offset into it's byte buffer.
+ */
+public class Decoder {
+
+    /**
+     * Helper class to validate the decoded message.
+     */
+    static final class Validator {
+
+        /**
+         * Minimal value for the next handle to deserialize.
+         */
+        private int mMinNextClaimedHandle = 0;
+        /**
+         * Minimal value of the start of the next memory to claim.
+         */
+        private long mMinNextMemory = 0;
+
+        /**
+         * The maximal memory accessible.
+         */
+        private final long mMaxMemory;
+
+        /**
+         * The number of handles in the message.
+         */
+        private final long mNumberOfHandles;
+
+        /**
+         * Constructor.
+         */
+        Validator(long maxMemory, int numberOfHandles) {
+            mMaxMemory = maxMemory;
+            mNumberOfHandles = numberOfHandles;
+        }
+
+        public void claimHandle(int handle) {
+            if (handle < mMinNextClaimedHandle) {
+                throw new DeserializationException(
+                        "Trying to access handle out of order.");
+            }
+            if (handle >= mNumberOfHandles) {
+                throw new DeserializationException("Trying to access non present handle.");
+            }
+            mMinNextClaimedHandle = handle + 1;
+        }
+
+        public void claimMemory(long start, long end) {
+            if (start % BindingsHelper.ALIGNMENT != 0) {
+                throw new DeserializationException("Incorrect starting alignment: " + start + ".");
+            }
+            if (start < mMinNextMemory) {
+                throw new DeserializationException("Trying to access memory out of order.");
+            }
+            if (end < start) {
+                throw new DeserializationException("Incorrect memory range.");
+            }
+            if (end > mMaxMemory) {
+                throw new DeserializationException("Trying to access out of range memory.");
+            }
+            mMinNextMemory = BindingsHelper.align(end);
+        }
+    }
+
+    /**
+     * The message to deserialize from.
+     */
+    private final Message mMessage;
+
+    /**
+     * The base offset in the byte buffer.
+     */
+    private final int mBaseOffset;
+
+    /**
+     * Validator for the decoded message.
+     */
+    private final Validator mValidator;
+
+    /**
+     * Constructor.
+     *
+     * @param message The message to decode.
+     */
+    public Decoder(Message message) {
+        this(message, new Validator(message.getData().limit(), message.getHandles().size()), 0);
+    }
+
+    private Decoder(Message message, Validator validator, int baseOffset) {
+        mMessage = message;
+        mMessage.getData().order(ByteOrder.nativeOrder());
+        mBaseOffset = baseOffset;
+        mValidator = validator;
+    }
+
+    /**
+     * Deserializes a {@link DataHeader} at the given offset.
+     */
+    public DataHeader readDataHeader() {
+        // Claim the memory for the header.
+        mValidator.claimMemory(mBaseOffset, mBaseOffset + DataHeader.HEADER_SIZE);
+        int size = readInt(DataHeader.SIZE_OFFSET);
+        int numFields = readInt(DataHeader.NUM_FIELDS_OFFSET);
+        if (size < 0) {
+            throw new DeserializationException(
+                    "Negative size. Unsigned integers are not valid for java.");
+        }
+        if (numFields < 0) {
+            throw new DeserializationException(
+                    "Negative number of fields. Unsigned integers are not valid for java.");
+        }
+
+        // Claim the remaining memory.
+        mValidator.claimMemory(mBaseOffset + DataHeader.HEADER_SIZE, mBaseOffset + size);
+        DataHeader res = new DataHeader(size, numFields);
+        return res;
+    }
+
+    /**
+     * Deserializes a {@link DataHeader} at the given offset and checks if it is correct for an
+     * array where element have the given size.
+     */
+    public DataHeader readDataHeaderForPointerArray(int expectedLength) {
+        return readDataHeaderForArray(8, expectedLength);
+    }
+
+    /**
+     * Deserializes a byte at the given offset.
+     */
+    public byte readByte(int offset) {
+        validateBufferSize(offset, 1);
+        return mMessage.getData().get(mBaseOffset + offset);
+    }
+
+    /**
+     * Deserializes a boolean at the given offset, re-using any partially read byte.
+     */
+    public boolean readBoolean(int offset, int bit) {
+        validateBufferSize(offset, 1);
+        return (readByte(offset) & (1 << bit)) != 0;
+    }
+
+    /**
+     * Deserializes a short at the given offset.
+     */
+    public short readShort(int offset) {
+        validateBufferSize(offset, 2);
+        return mMessage.getData().getShort(mBaseOffset + offset);
+    }
+
+    /**
+     * Deserializes an int at the given offset.
+     */
+    public int readInt(int offset) {
+        validateBufferSize(offset, 4);
+        return mMessage.getData().getInt(mBaseOffset + offset);
+    }
+
+    /**
+     * Deserializes a float at the given offset.
+     */
+    public float readFloat(int offset) {
+        validateBufferSize(offset, 4);
+        return mMessage.getData().getFloat(mBaseOffset + offset);
+    }
+
+    /**
+     * Deserializes a long at the given offset.
+     */
+    public long readLong(int offset) {
+        validateBufferSize(offset, 8);
+        return mMessage.getData().getLong(mBaseOffset + offset);
+    }
+
+    /**
+     * Deserializes a double at the given offset.
+     */
+    public double readDouble(int offset) {
+        validateBufferSize(offset, 8);
+        return mMessage.getData().getDouble(mBaseOffset + offset);
+    }
+
+    /**
+     * Deserializes a pointer at the given offset. Returns a Decoder suitable to decode the content
+     * of the pointer.
+     */
+    public Decoder readPointer(int offset, boolean nullable) {
+        int basePosition = mBaseOffset + offset;
+        long pointerOffset = readLong(offset);
+        if (pointerOffset == 0) {
+            if (!nullable) {
+                throw new DeserializationException(
+                        "Trying to decode null pointer for a non-nullable type.");
+            }
+            return null;
+        }
+        int newPosition = (int) (basePosition + pointerOffset);
+        // The method |getDecoderAtPosition| will validate that the pointer address is valid.
+        return getDecoderAtPosition(newPosition);
+
+    }
+
+    /**
+     * Deserializes an array of boolean at the given offset.
+     */
+    public boolean[] readBooleans(int offset, int arrayNullability, int expectedLength) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForBooleanArray(expectedLength);
+        byte[] bytes = new byte[(si.numFields + 7) / BindingsHelper.ALIGNMENT];
+        d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE);
+        d.mMessage.getData().get(bytes);
+        boolean[] result = new boolean[si.numFields];
+        for (int i = 0; i < bytes.length; ++i) {
+            for (int j = 0; j < BindingsHelper.ALIGNMENT; ++j) {
+                int booleanIndex = i * BindingsHelper.ALIGNMENT + j;
+                if (booleanIndex < result.length) {
+                    result[booleanIndex] = (bytes[i] & (1 << j)) != 0;
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Deserializes an array of bytes at the given offset.
+     */
+    public byte[] readBytes(int offset, int arrayNullability, int expectedLength) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForArray(1, expectedLength);
+        byte[] result = new byte[si.numFields];
+        d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE);
+        d.mMessage.getData().get(result);
+        return result;
+    }
+
+    /**
+     * Deserializes an array of shorts at the given offset.
+     */
+    public short[] readShorts(int offset, int arrayNullability, int expectedLength) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForArray(2, expectedLength);
+        short[] result = new short[si.numFields];
+        d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE);
+        d.mMessage.getData().asShortBuffer().get(result);
+        return result;
+    }
+
+    /**
+     * Deserializes an array of ints at the given offset.
+     */
+    public int[] readInts(int offset, int arrayNullability, int expectedLength) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForArray(4, expectedLength);
+        int[] result = new int[si.numFields];
+        d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE);
+        d.mMessage.getData().asIntBuffer().get(result);
+        return result;
+    }
+
+    /**
+     * Deserializes an array of floats at the given offset.
+     */
+    public float[] readFloats(int offset, int arrayNullability, int expectedLength) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForArray(4, expectedLength);
+        float[] result = new float[si.numFields];
+        d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE);
+        d.mMessage.getData().asFloatBuffer().get(result);
+        return result;
+    }
+
+    /**
+     * Deserializes an array of longs at the given offset.
+     */
+    public long[] readLongs(int offset, int arrayNullability, int expectedLength) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForArray(8, expectedLength);
+        long[] result = new long[si.numFields];
+        d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE);
+        d.mMessage.getData().asLongBuffer().get(result);
+        return result;
+    }
+
+    /**
+     * Deserializes an array of doubles at the given offset.
+     */
+    public double[] readDoubles(int offset, int arrayNullability, int expectedLength) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForArray(8, expectedLength);
+        double[] result = new double[si.numFields];
+        d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE);
+        d.mMessage.getData().asDoubleBuffer().get(result);
+        return result;
+    }
+
+    /**
+     * Deserializes an |Handle| at the given offset.
+     */
+    public Handle readHandle(int offset, boolean nullable) {
+        int index = readInt(offset);
+        if (index == -1) {
+            if (!nullable) {
+                throw new DeserializationException(
+                        "Trying to decode an invalid handle for a non-nullable type.");
+            }
+            return InvalidHandle.INSTANCE;
+        }
+        mValidator.claimHandle(index);
+        return mMessage.getHandles().get(index);
+    }
+
+    /**
+     * Deserializes an |UntypedHandle| at the given offset.
+     */
+    public UntypedHandle readUntypedHandle(int offset, boolean nullable) {
+        return readHandle(offset, nullable).toUntypedHandle();
+    }
+
+    /**
+     * Deserializes a |ConsumerHandle| at the given offset.
+     */
+    public DataPipe.ConsumerHandle readConsumerHandle(int offset, boolean nullable) {
+        return readUntypedHandle(offset, nullable).toDataPipeConsumerHandle();
+    }
+
+    /**
+     * Deserializes a |ProducerHandle| at the given offset.
+     */
+    public DataPipe.ProducerHandle readProducerHandle(int offset, boolean nullable) {
+        return readUntypedHandle(offset, nullable).toDataPipeProducerHandle();
+    }
+
+    /**
+     * Deserializes a |MessagePipeHandle| at the given offset.
+     */
+    public MessagePipeHandle readMessagePipeHandle(int offset, boolean nullable) {
+        return readUntypedHandle(offset, nullable).toMessagePipeHandle();
+    }
+
+    /**
+     * Deserializes a |SharedBufferHandle| at the given offset.
+     */
+    public SharedBufferHandle readSharedBufferHandle(int offset, boolean nullable) {
+        return readUntypedHandle(offset, nullable).toSharedBufferHandle();
+    }
+
+    /**
+     * Deserializes an interface at the given offset.
+     *
+     * @return a proxy to the service.
+     */
+    public <P extends Proxy> P readServiceInterface(int offset, boolean nullable,
+            Interface.Manager<?, P> manager) {
+        MessagePipeHandle handle = readMessagePipeHandle(offset, nullable);
+        if (!handle.isValid()) {
+            return null;
+        }
+        return manager.attachProxy(handle);
+    }
+
+    /**
+     * Deserializes a |InterfaceRequest| at the given offset.
+     */
+    public <I extends Interface> InterfaceRequest<I> readInterfaceRequest(int offset,
+            boolean nullable) {
+        MessagePipeHandle handle = readMessagePipeHandle(offset, nullable);
+        if (handle == null) {
+            return null;
+        }
+        return new InterfaceRequest<I>(handle);
+    }
+
+    /**
+     * Deserializes a string at the given offset.
+     */
+    public String readString(int offset, boolean nullable) {
+        final int arrayNullability = nullable ? BindingsHelper.ARRAY_NULLABLE : 0;
+        byte[] bytes = readBytes(offset, arrayNullability, BindingsHelper.UNSPECIFIED_ARRAY_LENGTH);
+        if (bytes == null) {
+            return null;
+        }
+        return new String(bytes, Charset.forName("utf8"));
+    }
+
+    /**
+     * Deserializes an array of |Handle| at the given offset.
+     */
+    public Handle[] readHandles(int offset, int arrayNullability, int expectedLength) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForArray(4, expectedLength);
+        Handle[] result = new Handle[si.numFields];
+        for (int i = 0; i < result.length; ++i) {
+            result[i] = d.readHandle(
+                    DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
+                    BindingsHelper.isElementNullable(arrayNullability));
+        }
+        return result;
+    }
+
+    /**
+     * Deserializes an array of |UntypedHandle| at the given offset.
+     */
+    public UntypedHandle[] readUntypedHandles(
+            int offset, int arrayNullability, int expectedLength) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForArray(4, expectedLength);
+        UntypedHandle[] result = new UntypedHandle[si.numFields];
+        for (int i = 0; i < result.length; ++i) {
+            result[i] = d.readUntypedHandle(
+                    DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
+                    BindingsHelper.isElementNullable(arrayNullability));
+        }
+        return result;
+    }
+
+    /**
+     * Deserializes an array of |ConsumerHandle| at the given offset.
+     */
+    public DataPipe.ConsumerHandle[] readConsumerHandles(
+            int offset, int arrayNullability, int expectedLength) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForArray(4, expectedLength);
+        DataPipe.ConsumerHandle[] result = new DataPipe.ConsumerHandle[si.numFields];
+        for (int i = 0; i < result.length; ++i) {
+            result[i] = d.readConsumerHandle(
+                    DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
+                    BindingsHelper.isElementNullable(arrayNullability));
+        }
+        return result;
+    }
+
+    /**
+     * Deserializes an array of |ProducerHandle| at the given offset.
+     */
+    public DataPipe.ProducerHandle[] readProducerHandles(
+            int offset, int arrayNullability, int expectedLength) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForArray(4, expectedLength);
+        DataPipe.ProducerHandle[] result = new DataPipe.ProducerHandle[si.numFields];
+        for (int i = 0; i < result.length; ++i) {
+            result[i] = d.readProducerHandle(
+                    DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
+                    BindingsHelper.isElementNullable(arrayNullability));
+        }
+        return result;
+
+    }
+
+    /**
+     * Deserializes an array of |MessagePipeHandle| at the given offset.
+     */
+    public MessagePipeHandle[] readMessagePipeHandles(
+            int offset, int arrayNullability, int expectedLength) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForArray(4, expectedLength);
+        MessagePipeHandle[] result = new MessagePipeHandle[si.numFields];
+        for (int i = 0; i < result.length; ++i) {
+            result[i] = d.readMessagePipeHandle(
+                    DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
+                    BindingsHelper.isElementNullable(arrayNullability));
+        }
+        return result;
+
+    }
+
+    /**
+     * Deserializes an array of |SharedBufferHandle| at the given offset.
+     */
+    public SharedBufferHandle[] readSharedBufferHandles(
+            int offset, int arrayNullability, int expectedLength) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForArray(4, expectedLength);
+        SharedBufferHandle[] result = new SharedBufferHandle[si.numFields];
+        for (int i = 0; i < result.length; ++i) {
+            result[i] = d.readSharedBufferHandle(
+                    DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
+                    BindingsHelper.isElementNullable(arrayNullability));
+        }
+        return result;
+
+    }
+
+    /**
+     * Deserializes an array of |ServiceHandle| at the given offset.
+     */
+    public <S extends Interface, P extends Proxy> S[] readServiceInterfaces(
+            int offset, int arrayNullability, int expectedLength, Interface.Manager<S, P> manager) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForArray(4, expectedLength);
+        S[] result = manager.buildArray(si.numFields);
+        for (int i = 0; i < result.length; ++i) {
+            // This cast is necessary because java 6 doesn't handle wildcard correctly when using
+            // Manager<S, ? extends S>
+            @SuppressWarnings("unchecked")
+            S value = (S) d.readServiceInterface(
+                    DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
+                    BindingsHelper.isElementNullable(arrayNullability), manager);
+            result[i] = value;
+        }
+        return result;
+    }
+
+    /**
+     * Deserializes an array of |InterfaceRequest| at the given offset.
+     */
+    public <I extends Interface> InterfaceRequest<I>[] readInterfaceRequests(
+            int offset, int arrayNullability, int expectedLength) {
+        Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+        if (d == null) {
+            return null;
+        }
+        DataHeader si = d.readDataHeaderForArray(4, expectedLength);
+        @SuppressWarnings("unchecked")
+        InterfaceRequest<I>[] result = new InterfaceRequest[si.numFields];
+        for (int i = 0; i < result.length; ++i) {
+            result[i] = d.readInterfaceRequest(
+                    DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
+                    BindingsHelper.isElementNullable(arrayNullability));
+        }
+        return result;
+    }
+
+    /**
+     * Returns a view of this decoder at the offset |offset|.
+     */
+    private Decoder getDecoderAtPosition(int offset) {
+        return new Decoder(mMessage, mValidator, offset);
+    }
+
+    /**
+     * Deserializes a {@link DataHeader} at the given offset and checks if it is correct for an
+     * array of booleans.
+     */
+    private DataHeader readDataHeaderForBooleanArray(int expectedLength) {
+        DataHeader dataHeader = readDataHeader();
+        if (dataHeader.size < DataHeader.HEADER_SIZE + (dataHeader.numFields + 7) / 8) {
+            throw new DeserializationException("Array header is incorrect.");
+        }
+        if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH
+                && dataHeader.numFields != expectedLength) {
+            throw new DeserializationException("Incorrect array length. Expected: " +
+                    expectedLength + ", but got: " + dataHeader.numFields + ".");
+        }
+        return dataHeader;
+    }
+
+    /**
+     * Deserializes a {@link DataHeader} of an array at the given offset.
+     */
+    private DataHeader readDataHeaderForArray(long elementSize, int expectedLength) {
+        DataHeader dataHeader = readDataHeader();
+        if (dataHeader.size < (DataHeader.HEADER_SIZE + elementSize * dataHeader.numFields)) {
+            throw new DeserializationException("Array header is incorrect.");
+        }
+        if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH
+                && dataHeader.numFields != expectedLength) {
+            throw new DeserializationException("Incorrect array length. Expected: " +
+                    expectedLength + ", but got: " + dataHeader.numFields + ".");
+        }
+        return dataHeader;
+    }
+
+    private void validateBufferSize(int offset, int size) {
+        if (mMessage.getData().limit() < offset + size) {
+            throw new DeserializationException("Buffer is smaller than expected.");
+        }
+    }
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/DelegatingConnectionErrorHandler.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/DelegatingConnectionErrorHandler.java
new file mode 100644
index 0000000..2ee2ae7
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/DelegatingConnectionErrorHandler.java
@@ -0,0 +1,49 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.MojoException;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+/**
+ * A {@link ConnectionErrorHandler} that delegate the errors to a list of registered handlers. This
+ * class will use weak pointers to prevent keeping references to any handlers it delegates to.
+ */
+public class DelegatingConnectionErrorHandler implements ConnectionErrorHandler {
+
+    /**
+     * The registered handlers. This uses a {@link WeakHashMap} so that it doesn't prevent the
+     * handler from being garbage collected.
+     */
+    private final Set<ConnectionErrorHandler> mHandlers =
+            Collections.newSetFromMap(new WeakHashMap<ConnectionErrorHandler, Boolean>());
+
+    /**
+     * @see ConnectionErrorHandler#onConnectionError(MojoException)
+     */
+    @Override
+    public void onConnectionError(MojoException e) {
+        for (ConnectionErrorHandler handler : mHandlers) {
+            handler.onConnectionError(e);
+        }
+    }
+
+    /**
+     * Add a handler that will be notified of any error this object receives.
+     */
+    public void addConnectionErrorHandler(ConnectionErrorHandler handler) {
+        mHandlers.add(handler);
+    }
+
+    /**
+     * Remove a previously registered handler.
+     */
+    public void removeConnectionErrorHandler(ConnectionErrorHandler handler) {
+        mHandlers.remove(handler);
+    }
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/DeserializationException.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/DeserializationException.java
new file mode 100644
index 0000000..eeb511c
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/DeserializationException.java
@@ -0,0 +1,26 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+/**
+ * Error when deserializing a mojo message.
+ */
+public class DeserializationException extends RuntimeException {
+
+    /**
+     * Constructs a new deserialization exception with the specified detail message.
+     */
+    public DeserializationException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new deserialization exception with the specified cause.
+     */
+    public DeserializationException(Exception cause) {
+        super(cause);
+    }
+
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java
new file mode 100644
index 0000000..e3b2bfe
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java
@@ -0,0 +1,518 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.bindings.Struct.DataHeader;
+import org.chromium.mojo.system.Core;
+import org.chromium.mojo.system.Handle;
+import org.chromium.mojo.system.MessagePipeHandle;
+import org.chromium.mojo.system.Pair;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class to encode a mojo struct. It keeps track of the output buffer, resizing it as needed.
+ * It also keeps track of the associated handles, and the offset of the current data section.
+ */
+public class Encoder {
+
+    /**
+     * Container class for all state that must be shared between the main encoder and any used sub
+     * encoder.
+     */
+    private static class EncoderState {
+
+        /**
+         * The core used to encode interfaces.
+         */
+        public final Core core;
+
+        /**
+         * The ByteBuffer to which the message will be encoded.
+         */
+        public ByteBuffer byteBuffer;
+
+        /**
+         * The list of encountered handles.
+         */
+        public final List<Handle> handles = new ArrayList<Handle>();
+
+        /**
+         * The current absolute position for the next data section.
+         */
+        public int dataEnd;
+
+        /**
+         * @param core the |Core| implementation used to generate handles. Only used if the |Struct|
+         *            being encoded contains interfaces, can be |null| otherwise.
+         * @param bufferSize A hint on the size of the message. Used to build the initial byte
+         *            buffer.
+         */
+        private EncoderState(Core core, int bufferSize) {
+            assert bufferSize % BindingsHelper.ALIGNMENT == 0;
+            this.core = core;
+            byteBuffer = ByteBuffer.allocateDirect(
+                    bufferSize > 0 ? bufferSize : INITIAL_BUFFER_SIZE);
+            byteBuffer.order(ByteOrder.nativeOrder());
+            dataEnd = 0;
+        }
+
+        /**
+         * Claim the given amount of memory at the end of the buffer, resizing it if needed.
+         */
+        public void claimMemory(int size) {
+            dataEnd += size;
+            growIfNeeded();
+        }
+
+        /**
+         * Grow the associated ByteBuffer if needed.
+         */
+        private void growIfNeeded() {
+            if (byteBuffer.capacity() >= dataEnd) {
+                return;
+            }
+            int targetSize = byteBuffer.capacity() * 2;
+            while (targetSize < dataEnd) {
+                targetSize *= 2;
+            }
+            ByteBuffer newBuffer = ByteBuffer.allocateDirect(targetSize);
+            newBuffer.order(ByteOrder.nativeOrder());
+            byteBuffer.position(0);
+            byteBuffer.limit(byteBuffer.capacity());
+            newBuffer.put(byteBuffer);
+            byteBuffer = newBuffer;
+        }
+    }
+
+    /**
+     * Default initial size of the data buffer. This must be a multiple of 8 bytes.
+     */
+    private static final int INITIAL_BUFFER_SIZE = 1024;
+
+    /**
+     * Base offset in the byte buffer for writing.
+     */
+    private int mBaseOffset;
+
+    /**
+     * The encoder state shared by the main encoder and all its sub-encoder.
+     */
+    private final EncoderState mEncoderState;
+
+    /**
+     * Returns the result message.
+     */
+    public Message getMessage() {
+        mEncoderState.byteBuffer.position(0);
+        mEncoderState.byteBuffer.limit(mEncoderState.dataEnd);
+        return new Message(mEncoderState.byteBuffer, mEncoderState.handles);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param core the |Core| implementation used to generate handles. Only used if the |Struct|
+     *            being encoded contains interfaces, can be |null| otherwise.
+     * @param sizeHint A hint on the size of the message. Used to build the initial byte buffer.
+     */
+    public Encoder(Core core, int sizeHint) {
+        this(new EncoderState(core, sizeHint));
+    }
+
+    /**
+     * Private constructor for sub-encoders.
+     */
+    private Encoder(EncoderState bufferInformation) {
+        mEncoderState = bufferInformation;
+        mBaseOffset = bufferInformation.dataEnd;
+    }
+
+    /**
+     * Returns a new encoder that will append to the current buffer.
+     */
+    public Encoder getEncoderAtDataOffset(DataHeader dataHeader) {
+        Encoder result = new Encoder(mEncoderState);
+        result.encode(dataHeader);
+        return result;
+    }
+
+    /**
+     * Encode a {@link DataHeader} and claim the amount of memory required for the data section
+     * (resizing the buffer if required).
+     */
+    public void encode(DataHeader s) {
+        mEncoderState.claimMemory(BindingsHelper.align(s.size));
+        encode(s.size, DataHeader.SIZE_OFFSET);
+        encode(s.numFields, DataHeader.NUM_FIELDS_OFFSET);
+    }
+
+    /**
+     * Encode a byte at the given offset.
+     */
+    public void encode(byte v, int offset) {
+        mEncoderState.byteBuffer.put(mBaseOffset + offset, v);
+    }
+
+    /**
+     * Encode a boolean at the given offset.
+     */
+    public void encode(boolean v, int offset, int bit) {
+        if (v) {
+            byte encodedValue = mEncoderState.byteBuffer.get(mBaseOffset + offset);
+            encodedValue |= 1 << bit;
+            mEncoderState.byteBuffer.put(mBaseOffset + offset, encodedValue);
+        }
+    }
+
+    /**
+     * Encode a short at the given offset.
+     */
+    public void encode(short v, int offset) {
+        mEncoderState.byteBuffer.putShort(mBaseOffset + offset, v);
+    }
+
+    /**
+     * Encode an int at the given offset.
+     */
+    public void encode(int v, int offset) {
+        mEncoderState.byteBuffer.putInt(mBaseOffset + offset, v);
+    }
+
+    /**
+     * Encode a float at the given offset.
+     */
+    public void encode(float v, int offset) {
+        mEncoderState.byteBuffer.putFloat(mBaseOffset + offset, v);
+    }
+
+    /**
+     * Encode a long at the given offset.
+     */
+    public void encode(long v, int offset) {
+        mEncoderState.byteBuffer.putLong(mBaseOffset + offset, v);
+    }
+
+    /**
+     * Encode a double at the given offset.
+     */
+    public void encode(double v, int offset) {
+        mEncoderState.byteBuffer.putDouble(mBaseOffset + offset, v);
+    }
+
+    /**
+     * Encode a {@link Struct} at the given offset.
+     */
+    public void encode(Struct v, int offset, boolean nullable) {
+        if (v == null) {
+            encodeNullPointer(offset, nullable);
+            return;
+        }
+        encodePointerToNextUnclaimedData(offset);
+        v.encode(this);
+    }
+
+    /**
+     * Encodes a String.
+     */
+    public void encode(String v, int offset, boolean nullable) {
+        if (v == null) {
+            encodeNullPointer(offset, nullable);
+            return;
+        }
+        final int arrayNullability = nullable ?
+                BindingsHelper.ARRAY_NULLABLE : BindingsHelper.NOTHING_NULLABLE;
+        encode(v.getBytes(Charset.forName("utf8")), offset, arrayNullability,
+                BindingsHelper.UNSPECIFIED_ARRAY_LENGTH);
+    }
+
+    /**
+     * Encodes a {@link Handle}.
+     */
+    public void encode(Handle v, int offset, boolean nullable) {
+        if (v == null || !v.isValid()) {
+            encodeInvalidHandle(offset, nullable);
+        } else {
+            encode(mEncoderState.handles.size(), offset);
+            mEncoderState.handles.add(v);
+        }
+    }
+
+    /**
+     * Encode an {@link Interface}.
+     */
+    public <T extends Interface> void encode(T v, int offset, boolean nullable,
+            Interface.Manager<T, ?> manager) {
+        if (v == null) {
+            encodeInvalidHandle(offset, nullable);
+            return;
+        }
+        if (mEncoderState.core == null) {
+            throw new UnsupportedOperationException(
+                    "The encoder has been created without a Core. It can't encode an interface.");
+        }
+        // If the instance is a proxy, pass the proxy's handle instead of creating a new stub.
+        if (v instanceof Interface.AbstractProxy) {
+            Interface.AbstractProxy proxy = (Interface.AbstractProxy) v;
+            if (proxy.getMessageReceiver() instanceof HandleOwner) {
+                encode(((HandleOwner<?>) proxy.getMessageReceiver()).passHandle(), offset,
+                        nullable);
+                return;
+            }
+            // If the proxy is not over a message pipe, the default case applies.
+        }
+        Pair<MessagePipeHandle, MessagePipeHandle> handles =
+                mEncoderState.core.createMessagePipe(null);
+        manager.bind(v, handles.first);
+        encode(handles.second, offset, nullable);
+    }
+
+    /**
+     * Encode an {@link InterfaceRequest}.
+     */
+    public <I extends Interface> void encode(InterfaceRequest<I> v, int offset, boolean nullable) {
+        if (v == null) {
+            encodeInvalidHandle(offset, nullable);
+            return;
+        }
+        if (mEncoderState.core == null) {
+            throw new UnsupportedOperationException(
+                    "The encoder has been created without a Core. It can't encode an interface.");
+        }
+        encode(v.passHandle(), offset, nullable);
+    }
+
+    /**
+     * Returns an {@link Encoder} suitable for encoding an array of pointer of the given length.
+     */
+    public Encoder encodePointerArray(int length, int offset, int expectedLength) {
+        return encoderForArray(BindingsHelper.POINTER_SIZE, length, offset, expectedLength);
+    }
+
+    /**
+     * Encodes an array of booleans.
+     */
+    public void encode(boolean[] v, int offset, int arrayNullability, int expectedLength) {
+        if (v == null) {
+            encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+            return;
+        }
+        if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH &&
+                expectedLength != v.length) {
+            throw new SerializationException("Trying to encode a fixed array of incorrect length.");
+        }
+        byte[] bytes = new byte[(v.length + 7) / BindingsHelper.ALIGNMENT];
+        for (int i = 0; i < bytes.length; ++i) {
+            for (int j = 0; j < BindingsHelper.ALIGNMENT; ++j) {
+                int booleanIndex = BindingsHelper.ALIGNMENT * i + j;
+                if (booleanIndex < v.length && v[booleanIndex]) {
+                    bytes[i] |= (1 << j);
+                }
+            }
+        }
+        encodeByteArray(bytes, v.length, offset);
+    }
+
+    /**
+     * Encodes an array of bytes.
+     */
+    public void encode(byte[] v, int offset, int arrayNullability, int expectedLength) {
+        if (v == null) {
+            encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+            return;
+        }
+        if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH &&
+                expectedLength != v.length) {
+            throw new SerializationException("Trying to encode a fixed array of incorrect length.");
+        }
+        encodeByteArray(v, v.length, offset);
+    }
+
+    /**
+     * Encodes an array of shorts.
+     */
+    public void encode(short[] v, int offset, int arrayNullability, int expectedLength) {
+        if (v == null) {
+            encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+            return;
+        }
+        encoderForArray(2, v.length, offset, expectedLength).append(v);
+    }
+
+    /**
+     * Encodes an array of ints.
+     */
+    public void encode(int[] v, int offset, int arrayNullability, int expectedLength) {
+        if (v == null) {
+            encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+            return;
+        }
+        encoderForArray(4, v.length, offset, expectedLength).append(v);
+    }
+
+    /**
+     * Encodes an array of floats.
+     */
+    public void encode(float[] v, int offset, int arrayNullability, int expectedLength) {
+        if (v == null) {
+            encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+            return;
+        }
+        encoderForArray(4, v.length, offset, expectedLength).append(v);
+    }
+
+    /**
+     * Encodes an array of longs.
+     */
+    public void encode(long[] v, int offset, int arrayNullability, int expectedLength) {
+        if (v == null) {
+            encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+            return;
+        }
+        encoderForArray(8, v.length, offset, expectedLength).append(v);
+    }
+
+    /**
+     * Encodes an array of doubles.
+     */
+    public void encode(double[] v, int offset, int arrayNullability, int expectedLength) {
+        if (v == null) {
+            encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+            return;
+        }
+        encoderForArray(8, v.length, offset, expectedLength).append(v);
+    }
+
+    /**
+     * Encodes an array of {@link Handle}.
+     */
+    public void encode(Handle[] v, int offset, int arrayNullability, int expectedLength) {
+        if (v == null) {
+            encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+            return;
+        }
+        Encoder e = encoderForArray(
+                BindingsHelper.SERIALIZED_HANDLE_SIZE, v.length, offset, expectedLength);
+        for (int i = 0; i < v.length; ++i) {
+            e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
+                    BindingsHelper.isElementNullable(arrayNullability));
+        }
+    }
+
+    /**
+     * Encodes an array of {@link Interface}.
+     */
+    public <T extends Interface> void encode(T[] v, int offset, int arrayNullability,
+            int expectedLength, Interface.Manager<T, ?> manager) {
+        if (v == null) {
+            encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+            return;
+        }
+        Encoder e = encoderForArray(
+                BindingsHelper.SERIALIZED_HANDLE_SIZE, v.length, offset, expectedLength);
+        for (int i = 0; i < v.length; ++i) {
+            e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
+                    BindingsHelper.isElementNullable(arrayNullability), manager);
+        }
+    }
+
+    /**
+     * Encodes an array of {@link InterfaceRequest}.
+     */
+    public <I extends Interface> void encode(InterfaceRequest<I>[] v, int offset,
+            int arrayNullability, int expectedLength) {
+        if (v == null) {
+            encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
+            return;
+        }
+        Encoder e = encoderForArray(
+                BindingsHelper.SERIALIZED_HANDLE_SIZE, v.length, offset, expectedLength);
+        for (int i = 0; i < v.length; ++i) {
+            e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
+                    BindingsHelper.isElementNullable(arrayNullability));
+        }
+    }
+
+    /**
+     * Encodes a <code>null</code> pointer iff the object is nullable, raises an exception
+     * otherwise.
+     */
+    public void encodeNullPointer(int offset, boolean nullable) {
+        if (!nullable) {
+            throw new SerializationException(
+                    "Trying to encode a null pointer for a non-nullable type.");
+        }
+        mEncoderState.byteBuffer.putLong(mBaseOffset + offset, 0);
+    }
+
+    /**
+     * Encodes an invalid handle iff the object is nullable, raises an exception otherwise.
+     */
+    public void encodeInvalidHandle(int offset, boolean nullable) {
+        if (!nullable) {
+            throw new SerializationException(
+                    "Trying to encode an invalid handle for a non-nullable type.");
+        }
+        mEncoderState.byteBuffer.putInt(mBaseOffset + offset, -1);
+    }
+
+    private void encodePointerToNextUnclaimedData(int offset) {
+        encode((long) mEncoderState.dataEnd - (mBaseOffset + offset), offset);
+    }
+
+    private Encoder encoderForArray(
+            int elementSizeInByte, int length, int offset, int expectedLength) {
+        if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH &&
+                expectedLength != length) {
+            throw new SerializationException("Trying to encode a fixed array of incorrect length.");
+        }
+        return encoderForArrayByTotalSize(length * elementSizeInByte, length, offset);
+    }
+
+    private Encoder encoderForArrayByTotalSize(int byteSize, int length, int offset) {
+        encodePointerToNextUnclaimedData(offset);
+        return getEncoderAtDataOffset(
+                new DataHeader(DataHeader.HEADER_SIZE + byteSize, length));
+    }
+
+    private void encodeByteArray(byte[] bytes, int length, int offset) {
+        encoderForArrayByTotalSize(bytes.length, length, offset).append(bytes);
+    }
+
+    private void append(byte[] v) {
+        mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
+        mEncoderState.byteBuffer.put(v);
+    }
+
+    private void append(short[] v) {
+        mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
+        mEncoderState.byteBuffer.asShortBuffer().put(v);
+    }
+
+    private void append(int[] v) {
+        mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
+        mEncoderState.byteBuffer.asIntBuffer().put(v);
+    }
+
+    private void append(float[] v) {
+        mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
+        mEncoderState.byteBuffer.asFloatBuffer().put(v);
+    }
+
+    private void append(double[] v) {
+        mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
+        mEncoderState.byteBuffer.asDoubleBuffer().put(v);
+    }
+
+    private void append(long[] v) {
+        mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
+        mEncoderState.byteBuffer.asLongBuffer().put(v);
+    }
+
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java
new file mode 100644
index 0000000..d0d5c3b
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java
@@ -0,0 +1,184 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.AsyncWaiter;
+import org.chromium.mojo.system.AsyncWaiter.Callback;
+import org.chromium.mojo.system.Core;
+import org.chromium.mojo.system.MessagePipeHandle;
+import org.chromium.mojo.system.MessagePipeHandle.ReadMessageResult;
+import org.chromium.mojo.system.MojoException;
+import org.chromium.mojo.system.MojoResult;
+import org.chromium.mojo.system.Pair;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * A factory which provides per-thread executors, which enable execution on the thread from which
+ * they were obtained.
+ */
+class ExecutorFactory {
+
+    /**
+     * A null buffer which is used to send messages without any data on the PipedExecutor's
+     * signaling handles.
+     */
+    private static final ByteBuffer NOTIFY_BUFFER = null;
+
+    /**
+     * Implementation of the executor which uses a pair of {@link MessagePipeHandle} for signaling.
+     * The executor will wait asynchronously on one end of a {@link MessagePipeHandle} on the thread
+     * on which it was created. Other threads can call execute with a {@link Runnable}, and the
+     * executor will queue the {@link Runnable} and write a message on the other end of the handle.
+     * This will wake up the executor which is waiting on the handle, which will then dequeue the
+     * {@link Runnable} and execute it on the original thread.
+     */
+    private static class PipedExecutor implements Executor, Callback {
+
+        /**
+         * The handle which is written to. Access to this object must be protected with |mLock|.
+         */
+        private final MessagePipeHandle mWriteHandle;
+        /**
+         * The handle which is read from.
+         */
+        private final MessagePipeHandle mReadHandle;
+        /**
+         * The list of actions left to be run. Access to this object must be protected with |mLock|.
+         */
+        private final List<Runnable> mPendingActions;
+        /**
+         * Lock protecting access to |mWriteHandle| and |mPendingActions|.
+         */
+        private final Object mLock;
+        /**
+         * The {@link AsyncWaiter} to get notified of new message availability on |mReadHandle|.
+         */
+        private final AsyncWaiter mWaiter;
+
+        /**
+         * Constructor.
+         */
+        public PipedExecutor(Core core) {
+            mWaiter = core.getDefaultAsyncWaiter();
+            assert mWaiter != null;
+            mLock = new Object();
+            Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(
+                    new MessagePipeHandle.CreateOptions());
+            mReadHandle = handles.first;
+            mWriteHandle = handles.second;
+            mPendingActions = new ArrayList<Runnable>();
+            asyncWait();
+        }
+
+        /**
+         * Asynchronously wait for the next command to arrive. This should only be called on the
+         * executor thread.
+         */
+        private void asyncWait() {
+            mWaiter.asyncWait(mReadHandle, Core.HandleSignals.READABLE, Core.DEADLINE_INFINITE,
+                    this);
+        }
+
+        /**
+         * @see Callback#onResult(int)
+         */
+        @Override
+        public void onResult(int result) {
+            if (result == MojoResult.OK && readNotifyBufferMessage()) {
+                runNextAction();
+            } else {
+                close();
+            }
+        }
+
+        /**
+         * @see Callback#onError(MojoException)
+         */
+        @Override
+        public void onError(MojoException exception) {
+            close();
+        }
+
+        /**
+         * Close the handles. Should only be called on the executor thread.
+         */
+        private void close() {
+            synchronized (mLock) {
+                mWriteHandle.close();
+                mPendingActions.clear();
+            }
+            mReadHandle.close();
+        }
+
+        /**
+         * Read the next message on |mReadHandle|, and return |true| if successful, |false|
+         * otherwise.
+         */
+        private boolean readNotifyBufferMessage() {
+            try {
+                ReadMessageResult readMessageResult = mReadHandle.readMessage(NOTIFY_BUFFER, 0,
+                        MessagePipeHandle.ReadFlags.NONE);
+                if (readMessageResult.getMojoResult() == MojoResult.OK) {
+                    asyncWait();
+                    return true;
+                }
+            } catch (MojoException e) {
+                // Will be closed by the fall back at the end of this method.
+            }
+            return false;
+        }
+
+        /**
+         * Run the next action in the |mPendingActions| queue.
+         */
+        private void runNextAction() {
+            Runnable toRun = null;
+            synchronized (mWriteHandle) {
+                toRun = mPendingActions.remove(0);
+            }
+            toRun.run();
+        }
+
+        /**
+         * Execute the given |command| in the executor thread. This can be called on any thread.
+         *
+         * @see Executor#execute(Runnable)
+         */
+        @Override
+        public void execute(Runnable command) {
+            // Accessing the write handle must be protected by the lock, because it can be closed
+            // from the executor's thread.
+            synchronized (mLock) {
+                if (!mWriteHandle.isValid()) {
+                    throw new IllegalStateException(
+                            "Trying to execute an action on a closed executor.");
+                }
+                mPendingActions.add(command);
+                mWriteHandle.writeMessage(NOTIFY_BUFFER, null, MessagePipeHandle.WriteFlags.NONE);
+            }
+        }
+    }
+
+    /**
+     * Keep one executor per executor thread.
+     */
+    private static final ThreadLocal<Executor> EXECUTORS = new ThreadLocal<Executor>();
+
+    /**
+     * Returns an {@link Executor} that will run all of its actions in the current thread.
+     */
+    public static Executor getExecutorForCurrentThread(Core core) {
+        Executor executor = EXECUTORS.get();
+        if (executor == null) {
+            executor = new PipedExecutor(core);
+            EXECUTORS.set(executor);
+        }
+        return executor;
+    }
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/HandleOwner.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/HandleOwner.java
new file mode 100644
index 0000000..60fc33b
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/HandleOwner.java
@@ -0,0 +1,29 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.Handle;
+
+import java.io.Closeable;
+
+/**
+ * Describes a class that owns a handle.
+ *
+ * @param <H> The type of the owned handle.
+ */
+public interface HandleOwner<H extends Handle> extends Closeable {
+
+    /**
+     * Pass the handle owned by this class.
+     */
+    public H passHandle();
+
+    /**
+     * @see java.io.Closeable#close()
+     */
+    @Override
+    public void close();
+
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java
new file mode 100644
index 0000000..c3b26a2
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java
@@ -0,0 +1,257 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.Core;
+import org.chromium.mojo.system.MessagePipeHandle;
+import org.chromium.mojo.system.MojoException;
+import org.chromium.mojo.system.Pair;
+
+import java.io.Closeable;
+
+/**
+ * Base class for mojo generated interfaces.
+ */
+public interface Interface extends ConnectionErrorHandler, Closeable {
+
+    /**
+     * The close method is called when the connection to the interface is closed.
+     *
+     * @see java.io.Closeable#close()
+     */
+    @Override
+    public void close();
+
+    /**
+     * A proxy to a mojo interface. This is base class for all generated proxies. It implements the
+     * Interface and each time a method is called, the parameters are serialized and sent to the
+     * {@link MessageReceiverWithResponder}, along with the response callback if needed.
+     */
+    public interface Proxy extends Interface {
+
+        /**
+         * Set the {@link ConnectionErrorHandler} that will be notified of errors.
+         */
+        public void setErrorHandler(ConnectionErrorHandler errorHandler);
+
+    }
+
+    /**
+     * Base implementation of {@link Proxy}.
+     */
+    abstract class AbstractProxy implements Proxy {
+
+        /**
+         * The {@link Core} implementation to use.
+         */
+        private final Core mCore;
+
+        /**
+         * The {@link MessageReceiverWithResponder} that will receive a serialized message for each
+         * method call.
+         */
+        private final MessageReceiverWithResponder mMessageReceiver;
+
+        /**
+         * The {@link ConnectionErrorHandler} that will be notified of errors.
+         */
+        private ConnectionErrorHandler mErrorHandler = null;
+
+        /**
+         * Constructor.
+         *
+         * @param core the Core implementation used to create pipes and access the async waiter.
+         * @param messageReceiver the message receiver to send message to.
+         */
+        protected AbstractProxy(Core core, MessageReceiverWithResponder messageReceiver) {
+            this.mCore = core;
+            this.mMessageReceiver = messageReceiver;
+        }
+
+        /**
+         * Returns the message receiver to send message to.
+         */
+        protected MessageReceiverWithResponder getMessageReceiver() {
+            return mMessageReceiver;
+        }
+
+        /**
+         * Returns the Core implementation.
+         */
+        protected Core getCore() {
+            return mCore;
+        }
+
+        /**
+         * @see Proxy#setErrorHandler(ConnectionErrorHandler)
+         */
+        @Override
+        public void setErrorHandler(ConnectionErrorHandler errorHandler) {
+            this.mErrorHandler = errorHandler;
+        }
+
+        /**
+         * @see ConnectionErrorHandler#onConnectionError(MojoException)
+         */
+        @Override
+        public void onConnectionError(MojoException e) {
+            if (mErrorHandler != null) {
+                mErrorHandler.onConnectionError(e);
+            }
+        }
+
+        /**
+         * @see Closeable#close()
+         */
+        @Override
+        public void close() {
+            mMessageReceiver.close();
+        }
+    }
+
+    /**
+     * Base implementation of Stub. Stubs are message receivers that deserialize the payload and
+     * call the appropriate method in the implementation. If the method returns result, the stub
+     * serializes the response and sends it back.
+     *
+     * @param <I> the type of the interface to delegate calls to.
+     */
+    abstract class Stub<I extends Interface> implements MessageReceiverWithResponder {
+
+        /**
+         * The {@link Core} implementation to use.
+         */
+        private final Core mCore;
+
+        /**
+         * The implementation to delegate calls to.
+         */
+        private final I mImpl;
+
+        /**
+         * Constructor.
+         *
+         * @param core the {@link Core} implementation to use.
+         * @param impl the implementation to delegate calls to.
+         */
+        public Stub(Core core, I impl) {
+            mCore = core;
+            mImpl = impl;
+        }
+
+        /**
+         * Returns the Core implementation.
+         */
+        protected Core getCore() {
+            return mCore;
+        }
+
+        /**
+         * Returns the implementation to delegate calls to.
+         */
+        protected I getImpl() {
+            return mImpl;
+        }
+
+        /**
+         * @see org.chromium.mojo.bindings.MessageReceiver#close()
+         */
+        @Override
+        public void close() {
+            mImpl.close();
+        }
+
+    }
+
+    /**
+     * The |Manager| object enables building of proxies and stubs for a given interface.
+     *
+     * @param <I> the type of the interface the manager can handle.
+     * @param <P> the type of the proxy the manager can handle. To be noted, P always extends I.
+     */
+    abstract class Manager<I extends Interface, P extends Proxy> {
+
+        /**
+         * Returns the name of the interface. This is an opaque (but human readable) identifier used
+         * by the service provider to identify services.
+         */
+        public abstract String getName();
+
+        /**
+         * Binds the given implementation to the handle.
+         */
+        public void bind(I impl, MessagePipeHandle handle) {
+            // The router (and by consequence the handle) is intentionally leaked. It will close
+            // itself when the connected handle is closed and the proxy receives the connection
+            // error.
+            Router router = new RouterImpl(handle);
+            bind(handle.getCore(), impl, router);
+            router.start();
+        }
+
+        /**
+         * Binds the given implementation to the InterfaceRequest.
+         */
+        public final void bind(I impl, InterfaceRequest<I> request) {
+            bind(impl, request.passHandle());
+        }
+
+        /**
+         * Returns a Proxy that will send messages to the given |handle|. This implies that the
+         * other end of the handle must be binded to an implementation of the interface.
+         */
+        public final P attachProxy(MessagePipeHandle handle) {
+            RouterImpl router = new RouterImpl(handle);
+            P proxy = attachProxy(handle.getCore(), router);
+            DelegatingConnectionErrorHandler handlers = new DelegatingConnectionErrorHandler();
+            handlers.addConnectionErrorHandler(proxy);
+            router.setErrorHandler(handlers);
+            router.start();
+            return proxy;
+        }
+
+        /**
+         * Constructs a new |InterfaceRequest| for the interface. This method returns a Pair where
+         * the first element is a proxy, and the second element is the request. The proxy can be
+         * used immediately.
+         */
+        public final Pair<P, InterfaceRequest<I>> getInterfaceRequest(Core core) {
+            Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
+            P proxy = attachProxy(handles.first);
+            return Pair.create(proxy, new InterfaceRequest<I>(handles.second));
+        }
+
+        /**
+         * Binds the implementation to the given |router|.
+         */
+        final void bind(Core core, I impl, Router router) {
+            router.setErrorHandler(impl);
+            router.setIncomingMessageReceiver(buildStub(core, impl));
+        }
+
+        /**
+         * Returns a Proxy that will send messages to the given |router|.
+         */
+        final P attachProxy(Core core, Router router) {
+            return buildProxy(core, new AutoCloseableRouter(core, router));
+        }
+
+        /**
+         * Creates a new array of the given |size|.
+         */
+        protected abstract I[] buildArray(int size);
+
+        /**
+         * Constructs a Stub delegating to the given implementation.
+         */
+        protected abstract Stub<I> buildStub(Core core, I impl);
+
+        /**
+         * Constructs a Proxy forwarding the calls to the given message receiver.
+         */
+        protected abstract P buildProxy(Core core, MessageReceiverWithResponder messageReceiver);
+
+    }
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/InterfaceRequest.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/InterfaceRequest.java
new file mode 100644
index 0000000..87835e0
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/InterfaceRequest.java
@@ -0,0 +1,50 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.MessagePipeHandle;
+
+/**
+ * One end of the message pipe representing a request to create an implementation to be bound to it.
+ * The other end of the pipe is bound to a proxy, which can be used immediately, while the
+ * InterfaceRequest is being sent.
+ * <p>
+ * InterfaceRequest are built using |Interface.Manager|.
+ *
+ * @param <P> the type of the remote interface proxy.
+ */
+public class InterfaceRequest<P extends Interface> implements HandleOwner<MessagePipeHandle> {
+
+    /**
+     * The handle which will be sent and will be connected to the implementation.
+     */
+    private final MessagePipeHandle mHandle;
+
+    /**
+     * Constructor.
+     *
+     * @param handle the handle which will be sent and will be connected to the implementation.
+     */
+    InterfaceRequest(MessagePipeHandle handle) {
+        mHandle = handle;
+    }
+
+    /**
+     * @see HandleOwner#passHandle()
+     */
+    @Override
+    public MessagePipeHandle passHandle() {
+        return mHandle.pass();
+    }
+
+    /**
+     * @see java.io.Closeable#close()
+     */
+    @Override
+    public void close() {
+        mHandle.close();
+    }
+
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/InterfaceWithClient.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/InterfaceWithClient.java
new file mode 100644
index 0000000..f7d8afe
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/InterfaceWithClient.java
@@ -0,0 +1,115 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.Core;
+import org.chromium.mojo.system.MessagePipeHandle;
+import org.chromium.mojo.system.Pair;
+
+/**
+ * Base class for mojo generated interfaces that have a client.
+ *
+ * @param <CI> the type of the client interface.
+ */
+public interface InterfaceWithClient<CI extends Interface> extends Interface {
+
+    /**
+     * Proxy class for interfaces with a client.
+     */
+    interface Proxy<CI extends Interface> extends Interface.Proxy, InterfaceWithClient<CI> {
+    }
+
+    /**
+     * Base implementation of Proxy.
+     *
+     * @param <CI> the type of the client interface.
+     */
+    abstract class AbstractProxy<CI extends Interface> extends Interface.AbstractProxy
+            implements Proxy<CI> {
+
+        /**
+         * Constructor.
+         *
+         * @param core the Core implementation used to create pipes and access the async waiter.
+         * @param messageReceiver the message receiver to send message to.
+         */
+        public AbstractProxy(Core core, MessageReceiverWithResponder messageReceiver) {
+            super(core, messageReceiver);
+        }
+
+        /**
+         * @see InterfaceWithClient#setClient(Interface)
+         */
+        @Override
+        public void setClient(CI client) {
+            throw new UnsupportedOperationException(
+                    "Setting the client on a proxy is not supported");
+        }
+    }
+
+    /**
+     * Base manager implementation for interfaces that have a client.
+     *
+     * @param <I> the type of the interface the manager can handle.
+     * @param <P> the type of the proxy the manager can handle. To be noted, P always extends I.
+     * @param <CI> the type of the client interface.
+     */
+    abstract class Manager<I extends InterfaceWithClient<CI>, P extends Proxy<CI>,
+            CI extends Interface> extends Interface.Manager<I, P> {
+
+        /**
+         * @see Interface.Manager#bind(Interface, MessagePipeHandle)
+         */
+        @Override
+        public final void bind(I impl, MessagePipeHandle handle) {
+            Router router = new RouterImpl(handle);
+            super.bind(handle.getCore(), impl, router);
+            @SuppressWarnings("unchecked")
+            CI client = (CI) getClientManager().attachProxy(handle.getCore(), router);
+            impl.setClient(client);
+            router.start();
+        }
+
+        /**
+         * Returns a Proxy that will send messages to the given |handle|. This implies that the
+         * other end of the handle must be connected to an implementation of the interface. |client|
+         * is the implementation of the client interface.
+         */
+        public P attachProxy(MessagePipeHandle handle, CI client) {
+            Router router = new RouterImpl(handle);
+            DelegatingConnectionErrorHandler handlers = new DelegatingConnectionErrorHandler();
+            handlers.addConnectionErrorHandler(client);
+            router.setErrorHandler(handlers);
+            getClientManager().bind(handle.getCore(), client, router);
+            P proxy = super.attachProxy(handle.getCore(), router);
+            handlers.addConnectionErrorHandler(proxy);
+            router.start();
+            return proxy;
+        }
+
+        /**
+         * Constructs a new |InterfaceRequest| for the interface. This method returns a Pair where
+         * the first element is a proxy, and the second element is the request. The proxy can be
+         * used immediately.
+         *
+         * @param client the implementation of the client interface.
+         */
+        public final Pair<P, InterfaceRequest<I>> getInterfaceRequest(Core core, CI client) {
+            Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
+            P proxy = attachProxy(handles.first, client);
+            return Pair.create(proxy, new InterfaceRequest<I>(handles.second));
+        }
+
+        /**
+         * Returns a manager for the client inetrafce.
+         */
+        protected abstract Interface.Manager<CI, ?> getClientManager();
+    }
+
+    /**
+     * Set the client implementation for this interface.
+     */
+    public void setClient(CI client);
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Message.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Message.java
new file mode 100644
index 0000000..0d270cc
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Message.java
@@ -0,0 +1,69 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.Handle;
+import org.chromium.mojo.system.MessagePipeHandle;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * A raw message to be sent/received from a {@link MessagePipeHandle}. Note that this can contain
+ * any data, not necessarily a Mojo message with a proper header. See also {@link ServiceMessage}.
+ */
+public class Message {
+
+    /**
+     * The data of the message.
+     */
+    private final ByteBuffer mBuffer;
+
+    /**
+     * The handles of the message.
+     */
+    private final List<? extends Handle> mHandle;
+
+    /**
+     * This message interpreted as a message for a mojo service with an appropriate header.
+     */
+    private ServiceMessage mWithHeader = null;
+
+    /**
+     * Constructor.
+     *
+     * @param buffer The buffer containing the bytes to send. This must be a direct buffer.
+     * @param handles The list of handles to send.
+     */
+    public Message(ByteBuffer buffer, List<? extends Handle> handles) {
+        assert buffer.isDirect();
+        mBuffer = buffer;
+        mHandle = handles;
+    }
+
+    /**
+     * The data of the message.
+     */
+    public ByteBuffer getData() {
+        return mBuffer;
+    }
+
+    /**
+     * The handles of the message.
+     */
+    public List<? extends Handle> getHandles() {
+        return mHandle;
+    }
+
+    /**
+     * Returns the message interpreted as a message for a mojo service.
+     */
+    public ServiceMessage asServiceMessage() {
+        if (mWithHeader == null) {
+            mWithHeader = new ServiceMessage(this);
+        }
+        return mWithHeader;
+    }
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/MessageHeader.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/MessageHeader.java
new file mode 100644
index 0000000..ad4e108
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/MessageHeader.java
@@ -0,0 +1,254 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.bindings.Struct.DataHeader;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Header information for a message.
+ */
+public class MessageHeader {
+
+    private static final int SIMPLE_MESSAGE_SIZE = 16;
+    private static final int SIMPLE_MESSAGE_NUM_FIELDS = 2;
+    private static final DataHeader SIMPLE_MESSAGE_STRUCT_INFO =
+            new DataHeader(SIMPLE_MESSAGE_SIZE, SIMPLE_MESSAGE_NUM_FIELDS);
+
+    private static final int MESSAGE_WITH_REQUEST_ID_SIZE = 24;
+    private static final int MESSAGE_WITH_REQUEST_ID_NUM_FIELDS = 3;
+    private static final DataHeader MESSAGE_WITH_REQUEST_ID_STRUCT_INFO =
+            new DataHeader(MESSAGE_WITH_REQUEST_ID_SIZE, MESSAGE_WITH_REQUEST_ID_NUM_FIELDS);
+
+    private static final int TYPE_OFFSET = 8;
+    private static final int FLAGS_OFFSET = 12;
+    private static final int REQUEST_ID_OFFSET = 16;
+
+    /**
+     * Flag for a header of a simple message.
+     */
+    public static final int NO_FLAG = 0;
+
+    /**
+     * Flag for a header of a message that expected a response.
+     */
+    public static final int MESSAGE_EXPECTS_RESPONSE_FLAG = 1 << 0;
+
+    /**
+     * Flag for a header of a message that is a response.
+     */
+    public static final int MESSAGE_IS_RESPONSE_FLAG = 1 << 1;
+
+    private final DataHeader mDataHeader;
+    private final int mType;
+    private final int mFlags;
+    private long mRequestId;
+
+    /**
+     * Constructor for the header of a message which does not have a response.
+     */
+    public MessageHeader(int type) {
+        mDataHeader = SIMPLE_MESSAGE_STRUCT_INFO;
+        mType = type;
+        mFlags = 0;
+        mRequestId = 0;
+    }
+
+    /**
+     * Constructor for the header of a message which have a response or being itself a response.
+     */
+    public MessageHeader(int type, int flags, long requestId) {
+        assert mustHaveRequestId(flags);
+        mDataHeader = MESSAGE_WITH_REQUEST_ID_STRUCT_INFO;
+        mType = type;
+        mFlags = flags;
+        mRequestId = requestId;
+    }
+
+    /**
+     * Constructor, parsing the header from a message. Should only be used by {@link Message}
+     * itself.
+     */
+    MessageHeader(Message message) {
+        Decoder decoder = new Decoder(message);
+        mDataHeader = decoder.readDataHeader();
+        validateDataHeader(mDataHeader);
+        mType = decoder.readInt(TYPE_OFFSET);
+        mFlags = decoder.readInt(FLAGS_OFFSET);
+        if (mustHaveRequestId(mFlags)) {
+            if (mDataHeader.size < MESSAGE_WITH_REQUEST_ID_SIZE) {
+                throw new DeserializationException("Incorrect message size, expecting at least "
+                        + MESSAGE_WITH_REQUEST_ID_SIZE
+                        + " for a message with a request identifier, but got: " + mDataHeader.size);
+
+            }
+            mRequestId = decoder.readLong(REQUEST_ID_OFFSET);
+        } else {
+            mRequestId = 0;
+        }
+    }
+
+    /**
+     * Returns the size in bytes of the serialization of the header.
+     */
+    public int getSize() {
+        return mDataHeader.size;
+    }
+
+    /**
+     * Returns the type of the message.
+     */
+    public int getType() {
+        return mType;
+    }
+
+    /**
+     * Returns the flags associated to the message.
+     */
+    public int getFlags() {
+        return mFlags;
+    }
+
+    /**
+     * Returns if the message has the given flag.
+     */
+    public boolean hasFlag(int flag) {
+        return (mFlags & flag) == flag;
+    }
+
+    /**
+     * Returns if the message has a request id.
+     */
+    public boolean hasRequestId() {
+        return mustHaveRequestId(mFlags);
+    }
+
+    /**
+     * Return the request id for the message. Must only be called if the message has a request id.
+     */
+    public long getRequestId() {
+        assert hasRequestId();
+        return mRequestId;
+    }
+
+    /**
+     * Encode the header.
+     */
+    public void encode(Encoder encoder) {
+        encoder.encode(mDataHeader);
+        encoder.encode(getType(), TYPE_OFFSET);
+        encoder.encode(getFlags(), FLAGS_OFFSET);
+        if (hasRequestId()) {
+            encoder.encode(getRequestId(), REQUEST_ID_OFFSET);
+        }
+    }
+
+    /**
+     * Returns true if the header has the expected flags. Only considers flags this class knows
+     * about in order to allow this class to work with future version of the header format.
+     */
+    public boolean validateHeader(int expectedFlags) {
+        int knownFlags = getFlags() & (MESSAGE_EXPECTS_RESPONSE_FLAG | MESSAGE_IS_RESPONSE_FLAG);
+        return knownFlags == expectedFlags;
+    }
+
+    /**
+     * Returns true if the header has the expected type and flags. Only consider flags this class
+     * knows about in order to allow this class to work with future version of the header format.
+     */
+    public boolean validateHeader(int expectedType, int expectedFlags) {
+        return getType() == expectedType && validateHeader(expectedFlags);
+    }
+
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((mDataHeader == null) ? 0 : mDataHeader.hashCode());
+        result = prime * result + mFlags;
+        result = prime * result + (int) (mRequestId ^ (mRequestId >>> 32));
+        result = prime * result + mType;
+        return result;
+    }
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (object == this)
+            return true;
+        if (object == null)
+            return false;
+        if (getClass() != object.getClass())
+            return false;
+
+        MessageHeader other = (MessageHeader) object;
+        if (mDataHeader == null) {
+            if (other.mDataHeader != null) {
+                return false;
+            }
+        } else {
+            if (!mDataHeader.equals(other.mDataHeader)) {
+                return false;
+            }
+        }
+
+        return (mFlags == other.mFlags &&
+                mRequestId == other.mRequestId &&
+                mType == other.mType);
+    }
+
+    /**
+     * Set the request id on the message contained in the given buffer.
+     */
+    void setRequestId(ByteBuffer buffer, long requestId) {
+        assert mustHaveRequestId(buffer.getInt(FLAGS_OFFSET));
+        buffer.putLong(REQUEST_ID_OFFSET, requestId);
+        mRequestId = requestId;
+    }
+
+    /**
+     * Returns whether a message with the given flags must have a request Id.
+     */
+    private static boolean mustHaveRequestId(int flags) {
+        return (flags & (MESSAGE_EXPECTS_RESPONSE_FLAG | MESSAGE_IS_RESPONSE_FLAG)) != 0;
+    }
+
+    /**
+     * Validate that the given {@link DataHeader} can be the data header of a message header.
+     */
+    private static void validateDataHeader(DataHeader dataHeader) {
+        if (dataHeader.numFields < SIMPLE_MESSAGE_NUM_FIELDS) {
+            throw new DeserializationException(
+                    "Incorrect number of fields, expecting at least " + SIMPLE_MESSAGE_NUM_FIELDS
+                    + ", but got: " + dataHeader.numFields);
+        }
+        if (dataHeader.size < SIMPLE_MESSAGE_SIZE) {
+            throw new DeserializationException(
+                    "Incorrect message size, expecting at least " + SIMPLE_MESSAGE_SIZE
+                    + ", but got: " + dataHeader.size);
+        }
+        if (dataHeader.numFields == SIMPLE_MESSAGE_NUM_FIELDS
+                && dataHeader.size != SIMPLE_MESSAGE_SIZE) {
+            throw new DeserializationException(
+                    "Incorrect message size for a message with " + SIMPLE_MESSAGE_NUM_FIELDS
+                    + " fields, expecting " + SIMPLE_MESSAGE_SIZE + ", but got: "
+                    + dataHeader.size);
+        }
+        if (dataHeader.numFields == MESSAGE_WITH_REQUEST_ID_NUM_FIELDS
+                && dataHeader.size != MESSAGE_WITH_REQUEST_ID_SIZE) {
+            throw new DeserializationException(
+                    "Incorrect message size for a message with "
+                    + MESSAGE_WITH_REQUEST_ID_NUM_FIELDS + " fields, expecting "
+                    + MESSAGE_WITH_REQUEST_ID_SIZE + ", but got: " + dataHeader.size);
+        }
+    }
+
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/MessageReceiver.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/MessageReceiver.java
new file mode 100644
index 0000000..4223297
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/MessageReceiver.java
@@ -0,0 +1,25 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import java.io.Closeable;
+
+/**
+ * A class which implements this interface can receive {@link Message} objects.
+ */
+public interface MessageReceiver extends Closeable {
+
+    /**
+     * Receive a {@link Message}. The {@link MessageReceiver} is allowed to mutate the message.
+     * Returns |true| if the message has been handled, |false| otherwise.
+     */
+    boolean accept(Message message);
+
+    /**
+     * @see java.io.Closeable#close()
+     */
+    @Override
+    public void close();
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/MessageReceiverWithResponder.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/MessageReceiverWithResponder.java
new file mode 100644
index 0000000..e24a558
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/MessageReceiverWithResponder.java
@@ -0,0 +1,21 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+/**
+ * A {@link MessageReceiver} that can also handle the handle the response message generated from the
+ * given message.
+ */
+public interface MessageReceiverWithResponder extends MessageReceiver {
+
+    /**
+     * A variant on {@link #accept(Message)} that registers a {@link MessageReceiver}
+     * (known as the responder) to handle the response message generated from the given message. The
+     * responder's {@link #accept(Message)} method may be called as part of the call to
+     * {@link #acceptWithResponder(Message, MessageReceiver)}, or some time after its
+     * return.
+     */
+    boolean acceptWithResponder(Message message, MessageReceiver responder);
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Router.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Router.java
new file mode 100644
index 0000000..ba19ae5
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Router.java
@@ -0,0 +1,31 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.MessagePipeHandle;
+
+/**
+ * A {@link Router} will handle mojo message and forward those to a {@link Connector}. It deals with
+ * parsing of headers and adding of request ids in order to be able to match a response to a
+ * request.
+ */
+public interface Router extends MessageReceiverWithResponder, HandleOwner<MessagePipeHandle> {
+
+    /**
+     * Start listening for incoming messages.
+     */
+    public void start();
+
+    /**
+     * Set the {@link MessageReceiverWithResponder} that will deserialize and use the message
+     * received from the pipe.
+     */
+    public void setIncomingMessageReceiver(MessageReceiverWithResponder incomingMessageReceiver);
+
+    /**
+     * Set the handle that will be notified of errors on the message pipe.
+     */
+    public void setErrorHandler(ConnectionErrorHandler errorHandler);
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java
new file mode 100644
index 0000000..5b27d7e
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java
@@ -0,0 +1,195 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.AsyncWaiter;
+import org.chromium.mojo.system.MessagePipeHandle;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Implementation of {@link Router}.
+ */
+public class RouterImpl implements Router {
+
+    /**
+     * {@link MessageReceiver} used as the {@link Connector} callback.
+     */
+    private class ResponderThunk implements MessageReceiver {
+
+        /**
+         * @see MessageReceiver#accept(Message)
+         */
+        @Override
+        public boolean accept(Message message) {
+            return handleIncomingMessage(message);
+        }
+
+        /**
+         * @see org.chromium.mojo.bindings.MessageReceiver#close()
+         */
+        @Override
+        public void close() {
+            handleConnectorClose();
+        }
+
+    }
+
+    /**
+     * The {@link Connector} which is connected to the handle.
+     */
+    private final Connector mConnector;
+
+    /**
+     * The {@link MessageReceiverWithResponder} that will consume the messages received from the
+     * pipe.
+     */
+    private MessageReceiverWithResponder mIncomingMessageReceiver;
+
+    /**
+     * The next id to use for a request id which needs a response. It is auto-incremented.
+     */
+    private long mNextRequestId = 1;
+
+    /**
+     * The map from request ids to {@link MessageReceiver} of request currently in flight.
+     */
+    private Map<Long, MessageReceiver> mResponders = new HashMap<Long, MessageReceiver>();
+
+    /**
+     * Constructor that will use the default {@link AsyncWaiter}.
+     *
+     * @param messagePipeHandle The {@link MessagePipeHandle} to route message for.
+     */
+    public RouterImpl(MessagePipeHandle messagePipeHandle) {
+        this(messagePipeHandle, BindingsHelper.getDefaultAsyncWaiterForHandle(messagePipeHandle));
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param messagePipeHandle The {@link MessagePipeHandle} to route message for.
+     * @param asyncWaiter the {@link AsyncWaiter} to use to get notification of new messages on the
+     *            handle.
+     */
+    public RouterImpl(MessagePipeHandle messagePipeHandle, AsyncWaiter asyncWaiter) {
+        mConnector = new Connector(messagePipeHandle, asyncWaiter);
+        mConnector.setIncomingMessageReceiver(new ResponderThunk());
+    }
+
+    /**
+     * @see org.chromium.mojo.bindings.Router#start()
+     */
+    @Override
+    public void start() {
+        mConnector.start();
+    }
+
+    /**
+     * @see Router#setIncomingMessageReceiver(MessageReceiverWithResponder)
+     */
+    @Override
+    public void setIncomingMessageReceiver(MessageReceiverWithResponder incomingMessageReceiver) {
+        this.mIncomingMessageReceiver = incomingMessageReceiver;
+    }
+
+    /**
+     * @see MessageReceiver#accept(Message)
+     */
+    @Override
+    public boolean accept(Message message) {
+        // A message without responder is directly forwarded to the connector.
+        return mConnector.accept(message);
+    }
+
+    /**
+     * @see MessageReceiverWithResponder#acceptWithResponder(Message, MessageReceiver)
+     */
+    @Override
+    public boolean acceptWithResponder(Message message, MessageReceiver responder) {
+        // The message must have a header.
+        ServiceMessage messageWithHeader = message.asServiceMessage();
+        // Checking the message expects a response.
+        assert messageWithHeader.getHeader().hasFlag(MessageHeader.MESSAGE_EXPECTS_RESPONSE_FLAG);
+
+        // Compute a request id for being able to route the response.
+        long requestId = mNextRequestId++;
+        // Reserve 0 in case we want it to convey special meaning in the future.
+        if (requestId == 0) {
+            requestId = mNextRequestId++;
+        }
+        if (mResponders.containsKey(requestId)) {
+            throw new IllegalStateException("Unable to find a new request identifier.");
+        }
+        messageWithHeader.setRequestId(requestId);
+        if (!mConnector.accept(messageWithHeader)) {
+            return false;
+        }
+        // Only keep the responder is the message has been accepted.
+        mResponders.put(requestId, responder);
+        return true;
+    }
+
+    /**
+     * @see org.chromium.mojo.bindings.HandleOwner#passHandle()
+     */
+    @Override
+    public MessagePipeHandle passHandle() {
+        return mConnector.passHandle();
+    }
+
+    /**
+     * @see java.io.Closeable#close()
+     */
+    @Override
+    public void close() {
+        mConnector.close();
+    }
+
+    /**
+     * @see Router#setErrorHandler(ConnectionErrorHandler)
+     */
+    @Override
+    public void setErrorHandler(ConnectionErrorHandler errorHandler) {
+        mConnector.setErrorHandler(errorHandler);
+    }
+
+    /**
+     * Receive a message from the connector. Returns |true| if the message has been handled.
+     */
+    private boolean handleIncomingMessage(Message message) {
+        MessageHeader header = message.asServiceMessage().getHeader();
+        if (header.hasFlag(MessageHeader.MESSAGE_EXPECTS_RESPONSE_FLAG)) {
+            if (mIncomingMessageReceiver != null) {
+                return mIncomingMessageReceiver.acceptWithResponder(message, this);
+            }
+            // If we receive a request expecting a response when the client is not
+            // listening, then we have no choice but to tear down the pipe.
+            close();
+            return false;
+        } else if (header.hasFlag(MessageHeader.MESSAGE_IS_RESPONSE_FLAG)) {
+            long requestId = header.getRequestId();
+            MessageReceiver responder = mResponders.get(requestId);
+            if (responder == null) {
+                return false;
+            }
+            mResponders.remove(requestId);
+            return responder.accept(message);
+        } else {
+            if (mIncomingMessageReceiver != null) {
+                return mIncomingMessageReceiver.accept(message);
+            }
+            // OK to drop the message.
+        }
+        return false;
+    }
+
+    private void handleConnectorClose() {
+        if (mIncomingMessageReceiver != null) {
+            mIncomingMessageReceiver.close();
+        }
+    }
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/SerializationException.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/SerializationException.java
new file mode 100644
index 0000000..d4f5502
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/SerializationException.java
@@ -0,0 +1,26 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+/**
+ * Error that can be thrown when serializing a mojo message.
+ */
+public class SerializationException extends RuntimeException {
+
+    /**
+     * Constructs a new serialization exception with the specified detail message.
+     */
+    public SerializationException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new serialization exception with the specified cause.
+     */
+    public SerializationException(Exception cause) {
+        super(cause);
+    }
+
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ServiceMessage.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ServiceMessage.java
new file mode 100644
index 0000000..ac62bf6
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ServiceMessage.java
@@ -0,0 +1,73 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Represents a {@link Message} which contains a {@link MessageHeader}. Deals with parsing the
+ * {@link MessageHeader} for a message.
+ */
+public class ServiceMessage extends Message {
+
+    private final MessageHeader mHeader;
+    private Message mPayload;
+
+    /**
+     * Reinterpret the given |message| as a message with the given |header|. The |message| must
+     * contain the |header| as the start of its raw data.
+     */
+    public ServiceMessage(Message baseMessage, MessageHeader header) {
+        super(baseMessage.getData(), baseMessage.getHandles());
+        assert header.equals(new org.chromium.mojo.bindings.MessageHeader(baseMessage));
+        this.mHeader = header;
+    }
+
+    /**
+     * Reinterpret the given |message| as a message with a header. The |message| must contain a
+     * header as the start of it's raw data, which will be parsed by this constructor.
+     */
+    ServiceMessage(Message baseMessage) {
+        this(baseMessage, new org.chromium.mojo.bindings.MessageHeader(baseMessage));
+    }
+
+    /**
+     * @see Message#asServiceMessage()
+     */
+    @Override
+    public ServiceMessage asServiceMessage() {
+        return this;
+    }
+
+    /**
+     * Returns the header of the given message. This will throw a {@link DeserializationException}
+     * if the start of the message is not a valid header.
+     */
+    public MessageHeader getHeader() {
+        return mHeader;
+    }
+
+    /**
+     * Returns the payload of the message.
+     */
+    public Message getPayload() {
+        if (mPayload == null) {
+            ByteBuffer truncatedBuffer =
+                    ((ByteBuffer) getData().position(getHeader().getSize())).slice();
+            truncatedBuffer.order(ByteOrder.nativeOrder());
+            mPayload = new Message(truncatedBuffer, getHandles());
+        }
+        return mPayload;
+    }
+
+    /**
+     * Set the request identifier on the message.
+     */
+    void setRequestId(long requestId) {
+        mHeader.setRequestId(getData(), requestId);
+    }
+
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/SideEffectFreeCloseable.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/SideEffectFreeCloseable.java
new file mode 100644
index 0000000..118c991
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/SideEffectFreeCloseable.java
@@ -0,0 +1,21 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import java.io.Closeable;
+
+/**
+ * An implementation of closeable that doesn't do anything.
+ */
+public class SideEffectFreeCloseable implements Closeable {
+
+    /**
+     * @see java.io.Closeable#close()
+     */
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Struct.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Struct.java
new file mode 100644
index 0000000..017d0ef
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Struct.java
@@ -0,0 +1,119 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.Core;
+
+/**
+ * Base class for all mojo structs.
+ */
+public abstract class Struct {
+
+    /**
+     * The header for a mojo complex element.
+     */
+    public static final class DataHeader {
+
+        /**
+         * The size of a serialized header, in bytes.
+         */
+        public static final int HEADER_SIZE = 8;
+
+        /**
+         * The offset of the size field.
+         */
+        public static final int SIZE_OFFSET = 0;
+
+        /**
+         * The offset of the number of fields field.
+         */
+        public static final int NUM_FIELDS_OFFSET = 4;
+
+        public final int size;
+        public final int numFields;
+
+        /**
+         * Constructor.
+         */
+        public DataHeader(int size, int numFields) {
+            super();
+            this.size = size;
+            this.numFields = numFields;
+        }
+
+        /**
+         * @see Object#hashCode()
+         */
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + numFields;
+            result = prime * result + size;
+            return result;
+        }
+
+        /**
+         * @see Object#equals(Object)
+         */
+        @Override
+        public boolean equals(Object object) {
+            if (object == this)
+                return true;
+            if (object == null)
+                return false;
+            if (getClass() != object.getClass())
+                return false;
+
+            DataHeader other = (DataHeader) object;
+            return (numFields == other.numFields &&
+                    size == other.size);
+        }
+    }
+
+    /**
+     * The base size of the struct.
+     */
+    protected final int mEncodedBaseSize;
+
+    /**
+     * Constructor.
+     */
+    protected Struct(int encodedBaseSize) {
+        this.mEncodedBaseSize = encodedBaseSize;
+    }
+
+    /**
+     * Use the given encoder to serialized this struct.
+     */
+    protected abstract void encode(Encoder encoder);
+
+    /**
+     * Returns the serialization of the struct. This method can close Handles.
+     *
+     * @param core the |Core| implementation used to generate handles. Only used if the |Struct|
+     *            being encoded contains interfaces, can be |null| otherwise.
+     */
+    public Message serialize(Core core) {
+        Encoder encoder = new Encoder(core, mEncodedBaseSize);
+        encode(encoder);
+        return encoder.getMessage();
+    }
+
+    /**
+     * Returns the serialization of the struct prepended with the given header.
+     *
+     * @param header the header to prepend to the returned message.
+     * @param core the |Core| implementation used to generate handles. Only used if the |Struct|
+     *            being encoded contains interfaces, can be |null| otherwise.
+     */
+    public ServiceMessage serializeWithHeader(Core core, MessageHeader header) {
+        Encoder encoder = new Encoder(core, mEncodedBaseSize + header.getSize());
+        header.encode(encoder);
+        encode(encoder);
+        return new ServiceMessage(encoder.getMessage(), header);
+    }
+
+}
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/AsyncWaiter.java b/mojo/public/java/system/src/org/chromium/mojo/system/AsyncWaiter.java
new file mode 100644
index 0000000..474de4b
--- /dev/null
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/AsyncWaiter.java
@@ -0,0 +1,53 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.system;
+
+import org.chromium.mojo.system.Core.HandleSignals;
+
+/**
+ * A class which implements the {@link AsyncWaiter} allows asynchronously waiting on a background
+ * thread.
+ */
+public interface AsyncWaiter {
+
+    /**
+     * Allows cancellation of an asyncWait operation.
+     */
+    interface Cancellable {
+        /**
+         * Cancels an asyncWait operation. Has no effect if the operation has already been canceled
+         * or the callback has already been called.
+         * <p>
+         * Must be called from the same thread as {@link AsyncWaiter#asyncWait} was called from.
+         */
+        void cancel();
+    }
+
+    /**
+     * Callback passed to {@link AsyncWaiter#asyncWait}.
+     */
+    public interface Callback {
+        /**
+         * Called when the handle is ready.
+         */
+        public void onResult(int result);
+
+        /**
+         * Called when an error occurred while waiting.
+         */
+        public void onError(MojoException exception);
+    }
+
+    /**
+     * Asynchronously call wait on a background thread. The given {@link Callback} will be notified
+     * of the result of the wait on the same thread as asyncWait was called.
+     *
+     * @return a {@link Cancellable} object that can be used to cancel waiting. The cancellable
+     *         should only be used on the current thread, and becomes invalid once the callback has
+     *         been notified.
+     */
+    Cancellable asyncWait(Handle handle, HandleSignals signals, long deadline, Callback callback);
+
+}
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/Core.java b/mojo/public/java/system/src/org/chromium/mojo/system/Core.java
new file mode 100644
index 0000000..d6c8e7d
--- /dev/null
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/Core.java
@@ -0,0 +1,195 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.system;
+
+import java.util.List;
+
+/**
+ * Core mojo interface giving access to the base operations. See |src/mojo/public/c/system/core.h|
+ * for the underlying api.
+ */
+public interface Core {
+
+    /**
+     * Used to indicate an infinite deadline (timeout).
+     */
+    public static final long DEADLINE_INFINITE = -1;
+
+    /**
+     * Signals for the wait operations on handles.
+     */
+    public static class HandleSignals extends Flags<HandleSignals> {
+        /**
+         * Constructor.
+         *
+         * @param signals the serialized signals.
+         */
+        private HandleSignals(int signals) {
+            super(signals);
+        }
+
+        private static final int FLAG_NONE = 0;
+        private static final int FLAG_READABLE = 1 << 0;
+        private static final int FLAG_WRITABLE = 1 << 1;
+
+        /**
+         * Immutable signals.
+         */
+        public static final HandleSignals NONE = HandleSignals.none().immutable();
+        public static final HandleSignals READABLE =
+                HandleSignals.none().setReadable(true).immutable();
+        public static final HandleSignals WRITABLE =
+                HandleSignals.none().setWritable(true).immutable();
+
+        /**
+         * Change the readable bit of this signal.
+         *
+         * @param readable the new value of the readable bit.
+         * @return this.
+         */
+        public HandleSignals setReadable(boolean readable) {
+            return setFlag(FLAG_READABLE, readable);
+        }
+
+        /**
+         * Change the writable bit of this signal.
+         *
+         * @param writable the new value of the writable bit.
+         * @return this.
+         */
+        public HandleSignals setWritable(boolean writable) {
+            return setFlag(FLAG_WRITABLE, writable);
+        }
+
+        /**
+         * @return a signal with no bit set.
+         */
+        public static HandleSignals none() {
+            return new HandleSignals(FLAG_NONE);
+        }
+
+    }
+
+    /**
+     * @return a platform-dependent monotonically increasing tick count representing "right now."
+     */
+    public long getTimeTicksNow();
+
+    /**
+     * Waits on the given |handle| until the state indicated by |signals| is satisfied or until
+     * |deadline| has passed.
+     *
+     * @return |MojoResult.OK| if some signal in |signals| was satisfied (or is already satisfied).
+     *         <p>
+     *         |MojoResult.DEADLINE_EXCEEDED| if the deadline has passed without any of the signals
+     *         being satisfied.
+     *         <p>
+     *         |MojoResult.CANCELLED| if |handle| is closed concurrently by another thread.
+     *         <p>
+     *         |MojoResult.FAILED_PRECONDITION| if it is or becomes impossible that any flag in
+     *         |signals| will ever be satisfied (for example, if the other endpoint is close).
+     */
+    public int wait(Handle handle, HandleSignals signals, long deadline);
+
+    /**
+     * Result for the |waitMany| method.
+     */
+    public static class WaitManyResult {
+
+        /**
+         * See |wait| for the different possible values.
+         */
+        private int mMojoResult;
+        /**
+         * If |mojoResult| is |MojoResult.OK|, |handleIndex| is the index of the handle for which
+         * some flag was satisfied (or is already satisfied). If |mojoResult| is
+         * |MojoResult.CANCELLED| or |MojoResult.FAILED_PRECONDITION|, |handleIndex| is the index of
+         * the handle for which the issue occurred.
+         */
+        private int mHandleIndex;
+
+        /**
+         * @return the mojoResult
+         */
+        public int getMojoResult() {
+            return mMojoResult;
+        }
+
+        /**
+         * @param mojoResult the mojoResult to set
+         */
+        public void setMojoResult(int mojoResult) {
+            mMojoResult = mojoResult;
+        }
+
+        /**
+         * @return the handleIndex
+         */
+        public int getHandleIndex() {
+            return mHandleIndex;
+        }
+
+        /**
+         * @param handleIndex the handleIndex to set
+         */
+        public void setHandleIndex(int handleIndex) {
+            mHandleIndex = handleIndex;
+        }
+    }
+
+    /**
+     * Waits on handle in |handles| for at least one of them to satisfy the associated
+     * |HandleSignals|, or until |deadline| has passed.
+     *
+     * @returns a |WaitManyResult|.
+     */
+    public WaitManyResult waitMany(List<Pair<Handle, HandleSignals>> handles, long deadline);
+
+    /**
+     * Creates a message pipe, which is a bidirectional communication channel for framed data (i.e.,
+     * messages), with the given options. Messages can contain plain data and/or Mojo handles.
+     *
+     * @return the set of handles for the two endpoints (ports) of the message pipe.
+     */
+    public Pair<MessagePipeHandle, MessagePipeHandle> createMessagePipe(
+            MessagePipeHandle.CreateOptions options);
+
+    /**
+     * Creates a data pipe, which is a unidirectional communication channel for unframed data, with
+     * the given options. Data is unframed, but must come as (multiples of) discrete elements, of
+     * the size given in |options|. See |DataPipe.CreateOptions| for a description of the different
+     * options available for data pipes. |options| may be set to null for a data pipe with the
+     * default options (which will have an element size of one byte and have some system-dependent
+     * capacity).
+     *
+     * @return the set of handles for the two endpoints of the data pipe.
+     */
+    public Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> createDataPipe(
+            DataPipe.CreateOptions options);
+
+    /**
+     * Creates a buffer that can be shared between applications (by duplicating the handle -- see
+     * |SharedBufferHandle.duplicate()| -- and passing it over a message pipe). To access the
+     * buffer, one must call |SharedBufferHandle.map|.
+     *
+     * @return the new |SharedBufferHandle|.
+     */
+    public SharedBufferHandle createSharedBuffer(SharedBufferHandle.CreateOptions options,
+            long numBytes);
+
+    /**
+     * Acquires a handle from the native side. The handle will be owned by the returned object and
+     * must not be closed outside of it.
+     *
+     * @return a new {@link UntypedHandle} representing the native handle.
+     */
+    public UntypedHandle acquireNativeHandle(int handle);
+
+    /**
+     * Returns a default implementation of {@link AsyncWaiter}.
+     */
+    public AsyncWaiter getDefaultAsyncWaiter();
+
+}
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/DataPipe.java b/mojo/public/java/system/src/org/chromium/mojo/system/DataPipe.java
new file mode 100644
index 0000000..4cd74e1
--- /dev/null
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/DataPipe.java
@@ -0,0 +1,335 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.system;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Interface for data pipes. A data pipe is a unidirectional communication channel for unframed
+ * data. Data is unframed, but must come as (multiples of) discrete elements, of the size given at
+ * creation time.
+ */
+public interface DataPipe {
+
+    /**
+     * Flags for the data pipe creation operation.
+     */
+    public static class CreateFlags extends Flags<CreateFlags> {
+        private static final int FLAG_NONE = 0;
+        private static final int FLAG_MAY_DISCARD = 1 << 0;
+
+        /**
+         * Immutable flag with not bit set.
+         */
+        public static final CreateFlags NONE = CreateFlags.none().immutable();
+
+        /**
+         * Dedicated constructor.
+         *
+         * @param flags initial value of the flags.
+         */
+        protected CreateFlags(int flags) {
+            super(flags);
+        }
+
+        /**
+         * Change the may-discard bit of this flag. This indicates that the data pipe may discard
+         * data for whatever reason; best-effort delivery. In particular, if the capacity is
+         * reached, old data may be discard to make room for new data.
+         *
+         * @param mayDiscard the new value of the may-discard bit.
+         * @return this.
+         */
+        public CreateFlags setMayDiscard(boolean mayDiscard) {
+            return setFlag(FLAG_MAY_DISCARD, mayDiscard);
+        }
+
+        /**
+         * @return flags with no bit set.
+         */
+        public static CreateFlags none() {
+            return new CreateFlags(FLAG_NONE);
+        }
+
+    }
+
+    /**
+     * Used to specify creation parameters for a data pipe to |Core.createDataPipe()|.
+     */
+    public static class CreateOptions {
+
+        /**
+         * Used to specify different modes of operation, see |DataPipe.CreateFlags|.
+         */
+        private CreateFlags mFlags = CreateFlags.none();
+        /**
+         * The size of an element, in bytes. All transactions and buffers will consist of an
+         * integral number of elements. Must be nonzero.
+         */
+        private int mElementNumBytes;
+        /**
+         * The capacity of the data pipe, in number of bytes; must be a multiple of
+         * |element_num_bytes|. The data pipe will always be able to queue AT LEAST this much data.
+         * Set to zero to opt for a system-dependent automatically-calculated capacity (which will
+         * always be at least one element).
+         */
+        private int mCapacityNumBytes;
+
+        /**
+         * @return the flags
+         */
+        public CreateFlags getFlags() {
+            return mFlags;
+        }
+
+        /**
+         * @return the elementNumBytes
+         */
+        public int getElementNumBytes() {
+            return mElementNumBytes;
+        }
+
+        /**
+         * @param elementNumBytes the elementNumBytes to set
+         */
+        public void setElementNumBytes(int elementNumBytes) {
+            mElementNumBytes = elementNumBytes;
+        }
+
+        /**
+         * @return the capacityNumBytes
+         */
+        public int getCapacityNumBytes() {
+            return mCapacityNumBytes;
+        }
+
+        /**
+         * @param capacityNumBytes the capacityNumBytes to set
+         */
+        public void setCapacityNumBytes(int capacityNumBytes) {
+            mCapacityNumBytes = capacityNumBytes;
+        }
+
+    }
+
+    /**
+     * Flags for the write operations on MessagePipeHandle .
+     */
+    public static class WriteFlags extends Flags<WriteFlags> {
+        private static final int FLAG_NONE = 0;
+        private static final int FLAG_ALL_OR_NONE = 1 << 0;
+
+        /**
+         * Immutable flag with not bit set.
+         */
+        public static final WriteFlags NONE = WriteFlags.none().immutable();
+
+        /**
+         * Dedicated constructor.
+         *
+         * @param flags initial value of the flags.
+         */
+        private WriteFlags(int flags) {
+            super(flags);
+        }
+
+        /**
+         * Change the all-or-none bit of those flags. If set, write either all the elements
+         * requested or none of them.
+         *
+         * @param allOrNone the new value of all-or-none bit.
+         * @return this.
+         */
+        public WriteFlags setAllOrNone(boolean allOrNone) {
+            return setFlag(FLAG_ALL_OR_NONE, allOrNone);
+        }
+
+        /**
+         * @return a flag with no bit set.
+         */
+        public static WriteFlags none() {
+            return new WriteFlags(FLAG_NONE);
+        }
+    }
+
+    /**
+     * Flags for the read operations on MessagePipeHandle.
+     */
+    public static class ReadFlags extends Flags<ReadFlags> {
+        private static final int FLAG_NONE = 0;
+        private static final int FLAG_ALL_OR_NONE = 1 << 0;
+        private static final int FLAG_QUERY = 1 << 2;
+
+        /**
+         * Immutable flag with not bit set.
+         */
+        public static final ReadFlags NONE = ReadFlags.none().immutable();
+
+        /**
+         * Dedicated constructor.
+         *
+         * @param flags initial value of the flag.
+         */
+        private ReadFlags(int flags) {
+            super(flags);
+        }
+
+        /**
+         * Change the all-or-none bit of this flag. If set, read (or discard) either the requested
+         * number of elements or none.
+         *
+         * @param allOrNone the new value of the all-or-none bit.
+         * @return this.
+         */
+        public ReadFlags setAllOrNone(boolean allOrNone) {
+            return setFlag(FLAG_ALL_OR_NONE, allOrNone);
+        }
+
+        /**
+         * Change the query bit of this flag. If set query the number of elements available to read.
+         * Mutually exclusive with |dicard| and |allOrNone| is ignored if this flag is set.
+         *
+         * @param query the new value of the query bit.
+         * @return this.
+         */
+        public ReadFlags query(boolean query) {
+            return setFlag(FLAG_QUERY, query);
+        }
+
+        /**
+         * @return a flag with no bit set.
+         */
+        public static ReadFlags none() {
+            return new ReadFlags(FLAG_NONE);
+        }
+
+    }
+
+    /**
+     * Handle for the producer part of a data pipe.
+     */
+    public static interface ProducerHandle extends Handle {
+
+        /**
+         * @see org.chromium.mojo.system.Handle#pass()
+         */
+        @Override
+        public ProducerHandle pass();
+
+        /**
+         * Writes the given data to the data pipe producer. |elements| points to data; the buffer
+         * must be a direct ByteBuffer and the limit should be a multiple of the data pipe's element
+         * size. If |allOrNone| is set in |flags|, either all the data will be written or none is.
+         * <p>
+         * On success, returns the amount of data that was actually written.
+         * <p>
+         * Note: If the data pipe has the "may discard" option flag (specified on creation), this
+         * will discard as much data as required to write the given data, starting with the earliest
+         * written data that has not been consumed. However, even with "may discard", if the buffer
+         * limit is greater than the data pipe's capacity (and |allOrNone| is not set), this will
+         * write the maximum amount possible (namely, the data pipe's capacity) and return that
+         * amount. It will *not* discard data from |elements|.
+         *
+         * @return number of written bytes.
+         */
+        public int writeData(ByteBuffer elements, WriteFlags flags);
+
+        /**
+         * Begins a two-phase write to the data pipe producer . On success, returns a |ByteBuffer|
+         * to which the caller can write. If flags has |allOrNone| set, then the buffer capacity
+         * will be at least as large as |numBytes|, which must also be a multiple of the element
+         * size (if |allOrNone| is not set, |numBytes| is ignored and the caller must check the
+         * capacity of the buffer).
+         * <p>
+         * During a two-phase write, this handle is *not* writable. E.g., if another thread tries to
+         * write to it, it will throw a |MojoException| with code |MojoResult.BUSY|; that thread can
+         * then wait for this handle to become writable again.
+         * <p>
+         * Once the caller has finished writing data to the buffer, it should call |endWriteData()|
+         * to specify the amount written and to complete the two-phase write.
+         * <p>
+         * Note: If the data pipe has the "may discard" option flag (specified on creation) and
+         * |flags| has |allOrNone| set, this may discard some data.
+         *
+         * @return The buffer to write to.
+         */
+        public ByteBuffer beginWriteData(int numBytes, WriteFlags flags);
+
+        /**
+         * Ends a two-phase write to the data pipe producer that was begun by a call to
+         * |beginWriteData()| on the same handle. |numBytesWritten| should indicate the amount of
+         * data actually written; it must be less than or equal to the capacity of the buffer
+         * returned by |beginWriteData()| and must be a multiple of the element size. The buffer
+         * returned from |beginWriteData()| must have been filled with exactly |numBytesWritten|
+         * bytes of data.
+         * <p>
+         * On failure, the two-phase write (if any) is ended (so the handle may become writable
+         * again, if there's space available) but no data written to the buffer is "put into" the
+         * data pipe.
+         */
+        public void endWriteData(int numBytesWritten);
+    }
+
+    /**
+     * Handle for the consumer part of a data pipe.
+     */
+    public static interface ConsumerHandle extends Handle {
+
+        /**
+         * @see org.chromium.mojo.system.Handle#pass()
+         */
+        @Override
+        public ConsumerHandle pass();
+
+       /**
+         * Discards data on the data pie consumer. This method discards up to |numBytes| (which
+         * again be a multiple of the element size) bytes of data, returning the amount actually
+         * discarded. if |flags| has |allOrNone|, it will either discard exactly |numBytes| bytes of
+         * data or none. In this case, |query| must not be set.
+         */
+        public int discardData(int numBytes, ReadFlags flags);
+
+        /**
+         * Reads data from the data pipe consumer. May also be used to query the amount of data
+         * available. If |flags| has not |query| set, this tries to read up to |elements| capacity
+         * (which must be a multiple of the data pipe's element size) bytes of data to |elements|
+         * and returns the amount actually read. |elements| must be a direct ByteBuffer. If flags
+         * has |allOrNone| set, it will either read exactly |elements| capacity bytes of data or
+         * none.
+         * <p>
+         * If flags has |query| set, it queries the amount of data available, returning the number
+         * of bytes available. In this case |allOrNone| is ignored, as are |elements|.
+         */
+        public int readData(ByteBuffer elements, ReadFlags flags);
+
+        /**
+         * Begins a two-phase read from the data pipe consumer. On success, returns a |ByteBuffer|
+         * from which the caller can read up to its limit bytes of data. If flags has |allOrNone|
+         * set, then the limit will be at least as large as |numBytes|, which must also be a
+         * multiple of the element size (if |allOrNone| is not set, |numBytes| is ignored). |flags|
+         * must not have |query| set.
+         * <p>
+         * During a two-phase read, this handle is *not* readable. E.g., if another thread tries to
+         * read from it, it will throw a |MojoException| with code |MojoResult.BUSY|; that thread
+         * can then wait for this handle to become readable again.
+         * <p>
+         * Once the caller has finished reading data from the buffer, it should call |endReadData()|
+         * to specify the amount read and to complete the two-phase read.
+         */
+        public ByteBuffer beginReadData(int numBytes, ReadFlags flags);
+
+        /**
+         * Ends a two-phase read from the data pipe consumer that was begun by a call to
+         * |beginReadData()| on the same handle. |numBytesRead| should indicate the amount of data
+         * actually read; it must be less than or equal to the limit of the buffer returned by
+         * |beginReadData()| and must be a multiple of the element size.
+         * <p>
+         * On failure, the two-phase read (if any) is ended (so the handle may become readable
+         * again) but no data is "removed" from the data pipe.
+         */
+        public void endReadData(int numBytesRead);
+    }
+
+}
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/Flags.java b/mojo/public/java/system/src/org/chromium/mojo/system/Flags.java
new file mode 100644
index 0000000..dd2b00a
--- /dev/null
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/Flags.java
@@ -0,0 +1,63 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.system;
+
+/**
+ * Base class for bit field used as flags.
+ *
+ * @param <F> the type of the flags.
+ */
+public abstract class Flags<F extends Flags<F>> {
+    private int mFlags;
+    private boolean mImmutable;
+
+    /**
+     * Dedicated constructor.
+     *
+     * @param flags initial value of the flag.
+     */
+    protected Flags(int flags) {
+        mImmutable = false;
+        mFlags = flags;
+    }
+
+    /**
+     * @return the computed flag.
+     */
+    public int getFlags() {
+        return mFlags;
+    }
+
+    /**
+     * Change the given bit of this flag.
+     *
+     * @param value the new value of given bit.
+     * @return this.
+     */
+    protected F setFlag(int flag, boolean value) {
+        if (mImmutable) {
+            throw new UnsupportedOperationException("Flags is immutable.");
+        }
+        if (value) {
+            mFlags |= flag;
+        } else {
+            mFlags &= ~flag;
+        }
+        @SuppressWarnings("unchecked")
+        F f = (F) this;
+        return f;
+    }
+
+    /**
+     * Makes this flag immutable. This is a non-reversable operation.
+     */
+    protected F immutable() {
+        mImmutable = true;
+        @SuppressWarnings("unchecked")
+        F f = (F) this;
+        return f;
+    }
+
+}
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/Handle.java b/mojo/public/java/system/src/org/chromium/mojo/system/Handle.java
new file mode 100644
index 0000000..907e2b9
--- /dev/null
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/Handle.java
@@ -0,0 +1,59 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.system;
+
+import java.io.Closeable;
+
+/**
+ * A generic mojo handle.
+ */
+public interface Handle extends Closeable {
+
+    /**
+     * Closes the given |handle|.
+     * <p>
+     * Concurrent operations on |handle| may succeed (or fail as usual) if they happen before the
+     * close, be cancelled with result |MojoResult.CANCELLED| if they properly overlap (this is
+     * likely the case with |wait()|, etc.), or fail with |MojoResult.INVALID_ARGUMENT| if they
+     * happen after.
+     */
+    @Override
+    public void close();
+
+    /**
+     * @see Core#wait(Handle, Core.HandleSignals, long)
+     */
+    public int wait(Core.HandleSignals signals, long deadline);
+
+    /**
+     * @return whether the handle is valid. A handle is valid until it has been explicitly closed or
+     *         send through a message pipe via |MessagePipeHandle.writeMessage|.
+     */
+    public boolean isValid();
+
+    /**
+     * Converts this handle into an {@link UntypedHandle}, invalidating this handle.
+     */
+    public UntypedHandle toUntypedHandle();
+
+    /**
+     * Returns the {@link Core} implementation for this handle. Can be null if this handle is
+     * invalid.
+     */
+    public Core getCore();
+
+    /**
+     * Passes ownership of the handle from this handle to the newly created Handle object,
+     * invalidating this handle object in the process.
+     */
+    public Handle pass();
+
+    /**
+     * Releases the native handle backed by this {@link Handle}. The caller owns the handle and must
+     * close it.
+     */
+    public int releaseNativeHandle();
+
+}
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/InvalidHandle.java b/mojo/public/java/system/src/org/chromium/mojo/system/InvalidHandle.java
new file mode 100644
index 0000000..12f0457
--- /dev/null
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/InvalidHandle.java
@@ -0,0 +1,219 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.system;
+
+import org.chromium.mojo.system.Core.HandleSignals;
+import org.chromium.mojo.system.DataPipe.ConsumerHandle;
+import org.chromium.mojo.system.DataPipe.ProducerHandle;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * A handle that will always be invalid.
+ */
+public class InvalidHandle implements UntypedHandle, MessagePipeHandle, ConsumerHandle,
+        ProducerHandle, SharedBufferHandle {
+
+    /**
+     * Instance singleton.
+     */
+    public static final InvalidHandle INSTANCE = new InvalidHandle();
+
+    /**
+     * Private constructor.
+     */
+    private InvalidHandle() {
+    }
+
+    /**
+     * @see Handle#close()
+     */
+    @Override
+    public void close() {
+        // Do nothing.
+    }
+
+    /**
+     * @see Handle#wait(Core.HandleSignals, long)
+     */
+    @Override
+    public int wait(HandleSignals signals, long deadline) {
+        throw new MojoException(MojoResult.INVALID_ARGUMENT);
+    }
+
+    /**
+     * @see Handle#isValid()
+     */
+    @Override
+    public boolean isValid() {
+        return false;
+    }
+
+    /**
+     * @see Handle#getCore()
+     */
+    @Override
+    public Core getCore() {
+        return null;
+    }
+
+    /**
+     * @see org.chromium.mojo.system.Handle#pass()
+     */
+    @Override
+    public InvalidHandle pass() {
+        return this;
+    }
+
+    /**
+     * @see Handle#toUntypedHandle()
+     */
+    @Override
+    public UntypedHandle toUntypedHandle() {
+        return this;
+    }
+
+    /**
+     * @see Handle#releaseNativeHandle()
+     */
+    @Override
+    public int releaseNativeHandle() {
+        return -1;
+    }
+
+    /**
+     * @see UntypedHandle#toMessagePipeHandle()
+     */
+    @Override
+    public MessagePipeHandle toMessagePipeHandle() {
+        return this;
+    }
+
+    /**
+     * @see UntypedHandle#toDataPipeConsumerHandle()
+     */
+    @Override
+    public ConsumerHandle toDataPipeConsumerHandle() {
+        return this;
+    }
+
+    /**
+     * @see UntypedHandle#toDataPipeProducerHandle()
+     */
+    @Override
+    public ProducerHandle toDataPipeProducerHandle() {
+        return this;
+    }
+
+    /**
+     * @see UntypedHandle#toSharedBufferHandle()
+     */
+    @Override
+    public SharedBufferHandle toSharedBufferHandle() {
+        return this;
+    }
+
+    /**
+     * @see SharedBufferHandle#duplicate(SharedBufferHandle.DuplicateOptions)
+     */
+    @Override
+    public SharedBufferHandle duplicate(DuplicateOptions options) {
+        throw new MojoException(MojoResult.INVALID_ARGUMENT);
+    }
+
+    /**
+     * @see SharedBufferHandle#map(long, long, SharedBufferHandle.MapFlags)
+     */
+    @Override
+    public ByteBuffer map(long offset, long numBytes, MapFlags flags) {
+        throw new MojoException(MojoResult.INVALID_ARGUMENT);
+    }
+
+    /**
+     * @see SharedBufferHandle#unmap(java.nio.ByteBuffer)
+     */
+    @Override
+    public void unmap(ByteBuffer buffer) {
+        throw new MojoException(MojoResult.INVALID_ARGUMENT);
+    }
+
+    /**
+     * @see DataPipe.ProducerHandle#writeData(java.nio.ByteBuffer, DataPipe.WriteFlags)
+     */
+    @Override
+    public int writeData(ByteBuffer elements, DataPipe.WriteFlags flags) {
+        throw new MojoException(MojoResult.INVALID_ARGUMENT);
+    }
+
+    /**
+     * @see DataPipe.ProducerHandle#beginWriteData(int, DataPipe.WriteFlags)
+     */
+    @Override
+    public ByteBuffer beginWriteData(int numBytes,
+            DataPipe.WriteFlags flags) {
+        throw new MojoException(MojoResult.INVALID_ARGUMENT);
+    }
+
+    /**
+     * @see DataPipe.ProducerHandle#endWriteData(int)
+     */
+    @Override
+    public void endWriteData(int numBytesWritten) {
+        throw new MojoException(MojoResult.INVALID_ARGUMENT);
+    }
+
+    /**
+     * @see DataPipe.ConsumerHandle#discardData(int, DataPipe.ReadFlags)
+     */
+    @Override
+    public int discardData(int numBytes, DataPipe.ReadFlags flags) {
+        throw new MojoException(MojoResult.INVALID_ARGUMENT);
+    }
+
+    /**
+     * @see DataPipe.ConsumerHandle#readData(java.nio.ByteBuffer, DataPipe.ReadFlags)
+     */
+    @Override
+    public int readData(ByteBuffer elements, DataPipe.ReadFlags flags) {
+        throw new MojoException(MojoResult.INVALID_ARGUMENT);
+    }
+
+    /**
+     * @see DataPipe.ConsumerHandle#beginReadData(int, DataPipe.ReadFlags)
+     */
+    @Override
+    public ByteBuffer beginReadData(int numBytes,
+            DataPipe.ReadFlags flags) {
+        throw new MojoException(MojoResult.INVALID_ARGUMENT);
+    }
+
+    /**
+     * @see DataPipe.ConsumerHandle#endReadData(int)
+     */
+    @Override
+    public void endReadData(int numBytesRead) {
+        throw new MojoException(MojoResult.INVALID_ARGUMENT);
+    }
+
+    /**
+     * @see MessagePipeHandle#writeMessage(java.nio.ByteBuffer, java.util.List,
+     *      MessagePipeHandle.WriteFlags)
+     */
+    @Override
+    public void writeMessage(ByteBuffer bytes, List<? extends Handle> handles, WriteFlags flags) {
+        throw new MojoException(MojoResult.INVALID_ARGUMENT);
+    }
+
+    /**
+     * @see MessagePipeHandle#readMessage(java.nio.ByteBuffer, int, MessagePipeHandle.ReadFlags)
+     */
+    @Override
+    public ReadMessageResult readMessage(ByteBuffer bytes, int maxNumberOfHandles,
+            ReadFlags flags) {
+        throw new MojoException(MojoResult.INVALID_ARGUMENT);
+    }
+
+}
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/MessagePipeHandle.java b/mojo/public/java/system/src/org/chromium/mojo/system/MessagePipeHandle.java
new file mode 100644
index 0000000..60ac682
--- /dev/null
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/MessagePipeHandle.java
@@ -0,0 +1,242 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.system;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * Message pipes are bidirectional communication channel for framed data (i.e., messages). Messages
+ * can contain plain data and/or Mojo handles.
+ */
+public interface MessagePipeHandle extends Handle {
+
+    /**
+     * Flags for the message pipe creation operation.
+     */
+    public static class CreateFlags extends Flags<CreateFlags> {
+        private static final int FLAG_NONE = 0;
+
+        /**
+         * Immutable flag with not bit set.
+         */
+        public static final CreateFlags NONE = CreateFlags.none().immutable();
+
+        /**
+         * Dedicated constructor.
+         *
+         * @param flags initial value of the flags.
+         */
+        protected CreateFlags(int flags) {
+            super(flags);
+        }
+
+        /**
+         * @return flags with no bit set.
+         */
+        public static CreateFlags none() {
+            return new CreateFlags(FLAG_NONE);
+        }
+
+    }
+
+    /**
+     * Used to specify creation parameters for a message pipe to |Core#createMessagePipe()|.
+     */
+    public static class CreateOptions {
+        private CreateFlags mFlags = CreateFlags.NONE;
+
+        /**
+         * @return the flags
+         */
+        public CreateFlags getFlags() {
+            return mFlags;
+        }
+
+    }
+
+    /**
+     * Flags for the write operations on MessagePipeHandle .
+     */
+    public static class WriteFlags extends Flags<WriteFlags> {
+        private static final int FLAG_NONE = 0;
+
+        /**
+         * Immutable flag with no bit set.
+         */
+        public static final WriteFlags NONE = WriteFlags.none().immutable();
+
+        /**
+         * Dedicated constructor.
+         *
+         * @param flags initial value of the flag.
+         */
+        private WriteFlags(int flags) {
+            super(flags);
+        }
+
+        /**
+         * @return a flag with no bit set.
+         */
+        public static WriteFlags none() {
+            return new WriteFlags(FLAG_NONE);
+        }
+    }
+
+    /**
+     * Flags for the read operations on MessagePipeHandle.
+     */
+    public static class ReadFlags extends Flags<ReadFlags> {
+        private static final int FLAG_NONE = 0;
+        private static final int FLAG_MAY_DISCARD = 1 << 0;
+
+        /**
+         * Immutable flag with no bit set.
+         */
+        public static final ReadFlags NONE = ReadFlags.none().immutable();
+
+        /**
+         * Dedicated constructor.
+         *
+         * @param flags initial value of the flag.
+         */
+        private ReadFlags(int flags) {
+            super(flags);
+        }
+
+        /**
+         * Change the may-discard bit of this flag. If set, if the message is unable to be read for
+         * whatever reason (e.g., the caller-supplied buffer is too small), discard the message
+         * (i.e., simply dequeue it).
+         *
+         * @param mayDiscard the new value of the may-discard bit.
+         * @return this.
+         */
+        public ReadFlags setMayDiscard(boolean mayDiscard) {
+            return setFlag(FLAG_MAY_DISCARD, mayDiscard);
+        }
+
+        /**
+         * @return a flag with no bit set.
+         */
+        public static ReadFlags none() {
+            return new ReadFlags(FLAG_NONE);
+        }
+
+    }
+
+    /**
+     * Result of the |readMessage| method.
+     */
+    public static class ReadMessageResult {
+        /**
+         * The MojoResult value of the read call.
+         */
+        private int mMojoResult;
+        /**
+         * If a message was read, the size in bytes of the message, otherwise the size in bytes of
+         * the next message.
+         */
+        private int mMessageSize;
+        /**
+         * If a message was read, the number of handles contained in the message, otherwise the
+         * number of handles contained in the next message.
+         */
+        private int mHandlesCount;
+        /**
+         * If a message was read, the handles contained in the message, undefined otherwise.
+         */
+        private List<UntypedHandle> mHandles;
+
+        /**
+         * @return the mojoResult
+         */
+        public int getMojoResult() {
+            return mMojoResult;
+        }
+
+        /**
+         * @param mojoResult the mojoResult to set
+         */
+        public void setMojoResult(int mojoResult) {
+            mMojoResult = mojoResult;
+        }
+
+        /**
+         * @return the messageSize
+         */
+        public int getMessageSize() {
+            return mMessageSize;
+        }
+
+        /**
+         * @param messageSize the messageSize to set
+         */
+        public void setMessageSize(int messageSize) {
+            mMessageSize = messageSize;
+        }
+
+        /**
+         * @return the handlesCount
+         */
+        public int getHandlesCount() {
+            return mHandlesCount;
+        }
+
+        /**
+         * @param handlesCount the handlesCount to set
+         */
+        public void setHandlesCount(int handlesCount) {
+            mHandlesCount = handlesCount;
+        }
+
+        /**
+         * @return the handles
+         */
+        public List<UntypedHandle> getHandles() {
+            return mHandles;
+        }
+
+        /**
+         * @param handles the handles to set
+         */
+        public void setHandles(List<UntypedHandle> handles) {
+            mHandles = handles;
+        }
+    }
+
+    /**
+     * @see org.chromium.mojo.system.Handle#pass()
+     */
+    @Override
+    public MessagePipeHandle pass();
+
+    /**
+     * Writes a message to the message pipe endpoint, with message data specified by |bytes| and
+     * attached handles specified by |handles|, and options specified by |flags|. If there is no
+     * message data, |bytes| may be null, otherwise it must be a direct ByteBuffer. If there are no
+     * attached handles, |handles| may be null.
+     * <p>
+     * If handles are attached, on success the handles will no longer be valid (the receiver will
+     * receive equivalent, but logically different, handles). Handles to be sent should not be in
+     * simultaneous use (e.g., on another thread).
+     */
+    void writeMessage(ByteBuffer bytes, List<? extends Handle> handles, WriteFlags flags);
+
+    /**
+     * Reads a message from the message pipe endpoint; also usable to query the size of the next
+     * message or discard the next message. |bytes| indicate the buffer/buffer size to receive the
+     * message data (if any) and |maxNumberOfHandles| indicate the maximum handle count to receive
+     * the attached handles (if any). |bytes| is optional. If null, |maxNumberOfHandles| must be
+     * zero, and the return value will indicate the size of the next message. If non-null, it must
+     * be a direct ByteBuffer and the return value will indicate if the message was read or not. If
+     * the message was read its content will be in |bytes|, and the attached handles will be in the
+     * return value. Partial reads are NEVER done. Either a full read is done and |wasMessageRead|
+     * will be true, or the read is NOT done and |wasMessageRead| will be false (if |mayDiscard| was
+     * set, the message is also discarded in this case).
+     */
+    ReadMessageResult readMessage(ByteBuffer bytes, int maxNumberOfHandles,
+            ReadFlags flags);
+}
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/MojoException.java b/mojo/public/java/system/src/org/chromium/mojo/system/MojoException.java
new file mode 100644
index 0000000..e06f647
--- /dev/null
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/MojoException.java
@@ -0,0 +1,36 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.system;
+
+/**
+ * Exception for the core mojo API.
+ */
+public class MojoException extends RuntimeException {
+
+    private final int mCode;
+
+    /**
+     * Constructor.
+     */
+    public MojoException(int code) {
+        mCode = code;
+    }
+
+    /**
+     * The mojo result code associated with this exception. See {@link MojoResult} for possible
+     * values.
+     */
+    public int getMojoResult() {
+        return mCode;
+    }
+
+    /**
+     * @see Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "MojoResult(" + mCode + "): " + MojoResult.describe(mCode);
+    }
+}
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/MojoResult.java b/mojo/public/java/system/src/org/chromium/mojo/system/MojoResult.java
new file mode 100644
index 0000000..a829c83
--- /dev/null
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/MojoResult.java
@@ -0,0 +1,82 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.system;
+
+/**
+ * The different mojo result codes.
+ */
+public final class MojoResult {
+    public static final int OK = 0;
+    public static final int CANCELLED = -1;
+    public static final int UNKNOWN = -2;
+    public static final int INVALID_ARGUMENT = -3;
+    public static final int DEADLINE_EXCEEDED = -4;
+    public static final int NOT_FOUND = -5;
+    public static final int ALREADY_EXISTS = -6;
+    public static final int PERMISSION_DENIED = -7;
+    public static final int RESOURCE_EXHAUSTED = -8;
+    public static final int FAILED_PRECONDITION = -9;
+    public static final int ABORTED = -10;
+    public static final int OUT_OF_RANGE = -11;
+    public static final int UNIMPLEMENTED = -12;
+    public static final int INTERNAL = -13;
+    public static final int UNAVAILABLE = -14;
+    public static final int DATA_LOSS = -15;
+    public static final int BUSY = -16;
+    public static final int SHOULD_WAIT = -17;
+
+    /**
+     * never instantiate.
+     */
+    private MojoResult() {
+    }
+
+    /**
+     * Describes the given result code.
+     */
+    public static String describe(int mCode) {
+        switch (mCode) {
+            case OK:
+                return "OK";
+            case CANCELLED:
+                return "CANCELLED";
+            case UNKNOWN:
+                return "UNKNOWN";
+            case INVALID_ARGUMENT:
+                return "INVALID_ARGUMENT";
+            case DEADLINE_EXCEEDED:
+                return "DEADLINE_EXCEEDED";
+            case NOT_FOUND:
+                return "NOT_FOUND";
+            case ALREADY_EXISTS:
+                return "ALREADY_EXISTS";
+            case PERMISSION_DENIED:
+                return "PERMISSION_DENIED";
+            case RESOURCE_EXHAUSTED:
+                return "RESOURCE_EXHAUSTED";
+            case FAILED_PRECONDITION:
+                return "FAILED_PRECONDITION";
+            case ABORTED:
+                return "ABORTED";
+            case OUT_OF_RANGE:
+                return "OUT_OF_RANGE";
+            case UNIMPLEMENTED:
+                return "UNIMPLEMENTED";
+            case INTERNAL:
+                return "INTERNAL";
+            case UNAVAILABLE:
+                return "UNAVAILABLE";
+            case DATA_LOSS:
+                return "DATA_LOSS";
+            case BUSY:
+                return "BUSY";
+            case SHOULD_WAIT:
+                return "SHOULD_WAIT";
+            default:
+                return "UNKNOWN";
+        }
+
+    }
+}
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/Pair.java b/mojo/public/java/system/src/org/chromium/mojo/system/Pair.java
new file mode 100644
index 0000000..2ead020
--- /dev/null
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/Pair.java
@@ -0,0 +1,67 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.system;
+
+
+/**
+ * A pair of object.
+ *
+ * @param <F> Type of the first element.
+ * @param <S> Type of the second element.
+ */
+public class Pair<F, S> {
+
+    public final F first;
+    public final S second;
+
+    /**
+     * Dedicated constructor.
+     *
+     * @param first the first element of the pair.
+     * @param second the second element of the pair.
+     */
+    public Pair(F first, S second) {
+        this.first = first;
+        this.second = second;
+    }
+
+    /**
+     * equals() that handles null values.
+     */
+    private boolean equals(Object o1, Object o2) {
+        return o1 == null ? o2 == null : o1.equals(o2);
+    }
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof Pair)) {
+            return false;
+        }
+        Pair<?, ?> p = (Pair<?, ?>) o;
+        return equals(first, p.first) && equals(second, p.second);
+    }
+
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
+    }
+
+    /**
+     * Helper method for creating a pair.
+     *
+     * @param a the first element of the pair.
+     * @param b the second element of the pair.
+     * @return the pair containing a and b.
+     */
+    public static <A, B> Pair<A, B> create(A a, B b) {
+        return new Pair<A, B>(a, b);
+    }
+}
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/SharedBufferHandle.java b/mojo/public/java/system/src/org/chromium/mojo/system/SharedBufferHandle.java
new file mode 100644
index 0000000..df317d1
--- /dev/null
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/SharedBufferHandle.java
@@ -0,0 +1,160 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.system;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A buffer that can be shared between applications.
+ */
+public interface SharedBufferHandle extends Handle {
+
+    /**
+     * Flags for the shared buffer creation operation.
+     */
+    public static class CreateFlags extends Flags<CreateFlags> {
+        private static final int FLAG_NONE = 0;
+
+        /**
+         * Immutable flag with not bit set.
+         */
+        public static final CreateFlags NONE = CreateFlags.none().immutable();
+
+        /**
+         * Dedicated constructor.
+         *
+         * @param flags initial value of the flags.
+         */
+        protected CreateFlags(int flags) {
+            super(flags);
+        }
+
+        /**
+         * @return flags with no bit set.
+         */
+        public static CreateFlags none() {
+            return new CreateFlags(FLAG_NONE);
+        }
+
+    }
+
+    /**
+     * Used to specify creation parameters for a shared buffer to |Core#createSharedBuffer()|.
+     */
+    public static class CreateOptions {
+        private CreateFlags mFlags = CreateFlags.NONE;
+
+        /**
+         * @return the flags
+         */
+        public CreateFlags getFlags() {
+            return mFlags;
+        }
+
+    }
+
+    /**
+     * Flags for the shared buffer duplication operation.
+     */
+    public static class DuplicateFlags extends Flags<DuplicateFlags> {
+        private static final int FLAG_NONE = 0;
+
+        /**
+         * Immutable flag with not bit set.
+         */
+        public static final DuplicateFlags NONE = DuplicateFlags.none().immutable();
+
+        /**
+         * Dedicated constructor.
+         *
+         * @param flags initial value of the flags.
+         */
+        protected DuplicateFlags(int flags) {
+            super(flags);
+        }
+
+        /**
+         * @return flags with no bit set.
+         */
+        public static DuplicateFlags none() {
+            return new DuplicateFlags(FLAG_NONE);
+        }
+
+    }
+
+    /**
+     * Used to specify parameters in duplicating access to a shared buffer to
+     * |SharedBufferHandle#duplicate|
+     */
+    public static class DuplicateOptions {
+        private DuplicateFlags mFlags = DuplicateFlags.NONE;
+
+        /**
+         * @return the flags
+         */
+        public DuplicateFlags getFlags() {
+            return mFlags;
+        }
+
+    }
+
+    /**
+     * Flags for the shared buffer map operation.
+     */
+    public static class MapFlags extends Flags<MapFlags> {
+        private static final int FLAG_NONE = 0;
+
+        /**
+         * Immutable flag with not bit set.
+         */
+        public static final MapFlags NONE = MapFlags.none().immutable();
+
+        /**
+         * Dedicated constructor.
+         *
+         * @param flags initial value of the flags.
+         */
+        protected MapFlags(int flags) {
+            super(flags);
+        }
+
+        /**
+         * @return flags with no bit set.
+         */
+        public static MapFlags none() {
+            return new MapFlags(FLAG_NONE);
+        }
+
+    }
+
+    /**
+     * @see org.chromium.mojo.system.Handle#pass()
+     */
+    @Override
+    public SharedBufferHandle pass();
+
+    /**
+     * Duplicates the handle. This creates another handle (returned on success), which can then be
+     * sent to another application over a message pipe, while retaining access to this handle (and
+     * any mappings that it may have).
+     */
+    public SharedBufferHandle duplicate(DuplicateOptions options);
+
+    /**
+     * Map the part (at offset |offset| of length |numBytes|) of the buffer given by this handle
+     * into memory. |offset + numBytes| must be less than or equal to the size of the buffer. On
+     * success, the returned buffer points to memory with the requested part of the buffer. A single
+     * buffer handle may have multiple active mappings (possibly depending on the buffer type). The
+     * permissions (e.g., writable or executable) of the returned memory may depend on the
+     * properties of the buffer and properties attached to the buffer handle as well as |flags|.
+     */
+    public ByteBuffer map(long offset, long numBytes, MapFlags flags);
+
+    /**
+     * Unmap a buffer pointer that was mapped by |map()|.
+     */
+    public void unmap(ByteBuffer buffer);
+
+}
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/UntypedHandle.java b/mojo/public/java/system/src/org/chromium/mojo/system/UntypedHandle.java
new file mode 100644
index 0000000..199b0a1
--- /dev/null
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/UntypedHandle.java
@@ -0,0 +1,45 @@
+// Copyright 2014 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.
+
+package org.chromium.mojo.system;
+
+import org.chromium.mojo.system.DataPipe.ConsumerHandle;
+import org.chromium.mojo.system.DataPipe.ProducerHandle;
+
+/**
+ * A mojo handle of unknown type. This handle can be typed by using one of its methods, which will
+ * return a handle of the requested type and invalidate this object. No validation is made when the
+ * conversion operation is called.
+ */
+public interface UntypedHandle extends Handle {
+
+    /**
+     * @see org.chromium.mojo.system.Handle#pass()
+     */
+    @Override
+    public UntypedHandle pass();
+
+    /**
+     * Returns the underlying handle, as a {@link MessagePipeHandle}, invalidating this
+     * representation.
+     */
+    public MessagePipeHandle toMessagePipeHandle();
+
+    /**
+     * Returns the underlying handle, as a {@link ConsumerHandle}, invalidating this representation.
+     */
+    public ConsumerHandle toDataPipeConsumerHandle();
+
+    /**
+     * Returns the underlying handle, as a {@link ProducerHandle}, invalidating this representation.
+     */
+    public ProducerHandle toDataPipeProducerHandle();
+
+    /**
+     * Returns the underlying handle, as a {@link SharedBufferHandle}, invalidating this
+     * representation.
+     */
+    public SharedBufferHandle toSharedBufferHandle();
+
+}
diff --git a/mojo/public/js/bindings/BUILD.gn b/mojo/public/js/bindings/BUILD.gn
new file mode 100644
index 0000000..0f305e9
--- /dev/null
+++ b/mojo/public/js/bindings/BUILD.gn
@@ -0,0 +1,10 @@
+# Copyright 2014 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.
+
+source_set("bindings") {
+  sources = [
+    "constants.cc",
+    "constants.h",
+  ]
+}
diff --git a/mojo/public/js/bindings/buffer.js b/mojo/public/js/bindings/buffer.js
new file mode 100644
index 0000000..d74fef6
--- /dev/null
+++ b/mojo/public/js/bindings/buffer.js
@@ -0,0 +1,156 @@
+// Copyright 2014 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.
+
+define("mojo/public/js/bindings/buffer", function() {
+
+  var kHostIsLittleEndian = (function () {
+    var endianArrayBuffer = new ArrayBuffer(2);
+    var endianUint8Array = new Uint8Array(endianArrayBuffer);
+    var endianUint16Array = new Uint16Array(endianArrayBuffer);
+    endianUint16Array[0] = 1;
+    return endianUint8Array[0] == 1;
+  })();
+
+  var kHighWordMultiplier = 0x100000000;
+
+  function Buffer(sizeOrArrayBuffer) {
+    if (sizeOrArrayBuffer instanceof ArrayBuffer)
+      this.arrayBuffer = sizeOrArrayBuffer;
+    else
+      this.arrayBuffer = new ArrayBuffer(sizeOrArrayBuffer);
+
+    this.dataView = new DataView(this.arrayBuffer);
+    this.next = 0;
+  }
+
+  Object.defineProperty(Buffer.prototype, "byteLength", {
+    get: function() { return this.arrayBuffer.byteLength; }
+  });
+
+  Buffer.prototype.alloc = function(size) {
+    var pointer = this.next;
+    this.next += size;
+    if (this.next > this.byteLength) {
+      var newSize = (1.5 * (this.byteLength + size)) | 0;
+      this.grow(newSize);
+    }
+    return pointer;
+  };
+
+  function copyArrayBuffer(dstArrayBuffer, srcArrayBuffer) {
+    (new Uint8Array(dstArrayBuffer)).set(new Uint8Array(srcArrayBuffer));
+  }
+
+  Buffer.prototype.grow = function(size) {
+    var newArrayBuffer = new ArrayBuffer(size);
+    copyArrayBuffer(newArrayBuffer, this.arrayBuffer);
+    this.arrayBuffer = newArrayBuffer;
+    this.dataView = new DataView(this.arrayBuffer);
+  };
+
+  Buffer.prototype.trim = function() {
+    this.arrayBuffer = this.arrayBuffer.slice(0, this.next);
+    this.dataView = new DataView(this.arrayBuffer);
+  };
+
+  Buffer.prototype.getUint8 = function(offset) {
+    return this.dataView.getUint8(offset);
+  }
+  Buffer.prototype.getUint16 = function(offset) {
+    return this.dataView.getUint16(offset, kHostIsLittleEndian);
+  }
+  Buffer.prototype.getUint32 = function(offset) {
+    return this.dataView.getUint32(offset, kHostIsLittleEndian);
+  }
+  Buffer.prototype.getUint64 = function(offset) {
+    var lo, hi;
+    if (kHostIsLittleEndian) {
+      lo = this.dataView.getUint32(offset, kHostIsLittleEndian);
+      hi = this.dataView.getUint32(offset + 4, kHostIsLittleEndian);
+    } else {
+      hi = this.dataView.getUint32(offset, kHostIsLittleEndian);
+      lo = this.dataView.getUint32(offset + 4, kHostIsLittleEndian);
+    }
+    return lo + hi * kHighWordMultiplier;
+  }
+
+  Buffer.prototype.getInt8 = function(offset) {
+    return this.dataView.getInt8(offset);
+  }
+  Buffer.prototype.getInt16 = function(offset) {
+    return this.dataView.getInt16(offset, kHostIsLittleEndian);
+  }
+  Buffer.prototype.getInt32 = function(offset) {
+    return this.dataView.getInt32(offset, kHostIsLittleEndian);
+  }
+  Buffer.prototype.getInt64 = function(offset) {
+    var lo, hi;
+    if (kHostIsLittleEndian) {
+      lo = this.dataView.getUint32(offset, kHostIsLittleEndian);
+      hi = this.dataView.getInt32(offset + 4, kHostIsLittleEndian);
+    } else {
+      hi = this.dataView.getInt32(offset, kHostIsLittleEndian);
+      lo = this.dataView.getUint32(offset + 4, kHostIsLittleEndian);
+    }
+    return lo + hi * kHighWordMultiplier;
+  }
+
+  Buffer.prototype.getFloat32 = function(offset) {
+    return this.dataView.getFloat32(offset, kHostIsLittleEndian);
+  }
+  Buffer.prototype.getFloat64 = function(offset) {
+    return this.dataView.getFloat64(offset, kHostIsLittleEndian);
+  }
+
+  Buffer.prototype.setUint8 = function(offset, value) {
+    this.dataView.setUint8(offset, value);
+  }
+  Buffer.prototype.setUint16 = function(offset, value) {
+    this.dataView.setUint16(offset, value, kHostIsLittleEndian);
+  }
+  Buffer.prototype.setUint32 = function(offset, value) {
+    this.dataView.setUint32(offset, value, kHostIsLittleEndian);
+  }
+  Buffer.prototype.setUint64 = function(offset, value) {
+    var hi = (value / kHighWordMultiplier) | 0;
+    if (kHostIsLittleEndian) {
+      this.dataView.setInt32(offset, value, kHostIsLittleEndian);
+      this.dataView.setInt32(offset + 4, hi, kHostIsLittleEndian);
+    } else {
+      this.dataView.setInt32(offset, hi, kHostIsLittleEndian);
+      this.dataView.setInt32(offset + 4, value, kHostIsLittleEndian);
+    }
+  }
+
+  Buffer.prototype.setInt8 = function(offset, value) {
+    this.dataView.setInt8(offset, value);
+  }
+  Buffer.prototype.setInt16 = function(offset, value) {
+    this.dataView.setInt16(offset, value, kHostIsLittleEndian);
+  }
+  Buffer.prototype.setInt32 = function(offset, value) {
+    this.dataView.setInt32(offset, value, kHostIsLittleEndian);
+  }
+  Buffer.prototype.setInt64 = function(offset, value) {
+    var hi = Math.floor(value / kHighWordMultiplier);
+    if (kHostIsLittleEndian) {
+      this.dataView.setInt32(offset, value, kHostIsLittleEndian);
+      this.dataView.setInt32(offset + 4, hi, kHostIsLittleEndian);
+    } else {
+      this.dataView.setInt32(offset, hi, kHostIsLittleEndian);
+      this.dataView.setInt32(offset + 4, value, kHostIsLittleEndian);
+    }
+  }
+
+  Buffer.prototype.setFloat32 = function(offset, value) {
+    this.dataView.setFloat32(offset, value, kHostIsLittleEndian);
+  }
+  Buffer.prototype.setFloat64 = function(offset, value) {
+    this.dataView.setFloat64(offset, value, kHostIsLittleEndian);
+  }
+
+  var exports = {};
+  exports.Buffer = Buffer;
+  return exports;
+});
diff --git a/mojo/public/js/bindings/codec.js b/mojo/public/js/bindings/codec.js
new file mode 100644
index 0000000..623cca7
--- /dev/null
+++ b/mojo/public/js/bindings/codec.js
@@ -0,0 +1,739 @@
+// Copyright 2014 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.
+
+define("mojo/public/js/bindings/codec", [
+  "mojo/public/js/bindings/unicode",
+  "mojo/public/js/bindings/buffer"
+  ], function(unicode, buffer) {
+
+  var kErrorUnsigned = "Passing negative value to unsigned";
+
+  // Memory -------------------------------------------------------------------
+
+  var kAlignment = 8;
+
+  function align(size) {
+    return size + (kAlignment - (size % kAlignment)) % kAlignment;
+  }
+
+  function isAligned(offset) {
+    return offset >= 0 && (offset % kAlignment) === 0;
+  }
+
+  // Constants ----------------------------------------------------------------
+
+  var kArrayHeaderSize = 8;
+  var kStructHeaderSize = 8;
+  var kMessageHeaderSize = 16;
+  var kMessageWithRequestIDHeaderSize = 24;
+
+  var kStructHeaderNumBytesOffset = 0;
+  var kStructHeaderNumFieldsOffset = 4;
+
+  var kEncodedInvalidHandleValue = 0xFFFFFFFF;
+
+  // Decoder ------------------------------------------------------------------
+
+  function Decoder(buffer, handles, base) {
+    this.buffer = buffer;
+    this.handles = handles;
+    this.base = base;
+    this.next = base;
+  }
+
+  Decoder.prototype.skip = function(offset) {
+    this.next += offset;
+  };
+
+  Decoder.prototype.readInt8 = function() {
+    var result = this.buffer.getInt8(this.next);
+    this.next += 1;
+    return result;
+  };
+
+  Decoder.prototype.readUint8 = function() {
+    var result = this.buffer.getUint8(this.next);
+    this.next += 1;
+    return result;
+  };
+
+  Decoder.prototype.readInt16 = function() {
+    var result = this.buffer.getInt16(this.next);
+    this.next += 2;
+    return result;
+  };
+
+  Decoder.prototype.readUint16 = function() {
+    var result = this.buffer.getUint16(this.next);
+    this.next += 2;
+    return result;
+  };
+
+  Decoder.prototype.readInt32 = function() {
+    var result = this.buffer.getInt32(this.next);
+    this.next += 4;
+    return result;
+  };
+
+  Decoder.prototype.readUint32 = function() {
+    var result = this.buffer.getUint32(this.next);
+    this.next += 4;
+    return result;
+  };
+
+  Decoder.prototype.readInt64 = function() {
+    var result = this.buffer.getInt64(this.next);
+    this.next += 8;
+    return result;
+  };
+
+  Decoder.prototype.readUint64 = function() {
+    var result = this.buffer.getUint64(this.next);
+    this.next += 8;
+    return result;
+  };
+
+  Decoder.prototype.readFloat = function() {
+    var result = this.buffer.getFloat32(this.next);
+    this.next += 4;
+    return result;
+  };
+
+  Decoder.prototype.readDouble = function() {
+    var result = this.buffer.getFloat64(this.next);
+    this.next += 8;
+    return result;
+  };
+
+  Decoder.prototype.decodePointer = function() {
+    // TODO(abarth): To correctly decode a pointer, we need to know the real
+    // base address of the array buffer.
+    var offsetPointer = this.next;
+    var offset = this.readUint64();
+    if (!offset)
+      return 0;
+    return offsetPointer + offset;
+  };
+
+  Decoder.prototype.decodeAndCreateDecoder = function(pointer) {
+    return new Decoder(this.buffer, this.handles, pointer);
+  };
+
+  Decoder.prototype.decodeHandle = function() {
+    return this.handles[this.readUint32()];
+  };
+
+  Decoder.prototype.decodeString = function() {
+    var numberOfBytes = this.readUint32();
+    var numberOfElements = this.readUint32();
+    var base = this.next;
+    this.next += numberOfElements;
+    return unicode.decodeUtf8String(
+        new Uint8Array(this.buffer.arrayBuffer, base, numberOfElements));
+  };
+
+  Decoder.prototype.decodeArray = function(cls) {
+    var numberOfBytes = this.readUint32();
+    var numberOfElements = this.readUint32();
+    var val = new Array(numberOfElements);
+    if (cls === PackedBool) {
+      var byte;
+      for (var i = 0; i < numberOfElements; ++i) {
+        if (i % 8 === 0)
+          byte = this.readUint8();
+        val[i] = (byte & (1 << i % 8)) ? true : false;
+      }
+    } else {
+      for (var i = 0; i < numberOfElements; ++i) {
+        val[i] = cls.decode(this);
+      }
+    }
+    return val;
+  };
+
+  Decoder.prototype.decodeStruct = function(cls) {
+    return cls.decode(this);
+  };
+
+  Decoder.prototype.decodeStructPointer = function(cls) {
+    var pointer = this.decodePointer();
+    if (!pointer) {
+      return null;
+    }
+    return cls.decode(this.decodeAndCreateDecoder(pointer));
+  };
+
+  Decoder.prototype.decodeArrayPointer = function(cls) {
+    var pointer = this.decodePointer();
+    if (!pointer) {
+      return null;
+    }
+    return this.decodeAndCreateDecoder(pointer).decodeArray(cls);
+  };
+
+  Decoder.prototype.decodeStringPointer = function() {
+    var pointer = this.decodePointer();
+    if (!pointer) {
+      return null;
+    }
+    return this.decodeAndCreateDecoder(pointer).decodeString();
+  };
+
+  // Encoder ------------------------------------------------------------------
+
+  function Encoder(buffer, handles, base) {
+    this.buffer = buffer;
+    this.handles = handles;
+    this.base = base;
+    this.next = base;
+  }
+
+  Encoder.prototype.skip = function(offset) {
+    this.next += offset;
+  };
+
+  Encoder.prototype.writeInt8 = function(val) {
+    this.buffer.setInt8(this.next, val);
+    this.next += 1;
+  };
+
+  Encoder.prototype.writeUint8 = function(val) {
+    if (val < 0) {
+      throw new Error(kErrorUnsigned);
+    }
+    this.buffer.setUint8(this.next, val);
+    this.next += 1;
+  };
+
+  Encoder.prototype.writeInt16 = function(val) {
+    this.buffer.setInt16(this.next, val);
+    this.next += 2;
+  };
+
+  Encoder.prototype.writeUint16 = function(val) {
+    if (val < 0) {
+      throw new Error(kErrorUnsigned);
+    }
+    this.buffer.setUint16(this.next, val);
+    this.next += 2;
+  };
+
+  Encoder.prototype.writeInt32 = function(val) {
+    this.buffer.setInt32(this.next, val);
+    this.next += 4;
+  };
+
+  Encoder.prototype.writeUint32 = function(val) {
+    if (val < 0) {
+      throw new Error(kErrorUnsigned);
+    }
+    this.buffer.setUint32(this.next, val);
+    this.next += 4;
+  };
+
+  Encoder.prototype.writeInt64 = function(val) {
+    this.buffer.setInt64(this.next, val);
+    this.next += 8;
+  };
+
+  Encoder.prototype.writeUint64 = function(val) {
+    if (val < 0) {
+      throw new Error(kErrorUnsigned);
+    }
+    this.buffer.setUint64(this.next, val);
+    this.next += 8;
+  };
+
+  Encoder.prototype.writeFloat = function(val) {
+    this.buffer.setFloat32(this.next, val);
+    this.next += 4;
+  };
+
+  Encoder.prototype.writeDouble = function(val) {
+    this.buffer.setFloat64(this.next, val);
+    this.next += 8;
+  };
+
+  Encoder.prototype.encodePointer = function(pointer) {
+    if (!pointer)
+      return this.writeUint64(0);
+    // TODO(abarth): To correctly encode a pointer, we need to know the real
+    // base address of the array buffer.
+    var offset = pointer - this.next;
+    this.writeUint64(offset);
+  };
+
+  Encoder.prototype.createAndEncodeEncoder = function(size) {
+    var pointer = this.buffer.alloc(align(size));
+    this.encodePointer(pointer);
+    return new Encoder(this.buffer, this.handles, pointer);
+  };
+
+  Encoder.prototype.encodeHandle = function(handle) {
+    this.handles.push(handle);
+    this.writeUint32(this.handles.length - 1);
+  };
+
+  Encoder.prototype.encodeString = function(val) {
+    var base = this.next + kArrayHeaderSize;
+    var numberOfElements = unicode.encodeUtf8String(
+        val, new Uint8Array(this.buffer.arrayBuffer, base));
+    var numberOfBytes = kArrayHeaderSize + numberOfElements;
+    this.writeUint32(numberOfBytes);
+    this.writeUint32(numberOfElements);
+    this.next += numberOfElements;
+  };
+
+  Encoder.prototype.encodeArray =
+      function(cls, val, numberOfElements, encodedSize) {
+    if (numberOfElements === undefined)
+      numberOfElements = val.length;
+    if (encodedSize === undefined)
+      encodedSize = kArrayHeaderSize + cls.encodedSize * numberOfElements;
+
+    this.writeUint32(encodedSize);
+    this.writeUint32(numberOfElements);
+
+    if (cls === PackedBool) {
+      var byte = 0;
+      for (i = 0; i < numberOfElements; ++i) {
+        if (val[i])
+          byte |= (1 << i % 8);
+        if (i % 8 === 7 || i == numberOfElements - 1) {
+          Uint8.encode(this, byte);
+          byte = 0;
+        }
+      }
+    } else {
+      for (var i = 0; i < numberOfElements; ++i)
+        cls.encode(this, val[i]);
+    }
+  };
+
+  Encoder.prototype.encodeStruct = function(cls, val) {
+    return cls.encode(this, val);
+  };
+
+  Encoder.prototype.encodeStructPointer = function(cls, val) {
+    if (val == null) {
+      // Also handles undefined, since undefined == null.
+      this.encodePointer(val);
+      return;
+    }
+    var encoder = this.createAndEncodeEncoder(cls.encodedSize);
+    cls.encode(encoder, val);
+  };
+
+  Encoder.prototype.encodeArrayPointer = function(cls, val) {
+    if (val == null) {
+      // Also handles undefined, since undefined == null.
+      this.encodePointer(val);
+      return;
+    }
+    var numberOfElements = val.length;
+    var encodedSize = kArrayHeaderSize + ((cls === PackedBool) ?
+        Math.ceil(numberOfElements / 8) : cls.encodedSize * numberOfElements);
+    var encoder = this.createAndEncodeEncoder(encodedSize);
+    encoder.encodeArray(cls, val, numberOfElements, encodedSize);
+  };
+
+  Encoder.prototype.encodeStringPointer = function(val) {
+    if (val == null) {
+      // Also handles undefined, since undefined == null.
+      this.encodePointer(val);
+      return;
+    }
+    var encodedSize = kArrayHeaderSize + unicode.utf8Length(val);
+    var encoder = this.createAndEncodeEncoder(encodedSize);
+    encoder.encodeString(val);
+  };
+
+  // Message ------------------------------------------------------------------
+
+  var kMessageNameOffset = kStructHeaderSize;
+  var kMessageFlagsOffset = kMessageNameOffset + 4;
+  var kMessageRequestIDOffset = kMessageFlagsOffset + 4;
+
+  var kMessageExpectsResponse = 1 << 0;
+  var kMessageIsResponse      = 1 << 1;
+
+  function Message(buffer, handles) {
+    this.buffer = buffer;
+    this.handles = handles;
+  }
+
+  Message.prototype.getHeaderNumBytes = function() {
+    return this.buffer.getUint32(kStructHeaderNumBytesOffset);
+  };
+
+  Message.prototype.getHeaderNumFields = function() {
+    return this.buffer.getUint32(kStructHeaderNumFieldsOffset);
+  };
+
+  Message.prototype.getName = function() {
+    return this.buffer.getUint32(kMessageNameOffset);
+  };
+
+  Message.prototype.getFlags = function() {
+    return this.buffer.getUint32(kMessageFlagsOffset);
+  };
+
+  Message.prototype.isResponse = function() {
+    return (this.getFlags() & kMessageIsResponse) != 0;
+  };
+
+  Message.prototype.expectsResponse = function() {
+    return (this.getFlags() & kMessageExpectsResponse) != 0;
+  };
+
+  Message.prototype.setRequestID = function(requestID) {
+    // TODO(darin): Verify that space was reserved for this field!
+    this.buffer.setUint64(kMessageRequestIDOffset, requestID);
+  };
+
+
+  // MessageBuilder -----------------------------------------------------------
+
+  function MessageBuilder(messageName, payloadSize) {
+    // Currently, we don't compute the payload size correctly ahead of time.
+    // Instead, we resize the buffer at the end.
+    var numberOfBytes = kMessageHeaderSize + payloadSize;
+    this.buffer = new buffer.Buffer(numberOfBytes);
+    this.handles = [];
+    var encoder = this.createEncoder(kMessageHeaderSize);
+    encoder.writeUint32(kMessageHeaderSize);
+    encoder.writeUint32(2);  // num_fields.
+    encoder.writeUint32(messageName);
+    encoder.writeUint32(0);  // flags.
+  }
+
+  MessageBuilder.prototype.createEncoder = function(size) {
+    var pointer = this.buffer.alloc(size);
+    return new Encoder(this.buffer, this.handles, pointer);
+  };
+
+  MessageBuilder.prototype.encodeStruct = function(cls, val) {
+    cls.encode(this.createEncoder(cls.encodedSize), val);
+  };
+
+  MessageBuilder.prototype.finish = function() {
+    // TODO(abarth): Rather than resizing the buffer at the end, we could
+    // compute the size we need ahead of time, like we do in C++.
+    this.buffer.trim();
+    var message = new Message(this.buffer, this.handles);
+    this.buffer = null;
+    this.handles = null;
+    this.encoder = null;
+    return message;
+  };
+
+  // MessageWithRequestIDBuilder -----------------------------------------------
+
+  function MessageWithRequestIDBuilder(messageName, payloadSize, flags,
+                                       requestID) {
+    // Currently, we don't compute the payload size correctly ahead of time.
+    // Instead, we resize the buffer at the end.
+    var numberOfBytes = kMessageWithRequestIDHeaderSize + payloadSize;
+    this.buffer = new buffer.Buffer(numberOfBytes);
+    this.handles = [];
+    var encoder = this.createEncoder(kMessageWithRequestIDHeaderSize);
+    encoder.writeUint32(kMessageWithRequestIDHeaderSize);
+    encoder.writeUint32(3);  // num_fields.
+    encoder.writeUint32(messageName);
+    encoder.writeUint32(flags);
+    encoder.writeUint64(requestID);
+  }
+
+  MessageWithRequestIDBuilder.prototype =
+      Object.create(MessageBuilder.prototype);
+
+  MessageWithRequestIDBuilder.prototype.constructor =
+      MessageWithRequestIDBuilder;
+
+  // MessageReader ------------------------------------------------------------
+
+  function MessageReader(message) {
+    this.decoder = new Decoder(message.buffer, message.handles, 0);
+    var messageHeaderSize = this.decoder.readUint32();
+    this.payloadSize = message.buffer.byteLength - messageHeaderSize;
+    var numFields = this.decoder.readUint32();
+    this.messageName = this.decoder.readUint32();
+    this.flags = this.decoder.readUint32();
+    if (numFields >= 3)
+      this.requestID = this.decoder.readUint64();
+    this.decoder.skip(messageHeaderSize - this.decoder.next);
+  }
+
+  MessageReader.prototype.decodeStruct = function(cls) {
+    return cls.decode(this.decoder);
+  };
+
+  // Built-in types -----------------------------------------------------------
+
+  // This type is only used with ArrayOf(PackedBool).
+  function PackedBool() {
+  }
+
+  function Int8() {
+  }
+
+  Int8.encodedSize = 1;
+
+  Int8.decode = function(decoder) {
+    return decoder.readInt8();
+  };
+
+  Int8.encode = function(encoder, val) {
+    encoder.writeInt8(val);
+  };
+
+  Uint8.encode = function(encoder, val) {
+    encoder.writeUint8(val);
+  };
+
+  function Uint8() {
+  }
+
+  Uint8.encodedSize = 1;
+
+  Uint8.decode = function(decoder) {
+    return decoder.readUint8();
+  };
+
+  Uint8.encode = function(encoder, val) {
+    encoder.writeUint8(val);
+  };
+
+  function Int16() {
+  }
+
+  Int16.encodedSize = 2;
+
+  Int16.decode = function(decoder) {
+    return decoder.readInt16();
+  };
+
+  Int16.encode = function(encoder, val) {
+    encoder.writeInt16(val);
+  };
+
+  function Uint16() {
+  }
+
+  Uint16.encodedSize = 2;
+
+  Uint16.decode = function(decoder) {
+    return decoder.readUint16();
+  };
+
+  Uint16.encode = function(encoder, val) {
+    encoder.writeUint16(val);
+  };
+
+  function Int32() {
+  }
+
+  Int32.encodedSize = 4;
+
+  Int32.decode = function(decoder) {
+    return decoder.readInt32();
+  };
+
+  Int32.encode = function(encoder, val) {
+    encoder.writeInt32(val);
+  };
+
+  function Uint32() {
+  }
+
+  Uint32.encodedSize = 4;
+
+  Uint32.decode = function(decoder) {
+    return decoder.readUint32();
+  };
+
+  Uint32.encode = function(encoder, val) {
+    encoder.writeUint32(val);
+  };
+
+  function Int64() {
+  }
+
+  Int64.encodedSize = 8;
+
+  Int64.decode = function(decoder) {
+    return decoder.readInt64();
+  };
+
+  Int64.encode = function(encoder, val) {
+    encoder.writeInt64(val);
+  };
+
+  function Uint64() {
+  }
+
+  Uint64.encodedSize = 8;
+
+  Uint64.decode = function(decoder) {
+    return decoder.readUint64();
+  };
+
+  Uint64.encode = function(encoder, val) {
+    encoder.writeUint64(val);
+  };
+
+  function String() {
+  };
+
+  String.encodedSize = 8;
+
+  String.decode = function(decoder) {
+    return decoder.decodeStringPointer();
+  };
+
+  String.encode = function(encoder, val) {
+    encoder.encodeStringPointer(val);
+  };
+
+  function NullableString() {
+  }
+
+  NullableString.encodedSize = String.encodedSize;
+
+  NullableString.decode = String.decode;
+
+  NullableString.encode = String.encode;
+
+  function Float() {
+  }
+
+  Float.encodedSize = 4;
+
+  Float.decode = function(decoder) {
+    return decoder.readFloat();
+  };
+
+  Float.encode = function(encoder, val) {
+    encoder.writeFloat(val);
+  };
+
+  function Double() {
+  }
+
+  Double.encodedSize = 8;
+
+  Double.decode = function(decoder) {
+    return decoder.readDouble();
+  };
+
+  Double.encode = function(encoder, val) {
+    encoder.writeDouble(val);
+  };
+
+  function PointerTo(cls) {
+    this.cls = cls;
+  }
+
+  PointerTo.prototype.encodedSize = 8;
+
+  PointerTo.prototype.decode = function(decoder) {
+    var pointer = decoder.decodePointer();
+    if (!pointer) {
+      return null;
+    }
+    return this.cls.decode(decoder.decodeAndCreateDecoder(pointer));
+  };
+
+  PointerTo.prototype.encode = function(encoder, val) {
+    if (!val) {
+      encoder.encodePointer(val);
+      return;
+    }
+    var objectEncoder = encoder.createAndEncodeEncoder(this.cls.encodedSize);
+    this.cls.encode(objectEncoder, val);
+  };
+
+  function NullablePointerTo(cls) {
+    PointerTo.call(this, cls);
+  }
+
+  NullablePointerTo.prototype = Object.create(PointerTo.prototype);
+
+  function ArrayOf(cls) {
+    this.cls = cls;
+  }
+
+  ArrayOf.prototype.encodedSize = 8;
+
+  ArrayOf.prototype.decode = function(decoder) {
+    return decoder.decodeArrayPointer(this.cls);
+  };
+
+  ArrayOf.prototype.encode = function(encoder, val) {
+    encoder.encodeArrayPointer(this.cls, val);
+  };
+
+  function NullableArrayOf(cls) {
+    ArrayOf.call(this, cls);
+  }
+
+  NullableArrayOf.prototype = Object.create(ArrayOf.prototype);
+
+  function Handle() {
+  }
+
+  Handle.encodedSize = 4;
+
+  Handle.decode = function(decoder) {
+    return decoder.decodeHandle();
+  };
+
+  Handle.encode = function(encoder, val) {
+    encoder.encodeHandle(val);
+  };
+
+  function NullableHandle() {
+  }
+
+  NullableHandle.encodedSize = Handle.encodedSize;
+
+  NullableHandle.decode = Handle.decode;
+
+  NullableHandle.encode = Handle.encode;
+
+  var exports = {};
+  exports.align = align;
+  exports.isAligned = isAligned;
+  exports.Message = Message;
+  exports.MessageBuilder = MessageBuilder;
+  exports.MessageWithRequestIDBuilder = MessageWithRequestIDBuilder;
+  exports.MessageReader = MessageReader;
+  exports.kArrayHeaderSize = kArrayHeaderSize;
+  exports.kStructHeaderSize = kStructHeaderSize;
+  exports.kEncodedInvalidHandleValue = kEncodedInvalidHandleValue;
+  exports.kMessageHeaderSize = kMessageHeaderSize;
+  exports.kMessageWithRequestIDHeaderSize = kMessageWithRequestIDHeaderSize;
+  exports.kMessageExpectsResponse = kMessageExpectsResponse;
+  exports.kMessageIsResponse = kMessageIsResponse;
+  exports.Int8 = Int8;
+  exports.Uint8 = Uint8;
+  exports.Int16 = Int16;
+  exports.Uint16 = Uint16;
+  exports.Int32 = Int32;
+  exports.Uint32 = Uint32;
+  exports.Int64 = Int64;
+  exports.Uint64 = Uint64;
+  exports.Float = Float;
+  exports.Double = Double;
+  exports.String = String;
+  exports.NullableString = NullableString;
+  exports.PointerTo = PointerTo;
+  exports.NullablePointerTo = NullablePointerTo;
+  exports.ArrayOf = ArrayOf;
+  exports.NullableArrayOf = NullableArrayOf;
+  exports.PackedBool = PackedBool;
+  exports.Handle = Handle;
+  exports.NullableHandle = NullableHandle;
+  return exports;
+});
diff --git a/mojo/public/js/bindings/codec_unittests.js b/mojo/public/js/bindings/codec_unittests.js
new file mode 100644
index 0000000..0276db2
--- /dev/null
+++ b/mojo/public/js/bindings/codec_unittests.js
@@ -0,0 +1,258 @@
+// Copyright 2014 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.
+
+define([
+    "gin/test/expect",
+    "mojo/public/js/bindings/codec",
+    "mojo/public/interfaces/bindings/tests/rect.mojom",
+    "mojo/public/interfaces/bindings/tests/sample_service.mojom",
+    "mojo/public/interfaces/bindings/tests/test_structs.mojom",
+  ], function(expect, codec, rect, sample, structs) {
+  testBar();
+  testFoo();
+  testNamedRegion();
+  testTypes();
+  testAlign();
+  testUtf8();
+  this.result = "PASS";
+
+  function testBar() {
+    var bar = new sample.Bar();
+    bar.alpha = 1;
+    bar.beta = 2;
+    bar.gamma = 3;
+    bar.type = 0x08070605;
+    bar.extraProperty = "banana";
+
+    var messageName = 42;
+    var payloadSize = sample.Bar.encodedSize;
+
+    var builder = new codec.MessageBuilder(messageName, payloadSize);
+    builder.encodeStruct(sample.Bar, bar);
+
+    var message = builder.finish();
+
+    var expectedMemory = new Uint8Array([
+      16, 0, 0, 0,
+       2, 0, 0, 0,
+      42, 0, 0, 0,
+       0, 0, 0, 0,
+
+      16, 0, 0, 0,
+       4, 0, 0, 0,
+
+       1, 2, 3, 0,
+       5, 6, 7, 8,
+    ]);
+
+    var actualMemory = new Uint8Array(message.buffer.arrayBuffer);
+    expect(actualMemory).toEqual(expectedMemory);
+
+    var reader = new codec.MessageReader(message);
+
+    expect(reader.payloadSize).toBe(payloadSize);
+    expect(reader.messageName).toBe(messageName);
+
+    var bar2 = reader.decodeStruct(sample.Bar);
+
+    expect(bar2.alpha).toBe(bar.alpha);
+    expect(bar2.beta).toBe(bar.beta);
+    expect(bar2.gamma).toBe(bar.gamma);
+    expect("extraProperty" in bar2).toBeFalsy();
+  }
+
+  function testFoo() {
+    var foo = new sample.Foo();
+    foo.x = 0x212B4D5;
+    foo.y = 0x16E93;
+    foo.a = 1;
+    foo.b = 0;
+    foo.c = 3; // This will get truncated to one bit.
+    foo.bar = new sample.Bar();
+    foo.bar.alpha = 91;
+    foo.bar.beta = 82;
+    foo.bar.gamma = 73;
+    foo.data = [
+      4, 5, 6, 7, 8,
+    ];
+    foo.extra_bars = [
+      new sample.Bar(), new sample.Bar(), new sample.Bar(),
+    ];
+    for (var i = 0; i < foo.extra_bars.length; ++i) {
+      foo.extra_bars[i].alpha = 1 * i;
+      foo.extra_bars[i].beta = 2 * i;
+      foo.extra_bars[i].gamma = 3 * i;
+    }
+    foo.name = "I am a banana";
+    // This is supposed to be a handle, but we fake it with an integer.
+    foo.source = 23423782;
+    foo.array_of_array_of_bools = [
+      [true], [false, true]
+    ];
+    foo.array_of_bools = [
+      true, false, true, false, true, false, true, true
+    ];
+
+
+    var messageName = 31;
+    var payloadSize = 304;
+
+    var builder = new codec.MessageBuilder(messageName, payloadSize);
+    builder.encodeStruct(sample.Foo, foo);
+
+    var message = builder.finish();
+
+    var expectedMemory = new Uint8Array([
+      /*  0: */   16,    0,    0,    0,    2,    0,    0,    0,
+      /*  8: */   31,    0,    0,    0,    0,    0,    0,    0,
+      /* 16: */   96,    0,    0,    0,   15,    0,    0,    0,
+      /* 24: */ 0xD5, 0xB4, 0x12, 0x02, 0x93, 0x6E, 0x01,    0,
+      /* 32: */    5,    0,    0,    0,    0,    0,    0,    0,
+      /* 40: */   72,    0,    0,    0,    0,    0,    0,    0,
+    ]);
+    // TODO(abarth): Test more of the message's raw memory.
+    var actualMemory = new Uint8Array(message.buffer.arrayBuffer,
+                                      0, expectedMemory.length);
+    expect(actualMemory).toEqual(expectedMemory);
+
+    var expectedHandles = [
+      23423782,
+    ];
+
+    expect(message.handles).toEqual(expectedHandles);
+
+    var reader = new codec.MessageReader(message);
+
+    expect(reader.payloadSize).toBe(payloadSize);
+    expect(reader.messageName).toBe(messageName);
+
+    var foo2 = reader.decodeStruct(sample.Foo);
+
+    expect(foo2.x).toBe(foo.x);
+    expect(foo2.y).toBe(foo.y);
+
+    expect(foo2.a).toBe(foo.a & 1 ? true : false);
+    expect(foo2.b).toBe(foo.b & 1 ? true : false);
+    expect(foo2.c).toBe(foo.c & 1 ? true : false);
+
+    expect(foo2.bar).toEqual(foo.bar);
+    expect(foo2.data).toEqual(foo.data);
+
+    expect(foo2.extra_bars).toEqual(foo.extra_bars);
+    expect(foo2.name).toBe(foo.name);
+    expect(foo2.source).toEqual(foo.source);
+
+    expect(foo2.array_of_bools).toEqual(foo.array_of_bools);
+  }
+
+  function createRect(x, y, width, height) {
+    var r = new rect.Rect();
+    r.x = x;
+    r.y = y;
+    r.width = width;
+    r.height = height;
+    return r;
+  }
+
+  // Verify that the references to the imported Rect type in test_structs.mojom
+  // are generated correctly.
+  function testNamedRegion() {
+    var r = new structs.NamedRegion();
+    r.name = "rectangle";
+    r.rects = new Array(createRect(1, 2, 3, 4), createRect(10, 20, 30, 40));
+
+    var builder = new codec.MessageBuilder(1, structs.NamedRegion.encodedSize);
+    builder.encodeStruct(structs.NamedRegion, r);
+    var reader = new codec.MessageReader(builder.finish());
+    var result = reader.decodeStruct(structs.NamedRegion);
+
+    expect(result.name).toEqual("rectangle");
+    expect(result.rects[0]).toEqual(createRect(1, 2, 3, 4));
+    expect(result.rects[1]).toEqual(createRect(10, 20, 30, 40));
+  }
+
+  function testTypes() {
+    function encodeDecode(cls, input, expectedResult, encodedSize) {
+      var messageName = 42;
+      var payloadSize = encodedSize || cls.encodedSize;
+
+      var builder = new codec.MessageBuilder(messageName, payloadSize);
+      builder.encodeStruct(cls, input)
+      var message = builder.finish();
+
+      var reader = new codec.MessageReader(message);
+      expect(reader.payloadSize).toBe(payloadSize);
+      expect(reader.messageName).toBe(messageName);
+      var result = reader.decodeStruct(cls);
+      expect(result).toEqual(expectedResult);
+    }
+    encodeDecode(codec.String, "banana", "banana", 24);
+    encodeDecode(codec.NullableString, null, null, 8);
+    encodeDecode(codec.Int8, -1, -1);
+    encodeDecode(codec.Int8, 0xff, -1);
+    encodeDecode(codec.Int16, -1, -1);
+    encodeDecode(codec.Int16, 0xff, 0xff);
+    encodeDecode(codec.Int16, 0xffff, -1);
+    encodeDecode(codec.Int32, -1, -1);
+    encodeDecode(codec.Int32, 0xffff, 0xffff);
+    encodeDecode(codec.Int32, 0xffffffff, -1);
+    encodeDecode(codec.Float, 1.0, 1.0);
+    encodeDecode(codec.Double, 1.0, 1.0);
+  }
+
+  function testAlign() {
+    var aligned = [
+      0, // 0
+      8, // 1
+      8, // 2
+      8, // 3
+      8, // 4
+      8, // 5
+      8, // 6
+      8, // 7
+      8, // 8
+      16, // 9
+      16, // 10
+      16, // 11
+      16, // 12
+      16, // 13
+      16, // 14
+      16, // 15
+      16, // 16
+      24, // 17
+      24, // 18
+      24, // 19
+      24, // 20
+    ];
+    for (var i = 0; i < aligned.length; ++i)
+      expect(codec.align(i)).toBe(aligned[i]);
+  }
+
+  function testUtf8() {
+    var str = "B\u03ba\u1f79";  // some UCS-2 codepoints
+    var messageName = 42;
+    var payloadSize = 24;
+
+    var builder = new codec.MessageBuilder(messageName, payloadSize);
+    var encoder = builder.createEncoder(8);
+    encoder.encodeStringPointer(str);
+    var message = builder.finish();
+    var expectedMemory = new Uint8Array([
+      /*  0: */   16,    0,    0,    0,    2,    0,    0,    0,
+      /*  8: */   42,    0,    0,    0,    0,    0,    0,    0,
+      /* 16: */    8,    0,    0,    0,    0,    0,    0,    0,
+      /* 24: */   14,    0,    0,    0,    6,    0,    0,    0,
+      /* 32: */ 0x42, 0xCE, 0xBA, 0xE1, 0xBD, 0xB9,    0,    0,
+    ]);
+    var actualMemory = new Uint8Array(message.buffer.arrayBuffer);
+    expect(actualMemory.length).toEqual(expectedMemory.length);
+    expect(actualMemory).toEqual(expectedMemory);
+
+    var reader = new codec.MessageReader(message);
+    expect(reader.payloadSize).toBe(payloadSize);
+    expect(reader.messageName).toBe(messageName);
+    var str2 = reader.decoder.decodeStringPointer();
+    expect(str2).toEqual(str);
+  }
+});
diff --git a/mojo/public/js/bindings/connection.js b/mojo/public/js/bindings/connection.js
new file mode 100644
index 0000000..31cf2aa
--- /dev/null
+++ b/mojo/public/js/bindings/connection.js
@@ -0,0 +1,57 @@
+// Copyright 2014 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.
+
+define("mojo/public/js/bindings/connection", [
+  "mojo/public/js/bindings/connector",
+  "mojo/public/js/bindings/router",
+], function(connector, router) {
+
+  function Connection(
+      handle, localFactory, remoteFactory, routerFactory, connectorFactory) {
+    if (routerFactory === undefined)
+      routerFactory = router.Router;
+    this.router_ = new routerFactory(handle, connectorFactory);
+    this.remote = new remoteFactory(this.router_);
+    this.local = new localFactory(this.remote);
+    this.router_.setIncomingReceiver(this.local);
+
+    var validateRequest = localFactory.prototype.validator;
+    var validateResponse = remoteFactory.prototype.validator;
+    var payloadValidators = [];
+    if (validateRequest)
+      payloadValidators.push(validateRequest);
+    if (validateResponse)
+      payloadValidators.push(validateResponse);
+    this.router_.setPayloadValidators(payloadValidators);
+  }
+
+  Connection.prototype.close = function() {
+    this.router_.close();
+    this.router_ = null;
+    this.local = null;
+    this.remote = null;
+  };
+
+  Connection.prototype.encounteredError = function() {
+    return this.router_.encounteredError();
+  };
+
+  // The TestConnection subclass is only intended to be used in unit tests.
+
+  function TestConnection(handle, localFactory, remoteFactory) {
+    Connection.call(this,
+                    handle,
+                    localFactory,
+                    remoteFactory,
+                    router.TestRouter,
+                    connector.TestConnector);
+  }
+
+  TestConnection.prototype = Object.create(Connection.prototype);
+
+  var exports = {};
+  exports.Connection = Connection;
+  exports.TestConnection = TestConnection;
+  return exports;
+});
diff --git a/mojo/public/js/bindings/connector.js b/mojo/public/js/bindings/connector.js
new file mode 100644
index 0000000..495896d
--- /dev/null
+++ b/mojo/public/js/bindings/connector.js
@@ -0,0 +1,127 @@
+// Copyright 2014 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.
+
+define("mojo/public/js/bindings/connector", [
+  "mojo/public/js/bindings/buffer",
+  "mojo/public/js/bindings/codec",
+  "mojo/public/js/bindings/core",
+  "mojo/public/js/bindings/support",
+], function(buffer, codec, core, support) {
+
+  function Connector(handle) {
+    this.handle_ = handle;
+    this.dropWrites_ = false;
+    this.error_ = false;
+    this.incomingReceiver_ = null;
+    this.readWaitCookie_ = null;
+    this.errorHandler_ = null;
+
+    this.waitToReadMore_();
+  }
+
+  Connector.prototype.close = function() {
+    if (this.readWaitCookie_) {
+      support.cancelWait(this.readWaitCookie_);
+      this.readWaitCookie_ = null;
+    }
+    if (this.handle_ != null) {
+      core.close(this.handle_);
+      this.handle_ = null;
+    }
+  };
+
+  Connector.prototype.accept = function(message) {
+    if (this.error_)
+      return false;
+
+    if (this.dropWrites_)
+      return true;
+
+    var result = core.writeMessage(this.handle_,
+                                   new Uint8Array(message.buffer.arrayBuffer),
+                                   message.handles,
+                                   core.WRITE_MESSAGE_FLAG_NONE);
+    switch (result) {
+      case core.RESULT_OK:
+        // The handles were successfully transferred, so we don't own them
+        // anymore.
+        message.handles = [];
+        break;
+      case core.RESULT_FAILED_PRECONDITION:
+        // There's no point in continuing to write to this pipe since the other
+        // end is gone. Avoid writing any future messages. Hide write failures
+        // from the caller since we'd like them to continue consuming any
+        // backlog of incoming messages before regarding the message pipe as
+        // closed.
+        this.dropWrites_ = true;
+        break;
+      default:
+        // This particular write was rejected, presumably because of bad input.
+        // The pipe is not necessarily in a bad state.
+        return false;
+    }
+    return true;
+  };
+
+  Connector.prototype.setIncomingReceiver = function(receiver) {
+    this.incomingReceiver_ = receiver;
+  };
+
+  Connector.prototype.setErrorHandler = function(handler) {
+    this.errorHandler_ = handler;
+  };
+
+  Connector.prototype.encounteredError = function() {
+    return this.error_;
+  };
+
+  Connector.prototype.waitToReadMore_ = function() {
+    this.readWaitCookie_ = support.asyncWait(this.handle_,
+                                             core.HANDLE_SIGNAL_READABLE,
+                                             this.readMore_.bind(this));
+  };
+
+  Connector.prototype.readMore_ = function(result) {
+    for (;;) {
+      var read = core.readMessage(this.handle_,
+                                  core.READ_MESSAGE_FLAG_NONE);
+      if (read.result == core.RESULT_SHOULD_WAIT) {
+        this.waitToReadMore_();
+        return;
+      }
+      if (read.result != core.RESULT_OK) {
+        this.error_ = true;
+        if (this.errorHandler_)
+          this.errorHandler_.onError(read.result);
+        return;
+      }
+      var messageBuffer = new buffer.Buffer(read.buffer);
+      var message = new codec.Message(messageBuffer, read.handles);
+      if (this.incomingReceiver_) {
+          this.incomingReceiver_.accept(message);
+      }
+    }
+  };
+
+  // The TestConnector subclass is only intended to be used in unit tests. It
+  // enables delivering a message to the pipe's handle without an async wait.
+
+  function TestConnector(handle) {
+    Connector.call(this, handle);
+  }
+
+  TestConnector.prototype = Object.create(Connector.prototype);
+
+  TestConnector.prototype.waitToReadMore_ = function() {
+  };
+
+  TestConnector.prototype.deliverMessage = function() {
+    this.readMore_(core.RESULT_OK);
+  }
+
+  var exports = {};
+  exports.Connector = Connector;
+  exports.TestConnector = TestConnector;
+  return exports;
+});
diff --git a/mojo/public/js/bindings/constants.cc b/mojo/public/js/bindings/constants.cc
new file mode 100644
index 0000000..547279d
--- /dev/null
+++ b/mojo/public/js/bindings/constants.cc
@@ -0,0 +1,17 @@
+// Copyright 2014 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/js/bindings/constants.h"
+
+namespace mojo {
+
+const char kBufferModuleName[] = "mojo/public/js/bindings/buffer";
+const char kCodecModuleName[] = "mojo/public/js/bindings/codec";
+const char kConnectionModuleName[] = "mojo/public/js/bindings/connection";
+const char kConnectorModuleName[] = "mojo/public/js/bindings/connector";
+const char kUnicodeModuleName[] = "mojo/public/js/bindings/unicode";
+const char kRouterModuleName[] = "mojo/public/js/bindings/router";
+const char kValidatorModuleName[] = "mojo/public/js/bindings/validator";
+
+}  // namespace mojo
diff --git a/mojo/public/js/bindings/constants.h b/mojo/public/js/bindings/constants.h
new file mode 100644
index 0000000..9927c8e
--- /dev/null
+++ b/mojo/public/js/bindings/constants.h
@@ -0,0 +1,21 @@
+// Copyright 2014 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_JS_BINDINGS_CONSTANTS_H_
+#define MOJO_PUBLIC_JS_BINDINGS_CONSTANTS_H_
+
+namespace mojo {
+
+// JavaScript module names:
+extern const char kBufferModuleName[];
+extern const char kCodecModuleName[];
+extern const char kConnectionModuleName[];
+extern const char kConnectorModuleName[];
+extern const char kUnicodeModuleName[];
+extern const char kRouterModuleName[];
+extern const char kValidatorModuleName[];
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_JS_BINDINGS_CONSTANTS_H_
diff --git a/mojo/public/js/bindings/core.js b/mojo/public/js/bindings/core.js
new file mode 100644
index 0000000..95d49a5
--- /dev/null
+++ b/mojo/public/js/bindings/core.js
@@ -0,0 +1,229 @@
+// Copyright 2014 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.
+
+// Module "mojo/public/js/bindings/core"
+//
+// Note: This file is for documentation purposes only. The code here is not
+// actually executed. The real module is implemented natively in Mojo.
+//
+// This module provides the JavaScript bindings for mojo/public/c/system/core.h.
+// Refer to that file for more detailed documentation for equivalent methods.
+
+while (1);
+
+/**
+ * MojoHandle: An opaque handles to a Mojo object (e.g. a message pipe).
+ */
+var kInvalidHandle;
+
+/**
+ * MojoResult {number}: Result codes for Mojo operations.
+ * See core.h for more information.
+ */
+var RESULT_OK;
+var RESULT_CANCELLED;
+var RESULT_UNKNOWN;
+var RESULT_INVALID_ARGUMENT;
+var RESULT_DEADLINE_EXCEEDED;
+var RESULT_NOT_FOUND;
+var RESULT_ALREADY_EXISTS;
+var RESULT_PERMISSION_DENIED;
+var RESULT_RESOURCE_EXHAUSTED;
+var RESULT_FAILED_PRECONDITION;
+var RESULT_ABORTED;
+var RESULT_OUT_OF_RANGE;
+var RESULT_UNIMPLEMENTED;
+var RESULT_INTERNAL;
+var RESULT_UNAVAILABLE;
+var RESULT_DATA_LOSS;
+var RESULT_BUSY;
+var RESULT_SHOULD_WAIT;
+
+/**
+ * MojoDeadline {number}: Used to specify deadlines (timeouts), in microseconds.
+ * See core.h for more information.
+ */
+var DEADLINE_INDEFINITE;
+
+/**
+ * MojoHandleSignals: Used to specify signals that can be waited on for a handle
+ *(and which can be triggered), e.g., the ability to read or write to
+ * the handle.
+ * See core.h for more information.
+ */
+var HANDLE_SIGNAL_NONE;
+var HANDLE_SIGNAL_READABLE;
+var HANDLE_SIGNAL_WRITABLE;
+
+/**
+ * MojoCreateDataMessageOptions: Used to specify creation parameters for a data
+ * pipe to |createDataMessage()|.
+ * See core.h for more information.
+ */
+dictionary MojoCreateDataMessageOptions {
+  MojoCreateDataMessageOptionsFlags flags;  // See below.
+};
+
+// MojoCreateDataMessageOptionsFlags
+var CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE;
+
+/*
+ * MojoWriteMessageFlags: Used to specify different modes to |writeMessage()|.
+ * See core.h for more information.
+ */
+var WRITE_MESSAGE_FLAG_NONE;
+
+/**
+ * MojoReadMessageFlags: Used to specify different modes to |readMessage()|.
+ * See core.h for more information.
+ */
+var READ_MESSAGE_FLAG_NONE;
+var READ_MESSAGE_FLAG_MAY_DISCARD;
+
+/**
+ * MojoCreateDataPipeOptions: Used to specify creation parameters for a data
+ * pipe to |createDataPipe()|.
+ * See core.h for more information.
+ */
+dictionary MojoCreateDataPipeOptions {
+  MojoCreateDataPipeOptionsFlags flags;  // See below.
+  int32 elementNumBytes;  // The size of an element, in bytes.
+  int32 capacityNumBytes;  // The capacity of the data pipe, in bytes.
+};
+
+// MojoCreateDataPipeOptionsFlags
+var CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
+var CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD;
+
+/*
+ * MojoWriteDataFlags: Used to specify different modes to |writeData()|.
+ * See core.h for more information.
+ */
+var WRITE_DATA_FLAG_NONE;
+var WRITE_DATA_FLAG_ALL_OR_NONE;
+
+/**
+ * MojoReadDataFlags: Used to specify different modes to |readData()|.
+ * See core.h for more information.
+ */
+var READ_DATA_FLAG_NONE;
+var READ_DATA_FLAG_ALL_OR_NONE;
+var READ_DATA_FLAG_DISCARD;
+var READ_DATA_FLAG_QUERY;
+
+/**
+ * Closes the given |handle|. See MojoClose for more info.
+ * @param {MojoHandle} Handle to close.
+ * @return {MojoResult} Result code.
+ */
+function close(handle) { [native code] }
+
+/**
+ * Waits on the given handle until a signal indicated by |signals| is
+ * satisfied or until |deadline| is passed. See MojoWait for more information.
+ *
+ * @param {MojoHandle} handle Handle to wait on.
+ * @param {MojoHandleSignals} signals Specifies the condition to wait for.
+ * @param {MojoDeadline} deadline Stops waiting if this is reached.
+ * @return {MojoResult} Result code.
+ */
+function wait(handle, signals, deadline) { [native code] }
+
+/**
+ * Waits on |handles[0]|, ..., |handles[handles.length-1]| for at least one of
+ * them to satisfy the state indicated by |flags[0]|, ...,
+ * |flags[handles.length-1]|, respectively, or until |deadline| has passed.
+ * See MojoWaitMany for more information.
+ *
+ * @param {Array.MojoHandle} handles Handles to wait on.
+ * @param {Array.MojoHandleSignals} signals Specifies the condition to wait for,
+ *   for each corresponding handle. Must be the same length as |handles|.
+ * @param {MojoDeadline} deadline Stops waiting if this is reached.
+ * @return {MojoResult} Result code.
+ */
+function waitMany(handles, signals, deadline) { [native code] }
+
+/**
+ * Creates a message pipe. This function always succeeds.
+ * See MojoCreateMessagePipe for more information on message pipes.
+ *
+ * @param {MojoCreateMessagePipeOptions} optionsDict Options to control the
+ * message pipe parameters. May be null.
+ * @return {MessagePipe} An object of the form {
+ *     handle0,
+ *     handle1,
+ *   }
+ *   where |handle0| and |handle1| are MojoHandles to each end of the channel.
+ */
+function createMessagePipe(optionsDict) { [native code] }
+
+/**
+ * Writes a message to the message pipe endpoint given by |handle|. See
+ * MojoWriteMessage for more information, including return codes.
+ *
+ * @param {MojoHandle} handle The endpoint to write to.
+ * @param {ArrayBufferView} buffer The message data. May be empty.
+ * @param {Array.MojoHandle} handlesArray Any handles to attach. Handles are
+ *   transferred on success and will no longer be valid. May be empty.
+ * @param {MojoWriteMessageFlags} flags Flags.
+ * @return {MojoResult} Result code.
+ */
+function writeMessage(handle, buffer, handlesArray, flags) { [native code] }
+
+/**
+ * Reads a message from the message pipe endpoint given by |handle|. See
+ * MojoReadMessage for more information, including return codes.
+ *
+ * @param {MojoHandle} handle The endpoint to read from.
+ * @param {MojoReadMessageFlags} flags Flags.
+ * @return {object} An object of the form {
+ *     result,  // |RESULT_OK| on success, error code otherwise.
+ *     buffer,  // An ArrayBufferView of the message data (only on success).
+ *     handles  // An array of MojoHandles transferred, if any.
+ *   }
+ */
+function readMessage(handle, flags) { [native code] }
+
+/**
+ * Creates a data pipe, which is a unidirectional communication channel for
+ * unframed data, with the given options. See MojoCreateDataPipe for more
+ * more information, including return codes.
+ *
+ * @param {MojoCreateDataPipeOptions} optionsDict Options to control the data
+ *   pipe parameters. May be null.
+ * @return {object} An object of the form {
+ *     result,  // |RESULT_OK| on success, error code otherwise.
+ *     producerHandle,  // MojoHandle to use with writeData (only on success).
+ *     consumerHandle,  // MojoHandle to use with readData (only on success).
+ *   }
+ */
+function createDataPipe(optionsDict) { [native code] }
+
+/**
+ * Writes the given data to the data pipe producer given by |handle|. See
+ * MojoWriteData for more information, including return codes.
+ *
+ * @param {MojoHandle} handle A producerHandle returned by createDataPipe.
+ * @param {ArrayBufferView} buffer The data to write.
+ * @param {MojoWriteDataFlags} flags Flags.
+ * @return {object} An object of the form {
+ *     result,  // |RESULT_OK| on success, error code otherwise.
+ *     numBytes,  // The number of bytes written.
+ *   }
+ */
+function writeData(handle, buffer, flags) { [native code] }
+
+/**
+ * Reads data from the data pipe consumer given by |handle|. May also
+ * be used to discard data. See MojoReadData for more information, including
+ * return codes.
+ *
+ * @param {MojoHandle} handle A consumerHandle returned by createDataPipe.
+ * @param {MojoReadDataFlags} flags Flags.
+ * @return {object} An object of the form {
+ *     result,  // |RESULT_OK| on success, error code otherwise.
+ *     buffer,  // An ArrayBufferView of the data read (only on success).
+ *   }
+ */
+function readData(handle, flags) { [native code] }
diff --git a/mojo/public/js/bindings/core_unittests.js b/mojo/public/js/bindings/core_unittests.js
new file mode 100644
index 0000000..b115cc0
--- /dev/null
+++ b/mojo/public/js/bindings/core_unittests.js
@@ -0,0 +1,118 @@
+// Copyright 2014 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.
+
+define([
+    "gin/test/expect",
+    "mojo/public/js/bindings/core",
+    "gc",
+  ], function(expect, core, gc) {
+  runWithMessagePipe(testNop);
+  runWithMessagePipe(testReadAndWriteMessage);
+  runWithMessagePipeWithOptions(testNop);
+  runWithMessagePipeWithOptions(testReadAndWriteMessage);
+  runWithDataPipe(testNop);
+  runWithDataPipe(testReadAndWriteDataPipe);
+  runWithDataPipeWithOptions(testNop);
+  runWithDataPipeWithOptions(testReadAndWriteDataPipe);
+  gc.collectGarbage();  // should not crash
+  this.result = "PASS";
+
+  function runWithMessagePipe(test) {
+    var pipe = core.createMessagePipe();
+    expect(pipe.result).toBe(core.RESULT_OK);
+
+    test(pipe);
+
+    expect(core.close(pipe.handle0)).toBe(core.RESULT_OK);
+    expect(core.close(pipe.handle1)).toBe(core.RESULT_OK);
+  }
+
+  function runWithMessagePipeWithOptions(test) {
+    var pipe = core.createMessagePipe({
+        flags: core.CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE
+    });
+    expect(pipe.result).toBe(core.RESULT_OK);
+
+    test(pipe);
+
+    expect(core.close(pipe.handle0)).toBe(core.RESULT_OK);
+    expect(core.close(pipe.handle1)).toBe(core.RESULT_OK);
+  }
+
+  function runWithDataPipe(test) {
+    var pipe = core.createDataPipe();
+    expect(pipe.result).toBe(core.RESULT_OK);
+
+    test(pipe);
+
+    expect(core.close(pipe.producerHandle)).toBe(core.RESULT_OK);
+    expect(core.close(pipe.consumerHandle)).toBe(core.RESULT_OK);
+  }
+
+  function runWithDataPipeWithOptions(test) {
+    var pipe = core.createDataPipe({
+        flags: core.CREATE_DATA_PIPE_OPTIONS_FLAG_NONE,
+        elementNumBytes: 1,
+        capacityNumBytes: 64
+        });
+    expect(pipe.result).toBe(core.RESULT_OK);
+
+    test(pipe);
+
+    expect(core.close(pipe.producerHandle)).toBe(core.RESULT_OK);
+    expect(core.close(pipe.consumerHandle)).toBe(core.RESULT_OK);
+  }
+
+  function testNop(pipe) {
+  }
+
+  function testReadAndWriteMessage(pipe) {
+    var senderData = new Uint8Array(42);
+    for (var i = 0; i < senderData.length; ++i) {
+      senderData[i] = i * i;
+    }
+
+    var result = core.writeMessage(
+      pipe.handle0, senderData, [],
+      core.WRITE_MESSAGE_FLAG_NONE);
+
+    expect(result).toBe(core.RESULT_OK);
+
+    var read = core.readMessage(
+      pipe.handle1, core.READ_MESSAGE_FLAG_NONE);
+
+    expect(read.result).toBe(core.RESULT_OK);
+    expect(read.buffer.byteLength).toBe(42);
+    expect(read.handles.length).toBe(0);
+
+    var memory = new Uint8Array(read.buffer);
+    for (var i = 0; i < memory.length; ++i)
+      expect(memory[i]).toBe((i * i) & 0xFF);
+  }
+
+  function testReadAndWriteDataPipe(pipe) {
+    var senderData = new Uint8Array(42);
+    for (var i = 0; i < senderData.length; ++i) {
+      senderData[i] = i * i;
+    }
+
+    var write = core.writeData(
+      pipe.producerHandle, senderData,
+      core.WRITE_DATA_FLAG_ALL_OR_NONE);
+
+    expect(write.result).toBe(core.RESULT_OK);
+    expect(write.numBytes).toBe(42);
+
+    var read = core.readData(
+      pipe.consumerHandle, core.READ_DATA_FLAG_ALL_OR_NONE);
+
+    expect(read.result).toBe(core.RESULT_OK);
+    expect(read.buffer.byteLength).toBe(42);
+
+    var memory = new Uint8Array(read.buffer);
+    for (var i = 0; i < memory.length; ++i)
+      expect(memory[i]).toBe((i * i) & 0xFF);
+  }
+
+});
diff --git a/mojo/public/js/bindings/router.js b/mojo/public/js/bindings/router.js
new file mode 100644
index 0000000..3682392
--- /dev/null
+++ b/mojo/public/js/bindings/router.js
@@ -0,0 +1,135 @@
+// Copyright 2014 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.
+
+define("mojo/public/js/bindings/router", [
+  "mojo/public/js/bindings/codec",
+  "mojo/public/js/bindings/connector",
+  "mojo/public/js/bindings/validator",
+], function(codec, connector, validator) {
+
+  function Router(handle, connectorFactory) {
+    if (connectorFactory === undefined)
+      connectorFactory = connector.Connector;
+    this.connector_ = new connectorFactory(handle);
+    this.incomingReceiver_ = null;
+    this.nextRequestID_ = 0;
+    this.responders_ = {};
+    this.payloadValidators_ = [];
+
+    this.connector_.setIncomingReceiver({
+        accept: this.handleIncomingMessage_.bind(this),
+    });
+    this.connector_.setErrorHandler({
+        onError: this.handleConnectionError_.bind(this),
+    });
+  }
+
+  Router.prototype.close = function() {
+    this.responders_ = {};  // Drop any responders.
+    this.connector_.close();
+  };
+
+  Router.prototype.accept = function(message) {
+    this.connector_.accept(message);
+  };
+
+  Router.prototype.reject = function(message) {
+    // TODO(mpcomplete): no way to trasmit errors over a Connection.
+  };
+
+  Router.prototype.acceptWithResponder = function(message, responder) {
+    // Reserve 0 in case we want it to convey special meaning in the future.
+    var requestID = this.nextRequestID_++;
+    if (requestID == 0)
+      requestID = this.nextRequestID_++;
+
+    message.setRequestID(requestID);
+    var result = this.connector_.accept(message);
+
+    this.responders_[requestID] = responder;
+
+    // TODO(mpcomplete): accept should return a Promise too, maybe?
+    if (result)
+      return Promise.resolve();
+    return Promise.reject(Error("Connection error"));
+  };
+
+  Router.prototype.setIncomingReceiver = function(receiver) {
+    this.incomingReceiver_ = receiver;
+  };
+
+  Router.prototype.setPayloadValidators = function(payloadValidators) {
+    this.payloadValidators_ = payloadValidators;
+  };
+
+  Router.prototype.encounteredError = function() {
+    return this.connector_.encounteredError();
+  };
+
+  Router.prototype.handleIncomingMessage_ = function(message) {
+    var noError = validator.validationError.NONE;
+    var messageValidator = new validator.Validator(message);
+    var err = messageValidator.validateMessageHeader();
+    for (var i = 0; err === noError && i < this.payloadValidators_.length; ++i)
+      err = this.payloadValidators_[i](messageValidator);
+
+    if (err == noError)
+      this.handleValidIncomingMessage_(message);
+    else
+      this.handleInvalidIncomingMessage_(message, err);
+  };
+
+  Router.prototype.handleValidIncomingMessage_ = function(message) {
+    if (message.expectsResponse()) {
+      if (this.incomingReceiver_) {
+        this.incomingReceiver_.acceptWithResponder(message, this);
+      } else {
+        // If we receive a request expecting a response when the client is not
+        // listening, then we have no choice but to tear down the pipe.
+        this.close();
+      }
+    } else if (message.isResponse()) {
+      var reader = new codec.MessageReader(message);
+      var requestID = reader.requestID;
+      var responder = this.responders_[requestID];
+      delete this.responders_[requestID];
+      responder.accept(message);
+    } else {
+      if (this.incomingReceiver_)
+        this.incomingReceiver_.accept(message);
+    }
+  }
+
+  Router.prototype.handleInvalidIncomingMessage_ = function(message, error) {
+    this.close();
+  }
+
+  Router.prototype.handleConnectionError_ = function(result) {
+    for (var each in this.responders_)
+      this.responders_[each].reject(result);
+    this.close();
+  };
+
+  // The TestRouter subclass is only intended to be used in unit tests.
+  // It defeats valid message handling and delgates invalid message handling.
+
+  function TestRouter(handle, connectorFactory) {
+    Router.call(this, handle, connectorFactory);
+  }
+
+  TestRouter.prototype = Object.create(Router.prototype);
+
+  TestRouter.prototype.handleValidIncomingMessage_ = function() {
+  };
+
+  TestRouter.prototype.handleInvalidIncomingMessage_ =
+      function(message, error) {
+        this.validationErrorHandler(error);
+      };
+
+  var exports = {};
+  exports.Router = Router;
+  exports.TestRouter = TestRouter;
+  return exports;
+});
diff --git a/mojo/public/js/bindings/struct_unittests.js b/mojo/public/js/bindings/struct_unittests.js
new file mode 100644
index 0000000..b9948a9
--- /dev/null
+++ b/mojo/public/js/bindings/struct_unittests.js
@@ -0,0 +1,79 @@
+// Copyright 2014 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.
+
+define([
+    "gin/test/expect",
+    "mojo/public/interfaces/bindings/tests/rect.mojom",
+    "mojo/public/interfaces/bindings/tests/test_structs.mojom"
+], function(expect,
+            rect,
+            testStructs) {
+
+  function testConstructors() {
+    var r = new rect.Rect();
+    expect(r).toEqual(new rect.Rect({x:0, y:0, width:0, height:0}));
+    expect(r).toEqual(new rect.Rect({foo:100, bar:200}));
+
+    r.x = 10;
+    r.y = 20;
+    r.width = 30;
+    r.height = 40;
+    var rp = new testStructs.RectPair({first: r, second: r});
+    expect(rp.first).toEqual(r);
+    expect(rp.second).toEqual(r);
+
+    expect(new testStructs.RectPair({second: r}).first).toBeNull();
+
+    var nr = new testStructs.NamedRegion();
+    expect(nr.name).toBeNull();
+    expect(nr.rects).toBeNull();
+    expect(nr).toEqual(new testStructs.NamedRegion({}));
+
+    nr.name = "foo";
+    nr.rects = [r, r, r];
+    expect(nr).toEqual(new testStructs.NamedRegion({
+      name: "foo",
+      rects: [r, r, r],
+    }));
+
+    var e = new testStructs.EmptyStruct();
+    expect(e).toEqual(new testStructs.EmptyStruct({foo:123}));
+  }
+
+  function testNoDefaultFieldValues() {
+    var s = new testStructs.NoDefaultFieldValues();
+    expect(s.f0).toEqual(false);
+
+    // f1 - f10, number type fields
+    for (var i = 1; i <= 10; i++)
+      expect(s["f" + i]).toEqual(0);
+
+    // f11,12 strings, f13-22 handles, f23-f26 arrays, f27,28 structs
+    for (var i = 11; i <= 28; i++)
+      expect(s["f" + i]).toBeNull();
+  }
+
+  function testDefaultFieldValues() {
+    var s = new testStructs.DefaultFieldValues();
+    expect(s.f0).toEqual(true);
+
+    // f1 - f12, number type fields
+    for (var i = 1; i <= 12; i++)
+      expect(s["f" + i]).toEqual(100);
+
+    // f13,14 "foo"
+    for (var i = 13; i <= 14; i++)
+      expect(s["f" + i]).toEqual("foo");
+
+    // f15,16 a default instance of Rect
+    var r = new rect.Rect();
+    expect(s.f15).toEqual(r);
+    expect(s.f16).toEqual(r);
+  }
+
+  testConstructors();
+  testNoDefaultFieldValues();
+  testDefaultFieldValues();
+  this.result = "PASS";
+});
\ No newline at end of file
diff --git a/mojo/public/js/bindings/support.js b/mojo/public/js/bindings/support.js
new file mode 100644
index 0000000..58df6bd
--- /dev/null
+++ b/mojo/public/js/bindings/support.js
@@ -0,0 +1,30 @@
+// Copyright 2014 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.
+
+// Module "mojo/public/js/bindings/support"
+//
+// Note: This file is for documentation purposes only. The code here is not
+// actually executed. The real module is implemented natively in Mojo.
+
+while (1);
+
+/*
+ * Waits on the given handle until the state indicated by |signals| is
+ * satisfied.
+ *
+ * @param {MojoHandle} handle The handle to wait on.
+ * @param {MojoHandleSignals} signals Specifies the condition to wait for.
+ * @param {function (mojoResult)} callback Called with the result the wait is
+ * complete. See MojoWait for possible result codes.
+ *
+ * @return {MojoWaitId} A waitId that can be passed to cancelWait to cancel the
+ * wait.
+ */
+function asyncWait(handle, signals, callback) { [native code] }
+
+/*
+ * Cancels the asyncWait operation specified by the given |waitId|.
+ * @param {MojoWaitId} waitId The waitId returned by asyncWait.
+ */
+function cancelWait(waitId) { [native code] }
diff --git a/mojo/public/js/bindings/tests/validation_test_input_parser.js b/mojo/public/js/bindings/tests/validation_test_input_parser.js
new file mode 100644
index 0000000..98b1c19
--- /dev/null
+++ b/mojo/public/js/bindings/tests/validation_test_input_parser.js
@@ -0,0 +1,299 @@
+// Copyright 2014 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.
+
+// Support for parsing binary sequences encoded as readable strings
+// or ".data" files. The input format is described here:
+// mojo/public/cpp/bindings/tests/validation_test_input_parser.h
+
+define([
+    "mojo/public/js/bindings/buffer"
+  ], function(buffer) {
+
+  // Files and Lines represent the raw text from an input string
+  // or ".data" file.
+
+  function InputError(message, line) {
+    this.message = message;
+    this.line = line;
+  }
+
+  InputError.prototype.toString = function() {
+    var s = 'Error: ' + this.message;
+    if (this.line)
+      s += ', at line ' +
+           (this.line.number + 1) + ': "' + this.line.contents + '"';
+    return s;
+  }
+
+  function File(contents) {
+    this.contents = contents;
+    this.index = 0;
+    this.lineNumber = 0;
+  }
+
+  File.prototype.endReached = function() {
+    return this.index >= this.contents.length;
+  }
+
+  File.prototype.nextLine = function() {
+    if (this.endReached())
+      return null;
+    var start = this.index;
+    var end = this.contents.indexOf('\n', start);
+    if (end == -1)
+      end = this.contents.length;
+    this.index = end + 1;
+    return new Line(this.contents.substring(start, end), this.lineNumber++);
+  }
+
+  function Line(contents, number) {
+    var i = contents.indexOf('//');
+    var s = (i == -1) ? contents.trim() : contents.substring(0, i).trim();
+    this.contents = contents;
+    this.items = (s.length > 0) ? s.split(/\s+/) : [];
+    this.index = 0;
+    this.number = number;
+  }
+
+  Line.prototype.endReached = function() {
+    return this.index >= this.items.length;
+  }
+
+  var ITEM_TYPE_SIZES = {
+    u1: 1, u2: 2, u4: 4, u8: 8, s1: 1, s2: 2, s4: 4, s8: 8, b: 1, f: 4, d: 8,
+    dist4: 4, dist8: 8, anchr: 0, handles: 0
+  };
+
+  function isValidItemType(type) {
+    return ITEM_TYPE_SIZES[type] !== undefined;
+  }
+
+  Line.prototype.nextItem = function() {
+    if (this.endReached())
+      return null;
+
+    var itemString = this.items[this.index++];
+    var type = 'u1';
+    var value = itemString;
+
+    if (itemString.charAt(0) == '[') {
+      var i = itemString.indexOf(']');
+      if (i != -1 && i + 1 < itemString.length) {
+        type = itemString.substring(1, i);
+        value = itemString.substring(i + 1);
+      } else {
+        throw new InputError('invalid item', this);
+      }
+    }
+    if (!isValidItemType(type))
+      throw new InputError('invalid item type', this);
+
+    return new Item(this, type, value);
+  }
+
+  // The text for each whitespace delimited binary data "item" is represented
+  // by an Item.
+
+  function Item(line, type, value) {
+    this.line = line;
+    this.type = type;
+    this.value = value;
+    this.size = ITEM_TYPE_SIZES[type];
+  }
+
+  Item.prototype.isFloat = function() {
+    return this.type == 'f' || this.type == 'd';
+  }
+
+  Item.prototype.isInteger = function() {
+    return ['u1', 'u2', 'u4', 'u8',
+            's1', 's2', 's4', 's8'].indexOf(this.type) != -1;
+  }
+
+  Item.prototype.isNumber = function() {
+    return this.isFloat() || this.isInteger();
+  }
+
+  Item.prototype.isByte = function() {
+    return this.type == 'b';
+  }
+
+  Item.prototype.isDistance = function() {
+    return this.type == 'dist4' || this.type == 'dist8';
+  }
+
+  Item.prototype.isAnchor = function() {
+    return this.type == 'anchr';
+  }
+
+  Item.prototype.isHandles = function() {
+    return this.type == 'handles';
+  }
+
+  // A TestMessage represents the complete binary message loaded from an input
+  // string or ".data" file. The parseTestMessage() function below constructs
+  // a TestMessage from a File.
+
+  function TestMessage(byteLength) {
+    this.index = 0;
+    this.buffer = new buffer.Buffer(byteLength);
+    this.distances = {};
+    this.handleCount = 0;
+  }
+
+  function checkItemNumberValue(item, n, min, max) {
+    if (n < min || n > max)
+      throw new InputError('invalid item value', item.line);
+  }
+
+  TestMessage.prototype.addNumber = function(item) {
+    var n = item.isInteger() ? parseInt(item.value) : parseFloat(item.value);
+    if (Number.isNaN(n))
+      throw new InputError("can't parse item value", item.line);
+
+    switch(item.type) {
+      case 'u1':
+        checkItemNumberValue(item, n, 0, 0xFF);
+        this.buffer.setUint8(this.index, n);
+        break;
+      case 'u2':
+        checkItemNumberValue(item, n, 0, 0xFFFF);
+        this.buffer.setUint16(this.index, n);
+        break;
+      case 'u4':
+        checkItemNumberValue(item, n, 0, 0xFFFFFFFF);
+        this.buffer.setUint32(this.index, n);
+        break;
+      case 'u8':
+        checkItemNumberValue(item, n, 0, Number.MAX_SAFE_INTEGER);
+        this.buffer.setUint64(this.index, n);
+        break;
+      case 's1':
+        checkItemNumberValue(item, n, -128, 127);
+        this.buffer.setInt8(this.index, n);
+        break;
+      case 's2':
+        checkItemNumberValue(item, n, -32768, 32767);
+        this.buffer.setInt16(this.index, n);
+        break;
+      case 's4':
+        checkItemNumberValue(item, n, -2147483648, 2147483647);
+        this.buffer.setInt32(this.index, n);
+        break;
+      case 's8':
+        checkItemNumberValue(item, n,
+                             Number.MIN_SAFE_INTEGER,
+                             Number.MAX_SAFE_INTEGER);
+        this.buffer.setInt64(this.index, n);
+        break;
+      case 'f':
+        this.buffer.setFloat32(this.index, n);
+        break;
+      case 'd':
+        this.buffer.setFloat64(this.index, n);
+        break;
+
+      default:
+        throw new InputError('unrecognized item type', item.line);
+      }
+  }
+
+  TestMessage.prototype.addByte = function(item) {
+    if (!/^[01]{8}$/.test(item.value))
+      throw new InputError('invalid byte item value', item.line);
+    function b(i) {
+      return (item.value.charAt(7 - i) == '1') ? 1 << i : 0;
+    }
+    var n = b(0) | b(1) | b(2) | b(3) | b(4) | b(5) | b(6) | b(7);
+    this.buffer.setUint8(this.index, n);
+  }
+
+  TestMessage.prototype.addDistance = function(item) {
+    if (this.distances[item.value])
+      throw new InputError('duplicate distance item', item.line);
+    this.distances[item.value] = {index: this.index, item: item};
+  }
+
+  TestMessage.prototype.addAnchor = function(item) {
+    var dist = this.distances[item.value];
+    if (!dist)
+      throw new InputError('unmatched anchor item', item.line);
+    delete this.distances[item.value];
+
+    var n = this.index - dist.index;
+    // TODO(hansmuller): validate n
+
+    if (dist.item.type == 'dist4')
+      this.buffer.setUint32(dist.index, n);
+    else if (dist.item.type == 'dist8')
+      this.buffer.setUint64(dist.index, n);
+    else
+      throw new InputError('unrecognzed distance item type', dist.item.line);
+  }
+
+  TestMessage.prototype.addHandles = function(item) {
+    this.handleCount = parseInt(item.value);
+    if (Number.isNaN(this.handleCount))
+      throw new InputError("can't parse handleCount", item.line);
+  }
+
+  TestMessage.prototype.addItem = function(item) {
+    if (item.isNumber())
+      this.addNumber(item);
+    else if (item.isByte())
+      this.addByte(item);
+    else if (item.isDistance())
+      this.addDistance(item);
+    else if (item.isAnchor())
+      this.addAnchor(item);
+    else if (item.isHandles())
+      this.addHandles(item);
+    else
+      throw new InputError('unrecognized item type', item.line);
+
+    this.index += item.size;
+  }
+
+  TestMessage.prototype.unanchoredDistances = function() {
+    var names = null;
+    for (var name in this.distances) {
+      if (this.distances.hasOwnProperty(name))
+        names = (names === null) ? name : names + ' ' + name;
+    }
+    return names;
+  }
+
+  function parseTestMessage(text) {
+    var file = new File(text);
+    var items = [];
+    var messageLength = 0;
+    while(!file.endReached()) {
+      var line = file.nextLine();
+      while (!line.endReached()) {
+        var item = line.nextItem();
+        if (item.isHandles() && items.length > 0)
+          throw new InputError('handles item is not first');
+        messageLength += item.size;
+        items.push(item);
+      }
+    }
+
+    var msg = new TestMessage(messageLength);
+    for (var i = 0; i < items.length; i++)
+      msg.addItem(items[i]);
+
+    if (messageLength != msg.index)
+      throw new InputError('failed to compute message length');
+    var names = msg.unanchoredDistances();
+    if (names)
+      throw new InputError('no anchors for ' + names, 0);
+
+    return msg;
+  }
+
+  var exports = {};
+  exports.parseTestMessage = parseTestMessage;
+  exports.InputError = InputError;
+  return exports;
+});
diff --git a/mojo/public/js/bindings/unicode.js b/mojo/public/js/bindings/unicode.js
new file mode 100644
index 0000000..ba0f00f
--- /dev/null
+++ b/mojo/public/js/bindings/unicode.js
@@ -0,0 +1,51 @@
+// Copyright 2014 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.
+
+/**
+ * Defines functions for translating between JavaScript strings and UTF8 strings
+ * stored in ArrayBuffers. There is much room for optimization in this code if
+ * it proves necessary.
+ */
+define("mojo/public/js/bindings/unicode", function() {
+  /**
+   * Decodes the UTF8 string from the given buffer.
+   * @param {ArrayBufferView} buffer The buffer containing UTF8 string data.
+   * @return {string} The corresponding JavaScript string.
+   */
+  function decodeUtf8String(buffer) {
+    return decodeURIComponent(escape(String.fromCharCode.apply(null, buffer)));
+  }
+
+  /**
+   * Encodes the given JavaScript string into UTF8.
+   * @param {string} str The string to encode.
+   * @param {ArrayBufferView} outputBuffer The buffer to contain the result.
+   * Should be pre-allocated to hold enough space. Use |utf8Length| to determine
+   * how much space is required.
+   * @return {number} The number of bytes written to |outputBuffer|.
+   */
+  function encodeUtf8String(str, outputBuffer) {
+    var utf8String = unescape(encodeURIComponent(str));
+    if (outputBuffer.length < utf8String.length)
+      throw new Error("Buffer too small for encodeUtf8String");
+    for (var i = 0; i < outputBuffer.length && i < utf8String.length; i++)
+      outputBuffer[i] = utf8String.charCodeAt(i);
+    return i;
+  }
+
+  /**
+   * Returns the number of bytes that a UTF8 encoding of the JavaScript string
+   * |str| would occupy.
+   */
+  function utf8Length(str) {
+    var utf8String = unescape(encodeURIComponent(str));
+    return utf8String.length;
+  }
+
+  var exports = {};
+  exports.decodeUtf8String = decodeUtf8String;
+  exports.encodeUtf8String = encodeUtf8String;
+  exports.utf8Length = utf8Length;
+  return exports;
+});
diff --git a/mojo/public/js/bindings/validation_unittests.js b/mojo/public/js/bindings/validation_unittests.js
new file mode 100644
index 0000000..73fd9c7
--- /dev/null
+++ b/mojo/public/js/bindings/validation_unittests.js
@@ -0,0 +1,302 @@
+// Copyright 2014 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.
+
+define([
+    "console",
+    "file",
+    "gin/test/expect",
+    "mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom",
+    "mojo/public/js/bindings/buffer",
+    "mojo/public/js/bindings/codec",
+    "mojo/public/js/bindings/connection",
+    "mojo/public/js/bindings/connector",
+    "mojo/public/js/bindings/core",
+    "mojo/public/js/bindings/tests/validation_test_input_parser",
+    "mojo/public/js/bindings/router",
+    "mojo/public/js/bindings/validator",
+], function(console,
+            file,
+            expect,
+            testInterface,
+            buffer,
+            codec,
+            connection,
+            connector,
+            core,
+            parser,
+            router,
+            validator) {
+
+  var noError = validator.validationError.NONE;
+
+  function checkTestMessageParser() {
+    function TestMessageParserFailure(message, input) {
+      this.message = message;
+      this.input = input;
+    }
+
+    TestMessageParserFailure.prototype.toString = function() {
+      return 'Error: ' + this.message + ' for "' + this.input + '"';
+    }
+
+    function checkData(data, expectedData, input) {
+      if (data.byteLength != expectedData.byteLength) {
+        var s = "message length (" + data.byteLength + ") doesn't match " +
+            "expected length: " + expectedData.byteLength;
+        throw new TestMessageParserFailure(s, input);
+      }
+
+      for (var i = 0; i < data.byteLength; i++) {
+        if (data.getUint8(i) != expectedData.getUint8(i)) {
+          var s = 'message data mismatch at byte offset ' + i;
+          throw new TestMessageParserFailure(s, input);
+        }
+      }
+    }
+
+    function testFloatItems() {
+      var input = '[f]+.3e9 [d]-10.03';
+      var msg = parser.parseTestMessage(input);
+      var expectedData = new buffer.Buffer(12);
+      expectedData.setFloat32(0, +.3e9);
+      expectedData.setFloat64(4, -10.03);
+      checkData(msg.buffer, expectedData, input);
+    }
+
+    function testUnsignedIntegerItems() {
+      var input = '[u1]0x10// hello world !! \n\r  \t [u2]65535 \n' +
+          '[u4]65536 [u8]0xFFFFFFFFFFFFF 0 0Xff';
+      var msg = parser.parseTestMessage(input);
+      var expectedData = new buffer.Buffer(17);
+      expectedData.setUint8(0, 0x10);
+      expectedData.setUint16(1, 65535);
+      expectedData.setUint32(3, 65536);
+      expectedData.setUint64(7, 0xFFFFFFFFFFFFF);
+      expectedData.setUint8(15, 0);
+      expectedData.setUint8(16, 0xff);
+      checkData(msg.buffer, expectedData, input);
+    }
+
+    function testSignedIntegerItems() {
+      var input = '[s8]-0x800 [s1]-128\t[s2]+0 [s4]-40';
+      var msg = parser.parseTestMessage(input);
+      var expectedData = new buffer.Buffer(15);
+      expectedData.setInt64(0, -0x800);
+      expectedData.setInt8(8, -128);
+      expectedData.setInt16(9, 0);
+      expectedData.setInt32(11, -40);
+      checkData(msg.buffer, expectedData, input);
+    }
+
+    function testByteItems() {
+      var input = '[b]00001011 [b]10000000  // hello world\n [b]00000000';
+      var msg = parser.parseTestMessage(input);
+      var expectedData = new buffer.Buffer(3);
+      expectedData.setUint8(0, 11);
+      expectedData.setUint8(1, 128);
+      expectedData.setUint8(2, 0);
+      checkData(msg.buffer, expectedData, input);
+    }
+
+    function testAnchors() {
+      var input = '[dist4]foo 0 [dist8]bar 0 [anchr]foo [anchr]bar';
+      var msg = parser.parseTestMessage(input);
+      var expectedData = new buffer.Buffer(14);
+      expectedData.setUint32(0, 14);
+      expectedData.setUint8(4, 0);
+      expectedData.setUint64(5, 9);
+      expectedData.setUint8(13, 0);
+      checkData(msg.buffer, expectedData, input);
+    }
+
+    function testHandles() {
+      var input = '// This message has handles! \n[handles]50 [u8]2';
+      var msg = parser.parseTestMessage(input);
+      var expectedData = new buffer.Buffer(8);
+      expectedData.setUint64(0, 2);
+
+      if (msg.handleCount != 50) {
+        var s = 'wrong handle count (' + msg.handleCount + ')';
+        throw new TestMessageParserFailure(s, input);
+      }
+      checkData(msg.buffer, expectedData, input);
+    }
+
+    function testEmptyInput() {
+      var msg = parser.parseTestMessage('');
+      if (msg.buffer.byteLength != 0)
+        throw new TestMessageParserFailure('expected empty message', '');
+    }
+
+    function testBlankInput() {
+      var input = '    \t  // hello world \n\r \t// the answer is 42   ';
+      var msg = parser.parseTestMessage(input);
+      if (msg.buffer.byteLength != 0)
+        throw new TestMessageParserFailure('expected empty message', input);
+    }
+
+    function testInvalidInput() {
+      function parserShouldFail(input) {
+        try {
+          parser.parseTestMessage(input);
+        } catch (e) {
+          if (e instanceof parser.InputError)
+            return;
+          throw new TestMessageParserFailure(
+            'unexpected exception ' + e.toString(), input);
+        }
+        throw new TestMessageParserFailure("didn't detect invalid input", file);
+      }
+
+      ['/ hello world',
+       '[u1]x',
+       '[u2]-1000',
+       '[u1]0x100',
+       '[s2]-0x8001',
+       '[b]1',
+       '[b]1111111k',
+       '[dist4]unmatched',
+       '[anchr]hello [dist8]hello',
+       '[dist4]a [dist4]a [anchr]a',
+       // '[dist4]a [anchr]a [dist4]a [anchr]a',
+       '0 [handles]50'
+      ].forEach(parserShouldFail);
+    }
+
+    try {
+      testFloatItems();
+      testUnsignedIntegerItems();
+      testSignedIntegerItems();
+      testByteItems();
+      testInvalidInput();
+      testEmptyInput();
+      testBlankInput();
+      testHandles();
+      testAnchors();
+    } catch (e) {
+      return e.toString();
+    }
+    return null;
+  }
+
+  function getMessageTestFiles(key) {
+    var sourceRoot = file.getSourceRootDirectory();
+    expect(sourceRoot).not.toBeNull();
+
+    var testDir = sourceRoot +
+      "/mojo/public/interfaces/bindings/tests/data/validation/";
+    var testFiles = file.getFilesInDirectory(testDir);
+    expect(testFiles).not.toBeNull();
+    expect(testFiles.length).toBeGreaterThan(0);
+
+    // The matching ".data" pathnames with the extension removed.
+    return testFiles.filter(function(s) {
+      return s.substr(-5) == ".data";
+    }).map(function(s) {
+      return testDir + s.slice(0, -5);
+    }).filter(function(s) {
+      return s.indexOf(key) != -1;
+    });
+  }
+
+  function readTestMessage(filename) {
+    var contents = file.readFileToString(filename + ".data");
+    expect(contents).not.toBeNull();
+    return parser.parseTestMessage(contents);
+  }
+
+  function readTestExpected(filename) {
+    var contents = file.readFileToString(filename + ".expected");
+    expect(contents).not.toBeNull();
+    return contents.trim();
+  }
+
+  function checkValidationResult(testFile, err) {
+    var actualResult = (err === noError) ? "PASS" : err;
+    var expectedResult = readTestExpected(testFile);
+    if (actualResult != expectedResult)
+      console.log("[Test message validation failed: " + testFile + " ]");
+    expect(actualResult).toEqual(expectedResult);
+  }
+
+  function testMessageValidation(key, filters) {
+    var testFiles = getMessageTestFiles(key);
+    expect(testFiles.length).toBeGreaterThan(0);
+
+    for (var i = 0; i < testFiles.length; i++) {
+      // TODO(hansmuller): Temporarily skipping array pointer overflow tests.
+      if (testFiles[i].indexOf("overflow") != -1) {
+        console.log("[Skipping " + testFiles[i] + "]");
+        continue;
+      }
+
+      var testMessage = readTestMessage(testFiles[i]);
+      var handles = new Array(testMessage.handleCount);
+      var message = new codec.Message(testMessage.buffer, handles);
+      var messageValidator = new validator.Validator(message);
+
+      var err = messageValidator.validateMessageHeader();
+      for (var j = 0; err === noError && j < filters.length; ++j)
+        err = filters[j](messageValidator);
+
+      checkValidationResult(testFiles[i], err);
+    }
+  }
+
+  function testConformanceMessageValidation() {
+    testMessageValidation("conformance_", [
+        testInterface.ConformanceTestInterfaceStub.prototype.validator]);
+  }
+
+  function testNotImplementedMessageValidation() {
+    testMessageValidation("not_implemented_", [
+        testInterface.ConformanceTestInterfaceStub.prototype.validator]);
+  }
+
+  function testIntegratedMessageValidation() {
+    var testFiles = getMessageTestFiles("integration_");
+    expect(testFiles.length).toBeGreaterThan(0);
+
+    for (var i = 0; i < testFiles.length; i++) {
+      // TODO(hansmuller): Temporarily skipping array pointer overflow tests.
+      if (testFiles[i].indexOf("overflow") != -1) {
+        console.log("[Skipping " + testFiles[i] + "]");
+        continue;
+      }
+
+      var testMessage = readTestMessage(testFiles[i]);
+      var handles = new Array(testMessage.handleCount);
+      var testMessagePipe = new core.createMessagePipe();
+      expect(testMessagePipe.result).toBe(core.RESULT_OK);
+
+      var writeMessageValue = core.writeMessage(
+          testMessagePipe.handle0,
+          new Uint8Array(testMessage.buffer.arrayBuffer),
+          new Array(testMessage.handleCount),
+          core.WRITE_MESSAGE_FLAG_NONE);
+      expect(writeMessageValue).toBe(core.RESULT_OK);
+
+      var testConnection = new connection.TestConnection(
+          testMessagePipe.handle1,
+          testInterface.IntegrationTestInterface1Stub,
+          testInterface.IntegrationTestInterface2Proxy);
+
+      var validationError = noError;
+      testConnection.router_.validationErrorHandler = function(err) {
+        validationError = err;
+      }
+
+      testConnection.router_.connector_.deliverMessage();
+      checkValidationResult(testFiles[i], validationError);
+
+      testConnection.close();
+      expect(core.close(testMessagePipe.handle0)).toBe(core.RESULT_OK);
+    }
+  }
+
+  expect(checkTestMessageParser()).toBeNull();
+  testConformanceMessageValidation();
+  testIntegratedMessageValidation();
+  this.result = "PASS";
+});
diff --git a/mojo/public/js/bindings/validator.js b/mojo/public/js/bindings/validator.js
new file mode 100644
index 0000000..de75656
--- /dev/null
+++ b/mojo/public/js/bindings/validator.js
@@ -0,0 +1,291 @@
+// Copyright 2014 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.
+
+define("mojo/public/js/bindings/validator", [
+  "mojo/public/js/bindings/codec",
+], function(codec) {
+
+  var validationError = {
+    NONE: 'VALIDATION_ERROR_NONE',
+    MISALIGNED_OBJECT: 'VALIDATION_ERROR_MISALIGNED_OBJECT',
+    ILLEGAL_MEMORY_RANGE: 'VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE',
+    UNEXPECTED_STRUCT_HEADER: 'VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER',
+    UNEXPECTED_ARRAY_HEADER: 'VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER',
+    ILLEGAL_HANDLE: 'VALIDATION_ERROR_ILLEGAL_HANDLE',
+    UNEXPECTED_INVALID_HANDLE: 'VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE',
+    ILLEGAL_POINTER: 'VALIDATION_ERROR_ILLEGAL_POINTER',
+    UNEXPECTED_NULL_POINTER: 'VALIDATION_ERROR_UNEXPECTED_NULL_POINTER',
+    MESSAGE_HEADER_INVALID_FLAG_COMBINATION:
+        'VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION',
+    MESSAGE_HEADER_MISSING_REQUEST_ID:
+        'VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID'
+  };
+
+  var NULL_MOJO_POINTER = "NULL_MOJO_POINTER";
+
+  function isStringClass(cls) {
+    return cls === codec.String || cls === codec.NullableString;
+  }
+
+  function isHandleClass(cls) {
+    return cls === codec.Handle || cls === codec.NullableHandle;
+  }
+
+  function isNullable(type) {
+    return type === codec.NullableString || type === codec.NullableHandle ||
+        type instanceof codec.NullableArrayOf ||
+        type instanceof codec.NullablePointerTo;
+  }
+
+  function Validator(message) {
+    this.message = message;
+    this.offset = 0;
+    this.handleIndex = 0;
+  }
+
+  Object.defineProperty(Validator.prototype, "offsetLimit", {
+    get: function() { return this.message.buffer.byteLength; }
+  });
+
+  Object.defineProperty(Validator.prototype, "handleIndexLimit", {
+    get: function() { return this.message.handles.length; }
+  });
+
+  // True if we can safely allocate a block of bytes from start to
+  // to start + numBytes.
+  Validator.prototype.isValidRange = function(start, numBytes) {
+    // Only positive JavaScript integers that are less than 2^53
+    // (Number.MAX_SAFE_INTEGER) can be represented exactly.
+    if (start < this.offset || numBytes <= 0 ||
+        !Number.isSafeInteger(start) ||
+        !Number.isSafeInteger(numBytes))
+      return false;
+
+    var newOffset = start + numBytes;
+    if (!Number.isSafeInteger(newOffset) || newOffset > this.offsetLimit)
+      return false;
+
+    return true;
+  }
+
+  Validator.prototype.claimRange = function(start, numBytes) {
+    if (this.isValidRange(start, numBytes)) {
+      this.offset = start + numBytes;
+      return true;
+    }
+    return false;
+  }
+
+  Validator.prototype.claimHandle = function(index) {
+    if (index === codec.kEncodedInvalidHandleValue)
+      return true;
+
+    if (index < this.handleIndex || index >= this.handleIndexLimit)
+      return false;
+
+    // This is safe because handle indices are uint32.
+    this.handleIndex = index + 1;
+    return true;
+  }
+
+  Validator.prototype.validateHandle = function(offset, nullable) {
+    var index = this.message.buffer.getUint32(offset);
+
+    if (index === codec.kEncodedInvalidHandleValue)
+      return nullable ?
+          validationError.NONE : validationError.UNEXPECTED_INVALID_HANDLE;
+
+    if (!this.claimHandle(index))
+      return validationError.ILLEGAL_HANDLE;
+    return validationError.NONE;
+  }
+
+  Validator.prototype.validateStructHeader =
+      function(offset, minNumBytes, minNumFields) {
+    if (!codec.isAligned(offset))
+      return validationError.MISALIGNED_OBJECT;
+
+    if (!this.isValidRange(offset, codec.kStructHeaderSize))
+      return validationError.ILLEGAL_MEMORY_RANGE;
+
+    var numBytes = this.message.buffer.getUint32(offset);
+    var numFields = this.message.buffer.getUint32(offset + 4);
+
+    if (numBytes < minNumBytes || numFields < minNumFields)
+      return validationError.UNEXPECTED_STRUCT_HEADER;
+
+    if (!this.claimRange(offset, numBytes))
+      return validationError.ILLEGAL_MEMORY_RANGE;
+
+    return validationError.NONE;
+  }
+
+  Validator.prototype.validateMessageHeader = function() {
+    var err = this.validateStructHeader(0, codec.kMessageHeaderSize, 2);
+    if (err != validationError.NONE)
+      return err;
+
+    var numBytes = this.message.getHeaderNumBytes();
+    var numFields = this.message.getHeaderNumFields();
+
+    var validNumFieldsAndNumBytes =
+        (numFields == 2 && numBytes == codec.kMessageHeaderSize) ||
+        (numFields == 3 &&
+         numBytes == codec.kMessageWithRequestIDHeaderSize) ||
+        (numFields > 3 &&
+         numBytes >= codec.kMessageWithRequestIDHeaderSize);
+    if (!validNumFieldsAndNumBytes)
+      return validationError.UNEXPECTED_STRUCT_HEADER;
+
+    var expectsResponse = this.message.expectsResponse();
+    var isResponse = this.message.isResponse();
+
+    if (numFields == 2 && (expectsResponse || isResponse))
+      return validationError.MESSAGE_HEADER_MISSING_REQUEST_ID;
+
+    if (isResponse && expectsResponse)
+      return validationError.MESSAGE_HEADER_INVALID_FLAG_COMBINATION;
+
+    return validationError.NONE;
+  }
+
+  // Returns the message.buffer relative offset this pointer "points to",
+  // NULL_MOJO_POINTER if the pointer represents a null, or JS null if the
+  // pointer's value is not valid.
+  Validator.prototype.decodePointer = function(offset) {
+    var pointerValue = this.message.buffer.getUint64(offset);
+    if (pointerValue === 0)
+      return NULL_MOJO_POINTER;
+    var bufferOffset = offset + pointerValue;
+    return Number.isSafeInteger(bufferOffset) ? bufferOffset : null;
+  }
+
+  Validator.prototype.validateArrayPointer = function(
+      offset, elementSize, expectedElementCount, elementType, nullable) {
+    var arrayOffset = this.decodePointer(offset);
+    if (arrayOffset === null)
+      return validationError.ILLEGAL_POINTER;
+
+    if (arrayOffset === NULL_MOJO_POINTER)
+      return nullable ?
+          validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
+
+    return this.validateArray(
+        arrayOffset, elementSize, expectedElementCount, elementType);
+  }
+
+  Validator.prototype.validateStructPointer = function(
+        offset, structClass, nullable) {
+    var structOffset = this.decodePointer(offset);
+    if (structOffset === null)
+      return validationError.ILLEGAL_POINTER;
+
+    if (structOffset === NULL_MOJO_POINTER)
+      return nullable ?
+          validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
+
+    return structClass.validate(this, structOffset);
+  }
+
+  Validator.prototype.validateStringPointer = function(offset, nullable) {
+    return this.validateArrayPointer(
+        offset, codec.Uint8.encodedSize, 0, codec.Uint8, nullable);
+  }
+
+  // Similar to Array_Data<T>::Validate()
+  // mojo/public/cpp/bindings/lib/array_internal.h
+
+  Validator.prototype.validateArray =
+      function (offset, elementSize, expectedElementCount, elementType) {
+    if (!codec.isAligned(offset))
+      return validationError.MISALIGNED_OBJECT;
+
+    if (!this.isValidRange(offset, codec.kArrayHeaderSize))
+      return validationError.ILLEGAL_MEMORY_RANGE;
+
+    var numBytes = this.message.buffer.getUint32(offset);
+    var numElements = this.message.buffer.getUint32(offset + 4);
+
+    // Note: this computation is "safe" because elementSize <= 8 and
+    // numElements is a uint32.
+    var elementsTotalSize = (elementType === codec.PackedBool) ?
+        Math.ceil(numElements / 8) : (elementSize * numElements);
+
+    if (numBytes < codec.kArrayHeaderSize + elementsTotalSize)
+      return validationError.UNEXPECTED_ARRAY_HEADER;
+
+    if (expectedElementCount != 0 && numElements != expectedElementCount)
+      return validationError.UNEXPECTED_ARRAY_HEADER;
+
+    if (!this.claimRange(offset, numBytes))
+      return validationError.ILLEGAL_MEMORY_RANGE;
+
+    // Validate the array's elements if they are pointers or handles.
+
+    var elementsOffset = offset + codec.kArrayHeaderSize;
+    var nullable = isNullable(elementType);
+
+    if (isHandleClass(elementType))
+      return this.validateHandleElements(elementsOffset, numElements, nullable);
+    if (isStringClass(elementType))
+      return this.validateArrayElements(
+          elementsOffset, numElements, codec.Uint8, nullable)
+    if (elementType instanceof codec.PointerTo)
+      return this.validateStructElements(
+          elementsOffset, numElements, elementType.cls, nullable);
+    if (elementType instanceof codec.ArrayOf)
+      return this.validateArrayElements(
+          elementsOffset, numElements, elementType.cls, nullable);
+
+    return validationError.NONE;
+  }
+
+  // Note: the |offset + i * elementSize| computation in the validateFooElements
+  // methods below is "safe" because elementSize <= 8, offset and
+  // numElements are uint32, and 0 <= i < numElements.
+
+  Validator.prototype.validateHandleElements =
+      function(offset, numElements, nullable) {
+    var elementSize = codec.Handle.encodedSize;
+    for (var i = 0; i < numElements; i++) {
+      var elementOffset = offset + i * elementSize;
+      var err = this.validateHandle(elementOffset, nullable);
+      if (err != validationError.NONE)
+        return err;
+    }
+    return validationError.NONE;
+  }
+
+  // The elementClass parameter is the element type of the element arrays.
+  Validator.prototype.validateArrayElements =
+      function(offset, numElements, elementClass, nullable) {
+    var elementSize = codec.PointerTo.prototype.encodedSize;
+    for (var i = 0; i < numElements; i++) {
+      var elementOffset = offset + i * elementSize;
+      var err = this.validateArrayPointer(
+          elementOffset, elementClass.encodedSize, 0, elementClass, nullable);
+      if (err != validationError.NONE)
+        return err;
+    }
+    return validationError.NONE;
+  }
+
+  Validator.prototype.validateStructElements =
+      function(offset, numElements, structClass, nullable) {
+    var elementSize = codec.PointerTo.prototype.encodedSize;
+    for (var i = 0; i < numElements; i++) {
+      var elementOffset = offset + i * elementSize;
+      var err =
+          this.validateStructPointer(elementOffset, structClass, nullable);
+      if (err != validationError.NONE)
+        return err;
+    }
+    return validationError.NONE;
+  }
+
+  var exports = {};
+  exports.validationError = validationError;
+  exports.Validator = Validator;
+  return exports;
+});
diff --git a/mojo/public/platform/native/BUILD.gn b/mojo/public/platform/native/BUILD.gn
new file mode 100644
index 0000000..a3e720b
--- /dev/null
+++ b/mojo/public/platform/native/BUILD.gn
@@ -0,0 +1,59 @@
+# Copyright 2014 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.
+
+source_set("system_thunks") {
+  visibility = [
+    "//mojo/public/c/system:for_component",
+    "//mojo/public/c/system:for_shared_library",
+  ]
+
+  sources = [
+    "system_thunks.h",
+    "system_thunks.cc",
+  ]
+  defines = [ "MOJO_SYSTEM_IMPLEMENTATION" ]
+  deps = [ "//mojo/public/c/system" ]
+
+  # The GYP target analogous to this one builds this code into a
+  # static library.  When building for Android, both the GYP and GN
+  # builds add --exclude-libs=ALL globally, which means that all
+  # symbols in static libraries are excluded from export.  That's a
+  # problem, as code outside this target needs to be able to call
+  # MojoSetSystemThunks(). Therefore, the GYP target needs to specifiy
+  # that all dependent targets remove that link flag. Since GN uses a
+  # source_set here, this flag change is not needed.
+}
+
+# GYP version: mojo/mojo_public.gypi:mojo_gles2
+source_set("gles2_thunks") {
+  visibility = [ "//mojo/public/gles2:for_shared_library" ]
+
+  sources = [
+    "gles2_thunks.cc",
+    "gles2_thunks.h",
+    "gles2_impl_thunks.cc",
+    "gles2_impl_thunks.h",
+    "gles2_impl_chromium_texture_mailbox_thunks.cc",
+    "gles2_impl_chromium_texture_mailbox_thunks.h",
+    "gles2_impl_chromium_sync_point_thunks.cc",
+    "gles2_impl_chromium_sync_point_thunks.h",
+  ]
+
+  defines = [
+    "MOJO_GLES2_IMPLEMENTATION",
+  ]
+
+  configs += [ "//third_party/khronos:khronos_headers" ]
+
+  deps = [
+    "//mojo/public/c/gles2",
+    "//mojo/public/c/environment",
+    "//mojo/public/c/system",
+  ]
+
+  if (is_mac) {
+    # TODO(GYP): Make it a run-path dependent library.
+    # 'DYLIB_INSTALL_NAME_BASE': '@loader_path',
+  }
+}
diff --git a/mojo/public/platform/native/gles2_impl_chromium_sync_point_thunks.cc b/mojo/public/platform/native/gles2_impl_chromium_sync_point_thunks.cc
new file mode 100644
index 0000000..0a47f33
--- /dev/null
+++ b/mojo/public/platform/native/gles2_impl_chromium_sync_point_thunks.cc
@@ -0,0 +1,32 @@
+// Copyright 2014 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/gles2_impl_chromium_sync_point_thunks.h"
+
+#include <assert.h>
+
+#include "mojo/public/platform/native/thunk_export.h"
+
+extern "C" {
+static MojoGLES2ImplChromiumSyncPointThunks g_impl_chromium_sync_point_thunks =
+    {0};
+
+#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) \
+  ReturnType gl##Function PARAMETERS {                             \
+    assert(g_impl_chromium_sync_point_thunks.Function);            \
+    return g_impl_chromium_sync_point_thunks.Function ARGUMENTS;   \
+  }
+#include "mojo/public/c/gles2/gles2_call_visitor_chromium_sync_point_autogen.h"
+#undef VISIT_GL_CALL
+
+extern "C" THUNK_EXPORT size_t MojoSetGLES2ImplChromiumSyncPointThunks(
+    const MojoGLES2ImplChromiumSyncPointThunks*
+        gles2_impl_chromium_sync_point_thunks) {
+  if (gles2_impl_chromium_sync_point_thunks->size >=
+      sizeof(g_impl_chromium_sync_point_thunks))
+    g_impl_chromium_sync_point_thunks = *gles2_impl_chromium_sync_point_thunks;
+  return sizeof(g_impl_chromium_sync_point_thunks);
+}
+
+}  // extern "C"
diff --git a/mojo/public/platform/native/gles2_impl_chromium_sync_point_thunks.h b/mojo/public/platform/native/gles2_impl_chromium_sync_point_thunks.h
new file mode 100644
index 0000000..af6817e
--- /dev/null
+++ b/mojo/public/platform/native/gles2_impl_chromium_sync_point_thunks.h
@@ -0,0 +1,44 @@
+// Copyright 2014 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_GLES2_IMPL_CHROMIUM_SYNC_POINT_THUNKS_H_
+#define MOJO_PUBLIC_PLATFORM_NATIVE_GLES2_IMPL_CHROMIUM_SYNC_POINT_THUNKS_H_
+
+#include <stddef.h>
+
+#include "mojo/public/c/gles2/chromium_sync_point.h"
+
+// Specifies the frozen API for the GLES2 CHROMIUM_sync_point extension.
+#pragma pack(push, 8)
+struct MojoGLES2ImplChromiumSyncPointThunks {
+  size_t size;  // Should be set to sizeof(*this).
+
+#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) \
+  ReturnType(*Function) PARAMETERS;
+#include "mojo/public/c/gles2/gles2_call_visitor_chromium_sync_point_autogen.h"
+#undef VISIT_GL_CALL
+};
+#pragma pack(pop)
+
+// Intended to be called from the embedder to get the embedder's implementation
+// of GLES2.
+inline MojoGLES2ImplChromiumSyncPointThunks
+MojoMakeGLES2ImplChromiumSyncPointThunks() {
+  MojoGLES2ImplChromiumSyncPointThunks gles2_impl_chromium_sync_point_thunks = {
+      sizeof(MojoGLES2ImplChromiumSyncPointThunks),
+#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) gl##Function,
+#include "mojo/public/c/gles2/gles2_call_visitor_chromium_sync_point_autogen.h"
+#undef VISIT_GL_CALL
+  };
+
+  return gles2_impl_chromium_sync_point_thunks;
+}
+
+// Use this type for the function found by dynamically discovering it in
+// a DSO linked with mojo_system.
+// The contents of |gles2_impl_chromium_sync_point_thunks| are copied.
+typedef size_t (*MojoSetGLES2ImplChromiumSyncPointThunksFn)(
+    const MojoGLES2ImplChromiumSyncPointThunks* thunks);
+
+#endif  // MOJO_PUBLIC_PLATFORM_NATIVE_GLES2_IMPL_CHROMIUM_SYNC_POINT_THUNKS_H_
diff --git a/mojo/public/platform/native/gles2_impl_chromium_texture_mailbox_thunks.cc b/mojo/public/platform/native/gles2_impl_chromium_texture_mailbox_thunks.cc
new file mode 100644
index 0000000..db2bc81
--- /dev/null
+++ b/mojo/public/platform/native/gles2_impl_chromium_texture_mailbox_thunks.cc
@@ -0,0 +1,33 @@
+// Copyright 2014 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/gles2_impl_chromium_texture_mailbox_thunks.h"
+
+#include <assert.h>
+
+#include "mojo/public/platform/native/thunk_export.h"
+
+extern "C" {
+static MojoGLES2ImplChromiumTextureMailboxThunks
+    g_impl_chromium_texture_mailbox_thunks = {0};
+
+#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS)    \
+  ReturnType gl##Function PARAMETERS {                                \
+    assert(g_impl_chromium_texture_mailbox_thunks.Function);          \
+    return g_impl_chromium_texture_mailbox_thunks.Function ARGUMENTS; \
+  }
+#include "mojo/public/c/gles2/gles2_call_visitor_chromium_texture_mailbox_autogen.h"
+#undef VISIT_GL_CALL
+
+extern "C" THUNK_EXPORT size_t MojoSetGLES2ImplChromiumTextureMailboxThunks(
+    const MojoGLES2ImplChromiumTextureMailboxThunks*
+        gles2_impl_chromium_texture_mailbox_thunks) {
+  if (gles2_impl_chromium_texture_mailbox_thunks->size >=
+      sizeof(g_impl_chromium_texture_mailbox_thunks))
+    g_impl_chromium_texture_mailbox_thunks =
+        *gles2_impl_chromium_texture_mailbox_thunks;
+  return sizeof(g_impl_chromium_texture_mailbox_thunks);
+}
+
+}  // extern "C"
diff --git a/mojo/public/platform/native/gles2_impl_chromium_texture_mailbox_thunks.h b/mojo/public/platform/native/gles2_impl_chromium_texture_mailbox_thunks.h
new file mode 100644
index 0000000..839e441
--- /dev/null
+++ b/mojo/public/platform/native/gles2_impl_chromium_texture_mailbox_thunks.h
@@ -0,0 +1,45 @@
+// Copyright 2014 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_GLES2_IMPL_CHROMIUM_TEXTURE_MAILBOX_THUNKS_H_
+#define MOJO_PUBLIC_PLATFORM_NATIVE_GLES2_IMPL_CHROMIUM_TEXTURE_MAILBOX_THUNKS_H_
+
+#include <stddef.h>
+
+#include "mojo/public/c/gles2/chromium_texture_mailbox.h"
+
+// Specifies the frozen API for the GLES2 CHROMIUM_texture_mailbox extension.
+#pragma pack(push, 8)
+struct MojoGLES2ImplChromiumTextureMailboxThunks {
+  size_t size;  // Should be set to sizeof(*this).
+
+#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) \
+  ReturnType(*Function) PARAMETERS;
+#include "mojo/public/c/gles2/gles2_call_visitor_chromium_texture_mailbox_autogen.h"
+#undef VISIT_GL_CALL
+};
+#pragma pack(pop)
+
+// Intended to be called from the embedder to get the embedder's implementation
+// of GLES2.
+inline MojoGLES2ImplChromiumTextureMailboxThunks
+MojoMakeGLES2ImplChromiumTextureMailboxThunks() {
+  MojoGLES2ImplChromiumTextureMailboxThunks
+      gles2_impl_chromium_texture_mailbox_thunks = {
+          sizeof(MojoGLES2ImplChromiumTextureMailboxThunks),
+#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) gl##Function,
+#include "mojo/public/c/gles2/gles2_call_visitor_chromium_texture_mailbox_autogen.h"
+#undef VISIT_GL_CALL
+      };
+
+  return gles2_impl_chromium_texture_mailbox_thunks;
+}
+
+// Use this type for the function found by dynamically discovering it in
+// a DSO linked with mojo_system.
+// The contents of |gles2_impl_chromium_texture_mailbox_thunks| are copied.
+typedef size_t (*MojoSetGLES2ImplChromiumTextureMailboxThunksFn)(
+    const MojoGLES2ImplChromiumTextureMailboxThunks* thunks);
+
+#endif  // MOJO_PUBLIC_PLATFORM_NATIVE_GLES2_IMPL_CHROMIUM_TEXTURE_MAILBOX_THUNKS_H_
diff --git a/mojo/public/platform/native/gles2_impl_thunks.cc b/mojo/public/platform/native/gles2_impl_thunks.cc
new file mode 100644
index 0000000..66dbc39
--- /dev/null
+++ b/mojo/public/platform/native/gles2_impl_thunks.cc
@@ -0,0 +1,29 @@
+// Copyright 2014 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/gles2_impl_thunks.h"
+
+#include <assert.h>
+
+#include "mojo/public/platform/native/thunk_export.h"
+
+extern "C" {
+static MojoGLES2ImplThunks g_impl_thunks = {0};
+
+#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) \
+  ReturnType gl##Function PARAMETERS {                             \
+    assert(g_impl_thunks.Function);                                \
+    return g_impl_thunks.Function ARGUMENTS;                       \
+  }
+#include "mojo/public/c/gles2/gles2_call_visitor_autogen.h"
+#undef VISIT_GL_CALL
+
+extern "C" THUNK_EXPORT size_t
+MojoSetGLES2ImplThunks(const MojoGLES2ImplThunks* gles2_impl_thunks) {
+  if (gles2_impl_thunks->size >= sizeof(g_impl_thunks))
+    g_impl_thunks = *gles2_impl_thunks;
+  return sizeof(g_impl_thunks);
+}
+
+}  // extern "C"
diff --git a/mojo/public/platform/native/gles2_impl_thunks.h b/mojo/public/platform/native/gles2_impl_thunks.h
new file mode 100644
index 0000000..04174fa
--- /dev/null
+++ b/mojo/public/platform/native/gles2_impl_thunks.h
@@ -0,0 +1,49 @@
+// Copyright 2014 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_GLES2_IMPL_THUNKS_H_
+#define MOJO_PUBLIC_PLATFORM_NATIVE_GLES2_IMPL_THUNKS_H_
+
+#include <stddef.h>
+
+#include "mojo/public/c/gles2/gles2.h"
+
+// Like MojoGLES2ControlThunks, but specifies the frozen GLES2 API. Separated
+// out as MojoGLES2ControlThunks may be modified and added to, but this
+// interface is frozen.
+#pragma pack(push, 8)
+struct MojoGLES2ImplThunks {
+  size_t size;  // Should be set to sizeof(MojoGLES2ImplThunks).
+
+#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) \
+  ReturnType(*Function) PARAMETERS;
+#include "mojo/public/c/gles2/gles2_call_visitor_autogen.h"
+#undef VISIT_GL_CALL
+};
+#pragma pack(pop)
+
+// Intended to be called from the embedder to get the embedder's implementation
+// of GLES2.
+inline MojoGLES2ImplThunks MojoMakeGLES2ImplThunks() {
+  MojoGLES2ImplThunks gles2_impl_thunks = {
+      sizeof(MojoGLES2ImplThunks),
+#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) gl##Function,
+#include "mojo/public/c/gles2/gles2_call_visitor_autogen.h"
+#undef VISIT_GL_CALL
+  };
+
+  return gles2_impl_thunks;
+}
+
+// Use this type for the function found by dynamically discovering it in
+// a DSO linked with mojo_system. For example:
+// MojoSetGLES2ImplThunksFn mojo_set_gles2_impl_thunks_fn =
+//     reinterpret_cast<MojoSetGLES2ImplThunksFn>(
+//         app_library.GetFunctionPointer("MojoSetGLES2ImplThunks"));
+// The expected size of |gles2_impl_thunks| is returned.
+// The contents of |gles2_impl_thunks| are copied.
+typedef size_t (*MojoSetGLES2ImplThunksFn)(
+    const MojoGLES2ImplThunks* gles2_impl_thunks);
+
+#endif  // MOJO_PUBLIC_PLATFORM_NATIVE_GLES2_IMPL_THUNKS_H_
diff --git a/mojo/public/platform/native/gles2_thunks.cc b/mojo/public/platform/native/gles2_thunks.cc
new file mode 100644
index 0000000..365fac9
--- /dev/null
+++ b/mojo/public/platform/native/gles2_thunks.cc
@@ -0,0 +1,56 @@
+// Copyright 2014 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/gles2_thunks.h"
+
+#include <assert.h>
+
+#include "mojo/public/platform/native/thunk_export.h"
+
+extern "C" {
+
+static MojoGLES2ControlThunks g_control_thunks = {0};
+
+MojoGLES2Context MojoGLES2CreateContext(MojoHandle handle,
+                                        MojoGLES2ContextLost lost_callback,
+                                        void* closure,
+                                        const MojoAsyncWaiter* async_waiter) {
+  assert(g_control_thunks.GLES2CreateContext);
+  return g_control_thunks.GLES2CreateContext(
+      handle, lost_callback, closure, async_waiter);
+}
+
+void MojoGLES2DestroyContext(MojoGLES2Context context) {
+  assert(g_control_thunks.GLES2DestroyContext);
+  g_control_thunks.GLES2DestroyContext(context);
+}
+
+void MojoGLES2MakeCurrent(MojoGLES2Context context) {
+  assert(g_control_thunks.GLES2MakeCurrent);
+  g_control_thunks.GLES2MakeCurrent(context);
+}
+
+void MojoGLES2SwapBuffers() {
+  assert(g_control_thunks.GLES2SwapBuffers);
+  g_control_thunks.GLES2SwapBuffers();
+}
+
+void* MojoGLES2GetGLES2Interface(MojoGLES2Context context) {
+  assert(g_control_thunks.GLES2GetGLES2Interface);
+  return g_control_thunks.GLES2GetGLES2Interface(context);
+}
+
+void* MojoGLES2GetContextSupport(MojoGLES2Context context) {
+  assert(g_control_thunks.GLES2GetContextSupport);
+  return g_control_thunks.GLES2GetContextSupport(context);
+}
+
+extern "C" THUNK_EXPORT size_t MojoSetGLES2ControlThunks(
+    const MojoGLES2ControlThunks* gles2_control_thunks) {
+  if (gles2_control_thunks->size >= sizeof(g_control_thunks))
+    g_control_thunks = *gles2_control_thunks;
+  return sizeof(g_control_thunks);
+}
+
+}  // extern "C"
diff --git a/mojo/public/platform/native/gles2_thunks.h b/mojo/public/platform/native/gles2_thunks.h
new file mode 100644
index 0000000..4718ab3
--- /dev/null
+++ b/mojo/public/platform/native/gles2_thunks.h
@@ -0,0 +1,62 @@
+// Copyright 2014 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_GLES2_THUNKS_H_
+#define MOJO_PUBLIC_PLATFORM_NATIVE_GLES2_THUNKS_H_
+
+#include <stddef.h>
+
+#include "mojo/public/c/gles2/gles2.h"
+
+// Structure used to bind the interface which manipulates GLES2 surfaces to a
+// DSO to theose of the embedder.
+//
+// This is the ABI between the embedder and the DSO. It can only have new
+// functions added to the end. No other changes are supported.
+#pragma pack(push, 8)
+struct MojoGLES2ControlThunks {
+  size_t size;  // Should be set to sizeof(MojoGLES2ControlThunks).
+
+  MojoGLES2Context (*GLES2CreateContext)(MojoHandle handle,
+                                         MojoGLES2ContextLost lost_callback,
+                                         void* closure,
+                                         const MojoAsyncWaiter* async_waiter);
+  void (*GLES2DestroyContext)(MojoGLES2Context context);
+  void (*GLES2MakeCurrent)(MojoGLES2Context context);
+  void (*GLES2SwapBuffers)();
+
+  // TODO(piman): We shouldn't have to leak these 2 interfaces, especially in a
+  // type-unsafe way.
+  void* (*GLES2GetGLES2Interface)(MojoGLES2Context context);
+  void* (*GLES2GetContextSupport)(MojoGLES2Context context);
+};
+#pragma pack(pop)
+
+// Intended to be called from the embedder. Returns an object initialized to
+// contain pointers to each of the embedder's MojoGLES2ControlThunks functions.
+inline MojoGLES2ControlThunks MojoMakeGLES2ControlThunks() {
+  MojoGLES2ControlThunks gles2_control_thunks = {
+    sizeof(MojoGLES2ControlThunks),
+    MojoGLES2CreateContext,
+    MojoGLES2DestroyContext,
+    MojoGLES2MakeCurrent,
+    MojoGLES2SwapBuffers,
+    MojoGLES2GetGLES2Interface,
+    MojoGLES2GetContextSupport
+  };
+
+  return gles2_control_thunks;
+}
+
+// Use this type for the function found by dynamically discovering it in
+// a DSO linked with mojo_system. For example:
+// MojoSetGLES2ControlThunksFn mojo_set_gles2_control_thunks_fn =
+//     reinterpret_cast<MojoSetGLES2ControlThunksFn>(
+//         app_library.GetFunctionPointer("MojoSetGLES2ControlThunks"));
+// The expected size of |gles2_control_thunks| is returned.
+// The contents of |gles2_control_thunks| are copied.
+typedef size_t (*MojoSetGLES2ControlThunksFn)(
+    const MojoGLES2ControlThunks* gles2_control_thunks);
+
+#endif  // MOJO_PUBLIC_PLATFORM_NATIVE_GLES2_THUNKS_H_
diff --git a/mojo/public/platform/native/system_thunks.cc b/mojo/public/platform/native/system_thunks.cc
new file mode 100644
index 0000000..fed6db9
--- /dev/null
+++ b/mojo/public/platform/native/system_thunks.cc
@@ -0,0 +1,164 @@
+// Copyright 2013 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/system_thunks.h"
+
+#include <assert.h>
+
+#include "mojo/public/platform/native/thunk_export.h"
+
+extern "C" {
+
+static MojoSystemThunks g_thunks = {0};
+
+MojoTimeTicks MojoGetTimeTicksNow() {
+  assert(g_thunks.GetTimeTicksNow);
+  return g_thunks.GetTimeTicksNow();
+}
+
+MojoResult MojoClose(MojoHandle handle) {
+  assert(g_thunks.Close);
+  return g_thunks.Close(handle);
+}
+
+MojoResult MojoWait(MojoHandle handle,
+                    MojoHandleSignals signals,
+                    MojoDeadline deadline) {
+  assert(g_thunks.Wait);
+  return g_thunks.Wait(handle, signals, deadline);
+}
+
+MojoResult MojoWaitMany(const MojoHandle* handles,
+                        const MojoHandleSignals* signals,
+                        uint32_t num_handles,
+                        MojoDeadline deadline) {
+  assert(g_thunks.WaitMany);
+  return g_thunks.WaitMany(handles, signals, num_handles, deadline);
+}
+
+MojoResult MojoCreateMessagePipe(const MojoCreateMessagePipeOptions* options,
+                                 MojoHandle* message_pipe_handle0,
+                                 MojoHandle* message_pipe_handle1) {
+  assert(g_thunks.CreateMessagePipe);
+  return g_thunks.CreateMessagePipe(options, message_pipe_handle0,
+                                    message_pipe_handle1);
+}
+
+MojoResult MojoWriteMessage(MojoHandle message_pipe_handle,
+                            const void* bytes,
+                            uint32_t num_bytes,
+                            const MojoHandle* handles,
+                            uint32_t num_handles,
+                            MojoWriteMessageFlags flags) {
+  assert(g_thunks.WriteMessage);
+  return g_thunks.WriteMessage(message_pipe_handle, bytes, num_bytes, handles,
+                               num_handles, flags);
+}
+
+MojoResult MojoReadMessage(MojoHandle message_pipe_handle,
+                           void* bytes,
+                           uint32_t* num_bytes,
+                           MojoHandle* handles,
+                           uint32_t* num_handles,
+                           MojoReadMessageFlags flags) {
+  assert(g_thunks.ReadMessage);
+  return g_thunks.ReadMessage(message_pipe_handle, bytes, num_bytes, handles,
+                              num_handles, flags);
+}
+
+MojoResult MojoCreateDataPipe(const MojoCreateDataPipeOptions* options,
+                              MojoHandle* data_pipe_producer_handle,
+                              MojoHandle* data_pipe_consumer_handle) {
+  assert(g_thunks.CreateDataPipe);
+  return g_thunks.CreateDataPipe(options, data_pipe_producer_handle,
+                                 data_pipe_consumer_handle);
+}
+
+MojoResult MojoWriteData(MojoHandle data_pipe_producer_handle,
+                         const void* elements,
+                         uint32_t* num_elements,
+                         MojoWriteDataFlags flags) {
+  assert(g_thunks.WriteData);
+  return g_thunks.WriteData(data_pipe_producer_handle, elements, num_elements,
+                            flags);
+}
+
+MojoResult MojoBeginWriteData(MojoHandle data_pipe_producer_handle,
+                              void** buffer,
+                              uint32_t* buffer_num_elements,
+                              MojoWriteDataFlags flags) {
+  assert(g_thunks.BeginWriteData);
+  return g_thunks.BeginWriteData(data_pipe_producer_handle, buffer,
+                                 buffer_num_elements, flags);
+}
+
+MojoResult MojoEndWriteData(MojoHandle data_pipe_producer_handle,
+                            uint32_t num_elements_written) {
+  assert(g_thunks.EndWriteData);
+  return g_thunks.EndWriteData(data_pipe_producer_handle, num_elements_written);
+}
+
+MojoResult MojoReadData(MojoHandle data_pipe_consumer_handle,
+                        void* elements,
+                        uint32_t* num_elements,
+                        MojoReadDataFlags flags) {
+  assert(g_thunks.ReadData);
+  return g_thunks.ReadData(data_pipe_consumer_handle, elements, num_elements,
+                           flags);
+}
+
+MojoResult MojoBeginReadData(MojoHandle data_pipe_consumer_handle,
+                             const void** buffer,
+                             uint32_t* buffer_num_elements,
+                             MojoReadDataFlags flags) {
+  assert(g_thunks.BeginReadData);
+  return g_thunks.BeginReadData(data_pipe_consumer_handle, buffer,
+                                buffer_num_elements, flags);
+}
+
+MojoResult MojoEndReadData(MojoHandle data_pipe_consumer_handle,
+                           uint32_t num_elements_read) {
+  assert(g_thunks.EndReadData);
+  return g_thunks.EndReadData(data_pipe_consumer_handle, num_elements_read);
+}
+
+MojoResult MojoCreateSharedBuffer(
+    const struct MojoCreateSharedBufferOptions* options,
+    uint64_t num_bytes,
+    MojoHandle* shared_buffer_handle) {
+  assert(g_thunks.CreateSharedBuffer);
+  return g_thunks.CreateSharedBuffer(options, num_bytes, shared_buffer_handle);
+}
+
+MojoResult MojoDuplicateBufferHandle(
+    MojoHandle buffer_handle,
+    const struct MojoDuplicateBufferHandleOptions* options,
+    MojoHandle* new_buffer_handle) {
+  assert(g_thunks.DuplicateBufferHandle);
+  return g_thunks.DuplicateBufferHandle(buffer_handle, options,
+                                        new_buffer_handle);
+}
+
+MojoResult MojoMapBuffer(MojoHandle buffer_handle,
+                         uint64_t offset,
+                         uint64_t num_bytes,
+                         void** buffer,
+                         MojoMapBufferFlags flags) {
+  assert(g_thunks.MapBuffer);
+  return g_thunks.MapBuffer(buffer_handle, offset, num_bytes, buffer, flags);
+}
+
+MojoResult MojoUnmapBuffer(void* buffer) {
+  assert(g_thunks.UnmapBuffer);
+  return g_thunks.UnmapBuffer(buffer);
+}
+
+extern "C" THUNK_EXPORT size_t MojoSetSystemThunks(
+    const MojoSystemThunks* system_thunks) {
+  if (system_thunks->size >= sizeof(g_thunks))
+    g_thunks = *system_thunks;
+  return sizeof(g_thunks);
+}
+
+}  // extern "C"
diff --git a/mojo/public/platform/native/system_thunks.h b/mojo/public/platform/native/system_thunks.h
new file mode 100644
index 0000000..d53485c
--- /dev/null
+++ b/mojo/public/platform/native/system_thunks.h
@@ -0,0 +1,145 @@
+// Copyright 2014 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.
+
+// Note: This header should be compilable as C.
+
+#ifndef MOJO_PUBLIC_PLATFORM_NATIVE_SYSTEM_THUNKS_H_
+#define MOJO_PUBLIC_PLATFORM_NATIVE_SYSTEM_THUNKS_H_
+
+#include <stddef.h>
+
+#include "mojo/public/c/system/core.h"
+
+// The embedder needs to bind the basic Mojo Core functions of a DSO to those of
+// the embedder when loading a DSO that is dependent on mojo_system.
+// The typical usage would look like:
+// base::ScopedNativeLibrary app_library(
+//     base::LoadNativeLibrary(app_path_, &error));
+// typedef MojoResult (*MojoSetSystemThunksFn)(MojoSystemThunks*);
+// MojoSetSystemThunksFn mojo_set_system_thunks_fn =
+//     reinterpret_cast<MojoSetSystemThunksFn>(app_library.GetFunctionPointer(
+//         "MojoSetSystemThunks"));
+// MojoSystemThunks system_thunks = MojoMakeSystemThunks();
+// size_t expected_size = mojo_set_system_thunks_fn(&system_thunks);
+// if (expected_size > sizeof(MojoSystemThunks)) {
+//   LOG(ERROR)
+//       << "Invalid DSO. Expected MojoSystemThunks size: "
+//       << expected_size;
+//   break;
+// }
+
+// Structure used to bind the basic Mojo Core functions of a DSO to those of
+// the embedder.
+// This is the ABI between the embedder and the DSO. It can only have new
+// functions added to the end. No other changes are supported.
+#pragma pack(push, 8)
+struct MojoSystemThunks {
+  size_t size;  // Should be set to sizeof(MojoSystemThunks).
+  MojoTimeTicks (*GetTimeTicksNow)();
+  MojoResult (*Close)(MojoHandle handle);
+  MojoResult (*Wait)(MojoHandle handle,
+                     MojoHandleSignals signals,
+                     MojoDeadline deadline);
+  MojoResult (*WaitMany)(const MojoHandle* handles,
+                         const MojoHandleSignals* signals,
+                         uint32_t num_handles,
+                         MojoDeadline deadline);
+  MojoResult (*CreateMessagePipe)(
+      const struct MojoCreateMessagePipeOptions* options,
+      MojoHandle* message_pipe_handle0,
+      MojoHandle* message_pipe_handle1);
+  MojoResult (*WriteMessage)(MojoHandle message_pipe_handle,
+                             const void* bytes,
+                             uint32_t num_bytes,
+                             const MojoHandle* handles,
+                             uint32_t num_handles,
+                             MojoWriteMessageFlags flags);
+  MojoResult (*ReadMessage)(MojoHandle message_pipe_handle,
+                            void* bytes,
+                            uint32_t* num_bytes,
+                            MojoHandle* handles,
+                            uint32_t* num_handles,
+                            MojoReadMessageFlags flags);
+  MojoResult (*CreateDataPipe)(const struct MojoCreateDataPipeOptions* options,
+                               MojoHandle* data_pipe_producer_handle,
+                               MojoHandle* data_pipe_consumer_handle);
+  MojoResult (*WriteData)(MojoHandle data_pipe_producer_handle,
+                          const void* elements,
+                          uint32_t* num_elements,
+                          MojoWriteDataFlags flags);
+  MojoResult (*BeginWriteData)(MojoHandle data_pipe_producer_handle,
+                               void** buffer,
+                               uint32_t* buffer_num_elements,
+                               MojoWriteDataFlags flags);
+  MojoResult (*EndWriteData)(MojoHandle data_pipe_producer_handle,
+                             uint32_t num_elements_written);
+  MojoResult (*ReadData)(MojoHandle data_pipe_consumer_handle,
+                         void* elements,
+                         uint32_t* num_elements,
+                         MojoReadDataFlags flags);
+  MojoResult (*BeginReadData)(MojoHandle data_pipe_consumer_handle,
+                              const void** buffer,
+                              uint32_t* buffer_num_elements,
+                              MojoReadDataFlags flags);
+  MojoResult (*EndReadData)(MojoHandle data_pipe_consumer_handle,
+                            uint32_t num_elements_read);
+  MojoResult (*CreateSharedBuffer)(
+      const struct MojoCreateSharedBufferOptions* options,
+      uint64_t num_bytes,
+      MojoHandle* shared_buffer_handle);
+  MojoResult (*DuplicateBufferHandle)(
+      MojoHandle buffer_handle,
+      const struct MojoDuplicateBufferHandleOptions* options,
+      MojoHandle* new_buffer_handle);
+  MojoResult (*MapBuffer)(MojoHandle buffer_handle,
+                          uint64_t offset,
+                          uint64_t num_bytes,
+                          void** buffer,
+                          MojoMapBufferFlags flags);
+  MojoResult (*UnmapBuffer)(void* buffer);
+};
+#pragma pack(pop)
+
+
+#ifdef __cplusplus
+// Intended to be called from the embedder. Returns a |MojoCore| initialized
+// to contain pointers to each of the embedder's MojoCore functions.
+inline MojoSystemThunks MojoMakeSystemThunks() {
+  MojoSystemThunks system_thunks = {
+    sizeof(MojoSystemThunks),
+    MojoGetTimeTicksNow,
+    MojoClose,
+    MojoWait,
+    MojoWaitMany,
+    MojoCreateMessagePipe,
+    MojoWriteMessage,
+    MojoReadMessage,
+    MojoCreateDataPipe,
+    MojoWriteData,
+    MojoBeginWriteData,
+    MojoEndWriteData,
+    MojoReadData,
+    MojoBeginReadData,
+    MojoEndReadData,
+    MojoCreateSharedBuffer,
+    MojoDuplicateBufferHandle,
+    MojoMapBuffer,
+    MojoUnmapBuffer
+  };
+  return system_thunks;
+}
+#endif
+
+
+// Use this type for the function found by dynamically discovering it in
+// a DSO linked with mojo_system. For example:
+// MojoSetSystemThunksFn mojo_set_system_thunks_fn =
+//     reinterpret_cast<MojoSetSystemThunksFn>(app_library.GetFunctionPointer(
+//         "MojoSetSystemThunks"));
+// The expected size of |system_thunks} is returned.
+// The contents of |system_thunks| are copied.
+typedef size_t (*MojoSetSystemThunksFn)(
+    const struct MojoSystemThunks* system_thunks);
+
+#endif  // MOJO_PUBLIC_PLATFORM_NATIVE_SYSTEM_THUNKS_H_
diff --git a/mojo/public/platform/native/thunk_export.h b/mojo/public/platform/native/thunk_export.h
new file mode 100644
index 0000000..d118fc5
--- /dev/null
+++ b/mojo/public/platform/native/thunk_export.h
@@ -0,0 +1,18 @@
+// Copyright 2014 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_THUNK_EXPORT_H_
+#define MOJO_PUBLIC_PLATFORM_THUNK_EXPORT_H_
+
+// Call this function by looking inside the resulting shared object and
+// grabbing the symbol manually.
+//
+// Always export this api.
+#if defined(WIN32)
+#define THUNK_EXPORT __declspec(dllexport)
+#else
+#define THUNK_EXPORT __attribute__((visibility("default")))
+#endif
+
+#endif // MOJO_PUBLIC_PLATFORM_THUNK_EXPORT_H_
diff --git a/mojo/public/python/BUILD.gn b/mojo/public/python/BUILD.gn
new file mode 100644
index 0000000..66f132f
--- /dev/null
+++ b/mojo/public/python/BUILD.gn
@@ -0,0 +1,64 @@
+# Copyright 2014 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.
+
+import("//third_party/cython/rules.gni")
+
+group("python") {
+  deps = [
+    ":base",
+    ":bindings",
+    ":system",
+  ]
+}
+
+# GYP version: mojo.gyp:mojo_python_system
+python_binary_module("system") {
+  python_base_module = "mojo"
+  sources = [
+    "mojo/c_core.pxd",
+    "mojo/c_environment.pxd",
+    "mojo/system.pyx",
+  ]
+  additional_sources = [
+    "src/python_system_helper.cc",
+    "src/python_system_helper.h",
+  ]
+  deps = [
+    "//mojo/public/c/environment",
+    "//mojo/public/c/system:for_shared_library",
+    "//mojo/public/cpp/environment:standalone",
+    "//mojo/public/cpp/system",
+    "//mojo/public/cpp/utility",
+    "//mojo/public/cpp/bindings:callback",
+    ":base",
+  ]
+}
+
+copy("base") {
+  sources = [
+    "mojo/__init__.py",
+  ]
+  outputs = [
+    "$root_out_dir/python/mojo/{{source_file_part}}",
+  ]
+}
+
+# GYP version: mojo.gyp:mojo_python_bindings
+copy("bindings") {
+  sources = [
+    "mojo/bindings/__init__.py",
+    "mojo/bindings/descriptor.py",
+    "mojo/bindings/messaging.py",
+    "mojo/bindings/promise.py",
+    "mojo/bindings/reflection.py",
+    "mojo/bindings/serialization.py",
+  ]
+  outputs = [
+    "$root_out_dir/python/mojo/bindings/{{source_file_part}}",
+  ]
+  deps = [
+    ":base",
+    ":system",
+  ]
+}
diff --git a/mojo/public/python/mojo/__init__.py b/mojo/public/python/mojo/__init__.py
new file mode 100644
index 0000000..4d6aabb
--- /dev/null
+++ b/mojo/public/python/mojo/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2014 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.
diff --git a/mojo/public/python/mojo/bindings/__init__.py b/mojo/public/python/mojo/bindings/__init__.py
new file mode 100644
index 0000000..4d6aabb
--- /dev/null
+++ b/mojo/public/python/mojo/bindings/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2014 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.
diff --git a/mojo/public/python/mojo/bindings/descriptor.py b/mojo/public/python/mojo/bindings/descriptor.py
new file mode 100644
index 0000000..d56789a
--- /dev/null
+++ b/mojo/public/python/mojo/bindings/descriptor.py
@@ -0,0 +1,555 @@
+# Copyright 2014 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.
+
+"""
+The descriptors used to define generated elements of the mojo python bindings.
+"""
+
+import array
+import itertools
+import struct
+
+# pylint: disable=F0401
+import mojo.bindings.serialization as serialization
+import mojo.system
+
+
+class Type(object):
+  """Describes the type of a struct field or a method parameter,"""
+
+  def Convert(self, value): # pylint: disable=R0201
+    """
+    Convert the given value into its canonical representation, raising an
+    exception if the value cannot be converted.
+    """
+    return value
+
+  def GetDefaultValue(self, value):
+    """
+    Returns the default value for this type associated with the given value.
+    This method must be able to correcly handle value being None.
+    """
+    return self.Convert(value)
+
+
+class SerializableType(Type):
+  """Describe a type that can be serialized by itself."""
+
+  def __init__(self, typecode):
+    Type.__init__(self)
+    self.typecode = typecode
+    self.byte_size = struct.calcsize('=%s' % self.GetTypeCode())
+
+  def GetTypeCode(self):
+    """
+    Returns the type code (as defined by the struct module) used to encode
+    this type.
+    """
+    return self.typecode
+
+  def GetByteSize(self):
+    """
+    Returns the size of the encoding of this type.
+    """
+    return self.byte_size
+
+  def Serialize(self, value, data_offset, data, handle_offset):
+    """
+    Serialize a value of this type.
+
+    Args:
+      value: the value to serialize.
+      data_offset: the offset to the end of the data bytearray. Used to encode
+                   pointers.
+      data: the bytearray to append additional data to.
+      handle_offset: the offset to use to encode handles.
+
+    Returns a a tuple where the first element is the value to encode, and the
+    second is the array of handles to add to the message.
+    """
+    raise NotImplementedError()
+
+  def Deserialize(self, value, data, handles):
+    """
+    Deserialize a value of this type.
+
+    Args:
+      value: the base value for this type. This is always a numeric type, and
+             corresponds to the first element in the tuple returned by
+             Serialize.
+      data: the bytearray to retrieve additional data from.
+      handles: the array of handles contained in the message to deserialize.
+
+    Returns the deserialized value.
+    """
+    raise NotImplementedError()
+
+
+class BooleanType(Type):
+  """Type object for booleans"""
+
+  def Convert(self, value):
+    return bool(value)
+
+
+class NumericType(SerializableType):
+  """Base Type object for all numeric types"""
+
+  def GetDefaultValue(self, value):
+    if value is None:
+      return self.Convert(0)
+    return self.Convert(value)
+
+  def Serialize(self, value, data_offset, data, handle_offset):
+    return (value, [])
+
+  def Deserialize(self, value, data, handles):
+    return value
+
+
+class IntegerType(NumericType):
+  """Type object for integer types."""
+
+  def __init__(self, typecode):
+    NumericType.__init__(self, typecode)
+    size = 8 * self.byte_size
+    signed = typecode.islower()
+    if signed:
+      self._min_value = -(1 << (size - 1))
+      self._max_value = (1 << (size - 1)) - 1
+    else:
+      self._min_value = 0
+      self._max_value = (1 << size) - 1
+
+  def Convert(self, value):
+    if value is None:
+      raise TypeError('None is not an integer.')
+    if not isinstance(value, (int, long)):
+      raise TypeError('%r is not an integer type' % value)
+    if value < self._min_value or value > self._max_value:
+      raise OverflowError('%r is not in the range [%d, %d]' %
+                          (value, self._min_value, self._max_value))
+    return value
+
+
+class FloatType(NumericType):
+  """Type object for floating point number types."""
+
+  def Convert(self, value):
+    if value is None:
+      raise TypeError('None is not an floating point number.')
+    if not isinstance(value, (int, long, float)):
+      raise TypeError('%r is not a numeric type' % value)
+    return float(value)
+
+
+class PointerType(SerializableType):
+  """Base Type object for pointers."""
+
+  def __init__(self, nullable=False):
+    SerializableType.__init__(self, 'Q')
+    self.nullable = nullable
+
+  def Serialize(self, value, data_offset, data, handle_offset):
+    if value is None and not self.nullable:
+      raise serialization.SerializationException(
+          'Trying to serialize null for non nullable type.')
+    if value is None:
+      return (0, [])
+    return self.SerializePointer(value, data_offset, data, handle_offset)
+
+  def Deserialize(self, value, data, handles):
+    if value == 0:
+      if not self.nullable:
+        raise serialization.DeserializationException(
+            'Trying to deserialize null for non nullable type.')
+      return None
+    pointed_data = buffer(data, value)
+    (size, nb_elements) = serialization.HEADER_STRUCT.unpack_from(pointed_data)
+    return self.DeserializePointer(size, nb_elements, pointed_data, handles)
+
+  def SerializePointer(self, value, data_offset, data, handle_offset):
+    """Serialize the not null value."""
+    raise NotImplementedError()
+
+  def DeserializePointer(self, size, nb_elements, data, handles):
+    raise NotImplementedError()
+
+
+class StringType(PointerType):
+  """
+  Type object for strings.
+
+  Strings are represented as unicode, and the conversion is done using the
+  default encoding if a string instance is used.
+  """
+
+  def __init__(self, nullable=False):
+    PointerType.__init__(self, nullable)
+    self._array_type = NativeArrayType('B', nullable)
+
+  def Convert(self, value):
+    if value is None or isinstance(value, unicode):
+      return value
+    if isinstance(value, str):
+      return unicode(value)
+    raise TypeError('%r is not a string' % value)
+
+  def SerializePointer(self, value, data_offset, data, handle_offset):
+    string_array = array.array('b')
+    string_array.fromstring(value.encode('utf8'))
+    return self._array_type.SerializeArray(
+        string_array, data_offset, data, handle_offset)
+
+  def DeserializePointer(self, size, nb_elements, data, handles):
+    string_array = self._array_type.DeserializeArray(
+        size, nb_elements, data, handles)
+    return unicode(string_array.tostring(), 'utf8')
+
+
+class HandleType(SerializableType):
+  """Type object for handles."""
+
+  def __init__(self, nullable=False):
+    SerializableType.__init__(self, 'i')
+    self.nullable = nullable
+
+  def Convert(self, value):
+    if value is None:
+      return mojo.system.Handle()
+    if not isinstance(value, mojo.system.Handle):
+      raise TypeError('%r is not a handle' % value)
+    return value
+
+  def Serialize(self, value, data_offset, data, handle_offset):
+    if not value.IsValid() and not self.nullable:
+      raise serialization.SerializationException(
+          'Trying to serialize null for non nullable type.')
+    if not value.IsValid():
+      return (-1, [])
+    return (handle_offset, [value])
+
+  def Deserialize(self, value, data, handles):
+    if value == -1:
+      if not self.nullable:
+        raise serialization.DeserializationException(
+            'Trying to deserialize null for non nullable type.')
+      return mojo.system.Handle()
+    # TODO(qsr) validate handle order
+    return handles[value]
+
+
+class BaseArrayType(PointerType):
+  """Abstract Type object for arrays."""
+
+  def __init__(self, nullable=False, length=0):
+    PointerType.__init__(self, nullable)
+    self.length = length
+
+  def SerializePointer(self, value, data_offset, data, handle_offset):
+    if self.length != 0 and len(value) != self.length:
+      raise serialization.SerializationException('Incorrect array size')
+    return self.SerializeArray(value, data_offset, data, handle_offset)
+
+  def SerializeArray(self, value, data_offset, data, handle_offset):
+    """Serialize the not null array."""
+    raise NotImplementedError()
+
+  def DeserializePointer(self, size, nb_elements, data, handles):
+    if self.length != 0 and size != self.length:
+      raise serialization.DeserializationException('Incorrect array size')
+    return self.DeserializeArray(size, nb_elements, data, handles)
+
+  def DeserializeArray(self, size, nb_elements, data, handles):
+    raise NotImplementedError()
+
+
+class BooleanArrayType(BaseArrayType):
+
+  def __init__(self, nullable=False, length=0):
+    BaseArrayType.__init__(self, nullable, length)
+    self._array_type = NativeArrayType('B', nullable)
+
+  def Convert(self, value):
+    if value is None:
+      return value
+    return [TYPE_BOOL.Convert(x) for x in value]
+
+  def SerializeArray(self, value, data_offset, data, handle_offset):
+    groups = [value[i:i+8] for i in range(0, len(value), 8)]
+    converted = array.array('B', [_ConvertBooleansToByte(x) for x in groups])
+    return _SerializeNativeArray(converted, data_offset, data, len(value))
+
+  def DeserializeArray(self, size, nb_elements, data, handles):
+    converted = self._array_type.DeserializeArray(
+        size, nb_elements, data, handles)
+    elements = list(itertools.islice(
+        itertools.chain.from_iterable(
+            [_ConvertByteToBooleans(x, 8) for x in converted]),
+        0,
+        nb_elements))
+    return elements
+
+
+class GenericArrayType(BaseArrayType):
+  """Type object for arrays of pointers."""
+
+  def __init__(self, sub_type, nullable=False, length=0):
+    BaseArrayType.__init__(self, nullable, length)
+    assert isinstance(sub_type, SerializableType)
+    self.sub_type = sub_type
+
+  def Convert(self, value):
+    if value is None:
+      return value
+    return [self.sub_type.Convert(x) for x in value]
+
+  def SerializeArray(self, value, data_offset, data, handle_offset):
+    size = (serialization.HEADER_STRUCT.size +
+            self.sub_type.GetByteSize() * len(value))
+    data_end = len(data)
+    position = len(data) + serialization.HEADER_STRUCT.size
+    data.extend(bytearray(size +
+                          serialization.NeededPaddingForAlignment(size)))
+    returned_handles = []
+    to_pack = []
+    for item in value:
+      (new_data, new_handles) = self.sub_type.Serialize(
+          item,
+          len(data) - position,
+          data,
+          handle_offset + len(returned_handles))
+      to_pack.append(new_data)
+      returned_handles.extend(new_handles)
+      position = position + self.sub_type.GetByteSize()
+    serialization.HEADER_STRUCT.pack_into(data, data_end, size, len(value))
+    struct.pack_into('%d%s' % (len(value), self.sub_type.GetTypeCode()),
+                     data,
+                     data_end + serialization.HEADER_STRUCT.size,
+                     *to_pack)
+    return (data_offset, returned_handles)
+
+  def DeserializeArray(self, size, nb_elements, data, handles):
+    values = struct.unpack_from(
+        '%d%s' % (nb_elements, self.sub_type.GetTypeCode()),
+        buffer(data, serialization.HEADER_STRUCT.size))
+    result = []
+    position = serialization.HEADER_STRUCT.size
+    for value in values:
+      result.append(
+          self.sub_type.Deserialize(value, buffer(data, position), handles))
+      position += self.sub_type.GetByteSize()
+    return result
+
+
+class NativeArrayType(BaseArrayType):
+  """Type object for arrays of native types."""
+
+  def __init__(self, typecode, nullable=False, length=0):
+    BaseArrayType.__init__(self, nullable, length)
+    self.array_typecode = typecode
+
+  def Convert(self, value):
+    if value is None:
+      return value
+    if (isinstance(value, array.array) and
+        value.array_typecode == self.array_typecode):
+      return value
+    return array.array(self.array_typecode, value)
+
+  def SerializeArray(self, value, data_offset, data, handle_offset):
+    return _SerializeNativeArray(value, data_offset, data, len(value))
+
+  def DeserializeArray(self, size, nb_elements, data, handles):
+    result = array.array(self.array_typecode)
+    result.fromstring(buffer(data,
+                             serialization.HEADER_STRUCT.size,
+                             size - serialization.HEADER_STRUCT.size))
+    return result
+
+
+class StructType(PointerType):
+  """Type object for structs."""
+
+  def __init__(self, struct_type, nullable=False):
+    PointerType.__init__(self)
+    self.struct_type = struct_type
+    self.nullable = nullable
+
+  def Convert(self, value):
+    if value is None or isinstance(value, self.struct_type):
+      return value
+    raise TypeError('%r is not an instance of %r' % (value, self.struct_type))
+
+  def GetDefaultValue(self, value):
+    if value:
+      return self.struct_type()
+    return None
+
+  def SerializePointer(self, value, data_offset, data, handle_offset):
+    (new_data, new_handles) = value.Serialize(handle_offset)
+    data.extend(new_data)
+    return (data_offset, new_handles)
+
+  def DeserializePointer(self, size, nb_elements, data, handles):
+    return self.struct_type.Deserialize(data, handles)
+
+
+class NoneType(SerializableType):
+  """Placeholder type, used temporarily until all mojo types are handled."""
+
+  def __init__(self):
+    SerializableType.__init__(self, 'B')
+
+  def Convert(self, value):
+    return None
+
+  def Serialize(self, value, data_offset, data, handle_offset):
+    return (0, [])
+
+  def Deserialize(self, value, data, handles):
+    return None
+
+
+TYPE_NONE = NoneType()
+
+TYPE_BOOL = BooleanType()
+
+TYPE_INT8 = IntegerType('b')
+TYPE_INT16 = IntegerType('h')
+TYPE_INT32 = IntegerType('i')
+TYPE_INT64 = IntegerType('q')
+
+TYPE_UINT8 = IntegerType('B')
+TYPE_UINT16 = IntegerType('H')
+TYPE_UINT32 = IntegerType('I')
+TYPE_UINT64 = IntegerType('Q')
+
+TYPE_FLOAT = FloatType('f')
+TYPE_DOUBLE = FloatType('d')
+
+TYPE_STRING = StringType()
+TYPE_NULLABLE_STRING = StringType(True)
+
+TYPE_HANDLE = HandleType()
+TYPE_NULLABLE_HANDLE = HandleType(True)
+
+
+class FieldDescriptor(object):
+  """Describes a field in a generated struct."""
+
+  def __init__(self, name, field_type, index, version, default_value=None):
+    self.name = name
+    self.field_type = field_type
+    self.version = version
+    self.index = index
+    self._default_value = default_value
+
+  def GetDefaultValue(self):
+    return self.field_type.GetDefaultValue(self._default_value)
+
+
+class FieldGroup(object):
+  """
+  Describe a list of field in the generated struct that must be
+  serialized/deserialized together.
+  """
+  def __init__(self, descriptors):
+    self.descriptors = descriptors
+
+  def GetDescriptors(self):
+    return self.descriptors
+
+  def GetTypeCode(self):
+    raise NotImplementedError()
+
+  def GetByteSize(self):
+    raise NotImplementedError()
+
+  def GetVersion(self):
+    raise NotImplementedError()
+
+  def Serialize(self, obj, data_offset, data, handle_offset):
+    raise NotImplementedError()
+
+  def Deserialize(self, value, data, handles):
+    raise NotImplementedError()
+
+
+class SingleFieldGroup(FieldGroup, FieldDescriptor):
+  """A FieldGroup that contains a single FieldDescriptor."""
+
+  def __init__(self, name, field_type, index, version, default_value=None):
+    FieldDescriptor.__init__(
+        self, name, field_type, index, version, default_value)
+    FieldGroup.__init__(self, [self])
+
+  def GetTypeCode(self):
+    return self.field_type.GetTypeCode()
+
+  def GetByteSize(self):
+    return self.field_type.GetByteSize()
+
+  def GetVersion(self):
+    return self.version
+
+  def Serialize(self, obj, data_offset, data, handle_offset):
+    value = getattr(obj, self.name)
+    return self.field_type.Serialize(value, data_offset, data, handle_offset)
+
+  def Deserialize(self, value, data, handles):
+    entity = self.field_type.Deserialize(value, data, handles)
+    return { self.name: entity }
+
+
+class BooleanGroup(FieldGroup):
+  """A FieldGroup to pack booleans."""
+  def __init__(self, descriptors):
+    FieldGroup.__init__(self, descriptors)
+    self.version = min([descriptor.version  for descriptor in descriptors])
+
+  def GetTypeCode(self):
+    return 'B'
+
+  def GetByteSize(self):
+    return 1
+
+  def GetVersion(self):
+    return self.version
+
+  def Serialize(self, obj, data_offset, data, handle_offset):
+    value = _ConvertBooleansToByte(
+        [getattr(obj, field.name) for field in self.GetDescriptors()])
+    return (value, [])
+
+  def Deserialize(self, value, data, handles):
+    values =  itertools.izip_longest([x.name for x in self.descriptors],
+                                      _ConvertByteToBooleans(value),
+                                     fillvalue=False)
+    return dict(values)
+
+
+def _SerializeNativeArray(value, data_offset, data, length):
+  data_size = len(data)
+  data.extend(bytearray(serialization.HEADER_STRUCT.size))
+  data.extend(buffer(value))
+  data_length = len(data) - data_size
+  data.extend(bytearray(serialization.NeededPaddingForAlignment(data_length)))
+  serialization.HEADER_STRUCT.pack_into(data, data_size, data_length, length)
+  return (data_offset, [])
+
+
+def _ConvertBooleansToByte(booleans):
+  """Pack a list of booleans into an integer."""
+  return reduce(lambda x, y: x * 2 + y, reversed(booleans), 0)
+
+
+def _ConvertByteToBooleans(value, min_size=0):
+  "Unpack an integer into a list of booleans."""
+  res = []
+  while value:
+    res.append(bool(value&1))
+    value = value / 2
+  res.extend([False] * (min_size - len(res)))
+  return res
diff --git a/mojo/public/python/mojo/bindings/messaging.py b/mojo/public/python/mojo/bindings/messaging.py
new file mode 100644
index 0000000..956f5b3
--- /dev/null
+++ b/mojo/public/python/mojo/bindings/messaging.py
@@ -0,0 +1,387 @@
+# Copyright 2014 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.
+
+"""Utility classes to handle sending and receiving messages."""
+
+
+import struct
+import weakref
+
+# pylint: disable=F0401
+import mojo.bindings.serialization as serialization
+import mojo.system as system
+
+
+# The flag values for a message header.
+NO_FLAG = 0
+MESSAGE_EXPECTS_RESPONSE_FLAG = 1 << 0
+MESSAGE_IS_RESPONSE_FLAG = 1 << 1
+
+
+class MessageHeader(object):
+  """The header of a mojo message."""
+
+  _SIMPLE_MESSAGE_NUM_FIELDS = 2
+  _SIMPLE_MESSAGE_STRUCT = struct.Struct("=IIII")
+
+  _REQUEST_ID_STRUCT = struct.Struct("=Q")
+  _REQUEST_ID_OFFSET = _SIMPLE_MESSAGE_STRUCT.size
+
+  _MESSAGE_WITH_REQUEST_ID_NUM_FIELDS = 3
+  _MESSAGE_WITH_REQUEST_ID_SIZE = (
+      _SIMPLE_MESSAGE_STRUCT.size + _REQUEST_ID_STRUCT.size)
+
+  def __init__(self, message_type, flags, request_id=0, data=None):
+    self._message_type = message_type
+    self._flags = flags
+    self._request_id = request_id
+    self._data = data
+
+  @classmethod
+  def Deserialize(cls, data):
+    buf = buffer(data)
+    if len(data) < cls._SIMPLE_MESSAGE_STRUCT.size:
+      raise serialization.DeserializationException('Header is too short.')
+    (size, version, message_type, flags) = (
+        cls._SIMPLE_MESSAGE_STRUCT.unpack_from(buf))
+    if (version < cls._SIMPLE_MESSAGE_NUM_FIELDS):
+      raise serialization.DeserializationException('Incorrect version.')
+    request_id = 0
+    if _HasRequestId(flags):
+      if version < cls._MESSAGE_WITH_REQUEST_ID_NUM_FIELDS:
+        raise serialization.DeserializationException('Incorrect version.')
+      if (size < cls._MESSAGE_WITH_REQUEST_ID_SIZE or
+          len(data) < cls._MESSAGE_WITH_REQUEST_ID_SIZE):
+        raise serialization.DeserializationException('Header is too short.')
+      (request_id, ) = cls._REQUEST_ID_STRUCT.unpack_from(
+          buf, cls._REQUEST_ID_OFFSET)
+    return MessageHeader(message_type, flags, request_id, data)
+
+  @property
+  def message_type(self):
+    return self._message_type
+
+  # pylint: disable=E0202
+  @property
+  def request_id(self):
+    assert self.has_request_id
+    return self._request_id
+
+  # pylint: disable=E0202
+  @request_id.setter
+  def request_id(self, request_id):
+    assert self.has_request_id
+    self._request_id = request_id
+    self._REQUEST_ID_STRUCT.pack_into(self._data, self._REQUEST_ID_OFFSET,
+                                      request_id)
+
+  @property
+  def has_request_id(self):
+    return _HasRequestId(self._flags)
+
+  @property
+  def expects_response(self):
+    return self._HasFlag(MESSAGE_EXPECTS_RESPONSE_FLAG)
+
+  @property
+  def is_response(self):
+    return self._HasFlag(MESSAGE_IS_RESPONSE_FLAG)
+
+  @property
+  def size(self):
+    if self.has_request_id:
+      return self._MESSAGE_WITH_REQUEST_ID_SIZE
+    return self._SIMPLE_MESSAGE_STRUCT.size
+
+  def Serialize(self):
+    if not self._data:
+      self._data = bytearray(self.size)
+      version = self._SIMPLE_MESSAGE_NUM_FIELDS
+      size = self._SIMPLE_MESSAGE_STRUCT.size
+      if self.has_request_id:
+        version = self._MESSAGE_WITH_REQUEST_ID_NUM_FIELDS
+        size = self._MESSAGE_WITH_REQUEST_ID_SIZE
+      self._SIMPLE_MESSAGE_STRUCT.pack_into(self._data, 0, size, version,
+                                            self._message_type, self._flags)
+      if self.has_request_id:
+        self._REQUEST_ID_STRUCT.pack_into(self._data, self._REQUEST_ID_OFFSET,
+                                          self._request_id)
+    return self._data
+
+  def _HasFlag(self, flag):
+    return self._flags & flag != 0
+
+
+class Message(object):
+  """A message for a message pipe. This contains data and handles."""
+
+  def __init__(self, data=None, handles=None):
+    self.data = data
+    self.handles = handles
+    self._header = None
+    self._payload = None
+
+  @property
+  def header(self):
+    if self._header is None:
+      self._header = MessageHeader.Deserialize(self.data)
+    return self._header
+
+  @property
+  def payload(self):
+    if self._payload is None:
+      self._payload = Message(self.data[self.header.size:], self.handles)
+    return self._payload
+
+  def SetRequestId(self, request_id):
+    header = self.header
+    header.request_id = request_id
+    (data, _) = header.Serialize()
+    self.data[:header.Size] = data[:header.Size]
+
+
+class MessageReceiver(object):
+  """A class which implements this interface can receive Message objects."""
+
+  def Accept(self, message):
+    """
+    Receive a Message. The MessageReceiver is allowed to mutate the message.
+
+    Args:
+      message: the received message.
+
+    Returns:
+      True if the message has been handled, False otherwise.
+    """
+    raise NotImplementedError()
+
+
+class MessageReceiverWithResponder(MessageReceiver):
+  """
+  A MessageReceiver that can also handle the response message generated from the
+  given message.
+  """
+
+  def AcceptWithResponder(self, message, responder):
+    """
+    A variant on Accept that registers a MessageReceiver (known as the
+    responder) to handle the response message generated from the given message.
+    The responder's Accept method may be called as part of the call to
+    AcceptWithResponder, or some time after its return.
+
+    Args:
+      message: the received message.
+      responder: the responder that will receive the response.
+
+    Returns:
+      True if the message has been handled, False otherwise.
+    """
+    raise NotImplementedError()
+
+
+class ConnectionErrorHandler(object):
+  """
+  A ConnectionErrorHandler is notified of an error happening while using the
+  bindings over message pipes.
+  """
+
+  def OnError(self, result):
+    raise NotImplementedError()
+
+
+class Connector(MessageReceiver):
+  """
+  A Connector owns a message pipe and will send any received messages to the
+  registered MessageReceiver. It also acts as a MessageReceiver and will send
+  any message through the handle.
+
+  The method Start must be called before the Connector will start listening to
+  incoming messages.
+  """
+
+  def __init__(self, handle):
+    MessageReceiver.__init__(self)
+    self._handle = handle
+    self._cancellable = None
+    self._incoming_message_receiver = None
+    self._error_handler = None
+
+  def __del__(self):
+    if self._cancellable:
+      self._cancellable()
+
+  def SetIncomingMessageReceiver(self, message_receiver):
+    """
+    Set the MessageReceiver that will receive message from the owned message
+    pipe.
+    """
+    self._incoming_message_receiver = message_receiver
+
+  def SetErrorHandler(self, error_handler):
+    """
+    Set the ConnectionErrorHandler that will be notified of errors on the owned
+    message pipe.
+    """
+    self._error_handler = error_handler
+
+  def Start(self):
+    assert not self._cancellable
+    self._RegisterAsyncWaiterForRead()
+
+  def Accept(self, message):
+    result = self._handle.WriteMessage(message.data, message.handles)
+    return result == system.RESULT_OK
+
+  def Close(self):
+    if self._cancellable:
+      self._cancellable()
+      self._cancellable = None
+    self._handle.Close()
+
+  def _OnAsyncWaiterResult(self, result):
+    self._cancellable = None
+    if result == system.RESULT_OK:
+      self._ReadOutstandingMessages()
+    else:
+      self._OnError(result)
+
+  def _OnError(self, result):
+    assert not self._cancellable
+    if self._error_handler:
+      self._error_handler.OnError(result)
+
+  def _RegisterAsyncWaiterForRead(self) :
+    assert not self._cancellable
+    self._cancellable = self._handle.AsyncWait(
+        system.HANDLE_SIGNAL_READABLE,
+        system.DEADLINE_INDEFINITE,
+        _WeakCallback(self._OnAsyncWaiterResult))
+
+  def _ReadOutstandingMessages(self):
+    result = system.RESULT_OK
+    while result == system.RESULT_OK:
+      result = _ReadAndDispatchMessage(self._handle,
+                                       self._incoming_message_receiver)
+    if result == system.RESULT_SHOULD_WAIT:
+      self._RegisterAsyncWaiterForRead()
+      return
+    self._OnError(result)
+
+
+class Router(MessageReceiverWithResponder):
+  """
+  A Router will handle mojo message and forward those to a Connector. It deals
+  with parsing of headers and adding of request ids in order to be able to match
+  a response to a request.
+  """
+
+  def __init__(self, handle):
+    MessageReceiverWithResponder.__init__(self)
+    self._incoming_message_receiver = None
+    self._next_request_id = 1
+    self._responders = {}
+    self._connector = Connector(handle)
+    self._connector.SetIncomingMessageReceiver(
+        ForwardingMessageReceiver(self._HandleIncomingMessage))
+
+  def Start(self):
+    self._connector.Start()
+
+  def SetIncomingMessageReceiver(self, message_receiver):
+    """
+    Set the MessageReceiver that will receive message from the owned message
+    pipe.
+    """
+    self._incoming_message_receiver = message_receiver
+
+  def SetErrorHandler(self, error_handler):
+    """
+    Set the ConnectionErrorHandler that will be notified of errors on the owned
+    message pipe.
+    """
+    self._connector.SetErrorHandler(error_handler)
+
+  def Accept(self, message):
+    # A message without responder is directly forwarded to the connector.
+    return self._connector.Accept(message)
+
+  def AcceptWithResponder(self, message, responder):
+    # The message must have a header.
+    header = message.header
+    assert header.expects_response
+    request_id = self.NextRequestId()
+    header.request_id = request_id
+    if not self._connector.Accept(message):
+      return False
+    self._responders[request_id] = responder
+    return True
+
+  def Close(self):
+    self._connector.Close()
+
+  def _HandleIncomingMessage(self, message):
+    header = message.header
+    if header.expects_response:
+      if self._incoming_message_receiver:
+        return self._incoming_message_receiver.AcceptWithResponder(
+            message, self)
+      # If we receive a request expecting a response when the client is not
+      # listening, then we have no choice but to tear down the pipe.
+      self.Close()
+      return False
+    if header.is_response:
+      request_id = header.request_id
+      responder = self._responders.pop(request_id, None)
+      if responder is None:
+        return False
+      return responder.Accept(message)
+    if self._incoming_message_receiver:
+      return self._incoming_message_receiver.Accept(message)
+    # Ok to drop the message
+    return False
+
+  def NextRequestId(self):
+    request_id = self._next_request_id
+    while request_id == 0 or request_id in self._responders:
+      request_id = (request_id + 1) % (1 << 64)
+    self._next_request_id = (request_id + 1) % (1 << 64)
+    return request_id
+
+class ForwardingMessageReceiver(MessageReceiver):
+  """A MessageReceiver that forward calls to |Accept| to a callable."""
+
+  def __init__(self, callback):
+    MessageReceiver.__init__(self)
+    self._callback = callback
+
+  def Accept(self, message):
+    return self._callback(message)
+
+
+def _WeakCallback(callback):
+  func = callback.im_func
+  self = callback.im_self
+  if not self:
+    return callback
+  weak_self = weakref.ref(self)
+  def Callback(*args, **kwargs):
+    self = weak_self()
+    if self:
+      return func(self, *args, **kwargs)
+  return Callback
+
+
+def _ReadAndDispatchMessage(handle, message_receiver):
+  (result, _, sizes) = handle.ReadMessage()
+  if result == system.RESULT_OK and message_receiver:
+    message_receiver.Accept(Message(bytearray(), []))
+  if result != system.RESULT_RESOURCE_EXHAUSTED:
+    return result
+  (result, data, _) = handle.ReadMessage(bytearray(sizes[0]))
+  if result == system.RESULT_OK and message_receiver:
+    message_receiver.Accept(Message(data[0], data[1]))
+  return result
+
+def _HasRequestId(flags):
+  return flags & (MESSAGE_EXPECTS_RESPONSE_FLAG|MESSAGE_IS_RESPONSE_FLAG) != 0
diff --git a/mojo/public/python/mojo/bindings/promise.py b/mojo/public/python/mojo/bindings/promise.py
new file mode 100644
index 0000000..c5d7d7c
--- /dev/null
+++ b/mojo/public/python/mojo/bindings/promise.py
@@ -0,0 +1,188 @@
+# Copyright 2014 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.
+
+"""
+Promise used by the python bindings.
+
+The API is following the ECMAScript 6 API for promises.
+"""
+
+
+class Promise(object):
+  """The promise object."""
+
+  STATE_PENDING = 0
+  STATE_FULLFILLED = 1
+  STATE_REJECTED = 2
+  STATE_BOUND = 3
+
+  def __init__(self, generator_function):
+    """
+    Constructor.
+
+    Args:
+      generator_function: A function taking 2 arguments: resolve and reject.
+      When |resolve| is called, the promise is fullfilled with the given value.
+      When |reject| is called, the promise is rejected with the given value.
+      A promise can only be resolved or rejected once, all following calls will
+      have no effect.
+    """
+    self._onCatched = []
+    self._onFulfilled = []
+    self._onRejected = []
+    self._state = Promise.STATE_PENDING
+    self._result = None
+    if generator_function:
+      generator_function(self._Resolve, self._Reject)
+
+  @staticmethod
+  def Resolve(value):
+    """
+    If value is a promise, make a promise that have the same behavior as value,
+    otherwise make a promise that fulfills to value.
+    """
+    if isinstance(value, Promise):
+      return value
+    return Promise(lambda x, y: x(value))
+
+  @staticmethod
+  def Reject(reason):
+    "Make a promise that rejects to reason."""
+    return Promise(lambda x, y: y(reason))
+
+  @staticmethod
+  def All(*iterable):
+    """
+    Make a promise that fulfills when every item in the array fulfills, and
+    rejects if (and when) any item rejects. Each array item is passed to
+    Promise.resolve, so the array can be a mixture of promise-like objects and
+    other objects. The fulfillment value is an array (in order) of fulfillment
+    values. The rejection value is the first rejection value.
+    """
+    def GeneratorFunction(resolve, reject):
+      state = {
+        'rejected': False,
+        'nb_resolved': 0,
+      }
+      promises = [Promise.Resolve(x) for x in iterable]
+      results = [None for x in promises]
+      def OnFullfilled(i):
+        def OnFullfilled(res):
+          if state['rejected']:
+            return
+          results[i] = res
+          state['nb_resolved'] = state['nb_resolved'] + 1
+          if state['nb_resolved'] == len(results):
+            resolve(results)
+        return OnFullfilled
+      def OnRejected(reason):
+        if state['rejected']:
+          return
+        state['rejected'] = True
+        reject(reason)
+
+      for (i, promise) in enumerate(promises):
+        promise.Then(OnFullfilled(i), OnRejected)
+    return Promise(GeneratorFunction)
+
+  @staticmethod
+  def Race(*iterable):
+    """
+    Make a Promise that fulfills as soon as any item fulfills, or rejects as
+    soon as any item rejects, whichever happens first.
+    """
+    def GeneratorFunction(resolve, reject):
+      state = {
+        'ended': False
+      }
+      def OnEvent(callback):
+        def OnEvent(res):
+          if state['ended']:
+            return
+          state['ended'] = True
+          callback(res)
+        return OnEvent
+      for promise in [Promise.Resolve(x) for x in iterable]:
+        promise.Then(OnEvent(resolve), OnEvent(reject))
+    return Promise(GeneratorFunction)
+
+  @property
+  def state(self):
+    if isinstance(self._result, Promise):
+      return self._result.state
+    return self._state
+
+  def Then(self, onFullfilled=None, onRejected=None):
+    """
+    onFulfilled is called when/if this promise resolves. onRejected is called
+    when/if this promise rejects. Both are optional, if either/both are omitted
+    the next onFulfilled/onRejected in the chain is called. Both callbacks have
+    a single parameter, the fulfillment value or rejection reason. |Then|
+    returns a new promise equivalent to the value you return from
+    onFulfilled/onRejected after being passed through Resolve. If an
+    error is thrown in the callback, the returned promise rejects with that
+    error.
+    """
+    if isinstance(self._result, Promise):
+      return self._result.Then(onFullfilled, onRejected)
+    def GeneratorFunction(resolve, reject):
+      if self._state == Promise.STATE_PENDING:
+        self._onFulfilled.append(_Delegate(resolve, reject, onFullfilled))
+        self._onRejected.append(_Delegate(reject, reject, onRejected))
+      if self._state == self.STATE_FULLFILLED:
+        _Delegate(resolve, reject, onFullfilled)(self._result)
+      if self._state == self.STATE_REJECTED:
+        recover = reject
+        if onRejected:
+          recover = resolve
+        _Delegate(recover, reject, onRejected)(self._result)
+    return Promise(GeneratorFunction)
+
+  def Catch(self, onCatched):
+    """Equivalent to |Then(None, onCatched)|"""
+    return self.Then(None, onCatched)
+
+  def _Resolve(self, value):
+    if self.state != Promise.STATE_PENDING:
+      return
+    self._result = value
+    if isinstance(value, Promise):
+      self._state = Promise.STATE_BOUND
+      self._result.Then(_IterateAction(self._onFulfilled),
+                        _IterateAction(self._onRejected))
+      return
+    self._state = Promise.STATE_FULLFILLED
+    for f in self._onFulfilled:
+      f(value)
+    self._onFulfilled = None
+    self._onRejected = None
+
+  def _Reject(self, reason):
+    if self.state != Promise.STATE_PENDING:
+      return
+    self._result = reason
+    self._state = Promise.STATE_REJECTED
+    for f in self._onRejected:
+      f(reason)
+    self._onFulfilled = None
+    self._onRejected = None
+
+
+def _IterateAction(iterable):
+  def _Run(x):
+    for f in iterable:
+      f(x)
+  return _Run
+
+
+def _Delegate(resolve, reject, action):
+  def _Run(x):
+    try:
+      if action:
+        resolve(action(x))
+      else:
+        resolve(x)
+    except Exception as e:
+      reject(e)
+  return _Run
diff --git a/mojo/public/python/mojo/bindings/reflection.py b/mojo/public/python/mojo/bindings/reflection.py
new file mode 100644
index 0000000..c682e5e
--- /dev/null
+++ b/mojo/public/python/mojo/bindings/reflection.py
@@ -0,0 +1,163 @@
+# Copyright 2014 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.
+
+"""The metaclasses used by the mojo python bindings."""
+
+import itertools
+
+# pylint: disable=F0401
+import mojo.bindings.serialization as serialization
+
+
+class MojoEnumType(type):
+  """Meta class for enumerations.
+
+  Usage:
+    class MyEnum(object):
+      __metaclass__ = MojoEnumType
+      VALUES = [
+        ('A', 0),
+        'B',
+        ('C', 5),
+      ]
+
+      This will define a enum with 3 values, 'A' = 0, 'B' = 1 and 'C' = 5.
+  """
+
+  def __new__(mcs, name, bases, dictionary):
+    dictionary['__slots__'] = ()
+    dictionary['__new__'] = None
+    for value in dictionary.pop('VALUES', []):
+      if not isinstance(value, tuple):
+        raise ValueError('incorrect value: %r' % value)
+      key, enum_value = value
+      if isinstance(key, str) and isinstance(enum_value, int):
+        dictionary[key] = enum_value
+      else:
+        raise ValueError('incorrect value: %r' % value)
+    return type.__new__(mcs, name, bases, dictionary)
+
+  def __setattr__(mcs, key, value):
+    raise AttributeError, 'can\'t set attribute'
+
+  def __delattr__(mcs, key):
+    raise AttributeError, 'can\'t delete attribute'
+
+
+class MojoStructType(type):
+  """Meta class for structs.
+
+  Usage:
+    class MyStruct(object):
+      __metaclass__ = MojoStructType
+      DESCRIPTOR = {
+        'constants': {
+          'C1': 1,
+          'C2': 2,
+        },
+        'enums': {
+          'ENUM1': [
+            ('V1', 1),
+            'V2',
+          ],
+          'ENUM2': [
+            ('V1', 1),
+            'V2',
+          ],
+        },
+        'fields': [
+           FieldDescriptor('x', _descriptor.TYPE_INT32, 0),
+        ],
+      }
+
+      This will define an struct, with:
+      - 2 constants 'C1' and 'C2';
+      - 2 enums 'ENUM1' and 'ENUM2', each of those having 2 values, 'V1' and
+        'V2';
+      - 1 int32 field named 'x'.
+  """
+
+  def __new__(mcs, name, bases, dictionary):
+    dictionary['__slots__'] = ('_fields')
+    descriptor = dictionary.pop('DESCRIPTOR', {})
+
+    # Add constants
+    dictionary.update(descriptor.get('constants', {}))
+
+    # Add enums
+    enums = descriptor.get('enums', {})
+    for key in enums:
+      dictionary[key] = MojoEnumType(key, (object,), { 'VALUES': enums[key] })
+
+    # Add fields
+    groups = descriptor.get('fields', [])
+
+    fields = list(
+        itertools.chain.from_iterable([group.descriptors for group in groups]))
+    fields.sort(key=lambda f: f.index)
+    for field in fields:
+      dictionary[field.name] = _BuildProperty(field)
+
+    # Add init
+    dictionary['__init__'] = _StructInit(fields)
+
+    # Add serialization method
+    serialization_object = serialization.Serialization(groups)
+    def Serialize(self, handle_offset=0):
+      return serialization_object.Serialize(self, handle_offset)
+    dictionary['Serialize'] = Serialize
+
+    def Deserialize(cls, data, handles):
+      result = cls.__new__(cls)
+      fields = {}
+      serialization_object.Deserialize(fields, data, handles)
+      result._fields = fields
+      return result
+    dictionary['Deserialize'] = classmethod(Deserialize)
+
+    return type.__new__(mcs, name, bases, dictionary)
+
+  # Prevent adding new attributes, or mutating constants.
+  def __setattr__(mcs, key, value):
+    raise AttributeError, 'can\'t set attribute'
+
+  # Prevent deleting constants.
+  def __delattr__(mcs, key):
+    raise AttributeError, 'can\'t delete attribute'
+
+
+def _StructInit(fields):
+  def _Init(self, *args, **kwargs):
+    if len(args) + len(kwargs) > len(fields):
+      raise TypeError('__init__() takes %d argument (%d given)' %
+                      (len(fields), len(args) + len(kwargs)))
+    self._fields = {}
+    for f, a in zip(fields, args):
+      self.__setattr__(f.name, a)
+    remaining_fields = set(x.name for x in fields[len(args):])
+    for name in kwargs:
+      if not name in remaining_fields:
+        if name in (x.name for x in fields[:len(args)]):
+          raise TypeError(
+              '__init__() got multiple values for keyword argument %r' % name)
+        raise TypeError('__init__() got an unexpected keyword argument %r' %
+                        name)
+      self.__setattr__(name, kwargs[name])
+  return _Init
+
+
+def _BuildProperty(field):
+  """Build the property for the given field."""
+
+  # pylint: disable=W0212
+  def Get(self):
+    if field.name not in self._fields:
+      self._fields[field.name] = field.GetDefaultValue()
+    return self._fields[field.name]
+
+  # pylint: disable=W0212
+  def Set(self, value):
+    self._fields[field.name] = field.field_type.Convert(value)
+
+  return property(Get, Set)
diff --git a/mojo/public/python/mojo/bindings/serialization.py b/mojo/public/python/mojo/bindings/serialization.py
new file mode 100644
index 0000000..9a4b6a9
--- /dev/null
+++ b/mojo/public/python/mojo/bindings/serialization.py
@@ -0,0 +1,126 @@
+# Copyright 2014 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.
+
+"""Utility classes for serialization"""
+
+import struct
+
+
+# Format of a header for a struct or an array.
+HEADER_STRUCT = struct.Struct("=II")
+
+
+class SerializationException(Exception):
+  """Error when strying to serialize a struct."""
+  pass
+
+
+class DeserializationException(Exception):
+  """Error when strying to deserialize a struct."""
+  pass
+
+
+class Serialization(object):
+  """
+  Helper class to serialize/deserialize a struct.
+  """
+  def __init__(self, groups):
+    self.version = _GetVersion(groups)
+    self._groups = groups
+    main_struct = _GetStruct(groups)
+    self.size = HEADER_STRUCT.size + main_struct.size
+    self._struct_per_version = {
+        self.version: main_struct,
+    }
+    self._groups_per_version = {
+        self.version: groups,
+    }
+
+  def _GetMainStruct(self):
+    return self._GetStruct(self.version)
+
+  def _GetGroups(self, version):
+    # If asking for a version greater than the last known.
+    version = min(version, self.version)
+    if version not in self._groups_per_version:
+      self._groups_per_version[version] = _FilterGroups(self._groups, version)
+    return self._groups_per_version[version]
+
+  def _GetStruct(self, version):
+    # If asking for a version greater than the last known.
+    version = min(version, self.version)
+    if version not in self._struct_per_version:
+      self._struct_per_version[version] = _GetStruct(self._GetGroups(version))
+    return self._struct_per_version[version]
+
+  def Serialize(self, obj, handle_offset):
+    """
+    Serialize the given obj. handle_offset is the the first value to use when
+    encoding handles.
+    """
+    handles = []
+    data = bytearray(self.size)
+    HEADER_STRUCT.pack_into(data, 0, self.size, self.version)
+    position = HEADER_STRUCT.size
+    to_pack = []
+    for group in self._groups:
+      position = position + NeededPaddingForAlignment(position,
+                                                      group.GetByteSize())
+      (entry, new_handles) = group.Serialize(
+          obj,
+          len(data) - position,
+          data,
+          handle_offset + len(handles))
+      to_pack.append(entry)
+      handles.extend(new_handles)
+      position = position + group.GetByteSize()
+    self._GetMainStruct().pack_into(data, HEADER_STRUCT.size, *to_pack)
+    return (data, handles)
+
+  def Deserialize(self, fields, data, handles):
+    if not isinstance(data, buffer):
+      data = buffer(data)
+    (_, version) = HEADER_STRUCT.unpack_from(data)
+    version_struct = self._GetStruct(version)
+    entitities = version_struct.unpack_from(data, HEADER_STRUCT.size)
+    filtered_groups = self._GetGroups(version)
+    position = HEADER_STRUCT.size
+    for (group, value) in zip(filtered_groups, entitities):
+      position = position + NeededPaddingForAlignment(position,
+                                                      group.GetByteSize())
+      fields.update(group.Deserialize(value, buffer(data, position), handles))
+      position += group.GetByteSize()
+
+
+def NeededPaddingForAlignment(value, alignment=8):
+  """Returns the padding necessary to align value with the given alignment."""
+  if value % alignment:
+    return alignment - (value % alignment)
+  return 0
+
+
+def _GetVersion(groups):
+  return sum([len(x.descriptors) for x in groups])
+
+
+def _FilterGroups(groups, version):
+  return [group for group in groups if group.GetVersion() < version]
+
+
+def _GetStruct(groups):
+  index = 0
+  codes = [ '=' ]
+  for group in groups:
+    code = group.GetTypeCode()
+    size = group.GetByteSize()
+    needed_padding = NeededPaddingForAlignment(index, size)
+    if needed_padding:
+      codes.append('x' * needed_padding)
+      index = index + needed_padding
+    codes.append(code)
+    index = index + size
+  alignment_needed = NeededPaddingForAlignment(index)
+  if alignment_needed:
+    codes.append('x' * alignment_needed)
+  return struct.Struct(''.join(codes))
diff --git a/mojo/public/python/mojo/c_core.pxd b/mojo/public/python/mojo/c_core.pxd
new file mode 100644
index 0000000..80b8487
--- /dev/null
+++ b/mojo/public/python/mojo/c_core.pxd
@@ -0,0 +1,201 @@
+# Copyright 2014 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.
+
+# distutils: language = c++
+
+from cpython.buffer cimport PyBUF_CONTIG
+from cpython.buffer cimport PyBUF_CONTIG_RO
+from cpython.buffer cimport Py_buffer
+from cpython.buffer cimport PyBuffer_FillInfo
+from cpython.buffer cimport PyBuffer_Release
+from cpython.buffer cimport PyObject_GetBuffer
+from cpython.mem cimport PyMem_Malloc, PyMem_Free
+from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t, uintptr_t
+
+cdef extern from "third_party/cython/python_export.h":
+  pass
+
+cdef extern from "mojo/public/platform/native/system_thunks.h" nogil:
+  cdef struct MojoSystemThunks:
+    pass
+
+cdef extern size_t MojoSetSystemThunks(const MojoSystemThunks* system_thunks)
+
+cdef extern from "mojo/public/c/system/core.h" nogil:
+  # types.h
+  ctypedef int64_t MojoTimeTicks
+
+  ctypedef uint32_t MojoHandle
+  const MojoHandle MOJO_HANDLE_INVALID
+
+  ctypedef int32_t MojoResult
+  const MojoResult MOJO_RESULT_OK
+  const MojoResult MOJO_RESULT_CANCELLED
+  const MojoResult MOJO_RESULT_UNKNOWN
+  const MojoResult MOJO_RESULT_INVALID_ARGUMENT
+  const MojoResult MOJO_RESULT_DEADLINE_EXCEEDED
+  const MojoResult MOJO_RESULT_NOT_FOUND
+  const MojoResult MOJO_RESULT_ALREADY_EXISTS
+  const MojoResult MOJO_RESULT_PERMISSION_DENIED
+  const MojoResult MOJO_RESULT_RESOURCE_EXHAUSTED
+  const MojoResult MOJO_RESULT_FAILED_PRECONDITION
+  const MojoResult MOJO_RESULT_ABORTED
+  const MojoResult MOJO_RESULT_OUT_OF_RANGE
+  const MojoResult MOJO_RESULT_UNIMPLEMENTED
+  const MojoResult MOJO_RESULT_INTERNAL
+  const MojoResult MOJO_RESULT_UNAVAILABLE
+  const MojoResult MOJO_RESULT_DATA_LOSS
+  const MojoResult MOJO_RESULT_BUSY
+  const MojoResult MOJO_RESULT_SHOULD_WAIT
+
+  ctypedef uint64_t MojoDeadline
+  const MojoDeadline MOJO_DEADLINE_INDEFINITE
+
+  ctypedef uint32_t MojoHandleSignals
+  const MojoHandleSignals MOJO_HANDLE_SIGNAL_NONE
+  const MojoHandleSignals MOJO_HANDLE_SIGNAL_READABLE
+  const MojoHandleSignals MOJO_HANDLE_SIGNAL_WRITABLE
+
+  # functions.h
+  MojoTimeTicks MojoGetTimeTicksNow()
+  MojoResult MojoClose(MojoHandle handle)
+  MojoResult MojoWait(MojoHandle handle,
+                      MojoHandleSignals signals,
+                      MojoDeadline deadline)
+  MojoResult MojoWaitMany(const MojoHandle* handles,
+                          const MojoHandleSignals* signals,
+                          uint32_t num_handles,
+                          MojoDeadline deadline)
+
+  # message_pipe.h
+  ctypedef uint32_t MojoCreateMessagePipeOptionsFlags
+  const MojoCreateMessagePipeOptionsFlags MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE
+
+  ctypedef uint32_t MojoWriteMessageFlags
+  const MojoWriteMessageFlags MOJO_WRITE_MESSAGE_FLAG_NONE
+
+  ctypedef uint32_t MojoReadMessageFlags
+  const MojoReadMessageFlags MOJO_READ_MESSAGE_FLAG_NONE
+  const MojoReadMessageFlags MOJO_READ_MESSAGE_FLAG_MAY_DISCARD
+
+  cdef struct MojoCreateMessagePipeOptions:
+    uint32_t struct_size
+    MojoCreateMessagePipeOptionsFlags flags
+
+  MojoResult MojoCreateMessagePipe(
+      const MojoCreateMessagePipeOptions* options,
+      MojoHandle* message_pipe_handle0,
+      MojoHandle* message_pipe_handle1)
+
+  MojoResult MojoWriteMessage(
+      MojoHandle message_pipe_handle,
+      const void* bytes,
+      uint32_t num_bytes,
+      const MojoHandle* handles,
+      uint32_t num_handles,
+      MojoWriteMessageFlags flags)
+
+  MojoResult MojoReadMessage(
+      MojoHandle message_pipe_handle,
+      void* bytes,
+      uint32_t* num_bytes,
+      MojoHandle* handles,
+      uint32_t* num_handles,
+      MojoReadMessageFlags flags)
+
+  # data_pipe.h
+  ctypedef uint32_t MojoCreateDataPipeOptionsFlags
+  const MojoCreateDataPipeOptionsFlags MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
+  const MojoCreateDataPipeOptionsFlags MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD
+
+  cdef struct MojoCreateDataPipeOptions:
+    uint32_t struct_size
+    MojoCreateDataPipeOptionsFlags flags
+    uint32_t element_num_bytes
+    uint32_t capacity_num_bytes
+
+  ctypedef uint32_t MojoWriteDataFlags
+
+  const MojoWriteDataFlags MOJO_WRITE_DATA_FLAG_NONE
+  const MojoWriteDataFlags MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
+
+  ctypedef uint32_t MojoReadDataFlags
+
+  const MojoReadDataFlags MOJO_READ_DATA_FLAG_NONE
+  const MojoReadDataFlags MOJO_READ_DATA_FLAG_ALL_OR_NONE
+  const MojoReadDataFlags MOJO_READ_DATA_FLAG_DISCARD
+  const MojoReadDataFlags MOJO_READ_DATA_FLAG_QUERY
+
+  MojoResult MojoCreateDataPipe(
+      const MojoCreateDataPipeOptions* options,
+      MojoHandle* data_pipe_producer_handle,
+      MojoHandle* data_pipe_consumer_handle)
+
+  MojoResult MojoWriteData(
+      MojoHandle data_pipe_producer_handle,
+      const void* elements,
+      uint32_t* num_bytes,
+      MojoWriteDataFlags flags)
+
+  MojoResult MojoBeginWriteData(
+      MojoHandle data_pipe_producer_handle,
+      void** buffer,
+      uint32_t* buffer_num_bytes,
+      MojoWriteDataFlags flags)
+
+  MojoResult MojoEndWriteData(
+      MojoHandle data_pipe_producer_handle,
+      uint32_t num_bytes_written)
+
+  MojoResult MojoReadData(
+      MojoHandle data_pipe_consumer_handle,
+      void* elements,
+      uint32_t* num_bytes,
+      MojoReadDataFlags flags)
+
+  MojoResult MojoBeginReadData(
+      MojoHandle data_pipe_consumer_handle,
+      const void** buffer,
+      uint32_t* buffer_num_bytes,
+      MojoReadDataFlags flags)
+
+  MojoResult MojoEndReadData(
+      MojoHandle data_pipe_consumer_handle,
+      uint32_t num_bytes_read)
+
+  # buffer.h
+  ctypedef uint32_t MojoCreateSharedBufferOptionsFlags
+  const MojoCreateSharedBufferOptionsFlags MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE
+
+  cdef struct MojoCreateSharedBufferOptions:
+    uint32_t struct_size
+    MojoCreateSharedBufferOptionsFlags flags
+
+  ctypedef uint32_t MojoDuplicateBufferHandleOptionsFlags
+  const MojoDuplicateBufferHandleOptionsFlags MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE
+
+  cdef struct MojoDuplicateBufferHandleOptions:
+    uint32_t struct_size
+    MojoDuplicateBufferHandleOptionsFlags flags
+
+  ctypedef uint32_t MojoMapBufferFlags
+  const MojoMapBufferFlags MOJO_MAP_BUFFER_FLAG_NONE
+
+  MojoResult MojoCreateSharedBuffer(
+      const MojoCreateSharedBufferOptions* options,
+      uint64_t num_bytes,
+      MojoHandle* shared_buffer_handle)
+
+  MojoResult MojoDuplicateBufferHandle(
+      MojoHandle buffer_handle,
+      const MojoDuplicateBufferHandleOptions* options,
+      MojoHandle* new_buffer_handle)
+
+  MojoResult MojoMapBuffer(MojoHandle buffer_handle,
+                           uint64_t offset,
+                           uint64_t num_bytes,
+                           void** buffer,
+                           MojoMapBufferFlags flags)
+
+  MojoResult MojoUnmapBuffer(void* buffer)
diff --git a/mojo/public/python/mojo/c_environment.pxd b/mojo/public/python/mojo/c_environment.pxd
new file mode 100644
index 0000000..13a0934
--- /dev/null
+++ b/mojo/public/python/mojo/c_environment.pxd
@@ -0,0 +1,48 @@
+# Copyright 2014 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.
+
+# distutils: language = c++
+
+from libc.stdint cimport int64_t, intptr_t, uint32_t, uint64_t
+
+
+cdef extern from "mojo/public/c/system/core.h" nogil:
+  ctypedef uint32_t MojoHandle
+  ctypedef uint64_t MojoDeadline
+  ctypedef uint32_t MojoHandleSignals
+
+
+cdef extern from "mojo/public/cpp/bindings/callback.h" nogil:
+  cdef cppclass CClosure "mojo::Callback<void()>":
+    CClosure()
+
+
+cdef extern from "mojo/public/c/environment/async_waiter.h"  nogil:
+  ctypedef intptr_t MojoAsyncWaitID
+
+
+cdef extern from "mojo/public/python/src/python_system_helper.h" \
+    namespace "mojo::python" nogil:
+  cdef CClosure BuildClosure(object)
+  cdef cppclass PythonAsyncWaiter "mojo::python::PythonAsyncWaiter":
+    PythonAsyncWaiter()
+    MojoAsyncWaitID AsyncWait(MojoHandle,
+                              MojoHandleSignals,
+                              MojoDeadline,
+                              object)
+    void CancelWait(MojoAsyncWaitID)
+
+
+cdef extern from "mojo/public/cpp/utility/run_loop.h" nogil:
+  cdef cppclass CRunLoop "mojo::RunLoop":
+    CRunLoop()
+    void Run() except *
+    void RunUntilIdle() except *
+    void Quit()
+    void PostDelayedTask(CClosure&, int64_t)
+
+
+cdef extern from "mojo/public/cpp/environment/environment.h" nogil:
+  cdef cppclass CEnvironment "mojo::Environment":
+    CEnvironment()
diff --git a/mojo/public/python/mojo/system.pyx b/mojo/public/python/mojo/system.pyx
new file mode 100644
index 0000000..4768247
--- /dev/null
+++ b/mojo/public/python/mojo/system.pyx
@@ -0,0 +1,741 @@
+# Copyright 2014 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.
+
+# distutils language = c++
+
+cimport c_core
+cimport c_environment
+
+
+from cpython.buffer cimport PyBUF_CONTIG
+from cpython.buffer cimport PyBUF_CONTIG_RO
+from cpython.buffer cimport Py_buffer
+from cpython.buffer cimport PyBuffer_FillInfo
+from cpython.buffer cimport PyBuffer_Release
+from cpython.buffer cimport PyObject_GetBuffer
+from cpython.mem cimport PyMem_Malloc, PyMem_Free
+from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t, uintptr_t
+
+def SetSystemThunks(system_thunks_as_object):
+  """Bind the basic Mojo Core functions.
+
+  This should only be used by the embedder.
+  """
+  cdef const c_core.MojoSystemThunks* system_thunks = (
+      <const c_core.MojoSystemThunks*><uintptr_t>system_thunks_as_object)
+  c_core.MojoSetSystemThunks(system_thunks)
+
+HANDLE_INVALID = c_core.MOJO_HANDLE_INVALID
+RESULT_OK = c_core.MOJO_RESULT_OK
+RESULT_CANCELLED = c_core.MOJO_RESULT_CANCELLED
+RESULT_UNKNOWN = c_core.MOJO_RESULT_UNKNOWN
+RESULT_INVALID_ARGUMENT = c_core.MOJO_RESULT_INVALID_ARGUMENT
+RESULT_DEADLINE_EXCEEDED = c_core.MOJO_RESULT_DEADLINE_EXCEEDED
+RESULT_NOT_FOUND = c_core.MOJO_RESULT_NOT_FOUND
+RESULT_ALREADY_EXISTS = c_core.MOJO_RESULT_ALREADY_EXISTS
+RESULT_PERMISSION_DENIED = c_core.MOJO_RESULT_PERMISSION_DENIED
+RESULT_RESOURCE_EXHAUSTED = c_core.MOJO_RESULT_RESOURCE_EXHAUSTED
+RESULT_FAILED_PRECONDITION = c_core.MOJO_RESULT_FAILED_PRECONDITION
+RESULT_ABORTED = c_core.MOJO_RESULT_ABORTED
+RESULT_OUT_OF_RANGE = c_core.MOJO_RESULT_OUT_OF_RANGE
+RESULT_UNIMPLEMENTED = c_core.MOJO_RESULT_UNIMPLEMENTED
+RESULT_INTERNAL = c_core.MOJO_RESULT_INTERNAL
+RESULT_UNAVAILABLE = c_core.MOJO_RESULT_UNAVAILABLE
+RESULT_DATA_LOSS = c_core.MOJO_RESULT_DATA_LOSS
+RESULT_BUSY = c_core.MOJO_RESULT_BUSY
+RESULT_SHOULD_WAIT = c_core.MOJO_RESULT_SHOULD_WAIT
+DEADLINE_INDEFINITE = c_core.MOJO_DEADLINE_INDEFINITE
+HANDLE_SIGNAL_NONE = c_core.MOJO_HANDLE_SIGNAL_NONE
+HANDLE_SIGNAL_READABLE = c_core.MOJO_HANDLE_SIGNAL_READABLE
+HANDLE_SIGNAL_WRITABLE = c_core.MOJO_HANDLE_SIGNAL_WRITABLE
+WRITE_MESSAGE_FLAG_NONE = c_core.MOJO_WRITE_MESSAGE_FLAG_NONE
+READ_MESSAGE_FLAG_NONE = c_core.MOJO_READ_MESSAGE_FLAG_NONE
+READ_MESSAGE_FLAG_MAY_DISCARD = c_core.MOJO_READ_MESSAGE_FLAG_MAY_DISCARD
+WRITE_DATA_FLAG_NONE = c_core.MOJO_WRITE_DATA_FLAG_NONE
+WRITE_DATA_FLAG_ALL_OR_NONE = c_core.MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
+READ_DATA_FLAG_NONE = c_core.MOJO_READ_DATA_FLAG_NONE
+READ_DATA_FLAG_ALL_OR_NONE = c_core.MOJO_READ_DATA_FLAG_ALL_OR_NONE
+READ_DATA_FLAG_DISCARD = c_core.MOJO_READ_DATA_FLAG_DISCARD
+READ_DATA_FLAG_QUERY = c_core.MOJO_READ_DATA_FLAG_QUERY
+MAP_BUFFER_FLAG_NONE = c_core.MOJO_MAP_BUFFER_FLAG_NONE
+
+def GetTimeTicksNow():
+  """Monotonically increasing tick count representing "right now."
+
+  See mojo/public/c/system/functions.h
+  """
+  return c_core.MojoGetTimeTicksNow()
+
+cdef class _ScopedMemory:
+  """Allocate memory at creation, and deallocate it at destruction."""
+  cdef void* memory
+  def __init__(self, size):
+    self.memory = PyMem_Malloc(size)
+
+  def __dealloc__(self):
+    PyMem_Free(self.memory)
+
+cdef class _ScopedBuffer:
+  """Retrieve pointer to a buffer a creation, and release it at destruction.
+  """
+  cdef Py_buffer _buf
+  cdef void* buf
+  cdef Py_ssize_t len
+
+  def __init__(self, obj, flags=PyBUF_CONTIG_RO):
+    if obj:
+      if PyObject_GetBuffer(obj, &self._buf, flags) < 0:
+        raise TypeError('Unable to read buffer.')
+      self.buf = self._buf.buf
+      self.len = self._buf.len
+    else:
+      self.buf = NULL
+      self.len = 0
+
+  def __dealloc__(self):
+    if self.buf:
+      PyBuffer_Release(&self._buf)
+
+def _SliceBuffer(buffer, size):
+  """Slice the given buffer, reducing it to the given size.
+
+  Return None if None is passed in.
+  """
+  if not buffer:
+    return buffer
+  return buffer[:size]
+
+cdef class _NativeMemoryView(object):
+  """Create a python buffer wrapping the given memory.
+
+  Will also retain the given handle until this object is deallocated.
+  """
+  cdef void* _memory
+  cdef uint32_t _size
+  cdef char _read_only
+  cdef char _wrapped
+  cdef object _handle
+
+  def __init__(self, handle):
+    self._handle = handle
+
+  def __cinit__(self):
+    self._memory = NULL
+    self._size = 0
+    self._read_only = True
+    self._wrapped = False
+
+  cdef Wrap(self,
+            const void* memory,
+            uint32_t size,
+            read_only=True):
+    """Makes this buffer wraps the given memory.
+
+    Must be called before using this buffer, and must only be called once.
+    """
+    assert not self._wrapped
+    self._wrapped = True
+    self._memory = <void*>memory
+    self._size = size
+    self._read_only = read_only
+
+  # buffer interface (PEP 3118)
+  def __getbuffer__(self, Py_buffer *view, int flags):
+    assert self._wrapped
+    if view == NULL:
+      return
+    PyBuffer_FillInfo(view,
+                      self,
+                      self._memory,
+                      self._size,
+                      self._read_only,
+                      flags)
+
+  def __releasebuffer__(self, Py_buffer *view):
+    assert self._wrapped
+    pass
+
+  # legacy buffer interface
+  def __getsegcount__(self, Py_ssize_t *sizes):
+    assert self._wrapped
+    if sizes != NULL:
+      sizes[0] = self._size
+    return 1
+
+  def __getreadbuffer__(self, Py_ssize_t index, void **data):
+    assert self._wrapped
+    if index != 0:
+      raise SystemError('Index out of bounds: %d' % index)
+    data[0] = self._memory
+    return self._size
+
+  def __getwritebuffer__(self, Py_ssize_t index, void **data):
+    assert self._wrapped
+    if index != 0:
+      raise SystemError('Index out of bounds: %d' % index)
+    if self._read_only:
+      raise TypeError('Buffer is read-only.')
+    data[0] = self._memory
+    return self._size
+
+class MojoException(Exception):
+  """Exception wrapping a mojo result error code."""
+
+  def __init__(self, mojo_result):
+    self.mojo_result = mojo_result
+
+def WaitMany(handles_and_signals, deadline):
+  """Waits on a list of handles.
+
+  Args:
+    handles_and_signals: list of tuples of handle and signal.
+
+  See mojo/public/c/system/functions.h
+  """
+  cdef uint32_t length = len(handles_and_signals)
+  cdef _ScopedMemory handles_alloc = _ScopedMemory(
+      sizeof(c_core.MojoHandle) * length)
+  cdef _ScopedMemory signals_alloc = _ScopedMemory(
+      sizeof(c_core.MojoHandleSignals) * length)
+  cdef c_core.MojoHandle* handles = <c_core.MojoHandle*>handles_alloc.memory
+  cdef c_core.MojoHandleSignals* signals = (
+      <c_core.MojoHandleSignals*>signals_alloc.memory)
+  cdef int index = 0
+  for (h, s) in handles_and_signals:
+    handles[index] = (<Handle?>h)._mojo_handle
+    signals[index] = s
+    index += 1
+  cdef c_core.MojoResult result = c_core.MOJO_RESULT_OK
+  cdef c_core.MojoDeadline cdeadline = deadline
+  with nogil:
+    result = c_core.MojoWaitMany(handles, signals, length, cdeadline)
+  return result
+
+cdef class DataPipeTwoPhaseBuffer(object):
+  """Return value for two phases read and write.
+
+  The buffer field contains the python buffer where data can be read or written.
+  When done with the buffer, the |end| method must be called with the number of
+  bytes read or written.
+  """
+
+  cdef object _buffer
+  cdef Handle _handle
+  cdef char _read
+
+  def __init__(self, handle, buffer, read=True):
+    self._buffer = buffer
+    self._handle = handle
+    self._read = read
+
+  def End(self, num_bytes):
+    self._buffer = None
+    cdef c_core.MojoResult result
+    if self._read:
+      result = c_core.MojoEndReadData(self._handle._mojo_handle, num_bytes)
+    else:
+      result = c_core.MojoEndWriteData(self._handle._mojo_handle, num_bytes)
+    self._handle = None
+    return result
+
+  @property
+  def buffer(self):
+    return self._buffer
+
+  def __dealloc__(self):
+    assert not self._buffer
+
+cdef class MappedBuffer(object):
+  """Return value for the |map| operation on shared buffer handles.
+
+  The buffer field contains the python buffer where data can be read or written.
+  When done with the buffer, the |unmap| method must be called.
+  """
+
+  cdef object _buffer
+  cdef object _handle
+  cdef object _cleanup
+
+  def __init__(self, handle, buffer, cleanup):
+    self._buffer = buffer
+    self._handle = handle
+    self._cleanup = cleanup
+
+  def UnMap(self):
+    self._buffer = None
+    cdef c_core.MojoResult result = self._cleanup()
+    self._cleanup = None
+    self._handle = None
+    return result
+
+  @property
+  def buffer(self):
+    return self._buffer
+
+  def __dealloc__(self):
+    if self._buffer:
+      self.UnMap()
+
+cdef class Handle(object):
+  """A mojo object."""
+
+  cdef c_core.MojoHandle _mojo_handle
+
+  def __init__(self, mojo_handle=c_core.MOJO_HANDLE_INVALID):
+    self._mojo_handle = mojo_handle
+
+  def _Invalidate(self):
+    """Invalidate the current handle.
+
+    The close operation is not called. It is the responsability of the caller to
+    ensure that the handle is not leaked.
+    """
+    self._mojo_handle = c_core.MOJO_HANDLE_INVALID
+
+  def IsValid(self):
+    """Returns whether this handle is valid."""
+    return self._mojo_handle != c_core.MOJO_HANDLE_INVALID
+
+  def Close(self):
+    """Closes this handle.
+
+    See mojo/public/c/system/functions.h
+    """
+    cdef c_core.MojoResult result = c_core.MOJO_RESULT_OK
+    if self.IsValid():
+      result = c_core.MojoClose(self._mojo_handle)
+      self._Invalidate()
+    return result
+
+  def __dealloc__(self):
+    self.Close()
+
+  def Wait(self, signals, deadline):
+    """Waits on the given handle.
+
+    See mojo/public/c/system/functions.h
+    """
+    cdef c_core.MojoHandle handle = self._mojo_handle
+    cdef c_core.MojoHandleSignals csignals = signals
+    cdef c_core.MojoDeadline cdeadline = deadline
+    cdef c_core.MojoResult result
+    with nogil:
+      result = c_core.MojoWait(handle, csignals, cdeadline)
+    return result
+
+  def AsyncWait(self, signals, deadline, callback):
+    cdef c_core.MojoHandle handle = self._mojo_handle
+    cdef c_core.MojoHandleSignals csignals = signals
+    cdef c_core.MojoDeadline cdeadline = deadline
+    cdef c_environment.MojoAsyncWaitID wait_id = _ASYNC_WAITER.AsyncWait(
+        handle,
+        csignals,
+        cdeadline,
+        callback)
+    def cancel():
+      _ASYNC_WAITER.CancelWait(wait_id)
+    return cancel
+
+  def WriteMessage(self,
+                    buffer=None,
+                    handles=None,
+                    flags=WRITE_MESSAGE_FLAG_NONE):
+    """Writes a message to the message pipe.
+
+    This method can only be used on a handle obtained from |MessagePipe()|.
+
+    See mojo/public/c/system/message_pipe.h
+    """
+    cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
+    cdef uint32_t input_buffer_length = buffer_as_buffer.len
+    cdef c_core.MojoHandle* input_handles = NULL
+    cdef uint32_t input_handles_length = 0
+    cdef _ScopedMemory handles_alloc = None
+    if handles:
+      input_handles_length = len(handles)
+      handles_alloc = _ScopedMemory(sizeof(c_core.MojoHandle) *
+                                    input_handles_length)
+      input_handles = <c_core.MojoHandle*>handles_alloc.memory
+      for i in xrange(input_handles_length):
+        input_handles[i] = (<Handle?>handles[i])._mojo_handle
+    cdef c_core.MojoResult res = c_core.MojoWriteMessage(self._mojo_handle,
+                                                         buffer_as_buffer.buf,
+                                                         input_buffer_length,
+                                                         input_handles,
+                                                         input_handles_length,
+                                                         flags)
+    if res == c_core.MOJO_RESULT_OK and handles:
+      # Handles have been transferred. Let's invalidate those.
+      for handle in handles:
+        handle._Invalidate()
+    return res
+
+  def ReadMessage(self,
+                   buffer=None,
+                   max_number_of_handles=0,
+                   flags=READ_MESSAGE_FLAG_NONE):
+    """Reads a message from the message pipe.
+
+    This method can only be used on a handle obtained from |MessagePipe()|.
+
+    This method returns a triplet of value (code, data, sizes):
+    - if code is RESULT_OK, sizes will be None, and data will be a pair of
+      (buffer, handles) where buffer is a view of the input buffer with the read
+      data, and handles is a list of received handles.
+    - if code is RESULT_RESOURCE_EXHAUSTED, data will be None and sizes will be
+      a pair of (buffer_size, handles_size) where buffer_size is the size of the
+      next message data and handles_size is the number of handles in the next
+      message.
+    - if code is any other value, data and sizes will be None.
+
+    See mojo/public/c/system/message_pipe.h
+    """
+    cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer, PyBUF_CONTIG)
+    cdef uint32_t input_buffer_length = buffer_as_buffer.len
+    cdef c_core.MojoHandle* input_handles = NULL
+    cdef uint32_t input_handles_length = 0
+    cdef _ScopedMemory handles_alloc = None
+    if max_number_of_handles > 0:
+      input_handles_length = max_number_of_handles
+      handles_alloc = _ScopedMemory(sizeof(c_core.MojoHandle) *
+                                    input_handles_length)
+      input_handles = <c_core.MojoHandle*>handles_alloc.memory
+    cdef res = c_core.MojoReadMessage(self._mojo_handle,
+                                      buffer_as_buffer.buf,
+                                      &input_buffer_length,
+                                      input_handles,
+                                      &input_handles_length,
+                                      flags)
+    if res == c_core.MOJO_RESULT_RESOURCE_EXHAUSTED:
+      return (res, None, (input_buffer_length, input_handles_length))
+    if res == c_core.MOJO_RESULT_OK:
+      returned_handles = [Handle(input_handles[i])
+                          for i in xrange(input_handles_length)]
+      return (res,
+              (_SliceBuffer(buffer, input_buffer_length), returned_handles),
+              None)
+    return (res, None, None)
+
+  def WriteData(self, buffer=None, flags=WRITE_DATA_FLAG_NONE):
+    """
+    Writes the given data to the data pipe producer.
+
+    This method can only be used on a producer handle obtained from
+    |DataPipe()|.
+
+    This method returns a tuple (code, num_bytes).
+    - If code is RESULT_OK, num_bytes is the number of written bytes.
+    - Otherwise, num_bytes is None.
+
+    See mojo/public/c/system/data_pipe.h
+    """
+    cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
+    cdef uint32_t input_buffer_length = buffer_as_buffer.len
+    cdef c_core.MojoResult res = c_core.MojoWriteData(self._mojo_handle,
+                                                      buffer_as_buffer.buf,
+                                                      &input_buffer_length,
+                                                      flags)
+    if res == c_core.MOJO_RESULT_OK:
+      return (res, input_buffer_length)
+    return (res, None)
+
+  def BeginWriteData(self,
+                       min_size=None,
+                       flags=WRITE_DATA_FLAG_NONE):
+    """
+    Begins a two-phase write to the data pipe producer.
+
+    This method can only be used on a producer handle obtained from
+    |DataPipe()|.
+
+    This method returns a tuple (code, two_phase_buffer).
+    - If code is RESULT_OK, two_phase_buffer is a writable
+      DataPipeTwoPhaseBuffer
+    - Otherwise, two_phase_buffer is None.
+
+    See mojo/public/c/system/data_pipe.h
+    """
+    cdef void* out_buffer
+    cdef uint32_t out_size = 0
+    if min_size:
+      flags |= c_core.MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
+      out_size = min_size
+    cdef c_core.MojoResult res = c_core.MojoBeginWriteData(self._mojo_handle,
+                                                           &out_buffer,
+                                                           &out_size,
+                                                           flags)
+    if res != c_core.MOJO_RESULT_OK:
+      return (res, None)
+    cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
+    view_buffer.Wrap(out_buffer, out_size, read_only=False)
+    return (res, DataPipeTwoPhaseBuffer(self, memoryview(view_buffer), False))
+
+  def ReadData(self, buffer=None, flags=READ_DATA_FLAG_NONE):
+    """Reads data from the data pipe consumer.
+
+    This method can only be used on a consumer handle obtained from
+    |DataPipe()|.
+
+    This method returns a tuple (code, buffer)
+    - if code is RESULT_OK, buffer will be a view of the input buffer with the
+      read data.
+    - otherwise, buffer will be None.
+
+    See mojo/public/c/system/data_pipe.h
+    """
+    cdef _ScopedBuffer buffer_as_buffer = _ScopedBuffer(buffer)
+    cdef uint32_t input_buffer_length = buffer_as_buffer.len
+    cdef c_core.MojoResult res = c_core.MojoReadData(self._mojo_handle,
+                                                     buffer_as_buffer.buf,
+                                                     &input_buffer_length,
+                                                     flags)
+    if res == c_core.MOJO_RESULT_OK:
+      return (res, _SliceBuffer(buffer, input_buffer_length))
+    return (res, None)
+
+  def QueryData(self, flags=READ_DATA_FLAG_NONE):
+    """Queries the amount of data available on the data pipe consumer.
+
+    This method can only be used on a consumer handle obtained from
+    |DataPipe()|.
+
+    This method returns a tuple (code, num_bytes)
+    - if code is RESULT_OK, num_bytes will be the number of bytes available on
+      the data pipe consumer.
+    - otherwise, num_bytes will be None.
+
+    See mojo/public/c/system/data_pipe.h
+    """
+    cdef uint32_t num_bytes = 0
+    cdef c_core.MojoResult res = c_core.MojoReadData(
+        self._mojo_handle,
+        NULL,
+        &num_bytes,
+        flags|c_core.MOJO_READ_DATA_FLAG_QUERY)
+    return (res, num_bytes)
+
+  def BeginReadData(self, min_size=None, flags=READ_DATA_FLAG_NONE):
+    """
+    Begins a two-phase read to the data pipe consumer.
+
+    This method can only be used on a consumer handle obtained from
+    |DataPipe()|.
+
+    This method returns a tuple (code, two_phase_buffer).
+    - If code is RESULT_OK, two_phase_buffer is a readable
+      DataPipeTwoPhaseBuffer
+    - Otherwise, two_phase_buffer is None.
+
+    See mojo/public/c/system/data_pipe.h
+    """
+    cdef const void* out_buffer
+    cdef uint32_t out_size = 0
+    if min_size:
+      flags |= c_core.MOJO_READ_DATA_FLAG_ALL_OR_NONE
+      out_size = min_size
+    cdef c_core.MojoResult res = c_core.MojoBeginReadData(self._mojo_handle,
+                                                          &out_buffer,
+                                                          &out_size,
+                                                          flags)
+    if res != c_core.MOJO_RESULT_OK:
+      return (res, None)
+    cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
+    view_buffer.Wrap(out_buffer, out_size, read_only=True)
+    return (res, DataPipeTwoPhaseBuffer(self, memoryview(view_buffer), True))
+
+  def Duplicate(self, options=None):
+    """Duplicate the shared buffer handle.
+
+    This method can only be used on a handle obtained from
+    |CreateSharedBuffer()| or |Duplicate()|.
+
+    See mojo/public/c/system/buffer.h
+    """
+    cdef c_core.MojoDuplicateBufferHandleOptions coptions
+    cdef c_core.MojoDuplicateBufferHandleOptions* coptions_ptr = NULL
+    cdef c_core.MojoHandle cnew_handle = c_core.MOJO_HANDLE_INVALID
+    if options:
+      coptions.struct_size = sizeof(c_core.MojoDuplicateBufferHandleOptions)
+      coptions.flags = options.flags
+      coptions_ptr = &coptions
+    cdef c_core.MojoResult result = c_core.MojoDuplicateBufferHandle(
+        self._mojo_handle, coptions_ptr, &cnew_handle)
+    new_handle = Handle(cnew_handle)
+    if result != c_core.MOJO_RESULT_OK:
+      raise MojoException(result)
+    return new_handle
+
+  def Map(self, offset, num_bytes, flags=MAP_BUFFER_FLAG_NONE):
+    """Maps the part (at offset |offset| of length |num_bytes|) of the buffer.
+
+    This method can only be used on a handle obtained from
+    |CreateSharedBuffer()| or |Duplicate()|.
+
+    This method returns a tuple (code, mapped_buffer).
+    - If code is RESULT_OK, mapped_buffer is a readable/writable
+      MappedBuffer
+    - Otherwise, mapped_buffer is None.
+
+    See mojo/public/c/system/buffer.h
+    """
+    cdef void* buffer
+    res = c_core.MojoMapBuffer(self._mojo_handle,
+                               offset,
+                               num_bytes,
+                               &buffer,
+                               flags)
+    if res != c_core.MOJO_RESULT_OK:
+      return (res, None)
+    cdef _NativeMemoryView view_buffer = _NativeMemoryView(self)
+    view_buffer.Wrap(buffer, num_bytes, read_only=False)
+    return (res, MappedBuffer(self,
+                              memoryview(view_buffer),
+                              lambda: c_core.MojoUnmapBuffer(buffer)))
+
+class CreateMessagePipeOptions(object):
+  """Options for creating a message pipe.
+
+  See mojo/public/c/system/message_pipe.h
+  """
+  FLAG_NONE = c_core.MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE
+
+  def __init__(self):
+    self.flags = CreateMessagePipeOptions.FLAG_NONE
+
+class MessagePipe(object):
+  """Creates a message pipe.
+
+  The two ends of the message pipe are accessible with the members handle0 and
+  handle1.
+
+  See mojo/public/c/system/message_pipe.h
+  """
+  def __init__(self, options=None):
+    cdef c_core.MojoCreateMessagePipeOptions coptions
+    cdef c_core.MojoCreateMessagePipeOptions* coptions_ptr = NULL
+    cdef c_core.MojoHandle chandle0 = c_core.MOJO_HANDLE_INVALID
+    cdef c_core.MojoHandle chandle1 = c_core.MOJO_HANDLE_INVALID
+    if options:
+      coptions.struct_size = sizeof(c_core.MojoCreateMessagePipeOptions)
+      coptions.flags = options.flags
+      coptions_ptr = &coptions
+    cdef c_core.MojoResult result = c_core.MojoCreateMessagePipe(coptions_ptr,
+                                                                 &chandle0,
+                                                                 &chandle1)
+    self.handle0 = Handle(chandle0)
+    self.handle1 = Handle(chandle1)
+    if result != c_core.MOJO_RESULT_OK:
+      raise c_core.MojoException(result)
+
+
+class CreateDataPipeOptions(object):
+  """Options for creating a data pipe.
+
+  See mojo/public/c/system/data_pipe.h
+  """
+  FLAG_NONE = c_core.MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
+  FLAG_MAY_DISCARD = c_core.MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD
+
+  def __init__(self):
+    self.flags = CreateDataPipeOptions.FLAG_NONE
+    self.element_num_bytes = 1
+    self.capacity_num_bytes = 0
+
+class DataPipe(object):
+  """Creates a data pipe.
+
+  The producer end of the data pipe is accessible with the member
+  producer_handle and the consumer end of the data pipe is accessible with the
+  member cconsumer_handle.
+
+  See mojo/public/c/system/data_pipe.h
+  """
+  def __init__(self, options=None):
+    cdef c_core.MojoCreateDataPipeOptions coptions
+    cdef c_core.MojoCreateDataPipeOptions* coptions_ptr = NULL
+    cdef c_core.MojoHandle cproducer_handle = c_core.MOJO_HANDLE_INVALID
+    cdef c_core.MojoHandle cconsumer_handle = c_core.MOJO_HANDLE_INVALID
+    if options:
+      coptions.struct_size = sizeof(c_core.MojoCreateDataPipeOptions)
+      coptions.flags = options.flags
+      coptions.element_num_bytes = options.element_num_bytes
+      coptions.capacity_num_bytes = options.capacity_num_bytes
+      coptions_ptr = &coptions
+    cdef c_core.MojoResult result = c_core.MojoCreateDataPipe(coptions_ptr,
+                                                              &cproducer_handle,
+                                                              &cconsumer_handle)
+    self.producer_handle = Handle(cproducer_handle)
+    self.consumer_handle = Handle(cconsumer_handle)
+    if result != c_core.MOJO_RESULT_OK:
+      raise MojoException(result)
+
+class CreateSharedBufferOptions(object):
+  """Options for creating a shared buffer.
+
+  See mojo/public/c/system/buffer.h
+  """
+  FLAG_NONE = c_core.MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE
+
+  def __init__(self):
+    self.flags = CreateSharedBufferOptions.FLAG_NONE
+
+def CreateSharedBuffer(num_bytes, options=None):
+  """Creates a buffer of size |num_bytes| bytes that can be shared.
+
+  See mojo/public/c/system/buffer.h
+  """
+  cdef c_core.MojoCreateSharedBufferOptions coptions
+  cdef c_core.MojoCreateSharedBufferOptions* coptions_ptr = NULL
+  cdef c_core.MojoHandle chandle = c_core.MOJO_HANDLE_INVALID
+  if options:
+    coptions.struct_size = sizeof(c_core.MojoCreateSharedBufferOptions)
+    coptions.flags = options.flags
+    coptions_ptr = &coptions
+  cdef c_core.MojoResult result = c_core.MojoCreateSharedBuffer(coptions_ptr,
+                                                                num_bytes,
+                                                                &chandle)
+  handle = Handle(chandle)
+  if result != c_core.MOJO_RESULT_OK:
+    raise MojoException(result)
+  return handle
+
+class DuplicateSharedBufferOptions(object):
+  """Options for duplicating a shared buffer.
+
+  See mojo/public/c/system/buffer.h
+  """
+  FLAG_NONE = c_core.MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE
+
+  def __init__(self):
+    self.flags = DuplicateSharedBufferOptions.FLAG_NONE
+
+
+cdef class RunLoop(object):
+  """RunLoop to use when using asynchronous operations on handles."""
+
+  cdef c_environment.CRunLoop c_run_loop
+
+  def Run(self):
+    """Run the runloop until Quit is called."""
+    self.c_run_loop.Run()
+
+  def RunUntilIdle(self):
+    """Run the runloop until Quit is called or no operation is waiting."""
+    self.c_run_loop.RunUntilIdle()
+
+  def Quit(self):
+    """Quit the runloop."""
+    self.c_run_loop.Quit()
+
+  def PostDelayedTask(self, runnable, delay=0):
+    """
+    Post a task on the runloop. This must be called from the thread owning the
+    runloop.
+    """
+    cdef c_environment.CClosure closure = c_environment.BuildClosure(runnable)
+    self.c_run_loop.PostDelayedTask(closure, delay)
+
+
+cdef c_environment.CEnvironment* _ENVIRONMENT = new c_environment.CEnvironment()
+cdef c_environment.PythonAsyncWaiter* _ASYNC_WAITER = new c_environment.PythonAsyncWaiter()
diff --git a/mojo/public/python/src/python_system_helper.cc b/mojo/public/python/src/python_system_helper.cc
new file mode 100644
index 0000000..f42e671
--- /dev/null
+++ b/mojo/public/python/src/python_system_helper.cc
@@ -0,0 +1,171 @@
+// Copyright 2014 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/python/src/python_system_helper.h"
+
+#include "Python.h"
+
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/environment/logging.h"
+#include "mojo/public/cpp/system/macros.h"
+#include "mojo/public/cpp/utility/run_loop.h"
+
+namespace {
+
+class ScopedGIL {
+ public:
+  ScopedGIL() { state_ = PyGILState_Ensure(); }
+
+  ~ScopedGIL() { PyGILState_Release(state_); }
+
+ private:
+  PyGILState_STATE state_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedGIL);
+};
+
+class PythonClosure : public mojo::Closure::Runnable {
+ public:
+  PythonClosure(PyObject* callable) : callable_(callable) {
+    MOJO_DCHECK(callable);
+    Py_XINCREF(callable);
+  }
+
+  virtual ~PythonClosure() {
+    ScopedGIL acquire_gil;
+    Py_DECREF(callable_);
+  }
+
+  virtual void Run() const override {
+    ScopedGIL acquire_gil;
+    PyObject* empty_tuple = PyTuple_New(0);
+    if (!empty_tuple) {
+      mojo::RunLoop::current()->Quit();
+      return;
+    }
+
+    PyObject* result = PyObject_CallObject(callable_, empty_tuple);
+    Py_DECREF(empty_tuple);
+    if (result) {
+      Py_DECREF(result);
+    } else {
+      mojo::RunLoop::current()->Quit();
+      return;
+    }
+  }
+
+ private:
+  PyObject* callable_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(PythonClosure);
+};
+
+void AsyncCallbackForwarder(void* closure, MojoResult result) {
+  mojo::Callback<void(MojoResult)>* callback =
+      static_cast<mojo::Callback<void(MojoResult)>*>(closure);
+  // callback will be deleted when it is run.
+  callback->Run(result);
+}
+
+}  // namespace
+
+namespace mojo {
+namespace python {
+
+class PythonAsyncWaiter::AsyncWaiterRunnable
+    : public mojo::Callback<void(MojoResult)>::Runnable {
+ public:
+  AsyncWaiterRunnable(PyObject* callable, CallbackMap* callbacks)
+      : wait_id_(0), callable_(callable), callbacks_(callbacks) {
+    MOJO_DCHECK(callable);
+    MOJO_DCHECK(callbacks_);
+    Py_XINCREF(callable);
+  }
+
+  virtual ~AsyncWaiterRunnable() {
+    ScopedGIL acquire_gil;
+    Py_DECREF(callable_);
+  }
+
+  void set_wait_id(int wait_id) { wait_id_ = wait_id; }
+
+  virtual void Run(MojoResult mojo_result) const override {
+    MOJO_DCHECK(wait_id_);
+
+    // Remove to reference to this object from PythonAsyncWaiter and ensure this
+    // object will be destroyed when this method exits.
+    MOJO_DCHECK(callbacks_->find(wait_id_) != callbacks_->end());
+    internal::SharedPtr<mojo::Callback<void(MojoResult)> > self =
+        (*callbacks_)[wait_id_];
+    callbacks_->erase(wait_id_);
+
+    ScopedGIL acquire_gil;
+    PyObject* args_tuple = Py_BuildValue("(i)", mojo_result);
+    if (!args_tuple) {
+      mojo::RunLoop::current()->Quit();
+      return;
+    }
+
+    PyObject* result = PyObject_CallObject(callable_, args_tuple);
+    Py_DECREF(args_tuple);
+    if (result) {
+      Py_DECREF(result);
+    } else {
+      mojo::RunLoop::current()->Quit();
+      return;
+    }
+  }
+
+ private:
+  MojoAsyncWaitID wait_id_;
+  PyObject* callable_;
+  CallbackMap* callbacks_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(AsyncWaiterRunnable);
+};
+
+Closure BuildClosure(PyObject* callable) {
+  if (!PyCallable_Check(callable))
+    return Closure();
+
+  return Closure(
+      static_cast<mojo::Closure::Runnable*>(new PythonClosure(callable)));
+}
+
+PythonAsyncWaiter::PythonAsyncWaiter() {
+  async_waiter_ = Environment::GetDefaultAsyncWaiter();
+}
+
+PythonAsyncWaiter::~PythonAsyncWaiter() {
+  for (CallbackMap::const_iterator it = callbacks_.begin();
+       it != callbacks_.end();
+       ++it) {
+    async_waiter_->CancelWait(it->first);
+  }
+}
+
+MojoAsyncWaitID PythonAsyncWaiter::AsyncWait(MojoHandle handle,
+                                             MojoHandleSignals signals,
+                                             MojoDeadline deadline,
+                                             PyObject* callable) {
+  AsyncWaiterRunnable* runner = new AsyncWaiterRunnable(callable, &callbacks_);
+  internal::SharedPtr<mojo::Callback<void(MojoResult)> > callback(
+      new mojo::Callback<void(MojoResult)>(
+          static_cast<mojo::Callback<void(MojoResult)>::Runnable*>(runner)));
+  MojoAsyncWaitID wait_id = async_waiter_->AsyncWait(
+      handle, signals, deadline, &AsyncCallbackForwarder, callback.get());
+  callbacks_[wait_id] = callback;
+  runner->set_wait_id(wait_id);
+  return wait_id;
+}
+
+void PythonAsyncWaiter::CancelWait(MojoAsyncWaitID wait_id) {
+  if (callbacks_.find(wait_id) != callbacks_.end()) {
+    async_waiter_->CancelWait(wait_id);
+    callbacks_.erase(wait_id);
+  }
+}
+
+}  // namespace python
+}  // namespace mojo
diff --git a/mojo/public/python/src/python_system_helper.h b/mojo/public/python/src/python_system_helper.h
new file mode 100644
index 0000000..e0d83ca
--- /dev/null
+++ b/mojo/public/python/src/python_system_helper.h
@@ -0,0 +1,50 @@
+// Copyright 2014 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_PYTHON_SRC_PYTHON_SYSTEM_HELPER_H_
+#define MOJO_PUBLIC_PYTHON_SRC_PYTHON_SYSTEM_HELPER_H_
+
+// Python must be the first include, as it defines preprocessor variable without
+// checking if they already exist.
+#include <Python.h>
+
+#include <map>
+
+#include "mojo/public/c/environment/async_waiter.h"
+#include "mojo/public/c/system/types.h"
+#include "mojo/public/cpp/bindings/callback.h"
+#include "mojo/public/cpp/bindings/lib/shared_ptr.h"
+
+namespace mojo {
+namespace python {
+
+// Create a mojo::Closure from a callable python object.
+mojo::Closure BuildClosure(PyObject* callable);
+
+class PythonAsyncWaiter {
+ public:
+  PythonAsyncWaiter();
+  ~PythonAsyncWaiter();
+  MojoAsyncWaitID AsyncWait(MojoHandle handle,
+                            MojoHandleSignals signals,
+                            MojoDeadline deadline,
+                            PyObject* callable);
+
+  void CancelWait(MojoAsyncWaitID wait_id);
+
+ private:
+  class AsyncWaiterRunnable;
+
+  typedef std::map<MojoAsyncWaitID,
+                   internal::SharedPtr<mojo::Callback<void(MojoResult)> > >
+      CallbackMap;
+
+  CallbackMap callbacks_;
+  const MojoAsyncWaiter* async_waiter_;
+};
+
+}  // namespace python
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_PYTHON_SRC_PYTHON_SYSTEM_HELPER_H_
diff --git a/mojo/public/tests/DEPS b/mojo/public/tests/DEPS
new file mode 100644
index 0000000..0669117
--- /dev/null
+++ b/mojo/public/tests/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+mojo",
+]
diff --git a/mojo/public/tests/test_support_private.cc b/mojo/public/tests/test_support_private.cc
new file mode 100644
index 0000000..fa5ead4
--- /dev/null
+++ b/mojo/public/tests/test_support_private.cc
@@ -0,0 +1,69 @@
+// Copyright 2014 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/tests/test_support_private.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static mojo::test::TestSupport* g_test_support = NULL;
+
+extern "C" {
+
+void MojoTestSupportLogPerfResult(const char* test_name,
+                                  double value,
+                                  const char* units) {
+  if (g_test_support)
+    g_test_support->LogPerfResult(test_name, value, units);
+  else
+    printf("[no test runner]\t%s\t%g\t%s\n", test_name, value, units);
+}
+
+FILE* MojoTestSupportOpenSourceRootRelativeFile(const char* relative_path) {
+  if (g_test_support)
+    return g_test_support->OpenSourceRootRelativeFile(relative_path);
+  printf("[no test runner]\n");
+  return NULL;
+}
+
+char** MojoTestSupportEnumerateSourceRootRelativeDirectory(
+    const char* relative_path) {
+  if (g_test_support)
+    return g_test_support->EnumerateSourceRootRelativeDirectory(relative_path);
+
+  printf("[no test runner]\n");
+
+  // Return empty list:
+  char** rv = static_cast<char**>(calloc(1, sizeof(char*)));
+  rv[0] = NULL;
+  return rv;
+}
+
+}  // extern "C"
+
+namespace mojo {
+namespace test {
+
+TestSupport::~TestSupport() {
+}
+
+// static
+void TestSupport::Init(TestSupport* test_support) {
+  assert(!g_test_support);
+  g_test_support = test_support;
+}
+
+// static
+TestSupport* TestSupport::Get() {
+  return g_test_support;
+}
+
+// static
+void TestSupport::Reset() {
+  g_test_support = NULL;
+}
+
+}  // namespace test
+}  // namespace mojo
diff --git a/mojo/public/tests/test_support_private.h b/mojo/public/tests/test_support_private.h
new file mode 100644
index 0000000..29983ca
--- /dev/null
+++ b/mojo/public/tests/test_support_private.h
@@ -0,0 +1,36 @@
+// Copyright 2014 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_TESTS_TEST_SUPPORT_PRIVATE_H_
+#define MOJO_PUBLIC_TESTS_TEST_SUPPORT_PRIVATE_H_
+
+#include <stdio.h>
+
+#include "mojo/public/c/test_support/test_support.h"
+
+namespace mojo {
+namespace test {
+
+// Implementors of the test support APIs can use this interface to install their
+// implementation into the mojo_test_support dynamic library.
+class MOJO_TEST_SUPPORT_EXPORT TestSupport {
+ public:
+  virtual ~TestSupport();
+
+  static void Init(TestSupport* test_support);
+  static TestSupport* Get();
+  static void Reset();
+
+  virtual void LogPerfResult(const char* test_name,
+                             double value,
+                             const char* units) = 0;
+  virtual FILE* OpenSourceRootRelativeFile(const char* relative_path) = 0;
+  virtual char** EnumerateSourceRootRelativeDirectory(
+      const char* relative_path) = 0;
+};
+
+}  // namespace test
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_TESTS_TEST_SUPPORT_PRIVATE_H_
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/enum_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/enum_declaration.tmpl
new file mode 100644
index 0000000..86c85d7
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/enum_declaration.tmpl
@@ -0,0 +1,9 @@
+enum {{enum.name}} {
+{%- for field in enum.fields %}
+{%-    if field.value %}
+  {{enum.name|to_all_caps}}_{{field.name}} = {{field.value|expression_to_text}},
+{%-    else %}
+  {{enum.name|to_all_caps}}_{{field.name}},
+{%-    endif %}
+{%- endfor %}
+};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl
new file mode 100644
index 0000000..30d20d8
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl
@@ -0,0 +1,49 @@
+{%- import "interface_macros.tmpl" as interface_macros %}
+class {{interface.name}}Proxy;
+class {{interface.name}}Stub;
+
+class {{interface.name}}RequestValidator;
+{%- if interface|has_callbacks %}
+class {{interface.name}}ResponseValidator;
+{%- endif %}
+{% if interface.client %}
+class {{interface.client}};
+{% endif %}
+
+class {{interface.name}} {
+ public:
+  static const char* Name_;
+
+  typedef {{interface.name}}Proxy Proxy_;
+  typedef {{interface.name}}Stub Stub_;
+
+  typedef {{interface.name}}RequestValidator RequestValidator_;
+{%- if interface|has_callbacks %}
+  typedef {{interface.name}}ResponseValidator ResponseValidator_;
+{%- else %}
+  typedef mojo::PassThroughFilter ResponseValidator_;
+{%- endif %}
+{% if interface.client %}
+  typedef {{interface.client}} Client;
+{% else %}
+  typedef mojo::NoInterface Client;
+{% endif %}
+
+{#--- Constants #}
+{%- for constant in interface.constants %}
+  static const {{constant.kind|cpp_pod_type}} {{constant.name}};
+{%- endfor %}
+
+{#--- Enums #}
+{%- for enum in interface.enums %}
+{%    macro enum_def() %}{% include "enum_declaration.tmpl" %}{% endmacro %}
+  {{enum_def()|indent(2)}}
+{%- endfor %}
+
+{#--- Methods #}
+  virtual ~{{interface.name}}() {}
+
+{%- for method in interface.methods %}
+  virtual void {{method.name}}({{interface_macros.declare_request_params("", method)}}) = 0;
+{%- endfor %}
+};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
new file mode 100644
index 0000000..bb5b777
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
@@ -0,0 +1,334 @@
+{%- import "interface_macros.tmpl" as interface_macros %}
+{%- set class_name = interface.name %}
+{%- set proxy_name = interface.name ~ "Proxy" %}
+{%- set namespace_as_string = "%s"|format(namespace|replace(".","::")) %}
+
+{%- macro alloc_params(parameters) %}
+{%-   for param in parameters %}
+{%-     if param.kind|is_object_kind  %}
+{{param.kind|cpp_result_type}} p{{loop.index}};
+Deserialize_(params->{{param.name}}.ptr, &p{{loop.index}});
+{%      endif -%}
+{%-   endfor %}
+{%- endmacro %}
+
+{%- macro pass_params(parameters) %}
+{%-   for param in parameters %}
+{%-     if param.kind|is_string_kind -%}
+p{{loop.index}}
+{%-     elif param.kind|is_object_kind -%}
+p{{loop.index}}.Pass()
+{%-     elif param.kind|is_interface_kind -%}
+mojo::MakeProxy<{{param.kind|get_name_for_kind}}>(mojo::MakeScopedHandle(mojo::internal::FetchAndReset(&params->{{param.name}})))
+{%-     elif param.kind|is_interface_request_kind -%}
+mojo::MakeRequest<{{param.kind.kind|get_name_for_kind}}>(mojo::MakeScopedHandle(mojo::internal::FetchAndReset(&params->{{param.name}})))
+{%-     elif param.kind|is_any_handle_kind -%}
+mojo::MakeScopedHandle(mojo::internal::FetchAndReset(&params->{{param.name}}))
+{%-     elif param.kind|is_enum_kind -%}
+static_cast<{{param.kind|cpp_wrapper_type}}>(params->{{param.name}})
+{%-     else -%}
+params->{{param.name}}
+{%-     endif -%}
+{%-     if not loop.last %}, {% endif %}
+{%-   endfor %}
+{%- endmacro %}
+
+{%- macro compute_payload_size(params_name, parameters) -%}
+  size_t payload_size =
+      mojo::internal::Align(sizeof({{params_name}}));
+{#--- Computes #}
+{%-   for param in parameters %}
+{%-     if param.kind|is_object_kind %}
+  payload_size += GetSerializedSize_(in_{{param.name}});
+{%-     endif %}
+{%-   endfor %}
+{%- endmacro %}
+
+{%- macro build_message(params_name, parameters, params_description) -%}
+  {# TODO(yzshen): Consider refactoring to share code with
+     struct_serialization_definition.tmpl #}
+  {{params_name}}* params =
+      {{params_name}}::New(builder.buffer());
+{#--- Sets #}
+{%   for param in parameters %}
+{%-     if param.kind|is_object_kind %}
+{%-       if param.kind|is_any_array_kind %}
+  mojo::SerializeArray_<{{param.kind|get_array_validate_params|indent(24)}}>(
+      mojo::internal::Forward(in_{{param.name}}), builder.buffer(), &params->{{param.name}}.ptr);
+{%-       else %}
+  Serialize_(mojo::internal::Forward(in_{{param.name}}), builder.buffer(), &params->{{param.name}}.ptr);
+{%-       endif %}
+{%-       if not param.kind|is_nullable_kind %}
+  MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
+      !params->{{param.name}}.ptr,
+      mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
+      "null {{param.name}} argument in {{params_description}}");
+{%-       endif %}
+{%-     elif param.kind|is_any_handle_kind %}
+{%-       if param.kind|is_interface_kind or
+             param.kind|is_interface_request_kind %}
+  // Delegate handle.
+  params->{{param.name}} = in_{{param.name}}.PassMessagePipe().release();
+{%-       else %}
+  params->{{param.name}} = in_{{param.name}}.release();
+{%-       endif %}
+{%-       if not param.kind|is_nullable_kind %}
+  MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
+      !params->{{param.name}}.is_valid(),
+      mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
+      "invalid {{param.name}} argument in {{params_description}}");
+{%-       endif %}
+{%-     else %}
+  params->{{param.name}} = in_{{param.name}};
+{%-     endif %}
+{%-   endfor %}
+  mojo::Message message;
+  params->EncodePointersAndHandles(message.mutable_handles());
+  builder.Finish(&message);
+{%- endmacro %}
+
+{#--- Begin #}
+const char* {{class_name}}::Name_ = "{{namespace_as_string}}::{{class_name}}";
+{#--- Constants #}
+{%  for constant in interface.constants %}
+const {{constant.kind|cpp_pod_type}} {{interface.name}}::{{constant.name}} = {{constant|constant_value}};
+{%- endfor %}
+
+{#--- ForwardToCallback definition #}
+{%- for method in interface.methods -%}
+{%-   if method.response_parameters != None %}
+class {{class_name}}_{{method.name}}_ForwardToCallback
+    : public mojo::MessageReceiver {
+ public:
+  {{class_name}}_{{method.name}}_ForwardToCallback(
+      const {{interface_macros.declare_callback(method)}}& callback)
+      : callback_(callback) {
+  }
+  virtual bool Accept(mojo::Message* message) override;
+ private:
+  {{interface_macros.declare_callback(method)}} callback_;
+  MOJO_DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ForwardToCallback);
+};
+bool {{class_name}}_{{method.name}}_ForwardToCallback::Accept(
+    mojo::Message* message) {
+  internal::{{class_name}}_{{method.name}}_ResponseParams_Data* params =
+      reinterpret_cast<internal::{{class_name}}_{{method.name}}_ResponseParams_Data*>(
+          message->mutable_payload());
+
+  params->DecodePointersAndHandles(message->mutable_handles());
+  {{alloc_params(method.response_parameters)|indent(2)}}
+  callback_.Run({{pass_params(method.response_parameters)}});
+  return true;
+}
+{%-   endif %}
+{%- endfor %}
+
+{{proxy_name}}::{{proxy_name}}(mojo::MessageReceiverWithResponder* receiver)
+    : receiver_(receiver) {
+}
+
+{#--- Proxy definitions #}
+
+{%- for method in interface.methods %}
+{%-   set message_name =
+          "internal::k%s_%s_Name"|format(interface.name, method.name) %}
+{%-   set params_name =
+          "internal::%s_%s_Params_Data"|format(interface.name, method.name) %}
+{%-   set params_description =
+          "%s.%s request"|format(interface.name, method.name) %}
+void {{proxy_name}}::{{method.name}}(
+    {{interface_macros.declare_request_params("in_", method)}}) {
+  {{compute_payload_size(params_name, method.parameters)}}
+
+{%- if method.response_parameters != None %}
+  mojo::internal::RequestMessageBuilder builder({{message_name}}, payload_size);
+{%- else %}
+  mojo::internal::MessageBuilder builder({{message_name}}, payload_size);
+{%- endif %}
+
+  {{build_message(params_name, method.parameters, params_description)}}
+
+{%- if method.response_parameters != None %}
+  mojo::MessageReceiver* responder =
+      new {{class_name}}_{{method.name}}_ForwardToCallback(callback);
+  if (!receiver_->AcceptWithResponder(&message, responder))
+    delete responder;
+{%- else %}
+  bool ok MOJO_ALLOW_UNUSED = receiver_->Accept(&message);
+  // This return value may be ignored as !ok implies the Connector has
+  // encountered an error, which will be visible through other means.
+{%- endif %}
+}
+{%- endfor %}
+
+{#--- ProxyToResponder definition #}
+{%- for method in interface.methods -%}
+{%-   if method.response_parameters != None %}
+{%-     set message_name =
+            "internal::k%s_%s_Name"|format(interface.name, method.name) %}
+{%-     set params_name =
+            "internal::%s_%s_ResponseParams_Data"|format(interface.name, method.name) %}
+{%-     set params_description =
+            "%s.%s response"|format(interface.name, method.name) %}
+class {{class_name}}_{{method.name}}_ProxyToResponder
+    : public {{interface_macros.declare_callback(method)}}::Runnable {
+ public:
+  virtual ~{{class_name}}_{{method.name}}_ProxyToResponder() {
+    delete responder_;
+  }
+
+  {{class_name}}_{{method.name}}_ProxyToResponder(
+      uint64_t request_id,
+      mojo::MessageReceiver* responder)
+      : request_id_(request_id),
+        responder_(responder) {
+  }
+
+  virtual void Run({{interface_macros.declare_params("in_", method.response_parameters)}}) const override;
+
+ private:
+  uint64_t request_id_;
+  mutable mojo::MessageReceiver* responder_;
+  MOJO_DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ProxyToResponder);
+};
+void {{class_name}}_{{method.name}}_ProxyToResponder::Run(
+    {{interface_macros.declare_params("in_", method.response_parameters)}}) const {
+  {{compute_payload_size(params_name, method.response_parameters)}}
+  mojo::internal::ResponseMessageBuilder builder(
+      {{message_name}}, payload_size, request_id_);
+  {{build_message(params_name, method.response_parameters, params_description)}}
+  bool ok MOJO_ALLOW_UNUSED = responder_->Accept(&message);
+  // TODO(darin): !ok returned here indicates a malformed message, and that may
+  // be good reason to close the connection. However, we don't have a way to do
+  // that from here. We should add a way.
+  delete responder_;
+  responder_ = nullptr;
+}
+{%-   endif -%}
+{%- endfor %}
+
+{{class_name}}Stub::{{class_name}}Stub()
+    : sink_(nullptr) {
+}
+
+{#--- Stub definition #}
+
+bool {{class_name}}Stub::Accept(mojo::Message* message) {
+{%- if interface.methods %}
+  switch (message->header()->name) {
+{%-   for method in interface.methods %}
+    case internal::k{{class_name}}_{{method.name}}_Name: {
+{%-     if method.response_parameters == None %}
+      internal::{{class_name}}_{{method.name}}_Params_Data* params =
+          reinterpret_cast<internal::{{class_name}}_{{method.name}}_Params_Data*>(
+              message->mutable_payload());
+
+      params->DecodePointersAndHandles(message->mutable_handles());
+      {{alloc_params(method.parameters)|indent(6)}}
+      sink_->{{method.name}}({{pass_params(method.parameters)}});
+      return true;
+{%-     else %}
+      break;
+{%-     endif %}
+    }
+{%-   endfor %}
+  }
+{%- endif %}
+  return false;
+}
+
+bool {{class_name}}Stub::AcceptWithResponder(
+    mojo::Message* message, mojo::MessageReceiver* responder) {
+{%- if interface.methods %}
+  switch (message->header()->name) {
+{%-   for method in interface.methods %}
+    case internal::k{{class_name}}_{{method.name}}_Name: {
+{%-     if method.response_parameters != None %}
+      internal::{{class_name}}_{{method.name}}_Params_Data* params =
+          reinterpret_cast<internal::{{class_name}}_{{method.name}}_Params_Data*>(
+              message->mutable_payload());
+
+      params->DecodePointersAndHandles(message->mutable_handles());
+      {{interface_macros.declare_callback(method)}}::Runnable* runnable =
+          new {{class_name}}_{{method.name}}_ProxyToResponder(
+              message->request_id(), responder);
+      {{interface_macros.declare_callback(method)}} callback(runnable);
+      {{alloc_params(method.parameters)|indent(6)}}
+      sink_->{{method.name}}(
+{%- if method.parameters -%}{{pass_params(method.parameters)}}, {% endif -%}callback);
+      return true;
+{%-     else %}
+      break;
+{%-     endif %}
+    }
+{%-   endfor %}
+  }
+{%- endif %}
+  return false;
+}
+
+{#--- Request validator definitions #}
+
+{{class_name}}RequestValidator::{{class_name}}RequestValidator(
+    mojo::MessageReceiver* sink) : MessageFilter(sink) {
+}
+
+bool {{class_name}}RequestValidator::Accept(mojo::Message* message) {
+{%- if interface.methods %}
+  switch (message->header()->name) {
+{%-   for method in interface.methods %}
+    case internal::k{{class_name}}_{{method.name}}_Name: {
+{%-     if method.response_parameters != None %}
+      if (!message->has_flag(mojo::internal::kMessageExpectsResponse))
+        break;
+{%-     else %}
+      if (message->has_flag(mojo::internal::kMessageExpectsResponse) ||
+          message->has_flag(mojo::internal::kMessageIsResponse)) {
+        break;
+      }
+{%-     endif %}
+      mojo::internal::BoundsChecker bounds_checker(
+          message->payload(), message->payload_num_bytes(),
+          message->handles()->size());
+      if (!internal::{{class_name}}_{{method.name}}_Params_Data::Validate(
+              message->payload(), &bounds_checker)) {
+        return false;
+      }
+      break;
+    }
+{%-   endfor %}
+  }
+{%- endif %}
+
+  return sink_->Accept(message);
+}
+
+{#--- Response validator definitions #}
+{% if interface|has_callbacks %}
+{{class_name}}ResponseValidator::{{class_name}}ResponseValidator(
+    mojo::MessageReceiver* sink) : MessageFilter(sink) {
+}
+
+bool {{class_name}}ResponseValidator::Accept(mojo::Message* message) {
+{%- if interface.methods %}
+  switch (message->header()->name) {
+{%-   for method in interface.methods if method.response_parameters != None %}
+    case internal::k{{class_name}}_{{method.name}}_Name: {
+      if (!message->has_flag(mojo::internal::kMessageIsResponse))
+        break;
+      mojo::internal::BoundsChecker bounds_checker(
+          message->payload(), message->payload_num_bytes(),
+          message->handles()->size());
+      if (!internal::{{class_name}}_{{method.name}}_ResponseParams_Data::Validate(
+              message->payload(), &bounds_checker)) {
+        return false;
+      }
+      break;
+    }
+{%-   endfor %}
+  }
+{%- endif %}
+
+  return sink_->Accept(message);
+}
+{%- endif -%}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
new file mode 100644
index 0000000..fbefce2
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
@@ -0,0 +1,23 @@
+{%- macro declare_params(prefix, parameters) %}
+{%-   for param in parameters -%}
+{{param.kind|cpp_const_wrapper_type}} {{prefix}}{{param.name}}
+{%- if not loop.last %}, {% endif %}
+{%-   endfor %}
+{%- endmacro %}
+
+{%- macro declare_callback(method) -%}
+mojo::Callback<void(
+{%-   for param in method.response_parameters -%}
+{{param.kind|cpp_result_type}}
+{%- if not loop.last %}, {% endif %}
+{%-   endfor -%}
+)>
+{%- endmacro -%}
+
+{%- macro declare_request_params(prefix, method) -%}
+{{declare_params(prefix, method.parameters)}}
+{%-   if method.response_parameters != None -%}
+{%- if method.parameters %}, {% endif %}
+const {{declare_callback(method)}}& callback
+{%-   endif -%}
+{%- endmacro -%}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl
new file mode 100644
index 0000000..6b8e7c5
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl
@@ -0,0 +1,14 @@
+{%- import "interface_macros.tmpl" as interface_macros %}
+class {{interface.name}}Proxy : public {{interface.name}} {
+ public:
+  explicit {{interface.name}}Proxy(mojo::MessageReceiverWithResponder* receiver);
+
+{%- for method in interface.methods %}
+  virtual void {{method.name}}(
+      {{interface_macros.declare_request_params("", method)}}
+  ) override;
+{%- endfor %}
+
+ private:
+  mojo::MessageReceiverWithResponder* receiver_;
+};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl
new file mode 100644
index 0000000..2239b69
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl
@@ -0,0 +1,6 @@
+class {{interface.name}}RequestValidator : public mojo::MessageFilter {
+ public:
+  explicit {{interface.name}}RequestValidator(mojo::MessageReceiver* sink = nullptr);
+
+  virtual bool Accept(mojo::Message* message) override;
+};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl
new file mode 100644
index 0000000..801603d
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl
@@ -0,0 +1,6 @@
+class {{interface.name}}ResponseValidator : public mojo::MessageFilter {
+ public:
+  explicit {{interface.name}}ResponseValidator(mojo::MessageReceiver* sink = nullptr);
+
+  virtual bool Accept(mojo::Message* message) override;
+};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl
new file mode 100644
index 0000000..afc6504
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl
@@ -0,0 +1,13 @@
+class {{interface.name}}Stub : public mojo::MessageReceiverWithResponder {
+ public:
+  {{interface.name}}Stub();
+  void set_sink({{interface.name}}* sink) { sink_ = sink; }
+  {{interface.name}}* sink() { return sink_; }
+
+  virtual bool Accept(mojo::Message* message) override;
+  virtual bool AcceptWithResponder(mojo::Message* message,
+                                   mojo::MessageReceiver* responder) override;
+
+ private:
+  {{interface.name}}* sink_;
+};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl
new file mode 100644
index 0000000..f0cf33b
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl
@@ -0,0 +1,49 @@
+// Copyright 2013 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.
+
+{%- set header_guard = "%s_INTERNAL_H_"|
+        format(module.path|upper|replace("/","_")|replace(".","_")) %}
+
+#ifndef {{header_guard}}
+#define {{header_guard}}
+
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/buffer.h"
+
+{%- for import in imports %}
+#include "{{import.module.path}}-internal.h"
+{%- endfor %}
+
+namespace mojo {
+namespace internal {
+class BoundsChecker;
+}
+}
+
+{%- for namespace in namespaces_as_array %}
+namespace {{namespace}} {
+{%- endfor %}
+
+{#--- Wrapper forward declarations #}
+{%  for struct in structs %}
+class {{struct.name}};
+{%- endfor %}
+
+namespace internal {
+
+#pragma pack(push, 1)
+
+{#--- Class declarations #}
+{%  for struct in structs %}
+{%    include "struct_declaration.tmpl" %}
+{%- endfor %}
+
+#pragma pack(pop)
+
+}  // namespace internal
+{%- for namespace in namespaces_as_array|reverse %}
+}  // namespace {{namespace}}
+{%- endfor %}
+
+#endif  // {{header_guard}}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
new file mode 100644
index 0000000..8f5e812
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
@@ -0,0 +1,94 @@
+// Copyright 2013 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.
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-private-field"
+#elif defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4056)
+#pragma warning(disable:4756)
+#endif
+
+#include "{{module.path}}.h"
+
+#include <math.h>
+
+#include "mojo/public/cpp/bindings/lib/array_serialization.h"
+#include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
+#include "mojo/public/cpp/bindings/lib/bounds_checker.h"
+#include "mojo/public/cpp/bindings/lib/message_builder.h"
+#include "mojo/public/cpp/bindings/lib/string_serialization.h"
+#include "mojo/public/cpp/bindings/lib/validation_errors.h"
+
+{%- for namespace in namespaces_as_array %}
+namespace {{namespace}} {
+{%- endfor %}
+
+{#--- Constants #}
+{%  for constant in module.constants %}
+const {{constant.kind|cpp_pod_type}} {{constant.name}} = {{constant|constant_value}};
+{%- endfor %}
+
+namespace internal {
+namespace {
+
+#pragma pack(push, 1)
+
+{#--- Interface parameter definitions #}
+{%- for interface in interfaces %}
+{%-   for method in interface.methods %}
+{%-     set method_name = "k%s_%s_Name"|format(interface.name, method.name) %}
+const uint32_t {{method_name}} = {{method.ordinal}};
+{%      set struct = method|struct_from_method %}
+{%-     include "params_definition.tmpl" %}
+{%-     if method.response_parameters != None %}
+{%-       set struct = method|response_struct_from_method %}
+{%-       include "params_definition.tmpl" %}
+{%-     endif %}
+{%-   endfor %}
+{%- endfor %}
+
+#pragma pack(pop)
+
+}  // namespace
+
+{#--- Struct definitions #}
+{%  for struct in structs %}
+{%-   include "struct_definition.tmpl" %}
+{%- endfor %}
+
+}  // namespace internal
+
+{#--- Struct Constants #}
+{%- for struct in structs %}
+{%     for constant in struct.constants %}
+const {{constant.kind|cpp_pod_type}} {{struct.name}}::{{constant.name}} = {{constant|constant_value}};
+{%-   endfor %}
+{%- endfor %}
+
+{#--- Struct builder definitions #}
+{%- for struct in structs %}
+{%-   include "wrapper_class_definition.tmpl" %}
+{%- endfor %}
+
+{#--- Interface definitions #}
+{%- for interface in interfaces %}
+{%-   include "interface_definition.tmpl" %}
+{%- endfor %}
+
+{#--- Struct Serialization Helpers #}
+{%- for struct in structs %}
+{%-   include "struct_serialization_definition.tmpl" %}
+{%- endfor %}
+
+{%- for namespace in namespaces_as_array|reverse %}
+}  // namespace {{namespace}}
+{%- endfor %}
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(_MSC_VER)
+#pragma warning(pop)
+#endif
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
new file mode 100644
index 0000000..4e21d47
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
@@ -0,0 +1,108 @@
+// Copyright 2013 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.
+
+{%- set header_guard = "%s_H_"|
+        format(module.path|upper|replace("/","_")|replace(".","_")) %}
+
+#ifndef {{header_guard}}
+#define {{header_guard}}
+
+#include "mojo/public/cpp/bindings/array.h"
+#include "mojo/public/cpp/bindings/callback.h"
+#include "mojo/public/cpp/bindings/interface_impl.h"
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/message_filter.h"
+#include "mojo/public/cpp/bindings/no_interface.h"
+#include "mojo/public/cpp/bindings/string.h"
+#include "mojo/public/cpp/bindings/struct_ptr.h"
+#include "{{module.path}}-internal.h"
+{%- for import in imports %}
+#include "{{import.module.path}}.h"
+{%- endfor %}
+
+{%- for namespace in namespaces_as_array %}
+namespace {{namespace}} {
+{%- endfor %}
+
+{#--- Constants #}
+{%  for constant in module.constants %}
+extern const {{constant.kind|cpp_pod_type}} {{constant.name}};
+{%- endfor %}
+
+{#--- Enums #}
+{%  for enum in enums %}
+{%    include "enum_declaration.tmpl" %}
+{%- endfor %}
+
+{#--- Interface Forward Declarations -#}
+{%  for interface in interfaces %}
+class {{interface.name}};
+typedef mojo::InterfacePtr<{{interface.name}}> {{interface.name}}Ptr;
+{%  endfor %}
+
+{#--- Struct Forward Declarations -#}
+{%  for struct in structs %}
+class {{struct.name}};
+{%    if struct|should_inline %}
+typedef mojo::InlinedStructPtr<{{struct.name}}> {{struct.name}}Ptr;
+{%    else %}
+typedef mojo::StructPtr<{{struct.name}}> {{struct.name}}Ptr;
+{%    endif %}
+{%  endfor %}
+
+{#--- NOTE: Non-inlined structs may have pointers to inlined structs, so we  #}
+{#---       need to fully define inlined structs ahead of the others.        #}
+
+{#--- Inlined structs #}
+{%  for struct in structs %}
+{%    if struct|should_inline %}
+{%      include "wrapper_class_declaration.tmpl" %}
+{%    endif %}
+{%- endfor %}
+
+{#--- Non-inlined structs #}
+{%  for struct in structs %}
+{%    if not struct|should_inline %}
+{%      include "wrapper_class_declaration.tmpl" %}
+{%    endif %}
+{%- endfor %}
+
+{#--- Interfaces -#}
+{%  for interface in interfaces %}
+{%    include "interface_declaration.tmpl" %}
+{%- endfor %}
+
+{#--- Interface Proxies -#}
+{%  for interface in interfaces %}
+{%    include "interface_proxy_declaration.tmpl" %}
+{%- endfor %}
+
+{#--- Interface Stubs -#}
+{%  for interface in interfaces %}
+{%    include "interface_stub_declaration.tmpl" %}
+{%- endfor %}
+
+{#--- Interface Request Validators -#}
+{%  for interface in interfaces %}
+{%    include "interface_request_validator_declaration.tmpl" %}
+{%- endfor %}
+
+{#--- Interface Response Validators -#}
+{%  for interface in interfaces if interface|has_callbacks %}
+{%    include "interface_response_validator_declaration.tmpl" %}
+{%- endfor %}
+
+{#--- Struct Serialization Helpers -#}
+{%  if structs %}
+{%    for struct in structs %}
+{%      include "struct_serialization_declaration.tmpl" %}
+{%-   endfor %}
+{%- endif %}
+
+{%- for namespace in namespaces_as_array|reverse %}
+}  // namespace {{namespace}}
+{%- endfor %}
+
+#endif  // {{header_guard}}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl
new file mode 100644
index 0000000..0b11047
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl
@@ -0,0 +1,33 @@
+{%- import "struct_macros.tmpl" as struct_macros %}
+{%- set class_name = struct.name ~ "_Data" %}
+class {{class_name}} {
+ public:
+  static {{class_name}}* New(mojo::internal::Buffer* buf) {
+    return new (buf->Allocate(sizeof({{class_name}})))
+        {{class_name}}();
+  }
+
+  static bool Validate(const void* data,
+                       mojo::internal::BoundsChecker* bounds_checker) {
+    {{ struct_macros.validate(struct, class_name)|indent(4) }}
+  }
+
+  mojo::internal::StructHeader header_;
+{{struct_macros.fields(struct)}}
+
+  void EncodePointersAndHandles(std::vector<mojo::Handle>* handles) {
+    {{ struct_macros.encodes(struct)|indent(4) }}
+  }
+
+  void DecodePointersAndHandles(std::vector<mojo::Handle>* handles) {
+    {{ struct_macros.decodes(struct)|indent(4) }}
+  }
+
+ private:
+  {{class_name}}() {
+    header_.num_bytes = sizeof(*this);
+    header_.num_fields = {{struct.packed.packed_fields|length}};
+  }
+};
+MOJO_COMPILE_ASSERT(sizeof({{class_name}}) == {{struct.packed|struct_size}},
+                    bad_sizeof_{{class_name}});
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl
new file mode 100644
index 0000000..60a6a9e
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl
@@ -0,0 +1,22 @@
+{%- import "struct_macros.tmpl" as struct_macros %}
+{%- set class_name = struct.name ~ "_Data" -%}
+
+class {{class_name}} {
+ public:
+  static {{class_name}}* New(mojo::internal::Buffer* buf);
+
+  static bool Validate(const void* data,
+                       mojo::internal::BoundsChecker* bounds_checker);
+
+  mojo::internal::StructHeader header_;
+{{struct_macros.fields(struct)}}
+
+  void EncodePointersAndHandles(std::vector<mojo::Handle>* handles);
+  void DecodePointersAndHandles(std::vector<mojo::Handle>* handles);
+
+ private:
+  {{class_name}}();
+  ~{{class_name}}();  // NOT IMPLEMENTED
+};
+MOJO_COMPILE_ASSERT(sizeof({{class_name}}) == {{struct.packed|struct_size}},
+                    bad_sizeof_{{class_name}});
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl
new file mode 100644
index 0000000..461f158
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl
@@ -0,0 +1,28 @@
+{%- import "struct_macros.tmpl" as struct_macros %}
+{%- set class_name = struct.name ~ "_Data" %}
+
+// static
+{{class_name}}* {{class_name}}::New(mojo::internal::Buffer* buf) {
+  return new (buf->Allocate(sizeof({{class_name}}))) {{class_name}}();
+}
+
+// static
+bool {{class_name}}::Validate(const void* data,
+                              mojo::internal::BoundsChecker* bounds_checker) {
+  {{ struct_macros.validate(struct, class_name)|indent(2) }}
+}
+
+{{class_name}}::{{class_name}}() {
+  header_.num_bytes = sizeof(*this);
+  header_.num_fields = {{struct.packed.packed_fields|length}};
+}
+
+void {{class_name}}::EncodePointersAndHandles(
+    std::vector<mojo::Handle>* handles) {
+  {{ struct_macros.encodes(struct)|indent(2) }}
+}
+
+void {{class_name}}::DecodePointersAndHandles(
+    std::vector<mojo::Handle>* handles) {
+  {{ struct_macros.decodes(struct)|indent(2) }}
+}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
new file mode 100644
index 0000000..0e51193
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
@@ -0,0 +1,115 @@
+{%- macro validate(struct, class_name) %}
+  if (!data)
+    return true;
+
+  if (!ValidateStructHeader(
+          data, sizeof({{class_name}}),
+          {{struct.packed.packed_fields|length}}, bounds_checker)) {
+    return false;
+  }
+
+  const {{class_name}}* MOJO_ALLOW_UNUSED object =
+      static_cast<const {{class_name}}*>(data);
+
+{%-   for packed_field in struct.packed.packed_fields %}
+{%-     set name = packed_field.field.name %}
+{%-     set kind = packed_field.field.kind %}
+{%-     if kind|is_object_kind %}
+{%-       set wrapper_type = kind|cpp_wrapper_type %}
+{%-       if not kind|is_nullable_kind %}
+  if (!object->{{name}}.offset) {
+    ReportValidationError(
+        mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
+        "null {{name}} field in {{struct.name}} struct");
+    return false;
+  }
+{%-       endif %}
+  if (!mojo::internal::ValidateEncodedPointer(&object->{{name}}.offset)) {
+    ReportValidationError(mojo::internal::VALIDATION_ERROR_ILLEGAL_POINTER);
+    return false;
+  }
+{%-       if kind|is_any_array_kind or kind|is_string_kind %}
+  if (!{{wrapper_type}}::Data_::Validate<
+          {{kind|get_array_validate_params|indent(10)}}>(
+              mojo::internal::DecodePointerRaw(&object->{{name}}.offset),
+              bounds_checker)) {
+{%-       else %}
+  if (!{{wrapper_type}}::Data_::Validate(
+          mojo::internal::DecodePointerRaw(&object->{{name}}.offset),
+          bounds_checker)) {
+{%-       endif %}
+    return false;
+  }
+{%-     elif kind|is_any_handle_kind %}
+{%-       if not kind|is_nullable_kind %}
+  if (object->{{name}}.value() == mojo::internal::kEncodedInvalidHandleValue) {
+    ReportValidationError(
+        mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
+        "invalid {{name}} field in {{struct.name}} struct");
+    return false;
+  }
+{%-       endif %}
+  if (!bounds_checker->ClaimHandle(object->{{name}})) {
+    ReportValidationError(mojo::internal::VALIDATION_ERROR_ILLEGAL_HANDLE);
+    return false;
+  }
+{%-     endif %}
+{%-   endfor %}
+
+  return true;
+{%- endmacro %}
+
+{%- macro field_line(field) %}
+{%-   set type = field.kind|cpp_field_type %}
+{%-   set name = field.name -%}
+{%-   if field.kind.spec == 'b' -%}
+  uint8_t {{name}} : 1;
+{%-   elif field.kind|is_enum_kind -%}
+  int32_t {{name}};
+{%-   else -%}
+  {{type}} {{name}};
+{%-   endif %}
+{%- endmacro %}
+
+{%- macro fields(struct) %}
+{%-   for packed_field in struct.packed.packed_fields %}
+  {{field_line(packed_field.field)}}
+{%-     if not loop.last %}
+{%-       set next_pf = struct.packed.packed_fields[loop.index0 + 1] %}
+{%-       set pad = next_pf.offset - (packed_field.offset + packed_field.size) %}
+{%-       if pad > 0 %}
+  uint8_t pad{{loop.index0}}_[{{pad}}];
+{%-       endif %}
+{%-     endif %}
+{%-   endfor -%}
+
+{%-   set num_fields = struct.packed.packed_fields|length %}
+{%-   if num_fields > 0 %}
+{%-     set last_field = struct.packed.packed_fields[num_fields - 1] %}
+{%-     set offset = last_field.offset + last_field.size %}
+{%-     set pad = offset|get_pad(8) -%}
+{%-     if pad > 0 %}
+  uint8_t padfinal_[{{pad}}];
+{%-     endif %}
+{%-   endif %}
+{%- endmacro %}
+
+{%- macro encodes(struct) -%}
+{%-   for pf in struct.packed.packed_fields %}
+{%-     if pf.field.kind|is_object_kind %}
+mojo::internal::Encode(&{{pf.field.name}}, handles);
+{%-     elif pf.field.kind|is_any_handle_kind %}
+mojo::internal::EncodeHandle(&{{pf.field.name}}, handles);
+{%-     endif %}
+{%-   endfor %}
+{%- endmacro -%}
+
+{%- macro decodes(struct) -%}
+{%-   for pf in struct.packed.packed_fields %}
+{%-     if pf.field.kind|is_object_kind %}
+mojo::internal::Decode(&{{pf.field.name}}, handles);
+{%-     elif pf.field.kind|is_any_handle_kind %}
+mojo::internal::DecodeHandle(&{{pf.field.name}}, handles);
+{%-     endif %}
+{%-   endfor %}
+{%- endmacro -%}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
new file mode 100644
index 0000000..604be86
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
@@ -0,0 +1,5 @@
+size_t GetSerializedSize_(const {{struct.name}}Ptr& input);
+void Serialize_({{struct.name}}Ptr input, mojo::internal::Buffer* buffer,
+                internal::{{struct.name}}_Data** output);
+void Deserialize_(internal::{{struct.name}}_Data* input,
+                  {{struct.name}}Ptr* output);
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl
new file mode 100644
index 0000000..09bf392
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl
@@ -0,0 +1,75 @@
+size_t GetSerializedSize_(const {{struct.name}}Ptr& input) {
+  if (!input)
+    return 0;
+  size_t size = sizeof(internal::{{struct.name}}_Data);
+{%- for pf in struct.packed.packed_fields if pf.field.kind|is_object_kind %}
+  size += GetSerializedSize_(input->{{pf.field.name}});
+{%- endfor %}
+  return size;
+}
+
+void Serialize_({{struct.name}}Ptr input, mojo::internal::Buffer* buf,
+                internal::{{struct.name}}_Data** output) {
+  if (input) {
+    internal::{{struct.name}}_Data* result =
+        internal::{{struct.name}}_Data::New(buf);
+{%- for pf in struct.packed.packed_fields %}
+{%-   if pf.field.kind|is_object_kind %}
+{%-     if pf.field.kind|is_any_array_kind %}
+    mojo::SerializeArray_<{{pf.field.kind|get_array_validate_params|indent(26)}}>(
+        mojo::internal::Forward(input->{{pf.field.name}}), buf, &result->{{pf.field.name}}.ptr);
+{%-     else %}
+    Serialize_(mojo::internal::Forward(input->{{pf.field.name}}), buf, &result->{{pf.field.name}}.ptr);
+{%-     endif %}
+{%-     if not pf.field.kind|is_nullable_kind %}
+    MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
+        !result->{{pf.field.name}}.ptr,
+        mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
+        "null {{pf.field.name}} field in {{struct.name}} struct");
+{%-     endif %}
+{%-   elif pf.field.kind|is_any_handle_kind %}
+{%-     if pf.field.kind|is_interface_kind %}
+    result->{{pf.field.name}} = input->{{pf.field.name}}.PassMessagePipe().release();
+{%-     else %}
+    result->{{pf.field.name}} = input->{{pf.field.name}}.release();
+{%-     endif %}
+{%-     if not pf.field.kind|is_nullable_kind %}
+    MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
+        !result->{{pf.field.name}}.is_valid(),
+        mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
+        "invalid {{pf.field.name}} field in {{struct.name}} struct");
+{%-     endif %}
+{%-   else %}
+    result->{{pf.field.name}} = input->{{pf.field.name}};
+{%-   endif %}
+{%- endfor %}
+    *output = result;
+  } else {
+    *output = nullptr;
+  }
+}
+
+void Deserialize_(internal::{{struct.name}}_Data* input,
+                  {{struct.name}}Ptr* output) {
+  if (input) {
+    {{struct.name}}Ptr result({{struct.name}}::New());
+{%- for pf in struct.packed.packed_fields %}
+{%-   if pf.field.kind|is_object_kind %}
+    Deserialize_(input->{{pf.field.name}}.ptr, &result->{{pf.field.name}});
+{%-   elif pf.field.kind|is_interface_kind %}
+    if (input->{{pf.field.name}}.is_valid())
+      result->{{pf.field.name}}.Bind(mojo::MakeScopedHandle(mojo::internal::FetchAndReset(&input->{{pf.field.name}})));
+{%-   elif pf.field.kind|is_any_handle_kind %}
+    result->{{pf.field.name}}.reset(mojo::internal::FetchAndReset(&input->{{pf.field.name}}));
+{%-   elif pf.field.kind|is_enum_kind %}
+    result->{{pf.field.name}} = static_cast<{{pf.field.kind|cpp_wrapper_type}}>(
+      input->{{pf.field.name}});
+{%-   else %}
+    result->{{pf.field.name}} = input->{{pf.field.name}};
+{%-   endif %}
+{%- endfor %}
+    *output = result.Pass();
+  } else {
+    output->reset();
+  }
+}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
new file mode 100644
index 0000000..21f2968
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
@@ -0,0 +1,34 @@
+
+class {{struct.name}} {
+ public:
+  typedef internal::{{struct.name}}_Data Data_;
+
+{#--- Constants #}
+{%- for constant in struct.constants %}
+  static const {{constant.kind|cpp_pod_type}} {{constant.name}};
+{%- endfor %}
+{#--- Enums #}
+{%- for enum in struct.enums -%}
+{%    macro enum_def() %}{% include "enum_declaration.tmpl" %}{% endmacro %}
+  {{enum_def()|indent(2)}}
+{%- endfor %}
+  static {{struct.name}}Ptr New();
+
+  template <typename U>
+  static {{struct.name}}Ptr From(const U& u) {
+    return mojo::TypeConverter<{{struct.name}}Ptr, U>::Convert(u);
+  }
+
+  {{struct.name}}();
+  ~{{struct.name}}();
+{%  if struct|is_cloneable_kind %}
+  {{struct.name}}Ptr Clone() const;
+{%- endif %}
+
+{#--- Getters #}
+{%  for field in struct.fields %}
+{%-   set type = field.kind|cpp_wrapper_type %}
+{%-   set name = field.name %}
+  {{type}} {{name}};
+{%- endfor %}
+};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl
new file mode 100644
index 0000000..42f7575
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl
@@ -0,0 +1,28 @@
+// static
+{{struct.name}}Ptr {{struct.name}}::New() {
+  {{struct.name}}Ptr rv;
+  mojo::internal::StructHelper<{{struct.name}}>::Initialize(&rv);
+  return rv.Pass();
+}
+
+{{struct.name}}::{{struct.name}}()
+{%- for field in struct.fields %}
+    {% if loop.first %}:{% else %} {% endif %} {{field.name}}({{field|default_value}}){% if not loop.last %},{% endif %}
+{%- endfor %} {
+}
+
+{{struct.name}}::~{{struct.name}}() {
+}
+{%  if struct|is_cloneable_kind %}
+{{struct.name}}Ptr {{struct.name}}::Clone() const {
+  {{struct.name}}Ptr rv(New());
+{%-   for field in struct.fields %}
+{%-     if field.kind|is_struct_kind or field.kind|is_any_array_kind %}
+  rv->{{field.name}} = {{field.name}}.Clone();
+{%-     else %}
+  rv->{{field.name}} = {{field.name}};
+{%-     endif %}
+{%-   endfor %}
+  return rv.Pass();
+}
+{%  endif %}
diff --git a/mojo/public/tools/bindings/generators/java_templates/constant_definition.tmpl b/mojo/public/tools/bindings/generators/java_templates/constant_definition.tmpl
new file mode 100644
index 0000000..db193e2
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/java_templates/constant_definition.tmpl
@@ -0,0 +1,3 @@
+{% macro constant_def(constant) %}
+public static final {{constant.kind|java_type}} {{constant|name}} = {{constant|constant_value}};
+{% endmacro %}
diff --git a/mojo/public/tools/bindings/generators/java_templates/constants.java.tmpl b/mojo/public/tools/bindings/generators/java_templates/constants.java.tmpl
new file mode 100644
index 0000000..0a4e299
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/java_templates/constants.java.tmpl
@@ -0,0 +1,12 @@
+{% from "constant_definition.tmpl" import constant_def %}
+{% include "header.java.tmpl" %}
+
+public final class {{main_entity}} {
+{%  for constant in constants %}
+
+    {{constant_def(constant)|indent(4)}}
+{%  endfor %}
+
+    private {{main_entity}}() {}
+
+}
diff --git a/mojo/public/tools/bindings/generators/java_templates/enum.java.tmpl b/mojo/public/tools/bindings/generators/java_templates/enum.java.tmpl
new file mode 100644
index 0000000..7096a18
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/java_templates/enum.java.tmpl
@@ -0,0 +1,4 @@
+{% from "enum_definition.tmpl" import enum_def %}
+{% include "header.java.tmpl" %}
+
+{{enum_def(enum, true)}}
diff --git a/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl b/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl
new file mode 100644
index 0000000..a16c178
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl
@@ -0,0 +1,21 @@
+{%- macro enum_value(enum, field, index) -%}
+{%- if field.value -%}
+(int) ({{field.value|expression_to_text('i32')}})
+{%- elif index == 0 -%}
+0
+{%- else -%}
+{{enum.fields[index - 1]|name}} + 1
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro enum_def(enum, top_level) -%}
+public {{ 'static ' if not top_level }}final class {{enum|name}} {
+
+{% for field in enum.fields %}
+    public static final int {{field|name}} = {{enum_value(enum, field, loop.index0)}};
+{% endfor %}
+
+    private {{enum|name}}() {}
+
+}
+{%- endmacro -%}
diff --git a/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl b/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl
new file mode 100644
index 0000000..ec6a88b
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl
@@ -0,0 +1,11 @@
+// Copyright 2014 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 is autogenerated by:
+//     mojo/public/tools/bindings/mojom_bindings_generator.py
+// For:
+//     {{module.path}}
+//
+
+package {{package}};
diff --git a/mojo/public/tools/bindings/generators/java_templates/interface.java.tmpl b/mojo/public/tools/bindings/generators/java_templates/interface.java.tmpl
new file mode 100644
index 0000000..10e5d7a
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/java_templates/interface.java.tmpl
@@ -0,0 +1,4 @@
+{% from "interface_definition.tmpl" import interface_def %}
+{% include "header.java.tmpl" %}
+
+{{ interface_def(interface, client) }}
diff --git a/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl
new file mode 100644
index 0000000..941fec7
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl
@@ -0,0 +1,294 @@
+{% from "constant_definition.tmpl" import constant_def %}
+{% from "enum_definition.tmpl" import enum_def %}
+{% from "struct_definition.tmpl" import struct_def %}
+
+{%- macro declare_params(parameters, boxed=false) %}
+{%-   for param in parameters -%}
+{{param.kind|java_type(boxed)}} {{param|name}}
+{%- if not loop.last %}, {% endif %}
+{%-   endfor %}
+{%- endmacro %}
+
+{% macro declare_request_params(method) %}
+{{declare_params(method.parameters)}}
+{%-   if method.response_parameters != None -%}
+{%- if method.parameters %}, {% endif %}
+{{method|interface_response_name}} callback
+{%-   endif -%}
+{% endmacro %}
+
+{%- macro declare_callback(method) -%}
+
+interface {{method|interface_response_name}} extends org.chromium.mojo.bindings.Callbacks.Callback{{method.response_parameters|length}}{% if method.response_parameters %}<
+{%-   for param in method.response_parameters -%}
+{{param.kind|java_type(True)}}
+{%- if not loop.last %}, {% endif %}
+{%-   endfor -%}
+>{% endif %} { }
+{%- endmacro -%}
+
+{%- macro run_callback(variable, parameters) -%}
+{%-   if parameters -%}
+{%-     for param in parameters -%}
+{{variable}}.{{param|name}}
+{%-   if not loop.last %}, {% endif %}
+{%-     endfor -%}
+{%-   endif -%}
+{%- endmacro -%}
+
+{%- macro super_class(client, with_generic=True) -%}
+{%-   if client -%}
+org.chromium.mojo.bindings.InterfaceWithClient{% if with_generic %}<{{client|java_type}}>{% endif %}
+{%-   else -%}
+org.chromium.mojo.bindings.Interface
+{%-   endif -%}
+{%- endmacro -%}
+
+{%- macro flags_for_method(method, is_parameter) -%}
+{{flags(method.response_parameters, is_parameter)}}
+{%- endmacro -%}
+
+{%- macro flags(has_response_parameters, is_parameter) -%}
+{%-  if not has_response_parameters -%}
+org.chromium.mojo.bindings.MessageHeader.NO_FLAG
+{%-   elif is_parameter: -%}
+org.chromium.mojo.bindings.MessageHeader.MESSAGE_EXPECTS_RESPONSE_FLAG
+{%-   else -%}
+org.chromium.mojo.bindings.MessageHeader.MESSAGE_IS_RESPONSE_FLAG
+{%-   endif -%}
+{%- endmacro -%}
+
+{%- macro manager_class(interface, client, fully_qualified=False) -%}
+{% if fully_qualified %}{{super_class(client, False)}}.{% endif %}Manager<{{interface|name}}, {{interface|name}}.Proxy
+{%- if client -%}, {{client|java_type}}{%-  endif -%}
+>
+{%- endmacro -%}
+
+{%- macro manager_def(interface, client) -%}
+public static final {{manager_class(interface, client, True)}} MANAGER =
+        new {{manager_class(interface, client, True)}}() {
+
+    public String getName() {
+        return "{{namespace|replace(".","::")}}::{{interface.name}}";
+    }
+
+    public Proxy buildProxy(org.chromium.mojo.system.Core core,
+                            org.chromium.mojo.bindings.MessageReceiverWithResponder messageReceiver) {
+        return new Proxy(core, messageReceiver);
+    }
+
+    public Stub buildStub(org.chromium.mojo.system.Core core, {{interface|name}} impl) {
+        return new Stub(core, impl);
+    }
+
+    public {{interface|name}}[] buildArray(int size) {
+      return new {{interface|name}}[size];
+    }
+{%  if client %}
+
+    protected org.chromium.mojo.bindings.Interface.Manager<{{client|java_type}}, ?> getClientManager() {
+        return {{client|java_type}}.MANAGER;
+    }
+{%  endif %}
+};
+{%- endmacro -%}
+
+{%- macro accept_body(interface, with_response) -%}
+{% if (interface|has_method_with_response and with_response) or
+      (interface|has_method_without_response and not with_response) %}
+try {
+    org.chromium.mojo.bindings.ServiceMessage messageWithHeader =
+            message.asServiceMessage();
+    org.chromium.mojo.bindings.MessageHeader header = messageWithHeader.getHeader();
+    if (!header.validateHeader({{flags(with_response, True)}})) {
+        return false;
+    }
+    switch(header.getType()) {
+{%   for method in interface.methods %}
+{%     if (with_response and method.response_parameters != None) or
+        (not with_response and method.response_parameters == None) %}
+{%       set request_struct = method|struct_from_method %}
+{%       if with_response %}
+{%         set response_struct = method|response_struct_from_method %}
+{%       endif %}
+        case {{method|method_ordinal_name}}: {
+{%       if method.parameters %}
+            {{request_struct|name}} data =
+                    {{request_struct|name}}.deserialize(messageWithHeader.getPayload());
+{%       else %}
+            {{request_struct|name}}.deserialize(messageWithHeader.getPayload());
+{%       endif %}
+            getImpl().{{method|name}}({{run_callback('data', method.parameters)}}{% if with_response %}{% if method.parameters %}, {% endif %}new {{response_struct|name}}ProxyToResponder(getCore(), receiver, header.getRequestId()){% endif %});
+            return true;
+        }
+{%     endif %}
+{%   endfor %}
+        default:
+            return false;
+    }
+} catch (org.chromium.mojo.bindings.DeserializationException e) {
+    return false;
+}
+{% else %}
+return false;
+{% endif %}
+{%- endmacro -%}
+
+{% macro interface_def(interface, client) %}
+public interface {{interface|name}} extends {{super_class(client)}} {
+{%  for constant in interface.constants %}
+
+    {{constant_def(constant)|indent(4)}}
+{%  endfor %}
+{%  for enum in interface.enums %}
+
+    {{enum_def(enum, false)|indent(4)}}
+{% endfor %}
+
+    public interface Proxy extends {{interface|name}}, {{super_class(client, False)}}.Proxy{% if client %}<{{client|java_type}}>{% endif %} {
+    }
+
+    {{manager_class(interface, client)}} MANAGER = {{interface|name}}_Internal.MANAGER;
+{% for method in interface.methods %}
+
+    void {{method|name}}({{declare_request_params(method)}});
+{%   if method.response_parameters != None %}
+    {{declare_callback(method)|indent(4)}}
+{%   endif %}
+{% endfor %}
+}
+{% endmacro %}
+
+{% macro interface_internal_def(interface, client) %}
+class {{interface|name}}_Internal {
+
+    {{manager_def(interface, client)|indent(4)}}
+
+{% for method in interface.methods %}
+    private static final int {{method|method_ordinal_name}} = {{method.ordinal}};
+{% endfor %}
+
+    static final class Proxy extends {% if client %}org.chromium.mojo.bindings.InterfaceWithClient.AbstractProxy<{{client|java_type}}>{% else %}org.chromium.mojo.bindings.Interface.AbstractProxy{% endif %} implements {{interface|name}}.Proxy {
+
+        Proxy(org.chromium.mojo.system.Core core,
+              org.chromium.mojo.bindings.MessageReceiverWithResponder messageReceiver) {
+            super(core, messageReceiver);
+        }
+{% for method in interface.methods %}
+
+        @Override
+        public void {{method|name}}({{declare_request_params(method)}}) {
+{%   set request_struct = method|struct_from_method %}
+            {{request_struct|name}} _message = new {{request_struct|name}}();
+{%   for param in method.parameters %}
+            _message.{{param|name}} = {{param|name}};
+{%   endfor %}
+{%   if method.response_parameters != None %}
+            getMessageReceiver().acceptWithResponder(
+                    _message.serializeWithHeader(
+                            getCore(),
+                            new org.chromium.mojo.bindings.MessageHeader(
+                                    {{method|method_ordinal_name}},
+                                    {{flags_for_method(method, True)}},
+                                    0)),
+                    new {{method|response_struct_from_method|name}}ForwardToCallback(callback));
+{%   else %}
+            getMessageReceiver().accept(
+                    _message.serializeWithHeader(
+                            getCore(),
+                            new org.chromium.mojo.bindings.MessageHeader({{method|method_ordinal_name}})));
+{%   endif %}
+        }
+{% endfor %}
+
+    }
+
+    static final class Stub extends org.chromium.mojo.bindings.Interface.Stub<{{interface|name}}> {
+
+        Stub(org.chromium.mojo.system.Core core, {{interface|name}} impl) {
+            super(core, impl);
+        }
+
+        @Override
+        public boolean accept(org.chromium.mojo.bindings.Message message) {
+            {{accept_body(interface, False)|indent(12)}}
+        }
+
+        @Override
+        public boolean acceptWithResponder(org.chromium.mojo.bindings.Message message, org.chromium.mojo.bindings.MessageReceiver receiver) {
+            {{accept_body(interface, True)|indent(12)}}
+        }
+    }
+{% for method in interface.methods %}
+
+    {{ struct_def(method|struct_from_method, True)|indent(4) }}
+{%   if method.response_parameters != None %}
+{%   set response_struct = method|response_struct_from_method %}
+
+    {{ struct_def(response_struct, True)|indent(4) }}
+
+    static class {{response_struct|name}}ForwardToCallback extends org.chromium.mojo.bindings.SideEffectFreeCloseable
+            implements org.chromium.mojo.bindings.MessageReceiver {
+        private final {{interface|name}}.{{method|interface_response_name}} mCallback;
+
+        {{response_struct|name}}ForwardToCallback({{interface|name}}.{{method|interface_response_name}} callback) {
+            this.mCallback = callback;
+        }
+
+        @Override
+        public boolean accept(org.chromium.mojo.bindings.Message message) {
+            try {
+                org.chromium.mojo.bindings.ServiceMessage messageWithHeader =
+                        message.asServiceMessage();
+                org.chromium.mojo.bindings.MessageHeader header = messageWithHeader.getHeader();
+                if (!header.validateHeader({{method|method_ordinal_name}},
+                                           {{flags_for_method(method, False)}})) {
+                    return false;
+                }
+{%   if method.response_parameters|length %}
+                {{response_struct|name}} response = {{response_struct|name}}.deserialize(messageWithHeader.getPayload());
+{%   endif %}
+                mCallback.call({{run_callback('response', method.response_parameters)}});
+                return true;
+            } catch (org.chromium.mojo.bindings.DeserializationException e) {
+                return false;
+            }
+        }
+    }
+
+    static class {{response_struct|name}}ProxyToResponder implements {{interface|name}}.{{method|interface_response_name}} {
+
+        private final org.chromium.mojo.system.Core mCore;
+        private final org.chromium.mojo.bindings.MessageReceiver mMessageReceiver;
+        private final long mRequestId;
+
+        {{response_struct|name}}ProxyToResponder(
+                org.chromium.mojo.system.Core core,
+                org.chromium.mojo.bindings.MessageReceiver messageReceiver,
+                long requestId) {
+            mCore = core;
+            mMessageReceiver = messageReceiver;
+            mRequestId = requestId;
+        }
+
+        @Override
+        public void call({{declare_params(method.response_parameters, true)}}) {
+            {{response_struct|name}} _response = new {{response_struct|name}}();
+{%   for param in method.response_parameters %}
+            _response.{{param|name}} = {{param|name}};
+{%   endfor %}
+            org.chromium.mojo.bindings.ServiceMessage _message =
+                    _response.serializeWithHeader(
+                            mCore,
+                            new org.chromium.mojo.bindings.MessageHeader(
+                                    {{method|method_ordinal_name}},
+                                    {{flags_for_method(method, False)}},
+                                    mRequestId));
+            mMessageReceiver.accept(_message);
+        }
+    }
+{%   endif %}
+{% endfor %}
+
+}
+{% endmacro %}
diff --git a/mojo/public/tools/bindings/generators/java_templates/interface_internal.java.tmpl b/mojo/public/tools/bindings/generators/java_templates/interface_internal.java.tmpl
new file mode 100644
index 0000000..efb17f3
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/java_templates/interface_internal.java.tmpl
@@ -0,0 +1,4 @@
+{% from "interface_definition.tmpl" import interface_internal_def %}
+{% include "header.java.tmpl" %}
+
+{{ interface_internal_def(interface, client) }}
diff --git a/mojo/public/tools/bindings/generators/java_templates/struct.java.tmpl b/mojo/public/tools/bindings/generators/java_templates/struct.java.tmpl
new file mode 100644
index 0000000..232ec26
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/java_templates/struct.java.tmpl
@@ -0,0 +1,4 @@
+{% from "struct_definition.tmpl" import struct_def %}
+{% include "header.java.tmpl" %}
+
+{{ struct_def(struct) }}
diff --git a/mojo/public/tools/bindings/generators/java_templates/struct_definition.tmpl b/mojo/public/tools/bindings/generators/java_templates/struct_definition.tmpl
new file mode 100644
index 0000000..2fc4439
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/java_templates/struct_definition.tmpl
@@ -0,0 +1,118 @@
+{% from "constant_definition.tmpl" import constant_def %}
+{% from "enum_definition.tmpl" import enum_def %}
+
+{%- macro array_expected_length(kind) -%}
+{%- if kind|is_fixed_array_kind -%}
+{{kind.length}}
+{%- else -%}
+org.chromium.mojo.bindings.BindingsHelper.UNSPECIFIED_ARRAY_LENGTH
+{%- endif -%}
+{%- endmacro -%}
+
+{% macro encode(variable, kind, offset, bit, level=0) %}
+{% if kind|is_pointer_array_kind %}
+{% set sub_kind = kind.kind %}
+if ({{variable}} == null) {
+    encoder{{level}}.encodeNullPointer({{offset}}, {{kind|is_nullable_kind|java_true_false}});
+} else {
+    org.chromium.mojo.bindings.Encoder encoder{{level + 1}} = encoder{{level}}.encodePointerArray({{variable}}.length, {{offset}}, {{array_expected_length(kind)}});
+    for (int i{{level}} = 0; i{{level}} < {{variable}}.length; ++i{{level}}) {
+        {{encode(variable~'[i'~level~']', sub_kind, 'DataHeader.HEADER_SIZE + org.chromium.mojo.bindings.BindingsHelper.POINTER_SIZE * i'~level, 0, level+1)|indent(8)}}
+    }
+}
+{% else %}
+encoder{{level}}.{{kind|encode_method(variable, offset, bit)}};
+{% endif %}
+{% endmacro %}
+
+{% macro decode(variable, kind, offset, bit, level=0) %}
+{% if kind|is_struct_kind or kind|is_pointer_array_kind %}
+org.chromium.mojo.bindings.Decoder decoder{{level+1}} = decoder{{level}}.readPointer({{offset}}, {{kind|is_nullable_kind|java_true_false}});
+{%   if kind|is_struct_kind %}
+{{variable}} = {{kind|java_type}}.decode(decoder{{level+1}});
+{%   else %}{# kind|is_pointer_array_kind #}
+if (decoder{{level+1}} == null) {
+    {{variable}} = null;
+} else {
+    DataHeader si{{level+1}} = decoder{{level+1}}.readDataHeaderForPointerArray({{array_expected_length(kind)}});
+    {{variable}} = {{kind|new_array('si'~(level+1)~'.numFields')}};
+    for (int i{{level+1}} = 0; i{{level+1}} < si{{level+1}}.numFields; ++i{{level+1}}) {
+        {{decode(variable~'[i'~(level+1)~']', kind.kind, 'DataHeader.HEADER_SIZE + org.chromium.mojo.bindings.BindingsHelper.POINTER_SIZE * i'~(level+1), 0, level+1)|indent(8)}}
+    }
+}
+{%   endif %}
+{% else %}
+{{variable}} = decoder{{level}}.{{kind|decode_method(offset, bit)}};
+{% endif %}
+{% endmacro %}
+
+{% macro struct_def(struct, inner_class=False) %}
+{{'static' if inner_class else 'public'}} final class {{struct|name}} extends org.chromium.mojo.bindings.Struct {
+
+    private static final int STRUCT_SIZE = {{struct.packed|struct_size}};
+    private static final DataHeader DEFAULT_STRUCT_INFO = new DataHeader(STRUCT_SIZE, {{struct.packed.packed_fields|length}});
+{%  for constant in struct.constants %}
+
+    {{constant_def(constant)|indent(4)}}
+{%  endfor %}
+{%  for enum in struct.enums %}
+
+    {{enum_def(enum, false)|indent(4)}}
+{% endfor %}
+{% if struct.fields %}
+
+{%   for field in struct.fields %}
+    public {{field.kind|java_type}} {{field|name}};
+{%   endfor %}
+{% endif %}
+
+    public {{struct|name}}() {
+        super(STRUCT_SIZE);
+{% for field in struct.fields %}
+{%   if field.default %}
+        {{field|name}} = {{field|default_value}};
+{%   elif field.kind|is_handle %}
+        {{field|name}} = org.chromium.mojo.system.InvalidHandle.INSTANCE;
+{%   endif %}
+{% endfor %}
+    }
+
+    public static {{struct|name}} deserialize(org.chromium.mojo.bindings.Message message) {
+        return decode(new org.chromium.mojo.bindings.Decoder(message));
+    }
+
+    public static {{struct|name}} decode(org.chromium.mojo.bindings.Decoder decoder0) {
+        if (decoder0 == null) {
+            return null;
+        }
+        {{struct|name}} result = new {{struct|name}}();
+{% if not struct.bytes %}
+        decoder0.readDataHeader();
+{% else %}
+        DataHeader mainDataHeader = decoder0.readDataHeader();
+{% endif %}
+{% for byte in struct.bytes %}
+{%   for packed_field in byte.packed_fields %}
+        if (mainDataHeader.numFields > {{packed_field.ordinal}}) {
+            {{decode('result.' ~ packed_field.field|name, packed_field.field.kind, 8+packed_field.offset, packed_field.bit)|indent(12)}}
+        }
+{%   endfor %}
+{% endfor %}
+        return result;
+    }
+
+    @Override
+    protected final void encode(org.chromium.mojo.bindings.Encoder encoder) {
+{% if not struct.bytes %}
+        encoder.getEncoderAtDataOffset(DEFAULT_STRUCT_INFO);
+{% else %}
+        org.chromium.mojo.bindings.Encoder encoder0 = encoder.getEncoderAtDataOffset(DEFAULT_STRUCT_INFO);
+{% endif %}
+{% for byte in struct.bytes %}
+{%   for packed_field in byte.packed_fields %}
+        {{encode(packed_field.field|name, packed_field.field.kind, 8+packed_field.offset, packed_field.bit)|indent(8)}}
+{%   endfor %}
+{% endfor %}
+    }
+}
+{% endmacro %}
diff --git a/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl
new file mode 100644
index 0000000..795116d
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl
@@ -0,0 +1,14 @@
+{%- macro enum_def(enum_name, enum, module) -%}
+  {{enum_name}} = {};
+
+{%- set prev_enum = 0 %}
+{%- for field in enum.fields %}
+{%-   if field.value %}
+  {{enum_name}}.{{field.name}} = {{field.value|expression_to_text}};
+{%-   elif loop.first %}
+  {{enum_name}}.{{field.name}} = 0;
+{%-   else %}
+  {{enum_name}}.{{field.name}} = {{enum_name}}.{{enum.fields[loop.index0 - 1].name}} + 1;
+{%-   endif %}
+{%- endfor %}
+{%- endmacro %}
diff --git a/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl
new file mode 100644
index 0000000..b41929c
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl
@@ -0,0 +1,178 @@
+{%- set namespace_as_string = namespace|replace(".","::") %}
+{%- for method in interface.methods %}
+  var k{{interface.name}}_{{method.name}}_Name = {{method.ordinal}};
+{%- endfor %}
+
+  function {{interface.name}}Proxy(receiver) {
+    this.receiver_ = receiver;
+  }
+
+  {{interface.name}}Proxy.NAME_ = '{{namespace_as_string}}::{{interface.name}}';
+
+{%- for method in interface.methods %}
+  {{interface.name}}Proxy.prototype.{{method.name|stylize_method}} = function(
+{%- for parameter in method.parameters -%}
+{{parameter.name}}{% if not loop.last %}, {% endif %}
+{%- endfor -%}
+) {
+    var params = new {{interface.name}}_{{method.name}}_Params();
+{%- for parameter in method.parameters %}
+    params.{{parameter.name}} = {{parameter.name}};
+{%- endfor %}
+
+{%- if method.response_parameters == None %}
+    var builder = new codec.MessageBuilder(
+        k{{interface.name}}_{{method.name}}_Name,
+        codec.align({{interface.name}}_{{method.name}}_Params.encodedSize));
+    builder.encodeStruct({{interface.name}}_{{method.name}}_Params, params);
+    var message = builder.finish();
+    this.receiver_.accept(message);
+{%- else %}
+    return new Promise(function(resolve, reject) {
+      var builder = new codec.MessageWithRequestIDBuilder(
+          k{{interface.name}}_{{method.name}}_Name,
+          codec.align({{interface.name}}_{{method.name}}_Params.encodedSize),
+          codec.kMessageExpectsResponse, 0);
+      builder.encodeStruct({{interface.name}}_{{method.name}}_Params, params);
+      var message = builder.finish();
+      this.receiver_.acceptWithResponder(message, {
+          accept: function(message) {
+            var reader = new codec.MessageReader(message);
+            var responseParams =
+                reader.decodeStruct({{interface.name}}_{{method.name}}_ResponseParams);
+            resolve(responseParams);
+          },
+          reject: function(result) {
+            reject(Error("Connection error: " + result));
+          },
+      }).catch(reject);
+    }.bind(this));
+{%- endif %}
+  };
+{%- endfor %}
+
+  function {{interface.name}}Stub() {
+  }
+
+  {{interface.name}}Stub.NAME_ = '{{namespace_as_string}}::{{interface.name}}';
+
+  {{interface.name}}Stub.prototype.accept = function(message) {
+    var reader = new codec.MessageReader(message);
+    switch (reader.messageName) {
+{%- for method in interface.methods %}
+{%- if method.response_parameters == None %}
+    case k{{interface.name}}_{{method.name}}_Name:
+      var params = reader.decodeStruct({{interface.name}}_{{method.name}}_Params);
+      this.{{method.name|stylize_method}}(
+{%- for parameter in method.parameters -%}
+params.{{parameter.name}}{% if not loop.last %}, {% endif %}
+{%- endfor %});
+      return true;
+{%- endif %}
+{%- endfor %}
+    default:
+      return false;
+    }
+  };
+
+  {{interface.name}}Stub.prototype.acceptWithResponder =
+      function(message, responder) {
+    var reader = new codec.MessageReader(message);
+    switch (reader.messageName) {
+{%- for method in interface.methods %}
+{%- if method.response_parameters != None %}
+    case k{{interface.name}}_{{method.name}}_Name:
+      var params = reader.decodeStruct({{interface.name}}_{{method.name}}_Params);
+      return this.{{method.name|stylize_method}}(
+{%- for parameter in method.parameters -%}
+params.{{parameter.name}}{% if not loop.last %}, {% endif -%}
+{%- endfor %}).then(function(response) {
+        var responseParams =
+            new {{interface.name}}_{{method.name}}_ResponseParams();
+{%-     for parameter in method.response_parameters %}
+        responseParams.{{parameter.name}} = response.{{parameter.name}};
+{%-     endfor %}
+        var builder = new codec.MessageWithRequestIDBuilder(
+            k{{interface.name}}_{{method.name}}_Name,
+            codec.align({{interface.name}}_{{method.name}}_ResponseParams.encodedSize),
+            codec.kMessageIsResponse, reader.requestID);
+        builder.encodeStruct({{interface.name}}_{{method.name}}_ResponseParams,
+                             responseParams);
+        var message = builder.finish();
+        responder.accept(message);
+      });
+{%- endif %}
+{%- endfor %}
+    default:
+      return Promise.reject(Error("Unhandled message: " + reader.messageName));
+    }
+  };
+
+{#--- Validation #}
+
+  function validate{{interface.name}}Request(messageValidator) {
+{%- if not(interface.methods) %}
+    return validator.validationError.NONE;
+{%- else %}
+    var message = messageValidator.message;
+    var paramsClass = null;
+    switch (message.getName()) {
+{%-   for method in interface.methods %}
+      case k{{interface.name}}_{{method.name}}_Name:
+{%-     if method.response_parameters == None %}
+        if (!message.expectsResponse() && !message.isResponse())
+          paramsClass = {{interface.name}}_{{method.name}}_Params;
+{%-     else %}
+        if (message.expectsResponse())
+          paramsClass = {{interface.name}}_{{method.name}}_Params;
+{%-     endif %}
+      break;
+{%-   endfor %}
+    }
+    if (paramsClass === null)
+      return validator.validationError.NONE;
+    return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes());
+{%- endif %}
+  }
+
+  function validate{{interface.name}}Response(messageValidator) {
+{%- if not(interface|has_callbacks) %}
+    return validator.validationError.NONE;
+{%- else %}
+   var message = messageValidator.message;
+   var paramsClass = null;
+   switch (message.getName()) {
+{%-   for method in interface.methods %}
+{%-     if method.response_parameters != None %}
+      case k{{interface.name}}_{{method.name}}_Name:
+        if (message.isResponse())
+          paramsClass = {{interface.name}}_{{method.name}}_ResponseParams;
+        break;
+{%-     endif %}
+{%-   endfor %}
+    }
+    if (paramsClass === null)
+      return validator.validationError.NONE;
+    return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes());
+{%- endif %}
+  }
+
+  {{interface.name}}Stub.prototype.validator = validate{{interface.name}}Request;
+{%- if interface|has_callbacks %}
+  {{interface.name}}Proxy.prototype.validator = validate{{interface.name}}Response;
+{%- else %}
+  {{interface.name}}Proxy.prototype.validator = null;
+{%- endif -%}
+
+{#--- Enums #}
+{%  from "enum_definition.tmpl" import enum_def -%}
+{%  for enum in interface.enums %}
+  {{enum_def("%sProxy.%s"|format(interface.name, enum.name), enum, module)}}
+  {{interface.name}}Stub.{{enum.name}} = {{interface.name}}Proxy.{{enum.name}};
+{%-  endfor %}
+
+{#--- Constants. #}
+{%  for constant in interface.constants %}
+  {{interface.name}}Proxy.{{constant.name}} = {{constant.value|expression_to_text}};
+  {{interface.name}}Stub.{{constant.name}} = {{interface.name}}Proxy.{{constant.name}};
+{%-  endfor %}
diff --git a/mojo/public/tools/bindings/generators/js_templates/module.js.tmpl b/mojo/public/tools/bindings/generators/js_templates/module.js.tmpl
new file mode 100644
index 0000000..93fa537
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/js_templates/module.js.tmpl
@@ -0,0 +1,53 @@
+// Copyright 2013 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.
+
+define("{{module.path}}", [
+    "mojo/public/js/bindings/codec",
+    "mojo/public/js/bindings/validator",
+{%- for import in imports %}
+    "{{import.module.path}}",
+{%- endfor %}
+  ], function(codec, validator
+{%- for import in imports -%}
+    , {{import.unique_name}}
+{%- endfor -%}
+) {
+
+{#--- Constants #}
+{%  for constant in module.constants %}
+  var {{constant.name}} = {{constant.value|expression_to_text}};
+{%- endfor %}
+
+{#--- Enums #}
+{%- from "enum_definition.tmpl" import enum_def %}
+{%- for enum in enums %}
+  var {{ enum_def(enum.name, enum, module) }}
+{%-  endfor %}
+
+{#--- Struct definitions #}
+{%  for struct in structs %}
+{%-   include "struct_definition.tmpl" %}
+{%- endfor -%}
+
+{#--- Interface definitions #}
+{%- for interface in interfaces -%}
+{%-   include "interface_definition.tmpl" %}
+{%- endfor %}
+
+  var exports = {};
+{%-  for constant in module.constants %}
+  exports.{{constant.name}} = {{constant.name}};
+{%- endfor %}
+{%- for enum in enums %}
+  exports.{{enum.name}} = {{enum.name}};
+{%- endfor %}
+{%- for struct in structs if struct.exported %}
+  exports.{{struct.name}} = {{struct.name}};
+{%- endfor %}
+{%- for interface in interfaces %}
+  exports.{{interface.name}}Proxy = {{interface.name}}Proxy;
+  exports.{{interface.name}}Stub = {{interface.name}}Stub;
+{%- endfor %}
+  return exports;
+});
diff --git a/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl
new file mode 100644
index 0000000..d77b28b
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl
@@ -0,0 +1,116 @@
+{#--- Begin #}
+  function {{struct.name}}(values) {
+    this.initDefaults_();
+    this.initFields_(values);
+  }
+
+{#--- Enums #}
+{%- from "enum_definition.tmpl" import enum_def %}
+{%  for enum in struct.enums %}
+  {{enum_def("%s.%s"|format(struct.name, enum.name), enum, module)}}
+{%-  endfor %}
+
+{#--- Constants #}
+{%  for constant in struct.constants %}
+  {{struct.name}}.{{constant.name}} = {{constant.value|expression_to_text}};
+{%-  endfor %}
+
+{#--- initDefaults() #}
+  {{struct.name}}.prototype.initDefaults_ = function() {
+{%- for packed_field in struct.packed.packed_fields %}
+    this.{{packed_field.field.name}} = {{packed_field.field|default_value}};
+{%- endfor %}
+  };
+
+{#--- initFields() #}
+  {{struct.name}}.prototype.initFields_ = function(fields) {
+    for(var field in fields) {
+        if (this.hasOwnProperty(field))
+          this[field] = fields[field];
+    }
+  };
+
+{#--- Validation #}
+
+  {{struct.name}}.validate = function(messageValidator, offset) {
+    var err;
+{% macro check_err() -%}
+    if (err !== validator.validationError.NONE)
+        return err;
+{%- endmacro %}
+    err = messageValidator.validateStructHeader(offset, {{struct.name}}.encodedSize, {{struct.packed.packed_fields|length}});
+    {{check_err()}}
+
+{%- for packed_field in struct.packed.packed_fields %}
+{%-   set field_name = packed_field.field.name %}
+{%-   if packed_field.field|is_string_pointer_field %}
+    // validate {{struct.name}}.{{field_name}}
+    err = messageValidator.validateStringPointer({{packed_field|validate_string_params}})
+    {{check_err()}}
+{%-   elif packed_field.field|is_array_pointer_field %}
+    // validate {{struct.name}}.{{field_name}}
+    err = messageValidator.validateArrayPointer({{packed_field|validate_array_params}});
+    {{check_err()}}
+{%-   elif packed_field.field|is_struct_pointer_field %}
+    // validate {{struct.name}}.{{field_name}}
+    err = messageValidator.validateStructPointer({{packed_field|validate_struct_params}});
+    {{check_err()}}
+{%-   elif packed_field.field|is_handle_field %}
+    // validate {{struct.name}}.{{field_name}}
+    err = messageValidator.validateHandle({{packed_field|validate_handle_params}})
+    {{check_err()}}
+{%-   endif %}
+{%- endfor %}
+
+    return validator.validationError.NONE;
+  };
+
+{#--- Encoding and decoding #}
+
+  {{struct.name}}.encodedSize = codec.kStructHeaderSize + {{struct.packed|payload_size}};
+
+  {{struct.name}}.decode = function(decoder) {
+    var packed;
+    var val = new {{struct.name}}();
+    var numberOfBytes = decoder.readUint32();
+    var numberOfFields = decoder.readUint32();
+{%- for byte in struct.bytes %}
+{%-   if byte.packed_fields|length > 1 %}
+    packed = decoder.readUint8();
+{%-     for packed_field in byte.packed_fields %}
+    val.{{packed_field.field.name}} = (packed >> {{packed_field.bit}}) & 1 ? true : false;
+{%-     endfor %}
+{%-   else %}
+{%-     for packed_field in byte.packed_fields %}
+    val.{{packed_field.field.name}} = decoder.{{packed_field.field.kind|decode_snippet}};
+{%-     endfor %}
+{%-   endif %}
+{%-   if byte.is_padding %}
+    decoder.skip(1);
+{%-   endif %}
+{%- endfor %}
+    return val;
+  };
+
+  {{struct.name}}.encode = function(encoder, val) {
+    var packed;
+    encoder.writeUint32({{struct.name}}.encodedSize);
+    encoder.writeUint32({{struct.packed.packed_fields|length}});
+
+{%- for byte in struct.bytes %}
+{%-   if byte.packed_fields|length > 1 %}
+    packed = 0;
+{%-     for packed_field in byte.packed_fields %}
+    packed |= (val.{{packed_field.field.name}} & 1) << {{packed_field.bit}}
+{%-     endfor %}
+    encoder.writeUint8(packed);
+{%-   else %}
+{%-     for packed_field in byte.packed_fields %}
+    encoder.{{packed_field.field.kind|encode_snippet}}val.{{packed_field.field.name}});
+{%-     endfor %}
+{%-   endif %}
+{%-   if byte.is_padding %}
+    encoder.skip(1);
+{%-   endif %}
+{%- endfor %}
+  };
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
new file mode 100644
index 0000000..68e0379
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -0,0 +1,338 @@
+# Copyright 2013 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.
+
+"""Generates C++ source files from a mojom.Module."""
+
+import mojom.generate.generator as generator
+import mojom.generate.module as mojom
+import mojom.generate.pack as pack
+from mojom.generate.template_expander import UseJinja
+
+
+_kind_to_cpp_type = {
+  mojom.BOOL:                  "bool",
+  mojom.INT8:                  "int8_t",
+  mojom.UINT8:                 "uint8_t",
+  mojom.INT16:                 "int16_t",
+  mojom.UINT16:                "uint16_t",
+  mojom.INT32:                 "int32_t",
+  mojom.UINT32:                "uint32_t",
+  mojom.FLOAT:                 "float",
+  mojom.HANDLE:                "mojo::Handle",
+  mojom.DCPIPE:                "mojo::DataPipeConsumerHandle",
+  mojom.DPPIPE:                "mojo::DataPipeProducerHandle",
+  mojom.MSGPIPE:               "mojo::MessagePipeHandle",
+  mojom.SHAREDBUFFER:          "mojo::SharedBufferHandle",
+  mojom.NULLABLE_HANDLE:       "mojo::Handle",
+  mojom.NULLABLE_DCPIPE:       "mojo::DataPipeConsumerHandle",
+  mojom.NULLABLE_DPPIPE:       "mojo::DataPipeProducerHandle",
+  mojom.NULLABLE_MSGPIPE:      "mojo::MessagePipeHandle",
+  mojom.NULLABLE_SHAREDBUFFER: "mojo::SharedBufferHandle",
+  mojom.INT64:                 "int64_t",
+  mojom.UINT64:                "uint64_t",
+  mojom.DOUBLE:                "double",
+}
+
+_kind_to_cpp_literal_suffix = {
+  mojom.UINT8:        "U",
+  mojom.UINT16:       "U",
+  mojom.UINT32:       "U",
+  mojom.FLOAT:        "f",
+  mojom.UINT64:       "ULL",
+}
+
+def ConstantValue(constant):
+  return ExpressionToText(constant.value, kind=constant.kind)
+
+def DefaultValue(field):
+  if field.default:
+    if mojom.IsStructKind(field.kind):
+      assert field.default == "default"
+      return "%s::New()" % GetNameForKind(field.kind)
+    return ExpressionToText(field.default, kind=field.kind)
+  return ""
+
+def NamespaceToArray(namespace):
+  return namespace.split('.') if namespace else []
+
+def GetNameForKind(kind, internal = False):
+  parts = []
+  if kind.imported_from:
+    parts.extend(NamespaceToArray(kind.imported_from["namespace"]))
+  if internal:
+    parts.append("internal")
+  if kind.parent_kind:
+    parts.append(kind.parent_kind.name)
+  parts.append(kind.name)
+  return "::".join(parts)
+
+def GetCppType(kind):
+  if mojom.IsStructKind(kind):
+    return "%s_Data*" % GetNameForKind(kind, internal=True)
+  if mojom.IsAnyArrayKind(kind):
+    return "mojo::internal::Array_Data<%s>*" % GetCppType(kind.kind)
+  if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind):
+    return "mojo::MessagePipeHandle"
+  if mojom.IsEnumKind(kind):
+    return "int32_t"
+  if mojom.IsStringKind(kind):
+    return "mojo::internal::String_Data*"
+  return _kind_to_cpp_type[kind]
+
+def GetCppPodType(kind):
+  if mojom.IsStringKind(kind):
+    return "char*"
+  return _kind_to_cpp_type[kind]
+
+def GetCppArrayArgWrapperType(kind):
+  if mojom.IsEnumKind(kind):
+    return GetNameForKind(kind)
+  if mojom.IsStructKind(kind):
+    return "%sPtr" % GetNameForKind(kind)
+  if mojom.IsAnyArrayKind(kind):
+    return "mojo::Array<%s> " % GetCppArrayArgWrapperType(kind.kind)
+  if mojom.IsInterfaceKind(kind):
+    raise Exception("Arrays of interfaces not yet supported!")
+  if mojom.IsInterfaceRequestKind(kind):
+    raise Exception("Arrays of interface requests not yet supported!")
+  if mojom.IsStringKind(kind):
+    return "mojo::String"
+  if mojom.IsHandleKind(kind):
+    return "mojo::ScopedHandle"
+  if mojom.IsDataPipeConsumerKind(kind):
+    return "mojo::ScopedDataPipeConsumerHandle"
+  if mojom.IsDataPipeProducerKind(kind):
+    return "mojo::ScopedDataPipeProducerHandle"
+  if mojom.IsMessagePipeKind(kind):
+    return "mojo::ScopedMessagePipeHandle"
+  if mojom.IsSharedBufferKind(kind):
+    return "mojo::ScopedSharedBufferHandle"
+  return _kind_to_cpp_type[kind]
+
+def GetCppResultWrapperType(kind):
+  if mojom.IsEnumKind(kind):
+    return GetNameForKind(kind)
+  if mojom.IsStructKind(kind):
+    return "%sPtr" % GetNameForKind(kind)
+  if mojom.IsAnyArrayKind(kind):
+    return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind)
+  if mojom.IsInterfaceKind(kind):
+    return "%sPtr" % GetNameForKind(kind)
+  if mojom.IsInterfaceRequestKind(kind):
+    return "mojo::InterfaceRequest<%s>" % GetNameForKind(kind.kind)
+  if mojom.IsStringKind(kind):
+    return "mojo::String"
+  if mojom.IsHandleKind(kind):
+    return "mojo::ScopedHandle"
+  if mojom.IsDataPipeConsumerKind(kind):
+    return "mojo::ScopedDataPipeConsumerHandle"
+  if mojom.IsDataPipeProducerKind(kind):
+    return "mojo::ScopedDataPipeProducerHandle"
+  if mojom.IsMessagePipeKind(kind):
+    return "mojo::ScopedMessagePipeHandle"
+  if mojom.IsSharedBufferKind(kind):
+    return "mojo::ScopedSharedBufferHandle"
+  return _kind_to_cpp_type[kind]
+
+def GetCppWrapperType(kind):
+  if mojom.IsEnumKind(kind):
+    return GetNameForKind(kind)
+  if mojom.IsStructKind(kind):
+    return "%sPtr" % GetNameForKind(kind)
+  if mojom.IsAnyArrayKind(kind):
+    return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind)
+  if mojom.IsInterfaceKind(kind):
+    return "%sPtr" % GetNameForKind(kind)
+  if mojom.IsInterfaceRequestKind(kind):
+    raise Exception("InterfaceRequest fields not supported!")
+  if mojom.IsStringKind(kind):
+    return "mojo::String"
+  if mojom.IsHandleKind(kind):
+    return "mojo::ScopedHandle"
+  if mojom.IsDataPipeConsumerKind(kind):
+    return "mojo::ScopedDataPipeConsumerHandle"
+  if mojom.IsDataPipeProducerKind(kind):
+    return "mojo::ScopedDataPipeProducerHandle"
+  if mojom.IsMessagePipeKind(kind):
+    return "mojo::ScopedMessagePipeHandle"
+  if mojom.IsSharedBufferKind(kind):
+    return "mojo::ScopedSharedBufferHandle"
+  return _kind_to_cpp_type[kind]
+
+def GetCppConstWrapperType(kind):
+  if mojom.IsStructKind(kind):
+    return "%sPtr" % GetNameForKind(kind)
+  if mojom.IsAnyArrayKind(kind):
+    return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind)
+  if mojom.IsInterfaceKind(kind):
+    return "%sPtr" % GetNameForKind(kind)
+  if mojom.IsInterfaceRequestKind(kind):
+    return "mojo::InterfaceRequest<%s>" % GetNameForKind(kind.kind)
+  if mojom.IsEnumKind(kind):
+    return GetNameForKind(kind)
+  if mojom.IsStringKind(kind):
+    return "const mojo::String&"
+  if mojom.IsHandleKind(kind):
+    return "mojo::ScopedHandle"
+  if mojom.IsDataPipeConsumerKind(kind):
+    return "mojo::ScopedDataPipeConsumerHandle"
+  if mojom.IsDataPipeProducerKind(kind):
+    return "mojo::ScopedDataPipeProducerHandle"
+  if mojom.IsMessagePipeKind(kind):
+    return "mojo::ScopedMessagePipeHandle"
+  if mojom.IsSharedBufferKind(kind):
+    return "mojo::ScopedSharedBufferHandle"
+  if not kind in _kind_to_cpp_type:
+    print "missing:", kind.spec
+  return _kind_to_cpp_type[kind]
+
+def GetCppFieldType(kind):
+  if mojom.IsStructKind(kind):
+    return ("mojo::internal::StructPointer<%s_Data>" %
+        GetNameForKind(kind, internal=True))
+  if mojom.IsAnyArrayKind(kind):
+    return "mojo::internal::ArrayPointer<%s>" % GetCppType(kind.kind)
+  if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind):
+    return "mojo::MessagePipeHandle"
+  if mojom.IsEnumKind(kind):
+    return GetNameForKind(kind)
+  if mojom.IsStringKind(kind):
+    return "mojo::internal::StringPointer"
+  return _kind_to_cpp_type[kind]
+
+def IsStructWithHandles(struct):
+  for pf in struct.packed.packed_fields:
+    if mojom.IsAnyHandleKind(pf.field.kind):
+      return True
+  return False
+
+def TranslateConstants(token, kind):
+  if isinstance(token, mojom.NamedValue):
+    # Both variable and enum constants are constructed like:
+    # Namespace::Struct::CONSTANT_NAME
+    # For enums, CONSTANT_NAME is ENUM_NAME_ENUM_VALUE.
+    name = []
+    if token.imported_from:
+      name.extend(NamespaceToArray(token.namespace))
+    if token.parent_kind:
+      name.append(token.parent_kind.name)
+    if isinstance(token, mojom.EnumValue):
+      name.append(
+          "%s_%s" % (generator.CamelCaseToAllCaps(token.enum.name), token.name))
+    else:
+      name.append(token.name)
+    return "::".join(name)
+
+  if isinstance(token, mojom.BuiltinValue):
+    if token.value == "double.INFINITY" or token.value == "float.INFINITY":
+      return "INFINITY";
+    if token.value == "double.NEGATIVE_INFINITY" or \
+       token.value == "float.NEGATIVE_INFINITY":
+      return "-INFINITY";
+    if token.value == "double.NAN" or token.value == "float.NAN":
+      return "NAN";
+
+  if (kind is not None and mojom.IsFloatKind(kind)):
+      return token if token.isdigit() else token + "f";
+
+  return '%s%s' % (token, _kind_to_cpp_literal_suffix.get(kind, ''))
+
+def ExpressionToText(value, kind=None):
+  return TranslateConstants(value, kind)
+
+def ShouldInlineStruct(struct):
+  # TODO(darin): Base this on the size of the wrapper class.
+  if len(struct.fields) > 4:
+    return False
+  for field in struct.fields:
+    if mojom.IsMoveOnlyKind(field.kind):
+      return False
+  return True
+
+def GetArrayValidateParams(kind):
+  if not mojom.IsAnyArrayKind(kind) and not mojom.IsStringKind(kind):
+    return "mojo::internal::NoValidateParams"
+
+  if mojom.IsStringKind(kind):
+    expected_num_elements = 0
+    element_is_nullable = False
+    element_validate_params = "mojo::internal::NoValidateParams"
+  else:
+    expected_num_elements = generator.ExpectedArraySize(kind)
+    element_is_nullable = mojom.IsNullableKind(kind.kind)
+    element_validate_params = GetArrayValidateParams(kind.kind)
+
+  return "mojo::internal::ArrayValidateParams<%d, %s,\n%s> " % (
+      expected_num_elements,
+      'true' if element_is_nullable else 'false',
+      element_validate_params)
+
+_HEADER_SIZE = 8
+
+class Generator(generator.Generator):
+
+  cpp_filters = {
+    "constant_value": ConstantValue,
+    "cpp_const_wrapper_type": GetCppConstWrapperType,
+    "cpp_field_type": GetCppFieldType,
+    "cpp_pod_type": GetCppPodType,
+    "cpp_result_type": GetCppResultWrapperType,
+    "cpp_type": GetCppType,
+    "cpp_wrapper_type": GetCppWrapperType,
+    "default_value": DefaultValue,
+    "expected_array_size": generator.ExpectedArraySize,
+    "expression_to_text": ExpressionToText,
+    "get_array_validate_params": GetArrayValidateParams,
+    "get_name_for_kind": GetNameForKind,
+    "get_pad": pack.GetPad,
+    "has_callbacks": mojom.HasCallbacks,
+    "should_inline": ShouldInlineStruct,
+    "is_any_array_kind": mojom.IsAnyArrayKind,
+    "is_cloneable_kind": mojom.IsCloneableKind,
+    "is_enum_kind": mojom.IsEnumKind,
+    "is_move_only_kind": mojom.IsMoveOnlyKind,
+    "is_any_handle_kind": mojom.IsAnyHandleKind,
+    "is_interface_kind": mojom.IsInterfaceKind,
+    "is_interface_request_kind": mojom.IsInterfaceRequestKind,
+    "is_nullable_kind": mojom.IsNullableKind,
+    "is_object_kind": mojom.IsObjectKind,
+    "is_string_kind": mojom.IsStringKind,
+    "is_struct_kind": mojom.IsStructKind,
+    "is_struct_with_handles": IsStructWithHandles,
+    "struct_size": lambda ps: ps.GetTotalSize() + _HEADER_SIZE,
+    "struct_from_method": generator.GetStructFromMethod,
+    "response_struct_from_method": generator.GetResponseStructFromMethod,
+    "stylize_method": generator.StudlyCapsToCamel,
+    "to_all_caps": generator.CamelCaseToAllCaps,
+  }
+
+  def GetJinjaExports(self):
+    return {
+      "module": self.module,
+      "namespace": self.module.namespace,
+      "namespaces_as_array": NamespaceToArray(self.module.namespace),
+      "imports": self.module.imports,
+      "kinds": self.module.kinds,
+      "enums": self.module.enums,
+      "structs": self.GetStructs(),
+      "interfaces": self.module.interfaces,
+    }
+
+  @UseJinja("cpp_templates/module.h.tmpl", filters=cpp_filters)
+  def GenerateModuleHeader(self):
+    return self.GetJinjaExports()
+
+  @UseJinja("cpp_templates/module-internal.h.tmpl", filters=cpp_filters)
+  def GenerateModuleInternalHeader(self):
+    return self.GetJinjaExports()
+
+  @UseJinja("cpp_templates/module.cc.tmpl", filters=cpp_filters)
+  def GenerateModuleSource(self):
+    return self.GetJinjaExports()
+
+  def GenerateFiles(self, args):
+    self.Write(self.GenerateModuleHeader(), "%s.h" % self.module.name)
+    self.Write(self.GenerateModuleInternalHeader(),
+        "%s-internal.h" % self.module.name)
+    self.Write(self.GenerateModuleSource(), "%s.cc" % self.module.name)
diff --git a/mojo/public/tools/bindings/generators/mojom_java_generator.py b/mojo/public/tools/bindings/generators/mojom_java_generator.py
new file mode 100644
index 0000000..043d9e3
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/mojom_java_generator.py
@@ -0,0 +1,504 @@
+# Copyright 2014 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.
+
+"""Generates java source files from a mojom.Module."""
+
+import argparse
+import ast
+import contextlib
+import os
+import re
+import shutil
+import tempfile
+import zipfile
+
+from jinja2 import contextfilter
+
+import mojom.generate.generator as generator
+import mojom.generate.module as mojom
+from mojom.generate.template_expander import UseJinja
+
+
+GENERATOR_PREFIX = 'java'
+
+_HEADER_SIZE = 8
+
+_spec_to_java_type = {
+  mojom.BOOL.spec: 'boolean',
+  mojom.DCPIPE.spec: 'org.chromium.mojo.system.DataPipe.ConsumerHandle',
+  mojom.DOUBLE.spec: 'double',
+  mojom.DPPIPE.spec: 'org.chromium.mojo.system.DataPipe.ProducerHandle',
+  mojom.FLOAT.spec: 'float',
+  mojom.HANDLE.spec: 'org.chromium.mojo.system.UntypedHandle',
+  mojom.INT16.spec: 'short',
+  mojom.INT32.spec: 'int',
+  mojom.INT64.spec: 'long',
+  mojom.INT8.spec: 'byte',
+  mojom.MSGPIPE.spec: 'org.chromium.mojo.system.MessagePipeHandle',
+  mojom.NULLABLE_DCPIPE.spec:
+      'org.chromium.mojo.system.DataPipe.ConsumerHandle',
+  mojom.NULLABLE_DPPIPE.spec:
+      'org.chromium.mojo.system.DataPipe.ProducerHandle',
+  mojom.NULLABLE_HANDLE.spec: 'org.chromium.mojo.system.UntypedHandle',
+  mojom.NULLABLE_MSGPIPE.spec: 'org.chromium.mojo.system.MessagePipeHandle',
+  mojom.NULLABLE_SHAREDBUFFER.spec:
+      'org.chromium.mojo.system.SharedBufferHandle',
+  mojom.NULLABLE_STRING.spec: 'String',
+  mojom.SHAREDBUFFER.spec: 'org.chromium.mojo.system.SharedBufferHandle',
+  mojom.STRING.spec: 'String',
+  mojom.UINT16.spec: 'short',
+  mojom.UINT32.spec: 'int',
+  mojom.UINT64.spec: 'long',
+  mojom.UINT8.spec: 'byte',
+}
+
+_spec_to_decode_method = {
+  mojom.BOOL.spec:                  'readBoolean',
+  mojom.DCPIPE.spec:                'readConsumerHandle',
+  mojom.DOUBLE.spec:                'readDouble',
+  mojom.DPPIPE.spec:                'readProducerHandle',
+  mojom.FLOAT.spec:                 'readFloat',
+  mojom.HANDLE.spec:                'readUntypedHandle',
+  mojom.INT16.spec:                 'readShort',
+  mojom.INT32.spec:                 'readInt',
+  mojom.INT64.spec:                 'readLong',
+  mojom.INT8.spec:                  'readByte',
+  mojom.MSGPIPE.spec:               'readMessagePipeHandle',
+  mojom.NULLABLE_DCPIPE.spec:       'readConsumerHandle',
+  mojom.NULLABLE_DPPIPE.spec:       'readProducerHandle',
+  mojom.NULLABLE_HANDLE.spec:       'readUntypedHandle',
+  mojom.NULLABLE_MSGPIPE.spec:      'readMessagePipeHandle',
+  mojom.NULLABLE_SHAREDBUFFER.spec: 'readSharedBufferHandle',
+  mojom.NULLABLE_STRING.spec:       'readString',
+  mojom.SHAREDBUFFER.spec:          'readSharedBufferHandle',
+  mojom.STRING.spec:                'readString',
+  mojom.UINT16.spec:                'readShort',
+  mojom.UINT32.spec:                'readInt',
+  mojom.UINT64.spec:                'readLong',
+  mojom.UINT8.spec:                 'readByte',
+}
+
+_java_primitive_to_boxed_type = {
+  'boolean': 'Boolean',
+  'byte':    'Byte',
+  'double':  'Double',
+  'float':   'Float',
+  'int':     'Integer',
+  'long':    'Long',
+  'short':   'Short',
+}
+
+
+def NameToComponent(name):
+  # insert '_' between anything and a Title name (e.g, HTTPEntry2FooBar ->
+  # HTTP_Entry2_FooBar)
+  name = re.sub('([^_])([A-Z][^A-Z_]+)', r'\1_\2', name)
+  # insert '_' between non upper and start of upper blocks (e.g.,
+  # HTTP_Entry2_FooBar -> HTTP_Entry2_Foo_Bar)
+  name = re.sub('([^A-Z_])([A-Z])', r'\1_\2', name)
+  return [x.lower() for x in name.split('_')]
+
+def UpperCamelCase(name):
+  return ''.join([x.capitalize() for x in NameToComponent(name)])
+
+def CamelCase(name):
+  uccc = UpperCamelCase(name)
+  return uccc[0].lower() + uccc[1:]
+
+def ConstantStyle(name):
+  components = NameToComponent(name)
+  if components[0] == 'k' and len(components) > 1:
+    components = components[1:]
+  # variable cannot starts with a digit.
+  if components[0][0].isdigit():
+    components[0] = '_' + components[0]
+  return '_'.join([x.upper() for x in components])
+
+def GetNameForElement(element):
+  if (mojom.IsEnumKind(element) or mojom.IsInterfaceKind(element) or
+      mojom.IsStructKind(element)):
+    return UpperCamelCase(element.name)
+  if mojom.IsInterfaceRequestKind(element):
+    return GetNameForElement(element.kind)
+  if isinstance(element, (mojom.Method,
+                          mojom.Parameter,
+                          mojom.Field)):
+    return CamelCase(element.name)
+  if isinstance(element,  mojom.EnumValue):
+    return (GetNameForElement(element.enum) + '.' +
+            ConstantStyle(element.name))
+  if isinstance(element, (mojom.NamedValue,
+                          mojom.Constant,
+                          mojom.EnumField)):
+    return ConstantStyle(element.name)
+  raise Exception('Unexpected element: %s' % element)
+
+def GetInterfaceResponseName(method):
+  return UpperCamelCase(method.name + 'Response')
+
+def ParseStringAttribute(attribute):
+  assert isinstance(attribute, basestring)
+  return attribute
+
+def GetJavaTrueFalse(value):
+  return 'true' if value else 'false'
+
+def GetArrayNullabilityFlags(kind):
+    """Returns nullability flags for an array type, see Decoder.java.
+
+    As we have dedicated decoding functions for arrays, we have to pass
+    nullability information about both the array itself, as well as the array
+    element type there.
+    """
+    assert mojom.IsAnyArrayKind(kind)
+    ARRAY_NULLABLE   = \
+        'org.chromium.mojo.bindings.BindingsHelper.ARRAY_NULLABLE'
+    ELEMENT_NULLABLE = \
+        'org.chromium.mojo.bindings.BindingsHelper.ELEMENT_NULLABLE'
+    NOTHING_NULLABLE = \
+        'org.chromium.mojo.bindings.BindingsHelper.NOTHING_NULLABLE'
+
+    flags_to_set = []
+    if mojom.IsNullableKind(kind):
+        flags_to_set.append(ARRAY_NULLABLE)
+    if mojom.IsNullableKind(kind.kind):
+        flags_to_set.append(ELEMENT_NULLABLE)
+
+    if not flags_to_set:
+        flags_to_set = [NOTHING_NULLABLE]
+    return ' | '.join(flags_to_set)
+
+
+def AppendEncodeDecodeParams(initial_params, context, kind, bit):
+  """ Appends standard parameters shared between encode and decode calls. """
+  params = list(initial_params)
+  if (kind == mojom.BOOL):
+    params.append(str(bit))
+  if mojom.IsReferenceKind(kind):
+    if mojom.IsAnyArrayKind(kind):
+      params.append(GetArrayNullabilityFlags(kind))
+    else:
+      params.append(GetJavaTrueFalse(mojom.IsNullableKind(kind)))
+  if mojom.IsAnyArrayKind(kind):
+    if mojom.IsFixedArrayKind(kind):
+      params.append(str(kind.length))
+    else:
+      params.append(
+        'org.chromium.mojo.bindings.BindingsHelper.UNSPECIFIED_ARRAY_LENGTH');
+  if mojom.IsInterfaceKind(kind):
+    params.append('%s.MANAGER' % GetJavaType(context, kind))
+  if mojom.IsAnyArrayKind(kind) and mojom.IsInterfaceKind(kind.kind):
+    params.append('%s.MANAGER' % GetJavaType(context, kind.kind))
+  return params
+
+
+@contextfilter
+def DecodeMethod(context, kind, offset, bit):
+  def _DecodeMethodName(kind):
+    if mojom.IsAnyArrayKind(kind):
+      return _DecodeMethodName(kind.kind) + 's'
+    if mojom.IsEnumKind(kind):
+      return _DecodeMethodName(mojom.INT32)
+    if mojom.IsInterfaceRequestKind(kind):
+      return 'readInterfaceRequest'
+    if mojom.IsInterfaceKind(kind):
+      return 'readServiceInterface'
+    return _spec_to_decode_method[kind.spec]
+  methodName = _DecodeMethodName(kind)
+  params = AppendEncodeDecodeParams([ str(offset) ], context, kind, bit)
+  return '%s(%s)' % (methodName, ', '.join(params))
+
+@contextfilter
+def EncodeMethod(context, kind, variable, offset, bit):
+  params = AppendEncodeDecodeParams(
+      [ variable, str(offset) ], context, kind, bit)
+  return 'encode(%s)' % ', '.join(params)
+
+def GetPackage(module):
+  if 'JavaPackage' in module.attributes:
+    return ParseStringAttribute(module.attributes['JavaPackage'])
+  # Default package.
+  if module.namespace:
+    return 'org.chromium.mojom.' + module.namespace
+  return 'org.chromium.mojom'
+
+def GetNameForKind(context, kind):
+  def _GetNameHierachy(kind):
+    hierachy = []
+    if kind.parent_kind:
+      hierachy = _GetNameHierachy(kind.parent_kind)
+    hierachy.append(GetNameForElement(kind))
+    return hierachy
+
+  module = context.resolve('module')
+  elements = []
+  if GetPackage(module) != GetPackage(kind.module):
+    elements += [GetPackage(kind.module)]
+  elements += _GetNameHierachy(kind)
+  return '.'.join(elements)
+
+def GetBoxedJavaType(context, kind):
+  unboxed_type = GetJavaType(context, kind, False)
+  if unboxed_type in _java_primitive_to_boxed_type:
+    return _java_primitive_to_boxed_type[unboxed_type]
+  return unboxed_type
+
+@contextfilter
+def GetJavaType(context, kind, boxed=False):
+  if boxed:
+    return GetBoxedJavaType(context, kind)
+  if mojom.IsStructKind(kind) or mojom.IsInterfaceKind(kind):
+    return GetNameForKind(context, kind)
+  if mojom.IsInterfaceRequestKind(kind):
+    return ('org.chromium.mojo.bindings.InterfaceRequest<%s>' %
+            GetNameForKind(context, kind.kind))
+  if mojom.IsAnyArrayKind(kind):
+    return '%s[]' % GetJavaType(context, kind.kind)
+  if mojom.IsEnumKind(kind):
+    return 'int'
+  return _spec_to_java_type[kind.spec]
+
+@contextfilter
+def DefaultValue(context, field):
+  assert field.default
+  if isinstance(field.kind, mojom.Struct):
+    assert field.default == 'default'
+    return 'new %s()' % GetJavaType(context, field.kind)
+  return '(%s) %s' % (
+      GetJavaType(context, field.kind),
+      ExpressionToText(context, field.default, kind_spec=field.kind.spec))
+
+@contextfilter
+def ConstantValue(context, constant):
+  return '(%s) %s' % (
+      GetJavaType(context, constant.kind),
+      ExpressionToText(context, constant.value, kind_spec=constant.kind.spec))
+
+@contextfilter
+def NewArray(context, kind, size):
+  if mojom.IsAnyArrayKind(kind.kind):
+    return NewArray(context, kind.kind, size) + '[]'
+  return 'new %s[%s]' % (GetJavaType(context, kind.kind), size)
+
+@contextfilter
+def ExpressionToText(context, token, kind_spec=''):
+  def _TranslateNamedValue(named_value):
+    entity_name = GetNameForElement(named_value)
+    if named_value.parent_kind:
+      return GetJavaType(context, named_value.parent_kind) + '.' + entity_name
+    # Handle the case where named_value is a module level constant:
+    if not isinstance(named_value, mojom.EnumValue):
+      entity_name = (GetConstantsMainEntityName(named_value.module) + '.' +
+                      entity_name)
+    if GetPackage(named_value.module) == GetPackage(context.resolve('module')):
+      return entity_name
+    return GetPackage(named_value.module) + '.' + entity_name
+
+  if isinstance(token, mojom.NamedValue):
+    return _TranslateNamedValue(token)
+  if kind_spec.startswith('i') or kind_spec.startswith('u'):
+    # Add Long suffix to all integer literals.
+    number = ast.literal_eval(token.lstrip('+ '))
+    if not isinstance(number, (int, long)):
+      raise ValueError('got unexpected type %r for int literal %r' % (
+          type(number), token))
+    # If the literal is too large to fit a signed long, convert it to the
+    # equivalent signed long.
+    if number >= 2 ** 63:
+      number -= 2 ** 64
+    return '%dL' % number
+  if isinstance(token, mojom.BuiltinValue):
+    if token.value == 'double.INFINITY':
+      return 'java.lang.Double.POSITIVE_INFINITY'
+    if token.value == 'double.NEGATIVE_INFINITY':
+      return 'java.lang.Double.NEGATIVE_INFINITY'
+    if token.value == 'double.NAN':
+      return 'java.lang.Double.NaN'
+    if token.value == 'float.INFINITY':
+      return 'java.lang.Float.POSITIVE_INFINITY'
+    if token.value == 'float.NEGATIVE_INFINITY':
+      return 'java.lang.Float.NEGATIVE_INFINITY'
+    if token.value == 'float.NAN':
+      return 'java.lang.Float.NaN'
+  return token
+
+def IsPointerArrayKind(kind):
+  if not mojom.IsAnyArrayKind(kind):
+    return False
+  sub_kind = kind.kind
+  return mojom.IsObjectKind(sub_kind)
+
+def GetResponseStructFromMethod(method):
+  return generator.GetDataHeader(
+      False, generator.GetResponseStructFromMethod(method))
+
+def GetStructFromMethod(method):
+  return generator.GetDataHeader(
+      False, generator.GetStructFromMethod(method))
+
+def GetConstantsMainEntityName(module):
+  if 'JavaConstantsClassName' in module.attributes:
+    return ParseStringAttribute(module.attributes['JavaConstantsClassName'])
+  # This constructs the name of the embedding classes for module level constants
+  # by extracting the mojom's filename and prepending it to Constants.
+  return (UpperCamelCase(module.path.split('/')[-1].rsplit('.', 1)[0]) +
+          'Constants')
+
+def GetMethodOrdinalName(method):
+  return ConstantStyle(method.name) + '_ORDINAL'
+
+def HasMethodWithResponse(interface):
+  for method in interface.methods:
+    if method.response_parameters is not None:
+      return True
+  return False
+
+def HasMethodWithoutResponse(interface):
+  for method in interface.methods:
+    if method.response_parameters is None:
+      return True
+  return False
+
+@contextlib.contextmanager
+def TempDir():
+  dirname = tempfile.mkdtemp()
+  try:
+    yield dirname
+  finally:
+    shutil.rmtree(dirname)
+
+def ZipContentInto(root, zip_filename):
+  with zipfile.ZipFile(zip_filename, 'w') as zip_file:
+    for dirname, _, files in os.walk(root):
+      for filename in files:
+        path = os.path.join(dirname, filename)
+        path_in_archive = os.path.relpath(path, root)
+        zip_file.write(path, path_in_archive)
+
+class Generator(generator.Generator):
+
+  java_filters = {
+    'interface_response_name': GetInterfaceResponseName,
+    'constant_value': ConstantValue,
+    'default_value': DefaultValue,
+    'decode_method': DecodeMethod,
+    'expression_to_text': ExpressionToText,
+    'encode_method': EncodeMethod,
+    'has_method_with_response': HasMethodWithResponse,
+    'has_method_without_response': HasMethodWithoutResponse,
+    'is_fixed_array_kind': mojom.IsFixedArrayKind,
+    'is_handle': mojom.IsNonInterfaceHandleKind,
+    'is_nullable_kind': mojom.IsNullableKind,
+    'is_pointer_array_kind': IsPointerArrayKind,
+    'is_struct_kind': mojom.IsStructKind,
+    'java_type': GetJavaType,
+    'java_true_false': GetJavaTrueFalse,
+    'method_ordinal_name': GetMethodOrdinalName,
+    'name': GetNameForElement,
+    'new_array': NewArray,
+    'response_struct_from_method': GetResponseStructFromMethod,
+    'struct_from_method': GetStructFromMethod,
+    'struct_size': lambda ps: ps.GetTotalSize() + _HEADER_SIZE,
+  }
+
+  def GetJinjaExports(self):
+    return {
+      'package': GetPackage(self.module),
+    }
+
+  def GetJinjaExportsForInterface(self, interface):
+    exports = self.GetJinjaExports()
+    exports.update({'interface': interface})
+    if interface.client:
+      for client in self.module.interfaces:
+        if client.name == interface.client:
+          exports.update({'client': client})
+    return exports
+
+  @UseJinja('java_templates/enum.java.tmpl', filters=java_filters)
+  def GenerateEnumSource(self, enum):
+    exports = self.GetJinjaExports()
+    exports.update({'enum': enum})
+    return exports
+
+  @UseJinja('java_templates/struct.java.tmpl', filters=java_filters)
+  def GenerateStructSource(self, struct):
+    exports = self.GetJinjaExports()
+    exports.update({'struct': struct})
+    return exports
+
+  @UseJinja('java_templates/interface.java.tmpl', filters=java_filters)
+  def GenerateInterfaceSource(self, interface):
+    return self.GetJinjaExportsForInterface(interface)
+
+  @UseJinja('java_templates/interface_internal.java.tmpl', filters=java_filters)
+  def GenerateInterfaceInternalSource(self, interface):
+    return self.GetJinjaExportsForInterface(interface)
+
+  @UseJinja('java_templates/constants.java.tmpl', filters=java_filters)
+  def GenerateConstantsSource(self, module):
+    exports = self.GetJinjaExports()
+    exports.update({'main_entity': GetConstantsMainEntityName(module),
+                    'constants': module.constants})
+    return exports
+
+  def DoGenerateFiles(self):
+    if not os.path.exists(self.output_dir):
+      try:
+        os.makedirs(self.output_dir)
+      except:
+        # Ignore errors on directory creation.
+        pass
+
+    # Keep this above the others as .GetStructs() changes the state of the
+    # module, annotating structs with required information.
+    for struct in self.GetStructs():
+      self.Write(self.GenerateStructSource(struct),
+                 '%s.java' % GetNameForElement(struct))
+
+    for enum in self.module.enums:
+      self.Write(self.GenerateEnumSource(enum),
+                 '%s.java' % GetNameForElement(enum))
+
+    for interface in self.module.interfaces:
+      self.Write(self.GenerateInterfaceSource(interface),
+                 '%s.java' % GetNameForElement(interface))
+      self.Write(self.GenerateInterfaceInternalSource(interface),
+                 '%s_Internal.java' % GetNameForElement(interface))
+
+    if self.module.constants:
+      self.Write(self.GenerateConstantsSource(self.module),
+                 '%s.java' % GetConstantsMainEntityName(self.module))
+
+  def GenerateFiles(self, unparsed_args):
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--java_output_directory', dest='java_output_directory')
+    args = parser.parse_args(unparsed_args)
+    package_path = GetPackage(self.module).replace('.', '/')
+
+    # Generate the java files in a temporary directory and place a single
+    # srcjar in the output directory.
+    zip_filename = os.path.join(self.output_dir,
+                                "%s.srcjar" % self.module.name)
+    with TempDir() as temp_java_root:
+      self.output_dir = os.path.join(temp_java_root, package_path)
+      self.DoGenerateFiles();
+      ZipContentInto(temp_java_root, zip_filename)
+
+    if args.java_output_directory:
+      # If requested, generate the java files directly into indicated directory.
+      self.output_dir = os.path.join(args.java_output_directory, package_path)
+      self.DoGenerateFiles();
+
+  def GetJinjaParameters(self):
+    return {
+      'lstrip_blocks': True,
+      'trim_blocks': True,
+    }
+
+  def GetGlobals(self):
+    return {
+      'namespace': self.module.namespace,
+      'module': self.module,
+    }
diff --git a/mojo/public/tools/bindings/generators/mojom_js_generator.py b/mojo/public/tools/bindings/generators/mojom_js_generator.py
new file mode 100644
index 0000000..c9109fb
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/mojom_js_generator.py
@@ -0,0 +1,275 @@
+# Copyright 2013 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.
+
+"""Generates JavaScript source files from a mojom.Module."""
+
+import mojom.generate.generator as generator
+import mojom.generate.module as mojom
+import mojom.generate.pack as pack
+from mojom.generate.template_expander import UseJinja
+
+_kind_to_javascript_default_value = {
+  mojom.BOOL:                  "false",
+  mojom.INT8:                  "0",
+  mojom.UINT8:                 "0",
+  mojom.INT16:                 "0",
+  mojom.UINT16:                "0",
+  mojom.INT32:                 "0",
+  mojom.UINT32:                "0",
+  mojom.FLOAT:                 "0",
+  mojom.HANDLE:                "null",
+  mojom.DCPIPE:                "null",
+  mojom.DPPIPE:                "null",
+  mojom.MSGPIPE:               "null",
+  mojom.SHAREDBUFFER:          "null",
+  mojom.NULLABLE_HANDLE:       "null",
+  mojom.NULLABLE_DCPIPE:       "null",
+  mojom.NULLABLE_DPPIPE:       "null",
+  mojom.NULLABLE_MSGPIPE:      "null",
+  mojom.NULLABLE_SHAREDBUFFER: "null",
+  mojom.INT64:                 "0",
+  mojom.UINT64:                "0",
+  mojom.DOUBLE:                "0",
+  mojom.STRING:                "null",
+  mojom.NULLABLE_STRING:       "null"
+}
+
+
+def JavaScriptType(kind):
+  if kind.imported_from:
+    return kind.imported_from["unique_name"] + "." + kind.name
+  return kind.name
+
+
+def JavaScriptDefaultValue(field):
+  if field.default:
+    if mojom.IsStructKind(field.kind):
+      assert field.default == "default"
+      return "new %s()" % JavaScriptType(field.kind)
+    return ExpressionToText(field.default)
+  if field.kind in mojom.PRIMITIVES:
+    return _kind_to_javascript_default_value[field.kind]
+  if mojom.IsStructKind(field.kind):
+    return "null"
+  if mojom.IsAnyArrayKind(field.kind):
+    return "null"
+  if mojom.IsInterfaceKind(field.kind) or \
+     mojom.IsInterfaceRequestKind(field.kind):
+    return _kind_to_javascript_default_value[mojom.MSGPIPE]
+  if mojom.IsEnumKind(field.kind):
+    return "0"
+
+
+def JavaScriptPayloadSize(packed):
+  packed_fields = packed.packed_fields
+  if not packed_fields:
+    return 0
+  last_field = packed_fields[-1]
+  offset = last_field.offset + last_field.size
+  pad = pack.GetPad(offset, 8)
+  return offset + pad
+
+
+_kind_to_codec_type = {
+  mojom.BOOL:                  "codec.Uint8",
+  mojom.INT8:                  "codec.Int8",
+  mojom.UINT8:                 "codec.Uint8",
+  mojom.INT16:                 "codec.Int16",
+  mojom.UINT16:                "codec.Uint16",
+  mojom.INT32:                 "codec.Int32",
+  mojom.UINT32:                "codec.Uint32",
+  mojom.FLOAT:                 "codec.Float",
+  mojom.HANDLE:                "codec.Handle",
+  mojom.DCPIPE:                "codec.Handle",
+  mojom.DPPIPE:                "codec.Handle",
+  mojom.MSGPIPE:               "codec.Handle",
+  mojom.SHAREDBUFFER:          "codec.Handle",
+  mojom.NULLABLE_HANDLE:       "codec.NullableHandle",
+  mojom.NULLABLE_DCPIPE:       "codec.NullableHandle",
+  mojom.NULLABLE_DPPIPE:       "codec.NullableHandle",
+  mojom.NULLABLE_MSGPIPE:      "codec.NullableHandle",
+  mojom.NULLABLE_SHAREDBUFFER: "codec.NullableHandle",
+  mojom.INT64:                 "codec.Int64",
+  mojom.UINT64:                "codec.Uint64",
+  mojom.DOUBLE:                "codec.Double",
+  mojom.STRING:                "codec.String",
+  mojom.NULLABLE_STRING:       "codec.NullableString",
+}
+
+
+def CodecType(kind):
+  if kind in mojom.PRIMITIVES:
+    return _kind_to_codec_type[kind]
+  if mojom.IsStructKind(kind):
+    pointer_type = "NullablePointerTo" if mojom.IsNullableKind(kind) \
+        else "PointerTo"
+    return "new codec.%s(%s)" % (pointer_type, JavaScriptType(kind))
+  if mojom.IsAnyArrayKind(kind):
+    array_type = "NullableArrayOf" if mojom.IsNullableKind(kind) else "ArrayOf"
+    element_type = "codec.PackedBool" if mojom.IsBoolKind(kind.kind) \
+        else CodecType(kind.kind)
+    return "new codec.%s(%s)" % (array_type, element_type)
+  if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind):
+    return CodecType(mojom.MSGPIPE)
+  if mojom.IsEnumKind(kind):
+    return _kind_to_codec_type[mojom.INT32]
+  return kind
+
+
+def JavaScriptDecodeSnippet(kind):
+  if kind in mojom.PRIMITIVES:
+    return "decodeStruct(%s)" % CodecType(kind)
+  if mojom.IsStructKind(kind):
+    return "decodeStructPointer(%s)" % JavaScriptType(kind)
+  if mojom.IsAnyArrayKind(kind) and mojom.IsBoolKind(kind.kind):
+    return "decodeArrayPointer(codec.PackedBool)"
+  if mojom.IsAnyArrayKind(kind):
+    return "decodeArrayPointer(%s)" % CodecType(kind.kind)
+  if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind):
+    return JavaScriptDecodeSnippet(mojom.MSGPIPE)
+  if mojom.IsEnumKind(kind):
+    return JavaScriptDecodeSnippet(mojom.INT32)
+
+
+def JavaScriptEncodeSnippet(kind):
+  if kind in mojom.PRIMITIVES:
+    return "encodeStruct(%s, " % CodecType(kind)
+  if mojom.IsStructKind(kind):
+    return "encodeStructPointer(%s, " % JavaScriptType(kind)
+  if mojom.IsAnyArrayKind(kind) and mojom.IsBoolKind(kind.kind):
+    return "encodeArrayPointer(codec.PackedBool, ";
+  if mojom.IsAnyArrayKind(kind):
+    return "encodeArrayPointer(%s, " % CodecType(kind.kind)
+  if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind):
+    return JavaScriptEncodeSnippet(mojom.MSGPIPE)
+  if mojom.IsEnumKind(kind):
+    return JavaScriptEncodeSnippet(mojom.INT32)
+
+
+def JavaScriptFieldOffset(packed_field):
+  return "offset + codec.kStructHeaderSize + %s" % packed_field.offset
+
+
+def JavaScriptNullableParam(packed_field):
+  return "true" if mojom.IsNullableKind(packed_field.field.kind) else "false"
+
+
+def JavaScriptValidateArrayParams(packed_field):
+  nullable = JavaScriptNullableParam(packed_field)
+  field_offset = JavaScriptFieldOffset(packed_field)
+  element_kind = packed_field.field.kind.kind
+  element_size = pack.PackedField.GetSizeForKind(element_kind)
+  element_count = generator.ExpectedArraySize(packed_field.field.kind)
+  element_type = "codec.PackedBool" if mojom.IsBoolKind(element_kind) \
+      else CodecType(element_kind)
+  return "%s, %s, %s, %s, %s" % \
+      (field_offset, element_size, element_count, element_type, nullable)
+
+
+def JavaScriptValidateStructParams(packed_field):
+  nullable = JavaScriptNullableParam(packed_field)
+  field_offset = JavaScriptFieldOffset(packed_field)
+  struct_type = JavaScriptType(packed_field.field.kind)
+  return "%s, %s, %s" % (field_offset, struct_type, nullable)
+
+
+def JavaScriptValidateStringParams(packed_field):
+  nullable = JavaScriptNullableParam(packed_field)
+  return "%s, %s" % (JavaScriptFieldOffset(packed_field), nullable)
+
+
+def JavaScriptValidateHandleParams(packed_field):
+  nullable = JavaScriptNullableParam(packed_field)
+  field_offset = JavaScriptFieldOffset(packed_field)
+  return "%s, %s" % (field_offset, nullable)
+
+
+def TranslateConstants(token):
+  if isinstance(token, (mojom.EnumValue, mojom.NamedValue)):
+    # Both variable and enum constants are constructed like:
+    # NamespaceUid.Struct[.Enum].CONSTANT_NAME
+    name = []
+    if token.imported_from:
+      name.append(token.imported_from["unique_name"])
+    if token.parent_kind:
+      name.append(token.parent_kind.name)
+    if isinstance(token, mojom.EnumValue):
+      name.append(token.enum.name)
+    name.append(token.name)
+    return ".".join(name)
+
+  if isinstance(token, mojom.BuiltinValue):
+    if token.value == "double.INFINITY" or token.value == "float.INFINITY":
+      return "Infinity";
+    if token.value == "double.NEGATIVE_INFINITY" or \
+       token.value == "float.NEGATIVE_INFINITY":
+      return "-Infinity";
+    if token.value == "double.NAN" or token.value == "float.NAN":
+      return "NaN";
+
+  return token
+
+
+def ExpressionToText(value):
+  return TranslateConstants(value)
+
+
+def IsArrayPointerField(field):
+  return mojom.IsAnyArrayKind(field.kind)
+
+def IsStringPointerField(field):
+  return mojom.IsStringKind(field.kind)
+
+def IsStructPointerField(field):
+  return mojom.IsStructKind(field.kind)
+
+def IsHandleField(field):
+  return mojom.IsAnyHandleKind(field.kind)
+
+
+class Generator(generator.Generator):
+
+  js_filters = {
+    "default_value": JavaScriptDefaultValue,
+    "payload_size": JavaScriptPayloadSize,
+    "decode_snippet": JavaScriptDecodeSnippet,
+    "encode_snippet": JavaScriptEncodeSnippet,
+    "expression_to_text": ExpressionToText,
+    "field_offset": JavaScriptFieldOffset,
+    "has_callbacks": mojom.HasCallbacks,
+    "is_array_pointer_field": IsArrayPointerField,
+    "is_struct_pointer_field": IsStructPointerField,
+    "is_string_pointer_field": IsStringPointerField,
+    "is_handle_field": IsHandleField,
+    "js_type": JavaScriptType,
+    "stylize_method": generator.StudlyCapsToCamel,
+    "validate_array_params": JavaScriptValidateArrayParams,
+    "validate_handle_params": JavaScriptValidateHandleParams,
+    "validate_string_params": JavaScriptValidateStringParams,
+    "validate_struct_params": JavaScriptValidateStructParams,
+  }
+
+  @UseJinja("js_templates/module.js.tmpl", filters=js_filters)
+  def GenerateJsModule(self):
+    return {
+      "namespace": self.module.namespace,
+      "imports": self.GetImports(),
+      "kinds": self.module.kinds,
+      "enums": self.module.enums,
+      "module": self.module,
+      "structs": self.GetStructs() + self.GetStructsFromMethods(),
+      "interfaces": self.module.interfaces,
+    }
+
+  def GenerateFiles(self, args):
+    self.Write(self.GenerateJsModule(), "%s.js" % self.module.name)
+
+  def GetImports(self):
+    # Since each import is assigned a variable in JS, they need to have unique
+    # names.
+    counter = 1
+    for each in self.module.imports:
+      each["unique_name"] = "import" + str(counter)
+      counter += 1
+    return self.module.imports
diff --git a/mojo/public/tools/bindings/generators/mojom_python_generator.py b/mojo/public/tools/bindings/generators/mojom_python_generator.py
new file mode 100644
index 0000000..8034480
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/mojom_python_generator.py
@@ -0,0 +1,291 @@
+# Copyright 2014 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.
+
+"""Generates Python source files from a mojom.Module."""
+
+import re
+from itertools import ifilter
+
+import mojom.generate.generator as generator
+import mojom.generate.module as mojom
+from mojom.generate.template_expander import UseJinja
+
+_kind_to_type = {
+  mojom.BOOL:                  '_descriptor.TYPE_BOOL',
+  mojom.INT8:                  '_descriptor.TYPE_INT8',
+  mojom.UINT8:                 '_descriptor.TYPE_UINT8',
+  mojom.INT16:                 '_descriptor.TYPE_INT16',
+  mojom.UINT16:                '_descriptor.TYPE_UINT16',
+  mojom.INT32:                 '_descriptor.TYPE_INT32',
+  mojom.UINT32:                '_descriptor.TYPE_UINT32',
+  mojom.INT64:                 '_descriptor.TYPE_INT64',
+  mojom.UINT64:                '_descriptor.TYPE_UINT64',
+  mojom.FLOAT:                 '_descriptor.TYPE_FLOAT',
+  mojom.DOUBLE:                '_descriptor.TYPE_DOUBLE',
+  mojom.STRING:                '_descriptor.TYPE_STRING',
+  mojom.NULLABLE_STRING:       '_descriptor.TYPE_NULLABLE_STRING',
+  mojom.HANDLE:                '_descriptor.TYPE_HANDLE',
+  mojom.DCPIPE:                '_descriptor.TYPE_HANDLE',
+  mojom.DPPIPE:                '_descriptor.TYPE_HANDLE',
+  mojom.MSGPIPE:               '_descriptor.TYPE_HANDLE',
+  mojom.SHAREDBUFFER:          '_descriptor.TYPE_HANDLE',
+  mojom.NULLABLE_HANDLE:       '_descriptor.TYPE_NULLABLE_HANDLE',
+  mojom.NULLABLE_DCPIPE:       '_descriptor.TYPE_NULLABLE_HANDLE',
+  mojom.NULLABLE_DPPIPE:       '_descriptor.TYPE_NULLABLE_HANDLE',
+  mojom.NULLABLE_MSGPIPE:      '_descriptor.TYPE_NULLABLE_HANDLE',
+  mojom.NULLABLE_SHAREDBUFFER: '_descriptor.TYPE_NULLABLE_HANDLE',
+}
+
+# int64 integers are not handled by array.array. int64/uint64 array are
+# supported but storage is not optimized (ie. they are plain python list, not
+# array.array)
+_kind_to_typecode_for_native_array = {
+  mojom.INT8:   'b',
+  mojom.UINT8:  'B',
+  mojom.INT16:  'h',
+  mojom.UINT16: 'H',
+  mojom.INT32:  'i',
+  mojom.UINT32: 'I',
+  mojom.FLOAT:  'f',
+  mojom.DOUBLE: 'd',
+}
+
+_kind_to_typecode = dict(_kind_to_typecode_for_native_array)
+_kind_to_typecode.update({
+  mojom.INT64:                 'q',
+  mojom.UINT64:                'Q',
+  mojom.HANDLE:                'i',
+  mojom.DCPIPE:                'i',
+  mojom.DPPIPE:                'i',
+  mojom.MSGPIPE:               'i',
+  mojom.SHAREDBUFFER:          'i',
+  mojom.NULLABLE_HANDLE:       'i',
+  mojom.NULLABLE_DCPIPE:       'i',
+  mojom.NULLABLE_DPPIPE:       'i',
+  mojom.NULLABLE_MSGPIPE:      'i',
+  mojom.NULLABLE_SHAREDBUFFER: 'i',
+})
+
+
+def NameToComponent(name):
+  # insert '_' between anything and a Title name (e.g, HTTPEntry2FooBar ->
+  # HTTP_Entry2_FooBar)
+  name = re.sub('([^_])([A-Z][^A-Z_]+)', r'\1_\2', name)
+  # insert '_' between non upper and start of upper blocks (e.g.,
+  # HTTP_Entry2_FooBar -> HTTP_Entry2_Foo_Bar)
+  name = re.sub('([^A-Z_])([A-Z])', r'\1_\2', name)
+  return [x.lower() for x in name.split('_')]
+
+def UpperCamelCase(name):
+  return ''.join([x.capitalize() for x in NameToComponent(name)])
+
+def CamelCase(name):
+  uccc = UpperCamelCase(name)
+  return uccc[0].lower() + uccc[1:]
+
+def ConstantStyle(name):
+  components = NameToComponent(name)
+  if components[0] == 'k':
+    components = components[1:]
+  return '_'.join([x.upper() for x in components])
+
+def GetNameForElement(element):
+  if (mojom.IsEnumKind(element) or mojom.IsInterfaceKind(element) or
+      mojom.IsStructKind(element)):
+    return UpperCamelCase(element.name)
+  if isinstance(element, mojom.EnumValue):
+    return (GetNameForElement(element.enum) + '.' +
+            ConstantStyle(element.name))
+  if isinstance(element, (mojom.NamedValue,
+                          mojom.Constant)):
+    return ConstantStyle(element.name)
+  raise Exception('Unexpected element: ' % element)
+
+def ExpressionToText(token):
+  if isinstance(token, (mojom.EnumValue, mojom.NamedValue)):
+    return str(token.computed_value)
+
+  if isinstance(token, mojom.BuiltinValue):
+    if token.value == 'double.INFINITY' or token.value == 'float.INFINITY':
+      return 'float(\'inf\')';
+    if (token.value == 'double.NEGATIVE_INFINITY' or
+        token.value == 'float.NEGATIVE_INFINITY'):
+      return 'float(\'-inf\')'
+    if token.value == 'double.NAN' or token.value == 'float.NAN':
+      return 'float(\'nan\')';
+
+  if token in ['true', 'false']:
+    return str(token == 'true')
+
+  return token
+
+def GetStructClass(kind):
+  name = []
+  if kind.imported_from:
+    name.append(kind.imported_from['python_module'])
+  name.append(GetNameForElement(kind))
+  return '.'.join(name)
+
+def GetFieldType(kind, field=None):
+  if mojom.IsAnyArrayKind(kind):
+    arguments = []
+    if kind.kind in _kind_to_typecode_for_native_array:
+      arguments.append('%r' %_kind_to_typecode_for_native_array[kind.kind])
+    elif kind.kind != mojom.BOOL:
+      arguments.append(GetFieldType(kind.kind))
+    if mojom.IsNullableKind(kind):
+      arguments.append('nullable=True')
+    if mojom.IsFixedArrayKind(kind):
+      arguments.append('length=%d' % kind.length)
+    array_type = 'GenericArrayType'
+    if kind.kind == mojom.BOOL:
+      array_type = 'BooleanArrayType'
+    elif kind.kind in _kind_to_typecode_for_native_array:
+      array_type = 'NativeArrayType'
+    return '_descriptor.%s(%s)' % (array_type, ', '.join(arguments))
+
+  if mojom.IsStructKind(kind):
+    arguments = [ GetStructClass(kind) ]
+    if mojom.IsNullableKind(kind):
+      arguments.append('nullable=True')
+    return '_descriptor.StructType(%s)' % ', '.join(arguments)
+
+  if mojom.IsEnumKind(kind):
+    return GetFieldType(mojom.INT32)
+
+  return _kind_to_type.get(kind, '_descriptor.TYPE_NONE')
+
+def GetFieldDescriptor(packed_field):
+  field = packed_field.field
+  class_name = 'SingleFieldGroup'
+  if field.kind == mojom.BOOL:
+    class_name = 'FieldDescriptor'
+  arguments = [ '%r' % field.name ]
+  arguments.append(GetFieldType(field.kind, field))
+  arguments.append(str(packed_field.index))
+  arguments.append(str(packed_field.ordinal))
+  if field.default:
+    if mojom.IsStructKind(field.kind):
+      arguments.append('default_value=True')
+    else:
+      arguments.append('default_value=%s' % ExpressionToText(field.default))
+  return '_descriptor.%s(%s)' % (class_name, ', '.join(arguments))
+
+def GetFieldGroup(byte):
+  if len(byte.packed_fields) > 1:
+    descriptors = map(GetFieldDescriptor, byte.packed_fields)
+    return '_descriptor.BooleanGroup([%s])' % ', '.join(descriptors)
+  assert len(byte.packed_fields) == 1
+  return GetFieldDescriptor(byte.packed_fields[0])
+
+def ComputeStaticValues(module):
+  in_progress = set()
+  computed = set()
+
+  def GetComputedValue(named_value):
+    if isinstance(named_value, mojom.EnumValue):
+      field = next(ifilter(lambda field: field.name == named_value.name,
+                           named_value.enum.fields), None)
+      if not field:
+        raise RuntimeError(
+            'Unable to get computed value for field %s of enum %s' %
+            (named_value.name, named_value.enum.name))
+      if field not in computed:
+        ResolveEnum(named_value.enum)
+      return field.computed_value
+    elif isinstance(named_value, mojom.ConstantValue):
+      ResolveConstant(named_value.constant)
+      named_value.computed_value = named_value.constant.computed_value
+      return named_value.computed_value
+    else:
+      print named_value
+
+  def ResolveConstant(constant):
+    if constant in computed:
+      return
+    if constant in in_progress:
+      raise RuntimeError('Circular dependency for constant: %s' % constant.name)
+    in_progress.add(constant)
+    if isinstance(constant.value, (mojom.EnumValue, mojom.ConstantValue)):
+      computed_value = GetComputedValue(constant.value)
+    else:
+      computed_value = ExpressionToText(constant.value)
+    constant.computed_value = computed_value
+    in_progress.remove(constant)
+    computed.add(constant)
+
+  def ResolveEnum(enum):
+    def ResolveEnumField(enum, field, default_value):
+      if field in computed:
+        return
+      if field in in_progress:
+        raise RuntimeError('Circular dependency for enum: %s' % enum.name)
+      in_progress.add(field)
+      if field.value:
+        if isinstance(field.value, mojom.EnumValue):
+          computed_value = GetComputedValue(field.value)
+        elif isinstance(field.value, str):
+          computed_value = int(field.value, 0)
+        else:
+          raise RuntimeError('Unexpected value: %s' % field.value)
+      else:
+        computed_value = default_value
+      field.computed_value = computed_value
+      in_progress.remove(field)
+      computed.add(field)
+
+    current_value = 0
+    for field in enum.fields:
+      ResolveEnumField(enum, field, current_value)
+      current_value = field.computed_value + 1
+
+  for constant in module.constants:
+    ResolveConstant(constant)
+
+  for enum in module.enums:
+    ResolveEnum(enum)
+
+  for struct in module.structs:
+    for constant in struct.constants:
+      ResolveConstant(constant)
+    for enum in struct.enums:
+      ResolveEnum(enum)
+    for field in struct.fields:
+      if isinstance(field.default, (mojom.ConstantValue, mojom.EnumValue)):
+        field.default.computed_value = GetComputedValue(field.default)
+
+  return module
+
+
+class Generator(generator.Generator):
+
+  python_filters = {
+    'expression_to_text': ExpressionToText,
+    'field_group': GetFieldGroup,
+    'name': GetNameForElement,
+  }
+
+  @UseJinja('python_templates/module.py.tmpl', filters=python_filters)
+  def GeneratePythonModule(self):
+    return {
+      'imports': self.GetImports(),
+      'enums': self.module.enums,
+      'module': ComputeStaticValues(self.module),
+      'structs': self.GetStructs(),
+    }
+
+  def GenerateFiles(self, args):
+    self.Write(self.GeneratePythonModule(),
+               '%s.py' % self.module.name.replace('.mojom', '_mojom'))
+
+  def GetImports(self):
+    for each in self.module.imports:
+      each['python_module'] = each['module_name'].replace('.mojom', '_mojom')
+    return self.module.imports
+
+  def GetJinjaParameters(self):
+    return {
+      'lstrip_blocks': True,
+      'trim_blocks': True,
+    }
diff --git a/mojo/public/tools/bindings/generators/python_templates/module.py.tmpl b/mojo/public/tools/bindings/generators/python_templates/module.py.tmpl
new file mode 100644
index 0000000..d5bff30
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/python_templates/module.py.tmpl
@@ -0,0 +1,56 @@
+{% from "module_macros.tmpl" import enum_values %}
+# Copyright 2014 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.
+
+import mojo.bindings.descriptor as _descriptor
+import mojo.bindings.reflection as _reflection
+{% if imports %}
+
+{% for import in imports %}
+import {{import.python_module}}
+{% endfor %}
+{% endif %}
+{#--- Constants #}
+{% if module.constants %}
+
+{% for constant in module.constants %}
+{{constant|name}} = {{constant.value|expression_to_text}}
+{% endfor %}
+{% endif %}
+{% for enum in module.enums %}
+
+class {{enum|name}}(object):
+  __metaclass__ = _reflection.MojoEnumType
+  VALUES = {{enum_values(enum)|indent(2)}}
+{% endfor %}
+{% for struct in module.structs %}
+
+class {{struct|name}}(object):
+  __metaclass__ = _reflection.MojoStructType
+  DESCRIPTOR = {
+{%   if struct.constants %}
+    'constants': {
+{%     for constant in struct.constants %}
+      '{{constant|name}}': {{constant.value|expression_to_text}},
+{%     endfor %}
+    },
+{%   endif %}
+{%   if struct.enums %}
+    'enums': {
+{%     for enum in struct.enums %}
+      '{{enum|name}}': {{enum_values(enum)|indent(6)}},
+{%     endfor %}
+    },
+{%   endif %}
+{%   if struct.fields %}
+    'fields': [
+{%    for byte in struct.bytes %}
+{%      if byte.packed_fields %}
+      {{byte|field_group}},
+{%      endif %}
+{%   endfor %}
+    ],
+{%   endif %}
+  }
+{% endfor %}
diff --git a/mojo/public/tools/bindings/generators/python_templates/module_macros.tmpl b/mojo/public/tools/bindings/generators/python_templates/module_macros.tmpl
new file mode 100644
index 0000000..305b26a
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/python_templates/module_macros.tmpl
@@ -0,0 +1,11 @@
+# Copyright 2014 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.
+
+{%- macro enum_values(enum) -%}
+[
+{% for field in enum.fields %}
+  ('{{field.name}}', {{field.computed_value}}),
+{% endfor %}
+]
+{%- endmacro -%}
diff --git a/mojo/public/tools/bindings/generators/run_cpp_generator.py b/mojo/public/tools/bindings/generators/run_cpp_generator.py
new file mode 100755
index 0000000..4c6f597
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/run_cpp_generator.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+# Copyright 2013 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.
+
+import ast
+import os
+import sys
+
+script_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.insert(0, os.path.join(script_dir, os.pardir, "pylib"))
+
+from mojom.generate.data
+import mojom_cpp_generator
+
+def ReadDict(file):
+  with open(file, 'r') as f:
+    s = f.read()
+    dict = ast.literal_eval(s)
+    return dict
+
+dict = ReadDict(sys.argv[1])
+module = mojom.generate.data.ModuleFromData(dict)
+dir = None
+if len(sys.argv) > 2:
+  dir = sys.argv[2]
+cpp = mojom_cpp_generator.Generator(module, ".", dir)
+cpp.GenerateFiles([])
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni
new file mode 100644
index 0000000..e12d8e0
--- /dev/null
+++ b/mojo/public/tools/bindings/mojom.gni
@@ -0,0 +1,130 @@
+# Copyright 2014 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.
+
+# Generate C++ and JavaScript source files from mojom files. The output files
+# will go under the generated file directory tree with the same path as each
+# input file.
+#
+# Parameters:
+#
+#   sources (required)
+#       List of source .mojom files to compile.
+#
+#   deps (optional)
+#
+#   public_deps (optional)
+#
+#   testonly (optional)
+#
+#   visibility (optional)
+template("mojom") {
+  assert(defined(invoker.sources),
+         "\"sources\" must be defined for the $target_name template.")
+
+  generator_root = "//mojo/public/tools/bindings"
+  generator_script = "$generator_root/mojom_bindings_generator.py"
+  generator_sources = [
+    generator_script,
+    "$generator_root/generators/cpp_templates/enum_declaration.tmpl",
+    "$generator_root/generators/cpp_templates/interface_declaration.tmpl",
+    "$generator_root/generators/cpp_templates/interface_definition.tmpl",
+    "$generator_root/generators/cpp_templates/interface_macros.tmpl",
+    "$generator_root/generators/cpp_templates/interface_proxy_declaration.tmpl",
+    "$generator_root/generators/cpp_templates/interface_request_validator_declaration.tmpl",
+    "$generator_root/generators/cpp_templates/interface_response_validator_declaration.tmpl",
+    "$generator_root/generators/cpp_templates/interface_stub_declaration.tmpl",
+    "$generator_root/generators/cpp_templates/module.cc.tmpl",
+    "$generator_root/generators/cpp_templates/module.h.tmpl",
+    "$generator_root/generators/cpp_templates/module-internal.h.tmpl",
+    "$generator_root/generators/cpp_templates/params_definition.tmpl",
+    "$generator_root/generators/cpp_templates/struct_declaration.tmpl",
+    "$generator_root/generators/cpp_templates/struct_definition.tmpl",
+    "$generator_root/generators/cpp_templates/struct_serialization_declaration.tmpl",
+    "$generator_root/generators/cpp_templates/struct_serialization_definition.tmpl",
+    "$generator_root/generators/cpp_templates/struct_macros.tmpl",
+    "$generator_root/generators/cpp_templates/wrapper_class_declaration.tmpl",
+    "$generator_root/generators/cpp_templates/wrapper_class_definition.tmpl",
+    "$generator_root/generators/js_templates/enum_definition.tmpl",
+    "$generator_root/generators/js_templates/interface_definition.tmpl",
+    "$generator_root/generators/js_templates/module.js.tmpl",
+    "$generator_root/generators/js_templates/struct_definition.tmpl",
+    "$generator_root/generators/python_templates/module_macros.tmpl",
+    "$generator_root/generators/python_templates/module.py.tmpl",
+    "$generator_root/generators/mojom_cpp_generator.py",
+    "$generator_root/generators/mojom_js_generator.py",
+    "$generator_root/generators/mojom_python_generator.py",
+    "$generator_root/pylib/mojom/__init__.py",
+    "$generator_root/pylib/mojom/error.py",
+    "$generator_root/pylib/mojom/generate/__init__.py",
+    "$generator_root/pylib/mojom/generate/data.py",
+    "$generator_root/pylib/mojom/generate/generator.py",
+    "$generator_root/pylib/mojom/generate/module.py",
+    "$generator_root/pylib/mojom/generate/pack.py",
+    "$generator_root/pylib/mojom/generate/template_expander.py",
+    "$generator_root/pylib/mojom/parse/__init__.py",
+    "$generator_root/pylib/mojom/parse/ast.py",
+    "$generator_root/pylib/mojom/parse/lexer.py",
+    "$generator_root/pylib/mojom/parse/parser.py",
+    "$generator_root/pylib/mojom/parse/translate.py",
+  ]
+  generator_cpp_outputs = [
+    "{{source_gen_dir}}/{{source_name_part}}.mojom.cc",
+    "{{source_gen_dir}}/{{source_name_part}}.mojom.h",
+    "{{source_gen_dir}}/{{source_name_part}}.mojom-internal.h",
+  ]
+  generator_js_outputs = [
+    "{{source_gen_dir}}/{{source_name_part}}.mojom.js",
+  ]
+  generator_python_outputs = [
+    "{{source_gen_dir}}/{{source_name_part}}_mojom.py",
+  ]
+
+  if (defined(invoker.visibility)) {
+    # Need to save this because the the target_name is overwritten inside the
+    # action to be that of the action itself. Only define this in the case the
+    # var is used to avoid unused var error.
+    target_visibility = [ ":$target_name" ]
+  }
+
+  generator_target_name = target_name + "__generator"
+  action_foreach(generator_target_name) {
+    if (defined(invoker.visibility)) {
+      visibility = target_visibility + invoker.visibility
+    }
+    script = generator_script
+    inputs = generator_sources
+    sources = invoker.sources
+    outputs = generator_cpp_outputs +
+              generator_js_outputs +
+              generator_python_outputs
+    args = [
+      "{{source}}",
+      "--use_chromium_bundled_pylibs",
+      "-d", rebase_path("//", root_build_dir),
+      "-I", rebase_path("//", root_build_dir),
+      "-o", "{{source_gen_dir}}",
+    ]
+  }
+
+  source_set(target_name) {
+    if (defined(invoker.visibility)) {
+      visibility = invoker.visibility
+    }
+    if (defined(invoker.testonly)) {
+      testonly = invoker.testonly
+    }
+    sources = process_file_template(invoker.sources, generator_cpp_outputs)
+    data = process_file_template(invoker.sources, generator_js_outputs)
+    deps = [
+      ":$generator_target_name",
+      "//mojo/public/cpp/bindings",
+    ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+    if (defined(invoker.public_deps)) {
+      public_deps = invoker.public_deps
+    }
+  }
+}
diff --git a/mojo/public/tools/bindings/mojom_bindings_generator.gypi b/mojo/public/tools/bindings/mojom_bindings_generator.gypi
new file mode 100644
index 0000000..c6e9f98
--- /dev/null
+++ b/mojo/public/tools/bindings/mojom_bindings_generator.gypi
@@ -0,0 +1,111 @@
+# Copyright 2013 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.
+
+{
+  'rules': [
+    {
+      'rule_name': '<(_target_name)_mojom_bindings_generator',
+      'extension': 'mojom',
+      'variables': {
+        'mojom_base_output_dir':
+             '<!(python <(DEPTH)/build/inverse_depth.py <(DEPTH))',
+        'mojom_bindings_generator':
+            '<(DEPTH)/mojo/public/tools/bindings/mojom_bindings_generator.py',
+        'java_out_dir': '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src',
+        'mojom_import_args%': [
+         '-I<(DEPTH)'
+        ],
+      },
+      'inputs': [
+        '<(mojom_bindings_generator)',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/enum_declaration.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/constant_definition.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/constants.java.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/enum.java.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/interface.java.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/interface_internal.java.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/struct_definition.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/struct.java.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/module.js.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/python_templates/module_macros.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/python_templates/module.py.tmpl',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_cpp_generator.py',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_java_generator.py',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_js_generator.py',
+        '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_python_generator.py',
+        '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/__init__.py',
+        '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/error.py',
+        '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/__init__.py',
+        '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/data.py',
+        '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/generator.py',
+        '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/module.py',
+        '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/pack.py',
+        '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py',
+        '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/__init__.py',
+        '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/ast.py',
+        '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/lexer.py',
+        '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/parser.py',
+        '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/translate.py',
+      ],
+      'outputs': [
+        '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom.cc',
+        '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom.h',
+        '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom.js',
+        '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT)_mojom.py',
+        '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom-internal.h',
+      ],
+      'action': [
+        'python', '<@(mojom_bindings_generator)',
+        './<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom',
+        '--use_chromium_bundled_pylibs',
+        '-d', '<(DEPTH)',
+        '<@(mojom_import_args)',
+        '-o', '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)',
+        '--java_output_directory=<(java_out_dir)',
+      ],
+      'message': 'Generating Mojo bindings from <(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom',
+      'process_outputs_as_sources': 1,
+    }
+  ],
+  'include_dirs': [
+    '<(DEPTH)',
+    '<(SHARED_INTERMEDIATE_DIR)',
+  ],
+  'direct_dependent_settings': {
+    'include_dirs': [
+      '<(DEPTH)',
+      '<(SHARED_INTERMEDIATE_DIR)',
+    ],
+    'variables': {
+      'generated_src_dirs': [
+        '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src',
+      ],
+    },
+  },
+  'hard_dependency': 1,
+}
diff --git a/mojo/public/tools/bindings/mojom_bindings_generator.py b/mojo/public/tools/bindings/mojom_bindings_generator.py
new file mode 100755
index 0000000..53e3a33
--- /dev/null
+++ b/mojo/public/tools/bindings/mojom_bindings_generator.py
@@ -0,0 +1,196 @@
+#!/usr/bin/env python
+# Copyright 2013 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.
+
+"""The frontend for the Mojo bindings system."""
+
+
+import argparse
+import imp
+import os
+import pprint
+import sys
+
+# Disable lint check for finding modules:
+# pylint: disable=F0401
+
+def _GetDirAbove(dirname):
+  """Returns the directory "above" this file containing |dirname| (which must
+  also be "above" this file)."""
+  path = os.path.abspath(__file__)
+  while True:
+    path, tail = os.path.split(path)
+    assert tail
+    if tail == dirname:
+      return path
+
+# Manually check for the command-line flag. (This isn't quite right, since it
+# ignores, e.g., "--", but it's close enough.)
+if "--use_chromium_bundled_pylibs" in sys.argv[1:]:
+  sys.path.insert(0, os.path.join(_GetDirAbove("mojo"), "third_party"))
+
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                                "pylib"))
+
+from mojom.error import Error
+from mojom.generate.data import OrderedModuleFromData
+from mojom.parse.parser import Parse
+from mojom.parse.translate import Translate
+
+
+def LoadGenerators(generators_string):
+  if not generators_string:
+    return []  # No generators.
+
+  script_dir = os.path.dirname(os.path.abspath(__file__))
+  generators = []
+  for generator_name in [s.strip() for s in generators_string.split(",")]:
+    # "Built-in" generators:
+    if generator_name.lower() == "c++":
+      generator_name = os.path.join(script_dir, "generators",
+                                    "mojom_cpp_generator.py")
+    elif generator_name.lower() == "javascript":
+      generator_name = os.path.join(script_dir, "generators",
+                                    "mojom_js_generator.py")
+    elif generator_name.lower() == "java":
+      generator_name = os.path.join(script_dir, "generators",
+                                    "mojom_java_generator.py")
+    elif generator_name.lower() == "python":
+      generator_name = os.path.join(script_dir, "generators",
+                                    "mojom_python_generator.py")
+    # Specified generator python module:
+    elif generator_name.endswith(".py"):
+      pass
+    else:
+      print "Unknown generator name %s" % generator_name
+      sys.exit(1)
+    generator_module = imp.load_source(os.path.basename(generator_name)[:-3],
+                                       generator_name)
+    generators.append(generator_module)
+  return generators
+
+
+def MakeImportStackMessage(imported_filename_stack):
+  """Make a (human-readable) message listing a chain of imports. (Returned
+  string begins with a newline (if nonempty) and does not end with one.)"""
+  return ''.join(
+      reversed(["\n  %s was imported by %s" % (a, b) for (a, b) in \
+                    zip(imported_filename_stack[1:], imported_filename_stack)]))
+
+
+def FindImportFile(dir_name, file_name, search_dirs):
+  for search_dir in [dir_name] + search_dirs:
+    path = os.path.join(search_dir, file_name)
+    if os.path.isfile(path):
+      return path
+  return os.path.join(dir_name, file_name)
+
+
+# Disable check for dangerous default arguments (they're "private" keyword
+# arguments; note that we want |_processed_files| to memoize across invocations
+# of |ProcessFile()|):
+# pylint: disable=W0102
+def ProcessFile(args, remaining_args, generator_modules, filename,
+                _processed_files={}, _imported_filename_stack=None):
+  # Memoized results.
+  if filename in _processed_files:
+    return _processed_files[filename]
+
+  if _imported_filename_stack is None:
+    _imported_filename_stack = []
+
+  # Ensure we only visit each file once.
+  if filename in _imported_filename_stack:
+    print "%s: Error: Circular dependency" % filename + \
+        MakeImportStackMessage(_imported_filename_stack + [filename])
+    sys.exit(1)
+
+  try:
+    with open(filename) as f:
+      source = f.read()
+  except IOError as e:
+    print "%s: Error: %s" % (e.filename, e.strerror) + \
+        MakeImportStackMessage(_imported_filename_stack + [filename])
+    sys.exit(1)
+
+  try:
+    tree = Parse(source, filename)
+  except Error as e:
+    print str(e) + MakeImportStackMessage(_imported_filename_stack + [filename])
+    sys.exit(1)
+
+  dirname, name = os.path.split(filename)
+  mojom = Translate(tree, name)
+  if args.debug_print_intermediate:
+    pprint.PrettyPrinter().pprint(mojom)
+
+  # Process all our imports first and collect the module object for each.
+  # We use these to generate proper type info.
+  for import_data in mojom['imports']:
+    import_filename = FindImportFile(dirname,
+                                     import_data['filename'],
+                                     args.import_directories)
+    import_data['module'] = ProcessFile(
+        args, remaining_args, generator_modules, import_filename,
+        _processed_files=_processed_files,
+        _imported_filename_stack=_imported_filename_stack + [filename])
+
+  module = OrderedModuleFromData(mojom)
+
+  # Set the path as relative to the source root.
+  module.path = os.path.relpath(os.path.abspath(filename),
+                                os.path.abspath(args.depth))
+
+  # Normalize to unix-style path here to keep the generators simpler.
+  module.path = module.path.replace('\\', '/')
+
+  for generator_module in generator_modules:
+    generator = generator_module.Generator(module, args.output_dir)
+    filtered_args = []
+    if hasattr(generator_module, 'GENERATOR_PREFIX'):
+      prefix = '--' + generator_module.GENERATOR_PREFIX + '_'
+      filtered_args = [arg for arg in remaining_args if arg.startswith(prefix)]
+    generator.GenerateFiles(filtered_args)
+
+  # Save result.
+  _processed_files[filename] = module
+  return module
+# pylint: enable=W0102
+
+
+def main():
+  parser = argparse.ArgumentParser(
+      description="Generate bindings from mojom files.")
+  parser.add_argument("filename", nargs="+",
+                      help="mojom input file")
+  parser.add_argument("-d", "--depth", dest="depth", default=".",
+                      help="depth from source root")
+  parser.add_argument("-o", "--output_dir", dest="output_dir", default=".",
+                      help="output directory for generated files")
+  parser.add_argument("-g", "--generators", dest="generators_string",
+                      metavar="GENERATORS",
+                      default="c++,javascript,java,python",
+                      help="comma-separated list of generators")
+  parser.add_argument("--debug_print_intermediate", action="store_true",
+                      help="print the intermediate representation")
+  parser.add_argument("-I", dest="import_directories", action="append",
+                      metavar="directory", default=[],
+                      help="add a directory to be searched for import files")
+  parser.add_argument("--use_chromium_bundled_pylibs", action="store_true",
+                      help="use Python modules bundled in the Chromium source")
+  (args, remaining_args) = parser.parse_known_args()
+
+  generator_modules = LoadGenerators(args.generators_string)
+
+  if not os.path.exists(args.output_dir):
+    os.makedirs(args.output_dir)
+
+  for filename in args.filename:
+    ProcessFile(args, remaining_args, generator_modules, filename)
+
+  return 0
+
+
+if __name__ == "__main__":
+  sys.exit(main())
diff --git a/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py b/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py
new file mode 100644
index 0000000..de38856
--- /dev/null
+++ b/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py
@@ -0,0 +1,23 @@
+# Copyright 2014 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.
+
+import unittest
+
+from mojom_bindings_generator import MakeImportStackMessage
+
+
+class MojoBindingsGeneratorTest(unittest.TestCase):
+  """Tests mojo_bindings_generator."""
+
+  def testMakeImportStackMessage(self):
+    """Tests MakeImportStackMessage()."""
+    self.assertEquals(MakeImportStackMessage(["x"]), "")
+    self.assertEquals(MakeImportStackMessage(["x", "y"]),
+        "\n  y was imported by x")
+    self.assertEquals(MakeImportStackMessage(["x", "y", "z"]),
+        "\n  z was imported by y\n  y was imported by x")
+
+
+if __name__ == "__main__":
+  unittest.main()
diff --git a/mojo/public/tools/bindings/pylib/mojom/__init__.py b/mojo/public/tools/bindings/pylib/mojom/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/__init__.py
diff --git a/mojo/public/tools/bindings/pylib/mojom/error.py b/mojo/public/tools/bindings/pylib/mojom/error.py
new file mode 100644
index 0000000..99522b9
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/error.py
@@ -0,0 +1,27 @@
+# Copyright 2014 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.
+
+class Error(Exception):
+  """Base class for Mojo IDL bindings parser/generator errors."""
+
+  def __init__(self, filename, message, lineno=None, addenda=None, **kwargs):
+    """|filename| is the (primary) file which caused the error, |message| is the
+    error message, |lineno| is the 1-based line number (or |None| if not
+    applicable/available), and |addenda| is a list of additional lines to append
+    to the final error message."""
+    Exception.__init__(self, **kwargs)
+    self.filename = filename
+    self.message = message
+    self.lineno = lineno
+    self.addenda = addenda
+
+  def __str__(self):
+    if self.lineno:
+      s = "%s:%d: Error: %s" % (self.filename, self.lineno, self.message)
+    else:
+      s = "%s: Error: %s" % (self.filename, self.message)
+    return "\n".join([s] + self.addenda) if self.addenda else s
+
+  def __repr__(self):
+    return str(self)
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/__init__.py b/mojo/public/tools/bindings/pylib/mojom/generate/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/__init__.py
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/data.py b/mojo/public/tools/bindings/pylib/mojom/generate/data.py
new file mode 100644
index 0000000..fab7e2e
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/data.py
@@ -0,0 +1,383 @@
+# Copyright 2013 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.
+
+# TODO(vtl): "data" is a pretty vague name. Rename it?
+
+import copy
+
+import module as mojom
+
+# This module provides a mechanism to turn mojom Modules to dictionaries and
+# back again. This can be used to persist a mojom Module created progromatically
+# or to read a dictionary from code or a file.
+# Example:
+# test_dict = {
+#   'name': 'test',
+#   'namespace': 'testspace',
+#   'structs': [{
+#     'name': 'teststruct',
+#     'fields': [
+#       {'name': 'testfield1', 'kind': 'i32'},
+#       {'name': 'testfield2', 'kind': 'a:i32', 'ordinal': 42}]}],
+#   'interfaces': [{
+#     'name': 'Server',
+#     'methods': [{
+#       'name': 'Foo',
+#       'parameters': [{
+#         'name': 'foo', 'kind': 'i32'},
+#         {'name': 'bar', 'kind': 'a:x:teststruct'}],
+#     'ordinal': 42}]}]
+# }
+# test_module = data.ModuleFromData(test_dict)
+
+# Used to create a subclass of str that supports sorting by index, to make
+# pretty printing maintain the order.
+def istr(index, string):
+  class IndexedString(str):
+    def __lt__(self, other):
+      return self.__index__ < other.__index__
+
+  rv = IndexedString(string)
+  rv.__index__ = index
+  return rv
+
+builtin_values = frozenset([
+    "double.INFINITY",
+    "double.NEGATIVE_INFINITY",
+    "double.NAN",
+    "float.INFINITY",
+    "float.NEGATIVE_INFINITY",
+    "float.NAN"])
+
+def IsBuiltinValue(value):
+  return value in builtin_values
+
+def LookupKind(kinds, spec, scope):
+  """Tries to find which Kind a spec refers to, given the scope in which its
+  referenced. Starts checking from the narrowest scope to most general. For
+  example, given a struct field like
+    Foo.Bar x;
+  Foo.Bar could refer to the type 'Bar' in the 'Foo' namespace, or an inner
+  type 'Bar' in the struct 'Foo' in the current namespace.
+
+  |scope| is a tuple that looks like (namespace, struct/interface), referring
+  to the location where the type is referenced."""
+  if spec.startswith('x:'):
+    name = spec[2:]
+    for i in xrange(len(scope), -1, -1):
+      test_spec = 'x:'
+      if i > 0:
+        test_spec += '.'.join(scope[:i]) + '.'
+      test_spec += name
+      kind = kinds.get(test_spec)
+      if kind:
+        return kind
+
+  return kinds.get(spec)
+
+def LookupValue(values, name, scope, kind):
+  """Like LookupKind, but for constant values."""
+  # If the type is an enum, the value can be specified as a qualified name, in
+  # which case the form EnumName.ENUM_VALUE must be used. We use the presence
+  # of a '.' in the requested name to identify this. Otherwise, we prepend the
+  # enum name.
+  if isinstance(kind, mojom.Enum) and '.' not in name:
+    name = '%s.%s' % (kind.spec.split(':', 1)[1], name)
+  for i in reversed(xrange(len(scope) + 1)):
+    test_spec = '.'.join(scope[:i])
+    if test_spec:
+      test_spec += '.'
+    test_spec += name
+    value = values.get(test_spec)
+    if value:
+      return value
+
+  return values.get(name)
+
+def FixupExpression(module, value, scope, kind):
+  """Translates an IDENTIFIER into a built-in value or structured NamedValue
+     object."""
+  if isinstance(value, tuple) and value[0] == 'IDENTIFIER':
+    # Allow user defined values to shadow builtins.
+    result = LookupValue(module.values, value[1], scope, kind)
+    if result:
+      if isinstance(result, tuple):
+        raise Exception('Unable to resolve expression: %r' % value[1])
+      return result
+    if IsBuiltinValue(value[1]):
+      return mojom.BuiltinValue(value[1])
+  return value
+
+def KindToData(kind):
+  return kind.spec
+
+def KindFromData(kinds, data, scope):
+  kind = LookupKind(kinds, data, scope)
+  if kind:
+    return kind
+
+  if data.startswith('?'):
+    kind = KindFromData(kinds, data[1:], scope).MakeNullableKind()
+  elif data.startswith('a:'):
+    kind = mojom.Array(KindFromData(kinds, data[2:], scope))
+  elif data.startswith('r:'):
+    kind = mojom.InterfaceRequest(KindFromData(kinds, data[2:], scope))
+  elif data.startswith('a'):
+    colon = data.find(':')
+    length = int(data[1:colon])
+    kind = mojom.FixedArray(length, KindFromData(kinds, data[colon+1:], scope))
+  else:
+    kind = mojom.Kind(data)
+
+  kinds[data] = kind
+  return kind
+
+def KindFromImport(original_kind, imported_from):
+  """Used with 'import module' - clones the kind imported from the given
+  module's namespace. Only used with Structs, Interfaces and Enums."""
+  kind = copy.copy(original_kind)
+  # |shared_definition| is used to store various properties (see
+  # |AddSharedProperty()| in module.py), including |imported_from|. We don't
+  # want the copy to share these with the original, so copy it if necessary.
+  if hasattr(original_kind, 'shared_definition'):
+    kind.shared_definition = copy.copy(original_kind.shared_definition)
+  kind.imported_from = imported_from
+  return kind
+
+def ImportFromData(module, data):
+  import_module = data['module']
+
+  import_item = {}
+  import_item['module_name'] = import_module.name
+  import_item['namespace'] = import_module.namespace
+  import_item['module'] = import_module
+
+  # Copy the struct kinds from our imports into the current module.
+  for kind in import_module.kinds.itervalues():
+    if (isinstance(kind, (mojom.Struct, mojom.Enum, mojom.Interface)) and
+        kind.imported_from is None):
+      kind = KindFromImport(kind, import_item)
+      module.kinds[kind.spec] = kind
+  # Ditto for values.
+  for value in import_module.values.itervalues():
+    if value.imported_from is None:
+      # Values don't have shared definitions (since they're not nullable), so no
+      # need to do anything special.
+      value = copy.copy(value)
+      value.imported_from = import_item
+      module.values[value.GetSpec()] = value
+
+  return import_item
+
+def StructToData(struct):
+  return {
+    istr(0, 'name'): struct.name,
+    istr(1, 'fields'): map(FieldToData, struct.fields)
+  }
+
+def StructFromData(module, data):
+  struct = mojom.Struct(module=module)
+  struct.name = data['name']
+  struct.attributes = data['attributes']
+  struct.spec = 'x:' + module.namespace + '.' + struct.name
+  module.kinds[struct.spec] = struct
+  struct.enums = map(lambda enum:
+      EnumFromData(module, enum, struct), data['enums'])
+  struct.constants = map(lambda constant:
+      ConstantFromData(module, constant, struct), data['constants'])
+  # Stash fields data here temporarily.
+  struct.fields_data = data['fields']
+  return struct
+
+def FieldToData(field):
+  data = {
+    istr(0, 'name'): field.name,
+    istr(1, 'kind'): KindToData(field.kind)
+  }
+  if field.ordinal != None:
+    data[istr(2, 'ordinal')] = field.ordinal
+  if field.default != None:
+    data[istr(3, 'default')] = field.default
+  return data
+
+def FieldFromData(module, data, struct):
+  field = mojom.Field()
+  field.name = data['name']
+  field.kind = KindFromData(
+      module.kinds, data['kind'], (module.namespace, struct.name))
+  field.ordinal = data.get('ordinal')
+  field.default = FixupExpression(
+      module, data.get('default'), (module.namespace, struct.name), field.kind)
+  return field
+
+def ParameterToData(parameter):
+  data = {
+    istr(0, 'name'): parameter.name,
+    istr(1, 'kind'): parameter.kind.spec
+  }
+  if parameter.ordinal != None:
+    data[istr(2, 'ordinal')] = parameter.ordinal
+  if parameter.default != None:
+    data[istr(3, 'default')] = parameter.default
+  return data
+
+def ParameterFromData(module, data, interface):
+  parameter = mojom.Parameter()
+  parameter.name = data['name']
+  parameter.kind = KindFromData(
+      module.kinds, data['kind'], (module.namespace, interface.name))
+  parameter.ordinal = data.get('ordinal')
+  parameter.default = data.get('default')
+  return parameter
+
+def MethodToData(method):
+  data = {
+    istr(0, 'name'):       method.name,
+    istr(1, 'parameters'): map(ParameterToData, method.parameters)
+  }
+  if method.ordinal != None:
+    data[istr(2, 'ordinal')] = method.ordinal
+  if method.response_parameters != None:
+    data[istr(3, 'response_parameters')] = map(
+        ParameterToData, method.response_parameters)
+  return data
+
+def MethodFromData(module, data, interface):
+  method = mojom.Method(interface, data['name'], ordinal=data.get('ordinal'))
+  method.default = data.get('default')
+  method.parameters = map(lambda parameter:
+      ParameterFromData(module, parameter, interface), data['parameters'])
+  if data.has_key('response_parameters'):
+    method.response_parameters = map(
+        lambda parameter: ParameterFromData(module, parameter, interface),
+                          data['response_parameters'])
+  return method
+
+def InterfaceToData(interface):
+  return {
+    istr(0, 'name'):    interface.name,
+    istr(1, 'client'):  interface.client,
+    istr(2, 'methods'): map(MethodToData, interface.methods)
+  }
+
+def InterfaceFromData(module, data):
+  interface = mojom.Interface(module=module)
+  interface.name = data['name']
+  interface.spec = 'x:' + module.namespace + '.' + interface.name
+  interface.client = data['client'] if data.has_key('client') else None
+  module.kinds[interface.spec] = interface
+  interface.enums = map(lambda enum:
+      EnumFromData(module, enum, interface), data['enums'])
+  interface.constants = map(lambda constant:
+      ConstantFromData(module, constant, interface), data['constants'])
+  # Stash methods data here temporarily.
+  interface.methods_data = data['methods']
+  return interface
+
+def EnumFieldFromData(module, enum, data, parent_kind):
+  field = mojom.EnumField()
+  field.name = data['name']
+  # TODO(mpcomplete): FixupExpression should be done in the second pass,
+  # so constants and enums can refer to each other.
+  # TODO(mpcomplete): But then, what if constants are initialized to an enum? Or
+  # vice versa?
+  if parent_kind:
+    field.value = FixupExpression(
+        module, data['value'], (module.namespace, parent_kind.name), enum)
+  else:
+    field.value = FixupExpression(
+        module, data['value'], (module.namespace, ), enum)
+  value = mojom.EnumValue(module, enum, field)
+  module.values[value.GetSpec()] = value
+  return field
+
+def EnumFromData(module, data, parent_kind):
+  enum = mojom.Enum(module=module)
+  enum.name = data['name']
+  name = enum.name
+  if parent_kind:
+    name = parent_kind.name + '.' + name
+  enum.spec = 'x:%s.%s' % (module.namespace, name)
+  enum.parent_kind = parent_kind
+
+  enum.fields = map(
+      lambda field: EnumFieldFromData(module, enum, field, parent_kind),
+      data['fields'])
+  module.kinds[enum.spec] = enum
+  return enum
+
+def ConstantFromData(module, data, parent_kind):
+  constant = mojom.Constant()
+  constant.name = data['name']
+  if parent_kind:
+    scope = (module.namespace, parent_kind.name)
+  else:
+    scope = (module.namespace, )
+  # TODO(mpcomplete): maybe we should only support POD kinds.
+  constant.kind = KindFromData(module.kinds, data['kind'], scope)
+  constant.value = FixupExpression(module, data.get('value'), scope, None)
+
+  value = mojom.ConstantValue(module, parent_kind, constant)
+  module.values[value.GetSpec()] = value
+  return constant
+
+def ModuleToData(module):
+  return {
+    istr(0, 'name'):       module.name,
+    istr(1, 'namespace'):  module.namespace,
+    istr(2, 'structs'):    map(StructToData, module.structs),
+    istr(3, 'interfaces'): map(InterfaceToData, module.interfaces)
+  }
+
+def ModuleFromData(data):
+  module = mojom.Module()
+  module.kinds = {}
+  for kind in mojom.PRIMITIVES:
+    module.kinds[kind.spec] = kind
+
+  module.values = {}
+
+  module.name = data['name']
+  module.namespace = data['namespace']
+  module.attributes = data['attributes']
+  # Imports must come first, because they add to module.kinds which is used
+  # by by the others.
+  module.imports = map(
+      lambda import_data: ImportFromData(module, import_data),
+      data['imports'])
+
+  # First pass collects kinds.
+  module.enums = map(
+      lambda enum: EnumFromData(module, enum, None), data['enums'])
+  module.structs = map(
+      lambda struct: StructFromData(module, struct), data['structs'])
+  module.interfaces = map(
+      lambda interface: InterfaceFromData(module, interface),
+      data['interfaces'])
+  module.constants = map(
+      lambda constant: ConstantFromData(module, constant, None),
+      data['constants'])
+
+  # Second pass expands fields and methods. This allows fields and parameters
+  # to refer to kinds defined anywhere in the mojom.
+  for struct in module.structs:
+    struct.fields = map(lambda field:
+        FieldFromData(module, field, struct), struct.fields_data)
+    del struct.fields_data
+  for interface in module.interfaces:
+    interface.methods = map(lambda method:
+        MethodFromData(module, method, interface), interface.methods_data)
+    del interface.methods_data
+
+  return module
+
+def OrderedModuleFromData(data):
+  module = ModuleFromData(data)
+  for interface in module.interfaces:
+    next_ordinal = 0
+    for method in interface.methods:
+      if method.ordinal is None:
+        method.ordinal = next_ordinal
+      next_ordinal = method.ordinal + 1
+  return module
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/data_tests.py b/mojo/public/tools/bindings/pylib/mojom/generate/data_tests.py
new file mode 100644
index 0000000..096554c
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/data_tests.py
@@ -0,0 +1,86 @@
+# Copyright 2013 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.
+
+import sys
+
+import data
+import test_support
+
+EXPECT_EQ = test_support.EXPECT_EQ
+EXPECT_TRUE = test_support.EXPECT_TRUE
+RunTest = test_support.RunTest
+
+
+def DeepEquals(d1, d2):
+  if d1 == d2:
+    return True
+  if d2.__class__ != d2.__class__:
+    return False
+  if isinstance(d1, dict):
+    if set(d1.keys()) != set(d2.keys()):
+      return False
+    for key in d1.keys():
+      if not DeepEquals(d1[key], d2[key]):
+        return False
+    return True
+  if isinstance(d1, (list, tuple)):
+    if len(d1) != len(d2):
+      return False
+    for i in range(len(d1)):
+      if not DeepEquals(d1[i], d2[i]):
+        return False
+    return True
+  return False
+
+
+test_dict = {
+  'name': 'test',
+  'namespace': 'testspace',
+  'structs': [{
+    'name': 'teststruct',
+    'fields': [
+      {'name': 'testfield1', 'kind': 'i32'},
+      {'name': 'testfield2', 'kind': 'a:i32', 'ordinal': 42}]}],
+  'interfaces': [{
+    'name': 'Server',
+    'client': None,
+    'methods': [{
+      'name': 'Foo',
+      'parameters': [
+        {'name': 'foo', 'kind': 'i32'},
+        {'name': 'bar', 'kind': 'a:x:teststruct'}],
+    'ordinal': 42}]}]
+}
+
+
+def TestRead():
+  module = data.ModuleFromData(test_dict)
+  return test_support.TestTestModule(module)
+
+
+def TestWrite():
+  module = test_support.BuildTestModule()
+  d = data.ModuleToData(module)
+  return EXPECT_TRUE(DeepEquals(test_dict, d))
+
+
+def TestWriteRead():
+  module1 = test_support.BuildTestModule()
+
+  dict1 = data.ModuleToData(module1)
+  module2 = data.ModuleFromData(dict1)
+  return EXPECT_TRUE(test_support.ModulesAreEqual(module1, module2))
+
+
+def Main(args):
+  errors = 0
+  errors += RunTest(TestWriteRead)
+  errors += RunTest(TestRead)
+  errors += RunTest(TestWrite)
+
+  return errors
+
+
+if __name__ == '__main__':
+  sys.exit(Main(sys.argv[1:]))
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/generator.py b/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
new file mode 100644
index 0000000..eb433bf
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
@@ -0,0 +1,85 @@
+# Copyright 2013 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.
+
+"""Code shared by the various language-specific code generators."""
+
+from functools import partial
+import os.path
+import re
+
+import module as mojom
+import pack
+
+def GetStructFromMethod(method):
+  """Converts a method's parameters into the fields of a struct."""
+  params_class = "%s_%s_Params" % (method.interface.name, method.name)
+  struct = mojom.Struct(params_class, module=method.interface.module)
+  for param in method.parameters:
+    struct.AddField(param.name, param.kind, param.ordinal)
+  struct.packed = pack.PackedStruct(struct)
+  return struct
+
+def GetResponseStructFromMethod(method):
+  """Converts a method's response_parameters into the fields of a struct."""
+  params_class = "%s_%s_ResponseParams" % (method.interface.name, method.name)
+  struct = mojom.Struct(params_class, module=method.interface.module)
+  for param in method.response_parameters:
+    struct.AddField(param.name, param.kind, param.ordinal)
+  struct.packed = pack.PackedStruct(struct)
+  return struct
+
+def GetDataHeader(exported, struct):
+  struct.packed = pack.PackedStruct(struct)
+  struct.bytes = pack.GetByteLayout(struct.packed)
+  struct.exported = exported
+  return struct
+
+def ExpectedArraySize(kind):
+  if mojom.IsFixedArrayKind(kind):
+    return kind.length
+  return 0
+
+def StudlyCapsToCamel(studly):
+  return studly[0].lower() + studly[1:]
+
+def CamelCaseToAllCaps(camel_case):
+  return '_'.join(
+      word for word in re.split(r'([A-Z][^A-Z]+)', camel_case) if word).upper()
+
+class Generator(object):
+  # Pass |output_dir| to emit files to disk. Omit |output_dir| to echo all
+  # files to stdout.
+  def __init__(self, module, output_dir=None):
+    self.module = module
+    self.output_dir = output_dir
+
+  def GetStructsFromMethods(self):
+    result = []
+    for interface in self.module.interfaces:
+      for method in interface.methods:
+        result.append(GetStructFromMethod(method))
+        if method.response_parameters != None:
+          result.append(GetResponseStructFromMethod(method))
+    return map(partial(GetDataHeader, False), result)
+
+  def GetStructs(self):
+    return map(partial(GetDataHeader, True), self.module.structs)
+
+  def Write(self, contents, filename):
+    if self.output_dir is None:
+      print contents
+      return
+    with open(os.path.join(self.output_dir, filename), "w+") as f:
+      f.write(contents)
+
+  def GenerateFiles(self, args):
+    raise NotImplementedError("Subclasses must override/implement this method")
+
+  def GetJinjaParameters(self):
+    """Returns default constructor parameters for the jinja environment."""
+    return {}
+
+  def GetGlobals(self):
+    """Returns global mappings for the template generation."""
+    return {}
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/mojo/public/tools/bindings/pylib/mojom/generate/module.py
new file mode 100644
index 0000000..7ae7a83
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/module.py
@@ -0,0 +1,448 @@
+# Copyright 2013 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 module's classes provide an interface to mojo modules. Modules are
+# collections of interfaces and structs to be used by mojo ipc clients and
+# servers.
+#
+# A simple interface would be created this way:
+# module = mojom.generate.module.Module('Foo')
+# interface = module.AddInterface('Bar')
+# method = interface.AddMethod('Tat', 0)
+# method.AddParameter('baz', 0, mojom.INT32)
+
+
+class Kind(object):
+  def __init__(self, spec=None):
+    self.spec = spec
+    self.parent_kind = None
+
+
+class ReferenceKind(Kind):
+  """ReferenceKind represents pointer types and handle types.
+  A type is nullable if null (for pointer types) or invalid handle (for handle
+  types) is a legal value for the type.
+  """
+
+  def __init__(self, spec=None, is_nullable=False):
+    assert spec is None or is_nullable == spec.startswith('?')
+    Kind.__init__(self, spec)
+    self.is_nullable = is_nullable
+    self.shared_definition = {}
+
+  def MakeNullableKind(self):
+    assert not self.is_nullable
+
+    if self == STRING:
+      return NULLABLE_STRING
+    if self == HANDLE:
+      return NULLABLE_HANDLE
+    if self == DCPIPE:
+      return NULLABLE_DCPIPE
+    if self == DPPIPE:
+      return NULLABLE_DPPIPE
+    if self == MSGPIPE:
+      return NULLABLE_MSGPIPE
+    if self == SHAREDBUFFER:
+      return NULLABLE_SHAREDBUFFER
+
+    nullable_kind = type(self)()
+    nullable_kind.shared_definition = self.shared_definition
+    if self.spec is not None:
+      nullable_kind.spec = '?' + self.spec
+    nullable_kind.is_nullable = True
+
+    return nullable_kind
+
+  @classmethod
+  def AddSharedProperty(cls, name):
+    """Adds a property |name| to |cls|, which accesses the corresponding item in
+       |shared_definition|.
+
+       The reason of adding such indirection is to enable sharing definition
+       between a reference kind and its nullable variation. For example:
+         a = Struct('test_struct_1')
+         b = a.MakeNullableKind()
+         a.name = 'test_struct_2'
+         print b.name  # Outputs 'test_struct_2'.
+    """
+    def Get(self):
+      return self.shared_definition[name]
+
+    def Set(self, value):
+      self.shared_definition[name] = value
+
+    setattr(cls, name, property(Get, Set))
+
+
+# Initialize the set of primitive types. These can be accessed by clients.
+BOOL                  = Kind('b')
+INT8                  = Kind('i8')
+INT16                 = Kind('i16')
+INT32                 = Kind('i32')
+INT64                 = Kind('i64')
+UINT8                 = Kind('u8')
+UINT16                = Kind('u16')
+UINT32                = Kind('u32')
+UINT64                = Kind('u64')
+FLOAT                 = Kind('f')
+DOUBLE                = Kind('d')
+STRING                = ReferenceKind('s')
+HANDLE                = ReferenceKind('h')
+DCPIPE                = ReferenceKind('h:d:c')
+DPPIPE                = ReferenceKind('h:d:p')
+MSGPIPE               = ReferenceKind('h:m')
+SHAREDBUFFER          = ReferenceKind('h:s')
+NULLABLE_STRING       = ReferenceKind('?s', True)
+NULLABLE_HANDLE       = ReferenceKind('?h', True)
+NULLABLE_DCPIPE       = ReferenceKind('?h:d:c', True)
+NULLABLE_DPPIPE       = ReferenceKind('?h:d:p', True)
+NULLABLE_MSGPIPE      = ReferenceKind('?h:m', True)
+NULLABLE_SHAREDBUFFER = ReferenceKind('?h:s', True)
+
+
+# Collection of all Primitive types
+PRIMITIVES = (
+  BOOL,
+  INT8,
+  INT16,
+  INT32,
+  INT64,
+  UINT8,
+  UINT16,
+  UINT32,
+  UINT64,
+  FLOAT,
+  DOUBLE,
+  STRING,
+  HANDLE,
+  DCPIPE,
+  DPPIPE,
+  MSGPIPE,
+  SHAREDBUFFER,
+  NULLABLE_STRING,
+  NULLABLE_HANDLE,
+  NULLABLE_DCPIPE,
+  NULLABLE_DPPIPE,
+  NULLABLE_MSGPIPE,
+  NULLABLE_SHAREDBUFFER
+)
+
+
+class NamedValue(object):
+  def __init__(self, module, parent_kind, name):
+    self.module = module
+    self.namespace = module.namespace
+    self.parent_kind = parent_kind
+    self.name = name
+    self.imported_from = None
+
+  def GetSpec(self):
+    return (self.namespace + '.' +
+        (self.parent_kind and (self.parent_kind.name + '.') or "") +
+        self.name)
+
+
+class BuiltinValue(object):
+  def __init__(self, value):
+    self.value = value
+
+
+class ConstantValue(NamedValue):
+  def __init__(self, module, parent_kind, constant):
+    NamedValue.__init__(self, module, parent_kind, constant.name)
+    self.constant = constant
+
+
+class EnumValue(NamedValue):
+  def __init__(self, module, enum, field):
+    NamedValue.__init__(self, module, enum.parent_kind, field.name)
+    self.enum = enum
+
+  def GetSpec(self):
+    return (self.namespace + '.' +
+        (self.parent_kind and (self.parent_kind.name + '.') or "") +
+        self.enum.name + '.' + self.name)
+
+
+class Constant(object):
+  def __init__(self, name=None, kind=None, value=None):
+    self.name = name
+    self.kind = kind
+    self.value = value
+
+
+class Field(object):
+  def __init__(self, name=None, kind=None, ordinal=None, default=None):
+    self.name = name
+    self.kind = kind
+    self.ordinal = ordinal
+    self.default = default
+
+
+class Struct(ReferenceKind):
+  ReferenceKind.AddSharedProperty('name')
+  ReferenceKind.AddSharedProperty('module')
+  ReferenceKind.AddSharedProperty('imported_from')
+  ReferenceKind.AddSharedProperty('fields')
+
+  def __init__(self, name=None, module=None):
+    if name is not None:
+      spec = 'x:' + name
+    else:
+      spec = None
+    ReferenceKind.__init__(self, spec)
+    self.name = name
+    self.module = module
+    self.imported_from = None
+    self.fields = []
+
+  def AddField(self, name, kind, ordinal=None, default=None):
+    field = Field(name, kind, ordinal, default)
+    self.fields.append(field)
+    return field
+
+
+class Array(ReferenceKind):
+  ReferenceKind.AddSharedProperty('kind')
+
+  def __init__(self, kind=None):
+    if kind is not None:
+      ReferenceKind.__init__(self, 'a:' + kind.spec)
+    else:
+      ReferenceKind.__init__(self)
+    self.kind = kind
+
+
+class FixedArray(ReferenceKind):
+  ReferenceKind.AddSharedProperty('kind')
+  ReferenceKind.AddSharedProperty('length')
+
+  def __init__(self, length=-1, kind=None):
+    if kind is not None:
+      ReferenceKind.__init__(self, 'a%d:%s' % (length, kind.spec))
+    else:
+      ReferenceKind.__init__(self)
+    self.kind = kind
+    self.length = length
+
+
+class InterfaceRequest(ReferenceKind):
+  ReferenceKind.AddSharedProperty('kind')
+
+  def __init__(self, kind=None):
+    if kind is not None:
+      ReferenceKind.__init__(self, 'r:' + kind.spec)
+    else:
+      ReferenceKind.__init__(self)
+    self.kind = kind
+
+
+class Parameter(object):
+  def __init__(self, name=None, kind=None, ordinal=None, default=None):
+    self.name = name
+    self.ordinal = ordinal
+    self.kind = kind
+    self.default = default
+
+
+class Method(object):
+  def __init__(self, interface, name, ordinal=None):
+    self.interface = interface
+    self.name = name
+    self.ordinal = ordinal
+    self.parameters = []
+    self.response_parameters = None
+
+  def AddParameter(self, name, kind, ordinal=None, default=None):
+    parameter = Parameter(name, kind, ordinal, default)
+    self.parameters.append(parameter)
+    return parameter
+
+  def AddResponseParameter(self, name, kind, ordinal=None, default=None):
+    if self.response_parameters == None:
+      self.response_parameters = []
+    parameter = Parameter(name, kind, ordinal, default)
+    self.response_parameters.append(parameter)
+    return parameter
+
+
+class Interface(ReferenceKind):
+  ReferenceKind.AddSharedProperty('module')
+  ReferenceKind.AddSharedProperty('name')
+  ReferenceKind.AddSharedProperty('imported_from')
+  ReferenceKind.AddSharedProperty('client')
+  ReferenceKind.AddSharedProperty('methods')
+
+  def __init__(self, name=None, client=None, module=None):
+    if name is not None:
+      spec = 'x:' + name
+    else:
+      spec = None
+    ReferenceKind.__init__(self, spec)
+    self.module = module
+    self.name = name
+    self.imported_from = None
+    self.client = client
+    self.methods = []
+
+  def AddMethod(self, name, ordinal=None):
+    method = Method(self, name, ordinal=ordinal)
+    self.methods.append(method)
+    return method
+
+
+class EnumField(object):
+  def __init__(self, name=None, value=None):
+    self.name = name
+    self.value = value
+
+
+class Enum(Kind):
+  def __init__(self, name=None, module=None):
+    self.module = module
+    self.name = name
+    self.imported_from = None
+    if name is not None:
+      spec = 'x:' + name
+    else:
+      spec = None
+    Kind.__init__(self, spec)
+    self.fields = []
+
+
+class Module(object):
+  def __init__(self, name=None, namespace=None):
+    self.name = name
+    self.path = name
+    self.namespace = namespace
+    self.structs = []
+    self.interfaces = []
+
+  def AddInterface(self, name):
+    self.interfaces.append(Interface(name, module=self))
+    return interface
+
+  def AddStruct(self, name):
+    struct=Struct(name, module=self)
+    self.structs.append(struct)
+    return struct
+
+
+def IsBoolKind(kind):
+  return kind.spec == BOOL.spec
+
+
+def IsFloatKind(kind):
+  return kind.spec == FLOAT.spec
+
+
+def IsStringKind(kind):
+  return kind.spec == STRING.spec or kind.spec == NULLABLE_STRING.spec
+
+
+def IsHandleKind(kind):
+  return kind.spec == HANDLE.spec or kind.spec == NULLABLE_HANDLE.spec
+
+
+def IsDataPipeConsumerKind(kind):
+  return kind.spec == DCPIPE.spec or kind.spec == NULLABLE_DCPIPE.spec
+
+
+def IsDataPipeProducerKind(kind):
+  return kind.spec == DPPIPE.spec or kind.spec == NULLABLE_DPPIPE.spec
+
+
+def IsMessagePipeKind(kind):
+  return kind.spec == MSGPIPE.spec or kind.spec == NULLABLE_MSGPIPE.spec
+
+
+def IsSharedBufferKind(kind):
+  return (kind.spec == SHAREDBUFFER.spec or
+          kind.spec == NULLABLE_SHAREDBUFFER.spec)
+
+
+def IsStructKind(kind):
+  return isinstance(kind, Struct)
+
+
+def IsArrayKind(kind):
+  return isinstance(kind, Array)
+
+
+def IsFixedArrayKind(kind):
+  return isinstance(kind, FixedArray)
+
+
+def IsInterfaceKind(kind):
+  return isinstance(kind, Interface)
+
+
+def IsInterfaceRequestKind(kind):
+  return isinstance(kind, InterfaceRequest)
+
+
+def IsEnumKind(kind):
+  return isinstance(kind, Enum)
+
+
+def IsReferenceKind(kind):
+  return isinstance(kind, ReferenceKind)
+
+
+def IsNullableKind(kind):
+  return IsReferenceKind(kind) and kind.is_nullable
+
+
+def IsAnyArrayKind(kind):
+  return IsArrayKind(kind) or IsFixedArrayKind(kind)
+
+
+def IsObjectKind(kind):
+  return IsStructKind(kind) or IsAnyArrayKind(kind) or IsStringKind(kind)
+
+
+def IsNonInterfaceHandleKind(kind):
+  return (IsHandleKind(kind) or
+          IsDataPipeConsumerKind(kind) or
+          IsDataPipeProducerKind(kind) or
+          IsMessagePipeKind(kind) or
+          IsSharedBufferKind(kind))
+
+
+def IsAnyHandleKind(kind):
+  return (IsNonInterfaceHandleKind(kind) or
+          IsInterfaceKind(kind) or
+          IsInterfaceRequestKind(kind))
+
+
+def IsMoveOnlyKind(kind):
+  return IsObjectKind(kind) or IsAnyHandleKind(kind)
+
+
+def IsCloneableKind(kind):
+  def ContainsHandles(kind, visited_kinds):
+    if kind in visited_kinds:
+      # No need to examine the kind again.
+      return False
+    visited_kinds.add(kind)
+    if IsAnyHandleKind(kind):
+      return True
+    if IsAnyArrayKind(kind):
+      return ContainsHandles(kind.kind, visited_kinds)
+    if IsStructKind(kind):
+      for field in kind.fields:
+        if ContainsHandles(field.kind, visited_kinds):
+          return True
+    return False
+
+  return not ContainsHandles(kind, set())
+
+
+def HasCallbacks(interface):
+  for method in interface.methods:
+    if method.response_parameters != None:
+      return True
+  return False
+
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/module_tests.py b/mojo/public/tools/bindings/pylib/mojom/generate/module_tests.py
new file mode 100644
index 0000000..a887686
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/module_tests.py
@@ -0,0 +1,34 @@
+# Copyright 2013 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.
+
+import sys
+
+import test_support
+
+EXPECT_EQ = test_support.EXPECT_EQ
+EXPECT_TRUE = test_support.EXPECT_TRUE
+RunTest = test_support.RunTest
+ModulesAreEqual = test_support.ModulesAreEqual
+BuildTestModule = test_support.BuildTestModule
+TestTestModule = test_support.TestTestModule
+
+
+def BuildAndTestModule():
+  return TestTestModule(BuildTestModule())
+
+
+def TestModulesEqual():
+  return EXPECT_TRUE(ModulesAreEqual(BuildTestModule(), BuildTestModule()))
+
+
+def Main(args):
+  errors = 0
+  errors += RunTest(BuildAndTestModule)
+  errors += RunTest(TestModulesEqual)
+
+  return errors
+
+
+if __name__ == '__main__':
+  sys.exit(Main(sys.argv[1:]))
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/pack.py b/mojo/public/tools/bindings/pylib/mojom/generate/pack.py
new file mode 100644
index 0000000..4661941
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/pack.py
@@ -0,0 +1,163 @@
+# Copyright 2013 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.
+
+import module as mojom
+
+# This module provides a mechanism for determining the packed order and offsets
+# of a mojom.Struct.
+#
+# ps = pack.PackedStruct(struct)
+# ps.packed_fields will access a list of PackedField objects, each of which
+# will have an offset, a size and a bit (for mojom.BOOLs).
+
+class PackedField(object):
+  kind_to_size = {
+    mojom.BOOL:                  1,
+    mojom.INT8:                  1,
+    mojom.UINT8:                 1,
+    mojom.INT16:                 2,
+    mojom.UINT16:                2,
+    mojom.INT32:                 4,
+    mojom.UINT32:                4,
+    mojom.FLOAT:                 4,
+    mojom.HANDLE:                4,
+    mojom.MSGPIPE:               4,
+    mojom.SHAREDBUFFER:          4,
+    mojom.DCPIPE:                4,
+    mojom.DPPIPE:                4,
+    mojom.NULLABLE_HANDLE:       4,
+    mojom.NULLABLE_MSGPIPE:      4,
+    mojom.NULLABLE_SHAREDBUFFER: 4,
+    mojom.NULLABLE_DCPIPE:       4,
+    mojom.NULLABLE_DPPIPE:       4,
+    mojom.INT64:                 8,
+    mojom.UINT64:                8,
+    mojom.DOUBLE:                8,
+    mojom.STRING:                8,
+    mojom.NULLABLE_STRING:       8
+  }
+
+  @classmethod
+  def GetSizeForKind(cls, kind):
+    if isinstance(kind, (mojom.Array, mojom.Struct, mojom.FixedArray)):
+      return 8
+    if isinstance(kind, mojom.Interface) or \
+       isinstance(kind, mojom.InterfaceRequest):
+      kind = mojom.MSGPIPE
+    if isinstance(kind, mojom.Enum):
+      # TODO(mpcomplete): what about big enums?
+      return cls.kind_to_size[mojom.INT32]
+    if not kind in cls.kind_to_size:
+      raise Exception("Invalid kind: %s" % kind.spec)
+    return cls.kind_to_size[kind]
+
+  def __init__(self, field, index, ordinal):
+    """
+    Args:
+      field: the original field.
+      index: the position of the original field in the struct.
+      ordinal: the ordinal of the field for serialization.
+    """
+    self.field = field
+    self.index = index
+    self.ordinal = ordinal
+    self.size = self.GetSizeForKind(field.kind)
+    self.offset = None
+    self.bit = None
+
+
+# Returns the pad necessary to reserve space for alignment of |size|.
+def GetPad(offset, size):
+  return (size - (offset % size)) % size
+
+
+# Returns a 2-tuple of the field offset and bit (for BOOLs)
+def GetFieldOffset(field, last_field):
+  if field.field.kind == mojom.BOOL and \
+      last_field.field.kind == mojom.BOOL and \
+      last_field.bit < 7:
+    return (last_field.offset, last_field.bit + 1)
+
+  offset = last_field.offset + last_field.size
+  pad = GetPad(offset, field.size)
+  return (offset + pad, 0)
+
+
+class PackedStruct(object):
+  def __init__(self, struct):
+    self.struct = struct
+    self.packed_fields = []
+
+    # No fields.
+    if (len(struct.fields) == 0):
+      return
+
+    # Start by sorting by ordinal.
+    src_fields = []
+    ordinal = 0
+    for index, field in enumerate(struct.fields):
+      if field.ordinal is not None:
+        ordinal = field.ordinal
+      src_fields.append(PackedField(field, index, ordinal))
+      ordinal += 1
+    src_fields.sort(key=lambda field: field.ordinal)
+
+    src_field = src_fields[0]
+    src_field.offset = 0
+    src_field.bit = 0
+    # dst_fields will contain each of the fields, in increasing offset order.
+    dst_fields = self.packed_fields
+    dst_fields.append(src_field)
+
+    # Then find first slot that each field will fit.
+    for src_field in src_fields[1:]:
+      last_field = dst_fields[0]
+      for i in xrange(1, len(dst_fields)):
+        next_field = dst_fields[i]
+        offset, bit = GetFieldOffset(src_field, last_field)
+        if offset + src_field.size <= next_field.offset:
+          # Found hole.
+          src_field.offset = offset
+          src_field.bit = bit
+          dst_fields.insert(i, src_field)
+          break
+        last_field = next_field
+      if src_field.offset is None:
+        # Add to end
+        src_field.offset, src_field.bit = GetFieldOffset(src_field, last_field)
+        dst_fields.append(src_field)
+
+  def GetTotalSize(self):
+    if not self.packed_fields:
+      return 0
+    last_field = self.packed_fields[-1]
+    offset = last_field.offset + last_field.size
+    pad = GetPad(offset, 8)
+    return offset + pad
+
+
+class ByteInfo(object):
+  def __init__(self):
+    self.is_padding = False
+    self.packed_fields = []
+
+
+def GetByteLayout(packed_struct):
+  bytes = [ByteInfo() for i in xrange(packed_struct.GetTotalSize())]
+
+  limit_of_previous_field = 0
+  for packed_field in packed_struct.packed_fields:
+    for i in xrange(limit_of_previous_field, packed_field.offset):
+      bytes[i].is_padding = True
+    bytes[packed_field.offset].packed_fields.append(packed_field)
+    limit_of_previous_field = packed_field.offset + packed_field.size
+
+  for i in xrange(limit_of_previous_field, len(bytes)):
+    bytes[i].is_padding = True
+
+  for byte in bytes:
+    # A given byte cannot both be padding and have a fields packed into it.
+    assert not (byte.is_padding and byte.packed_fields)
+
+  return bytes
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/pack_tests.py b/mojo/public/tools/bindings/pylib/mojom/generate/pack_tests.py
new file mode 100644
index 0000000..a0f664b
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/pack_tests.py
@@ -0,0 +1,193 @@
+# Copyright 2013 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.
+
+import sys
+
+import module as mojom
+import pack
+import test_support
+
+
+EXPECT_EQ = test_support.EXPECT_EQ
+EXPECT_TRUE = test_support.EXPECT_TRUE
+RunTest = test_support.RunTest
+
+
+def TestOrdinalOrder():
+  errors = 0
+  struct = mojom.Struct('test')
+  struct.AddField('testfield1', mojom.INT32, 2)
+  struct.AddField('testfield2', mojom.INT32, 1)
+  ps = pack.PackedStruct(struct)
+
+  errors += EXPECT_EQ(2, len(ps.packed_fields))
+  errors += EXPECT_EQ('testfield2', ps.packed_fields[0].field.name)
+  errors += EXPECT_EQ('testfield1', ps.packed_fields[1].field.name)
+
+  return errors
+
+def TestZeroFields():
+  errors = 0
+  struct = mojom.Struct('test')
+  ps = pack.PackedStruct(struct)
+  errors += EXPECT_EQ(0, len(ps.packed_fields))
+  return errors
+
+
+def TestOneField():
+  errors = 0
+  struct = mojom.Struct('test')
+  struct.AddField('testfield1', mojom.INT8)
+  ps = pack.PackedStruct(struct)
+  errors += EXPECT_EQ(1, len(ps.packed_fields))
+  return errors
+
+# Pass three tuples.
+# |kinds| is a sequence of mojom.Kinds that specify the fields that are to
+# be created.
+# |fields| is the expected order of the resulting fields, with the integer
+# "1" first.
+# |offsets| is the expected order of offsets, with the integer "0" first.
+def TestSequence(kinds, fields, offsets):
+  errors = 0
+  struct = mojom.Struct('test')
+  index = 1
+  for kind in kinds:
+    struct.AddField("%d" % index, kind)
+    index += 1
+  ps = pack.PackedStruct(struct)
+  num_fields = len(ps.packed_fields)
+  errors += EXPECT_EQ(len(kinds), num_fields)
+  for i in xrange(num_fields):
+    EXPECT_EQ("%d" % fields[i], ps.packed_fields[i].field.name)
+    EXPECT_EQ(offsets[i], ps.packed_fields[i].offset)
+
+  return errors
+
+
+def TestPaddingPackedInOrder():
+  return TestSequence(
+      (mojom.INT8, mojom.UINT8, mojom.INT32),
+      (1, 2, 3),
+      (0, 1, 4))
+
+
+def TestPaddingPackedOutOfOrder():
+  return TestSequence(
+      (mojom.INT8, mojom.INT32, mojom.UINT8),
+      (1, 3, 2),
+      (0, 1, 4))
+
+
+def TestPaddingPackedOverflow():
+  kinds = (mojom.INT8, mojom.INT32, mojom.INT16, mojom.INT8, mojom.INT8)
+  # 2 bytes should be packed together first, followed by short, then by int.
+  fields = (1, 4, 3, 2, 5)
+  offsets = (0, 1, 2, 4, 8)
+  return TestSequence(kinds, fields, offsets)
+
+
+def TestNullableTypes():
+  kinds = (mojom.STRING.MakeNullableKind(),
+           mojom.HANDLE.MakeNullableKind(),
+           mojom.Struct('test_struct').MakeNullableKind(),
+           mojom.DCPIPE.MakeNullableKind(),
+           mojom.Array().MakeNullableKind(),
+           mojom.DPPIPE.MakeNullableKind(),
+           mojom.FixedArray(5).MakeNullableKind(),
+           mojom.MSGPIPE.MakeNullableKind(),
+           mojom.Interface('test_inteface').MakeNullableKind(),
+           mojom.SHAREDBUFFER.MakeNullableKind(),
+           mojom.InterfaceRequest().MakeNullableKind())
+  fields = (1, 2, 4, 3, 5, 6, 8, 7, 9, 10, 11)
+  offsets = (0, 8, 12, 16, 24, 32, 36, 40, 48, 52, 56)
+  return TestSequence(kinds, fields, offsets)
+
+
+def TestAllTypes():
+  return TestSequence(
+      (mojom.BOOL, mojom.INT8, mojom.STRING, mojom.UINT8,
+       mojom.INT16, mojom.DOUBLE, mojom.UINT16,
+       mojom.INT32, mojom.UINT32, mojom.INT64,
+       mojom.FLOAT, mojom.STRING, mojom.HANDLE,
+       mojom.UINT64, mojom.Struct('test'), mojom.Array(),
+       mojom.STRING.MakeNullableKind()),
+      (1, 2, 4, 5, 7, 3, 6,  8,  9,  10, 11, 13, 12, 14, 15, 16, 17, 18),
+      (0, 1, 2, 4, 6, 8, 16, 24, 28, 32, 40, 44, 48, 56, 64, 72, 80, 88))
+
+
+def TestPaddingPackedOutOfOrderByOrdinal():
+  errors = 0
+  struct = mojom.Struct('test')
+  struct.AddField('testfield1', mojom.INT8)
+  struct.AddField('testfield3', mojom.UINT8, 3)
+  struct.AddField('testfield2', mojom.INT32, 2)
+  ps = pack.PackedStruct(struct)
+  errors += EXPECT_EQ(3, len(ps.packed_fields))
+
+  # Second byte should be packed in behind first, altering order.
+  errors += EXPECT_EQ('testfield1', ps.packed_fields[0].field.name)
+  errors += EXPECT_EQ('testfield3', ps.packed_fields[1].field.name)
+  errors += EXPECT_EQ('testfield2', ps.packed_fields[2].field.name)
+
+  # Second byte should be packed with first.
+  errors += EXPECT_EQ(0, ps.packed_fields[0].offset)
+  errors += EXPECT_EQ(1, ps.packed_fields[1].offset)
+  errors += EXPECT_EQ(4, ps.packed_fields[2].offset)
+
+  return errors
+
+
+def TestBools():
+  errors = 0
+  struct = mojom.Struct('test')
+  struct.AddField('bit0', mojom.BOOL)
+  struct.AddField('bit1', mojom.BOOL)
+  struct.AddField('int', mojom.INT32)
+  struct.AddField('bit2', mojom.BOOL)
+  struct.AddField('bit3', mojom.BOOL)
+  struct.AddField('bit4', mojom.BOOL)
+  struct.AddField('bit5', mojom.BOOL)
+  struct.AddField('bit6', mojom.BOOL)
+  struct.AddField('bit7', mojom.BOOL)
+  struct.AddField('bit8', mojom.BOOL)
+  ps = pack.PackedStruct(struct)
+  errors += EXPECT_EQ(10, len(ps.packed_fields))
+
+  # First 8 bits packed together.
+  for i in xrange(8):
+    pf = ps.packed_fields[i]
+    errors += EXPECT_EQ(0, pf.offset)
+    errors += EXPECT_EQ("bit%d" % i, pf.field.name)
+    errors += EXPECT_EQ(i, pf.bit)
+
+  # Ninth bit goes into second byte.
+  errors += EXPECT_EQ("bit8", ps.packed_fields[8].field.name)
+  errors += EXPECT_EQ(1, ps.packed_fields[8].offset)
+  errors += EXPECT_EQ(0, ps.packed_fields[8].bit)
+
+  # int comes last.
+  errors += EXPECT_EQ("int", ps.packed_fields[9].field.name)
+  errors += EXPECT_EQ(4, ps.packed_fields[9].offset)
+
+  return errors
+
+
+def Main(args):
+  errors = 0
+  errors += RunTest(TestZeroFields)
+  errors += RunTest(TestOneField)
+  errors += RunTest(TestPaddingPackedInOrder)
+  errors += RunTest(TestPaddingPackedOutOfOrder)
+  errors += RunTest(TestPaddingPackedOverflow)
+  errors += RunTest(TestNullableTypes)
+  errors += RunTest(TestAllTypes)
+  errors += RunTest(TestPaddingPackedOutOfOrderByOrdinal)
+  errors += RunTest(TestBools)
+
+  return errors
+
+
+if __name__ == '__main__':
+  sys.exit(Main(sys.argv[1:]))
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/run_tests.py b/mojo/public/tools/bindings/pylib/mojom/generate/run_tests.py
new file mode 100755
index 0000000..41f11a2
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/run_tests.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# Copyright 2013 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.
+
+""" Test runner for Mojom """
+
+import subprocess
+import sys
+
+def TestMojom(testname, args):
+  print '\nRunning unit tests for %s.' % testname
+  try:
+    args = [sys.executable, testname] + args
+    subprocess.check_call(args, stdout=sys.stdout)
+    print 'Succeeded'
+    return 0
+  except subprocess.CalledProcessError as err:
+    print 'Failed with %s.' % str(err)
+    return 1
+
+
+def main(args):
+  errors = 0
+  errors += TestMojom('data_tests.py', ['--test'])
+  errors += TestMojom('module_tests.py', ['--test'])
+  errors += TestMojom('pack_tests.py', ['--test'])
+
+  if errors:
+    print '\nFailed tests.'
+  return min(errors, 127)  # Make sure the return value doesn't "wrap".
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py b/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py
new file mode 100644
index 0000000..3801d43
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py
@@ -0,0 +1,59 @@
+# Copyright 2013 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.
+
+# Based on:
+# http://src.chromium.org/viewvc/blink/trunk/Source/build/scripts/template_expander.py
+
+import imp
+import inspect
+import os.path
+import sys
+
+# Disable lint check for finding modules:
+# pylint: disable=F0401
+
+def _GetDirAbove(dirname):
+  """Returns the directory "above" this file containing |dirname| (which must
+  also be "above" this file)."""
+  path = os.path.abspath(__file__)
+  while True:
+    path, tail = os.path.split(path)
+    assert tail
+    if tail == dirname:
+      return path
+
+try:
+  imp.find_module("jinja2")
+except ImportError:
+  sys.path.append(os.path.join(_GetDirAbove("mojo"), "third_party"))
+import jinja2
+
+
+def ApplyTemplate(mojo_generator, base_dir, path_to_template, params,
+                  filters=None, **kwargs):
+  template_directory, template_name = os.path.split(path_to_template)
+  path_to_templates = os.path.join(base_dir, template_directory)
+  loader = jinja2.FileSystemLoader([path_to_templates])
+  final_kwargs = dict(mojo_generator.GetJinjaParameters())
+  final_kwargs.update(kwargs)
+  jinja_env = jinja2.Environment(loader=loader, keep_trailing_newline=True,
+                                 **final_kwargs)
+  jinja_env.globals.update(mojo_generator.GetGlobals())
+  if filters:
+    jinja_env.filters.update(filters)
+  template = jinja_env.get_template(template_name)
+  return template.render(params)
+
+
+def UseJinja(path_to_template, **kwargs):
+  # Get the directory of our caller's file.
+  base_dir = os.path.dirname(inspect.getfile(sys._getframe(1)))
+  def RealDecorator(generator):
+    def GeneratorInternal(*args, **kwargs2):
+      parameters = generator(*args, **kwargs2)
+      return ApplyTemplate(args[0], base_dir, path_to_template, parameters,
+                           **kwargs)
+    GeneratorInternal.func_name = generator.func_name
+    return GeneratorInternal
+  return RealDecorator
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/test_support.py b/mojo/public/tools/bindings/pylib/mojom/generate/test_support.py
new file mode 100644
index 0000000..eb39461
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/test_support.py
@@ -0,0 +1,193 @@
+# Copyright 2013 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.
+
+import sys
+import traceback
+
+import module as mojom
+
+# Support for writing mojom test cases.
+# RunTest(fn) will execute fn, catching any exceptions. fn should return
+# the number of errors that are encountered.
+#
+# EXPECT_EQ(a, b) and EXPECT_TRUE(b) will print error information if the
+# expectations are not true and return a non zero value. This allows test cases
+# to be written like this
+#
+# def Foo():
+#   errors = 0
+#   errors += EXPECT_EQ('test', test())
+#   ...
+#   return errors
+#
+# RunTest(foo)
+
+def FieldsAreEqual(field1, field2):
+  if field1 == field2:
+    return True
+  return field1.name == field2.name and \
+      KindsAreEqual(field1.kind, field2.kind) and \
+      field1.ordinal == field2.ordinal and \
+      field1.default == field2.default
+
+
+def KindsAreEqual(kind1, kind2):
+  if kind1 == kind2:
+    return True
+  if kind1.__class__ != kind2.__class__ or kind1.spec != kind2.spec:
+    return False
+  if kind1.__class__ == mojom.Kind:
+    return kind1.spec == kind2.spec
+  if kind1.__class__ == mojom.Struct:
+    if kind1.name != kind2.name or \
+        kind1.spec != kind2.spec or \
+        len(kind1.fields) != len(kind2.fields):
+      return False
+    for i in range(len(kind1.fields)):
+      if not FieldsAreEqual(kind1.fields[i], kind2.fields[i]):
+        return False
+    return True
+  if kind1.__class__ == mojom.Array:
+    return KindsAreEqual(kind1.kind, kind2.kind)
+  print 'Unknown Kind class: ', kind1.__class__.__name__
+  return False
+
+
+def ParametersAreEqual(parameter1, parameter2):
+  if parameter1 == parameter2:
+    return True
+  return parameter1.name == parameter2.name and \
+     parameter1.ordinal == parameter2.ordinal and \
+     parameter1.default == parameter2.default and \
+     KindsAreEqual(parameter1.kind, parameter2.kind)
+
+
+def MethodsAreEqual(method1, method2):
+  if method1 == method2:
+    return True
+  if method1.name != method2.name or \
+      method1.ordinal != method2.ordinal or \
+      len(method1.parameters) != len(method2.parameters):
+    return False
+  for i in range(len(method1.parameters)):
+    if not ParametersAreEqual(method1.parameters[i], method2.parameters[i]):
+      return False
+  return True
+
+
+def InterfacesAreEqual(interface1, interface2):
+  if interface1 == interface2:
+    return True
+  if interface1.name != interface2.name or \
+      len(interface1.methods) != len(interface2.methods):
+    return False
+  for i in range(len(interface1.methods)):
+    if not MethodsAreEqual(interface1.methods[i], interface2.methods[i]):
+      return False
+  return True
+
+
+def ModulesAreEqual(module1, module2):
+  if module1 == module2:
+    return True
+  if module1.name != module2.name or \
+      module1.namespace != module2.namespace or \
+      len(module1.structs) != len(module2.structs) or \
+      len(module1.interfaces) != len(module2.interfaces):
+    return False
+  for i in range(len(module1.structs)):
+    if not KindsAreEqual(module1.structs[i], module2.structs[i]):
+      return False
+  for i in range(len(module1.interfaces)):
+    if not InterfacesAreEqual(module1.interfaces[i], module2.interfaces[i]):
+      return False
+  return True
+
+
+# Builds and returns a Module suitable for testing/
+def BuildTestModule():
+  module = mojom.Module('test', 'testspace')
+  struct = module.AddStruct('teststruct')
+  struct.AddField('testfield1', mojom.INT32)
+  struct.AddField('testfield2', mojom.Array(mojom.INT32), 42)
+
+  interface = module.AddInterface('Server')
+  method = interface.AddMethod('Foo', 42)
+  method.AddParameter('foo', mojom.INT32)
+  method.AddParameter('bar', mojom.Array(struct))
+
+  return module
+
+
+# Tests if |module| is as built by BuildTestModule(). Returns the number of
+# errors
+def TestTestModule(module):
+  errors = 0
+
+  errors += EXPECT_EQ('test', module.name)
+  errors += EXPECT_EQ('testspace', module.namespace)
+  errors += EXPECT_EQ(1, len(module.structs))
+  errors += EXPECT_EQ('teststruct', module.structs[0].name)
+  errors += EXPECT_EQ(2, len(module.structs[0].fields))
+  errors += EXPECT_EQ('testfield1', module.structs[0].fields[0].name)
+  errors += EXPECT_EQ(mojom.INT32, module.structs[0].fields[0].kind)
+  errors += EXPECT_EQ('testfield2', module.structs[0].fields[1].name)
+  errors += EXPECT_EQ(mojom.Array, module.structs[0].fields[1].kind.__class__)
+  errors += EXPECT_EQ(mojom.INT32, module.structs[0].fields[1].kind.kind)
+
+  errors += EXPECT_EQ(1, len(module.interfaces))
+  errors += EXPECT_EQ('Server', module.interfaces[0].name)
+  errors += EXPECT_EQ(1, len(module.interfaces[0].methods))
+  errors += EXPECT_EQ('Foo', module.interfaces[0].methods[0].name)
+  errors += EXPECT_EQ(2, len(module.interfaces[0].methods[0].parameters))
+  errors += EXPECT_EQ('foo', module.interfaces[0].methods[0].parameters[0].name)
+  errors += EXPECT_EQ(mojom.INT32,
+                      module.interfaces[0].methods[0].parameters[0].kind)
+  errors += EXPECT_EQ('bar', module.interfaces[0].methods[0].parameters[1].name)
+  errors += EXPECT_EQ(
+    mojom.Array,
+    module.interfaces[0].methods[0].parameters[1].kind.__class__)
+  errors += EXPECT_EQ(
+    module.structs[0],
+    module.interfaces[0].methods[0].parameters[1].kind.kind)
+  return errors
+
+
+def PrintFailure(string):
+  stack = traceback.extract_stack()
+  frame = stack[len(stack)-3]
+  sys.stderr.write("ERROR at %s:%d, %s\n" % (frame[0], frame[1], string))
+  print "Traceback:"
+  for line in traceback.format_list(stack[:len(stack)-2]):
+    sys.stderr.write(line)
+
+
+def EXPECT_EQ(a, b):
+  if a != b:
+    PrintFailure("%s != %s" % (a, b))
+    return 1
+  return 0
+
+
+def EXPECT_TRUE(a):
+  if not a:
+    PrintFailure('Expecting True')
+    return 1
+  return 0
+
+
+def RunTest(fn):
+  sys.stdout.write('Running %s...' % fn.__name__)
+  try:
+    errors = fn()
+  except:
+    traceback.print_exc(sys.stderr)
+    errors = 1
+  if errors == 0:
+    sys.stdout.write('OK\n')
+  elif errors == 1:
+    sys.stdout.write('1 ERROR\n')
+  else:
+    sys.stdout.write('%d ERRORS\n' % errors)
+  return errors
diff --git a/mojo/public/tools/bindings/pylib/mojom/parse/__init__.py b/mojo/public/tools/bindings/pylib/mojom/parse/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/parse/__init__.py
diff --git a/mojo/public/tools/bindings/pylib/mojom/parse/ast.py b/mojo/public/tools/bindings/pylib/mojom/parse/ast.py
new file mode 100644
index 0000000..1612d98
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/parse/ast.py
@@ -0,0 +1,354 @@
+# Copyright 2014 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.
+
+"""Node classes for the AST for a Mojo IDL file."""
+
+# Note: For convenience of testing, you probably want to define __eq__() methods
+# for all node types; it's okay to be slightly lax (e.g., not compare filename
+# and lineno). You may also define __repr__() to help with analyzing test
+# failures, especially for more complex types.
+
+
+class NodeBase(object):
+  """Base class for nodes in the AST."""
+
+  def __init__(self, filename=None, lineno=None):
+    self.filename = filename
+    self.lineno = lineno
+
+  def __eq__(self, other):
+    return type(self) == type(other)
+
+  # Make != the inverse of ==. (Subclasses shouldn't have to override this.)
+  def __ne__(self, other):
+    return not self == other
+
+
+# TODO(vtl): Some of this is complicated enough that it should be tested.
+class NodeListBase(NodeBase):
+  """Represents a list of other nodes, all having the same type. (This is meant
+  to be subclassed, with subclasses defining _list_item_type to be the class (or
+  classes, in a tuple) of the members of the list.)"""
+
+  def __init__(self, item_or_items=None, **kwargs):
+    super(NodeListBase, self).__init__(**kwargs)
+    self.items = []
+    if item_or_items is None:
+      pass
+    elif isinstance(item_or_items, list):
+      for item in item_or_items:
+        assert isinstance(item, self._list_item_type)
+        self.Append(item)
+    else:
+      assert isinstance(item_or_items, self._list_item_type)
+      self.Append(item_or_items)
+
+  # Support iteration. For everything else, users should just access |items|
+  # directly. (We intentionally do NOT supply |__len__()| or |__nonzero__()|, so
+  # |bool(NodeListBase())| is true.)
+  def __iter__(self):
+    return self.items.__iter__()
+
+  def __eq__(self, other):
+    return super(NodeListBase, self).__eq__(other) and \
+           self.items == other.items
+
+  # Implement this so that on failure, we get slightly more sensible output.
+  def __repr__(self):
+    return self.__class__.__name__ + "([" + \
+           ", ".join([repr(elem) for elem in self.items]) + "])"
+
+  def Insert(self, item):
+    """Inserts item at the front of the list."""
+
+    assert isinstance(item, self._list_item_type)
+    self.items.insert(0, item)
+    self._UpdateFilenameAndLineno()
+
+  def Append(self, item):
+    """Appends item to the end of the list."""
+
+    assert isinstance(item, self._list_item_type)
+    self.items.append(item)
+    self._UpdateFilenameAndLineno()
+
+  def _UpdateFilenameAndLineno(self):
+    if self.items:
+      self.filename = self.items[0].filename
+      self.lineno = self.items[0].lineno
+
+
+class Definition(NodeBase):
+  """Represents a definition of anything that has a global name (e.g., enums,
+  enum values, consts, structs, struct fields, interfaces). (This does not
+  include parameter definitions.) This class is meant to be subclassed."""
+
+  def __init__(self, name, **kwargs):
+    assert isinstance(name, str)
+    NodeBase.__init__(self, **kwargs)
+    self.name = name
+
+
+################################################################################
+
+
+class Attribute(NodeBase):
+  """Represents an attribute."""
+
+  def __init__(self, key, value, **kwargs):
+    assert isinstance(key, str)
+    super(Attribute, self).__init__(**kwargs)
+    self.key = key
+    self.value = value
+
+  def __eq__(self, other):
+    return super(Attribute, self).__eq__(other) and \
+           self.key == other.key and \
+           self.value == other.value
+
+
+class AttributeList(NodeListBase):
+  """Represents a list attributes."""
+
+  _list_item_type = Attribute
+
+
+class Const(Definition):
+  """Represents a const definition."""
+
+  def __init__(self, name, typename, value, **kwargs):
+    # The typename is currently passed through as a string.
+    assert isinstance(typename, str)
+    # The value is either a literal (currently passed through as a string) or a
+    # "wrapped identifier".
+    assert isinstance(value, str) or isinstance(value, tuple)
+    super(Const, self).__init__(name, **kwargs)
+    self.typename = typename
+    self.value = value
+
+  def __eq__(self, other):
+    return super(Const, self).__eq__(other) and \
+           self.typename == other.typename and \
+           self.value == other.value
+
+
+class Enum(Definition):
+  """Represents an enum definition."""
+
+  def __init__(self, name, enum_value_list, **kwargs):
+    assert isinstance(enum_value_list, EnumValueList)
+    super(Enum, self).__init__(name, **kwargs)
+    self.enum_value_list = enum_value_list
+
+  def __eq__(self, other):
+    return super(Enum, self).__eq__(other) and \
+           self.enum_value_list == other.enum_value_list
+
+
+class EnumValue(Definition):
+  """Represents a definition of an enum value."""
+
+  def __init__(self, name, value, **kwargs):
+    # The optional value is either an int (which is current a string) or a
+    # "wrapped identifier".
+    assert value is None or isinstance(value, (str, tuple))
+    super(EnumValue, self).__init__(name, **kwargs)
+    self.value = value
+
+  def __eq__(self, other):
+    return super(EnumValue, self).__eq__(other) and \
+           self.value == other.value
+
+
+class EnumValueList(NodeListBase):
+  """Represents a list of enum value definitions (i.e., the "body" of an enum
+  definition)."""
+
+  _list_item_type = EnumValue
+
+
+class Import(NodeBase):
+  """Represents an import statement."""
+
+  def __init__(self, import_filename, **kwargs):
+    assert isinstance(import_filename, str)
+    super(Import, self).__init__(**kwargs)
+    self.import_filename = import_filename
+
+  def __eq__(self, other):
+    return super(Import, self).__eq__(other) and \
+           self.import_filename == other.import_filename
+
+
+class ImportList(NodeListBase):
+  """Represents a list (i.e., sequence) of import statements."""
+
+  _list_item_type = Import
+
+
+class Interface(Definition):
+  """Represents an interface definition."""
+
+  def __init__(self, name, attribute_list, body, **kwargs):
+    assert attribute_list is None or isinstance(attribute_list, AttributeList)
+    assert isinstance(body, InterfaceBody)
+    super(Interface, self).__init__(name, **kwargs)
+    self.attribute_list = attribute_list
+    self.body = body
+
+  def __eq__(self, other):
+    return super(Interface, self).__eq__(other) and \
+           self.attribute_list == other.attribute_list and \
+           self.body == other.body
+
+
+class Method(Definition):
+  """Represents a method definition."""
+
+  def __init__(self, name, ordinal, parameter_list, response_parameter_list,
+               **kwargs):
+    assert ordinal is None or isinstance(ordinal, Ordinal)
+    assert isinstance(parameter_list, ParameterList)
+    assert response_parameter_list is None or \
+           isinstance(response_parameter_list, ParameterList)
+    super(Method, self).__init__(name, **kwargs)
+    self.ordinal = ordinal
+    self.parameter_list = parameter_list
+    self.response_parameter_list = response_parameter_list
+
+  def __eq__(self, other):
+    return super(Method, self).__eq__(other) and \
+           self.ordinal == other.ordinal and \
+           self.parameter_list == other.parameter_list and \
+           self.response_parameter_list == other.response_parameter_list
+
+
+# This needs to be declared after |Method|.
+class InterfaceBody(NodeListBase):
+  """Represents the body of (i.e., list of definitions inside) an interface."""
+
+  _list_item_type = (Const, Enum, Method)
+
+
+class Module(NodeBase):
+  """Represents a module statement."""
+
+  def __init__(self, name, attribute_list, **kwargs):
+    # |name| is either none or a "wrapped identifier".
+    assert name is None or isinstance(name, tuple)
+    assert attribute_list is None or isinstance(attribute_list, AttributeList)
+    super(Module, self).__init__(**kwargs)
+    self.name = name
+    self.attribute_list = attribute_list
+
+  def __eq__(self, other):
+    return super(Module, self).__eq__(other) and \
+           self.name == other.name and \
+           self.attribute_list == other.attribute_list
+
+
+class Mojom(NodeBase):
+  """Represents an entire .mojom file. (This is the root node."""
+
+  def __init__(self, module, import_list, definition_list, **kwargs):
+    assert module is None or isinstance(module, Module)
+    assert isinstance(import_list, ImportList)
+    assert isinstance(definition_list, list)
+    super(Mojom, self).__init__(**kwargs)
+    self.module = module
+    self.import_list = import_list
+    self.definition_list = definition_list
+
+  def __eq__(self, other):
+    return super(Mojom, self).__eq__(other) and \
+           self.module == other.module and \
+           self.import_list == other.import_list and \
+           self.definition_list == other.definition_list
+
+  def __repr__(self):
+    return "%s(%r, %r, %r)" % (self.__class__.__name__, self.module,
+                               self.import_list, self.definition_list)
+
+
+class Ordinal(NodeBase):
+  """Represents an ordinal value labeling, e.g., a struct field."""
+
+  def __init__(self, value, **kwargs):
+    assert isinstance(value, int)
+    super(Ordinal, self).__init__(**kwargs)
+    self.value = value
+
+  def __eq__(self, other):
+    return super(Ordinal, self).__eq__(other) and \
+           self.value == other.value
+
+
+class Parameter(NodeBase):
+  """Represents a method request or response parameter."""
+
+  def __init__(self, name, ordinal, typename, **kwargs):
+    assert isinstance(name, str)
+    assert ordinal is None or isinstance(ordinal, Ordinal)
+    assert isinstance(typename, str)
+    super(Parameter, self).__init__(**kwargs)
+    self.name = name
+    self.ordinal = ordinal
+    self.typename = typename
+
+  def __eq__(self, other):
+    return super(Parameter, self).__eq__(other) and \
+           self.name == other.name and \
+           self.ordinal == other.ordinal and \
+           self.typename == other.typename
+
+
+class ParameterList(NodeListBase):
+  """Represents a list of (method request or response) parameters."""
+
+  _list_item_type = Parameter
+
+
+class Struct(Definition):
+  """Represents a struct definition."""
+
+  def __init__(self, name, attribute_list, body, **kwargs):
+    assert attribute_list is None or isinstance(attribute_list, AttributeList)
+    assert isinstance(body, StructBody)
+    super(Struct, self).__init__(name, **kwargs)
+    self.attribute_list = attribute_list
+    self.body = body
+
+  def __eq__(self, other):
+    return super(Struct, self).__eq__(other) and \
+           self.attribute_list == other.attribute_list and \
+           self.body == other.body
+
+
+class StructField(Definition):
+  """Represents a struct field definition."""
+
+  def __init__(self, name, ordinal, typename, default_value, **kwargs):
+    assert isinstance(name, str)
+    assert ordinal is None or isinstance(ordinal, Ordinal)
+    assert isinstance(typename, str)
+    # The optional default value is currently either a value as a string or a
+    # "wrapped identifier".
+    assert default_value is None or isinstance(default_value, (str, tuple))
+    super(StructField, self).__init__(name, **kwargs)
+    self.ordinal = ordinal
+    self.typename = typename
+    self.default_value = default_value
+
+  def __eq__(self, other):
+    return super(StructField, self).__eq__(other) and \
+           self.ordinal == other.ordinal and \
+           self.typename == other.typename and \
+           self.default_value == other.default_value
+
+
+# This needs to be declared after |StructField|.
+class StructBody(NodeListBase):
+  """Represents the body of (i.e., list of definitions inside) a struct."""
+
+  _list_item_type = (Const, Enum, StructField)
diff --git a/mojo/public/tools/bindings/pylib/mojom/parse/lexer.py b/mojo/public/tools/bindings/pylib/mojom/parse/lexer.py
new file mode 100644
index 0000000..b13fac3
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/parse/lexer.py
@@ -0,0 +1,251 @@
+# Copyright 2014 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.
+
+import imp
+import os.path
+import sys
+
+def _GetDirAbove(dirname):
+  """Returns the directory "above" this file containing |dirname| (which must
+  also be "above" this file)."""
+  path = os.path.abspath(__file__)
+  while True:
+    path, tail = os.path.split(path)
+    assert tail
+    if tail == dirname:
+      return path
+
+try:
+  imp.find_module("ply")
+except ImportError:
+  sys.path.append(os.path.join(_GetDirAbove("mojo"), "third_party"))
+from ply.lex import TOKEN
+
+from ..error import Error
+
+
+class LexError(Error):
+  """Class for errors from the lexer."""
+
+  def __init__(self, filename, message, lineno):
+    Error.__init__(self, filename, message, lineno=lineno)
+
+
+# We have methods which look like they could be functions:
+# pylint: disable=R0201
+class Lexer(object):
+
+  def __init__(self, filename):
+    self.filename = filename
+
+  ######################--   PRIVATE   --######################
+
+  ##
+  ## Internal auxiliary methods
+  ##
+  def _error(self, msg, token):
+    raise LexError(self.filename, msg, token.lineno)
+
+  ##
+  ## Reserved keywords
+  ##
+  keywords = (
+    'HANDLE',
+
+    'IMPORT',
+    'MODULE',
+    'STRUCT',
+    'INTERFACE',
+    'ENUM',
+    'CONST',
+    'TRUE',
+    'FALSE',
+    'DEFAULT',
+    'ARRAY'
+  )
+
+  keyword_map = {}
+  for keyword in keywords:
+    keyword_map[keyword.lower()] = keyword
+
+  ##
+  ## All the tokens recognized by the lexer
+  ##
+  tokens = keywords + (
+    # Identifiers
+    'NAME',
+
+    # Constants
+    'ORDINAL',
+    'INT_CONST_DEC', 'INT_CONST_HEX',
+    'FLOAT_CONST',
+
+    # String literals
+    'STRING_LITERAL',
+
+    # Operators
+    'MINUS',
+    'PLUS',
+    'AMP',
+    'QSTN',
+
+    # Assignment
+    'EQUALS',
+
+    # Request / response
+    'RESPONSE',
+
+    # Delimiters
+    'LPAREN', 'RPAREN',         # ( )
+    'LBRACKET', 'RBRACKET',     # [ ]
+    'LBRACE', 'RBRACE',         # { }
+    'LANGLE', 'RANGLE',         # < >
+    'SEMI',                     # ;
+    'COMMA', 'DOT'              # , .
+  )
+
+  ##
+  ## Regexes for use in tokens
+  ##
+
+  # valid C identifiers (K&R2: A.2.3)
+  identifier = r'[a-zA-Z_][0-9a-zA-Z_]*'
+
+  hex_prefix = '0[xX]'
+  hex_digits = '[0-9a-fA-F]+'
+
+  # integer constants (K&R2: A.2.5.1)
+  decimal_constant = '0|([1-9][0-9]*)'
+  hex_constant = hex_prefix+hex_digits
+  # Don't allow octal constants (even invalid octal).
+  octal_constant_disallowed = '0[0-9]+'
+
+  # character constants (K&R2: A.2.5.2)
+  # Note: a-zA-Z and '.-~^_!=&;,' are allowed as escape chars to support #line
+  # directives with Windows paths as filenames (..\..\dir\file)
+  # For the same reason, decimal_escape allows all digit sequences. We want to
+  # parse all correct code, even if it means to sometimes parse incorrect
+  # code.
+  #
+  simple_escape = r"""([a-zA-Z._~!=&\^\-\\?'"])"""
+  decimal_escape = r"""(\d+)"""
+  hex_escape = r"""(x[0-9a-fA-F]+)"""
+  bad_escape = r"""([\\][^a-zA-Z._~^!=&\^\-\\?'"x0-7])"""
+
+  escape_sequence = \
+      r"""(\\("""+simple_escape+'|'+decimal_escape+'|'+hex_escape+'))'
+
+  # string literals (K&R2: A.2.6)
+  string_char = r"""([^"\\\n]|"""+escape_sequence+')'
+  string_literal = '"'+string_char+'*"'
+  bad_string_literal = '"'+string_char+'*'+bad_escape+string_char+'*"'
+
+  # floating constants (K&R2: A.2.5.3)
+  exponent_part = r"""([eE][-+]?[0-9]+)"""
+  fractional_constant = r"""([0-9]*\.[0-9]+)|([0-9]+\.)"""
+  floating_constant = \
+      '(((('+fractional_constant+')'+ \
+      exponent_part+'?)|([0-9]+'+exponent_part+')))'
+
+  # Ordinals
+  ordinal = r'@[0-9]+'
+  missing_ordinal_value = r'@'
+  # Don't allow ordinal values in octal (even invalid octal, like 09) or
+  # hexadecimal.
+  octal_or_hex_ordinal_disallowed = r'@((0[0-9]+)|('+hex_prefix+hex_digits+'))'
+
+  ##
+  ## Rules for the normal state
+  ##
+  t_ignore = ' \t\r'
+
+  # Newlines
+  def t_NEWLINE(self, t):
+    r'\n+'
+    t.lexer.lineno += len(t.value)
+
+  # Operators
+  t_MINUS             = r'-'
+  t_PLUS              = r'\+'
+  t_AMP               = r'&'
+  t_QSTN              = r'\?'
+
+  # =
+  t_EQUALS            = r'='
+
+  # =>
+  t_RESPONSE          = r'=>'
+
+  # Delimiters
+  t_LPAREN            = r'\('
+  t_RPAREN            = r'\)'
+  t_LBRACKET          = r'\['
+  t_RBRACKET          = r'\]'
+  t_LBRACE            = r'\{'
+  t_RBRACE            = r'\}'
+  t_LANGLE            = r'<'
+  t_RANGLE            = r'>'
+  t_COMMA             = r','
+  t_DOT               = r'\.'
+  t_SEMI              = r';'
+
+  t_STRING_LITERAL    = string_literal
+
+  # The following floating and integer constants are defined as
+  # functions to impose a strict order (otherwise, decimal
+  # is placed before the others because its regex is longer,
+  # and this is bad)
+  #
+  @TOKEN(floating_constant)
+  def t_FLOAT_CONST(self, t):
+    return t
+
+  @TOKEN(hex_constant)
+  def t_INT_CONST_HEX(self, t):
+    return t
+
+  @TOKEN(octal_constant_disallowed)
+  def t_OCTAL_CONSTANT_DISALLOWED(self, t):
+    msg = "Octal values not allowed"
+    self._error(msg, t)
+
+  @TOKEN(decimal_constant)
+  def t_INT_CONST_DEC(self, t):
+    return t
+
+  # unmatched string literals are caught by the preprocessor
+
+  @TOKEN(bad_string_literal)
+  def t_BAD_STRING_LITERAL(self, t):
+    msg = "String contains invalid escape code"
+    self._error(msg, t)
+
+  # Handle ordinal-related tokens in the right order:
+  @TOKEN(octal_or_hex_ordinal_disallowed)
+  def t_OCTAL_OR_HEX_ORDINAL_DISALLOWED(self, t):
+    msg = "Octal and hexadecimal ordinal values not allowed"
+    self._error(msg, t)
+
+  @TOKEN(ordinal)
+  def t_ORDINAL(self, t):
+    return t
+
+  @TOKEN(missing_ordinal_value)
+  def t_BAD_ORDINAL(self, t):
+    msg = "Missing ordinal value"
+    self._error(msg, t)
+
+  @TOKEN(identifier)
+  def t_NAME(self, t):
+    t.type = self.keyword_map.get(t.value, "NAME")
+    return t
+
+  # Ignore C and C++ style comments
+  def t_COMMENT(self, t):
+    r'(/\*(.|\n)*?\*/)|(//.*(\n[ \t]*//.*)*)'
+    t.lexer.lineno += t.value.count("\n")
+
+  def t_error(self, t):
+    msg = "Illegal character %s" % repr(t.value[0])
+    self._error(msg, t)
diff --git a/mojo/public/tools/bindings/pylib/mojom/parse/parser.py b/mojo/public/tools/bindings/pylib/mojom/parse/parser.py
new file mode 100644
index 0000000..551c049
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/parse/parser.py
@@ -0,0 +1,383 @@
+# Copyright 2014 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.
+
+"""Generates a syntax tree from a Mojo IDL file."""
+
+import imp
+import os.path
+import sys
+
+def _GetDirAbove(dirname):
+  """Returns the directory "above" this file containing |dirname| (which must
+  also be "above" this file)."""
+  path = os.path.abspath(__file__)
+  while True:
+    path, tail = os.path.split(path)
+    assert tail
+    if tail == dirname:
+      return path
+
+try:
+  imp.find_module("ply")
+except ImportError:
+  sys.path.append(os.path.join(_GetDirAbove("mojo"), "third_party"))
+from ply import lex
+from ply import yacc
+
+from ..error import Error
+from . import ast
+from .lexer import Lexer
+
+
+_MAX_ORDINAL_VALUE = 0xffffffff
+_MAX_ARRAY_SIZE = 0xffffffff
+
+
+class ParseError(Error):
+  """Class for errors from the parser."""
+
+  def __init__(self, filename, message, lineno=None, snippet=None):
+    Error.__init__(self, filename, message, lineno=lineno,
+                   addenda=([snippet] if snippet else None))
+
+
+# We have methods which look like they could be functions:
+# pylint: disable=R0201
+class Parser(object):
+
+  def __init__(self, lexer, source, filename):
+    self.tokens = lexer.tokens
+    self.source = source
+    self.filename = filename
+
+  # Names of functions
+  #
+  # In general, we name functions after the left-hand-side of the rule(s) that
+  # they handle. E.g., |p_foo_bar| for a rule |foo_bar : ...|.
+  #
+  # There may be multiple functions handling rules for the same left-hand-side;
+  # then we name the functions |p_foo_bar_N| (for left-hand-side |foo_bar|),
+  # where N is a number (numbered starting from 1). Note that using multiple
+  # functions is actually more efficient than having single functions handle
+  # multiple rules (and, e.g., distinguishing them by examining |len(p)|).
+  #
+  # It's also possible to have a function handling multiple rules with different
+  # left-hand-sides. We do not do this.
+  #
+  # See http://www.dabeaz.com/ply/ply.html#ply_nn25 for more details.
+
+  # TODO(vtl): Get rid of the braces in the module "statement". (Consider
+  # renaming "module" -> "package".) Then we'll be able to have a single rule
+  # for root (by making module "optional").
+  def p_root_1(self, p):
+    """root : import_list module LBRACE definition_list RBRACE"""
+    p[0] = ast.Mojom(p[2], p[1], p[4])
+
+  def p_root_2(self, p):
+    """root : import_list definition_list"""
+    p[0] = ast.Mojom(None, p[1], p[2])
+
+  def p_import_list_1(self, p):
+    """import_list : """
+    p[0] = ast.ImportList()
+
+  def p_import_list_2(self, p):
+    """import_list : import_list import"""
+    p[0] = p[1]
+    p[0].Append(p[2])
+
+  def p_import(self, p):
+    """import : IMPORT STRING_LITERAL"""
+    # 'eval' the literal to strip the quotes.
+    # TODO(vtl): This eval is dubious. We should unquote/unescape ourselves.
+    p[0] = ast.Import(eval(p[2]))
+
+  def p_module(self, p):
+    """module : attribute_section MODULE identifier_wrapped """
+    p[0] = ast.Module(p[3], p[1], filename=self.filename, lineno=p.lineno(2))
+
+  def p_definition_list(self, p):
+    """definition_list : definition definition_list
+                       | """
+    if len(p) > 1:
+      p[0] = p[2]
+      p[0].insert(0, p[1])
+    else:
+      p[0] = []
+
+  def p_definition(self, p):
+    """definition : struct
+                  | interface
+                  | enum
+                  | const"""
+    p[0] = p[1]
+
+  def p_attribute_section_1(self, p):
+    """attribute_section : """
+    p[0] = None
+
+  def p_attribute_section_2(self, p):
+    """attribute_section : LBRACKET attribute_list RBRACKET"""
+    p[0] = p[2]
+
+  def p_attribute_list_1(self, p):
+    """attribute_list : """
+    p[0] = ast.AttributeList()
+
+  def p_attribute_list_2(self, p):
+    """attribute_list : nonempty_attribute_list"""
+    p[0] = p[1]
+
+  def p_nonempty_attribute_list_1(self, p):
+    """nonempty_attribute_list : attribute"""
+    p[0] = ast.AttributeList(p[1])
+
+  def p_nonempty_attribute_list_2(self, p):
+    """nonempty_attribute_list : nonempty_attribute_list COMMA attribute"""
+    p[0] = p[1]
+    p[0].Append(p[3])
+
+  def p_attribute(self, p):
+    """attribute : NAME EQUALS evaled_literal
+                 | NAME EQUALS NAME"""
+    p[0] = ast.Attribute(p[1], p[3], filename=self.filename, lineno=p.lineno(1))
+
+  def p_evaled_literal(self, p):
+    """evaled_literal : literal"""
+    # 'eval' the literal to strip the quotes.
+    p[0] = eval(p[1])
+
+  def p_struct(self, p):
+    """struct : attribute_section STRUCT NAME LBRACE struct_body RBRACE SEMI"""
+    p[0] = ast.Struct(p[3], p[1], p[5])
+
+  def p_struct_body_1(self, p):
+    """struct_body : """
+    p[0] = ast.StructBody()
+
+  def p_struct_body_2(self, p):
+    """struct_body : struct_body const
+                   | struct_body enum
+                   | struct_body struct_field"""
+    p[0] = p[1]
+    p[0].Append(p[2])
+
+  def p_struct_field(self, p):
+    """struct_field : typename NAME ordinal default SEMI"""
+    p[0] = ast.StructField(p[2], p[3], p[1], p[4])
+
+  def p_default_1(self, p):
+    """default : """
+    p[0] = None
+
+  def p_default_2(self, p):
+    """default : EQUALS constant"""
+    p[0] = p[2]
+
+  def p_interface(self, p):
+    """interface : attribute_section INTERFACE NAME LBRACE interface_body \
+                       RBRACE SEMI"""
+    p[0] = ast.Interface(p[3], p[1], p[5])
+
+  def p_interface_body_1(self, p):
+    """interface_body : """
+    p[0] = ast.InterfaceBody()
+
+  def p_interface_body_2(self, p):
+    """interface_body : interface_body const
+                      | interface_body enum
+                      | interface_body method"""
+    p[0] = p[1]
+    p[0].Append(p[2])
+
+  def p_response_1(self, p):
+    """response : """
+    p[0] = None
+
+  def p_response_2(self, p):
+    """response : RESPONSE LPAREN parameter_list RPAREN"""
+    p[0] = p[3]
+
+  def p_method(self, p):
+    """method : NAME ordinal LPAREN parameter_list RPAREN response SEMI"""
+    p[0] = ast.Method(p[1], p[2], p[4], p[6])
+
+  def p_parameter_list_1(self, p):
+    """parameter_list : """
+    p[0] = ast.ParameterList()
+
+  def p_parameter_list_2(self, p):
+    """parameter_list : nonempty_parameter_list"""
+    p[0] = p[1]
+
+  def p_nonempty_parameter_list_1(self, p):
+    """nonempty_parameter_list : parameter"""
+    p[0] = ast.ParameterList(p[1])
+
+  def p_nonempty_parameter_list_2(self, p):
+    """nonempty_parameter_list : nonempty_parameter_list COMMA parameter"""
+    p[0] = p[1]
+    p[0].Append(p[3])
+
+  def p_parameter(self, p):
+    """parameter : typename NAME ordinal"""
+    p[0] = ast.Parameter(p[2], p[3], p[1],
+                         filename=self.filename, lineno=p.lineno(2))
+
+  def p_typename(self, p):
+    """typename : nonnullable_typename QSTN
+                | nonnullable_typename"""
+    if len(p) == 2:
+      p[0] = p[1]
+    else:
+      p[0] = p[1] + "?"
+
+  def p_nonnullable_typename(self, p):
+    """nonnullable_typename : basictypename
+                            | array
+                            | fixed_array
+                            | interfacerequest"""
+    p[0] = p[1]
+
+  def p_basictypename(self, p):
+    """basictypename : identifier
+                     | handletype"""
+    p[0] = p[1]
+
+  def p_handletype(self, p):
+    """handletype : HANDLE
+                  | HANDLE LANGLE NAME RANGLE"""
+    if len(p) == 2:
+      p[0] = p[1]
+    else:
+      if p[3] not in ('data_pipe_consumer',
+                      'data_pipe_producer',
+                      'message_pipe',
+                      'shared_buffer'):
+        # Note: We don't enable tracking of line numbers for everything, so we
+        # can't use |p.lineno(3)|.
+        raise ParseError(self.filename, "Invalid handle type %r:" % p[3],
+                         lineno=p.lineno(1),
+                         snippet=self._GetSnippet(p.lineno(1)))
+      p[0] = "handle<" + p[3] + ">"
+
+  def p_array(self, p):
+    """array : ARRAY LANGLE typename RANGLE"""
+    p[0] = p[3] + "[]"
+
+  def p_fixed_array(self, p):
+    """fixed_array : ARRAY LANGLE typename COMMA INT_CONST_DEC RANGLE"""
+    value = int(p[5])
+    if value == 0 or value > _MAX_ARRAY_SIZE:
+      raise ParseError(self.filename, "Fixed array size %d invalid" % value,
+                       lineno=p.lineno(5),
+                       snippet=self._GetSnippet(p.lineno(5)))
+    p[0] = p[3] + "[" + p[5] + "]"
+
+  def p_interfacerequest(self, p):
+    """interfacerequest : identifier AMP"""
+    p[0] = p[1] + "&"
+
+  def p_ordinal_1(self, p):
+    """ordinal : """
+    p[0] = None
+
+  def p_ordinal_2(self, p):
+    """ordinal : ORDINAL"""
+    value = int(p[1][1:])
+    if value > _MAX_ORDINAL_VALUE:
+      raise ParseError(self.filename, "Ordinal value %d too large:" % value,
+                       lineno=p.lineno(1),
+                       snippet=self._GetSnippet(p.lineno(1)))
+    p[0] = ast.Ordinal(value, filename=self.filename, lineno=p.lineno(1))
+
+  def p_enum(self, p):
+    """enum : ENUM NAME LBRACE nonempty_enum_value_list RBRACE SEMI
+            | ENUM NAME LBRACE nonempty_enum_value_list COMMA RBRACE SEMI"""
+    p[0] = ast.Enum(p[2], p[4], filename=self.filename, lineno=p.lineno(1))
+
+  def p_nonempty_enum_value_list_1(self, p):
+    """nonempty_enum_value_list : enum_value"""
+    p[0] = ast.EnumValueList(p[1])
+
+  def p_nonempty_enum_value_list_2(self, p):
+    """nonempty_enum_value_list : nonempty_enum_value_list COMMA enum_value"""
+    p[0] = p[1]
+    p[0].Append(p[3])
+
+  def p_enum_value(self, p):
+    """enum_value : NAME
+                  | NAME EQUALS int
+                  | NAME EQUALS identifier_wrapped"""
+    p[0] = ast.EnumValue(p[1], p[3] if len(p) == 4 else None,
+                         filename=self.filename, lineno=p.lineno(1))
+
+  def p_const(self, p):
+    """const : CONST typename NAME EQUALS constant SEMI"""
+    p[0] = ast.Const(p[3], p[2], p[5])
+
+  def p_constant(self, p):
+    """constant : literal
+                | identifier_wrapped"""
+    p[0] = p[1]
+
+  def p_identifier_wrapped(self, p):
+    """identifier_wrapped : identifier"""
+    p[0] = ('IDENTIFIER', p[1])
+
+  # TODO(vtl): Make this produce a "wrapped" identifier (probably as an
+  # |ast.Identifier|, to be added) and get rid of identifier_wrapped.
+  def p_identifier(self, p):
+    """identifier : NAME
+                  | NAME DOT identifier"""
+    p[0] = ''.join(p[1:])
+
+  def p_literal(self, p):
+    """literal : int
+               | float
+               | TRUE
+               | FALSE
+               | DEFAULT
+               | STRING_LITERAL"""
+    p[0] = p[1]
+
+  def p_int(self, p):
+    """int : int_const
+           | PLUS int_const
+           | MINUS int_const"""
+    p[0] = ''.join(p[1:])
+
+  def p_int_const(self, p):
+    """int_const : INT_CONST_DEC
+                 | INT_CONST_HEX"""
+    p[0] = p[1]
+
+  def p_float(self, p):
+    """float : FLOAT_CONST
+             | PLUS FLOAT_CONST
+             | MINUS FLOAT_CONST"""
+    p[0] = ''.join(p[1:])
+
+  def p_error(self, e):
+    if e is None:
+      # Unexpected EOF.
+      # TODO(vtl): Can we figure out what's missing?
+      raise ParseError(self.filename, "Unexpected end of file")
+
+    raise ParseError(self.filename, "Unexpected %r:" % e.value, lineno=e.lineno,
+                     snippet=self._GetSnippet(e.lineno))
+
+  def _GetSnippet(self, lineno):
+    return self.source.split('\n')[lineno - 1]
+
+
+def Parse(source, filename):
+  lexer = Lexer(filename)
+  parser = Parser(lexer, source, filename)
+
+  lex.lex(object=lexer)
+  yacc.yacc(module=parser, debug=0, write_tables=0)
+
+  tree = yacc.parse(source)
+  return tree
diff --git a/mojo/public/tools/bindings/pylib/mojom/parse/translate.py b/mojo/public/tools/bindings/pylib/mojom/parse/translate.py
new file mode 100644
index 0000000..77e92c5
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/parse/translate.py
@@ -0,0 +1,160 @@
+# Copyright 2014 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.
+
+"""Translates parse tree to Mojom IR."""
+
+
+import re
+
+from . import ast
+
+
+def _MapTreeForType(func, tree, type_to_map):
+  assert isinstance(type_to_map, type)
+  if not tree:
+    return []
+  return [func(subtree) for subtree in tree if isinstance(subtree, type_to_map)]
+
+_FIXED_ARRAY_REGEXP = re.compile(r'\[[0-9]+\]')
+
+def _MapKind(kind):
+  map_to_kind = {'bool': 'b',
+                 'int8': 'i8',
+                 'int16': 'i16',
+                 'int32': 'i32',
+                 'int64': 'i64',
+                 'uint8': 'u8',
+                 'uint16': 'u16',
+                 'uint32': 'u32',
+                 'uint64': 'u64',
+                 'float': 'f',
+                 'double': 'd',
+                 'string': 's',
+                 'handle': 'h',
+                 'handle<data_pipe_consumer>': 'h:d:c',
+                 'handle<data_pipe_producer>': 'h:d:p',
+                 'handle<message_pipe>': 'h:m',
+                 'handle<shared_buffer>': 'h:s'}
+  if kind.endswith('?'):
+    base_kind = _MapKind(kind[0:-1])
+    # NOTE: This doesn't rule out enum types. Those will be detected later, when
+    # cross-reference is established.
+    reference_kinds = ('s', 'h', 'a', 'r', 'x')
+    if base_kind[0] not in reference_kinds:
+      raise Exception(
+          'A type (spec "%s") cannot be made nullable' % base_kind)
+    return '?' + base_kind
+  if kind.endswith('[]'):
+    typename = kind[0:-2]
+    if _FIXED_ARRAY_REGEXP.search(typename):
+      raise Exception('Arrays of fixed sized arrays not supported')
+    return 'a:' + _MapKind(typename)
+  if kind.endswith(']'):
+    lbracket = kind.rfind('[')
+    typename = kind[0:lbracket]
+    if typename.find('[') != -1:
+      raise Exception('Fixed sized arrays of arrays not supported')
+    return 'a' + kind[lbracket+1:-1] + ':' + _MapKind(typename)
+  if kind.endswith('&'):
+    return 'r:' + _MapKind(kind[0:-1])
+  if kind in map_to_kind:
+    return map_to_kind[kind]
+  return 'x:' + kind
+
+def _AttributeListToDict(attribute_list):
+  if attribute_list is None:
+    return {}
+  assert isinstance(attribute_list, ast.AttributeList)
+  # TODO(vtl): Check for duplicate keys here.
+  return dict([(attribute.key, attribute.value)
+                   for attribute in attribute_list])
+
+def _EnumToDict(enum):
+  def EnumValueToDict(enum_value):
+    assert isinstance(enum_value, ast.EnumValue)
+    return {'name': enum_value.name,
+            'value': enum_value.value}
+
+  assert isinstance(enum, ast.Enum)
+  return {'name': enum.name,
+          'fields': map(EnumValueToDict, enum.enum_value_list)}
+
+def _ConstToDict(const):
+  assert isinstance(const, ast.Const)
+  return {'name': const.name,
+          'kind': _MapKind(const.typename),
+          'value': const.value}
+
+
+class _MojomBuilder(object):
+  def __init__(self):
+    self.mojom = {}
+
+  def Build(self, tree, name):
+    def StructToDict(struct):
+      def StructFieldToDict(struct_field):
+        assert isinstance(struct_field, ast.StructField)
+        return {'name': struct_field.name,
+                'kind': _MapKind(struct_field.typename),
+                'ordinal': struct_field.ordinal.value \
+                    if struct_field.ordinal else None,
+                'default': struct_field.default_value}
+
+      assert isinstance(struct, ast.Struct)
+      return {'name': struct.name,
+              'attributes': _AttributeListToDict(struct.attribute_list),
+              'fields': _MapTreeForType(StructFieldToDict, struct.body,
+                                        ast.StructField),
+              'enums': _MapTreeForType(_EnumToDict, struct.body, ast.Enum),
+              'constants': _MapTreeForType(_ConstToDict, struct.body,
+                                           ast.Const)}
+
+    def InterfaceToDict(interface):
+      def MethodToDict(method):
+        def ParameterToDict(param):
+          assert isinstance(param, ast.Parameter)
+          return {'name': param.name,
+                  'kind': _MapKind(param.typename),
+                  'ordinal': param.ordinal.value if param.ordinal else None}
+
+        assert isinstance(method, ast.Method)
+        rv = {'name': method.name,
+              'parameters': map(ParameterToDict, method.parameter_list),
+              'ordinal': method.ordinal.value if method.ordinal else None}
+        if method.response_parameter_list is not None:
+          rv['response_parameters'] = map(ParameterToDict,
+                                          method.response_parameter_list)
+        return rv
+
+      assert isinstance(interface, ast.Interface)
+      attributes = _AttributeListToDict(interface.attribute_list)
+      return {'name': interface.name,
+              'attributes': attributes,
+              'client': attributes.get('Client'),
+              'methods': _MapTreeForType(MethodToDict, interface.body,
+                                         ast.Method),
+              'enums': _MapTreeForType(_EnumToDict, interface.body, ast.Enum),
+              'constants': _MapTreeForType(_ConstToDict, interface.body,
+                                           ast.Const)}
+
+    assert isinstance(tree, ast.Mojom)
+    self.mojom['name'] = name
+    self.mojom['namespace'] = tree.module.name[1] if tree.module else ''
+    self.mojom['imports'] = \
+        [{'filename': imp.import_filename} for imp in tree.import_list]
+    self.mojom['attributes'] = \
+        _AttributeListToDict(tree.module.attribute_list) if tree.module else {}
+    self.mojom['structs'] = \
+        _MapTreeForType(StructToDict, tree.definition_list, ast.Struct)
+    self.mojom['interfaces'] = \
+        _MapTreeForType(InterfaceToDict, tree.definition_list, ast.Interface)
+    self.mojom['enums'] = \
+        _MapTreeForType(_EnumToDict, tree.definition_list, ast.Enum)
+    self.mojom['constants'] = \
+        _MapTreeForType(_ConstToDict, tree.definition_list, ast.Const)
+    return self.mojom
+
+
+def Translate(tree, name):
+  return _MojomBuilder().Build(tree, name)
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/__init__.py b/mojo/public/tools/bindings/pylib/mojom_tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom_tests/__init__.py
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/parse/__init__.py b/mojo/public/tools/bindings/pylib/mojom_tests/parse/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom_tests/parse/__init__.py
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/parse/ast_unittest.py b/mojo/public/tools/bindings/pylib/mojom_tests/parse/ast_unittest.py
new file mode 100644
index 0000000..dd28cdd
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom_tests/parse/ast_unittest.py
@@ -0,0 +1,135 @@
+# Copyright 2014 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.
+
+import imp
+import os.path
+import sys
+import unittest
+
+def _GetDirAbove(dirname):
+  """Returns the directory "above" this file containing |dirname| (which must
+  also be "above" this file)."""
+  path = os.path.abspath(__file__)
+  while True:
+    path, tail = os.path.split(path)
+    assert tail
+    if tail == dirname:
+      return path
+
+try:
+  imp.find_module("mojom")
+except ImportError:
+  sys.path.append(os.path.join(_GetDirAbove("pylib"), "pylib"))
+import mojom.parse.ast as ast
+
+
+class _TestNode(ast.NodeBase):
+  """Node type for tests."""
+
+  def __init__(self, value, **kwargs):
+    super(_TestNode, self).__init__(**kwargs)
+    self.value = value
+
+  def __eq__(self, other):
+    return super(_TestNode, self).__eq__(other) and self.value == other.value
+
+
+class _TestNodeList(ast.NodeListBase):
+  """Node list type for tests."""
+
+  _list_item_type = _TestNode
+
+
+class ASTTest(unittest.TestCase):
+  """Tests various AST classes."""
+
+  def testNodeBase(self):
+    # Test |__eq__()|; this is only used for testing, where we want to do
+    # comparison by value and ignore filenames/line numbers (for convenience).
+    node1 = ast.NodeBase(filename="hello.mojom", lineno=123)
+    node2 = ast.NodeBase()
+    self.assertEquals(node1, node2)
+    self.assertEquals(node2, node1)
+
+    # Check that |__ne__()| just defers to |__eq__()| properly.
+    self.assertFalse(node1 != node2)
+    self.assertFalse(node2 != node1)
+
+    # Check that |filename| and |lineno| are set properly (and are None by
+    # default).
+    self.assertEquals(node1.filename, "hello.mojom")
+    self.assertEquals(node1.lineno, 123)
+    self.assertIsNone(node2.filename)
+    self.assertIsNone(node2.lineno)
+
+    # |NodeBase|'s |__eq__()| should compare types (and a subclass's |__eq__()|
+    # should first defer to its superclass's).
+    node3 = _TestNode(123)
+    self.assertNotEqual(node1, node3)
+    self.assertNotEqual(node3, node1)
+    # Also test |__eq__()| directly.
+    self.assertFalse(node1 == node3)
+    self.assertFalse(node3 == node1)
+
+    node4 = _TestNode(123, filename="world.mojom", lineno=123)
+    self.assertEquals(node4, node3)
+    node5 = _TestNode(456)
+    self.assertNotEquals(node5, node4)
+
+  def testNodeListBase(self):
+    node1 = _TestNode(1, filename="foo.mojom", lineno=1)
+    # Equal to, but not the same as, |node1|:
+    node1b = _TestNode(1, filename="foo.mojom", lineno=1)
+    node2 = _TestNode(2, filename="foo.mojom", lineno=2)
+
+    nodelist1 = _TestNodeList()  # Contains: (empty).
+    self.assertEquals(nodelist1, nodelist1)
+    self.assertEquals(nodelist1.items, [])
+    self.assertIsNone(nodelist1.filename)
+    self.assertIsNone(nodelist1.lineno)
+
+    nodelist2 = _TestNodeList(node1)  # Contains: 1.
+    self.assertEquals(nodelist2, nodelist2)
+    self.assertEquals(nodelist2.items, [node1])
+    self.assertNotEqual(nodelist2, nodelist1)
+    self.assertEquals(nodelist2.filename, "foo.mojom")
+    self.assertEquals(nodelist2.lineno, 1)
+
+    nodelist3 = _TestNodeList([node2])  # Contains: 2.
+    self.assertEquals(nodelist3.items, [node2])
+    self.assertNotEqual(nodelist3, nodelist1)
+    self.assertNotEqual(nodelist3, nodelist2)
+    self.assertEquals(nodelist3.filename, "foo.mojom")
+    self.assertEquals(nodelist3.lineno, 2)
+
+    nodelist1.Append(node1b)  # Contains: 1.
+    self.assertEquals(nodelist1.items, [node1])
+    self.assertEquals(nodelist1, nodelist2)
+    self.assertNotEqual(nodelist1, nodelist3)
+    self.assertEquals(nodelist1.filename, "foo.mojom")
+    self.assertEquals(nodelist1.lineno, 1)
+
+    nodelist1.Append(node2)  # Contains: 1, 2.
+    self.assertEquals(nodelist1.items, [node1, node2])
+    self.assertNotEqual(nodelist1, nodelist2)
+    self.assertNotEqual(nodelist1, nodelist3)
+    self.assertEquals(nodelist1.lineno, 1)
+
+    nodelist2.Append(node2)  # Contains: 1, 2.
+    self.assertEquals(nodelist2.items, [node1, node2])
+    self.assertEquals(nodelist2, nodelist1)
+    self.assertNotEqual(nodelist2, nodelist3)
+    self.assertEquals(nodelist2.lineno, 1)
+
+    nodelist3.Insert(node1)  # Contains: 1, 2.
+    self.assertEquals(nodelist3.items, [node1, node2])
+    self.assertEquals(nodelist3, nodelist1)
+    self.assertEquals(nodelist3, nodelist2)
+    self.assertEquals(nodelist3.lineno, 1)
+
+    # Test iteration:
+    i = 1
+    for item in nodelist1:
+      self.assertEquals(item.value, i)
+      i += 1
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/parse/lexer_unittest.py b/mojo/public/tools/bindings/pylib/mojom_tests/parse/lexer_unittest.py
new file mode 100644
index 0000000..d24b7e2
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom_tests/parse/lexer_unittest.py
@@ -0,0 +1,186 @@
+# Copyright 2014 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.
+
+import imp
+import os.path
+import sys
+import unittest
+
+def _GetDirAbove(dirname):
+  """Returns the directory "above" this file containing |dirname| (which must
+  also be "above" this file)."""
+  path = os.path.abspath(__file__)
+  while True:
+    path, tail = os.path.split(path)
+    assert tail
+    if tail == dirname:
+      return path
+
+try:
+  imp.find_module("ply")
+except ImportError:
+  sys.path.append(os.path.join(_GetDirAbove("mojo"), "third_party"))
+from ply import lex
+
+try:
+  imp.find_module("mojom")
+except ImportError:
+  sys.path.append(os.path.join(_GetDirAbove("pylib"), "pylib"))
+import mojom.parse.lexer
+
+
+# This (monkey-patching LexToken to make comparison value-based) is evil, but
+# we'll do it anyway. (I'm pretty sure ply's lexer never cares about comparing
+# for object identity.)
+def _LexTokenEq(self, other):
+  return self.type == other.type and self.value == other.value and \
+         self.lineno == other.lineno and self.lexpos == other.lexpos
+setattr(lex.LexToken, '__eq__', _LexTokenEq)
+
+
+def _MakeLexToken(token_type, value, lineno=1, lexpos=0):
+  """Makes a LexToken with the given parameters. (Note that lineno is 1-based,
+  but lexpos is 0-based.)"""
+  rv = lex.LexToken()
+  rv.type, rv.value, rv.lineno, rv.lexpos = token_type, value, lineno, lexpos
+  return rv
+
+
+def _MakeLexTokenForKeyword(keyword, **kwargs):
+  """Makes a LexToken for the given keyword."""
+  return _MakeLexToken(keyword.upper(), keyword.lower(), **kwargs)
+
+
+class LexerTest(unittest.TestCase):
+  """Tests |mojom.parse.lexer.Lexer|."""
+
+  def __init__(self, *args, **kwargs):
+    unittest.TestCase.__init__(self, *args, **kwargs)
+    # Clone all lexer instances from this one, since making a lexer is slow.
+    self._zygote_lexer = lex.lex(mojom.parse.lexer.Lexer("my_file.mojom"))
+
+  def testValidKeywords(self):
+    """Tests valid keywords."""
+    self.assertEquals(self._SingleTokenForInput("handle"),
+                      _MakeLexTokenForKeyword("handle"))
+    self.assertEquals(self._SingleTokenForInput("import"),
+                      _MakeLexTokenForKeyword("import"))
+    self.assertEquals(self._SingleTokenForInput("module"),
+                      _MakeLexTokenForKeyword("module"))
+    self.assertEquals(self._SingleTokenForInput("struct"),
+                      _MakeLexTokenForKeyword("struct"))
+    self.assertEquals(self._SingleTokenForInput("interface"),
+                      _MakeLexTokenForKeyword("interface"))
+    self.assertEquals(self._SingleTokenForInput("enum"),
+                      _MakeLexTokenForKeyword("enum"))
+    self.assertEquals(self._SingleTokenForInput("const"),
+                      _MakeLexTokenForKeyword("const"))
+    self.assertEquals(self._SingleTokenForInput("true"),
+                      _MakeLexTokenForKeyword("true"))
+    self.assertEquals(self._SingleTokenForInput("false"),
+                      _MakeLexTokenForKeyword("false"))
+    self.assertEquals(self._SingleTokenForInput("default"),
+                      _MakeLexTokenForKeyword("default"))
+    self.assertEquals(self._SingleTokenForInput("array"),
+                      _MakeLexTokenForKeyword("array"))
+
+  def testValidIdentifiers(self):
+    """Tests identifiers."""
+    self.assertEquals(self._SingleTokenForInput("abcd"),
+                      _MakeLexToken("NAME", "abcd"))
+    self.assertEquals(self._SingleTokenForInput("AbC_d012_"),
+                      _MakeLexToken("NAME", "AbC_d012_"))
+    self.assertEquals(self._SingleTokenForInput("_0123"),
+                      _MakeLexToken("NAME", "_0123"))
+
+  def testInvalidIdentifiers(self):
+    with self.assertRaisesRegexp(
+        mojom.parse.lexer.LexError,
+        r"^my_file\.mojom:1: Error: Illegal character '\$'$"):
+      self._TokensForInput("$abc")
+    with self.assertRaisesRegexp(
+        mojom.parse.lexer.LexError,
+        r"^my_file\.mojom:1: Error: Illegal character '\$'$"):
+      self._TokensForInput("a$bc")
+
+  def testDecimalIntegerConstants(self):
+    self.assertEquals(self._SingleTokenForInput("0"),
+                      _MakeLexToken("INT_CONST_DEC", "0"))
+    self.assertEquals(self._SingleTokenForInput("1"),
+                      _MakeLexToken("INT_CONST_DEC", "1"))
+    self.assertEquals(self._SingleTokenForInput("123"),
+                      _MakeLexToken("INT_CONST_DEC", "123"))
+    self.assertEquals(self._SingleTokenForInput("10"),
+                      _MakeLexToken("INT_CONST_DEC", "10"))
+
+  def testValidTokens(self):
+    """Tests valid tokens (which aren't tested elsewhere)."""
+    # Keywords tested in |testValidKeywords|.
+    # NAME tested in |testValidIdentifiers|.
+    self.assertEquals(self._SingleTokenForInput("@123"),
+                      _MakeLexToken("ORDINAL", "@123"))
+    self.assertEquals(self._SingleTokenForInput("456"),
+                      _MakeLexToken("INT_CONST_DEC", "456"))
+    self.assertEquals(self._SingleTokenForInput("0x01aB2eF3"),
+                      _MakeLexToken("INT_CONST_HEX", "0x01aB2eF3"))
+    self.assertEquals(self._SingleTokenForInput("123.456"),
+                      _MakeLexToken("FLOAT_CONST", "123.456"))
+    self.assertEquals(self._SingleTokenForInput("\"hello\""),
+                      _MakeLexToken("STRING_LITERAL", "\"hello\""))
+    self.assertEquals(self._SingleTokenForInput("+"),
+                      _MakeLexToken("PLUS", "+"))
+    self.assertEquals(self._SingleTokenForInput("-"),
+                      _MakeLexToken("MINUS", "-"))
+    self.assertEquals(self._SingleTokenForInput("&"),
+                      _MakeLexToken("AMP", "&"))
+    self.assertEquals(self._SingleTokenForInput("?"),
+                      _MakeLexToken("QSTN", "?"))
+    self.assertEquals(self._SingleTokenForInput("="),
+                      _MakeLexToken("EQUALS", "="))
+    self.assertEquals(self._SingleTokenForInput("=>"),
+                      _MakeLexToken("RESPONSE", "=>"))
+    self.assertEquals(self._SingleTokenForInput("("),
+                      _MakeLexToken("LPAREN", "("))
+    self.assertEquals(self._SingleTokenForInput(")"),
+                      _MakeLexToken("RPAREN", ")"))
+    self.assertEquals(self._SingleTokenForInput("["),
+                      _MakeLexToken("LBRACKET", "["))
+    self.assertEquals(self._SingleTokenForInput("]"),
+                      _MakeLexToken("RBRACKET", "]"))
+    self.assertEquals(self._SingleTokenForInput("{"),
+                      _MakeLexToken("LBRACE", "{"))
+    self.assertEquals(self._SingleTokenForInput("}"),
+                      _MakeLexToken("RBRACE", "}"))
+    self.assertEquals(self._SingleTokenForInput("<"),
+                      _MakeLexToken("LANGLE", "<"))
+    self.assertEquals(self._SingleTokenForInput(">"),
+                      _MakeLexToken("RANGLE", ">"))
+    self.assertEquals(self._SingleTokenForInput(";"),
+                      _MakeLexToken("SEMI", ";"))
+    self.assertEquals(self._SingleTokenForInput(","),
+                      _MakeLexToken("COMMA", ","))
+    self.assertEquals(self._SingleTokenForInput("."),
+                      _MakeLexToken("DOT", "."))
+
+  def _TokensForInput(self, input_string):
+    """Gets a list of tokens for the given input string."""
+    lexer = self._zygote_lexer.clone()
+    lexer.input(input_string)
+    rv = []
+    while True:
+      tok = lexer.token()
+      if not tok:
+        return rv
+      rv.append(tok)
+
+  def _SingleTokenForInput(self, input_string):
+    """Gets the single token for the given input string. (Raises an exception if
+    the input string does not result in exactly one token.)"""
+    toks = self._TokensForInput(input_string)
+    assert len(toks) == 1
+    return toks[0]
+
+
+if __name__ == "__main__":
+  unittest.main()
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py b/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py
new file mode 100644
index 0000000..8671b1a
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py
@@ -0,0 +1,1058 @@
+# Copyright 2014 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.
+
+import imp
+import os.path
+import sys
+import unittest
+
+def _GetDirAbove(dirname):
+  """Returns the directory "above" this file containing |dirname| (which must
+  also be "above" this file)."""
+  path = os.path.abspath(__file__)
+  while True:
+    path, tail = os.path.split(path)
+    assert tail
+    if tail == dirname:
+      return path
+
+try:
+  imp.find_module("mojom")
+except ImportError:
+  sys.path.append(os.path.join(_GetDirAbove("pylib"), "pylib"))
+import mojom.parse.ast as ast
+import mojom.parse.lexer as lexer
+import mojom.parse.parser as parser
+
+
+class ParserTest(unittest.TestCase):
+  """Tests |parser.Parse()|."""
+
+  def testTrivialValidSource(self):
+    """Tests a trivial, but valid, .mojom source."""
+
+    source = """\
+        // This is a comment.
+
+        module my_module {
+        }
+        """
+    expected = ast.Mojom(
+        ast.Module(('IDENTIFIER', 'my_module'), None),
+        ast.ImportList(),
+        [])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testSourceWithCrLfs(self):
+    """Tests a .mojom source with CR-LFs instead of LFs."""
+
+    source = "// This is a comment.\r\n\r\nmodule my_module {\r\n}\r\n"
+    expected = ast.Mojom(
+        ast.Module(('IDENTIFIER', 'my_module'), None),
+        ast.ImportList(),
+        [])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testUnexpectedEOF(self):
+    """Tests a "truncated" .mojom source."""
+
+    source = """\
+        // This is a comment.
+
+        module my_module {
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom: Error: Unexpected end of file$"):
+      parser.Parse(source, "my_file.mojom")
+
+  def testCommentLineNumbers(self):
+    """Tests that line numbers are correctly tracked when comments are
+    present."""
+
+    source1 = """\
+        // Isolated C++-style comments.
+
+        // Foo.
+        asdf1
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:4: Error: Unexpected 'asdf1':\n *asdf1$"):
+      parser.Parse(source1, "my_file.mojom")
+
+    source2 = """\
+        // Consecutive C++-style comments.
+        // Foo.
+          // Bar.
+
+        struct Yada {  // Baz.
+        // Quux.
+          int32 x;
+        };
+
+        asdf2
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:10: Error: Unexpected 'asdf2':\n *asdf2$"):
+      parser.Parse(source2, "my_file.mojom")
+
+    source3 = """\
+        /* Single-line C-style comments. */
+        /* Foobar. */
+
+        /* Baz. */
+        asdf3
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:5: Error: Unexpected 'asdf3':\n *asdf3$"):
+      parser.Parse(source3, "my_file.mojom")
+
+    source4 = """\
+        /* Multi-line C-style comments.
+        */
+        /*
+        Foo.
+        Bar.
+        */
+
+        /* Baz
+           Quux. */
+        asdf4
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:10: Error: Unexpected 'asdf4':\n *asdf4$"):
+      parser.Parse(source4, "my_file.mojom")
+
+
+  def testSimpleStruct(self):
+    """Tests a simple .mojom source that just defines a struct."""
+
+    source = """\
+        module my_module {
+
+        struct MyStruct {
+          int32 a;
+          double b;
+        };
+
+        }  // module my_module
+        """
+    expected = ast.Mojom(
+        ast.Module(('IDENTIFIER', 'my_module'), None),
+        ast.ImportList(),
+        [ast.Struct(
+            'MyStruct',
+            None,
+            ast.StructBody(
+                [ast.StructField('a', None, 'int32', None),
+                 ast.StructField('b', None, 'double', None)]))])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testSimpleStructWithoutModule(self):
+    """Tests a simple struct without an enclosing module."""
+
+    source = """\
+        struct MyStruct {
+          int32 a;
+          double b;
+        };
+        """
+    expected = ast.Mojom(
+        None,
+        ast.ImportList(),
+        [ast.Struct(
+            'MyStruct',
+            None,
+            ast.StructBody(
+                [ast.StructField('a', None, 'int32', None),
+                 ast.StructField('b', None, 'double', None)]))])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testValidStructDefinitions(self):
+    """Tests all types of definitions that can occur in a struct."""
+
+    source = """\
+        struct MyStruct {
+          enum MyEnum { VALUE };
+          const double kMyConst = 1.23;
+          int32 a;
+          SomeOtherStruct b;  // Invalidity detected at another stage.
+        };
+        """
+    expected = ast.Mojom(
+        None,
+        ast.ImportList(),
+        [ast.Struct(
+            'MyStruct',
+            None,
+            ast.StructBody(
+                [ast.Enum('MyEnum',
+                          ast.EnumValueList(ast.EnumValue('VALUE', None))),
+                 ast.Const('kMyConst', 'double', '1.23'),
+                 ast.StructField('a', None, 'int32', None),
+                 ast.StructField('b', None, 'SomeOtherStruct', None)]))])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testInvalidStructDefinitions(self):
+    """Tests that definitions that aren't allowed in a struct are correctly
+    detected."""
+
+    source1 = """\
+        struct MyStruct {
+          MyMethod(int32 a);
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected '\(':\n"
+            r" *MyMethod\(int32 a\);$"):
+      parser.Parse(source1, "my_file.mojom")
+
+    source2 = """\
+        struct MyStruct {
+          struct MyInnerStruct {
+            int32 a;
+          };
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected 'struct':\n"
+            r" *struct MyInnerStruct {$"):
+      parser.Parse(source2, "my_file.mojom")
+
+    source3 = """\
+        struct MyStruct {
+          interface MyInterface {
+            MyMethod(int32 a);
+          };
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected 'interface':\n"
+            r" *interface MyInterface {$"):
+      parser.Parse(source3, "my_file.mojom")
+
+  def testMissingModuleName(self):
+    """Tests an (invalid) .mojom with a missing module name."""
+
+    source1 = """\
+        // Missing module name.
+        module {
+        struct MyStruct {
+          int32 a;
+        };
+        }
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected '{':\n *module {$"):
+      parser.Parse(source1, "my_file.mojom")
+
+    # Another similar case, but make sure that line-number tracking/reporting
+    # is correct.
+    source2 = """\
+        module
+        // This line intentionally left unblank.
+
+        {
+        }
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:4: Error: Unexpected '{':\n *{$"):
+      parser.Parse(source2, "my_file.mojom")
+
+  def testEnums(self):
+    """Tests that enum statements are correctly parsed."""
+
+    source = """\
+        module my_module {
+        enum MyEnum1 { VALUE1, VALUE2 };  // No trailing comma.
+        enum MyEnum2 {
+          VALUE1 = -1,
+          VALUE2 = 0,
+          VALUE3 = + 987,  // Check that space is allowed.
+          VALUE4 = 0xAF12,
+          VALUE5 = -0x09bcd,
+          VALUE6 = VALUE5,
+          VALUE7,  // Leave trailing comma.
+        };
+        }  // my_module
+        """
+    expected = ast.Mojom(
+        ast.Module(('IDENTIFIER', 'my_module'), None),
+        ast.ImportList(),
+        [ast.Enum(
+            'MyEnum1',
+            ast.EnumValueList([ast.EnumValue('VALUE1', None),
+                               ast.EnumValue('VALUE2', None)])),
+         ast.Enum(
+            'MyEnum2',
+            ast.EnumValueList([ast.EnumValue('VALUE1', '-1'),
+                               ast.EnumValue('VALUE2', '0'),
+                               ast.EnumValue('VALUE3', '+987'),
+                               ast.EnumValue('VALUE4', '0xAF12'),
+                               ast.EnumValue('VALUE5', '-0x09bcd'),
+                               ast.EnumValue('VALUE6', ('IDENTIFIER',
+                                                        'VALUE5')),
+                               ast.EnumValue('VALUE7', None)]))])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testInvalidEnumInitializers(self):
+    """Tests that invalid enum initializers are correctly detected."""
+
+    # No values.
+    source1 = """\
+        enum MyEnum {
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected '}':\n"
+            r" *};$"):
+      parser.Parse(source1, "my_file.mojom")
+
+    # Floating point value.
+    source2 = "enum MyEnum { VALUE = 0.123 };"
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:1: Error: Unexpected '0\.123':\n"
+            r"enum MyEnum { VALUE = 0\.123 };$"):
+      parser.Parse(source2, "my_file.mojom")
+
+    # Boolean value.
+    source2 = "enum MyEnum { VALUE = true };"
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:1: Error: Unexpected 'true':\n"
+            r"enum MyEnum { VALUE = true };$"):
+      parser.Parse(source2, "my_file.mojom")
+
+  def testConsts(self):
+    """Tests some constants and struct members initialized with them."""
+
+    source = """\
+        module my_module {
+
+        struct MyStruct {
+          const int8 kNumber = -1;
+          int8 number@0 = kNumber;
+        };
+
+        }  // my_module
+        """
+    expected = ast.Mojom(
+        ast.Module(('IDENTIFIER', 'my_module'), None),
+        ast.ImportList(),
+        [ast.Struct(
+            'MyStruct', None,
+            ast.StructBody(
+                [ast.Const('kNumber', 'int8', '-1'),
+                 ast.StructField('number', ast.Ordinal(0), 'int8',
+                                 ('IDENTIFIER', 'kNumber'))]))])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testNoConditionals(self):
+    """Tests that ?: is not allowed."""
+
+    source = """\
+        module my_module {
+
+        enum MyEnum {
+          MY_ENUM_1 = 1 ? 2 : 3
+        };
+
+        }  // my_module
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:4: Error: Unexpected '\?':\n"
+            r" *MY_ENUM_1 = 1 \? 2 : 3$"):
+      parser.Parse(source, "my_file.mojom")
+
+  def testSimpleOrdinals(self):
+    """Tests that (valid) ordinal values are scanned correctly."""
+
+    source = """\
+        module my_module {
+
+        // This isn't actually valid .mojom, but the problem (missing ordinals)
+        // should be handled at a different level.
+        struct MyStruct {
+          int32 a0@0;
+          int32 a1@1;
+          int32 a2@2;
+          int32 a9@9;
+          int32 a10 @10;
+          int32 a11 @11;
+          int32 a29 @29;
+          int32 a1234567890 @1234567890;
+        };
+
+        }  // module my_module
+        """
+    expected = ast.Mojom(
+        ast.Module(('IDENTIFIER', 'my_module'), None),
+        ast.ImportList(),
+        [ast.Struct(
+            'MyStruct',
+            None,
+            ast.StructBody(
+                [ast.StructField('a0', ast.Ordinal(0), 'int32', None),
+                 ast.StructField('a1', ast.Ordinal(1), 'int32', None),
+                 ast.StructField('a2', ast.Ordinal(2), 'int32', None),
+                 ast.StructField('a9', ast.Ordinal(9), 'int32', None),
+                 ast.StructField('a10', ast.Ordinal(10), 'int32', None),
+                 ast.StructField('a11', ast.Ordinal(11), 'int32', None),
+                 ast.StructField('a29', ast.Ordinal(29), 'int32', None),
+                 ast.StructField('a1234567890', ast.Ordinal(1234567890),
+                                 'int32', None)]))])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testInvalidOrdinals(self):
+    """Tests that (lexically) invalid ordinals are correctly detected."""
+
+    source1 = """\
+        module my_module {
+
+        struct MyStruct {
+          int32 a_missing@;
+        };
+
+        }  // module my_module
+        """
+    with self.assertRaisesRegexp(
+        lexer.LexError,
+        r"^my_file\.mojom:4: Error: Missing ordinal value$"):
+      parser.Parse(source1, "my_file.mojom")
+
+    source2 = """\
+        module my_module {
+
+        struct MyStruct {
+          int32 a_octal@01;
+        };
+
+        }  // module my_module
+        """
+    with self.assertRaisesRegexp(
+        lexer.LexError,
+        r"^my_file\.mojom:4: Error: "
+            r"Octal and hexadecimal ordinal values not allowed$"):
+      parser.Parse(source2, "my_file.mojom")
+
+    source3 = """\
+        module my_module { struct MyStruct { int32 a_invalid_octal@08; }; }
+        """
+    with self.assertRaisesRegexp(
+        lexer.LexError,
+        r"^my_file\.mojom:1: Error: "
+            r"Octal and hexadecimal ordinal values not allowed$"):
+      parser.Parse(source3, "my_file.mojom")
+
+    source4 = "module my_module { struct MyStruct { int32 a_hex@0x1aB9; }; }"
+    with self.assertRaisesRegexp(
+        lexer.LexError,
+        r"^my_file\.mojom:1: Error: "
+            r"Octal and hexadecimal ordinal values not allowed$"):
+      parser.Parse(source4, "my_file.mojom")
+
+    source5 = "module my_module { struct MyStruct { int32 a_hex@0X0; }; }"
+    with self.assertRaisesRegexp(
+        lexer.LexError,
+        r"^my_file\.mojom:1: Error: "
+            r"Octal and hexadecimal ordinal values not allowed$"):
+      parser.Parse(source5, "my_file.mojom")
+
+    source6 = """\
+        struct MyStruct {
+          int32 a_too_big@999999999999;
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: "
+            r"Ordinal value 999999999999 too large:\n"
+            r" *int32 a_too_big@999999999999;$"):
+      parser.Parse(source6, "my_file.mojom")
+
+  def testNestedNamespace(self):
+    """Tests that "nested" namespaces work."""
+
+    source = """\
+        module my.mod {
+
+        struct MyStruct {
+          int32 a;
+        };
+
+        }  // module my.mod
+        """
+    expected = ast.Mojom(
+        ast.Module(('IDENTIFIER', 'my.mod'), None),
+        ast.ImportList(),
+        [ast.Struct(
+            'MyStruct',
+            None,
+            ast.StructBody(ast.StructField('a', None, 'int32', None)))])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testValidHandleTypes(self):
+    """Tests (valid) handle types."""
+
+    source = """\
+        struct MyStruct {
+          handle a;
+          handle<data_pipe_consumer> b;
+          handle <data_pipe_producer> c;
+          handle < message_pipe > d;
+          handle
+            < shared_buffer
+            > e;
+        };
+        """
+    expected = ast.Mojom(
+        None,
+        ast.ImportList(),
+        [ast.Struct(
+            'MyStruct',
+            None,
+            ast.StructBody(
+                [ast.StructField('a', None, 'handle', None),
+                 ast.StructField('b', None, 'handle<data_pipe_consumer>', None),
+                 ast.StructField('c', None, 'handle<data_pipe_producer>', None),
+                 ast.StructField('d', None, 'handle<message_pipe>', None),
+                 ast.StructField('e', None, 'handle<shared_buffer>', None)]))])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testInvalidHandleType(self):
+    """Tests an invalid (unknown) handle type."""
+
+    source = """\
+        struct MyStruct {
+          handle<wtf_is_this> foo;
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: "
+            r"Invalid handle type 'wtf_is_this':\n"
+            r" *handle<wtf_is_this> foo;$"):
+      parser.Parse(source, "my_file.mojom")
+
+  def testValidDefaultValues(self):
+    """Tests default values that are valid (to the parser)."""
+
+    source = """\
+        struct MyStruct {
+          int16 a0 = 0;
+          uint16 a1 = 0x0;
+          uint16 a2 = 0x00;
+          uint16 a3 = 0x01;
+          uint16 a4 = 0xcd;
+          int32 a5 = 12345;
+          int64 a6 = -12345;
+          int64 a7 = +12345;
+          uint32 a8 = 0x12cd3;
+          uint32 a9 = -0x12cD3;
+          uint32 a10 = +0x12CD3;
+          bool a11 = true;
+          bool a12 = false;
+          float a13 = 1.2345;
+          float a14 = -1.2345;
+          float a15 = +1.2345;
+          float a16 = 123.;
+          float a17 = .123;
+          double a18 = 1.23E10;
+          double a19 = 1.E-10;
+          double a20 = .5E+10;
+          double a21 = -1.23E10;
+          double a22 = +.123E10;
+        };
+        """
+    expected = ast.Mojom(
+        None,
+        ast.ImportList(),
+        [ast.Struct(
+            'MyStruct',
+            None,
+            ast.StructBody(
+                [ast.StructField('a0', None, 'int16', '0'),
+                 ast.StructField('a1', None, 'uint16', '0x0'),
+                 ast.StructField('a2', None, 'uint16', '0x00'),
+                 ast.StructField('a3', None, 'uint16', '0x01'),
+                 ast.StructField('a4', None, 'uint16', '0xcd'),
+                 ast.StructField('a5' , None, 'int32', '12345'),
+                 ast.StructField('a6', None, 'int64', '-12345'),
+                 ast.StructField('a7', None, 'int64', '+12345'),
+                 ast.StructField('a8', None, 'uint32', '0x12cd3'),
+                 ast.StructField('a9', None, 'uint32', '-0x12cD3'),
+                 ast.StructField('a10', None, 'uint32', '+0x12CD3'),
+                 ast.StructField('a11', None, 'bool', 'true'),
+                 ast.StructField('a12', None, 'bool', 'false'),
+                 ast.StructField('a13', None, 'float', '1.2345'),
+                 ast.StructField('a14', None, 'float', '-1.2345'),
+                 ast.StructField('a15', None, 'float', '+1.2345'),
+                 ast.StructField('a16', None, 'float', '123.'),
+                 ast.StructField('a17', None, 'float', '.123'),
+                 ast.StructField('a18', None, 'double', '1.23E10'),
+                 ast.StructField('a19', None, 'double', '1.E-10'),
+                 ast.StructField('a20', None, 'double', '.5E+10'),
+                 ast.StructField('a21', None, 'double', '-1.23E10'),
+                 ast.StructField('a22', None, 'double', '+.123E10')]))])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testValidFixedSizeArray(self):
+    """Tests parsing a fixed size array."""
+
+    source = """\
+        struct MyStruct {
+          array<int32> normal_array;
+          array<int32, 1> fixed_size_array_one_entry;
+          array<int32, 10> fixed_size_array_ten_entries;
+        };
+        """
+    expected = ast.Mojom(
+        None,
+        ast.ImportList(),
+        [ast.Struct(
+            'MyStruct',
+            None,
+            ast.StructBody(
+                [ast.StructField('normal_array', None, 'int32[]', None),
+                 ast.StructField('fixed_size_array_one_entry', None, 'int32[1]',
+                                 None),
+                 ast.StructField('fixed_size_array_ten_entries', None,
+                                 'int32[10]', None)]))])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testValidNestedArray(self):
+    """Tests parsing a nested array."""
+
+    source = "struct MyStruct { array<array<int32>> nested_array; };"
+    expected = ast.Mojom(
+        None,
+        ast.ImportList(),
+        [ast.Struct(
+            'MyStruct',
+            None,
+            ast.StructBody(
+                ast.StructField('nested_array', None, 'int32[][]', None)))])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testInvalidFixedArraySize(self):
+    """Tests that invalid fixed array bounds are correctly detected."""
+
+    source1 = """\
+        struct MyStruct {
+          array<int32, 0> zero_size_array;
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Fixed array size 0 invalid\n"
+            r" *array<int32, 0> zero_size_array;$"):
+      parser.Parse(source1, "my_file.mojom")
+
+    source2 = """\
+        struct MyStruct {
+          array<int32, 999999999999> too_big_array;
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Fixed array size 999999999999 invalid\n"
+            r" *array<int32, 999999999999> too_big_array;$"):
+      parser.Parse(source2, "my_file.mojom")
+
+    source3 = """\
+        struct MyStruct {
+          array<int32, abcdefg> not_a_number;
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected 'abcdefg':\n"
+        r" *array<int32, abcdefg> not_a_number;"):
+      parser.Parse(source3, "my_file.mojom")
+
+  def testValidMethod(self):
+    """Tests parsing method declarations."""
+
+    source1 = "interface MyInterface { MyMethod(int32 a); };"
+    expected1 = ast.Mojom(
+        None,
+        ast.ImportList(),
+        [ast.Interface(
+            'MyInterface',
+            None,
+            ast.InterfaceBody(
+                ast.Method(
+                    'MyMethod',
+                    None,
+                    ast.ParameterList(ast.Parameter('a', None, 'int32')),
+                    None)))])
+    self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1)
+
+    source2 = """\
+        interface MyInterface {
+          MyMethod1@0(int32 a@0, int64 b@1);
+          MyMethod2@1() => ();
+        };
+        """
+    expected2 = ast.Mojom(
+        None,
+        ast.ImportList(),
+        [ast.Interface(
+            'MyInterface',
+            None,
+            ast.InterfaceBody(
+                [ast.Method(
+                    'MyMethod1',
+                    ast.Ordinal(0),
+                    ast.ParameterList([ast.Parameter('a', ast.Ordinal(0),
+                                                     'int32'),
+                                       ast.Parameter('b', ast.Ordinal(1),
+                                                     'int64')]),
+                    None),
+                  ast.Method(
+                    'MyMethod2',
+                    ast.Ordinal(1),
+                    ast.ParameterList(),
+                    ast.ParameterList())]))])
+    self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2)
+
+    source3 = """\
+        interface MyInterface {
+          MyMethod(string a) => (int32 a, bool b);
+        };
+        """
+    expected3 = ast.Mojom(
+        None,
+        ast.ImportList(),
+        [ast.Interface(
+            'MyInterface',
+            None,
+            ast.InterfaceBody(
+                ast.Method(
+                    'MyMethod',
+                    None,
+                    ast.ParameterList(ast.Parameter('a', None, 'string')),
+                    ast.ParameterList([ast.Parameter('a', None, 'int32'),
+                                       ast.Parameter('b', None, 'bool')]))))])
+    self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3)
+
+  def testInvalidMethods(self):
+    """Tests that invalid method declarations are correctly detected."""
+
+    # No trailing commas.
+    source1 = """\
+        interface MyInterface {
+          MyMethod(string a,);
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected '\)':\n"
+            r" *MyMethod\(string a,\);$"):
+      parser.Parse(source1, "my_file.mojom")
+
+    # No leading commas.
+    source2 = """\
+        interface MyInterface {
+          MyMethod(, string a);
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected ',':\n"
+            r" *MyMethod\(, string a\);$"):
+      parser.Parse(source2, "my_file.mojom")
+
+  def testValidInterfaceDefinitions(self):
+    """Tests all types of definitions that can occur in an interface."""
+
+    source = """\
+        interface MyInterface {
+          enum MyEnum { VALUE };
+          const int32 kMyConst = 123;
+          MyMethod(int32 x) => (MyEnum y);
+        };
+        """
+    expected = ast.Mojom(
+        None,
+        ast.ImportList(),
+        [ast.Interface(
+            'MyInterface',
+            None,
+            ast.InterfaceBody(
+                [ast.Enum('MyEnum',
+                          ast.EnumValueList(ast.EnumValue('VALUE', None))),
+                 ast.Const('kMyConst', 'int32', '123'),
+                 ast.Method(
+                    'MyMethod',
+                    None,
+                    ast.ParameterList(ast.Parameter('x', None, 'int32')),
+                    ast.ParameterList(ast.Parameter('y', None, 'MyEnum')))]))])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testInvalidInterfaceDefinitions(self):
+    """Tests that definitions that aren't allowed in an interface are correctly
+    detected."""
+
+    source1 = """\
+        interface MyInterface {
+          struct MyStruct {
+            int32 a;
+          };
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected 'struct':\n"
+            r" *struct MyStruct {$"):
+      parser.Parse(source1, "my_file.mojom")
+
+    source2 = """\
+        interface MyInterface {
+          interface MyInnerInterface {
+            MyMethod(int32 x);
+          };
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected 'interface':\n"
+            r" *interface MyInnerInterface {$"):
+      parser.Parse(source2, "my_file.mojom")
+
+    source3 = """\
+        interface MyInterface {
+          int32 my_field;
+        };
+        """
+    # The parser thinks that "int32" is a plausible name for a method, so it's
+    # "my_field" that gives it away.
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected 'my_field':\n"
+            r" *int32 my_field;$"):
+      parser.Parse(source3, "my_file.mojom")
+
+  def testValidAttributes(self):
+    """Tests parsing attributes (and attribute lists)."""
+
+    # Note: We use structs because they have (optional) attribute lists.
+
+    # Empty attribute list.
+    source1 = "[] struct MyStruct {};"
+    expected1 = ast.Mojom(
+        None,
+        ast.ImportList(),
+        [ast.Struct('MyStruct', ast.AttributeList(), ast.StructBody())])
+    self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1)
+
+    # One-element attribute list, with name value.
+    source2 = "[MyAttribute=MyName] struct MyStruct {};"
+    expected2 = ast.Mojom(
+        None,
+        ast.ImportList(),
+        [ast.Struct(
+            'MyStruct',
+            ast.AttributeList(ast.Attribute("MyAttribute", "MyName")),
+            ast.StructBody())])
+    self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2)
+
+    # Two-element attribute list, with one string value and one integer value.
+    source3 = "[MyAttribute1 = \"hello\", MyAttribute2 = 5] struct MyStruct {};"
+    expected3 = ast.Mojom(
+        None,
+        ast.ImportList(),
+        [ast.Struct(
+            'MyStruct',
+            ast.AttributeList([ast.Attribute("MyAttribute1", "hello"),
+                               ast.Attribute("MyAttribute2", 5)]),
+            ast.StructBody())])
+    self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3)
+
+    # TODO(vtl): Boolean attributes don't work yet. (In fact, we just |eval()|
+    # literal (non-name) values, which is extremely dubious.)
+
+  def testInvalidAttributes(self):
+    """Tests that invalid attributes and attribute lists are correctly
+    detected."""
+
+    # Trailing commas not allowed.
+    source1 = "[MyAttribute=MyName,] struct MyStruct {};"
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:1: Error: Unexpected '\]':\n"
+            r"\[MyAttribute=MyName,\] struct MyStruct {};$"):
+      parser.Parse(source1, "my_file.mojom")
+
+    # Missing value.
+    source2 = "[MyAttribute=] struct MyStruct {};"
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:1: Error: Unexpected '\]':\n"
+            r"\[MyAttribute=\] struct MyStruct {};$"):
+      parser.Parse(source2, "my_file.mojom")
+
+    # Missing key.
+    source3 = "[=MyName] struct MyStruct {};"
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:1: Error: Unexpected '=':\n"
+            r"\[=MyName\] struct MyStruct {};$"):
+      parser.Parse(source3, "my_file.mojom")
+
+  def testValidImports(self):
+    """Tests parsing import statements."""
+
+    # One import (no module statement).
+    source1 = "import \"somedir/my.mojom\""
+    expected1 = ast.Mojom(
+        None,
+        ast.ImportList(ast.Import("somedir/my.mojom")),
+        [])
+    self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1)
+
+    # Two imports (no module statement).
+    source2 = """\
+        import "somedir/my1.mojom"
+        import "somedir/my2.mojom"
+        """
+    expected2 = ast.Mojom(
+        None,
+        ast.ImportList([ast.Import("somedir/my1.mojom"),
+                        ast.Import("somedir/my2.mojom")]),
+        [])
+    self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2)
+
+    # Imports with module statement.
+    source3 = """\
+        import "somedir/my1.mojom"
+        import "somedir/my2.mojom"
+        module my_module {}
+        """
+    expected3 = ast.Mojom(
+        ast.Module(('IDENTIFIER', 'my_module'), None),
+        ast.ImportList([ast.Import("somedir/my1.mojom"),
+                        ast.Import("somedir/my2.mojom")]),
+        [])
+    self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3)
+
+  def testInvalidImports(self):
+    """Tests that invalid import statements are correctly detected."""
+
+    source1 = """\
+        // Make the error occur on line 2.
+        import invalid
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected 'invalid':\n"
+            r" *import invalid$"):
+      parser.Parse(source1, "my_file.mojom")
+
+    source2 = """\
+        import  // Missing string.
+        module {}
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected 'module':\n"
+            r" *module {}$"):
+      parser.Parse(source2, "my_file.mojom")
+
+  def testValidNullableTypes(self):
+    """Tests parsing nullable types."""
+
+    source = """\
+        struct MyStruct {
+          int32? a;  // This is actually invalid, but handled at a different
+                     // level.
+          string? b;
+          array<int32> ? c;
+          array<string ? > ? d;
+          array<array<int32>?>? e;
+          array<int32, 1>? f;
+          array<string?, 1>? g;
+          some_struct? h;
+          handle? i;
+          handle<data_pipe_consumer>? j;
+          handle<data_pipe_producer>? k;
+          handle<message_pipe>? l;
+          handle<shared_buffer>? m;
+          some_interface&? n;
+        };
+        """
+    expected = ast.Mojom(
+        None,
+        ast.ImportList(),
+        [ast.Struct(
+            'MyStruct',
+            None,
+            ast.StructBody(
+                [ast.StructField('a', None, 'int32?', None),
+                 ast.StructField('b', None, 'string?', None),
+                 ast.StructField('c', None, 'int32[]?', None),
+                 ast.StructField('d', None, 'string?[]?', None),
+                 ast.StructField('e', None, 'int32[]?[]?', None),
+                 ast.StructField('f', None, 'int32[1]?', None),
+                 ast.StructField('g', None, 'string?[1]?', None),
+                 ast.StructField('h', None, 'some_struct?', None),
+                 ast.StructField('i', None, 'handle?', None),
+                 ast.StructField('j', None, 'handle<data_pipe_consumer>?',
+                                 None),
+                 ast.StructField('k', None, 'handle<data_pipe_producer>?',
+                                 None),
+                 ast.StructField('l', None, 'handle<message_pipe>?', None),
+                 ast.StructField('m', None, 'handle<shared_buffer>?', None),
+                 ast.StructField('n', None, 'some_interface&?', None)]))])
+    self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
+
+  def testInvalidNullableTypes(self):
+    """Tests that invalid nullable types are correctly detected."""
+    source1 = """\
+        struct MyStruct {
+          string?? a;
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected '\?':\n"
+            r" *string\?\? a;$"):
+      parser.Parse(source1, "my_file.mojom")
+
+    source2 = """\
+        struct MyStruct {
+          handle?<data_pipe_consumer> a;
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected '<':\n"
+            r" *handle\?<data_pipe_consumer> a;$"):
+      parser.Parse(source2, "my_file.mojom")
+
+    source3 = """\
+        struct MyStruct {
+          some_interface?& a;
+        };
+        """
+    with self.assertRaisesRegexp(
+        parser.ParseError,
+        r"^my_file\.mojom:2: Error: Unexpected '&':\n"
+            r" *some_interface\?& a;$"):
+      parser.Parse(source3, "my_file.mojom")
+
+if __name__ == "__main__":
+  unittest.main()
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/parse/run_parser.py b/mojo/public/tools/bindings/pylib/mojom_tests/parse/run_parser.py
new file mode 100755
index 0000000..b160de6
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom_tests/parse/run_parser.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# Copyright 2014 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.
+
+"""Simple testing utility to just run the mojom parser."""
+
+
+import os.path
+import sys
+
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                                os.path.pardir, os.path.pardir))
+
+from mojom.parse.parser import Parse, ParseError
+
+
+def main(argv):
+  if len(argv) < 2:
+    print "usage: %s filename" % argv[0]
+    return 0
+
+  for filename in argv[1:]:
+    with open(filename) as f:
+      print "%s:" % filename
+      try:
+        print Parse(f.read(), filename)
+      except ParseError, e:
+        print e
+        return 1
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/parse/run_translate.py b/mojo/public/tools/bindings/pylib/mojom_tests/parse/run_translate.py
new file mode 100755
index 0000000..899d40e
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom_tests/parse/run_translate.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+# Copyright 2014 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.
+
+"""Simple testing utility to just run the mojom translate stage."""
+
+
+import os.path
+import sys
+
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                                os.path.pardir, os.path.pardir))
+
+from mojom.parse.parser import Parse
+from mojom.parse.translate import Translate
+
+
+def main(argv):
+  if len(argv) < 2:
+    print "usage: %s filename" % sys.argv[0]
+    return 1
+
+  for filename in argv[1:]:
+    with open(filename) as f:
+      print "%s:" % filename
+      print Translate(Parse(f.read(), filename),
+                      os.path.splitext(os.path.basename(filename))[0])
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/support/__init__.py b/mojo/public/tools/bindings/pylib/mojom_tests/support/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom_tests/support/__init__.py
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/support/find_files.py b/mojo/public/tools/bindings/pylib/mojom_tests/support/find_files.py
new file mode 100644
index 0000000..2a4b17b
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom_tests/support/find_files.py
@@ -0,0 +1,32 @@
+# Copyright 2014 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.
+
+import fnmatch
+from os import walk
+from os.path import join
+import sys
+
+
+def FindFiles(top, pattern, **kwargs):
+  """Finds files under |top| matching the glob pattern |pattern|, returning a
+  list of paths."""
+  matches = []
+  for dirpath, _, filenames in walk(top, **kwargs):
+    for filename in fnmatch.filter(filenames, pattern):
+      matches.append(join(dirpath, filename))
+  return matches
+
+
+def main(argv):
+  if len(argv) != 3:
+    print "usage: %s path pattern" % argv[0]
+    return 1
+
+  for filename in FindFiles(argv[1], argv[2]):
+    print filename
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/support/run_bindings_generator.py b/mojo/public/tools/bindings/pylib/mojom_tests/support/run_bindings_generator.py
new file mode 100644
index 0000000..20ef461
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom_tests/support/run_bindings_generator.py
@@ -0,0 +1,47 @@
+# Copyright 2014 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.
+
+import os.path
+from subprocess import check_call
+import sys
+
+
+def RunBindingsGenerator(out_dir, root_dir, mojom_file, extra_flags=None):
+  out_dir = os.path.abspath(out_dir)
+  root_dir = os.path.abspath(root_dir)
+  mojom_file = os.path.abspath(mojom_file)
+
+  # The mojom file should be under the root directory somewhere.
+  assert mojom_file.startswith(root_dir)
+  mojom_reldir = os.path.dirname(os.path.relpath(mojom_file, root_dir))
+
+  # TODO(vtl): Abstract out the "main" functions, so that we can just import
+  # the bindings generator (which would be more portable and easier to use in
+  # tests).
+  this_dir = os.path.dirname(os.path.abspath(__file__))
+  # We're in src/mojo/public/tools/bindings/pylib/mojom_tests/support;
+  # mojom_bindings_generator.py is in .../bindings.
+  bindings_generator = os.path.join(this_dir, os.pardir, os.pardir, os.pardir,
+                                    "mojom_bindings_generator.py")
+
+  args = ["python", bindings_generator,
+          "-o", os.path.join(out_dir, mojom_reldir)]
+  if extra_flags:
+    args.extend(extra_flags)
+  args.append(mojom_file)
+
+  check_call(args)
+
+
+def main(argv):
+  if len(argv) < 4:
+    print "usage: %s out_dir root_dir mojom_file [extra_flags]" % argv[0]
+    return 1
+
+  RunBindingsGenerator(argv[1], argv[2], argv[3], extra_flags=argv[4:])
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))