Revert "libmojo: Uprev the library to r456626 from Chromium"

This reverts commit 8ac9103e05b66812c25348943383f9365d1ce3e0.

Reason for revert: Broke the mac_sdk
Exempt-From-Owner-Approval: Fixing mac_sdk

Change-Id: I0b74d1abaa66933a93fd6f82ff018e8948c1204e
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
index 5c41384..3ec9824 100644
--- a/mojo/public/cpp/bindings/BUILD.gn
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -2,31 +2,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-interfaces_bindings_gen_dir = "$root_gen_dir/mojo/public/interfaces/bindings"
-
-component("bindings") {
+static_library("bindings") {
   sources = [
-    # Normally, targets should depend on the source_sets generated by mojom
-    # targets. However, the generated source_sets use portions of the bindings
-    # library. In order to avoid linker warnings about locally-defined imports
-    # in Windows components build, this target depends on the generated C++
-    # files directly so that the EXPORT macro defintions match.
-    "$interfaces_bindings_gen_dir/interface_control_messages.mojom-shared-internal.h",
-    "$interfaces_bindings_gen_dir/interface_control_messages.mojom-shared.cc",
-    "$interfaces_bindings_gen_dir/interface_control_messages.mojom-shared.h",
-    "$interfaces_bindings_gen_dir/interface_control_messages.mojom.cc",
-    "$interfaces_bindings_gen_dir/interface_control_messages.mojom.h",
-    "$interfaces_bindings_gen_dir/pipe_control_messages.mojom-shared-internal.h",
-    "$interfaces_bindings_gen_dir/pipe_control_messages.mojom-shared.cc",
-    "$interfaces_bindings_gen_dir/pipe_control_messages.mojom-shared.h",
-    "$interfaces_bindings_gen_dir/pipe_control_messages.mojom.cc",
-    "$interfaces_bindings_gen_dir/pipe_control_messages.mojom.h",
-    "array_data_view.h",
+    "array.h",
     "array_traits.h",
     "array_traits_carray.h",
+    "array_traits_standard.h",
     "array_traits_stl.h",
     "associated_binding.h",
-    "associated_binding_set.h",
     "associated_group.h",
     "associated_group_controller.h",
     "associated_interface_ptr.h",
@@ -34,13 +17,8 @@
     "associated_interface_request.h",
     "binding.h",
     "binding_set.h",
-    "bindings_export.h",
-    "clone_traits.h",
-    "connection_error_callback.h",
     "connector.h",
-    "disconnect_reason.h",
-    "filter_chain.h",
-    "interface_data_view.h",
+    "enum_traits.h",
     "interface_endpoint_client.h",
     "interface_endpoint_controller.h",
     "interface_id.h",
@@ -51,35 +29,34 @@
     "lib/array_internal.cc",
     "lib/array_internal.h",
     "lib/array_serialization.h",
-    "lib/associated_binding.cc",
     "lib/associated_group.cc",
     "lib/associated_group_controller.cc",
     "lib/associated_interface_ptr_state.h",
-    "lib/binding_state.cc",
     "lib/binding_state.h",
+    "lib/bindings_internal.cc",
     "lib/bindings_internal.h",
     "lib/buffer.h",
+    "lib/clone_equals_util.h",
     "lib/connector.cc",
     "lib/control_message_handler.cc",
     "lib/control_message_handler.h",
     "lib/control_message_proxy.cc",
     "lib/control_message_proxy.h",
-    "lib/equals_traits.h",
     "lib/filter_chain.cc",
+    "lib/filter_chain.h",
     "lib/fixed_buffer.cc",
     "lib/fixed_buffer.h",
     "lib/handle_interface_serialization.h",
-    "lib/hash_util.h",
     "lib/interface_endpoint_client.cc",
     "lib/interface_ptr_state.h",
     "lib/map_data_internal.h",
     "lib/map_serialization.h",
-    "lib/may_auto_lock.h",
     "lib/message.cc",
     "lib/message_buffer.cc",
     "lib/message_buffer.h",
     "lib/message_builder.cc",
     "lib/message_builder.h",
+    "lib/message_filter.cc",
     "lib/message_header_validator.cc",
     "lib/message_internal.h",
     "lib/multiplex_router.cc",
@@ -91,8 +68,11 @@
     "lib/native_struct_data.h",
     "lib/native_struct_serialization.cc",
     "lib/native_struct_serialization.h",
+    "lib/no_interface.cc",
     "lib/pipe_control_message_handler.cc",
     "lib/pipe_control_message_proxy.cc",
+    "lib/router.cc",
+    "lib/router.h",
     "lib/scoped_interface_endpoint_handle.cc",
     "lib/serialization.h",
     "lib/serialization_context.cc",
@@ -114,35 +94,32 @@
     "lib/validation_util.cc",
     "lib/validation_util.h",
     "map.h",
-    "map_data_view.h",
     "map_traits.h",
+    "map_traits_standard.h",
     "map_traits_stl.h",
     "message.h",
+    "message_filter.h",
     "message_header_validator.h",
     "native_enum.h",
     "native_struct.h",
-    "native_struct_data_view.h",
+    "no_interface.h",
     "pipe_control_message_handler.h",
     "pipe_control_message_handler_delegate.h",
     "pipe_control_message_proxy.h",
-    "raw_ptr_impl_ref_traits.h",
     "scoped_interface_endpoint_handle.h",
-    "string_data_view.h",
+    "stl_converters.h",
+    "string.h",
     "string_traits.h",
+    "string_traits_standard.h",
     "string_traits_stl.h",
     "string_traits_string16.h",
     "string_traits_string_piece.h",
-    "strong_associated_binding.h",
     "strong_binding.h",
-    "strong_binding_set.h",
     "struct_ptr.h",
     "sync_call_restrictions.h",
     "sync_handle_registry.h",
     "sync_handle_watcher.h",
-    "thread_safe_interface_ptr.h",
     "type_converter.h",
-    "union_traits.h",
-    "unique_ptr_impl_ref_traits.h",
   ]
 
   public_deps = [
@@ -154,16 +131,12 @@
 
   deps = [
     "//base",
-    "//mojo/public/interfaces/bindings:bindings__generator",
-    "//mojo/public/interfaces/bindings:bindings_shared__generator",
+    "//mojo/public/interfaces/bindings:bindings_cpp_sources",
   ]
-
-  defines = [ "MOJO_CPP_BINDINGS_IMPLEMENTATION" ]
 }
 
 source_set("struct_traits") {
   sources = [
-    "enum_traits.h",
     "struct_traits.h",
   ]
 }
@@ -172,13 +145,16 @@
   # TODO(yzshen): crbug.com/617718 Consider moving this into blink.
   source_set("wtf_support") {
     sources = [
+      "array_traits_wtf.h",
       "array_traits_wtf_vector.h",
       "lib/string_traits_wtf.cc",
       "lib/wtf_clone_equals_util.h",
-      "lib/wtf_hash_util.h",
       "lib/wtf_serialization.h",
+      "map_traits_wtf.h",
       "map_traits_wtf_hash_map.h",
       "string_traits_wtf.h",
+      "wtf_array.h",
+      "wtf_map.h",
     ]
 
     public_deps = [
diff --git a/mojo/public/cpp/bindings/array.h b/mojo/public/cpp/bindings/array.h
new file mode 100644
index 0000000..a253da1
--- /dev/null
+++ b/mojo/public/cpp/bindings/array.h
@@ -0,0 +1,279 @@
+// 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 <stddef.h>
+#include <string.h>
+#include <algorithm>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/clone_equals_util.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+#include "mojo/public/cpp/bindings/type_converter.h"
+
+namespace mojo {
+
+// Represents a moveable array with contents of type |T|. The array can be null,
+// meaning that no value has been assigned to it. Null is distinct from empty.
+template <typename T>
+class Array {
+ public:
+  using ConstRefType = typename std::vector<T>::const_reference;
+  using RefType = typename std::vector<T>::reference;
+
+  using Element = T;
+
+  using iterator = typename std::vector<T>::iterator;
+  using const_iterator = typename std::vector<T>::const_iterator;
+
+  // Constructs an empty array.
+  Array() : is_null_(false) {}
+  // Constructs a null array.
+  Array(std::nullptr_t null_pointer) : is_null_(true) {}
+
+  // Constructs a new non-null array of the specified size. The elements will
+  // be value-initialized (meaning that they will be initialized by their
+  // default constructor, if any, or else zero-initialized).
+  explicit Array(size_t size) : vec_(size), is_null_(false) {}
+  ~Array() {}
+
+  // Copies the contents of |other| into this array.
+  Array(const std::vector<T>& other) : vec_(other), is_null_(false) {}
+
+  // Moves the contents of |other| into this array.
+  Array(std::vector<T>&& other) : vec_(std::move(other)), is_null_(false) {}
+  Array(Array&& other) : is_null_(true) { Take(&other); }
+
+  Array& operator=(std::vector<T>&& other) {
+    vec_ = std::move(other);
+    is_null_ = false;
+    return *this;
+  }
+  Array& operator=(Array&& other) {
+    Take(&other);
+    return *this;
+  }
+
+  Array& operator=(std::nullptr_t null_pointer) {
+    is_null_ = true;
+    vec_.clear();
+    return *this;
+  }
+
+  // Creates a non-null array of the specified size. The elements will be
+  // value-initialized (meaning that they will be initialized by their default
+  // constructor, if any, or else zero-initialized).
+  static Array New(size_t size) { return Array(size); }
+
+  // Creates a new array with a copy of the contents of |other|.
+  template <typename U>
+  static Array From(const U& other) {
+    return TypeConverter<Array, U>::Convert(other);
+  }
+
+  // Copies the contents of this array to a new object of type |U|.
+  template <typename U>
+  U To() const {
+    return TypeConverter<U, Array>::Convert(*this);
+  }
+
+  // Indicates whether the array is null (which is distinct from empty).
+  bool is_null() const { return is_null_; }
+
+  // Indicates whether the array is empty (which is distinct from null).
+  bool empty() const { return vec_.empty() && !is_null_; }
+
+  // Returns a reference to the first element of the array. Calling this on a
+  // null or empty array causes undefined behavior.
+  ConstRefType front() const { return vec_.front(); }
+  RefType front() { return vec_.front(); }
+
+  iterator begin() { return vec_.begin(); }
+  const_iterator begin() const { return vec_.begin(); }
+  iterator end() { return vec_.end(); }
+  const_iterator end() const { return vec_.end(); }
+
+  // Returns the size of the array, which will be zero if the array is null.
+  size_t size() const { return vec_.size(); }
+
+  // Returns a reference to the element at zero-based |offset|. Calling this on
+  // an array with size less than |offset|+1 causes undefined behavior.
+  ConstRefType at(size_t offset) const { return vec_.at(offset); }
+  ConstRefType operator[](size_t offset) const { return at(offset); }
+  RefType at(size_t offset) { return vec_.at(offset); }
+  RefType operator[](size_t offset) { return at(offset); }
+
+  // Pushes |value| onto the back of the array. If this array was null, it will
+  // become non-null with a size of 1.
+  void push_back(const T& value) {
+    is_null_ = false;
+    vec_.push_back(value);
+  }
+  void push_back(T&& value) {
+    is_null_ = false;
+    vec_.push_back(std::move(value));
+  }
+
+  // Resizes the array to |size| and makes it non-null. Otherwise, works just
+  // like the resize method of |std::vector|.
+  void resize(size_t size) {
+    is_null_ = false;
+    vec_.resize(size);
+  }
+
+  // Sets the array to empty (even if previously it was null.)
+  void SetToEmpty() { resize(0); }
+
+  // Returns a const reference to the |std::vector| managed by this class. If
+  // the array is null, this will be an empty vector.
+  const std::vector<T>& storage() const { return vec_; }
+
+  // Passes the underlying storage and resets this array to null.
+  std::vector<T> PassStorage() {
+    is_null_ = true;
+    return std::move(vec_);
+  }
+
+  operator const std::vector<T>&() const { return vec_; }
+
+  void Swap(Array* other) {
+    std::swap(is_null_, other->is_null_);
+    vec_.swap(other->vec_);
+  }
+
+  // Swaps the contents of this array with the specified vector, making this
+  // array non-null. Since the vector cannot represent null, it will just be
+  // made empty if this array is null.
+  void Swap(std::vector<T>* other) {
+    is_null_ = false;
+    vec_.swap(*other);
+  }
+
+  // Returns a copy of the array where each value of the new array has been
+  // "cloned" from the corresponding value of this array. If the element type
+  // defines a Clone() method, it will be used; otherwise copy
+  // constructor/assignment will be used.
+  //
+  // 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 containing Mojo handles).
+  Array Clone() const {
+    Array result;
+    result.is_null_ = is_null_;
+    result.vec_ = internal::Clone(vec_);
+    return result;
+  }
+
+  // Indicates whether the contents of this array are equal to |other|. A null
+  // array is only equal to another null array. If the element type defines an
+  // Equals() method, it will be used; otherwise == operator will be used.
+  bool Equals(const Array& other) const {
+    if (is_null() != other.is_null())
+      return false;
+    return internal::Equals(vec_, other.vec_);
+  }
+
+ private:
+  typedef std::vector<T> Array::*Testable;
+
+ public:
+  operator Testable() const { return is_null_ ? 0 : &Array::vec_; }
+
+ private:
+  // Forbid the == and != operators explicitly, otherwise Array will be
+  // converted to Testable to do == or != comparison.
+  template <typename U>
+  bool operator==(const Array<U>& other) const = delete;
+  template <typename U>
+  bool operator!=(const Array<U>& other) const = delete;
+
+  void Take(Array* other) {
+    operator=(nullptr);
+    Swap(other);
+  }
+
+  std::vector<T> vec_;
+  bool is_null_;
+
+  DISALLOW_COPY_AND_ASSIGN(Array);
+};
+
+// A |TypeConverter| that will create an |Array<T>| containing a copy of the
+// contents of an |std::vector<E>|, using |TypeConverter<T, E>| to copy each
+// element. The returned array will always be non-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 std::move(result);
+  }
+};
+
+// A |TypeConverter| that will create an |std::vector<E>| containing a copy of
+// the contents of an |Array<T>|, using |TypeConverter<E, T>| to copy each
+// element. If the input array is null, the output vector will be empty.
+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;
+  }
+};
+
+// A |TypeConverter| that will create an |Array<T>| containing a copy of the
+// contents of an |std::set<E>|, using |TypeConverter<T, E>| to copy each
+// element. The returned array will always be non-null.
+template <typename T, typename E>
+struct TypeConverter<Array<T>, std::set<E>> {
+  static Array<T> Convert(const std::set<E>& input) {
+    Array<T> result;
+    for (auto i : input)
+      result.push_back(TypeConverter<T, E>::Convert(i));
+    return std::move(result);
+  }
+};
+
+// A |TypeConverter| that will create an |std::set<E>| containing a copy of
+// the contents of an |Array<T>|, using |TypeConverter<E, T>| to copy each
+// element. If the input array is null, the output set will be empty.
+template <typename E, typename T>
+struct TypeConverter<std::set<E>, Array<T>> {
+  static std::set<E> Convert(const Array<T>& input) {
+    std::set<E> result;
+    if (!input.is_null()) {
+      for (size_t i = 0; i < input.size(); ++i)
+        result.insert(TypeConverter<E, T>::Convert(input[i]));
+    }
+    return result;
+  }
+};
+
+// Less than operator to allow Arrays as keys in std maps and sets.
+template <typename T>
+inline bool operator<(const Array<T>& a, const Array<T>& b) {
+  if (a.is_null())
+    return !b.is_null();
+  if (b.is_null())
+    return false;
+  return a.storage() < b.storage();
+}
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_
diff --git a/mojo/public/cpp/bindings/array_data_view.h b/mojo/public/cpp/bindings/array_data_view.h
deleted file mode 100644
index d02a884..0000000
--- a/mojo/public/cpp/bindings/array_data_view.h
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_ARRAY_DATA_VIEW_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_DATA_VIEW_H_
-
-#include <type_traits>
-
-#include "mojo/public/cpp/bindings/lib/array_internal.h"
-#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
-#include "mojo/public/cpp/bindings/lib/serialization_context.h"
-#include "mojo/public/cpp/bindings/lib/serialization_forward.h"
-
-namespace mojo {
-namespace internal {
-
-template <typename T, typename EnableType = void>
-class ArrayDataViewImpl;
-
-template <typename T>
-class ArrayDataViewImpl<
-    T,
-    typename std::enable_if<
-        BelongsTo<T, MojomTypeCategory::POD>::value>::type> {
- public:
-  using Data_ = typename MojomTypeTraits<ArrayDataView<T>>::Data;
-
-  ArrayDataViewImpl(Data_* data, SerializationContext* context)
-      : data_(data), context_(context) {}
-
-  T operator[](size_t index) const { return data_->at(index); }
-
-  const T* data() const { return data_->storage(); }
-
- protected:
-  Data_* data_;
-  SerializationContext* context_;
-};
-
-template <typename T>
-class ArrayDataViewImpl<
-    T,
-    typename std::enable_if<
-        BelongsTo<T, MojomTypeCategory::BOOLEAN>::value>::type> {
- public:
-  using Data_ = typename MojomTypeTraits<ArrayDataView<T>>::Data;
-
-  ArrayDataViewImpl(Data_* data, SerializationContext* context)
-      : data_(data), context_(context) {}
-
-  bool operator[](size_t index) const { return data_->at(index); }
-
- protected:
-  Data_* data_;
-  SerializationContext* context_;
-};
-
-template <typename T>
-class ArrayDataViewImpl<
-    T,
-    typename std::enable_if<
-        BelongsTo<T, MojomTypeCategory::ENUM>::value>::type> {
- public:
-  static_assert(sizeof(T) == sizeof(int32_t), "Unexpected enum size");
-
-  using Data_ = typename MojomTypeTraits<ArrayDataView<T>>::Data;
-
-  ArrayDataViewImpl(Data_* data, SerializationContext* context)
-      : data_(data), context_(context) {}
-
-  T operator[](size_t index) const { return static_cast<T>(data_->at(index)); }
-
-  const T* data() const { return reinterpret_cast<const T*>(data_->storage()); }
-
-  template <typename U>
-  bool Read(size_t index, U* output) {
-    return Deserialize<T>(data_->at(index), output);
-  }
-
- protected:
-  Data_* data_;
-  SerializationContext* context_;
-};
-
-template <typename T>
-class ArrayDataViewImpl<
-    T,
-    typename std::enable_if<
-        BelongsTo<T,
-                  MojomTypeCategory::ASSOCIATED_INTERFACE |
-                      MojomTypeCategory::ASSOCIATED_INTERFACE_REQUEST |
-                      MojomTypeCategory::INTERFACE |
-                      MojomTypeCategory::INTERFACE_REQUEST>::value>::type> {
- public:
-  using Data_ = typename MojomTypeTraits<ArrayDataView<T>>::Data;
-
-  ArrayDataViewImpl(Data_* data, SerializationContext* context)
-      : data_(data), context_(context) {}
-
-  template <typename U>
-  U Take(size_t index) {
-    U result;
-    bool ret = Deserialize<T>(&data_->at(index), &result, context_);
-    DCHECK(ret);
-    return result;
-  }
-
- protected:
-  Data_* data_;
-  SerializationContext* context_;
-};
-
-template <typename T>
-class ArrayDataViewImpl<
-    T,
-    typename std::enable_if<
-        BelongsTo<T, MojomTypeCategory::HANDLE>::value>::type> {
- public:
-  using Data_ = typename MojomTypeTraits<ArrayDataView<T>>::Data;
-
-  ArrayDataViewImpl(Data_* data, SerializationContext* context)
-      : data_(data), context_(context) {}
-
-  T Take(size_t index) {
-    T result;
-    bool ret = Deserialize<T>(&data_->at(index), &result, context_);
-    DCHECK(ret);
-    return result;
-  }
-
- protected:
-  Data_* data_;
-  SerializationContext* context_;
-};
-
-template <typename T>
-class ArrayDataViewImpl<T,
-                        typename std::enable_if<BelongsTo<
-                            T,
-                            MojomTypeCategory::ARRAY | MojomTypeCategory::MAP |
-                                MojomTypeCategory::STRING |
-                                MojomTypeCategory::STRUCT>::value>::type> {
- public:
-  using Data_ = typename MojomTypeTraits<ArrayDataView<T>>::Data;
-
-  ArrayDataViewImpl(Data_* data, SerializationContext* context)
-      : data_(data), context_(context) {}
-
-  void GetDataView(size_t index, T* output) {
-    *output = T(data_->at(index).Get(), context_);
-  }
-
-  template <typename U>
-  bool Read(size_t index, U* output) {
-    return Deserialize<T>(data_->at(index).Get(), output, context_);
-  }
-
- protected:
-  Data_* data_;
-  SerializationContext* context_;
-};
-
-template <typename T>
-class ArrayDataViewImpl<
-    T,
-    typename std::enable_if<
-        BelongsTo<T, MojomTypeCategory::UNION>::value>::type> {
- public:
-  using Data_ = typename MojomTypeTraits<ArrayDataView<T>>::Data;
-
-  ArrayDataViewImpl(Data_* data, SerializationContext* context)
-      : data_(data), context_(context) {}
-
-  void GetDataView(size_t index, T* output) {
-    *output = T(&data_->at(index), context_);
-  }
-
-  template <typename U>
-  bool Read(size_t index, U* output) {
-    return Deserialize<T>(&data_->at(index), output, context_);
-  }
-
- protected:
-  Data_* data_;
-  SerializationContext* context_;
-};
-
-}  // namespace internal
-
-template <typename K, typename V>
-class MapDataView;
-
-template <typename T>
-class ArrayDataView : public internal::ArrayDataViewImpl<T> {
- public:
-  using Element = T;
-  using Data_ = typename internal::ArrayDataViewImpl<T>::Data_;
-
-  ArrayDataView() : internal::ArrayDataViewImpl<T>(nullptr, nullptr) {}
-
-  ArrayDataView(Data_* data, internal::SerializationContext* context)
-      : internal::ArrayDataViewImpl<T>(data, context) {}
-
-  bool is_null() const { return !this->data_; }
-
-  size_t size() const { return this->data_->size(); }
-
-  // Methods to access elements are different for different element types. They
-  // are inherited from internal::ArrayDataViewImpl:
-
-  // POD types except boolean and enums:
-  //   T operator[](size_t index) const;
-  //   const T* data() const;
-
-  // Boolean:
-  //   bool operator[](size_t index) const;
-
-  // Enums:
-  //   T operator[](size_t index) const;
-  //   const T* data() const;
-  //   template <typename U>
-  //   bool Read(size_t index, U* output);
-
-  // Handles:
-  //   T Take(size_t index);
-
-  // Interfaces:
-  //   template <typename U>
-  //   U Take(size_t index);
-
-  // Object types:
-  //   void GetDataView(size_t index, T* output);
-  //   template <typename U>
-  //   bool Read(size_t index, U* output);
-
- private:
-  template <typename K, typename V>
-  friend class MapDataView;
-};
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_DATA_VIEW_H_
diff --git a/mojo/public/cpp/bindings/array_traits.h b/mojo/public/cpp/bindings/array_traits.h
index 594b2e0..366573d 100644
--- a/mojo/public/cpp/bindings/array_traits.h
+++ b/mojo/public/cpp/bindings/array_traits.h
@@ -47,9 +47,7 @@
 //     static void AdvanceIterator(Iterator& iterator);
 //
 //     // Returns a reference to the value at the current position of
-//     // |iterator|. Optionally, the ConstIterator version of GetValue can
-//     // return by value instead of by reference if it makes sense for the
-//     // type.
+//     // |iterator|.
 //     static const T& GetValue(ConstIterator& iterator);
 //     static T& GetValue(Iterator& iterator);
 //
diff --git a/mojo/public/cpp/bindings/array_traits_carray.h b/mojo/public/cpp/bindings/array_traits_carray.h
index 3ff694b..ffcf9d5 100644
--- a/mojo/public/cpp/bindings/array_traits_carray.h
+++ b/mojo/public/cpp/bindings/array_traits_carray.h
@@ -20,14 +20,6 @@
 };
 
 template <typename T>
-struct ConstCArray {
-  ConstCArray() : size(0), data(nullptr) {}
-  ConstCArray(size_t size, const T* data) : size(size), data(data) {}
-  size_t size;
-  const T* data;
-};
-
-template <typename T>
 struct ArrayTraits<CArray<T>> {
   using Element = T;
 
@@ -56,21 +48,6 @@
   }
 };
 
-template <typename T>
-struct ArrayTraits<ConstCArray<T>> {
-  using Element = T;
-
-  static bool IsNull(const ConstCArray<T>& input) { return !input.data; }
-
-  static size_t GetSize(const ConstCArray<T>& input) { return input.size; }
-
-  static const T* GetData(const ConstCArray<T>& input) { return input.data; }
-
-  static const T& GetAt(const ConstCArray<T>& input, size_t index) {
-    return input.data[index];
-  }
-};
-
 }  // namespace mojo
 
 #endif  // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_CARRAY_H_
diff --git a/mojo/public/cpp/bindings/array_traits_standard.h b/mojo/public/cpp/bindings/array_traits_standard.h
new file mode 100644
index 0000000..862de6b
--- /dev/null
+++ b/mojo/public/cpp/bindings/array_traits_standard.h
@@ -0,0 +1,43 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STANDARD_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STANDARD_H_
+
+#include "mojo/public/cpp/bindings/array.h"
+#include "mojo/public/cpp/bindings/array_traits.h"
+
+namespace mojo {
+
+template <typename T>
+struct ArrayTraits<Array<T>> {
+  using Element = T;
+
+  static bool IsNull(const Array<T>& input) { return input.is_null(); }
+  static void SetToNull(Array<T>* output) { *output = nullptr; }
+
+  static size_t GetSize(const Array<T>& input) { return input.size(); }
+
+  static T* GetData(Array<T>& input) { return &input.front(); }
+
+  static const T* GetData(const Array<T>& input) { return &input.front(); }
+
+  static typename Array<T>::RefType GetAt(Array<T>& input, size_t index) {
+    return input[index];
+  }
+
+  static typename Array<T>::ConstRefType GetAt(const Array<T>& input,
+                                               size_t index) {
+    return input[index];
+  }
+
+  static bool Resize(Array<T>& input, size_t size) {
+    input.resize(size);
+    return true;
+  }
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STANDARD_H_
diff --git a/mojo/public/cpp/bindings/array_traits_stl.h b/mojo/public/cpp/bindings/array_traits_stl.h
index dec47bf..9054a92 100644
--- a/mojo/public/cpp/bindings/array_traits_stl.h
+++ b/mojo/public/cpp/bindings/array_traits_stl.h
@@ -5,8 +5,6 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STL_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STL_H_
 
-#include <map>
-#include <set>
 #include <vector>
 
 #include "mojo/public/cpp/bindings/array_traits.h"
@@ -44,17 +42,13 @@
     return input[index];
   }
 
-  static inline bool Resize(std::vector<T>& input, size_t size) {
-    // Instead of calling std::vector<T>::resize() directly, this is a hack to
-    // make compilers happy. Some compilers (e.g., Mac, Android, Linux MSan)
-    // currently don't allow resizing types like
-    // std::vector<std::vector<MoveOnlyType>>.
-    // Because the deserialization code doesn't care about the original contents
-    // of |input|, we discard them directly.
-    //
-    // The "inline" keyword of this method matters. Without it, we have observed
-    // significant perf regression with some tests on Mac. crbug.com/631415
+  static bool Resize(std::vector<T>& input, size_t size) {
     if (input.size() != size) {
+      // This is a hack to make compilers for Mac and Android happy. They
+      // currently don't allow resizing types like
+      // std::vector<std::vector<MoveOnlyType>>.
+      // Because the deserialization code doesn't care about the original
+      // contents of |input|, we discard them directly.
       std::vector<T> temp(size);
       input.swap(temp);
     }
@@ -63,65 +57,6 @@
   }
 };
 
-// This ArrayTraits specialization is used only for serialization.
-template <typename T>
-struct ArrayTraits<std::set<T>> {
-  using Element = T;
-  using ConstIterator = typename std::set<T>::const_iterator;
-
-  static bool IsNull(const std::set<T>& input) {
-    // std::set<> is always converted to non-null mojom array.
-    return false;
-  }
-
-  static size_t GetSize(const std::set<T>& input) { return input.size(); }
-
-  static ConstIterator GetBegin(const std::set<T>& input) {
-    return input.begin();
-  }
-  static void AdvanceIterator(ConstIterator& iterator) {
-    ++iterator;
-  }
-  static const T& GetValue(ConstIterator& iterator) {
-    return *iterator;
-  }
-};
-
-template <typename K, typename V>
-struct MapValuesArrayView {
-  explicit MapValuesArrayView(const std::map<K, V>& map) : map(map) {}
-  const std::map<K, V>& map;
-};
-
-// Convenience function to create a MapValuesArrayView<> that infers the
-// template arguments from its argument type.
-template <typename K, typename V>
-MapValuesArrayView<K, V> MapValuesToArray(const std::map<K, V>& map) {
-  return MapValuesArrayView<K, V>(map);
-}
-
-// This ArrayTraits specialization is used only for serialization and converts
-// a map<K, V> into an array<V>, discarding the keys.
-template <typename K, typename V>
-struct ArrayTraits<MapValuesArrayView<K, V>> {
-  using Element = V;
-  using ConstIterator = typename std::map<K, V>::const_iterator;
-
-  static bool IsNull(const MapValuesArrayView<K, V>& input) {
-    // std::map<> is always converted to non-null mojom array.
-    return false;
-  }
-
-  static size_t GetSize(const MapValuesArrayView<K, V>& input) {
-    return input.map.size();
-  }
-  static ConstIterator GetBegin(const MapValuesArrayView<K, V>& input) {
-    return input.map.begin();
-  }
-  static void AdvanceIterator(ConstIterator& iterator) { ++iterator; }
-  static const V& GetValue(ConstIterator& iterator) { return iterator->second; }
-};
-
 }  // namespace mojo
 
 #endif  // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STL_H_
diff --git a/mojo/public/cpp/bindings/array_traits_wtf.h b/mojo/public/cpp/bindings/array_traits_wtf.h
new file mode 100644
index 0000000..7e773fc
--- /dev/null
+++ b/mojo/public/cpp/bindings/array_traits_wtf.h
@@ -0,0 +1,40 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_WTF_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_WTF_H_
+
+#include "mojo/public/cpp/bindings/array_traits.h"
+#include "mojo/public/cpp/bindings/wtf_array.h"
+
+namespace mojo {
+
+template <typename U>
+struct ArrayTraits<WTFArray<U>> {
+  using Element = U;
+
+  static bool IsNull(const WTFArray<U>& input) { return input.is_null(); }
+  static void SetToNull(WTFArray<U>* output) { *output = nullptr; }
+
+  static size_t GetSize(const WTFArray<U>& input) { return input.size(); }
+
+  static U* GetData(WTFArray<U>& input) { return &input.front(); }
+
+  static const U* GetData(const WTFArray<U>& input) { return &input.front(); }
+
+  static U& GetAt(WTFArray<U>& input, size_t index) { return input[index]; }
+
+  static const U& GetAt(const WTFArray<U>& input, size_t index) {
+    return input[index];
+  }
+
+  static bool Resize(WTFArray<U>& input, size_t size) {
+    input.resize(size);
+    return true;
+  }
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_WTF_H_
diff --git a/mojo/public/cpp/bindings/associated_binding.h b/mojo/public/cpp/bindings/associated_binding.h
index 5941166..1da5009 100644
--- a/mojo/public/cpp/bindings/associated_binding.h
+++ b/mojo/public/cpp/bindings/associated_binding.h
@@ -6,78 +6,23 @@
 #define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_BINDING_H_
 
 #include <memory>
-#include <string>
 #include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
+#include "mojo/public/cpp/bindings/associated_group.h"
+#include "mojo/public/cpp/bindings/associated_group_controller.h"
 #include "mojo/public/cpp/bindings/associated_interface_request.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
-#include "mojo/public/cpp/bindings/connection_error_callback.h"
 #include "mojo/public/cpp/bindings/interface_endpoint_client.h"
-#include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h"
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 
 namespace mojo {
 
-class MessageReceiver;
-
-// Base class used to factor out code in AssociatedBinding<T> expansions, in
-// particular for Bind().
-class MOJO_CPP_BINDINGS_EXPORT AssociatedBindingBase {
- public:
-  AssociatedBindingBase();
-  ~AssociatedBindingBase();
-
-  // Adds a message filter to be notified of each incoming message before
-  // dispatch. If a filter returns |false| from Accept(), the message is not
-  // dispatched and the pipe is closed. Filters cannot be removed.
-  void AddFilter(std::unique_ptr<MessageReceiver> filter);
-
-  // Closes the associated interface. Puts this object into a state where it can
-  // be rebound.
-  void Close();
-
-  // Similar to the method above, but also specifies a disconnect reason.
-  void CloseWithReason(uint32_t custom_reason, const std::string& description);
-
-  // Sets an error handler that will be called if a connection error occurs.
-  //
-  // This method may only be called after this AssociatedBinding has been bound
-  // to a message pipe. The error handler will be reset when this
-  // AssociatedBinding is unbound or closed.
-  void set_connection_error_handler(const base::Closure& error_handler);
-
-  void set_connection_error_with_reason_handler(
-      const ConnectionErrorWithReasonCallback& error_handler);
-
-  // Indicates whether the associated binding has been completed.
-  bool is_bound() const { return !!endpoint_client_; }
-
-  // Sends a message on the underlying message pipe and runs the current
-  // message loop until its response is received. This can be used in tests to
-  // verify that no message was sent on a message pipe in response to some
-  // stimulus.
-  void FlushForTesting();
-
- protected:
-  void BindImpl(ScopedInterfaceEndpointHandle handle,
-                MessageReceiverWithResponderStatus* receiver,
-                std::unique_ptr<MessageReceiver> payload_validator,
-                bool expect_sync_requests,
-                scoped_refptr<base::SingleThreadTaskRunner> runner,
-                uint32_t interface_version);
-
-  std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
-};
-
 // Represents the implementation side of an associated interface. It is similar
 // to Binding, except that it doesn't own a message pipe handle.
 //
@@ -88,48 +33,53 @@
 // single thread for the purposes of task scheduling. Please note that incoming
 // synchrounous method calls may not be run from this task runner, when they
 // reenter outgoing synchrounous calls on the same thread.
-template <typename Interface,
-          typename ImplRefTraits = RawPtrImplRefTraits<Interface>>
-class AssociatedBinding : public AssociatedBindingBase {
+template <typename Interface>
+class AssociatedBinding {
  public:
-  using ImplPointerType = typename ImplRefTraits::PointerType;
-
   // Constructs an incomplete associated binding that will use the
   // implementation |impl|. It may be completed with a subsequent call to the
   // |Bind| method. Does not take ownership of |impl|, which must outlive this
   // object.
-  explicit AssociatedBinding(ImplPointerType impl) { stub_.set_sink(impl); }
+  explicit AssociatedBinding(Interface* impl) : impl_(impl) {
+    stub_.set_sink(impl_);
+  }
 
   // Constructs a completed associated binding of |impl|. The output |ptr_info|
-  // should be sent by another interface. |impl| must outlive this object.
-  AssociatedBinding(ImplPointerType impl,
+  // should be passed through the message pipe endpoint referred to by
+  // |associated_group| to setup the corresponding asssociated interface
+  // pointer. |impl| must outlive this object.
+  AssociatedBinding(Interface* impl,
                     AssociatedInterfacePtrInfo<Interface>* ptr_info,
+                    AssociatedGroup* associated_group,
                     scoped_refptr<base::SingleThreadTaskRunner> runner =
                         base::ThreadTaskRunnerHandle::Get())
-      : AssociatedBinding(std::move(impl)) {
-    Bind(ptr_info, std::move(runner));
+      : AssociatedBinding(impl) {
+    Bind(ptr_info, associated_group, std::move(runner));
   }
 
   // Constructs a completed associated binding of |impl|. |impl| must outlive
   // the binding.
-  AssociatedBinding(ImplPointerType impl,
+  AssociatedBinding(Interface* impl,
                     AssociatedInterfaceRequest<Interface> request,
                     scoped_refptr<base::SingleThreadTaskRunner> runner =
                         base::ThreadTaskRunnerHandle::Get())
-      : AssociatedBinding(std::move(impl)) {
+      : AssociatedBinding(impl) {
     Bind(std::move(request), std::move(runner));
   }
 
   ~AssociatedBinding() {}
 
   // Creates an associated inteface and sets up this object as the
-  // implementation side. The output |ptr_info| should be sent by another
-  // interface.
+  // implementation side. The output |ptr_info| should be passed through the
+  // message pipe endpoint referred to by |associated_group| to setup the
+  // corresponding asssociated interface pointer.
   void Bind(AssociatedInterfacePtrInfo<Interface>* ptr_info,
+            AssociatedGroup* associated_group,
             scoped_refptr<base::SingleThreadTaskRunner> runner =
                 base::ThreadTaskRunnerHandle::Get()) {
-    auto request = MakeRequest(ptr_info);
-    ptr_info->set_version(Interface::Version_);
+    AssociatedInterfaceRequest<Interface> request;
+    associated_group->CreateAssociatedInterface(AssociatedGroup::WILL_PASS_PTR,
+                                                ptr_info, &request);
     Bind(std::move(request), std::move(runner));
   }
 
@@ -137,10 +87,35 @@
   void Bind(AssociatedInterfaceRequest<Interface> request,
             scoped_refptr<base::SingleThreadTaskRunner> runner =
                 base::ThreadTaskRunnerHandle::Get()) {
-    BindImpl(request.PassHandle(), &stub_,
-             base::WrapUnique(new typename Interface::RequestValidator_()),
-             Interface::HasSyncMethods_, std::move(runner),
-             Interface::Version_);
+    ScopedInterfaceEndpointHandle handle = request.PassHandle();
+
+    DCHECK(handle.is_local())
+        << "The AssociatedInterfaceRequest is supposed to be used at the "
+        << "other side of the message pipe.";
+
+    if (!handle.is_valid() || !handle.is_local()) {
+      endpoint_client_.reset();
+      return;
+    }
+
+    endpoint_client_.reset(new InterfaceEndpointClient(
+        std::move(handle), &stub_,
+        base::WrapUnique(new typename Interface::RequestValidator_()),
+        Interface::HasSyncMethods_, std::move(runner)));
+    endpoint_client_->set_connection_error_handler(
+        base::Bind(&AssociatedBinding::RunConnectionErrorHandler,
+                   base::Unretained(this)));
+
+    stub_.serialization_context()->group_controller =
+        endpoint_client_->group_controller();
+  }
+
+  // Closes the associated interface. Puts this object into a state where it can
+  // be rebound.
+  void Close() {
+    DCHECK(endpoint_client_);
+    endpoint_client_.reset();
+    connection_error_handler_.Reset();
   }
 
   // Unbinds and returns the associated interface request so it can be
@@ -153,15 +128,44 @@
     request.Bind(endpoint_client_->PassHandle());
 
     endpoint_client_.reset();
+    connection_error_handler_.Reset();
 
     return request;
   }
 
+  // Sets an error handler that will be called if a connection error occurs.
+  //
+  // This method may only be called after this AssociatedBinding has been bound
+  // to a message pipe. The error handler will be reset when this
+  // AssociatedBinding is unbound or closed.
+  void set_connection_error_handler(const base::Closure& error_handler) {
+    DCHECK(is_bound());
+    connection_error_handler_ = error_handler;
+  }
+
   // Returns the interface implementation that was previously specified.
-  Interface* impl() { return ImplRefTraits::GetRawPointer(&stub_.sink()); }
+  Interface* impl() { return impl_; }
+
+  // Indicates whether the associated binding has been completed.
+  bool is_bound() const { return !!endpoint_client_; }
+
+  // Returns the associated group that this object belongs to. Returns null if
+  // the object is not bound.
+  AssociatedGroup* associated_group() {
+    return endpoint_client_ ? endpoint_client_->associated_group() : nullptr;
+  }
 
  private:
-  typename Interface::template Stub_<ImplRefTraits> stub_;
+  void RunConnectionErrorHandler() {
+    if (!connection_error_handler_.is_null())
+      connection_error_handler_.Run();
+  }
+
+  std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
+
+  typename Interface::Stub_ stub_;
+  Interface* impl_;
+  base::Closure connection_error_handler_;
 
   DISALLOW_COPY_AND_ASSIGN(AssociatedBinding);
 };
diff --git a/mojo/public/cpp/bindings/associated_group.h b/mojo/public/cpp/bindings/associated_group.h
index 14e78ec..836c0d6 100644
--- a/mojo/public/cpp/bindings/associated_group.h
+++ b/mojo/public/cpp/bindings/associated_group.h
@@ -5,9 +5,11 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_GROUP_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_GROUP_H_
 
-#include "base/callback.h"
+#include <utility>
+
 #include "base/memory/ref_counted.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
+#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
+#include "mojo/public/cpp/bindings/associated_interface_request.h"
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 
 namespace mojo {
@@ -15,34 +17,71 @@
 class AssociatedGroupController;
 
 // AssociatedGroup refers to all the interface endpoints running at one end of a
-// message pipe.
+// message pipe. It is used to create associated interfaces for that message
+// pipe.
 // It is thread safe and cheap to make copies.
-class MOJO_CPP_BINDINGS_EXPORT AssociatedGroup {
+class AssociatedGroup {
  public:
+  // Configuration used by CreateAssociatedInterface(). Please see the comments
+  // of that method for more details.
+  enum AssociatedInterfaceConfig { WILL_PASS_PTR, WILL_PASS_REQUEST };
+
   AssociatedGroup();
-
-  explicit AssociatedGroup(scoped_refptr<AssociatedGroupController> controller);
-
-  explicit AssociatedGroup(const ScopedInterfaceEndpointHandle& handle);
-
   AssociatedGroup(const AssociatedGroup& other);
 
   ~AssociatedGroup();
 
   AssociatedGroup& operator=(const AssociatedGroup& other);
 
-  // The return value of this getter if this object is initialized with a
-  // ScopedInterfaceEndpointHandle:
-  //   - If the handle is invalid, the return value will always be null.
-  //   - If the handle is valid and non-pending, the return value will be
-  //     non-null and remain unchanged even if the handle is later reset.
-  //   - If the handle is pending asssociation, the return value will initially
-  //     be null, change to non-null when/if the handle is associated, and
-  //     remain unchanged ever since.
-  AssociatedGroupController* GetController();
+  // |config| indicates whether |ptr_info| or |request| will be sent to the
+  // remote side of the message pipe.
+  //
+  // NOTE: If |config| is |WILL_PASS_REQUEST|, you will want to bind |ptr_info|
+  // to a local AssociatedInterfacePtr to make calls. However, there is one
+  // restriction: the pointer should NOT be used to make calls before |request|
+  // is sent. Violating that will cause the message pipe to be closed. On the
+  // other hand, as soon as |request| is sent, the pointer is usable. There is
+  // no need to wait until |request| is bound to an implementation at the remote
+  // side.
+  template <typename T>
+  void CreateAssociatedInterface(
+      AssociatedInterfaceConfig config,
+      AssociatedInterfacePtrInfo<T>* ptr_info,
+      AssociatedInterfaceRequest<T>* request) {
+    ScopedInterfaceEndpointHandle local;
+    ScopedInterfaceEndpointHandle remote;
+    CreateEndpointHandlePair(&local, &remote);
+
+    if (!local.is_valid() || !remote.is_valid()) {
+      *ptr_info = AssociatedInterfacePtrInfo<T>();
+      *request = AssociatedInterfaceRequest<T>();
+      return;
+    }
+
+    if (config == WILL_PASS_PTR) {
+      ptr_info->set_handle(std::move(remote));
+
+      // The implementation is local, therefore set the version according to
+      // the interface definition that this code is built against.
+      ptr_info->set_version(T::Version_);
+      request->Bind(std::move(local));
+    } else {
+      ptr_info->set_handle(std::move(local));
+
+      // The implementation is remote, we don't know about its actual version
+      // yet.
+      ptr_info->set_version(0u);
+      request->Bind(std::move(remote));
+    }
+  }
 
  private:
-  base::Callback<AssociatedGroupController*()> controller_getter_;
+  friend class AssociatedGroupController;
+
+  void CreateEndpointHandlePair(
+      ScopedInterfaceEndpointHandle* local_endpoint,
+      ScopedInterfaceEndpointHandle* remote_endpoint);
+
   scoped_refptr<AssociatedGroupController> controller_;
 };
 
diff --git a/mojo/public/cpp/bindings/associated_group_controller.h b/mojo/public/cpp/bindings/associated_group_controller.h
index d33c277..0ab8253 100644
--- a/mojo/public/cpp/bindings/associated_group_controller.h
+++ b/mojo/public/cpp/bindings/associated_group_controller.h
@@ -9,47 +9,41 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/optional.h"
+#include "base/memory/ref_counted_delete_on_message_loop.h"
 #include "base/single_thread_task_runner.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
-#include "mojo/public/cpp/bindings/disconnect_reason.h"
 #include "mojo/public/cpp/bindings/interface_id.h"
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 
 namespace mojo {
 
+class AssociatedGroup;
 class InterfaceEndpointClient;
 class InterfaceEndpointController;
 
-// An internal interface used to manage endpoints within an associated group,
-// which corresponds to one end of a message pipe.
-class MOJO_CPP_BINDINGS_EXPORT AssociatedGroupController
-    : public base::RefCountedThreadSafe<AssociatedGroupController> {
+// An internal interface used to manage endpoints within an associated group.
+class AssociatedGroupController :
+    public base::RefCountedDeleteOnMessageLoop<AssociatedGroupController> {
  public:
-  // Associates an interface with this AssociatedGroupController's message pipe.
-  // It takes ownership of |handle_to_send| and returns an interface ID that
-  // could be sent by any endpoints within the same associated group.
-  // If |handle_to_send| is not in pending association state, it returns
-  // kInvalidInterfaceId. Otherwise, the peer handle of |handle_to_send| joins
-  // the associated group and is no longer pending.
-  virtual InterfaceId AssociateInterface(
-      ScopedInterfaceEndpointHandle handle_to_send) = 0;
+  explicit AssociatedGroupController(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+  // Creates a pair of interface endpoint handles. The method generates a new
+  // interface ID and assigns it to the two handles. |local_endpoint| is used
+  // locally; while |remote_endpoint| is sent over the message pipe.
+  virtual void CreateEndpointHandlePair(
+      ScopedInterfaceEndpointHandle* local_endpoint,
+      ScopedInterfaceEndpointHandle* remote_endpoint) = 0;
 
   // Creates an interface endpoint handle from a given interface ID. The handle
-  // joins this associated group.
+  // is used locally.
   // Typically, this method is used to (1) create an endpoint handle for the
   // master interface; or (2) create an endpoint handle on receiving an
   // interface ID from the message pipe.
-  //
-  // On failure, the method returns an invalid handle. Usually that is because
-  // the ID has already been used to create a handle.
   virtual ScopedInterfaceEndpointHandle CreateLocalEndpointHandle(
       InterfaceId id) = 0;
 
   // Closes an interface endpoint handle.
-  virtual void CloseEndpointHandle(
-      InterfaceId id,
-      const base::Optional<DisconnectReason>& reason) = 0;
+  virtual void CloseEndpointHandle(InterfaceId id, bool is_local) = 0;
 
   // Attaches a client to the specified endpoint to send and receive messages.
   // The returned object is still owned by the controller. It must only be used
@@ -69,23 +63,21 @@
   // and notifies all interfaces running on this pipe.
   virtual void RaiseError() = 0;
 
+  std::unique_ptr<AssociatedGroup> CreateAssociatedGroup();
+
  protected:
-  friend class base::RefCountedThreadSafe<AssociatedGroupController>;
+  friend class base::RefCountedDeleteOnMessageLoop<AssociatedGroupController>;
+  friend class base::DeleteHelper<AssociatedGroupController>;
 
-  // Creates a new ScopedInterfaceEndpointHandle within this associated group.
+  // Creates a new ScopedInterfaceEndpointHandle associated with this
+  // controller.
   ScopedInterfaceEndpointHandle CreateScopedInterfaceEndpointHandle(
-      InterfaceId id);
-
-  // Notifies that the interface represented by |handle_to_send| and its peer
-  // has been associated with this AssociatedGroupController's message pipe, and
-  // |handle_to_send|'s peer has joined this associated group. (Note: it is the
-  // peer who has joined the associated group; |handle_to_send| will be sent to
-  // the remote side.)
-  // Returns false if |handle_to_send|'s peer has closed.
-  bool NotifyAssociation(ScopedInterfaceEndpointHandle* handle_to_send,
-                         InterfaceId id);
+      InterfaceId id,
+      bool is_local);
 
   virtual ~AssociatedGroupController();
+
+  DISALLOW_COPY_AND_ASSIGN(AssociatedGroupController);
 };
 
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/associated_interface_ptr.h b/mojo/public/cpp/bindings/associated_interface_ptr.h
index 8e66f4e..10494ce 100644
--- a/mojo/public/cpp/bindings/associated_interface_ptr.h
+++ b/mojo/public/cpp/bindings/associated_interface_ptr.h
@@ -6,8 +6,6 @@
 #define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
 
 #include <stdint.h>
-
-#include <string>
 #include <utility>
 
 #include "base/callback.h"
@@ -16,12 +14,10 @@
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "mojo/public/cpp/bindings/associated_group.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
 #include "mojo/public/cpp/bindings/associated_interface_request.h"
-#include "mojo/public/cpp/bindings/connection_error_callback.h"
 #include "mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h"
-#include "mojo/public/cpp/bindings/lib/multiplex_router.h"
-#include "mojo/public/cpp/system/message_pipe.h"
 
 namespace mojo {
 
@@ -30,9 +26,6 @@
 template <typename Interface>
 class AssociatedInterfacePtr {
  public:
-  using InterfaceType = Interface;
-  using PtrInfoType = AssociatedInterfacePtrInfo<Interface>;
-
   // Constructs an unbound AssociatedInterfacePtr.
   AssociatedInterfacePtr() {}
   AssociatedInterfacePtr(decltype(nullptr)) {}
@@ -65,16 +58,20 @@
   // multiple task runners to a single thread for the purposes of task
   // scheduling.
   //
-  // NOTE: The corresponding AssociatedInterfaceRequest must be sent over
-  // another interface before using this object to make calls. Please see the
-  // comments of MakeRequest(AssociatedInterfacePtr<Interface>*) for more
-  // details.
+  // NOTE: Please see the comments of
+  // AssociatedGroup.CreateAssociatedInterface() about when you can use this
+  // object to make calls.
   void Bind(AssociatedInterfacePtrInfo<Interface> info,
             scoped_refptr<base::SingleThreadTaskRunner> runner =
                 base::ThreadTaskRunnerHandle::Get()) {
     reset();
 
-    if (info.is_valid())
+    bool is_local = info.handle().is_local();
+
+    DCHECK(is_local) << "The AssociatedInterfacePtrInfo is supposed to be used "
+                        "at the other side of the message pipe.";
+
+    if (info.is_valid() && is_local)
       internal_state_.Bind(std::move(info), std::move(runner));
   }
 
@@ -89,6 +86,9 @@
   // Returns the version number of the interface that the remote side supports.
   uint32_t version() const { return internal_state_.version(); }
 
+  // Returns the internal interface ID of this associated interface.
+  uint32_t interface_id() const { return internal_state_.interface_id(); }
+
   // Queries the max version that the remote side supports. On completion, the
   // result will be returned as the input of |callback|. The version number of
   // this object will also be updated.
@@ -107,12 +107,6 @@
     internal_state_.RequireVersion(version);
   }
 
-  // Sends a message on the underlying message pipe and runs the current
-  // message loop until its response is received. This can be used in tests to
-  // verify that no message was sent on a message pipe in response to some
-  // stimulus.
-  void FlushForTesting() { internal_state_.FlushForTesting(); }
-
   // Closes the associated interface (if any) and returns the pointer to the
   // unbound state.
   void reset() {
@@ -120,13 +114,6 @@
     internal_state_.Swap(&doomed);
   }
 
-  // Similar to the method above, but also specifies a disconnect reason.
-  void ResetWithReason(uint32_t custom_reason, const std::string& description) {
-    if (internal_state_.is_bound())
-      internal_state_.CloseWithReason(custom_reason, description);
-    reset();
-  }
-
   // Indicates whether an error has been encountered. If true, method calls made
   // on this interface will be dropped (and may already have been dropped).
   bool encountered_error() const { return internal_state_.encountered_error(); }
@@ -139,11 +126,6 @@
     internal_state_.set_connection_error_handler(error_handler);
   }
 
-  void set_connection_error_with_reason_handler(
-      const ConnectionErrorWithReasonCallback& error_handler) {
-    internal_state_.set_connection_error_with_reason_handler(error_handler);
-  }
-
   // Unbinds and returns the associated interface pointer information which
   // could be used to setup an AssociatedInterfacePtr again. This method may be
   // used to move the proxy to a different thread.
@@ -159,6 +141,12 @@
     return state.PassInterface();
   }
 
+  // Returns the associated group that this object belongs to. Returns null if
+  // the object is not bound.
+  AssociatedGroup* associated_group() {
+    return internal_state_.associated_group();
+  }
+
   // DO NOT USE. Exposed only for internal use and for testing.
   internal::AssociatedInterfacePtrState<Interface>* internal_state() {
     return &internal_state_;
@@ -191,95 +179,30 @@
   DISALLOW_COPY_AND_ASSIGN(AssociatedInterfacePtr);
 };
 
-// Creates an associated interface. The returned request is supposed to be sent
-// over another interface (either associated or non-associated).
+// Creates an associated interface. The output |ptr| should be used locally
+// while the returned request should be passed through the message pipe endpoint
+// referred to by |associated_group| to setup the corresponding asssociated
+// interface implementation at the remote side.
 //
-// NOTE: |ptr| must NOT be used to make calls before the request is sent.
-// Violating that will lead to crash. On the other hand, as soon as the request
-// is sent, |ptr| is usable. There is no need to wait until the request is bound
-// to an implementation at the remote side.
+// NOTE: |ptr| should NOT be used to make calls before the request is sent.
+// Violating that will cause the message pipe to be closed. On the other hand,
+// as soon as the request is sent, |ptr| is usable. There is no need to wait
+// until the request is bound to an implementation at the remote side.
 template <typename Interface>
-AssociatedInterfaceRequest<Interface> MakeRequest(
+AssociatedInterfaceRequest<Interface> GetProxy(
     AssociatedInterfacePtr<Interface>* ptr,
+    AssociatedGroup* group,
     scoped_refptr<base::SingleThreadTaskRunner> runner =
         base::ThreadTaskRunnerHandle::Get()) {
+  AssociatedInterfaceRequest<Interface> request;
   AssociatedInterfacePtrInfo<Interface> ptr_info;
-  auto request = MakeRequest(&ptr_info);
+  group->CreateAssociatedInterface(AssociatedGroup::WILL_PASS_REQUEST,
+                                   &ptr_info, &request);
+
   ptr->Bind(std::move(ptr_info), std::move(runner));
   return request;
 }
 
-// Creates an associated interface. One of the two endpoints is supposed to be
-// sent over another interface (either associated or non-associated); while the
-// other is used locally.
-//
-// NOTE: If |ptr_info| is used locally and bound to an AssociatedInterfacePtr,
-// the interface pointer must NOT be used to make calls before the request is
-// sent. Please see NOTE of the previous function for more details.
-template <typename Interface>
-AssociatedInterfaceRequest<Interface> MakeRequest(
-    AssociatedInterfacePtrInfo<Interface>* ptr_info) {
-  ScopedInterfaceEndpointHandle handle0;
-  ScopedInterfaceEndpointHandle handle1;
-  ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&handle0,
-                                                              &handle1);
-
-  ptr_info->set_handle(std::move(handle0));
-  ptr_info->set_version(0);
-
-  AssociatedInterfaceRequest<Interface> request;
-  request.Bind(std::move(handle1));
-  return request;
-}
-
-// Like |GetProxy|, but the interface is never associated with any other
-// interface. The returned request can be bound directly to the corresponding
-// associated interface implementation, without first passing it through a
-// message pipe endpoint.
-//
-// This function has two main uses:
-//
-//  * In testing, where the returned request is bound to e.g. a mock and there
-//    are no other interfaces involved.
-//
-//  * When discarding messages sent on an interface, which can be done by
-//    discarding the returned request.
-template <typename Interface>
-AssociatedInterfaceRequest<Interface> GetIsolatedProxy(
-    AssociatedInterfacePtr<Interface>* ptr) {
-  MessagePipe pipe;
-  scoped_refptr<internal::MultiplexRouter> router0 =
-      new internal::MultiplexRouter(std::move(pipe.handle0),
-                                    internal::MultiplexRouter::MULTI_INTERFACE,
-                                    false, base::ThreadTaskRunnerHandle::Get());
-  scoped_refptr<internal::MultiplexRouter> router1 =
-      new internal::MultiplexRouter(std::move(pipe.handle1),
-                                    internal::MultiplexRouter::MULTI_INTERFACE,
-                                    true, base::ThreadTaskRunnerHandle::Get());
-
-  ScopedInterfaceEndpointHandle endpoint0, endpoint1;
-  ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&endpoint0,
-                                                              &endpoint1);
-  InterfaceId id = router1->AssociateInterface(std::move(endpoint0));
-  endpoint0 = router0->CreateLocalEndpointHandle(id);
-
-  ptr->Bind(AssociatedInterfacePtrInfo<Interface>(std::move(endpoint0),
-                                                  Interface::Version_));
-
-  AssociatedInterfaceRequest<Interface> request;
-  request.Bind(std::move(endpoint1));
-  return request;
-}
-
-// Creates an associated interface proxy in its own AssociatedGroup.
-// TODO(yzshen): Rename GetIsolatedProxy() to MakeIsolatedRequest(), and change
-// all callsites of this function to directly use that.
-template <typename Interface>
-AssociatedInterfaceRequest<Interface> MakeRequestForTesting(
-    AssociatedInterfacePtr<Interface>* ptr) {
-  return GetIsolatedProxy(ptr);
-}
-
 }  // namespace mojo
 
 #endif  // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
diff --git a/mojo/public/cpp/bindings/associated_interface_ptr_info.h b/mojo/public/cpp/bindings/associated_interface_ptr_info.h
index 3c6ca54..bfb3297 100644
--- a/mojo/public/cpp/bindings/associated_interface_ptr_info.h
+++ b/mojo/public/cpp/bindings/associated_interface_ptr_info.h
@@ -20,7 +20,6 @@
 class AssociatedInterfacePtrInfo {
  public:
   AssociatedInterfacePtrInfo() : version_(0u) {}
-  AssociatedInterfacePtrInfo(std::nullptr_t) : version_(0u) {}
 
   AssociatedInterfacePtrInfo(AssociatedInterfacePtrInfo&& other)
       : handle_(std::move(other.handle_)), version_(other.version_) {
diff --git a/mojo/public/cpp/bindings/associated_interface_request.h b/mojo/public/cpp/bindings/associated_interface_request.h
index c37636c..30fcd16 100644
--- a/mojo/public/cpp/bindings/associated_interface_request.h
+++ b/mojo/public/cpp/bindings/associated_interface_request.h
@@ -5,7 +5,6 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_REQUEST_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_REQUEST_H_
 
-#include <string>
 #include <utility>
 
 #include "base/macros.h"
@@ -65,10 +64,6 @@
     return !is_pending() && !other.is_pending();
   }
 
-  void ResetWithReason(uint32_t custom_reason, const std::string& description) {
-    handle_.ResetWithReason(custom_reason, description);
-  }
-
  private:
   ScopedInterfaceEndpointHandle handle_;
 
diff --git a/mojo/public/cpp/bindings/binding.h b/mojo/public/cpp/bindings/binding.h
index 1da331b..8c9ee2f 100644
--- a/mojo/public/cpp/bindings/binding.h
+++ b/mojo/public/cpp/bindings/binding.h
@@ -5,7 +5,6 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_BINDING_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_BINDING_H_
 
-#include <string>
 #include <utility>
 
 #include "base/callback_forward.h"
@@ -13,17 +12,15 @@
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "mojo/public/cpp/bindings/connection_error_callback.h"
 #include "mojo/public/cpp/bindings/interface_ptr.h"
 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "mojo/public/cpp/bindings/lib/binding_state.h"
-#include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h"
 #include "mojo/public/cpp/system/core.h"
 
 namespace mojo {
 
-class MessageReceiver;
+class AssociatedGroup;
 
 // Represents the binding of an interface implementation to a message pipe.
 // When the |Binding| object is destroyed, the binding between the message pipe
@@ -66,24 +63,21 @@
 // single thread for the purposes of task scheduling. Please note that incoming
 // synchrounous method calls may not be run from this task runner, when they
 // reenter outgoing synchrounous calls on the same thread.
-template <typename Interface,
-          typename ImplRefTraits = RawPtrImplRefTraits<Interface>>
+template <typename Interface>
 class Binding {
  public:
-  using ImplPointerType = typename ImplRefTraits::PointerType;
-
   // Constructs an incomplete binding that will use the implementation |impl|.
   // The binding may be completed with a subsequent call to the |Bind| method.
   // Does not take ownership of |impl|, which must outlive the binding.
-  explicit Binding(ImplPointerType impl) : internal_state_(std::move(impl)) {}
+  explicit Binding(Interface* impl) : internal_state_(impl) {}
 
   // Constructs a completed binding of message pipe |handle| to implementation
   // |impl|. Does not take ownership of |impl|, which must outlive the binding.
-  Binding(ImplPointerType impl,
+  Binding(Interface* impl,
           ScopedMessagePipeHandle handle,
           scoped_refptr<base::SingleThreadTaskRunner> runner =
               base::ThreadTaskRunnerHandle::Get())
-      : Binding(std::move(impl)) {
+      : Binding(impl) {
     Bind(std::move(handle), std::move(runner));
   }
 
@@ -92,22 +86,22 @@
   // pass |ptr| on to the client of the service. Does not take ownership of any
   // of the parameters. |impl| must outlive the binding. |ptr| only needs to
   // last until the constructor returns.
-  Binding(ImplPointerType impl,
+  Binding(Interface* impl,
           InterfacePtr<Interface>* ptr,
           scoped_refptr<base::SingleThreadTaskRunner> runner =
               base::ThreadTaskRunnerHandle::Get())
-      : Binding(std::move(impl)) {
+      : Binding(impl) {
     Bind(ptr, std::move(runner));
   }
 
   // Constructs a completed binding of |impl| to the message pipe endpoint in
   // |request|, taking ownership of the endpoint. Does not take ownership of
   // |impl|, which must outlive the binding.
-  Binding(ImplPointerType impl,
+  Binding(Interface* impl,
           InterfaceRequest<Interface> request,
           scoped_refptr<base::SingleThreadTaskRunner> runner =
               base::ThreadTaskRunnerHandle::Get())
-      : Binding(std::move(impl)) {
+      : Binding(impl) {
     Bind(request.PassMessagePipe(), std::move(runner));
   }
 
@@ -158,14 +152,6 @@
     Bind(request.PassMessagePipe(), std::move(runner));
   }
 
-  // Adds a message filter to be notified of each incoming message before
-  // dispatch. If a filter returns |false| from Accept(), the message is not
-  // dispatched and the pipe is closed. Filters cannot be removed.
-  void AddFilter(std::unique_ptr<MessageReceiver> filter) {
-    DCHECK(is_bound());
-    internal_state_.AddFilter(std::move(filter));
-  }
-
   // Whether there are any associated interfaces running on the pipe currently.
   bool HasAssociatedInterfaces() const {
     return internal_state_.HasAssociatedInterfaces();
@@ -203,11 +189,6 @@
   // state where it can be rebound to a new pipe.
   void Close() { internal_state_.Close(); }
 
-  // Similar to the method above, but also specifies a disconnect reason.
-  void CloseWithReason(uint32_t custom_reason, const std::string& description) {
-    internal_state_.CloseWithReason(custom_reason, description);
-  }
-
   // Unbinds the underlying pipe from this binding and returns it so it can be
   // used in another context, such as on another thread or with a different
   // implementation. Put this object into a state where it can be rebound to a
@@ -236,12 +217,6 @@
     internal_state_.set_connection_error_handler(error_handler);
   }
 
-  void set_connection_error_with_reason_handler(
-      const ConnectionErrorWithReasonCallback& error_handler) {
-    DCHECK(is_bound());
-    internal_state_.set_connection_error_with_reason_handler(error_handler);
-  }
-
   // Returns the interface implementation that was previously specified. Caller
   // does not take ownership.
   Interface* impl() { return internal_state_.impl(); }
@@ -256,17 +231,20 @@
   // transferred to the caller.
   MessagePipeHandle handle() const { return internal_state_.handle(); }
 
-  // Sends a no-op message on the underlying message pipe and runs the current
-  // message loop until its response is received. This can be used in tests to
-  // verify that no message was sent on a message pipe in response to some
-  // stimulus.
-  void FlushForTesting() { internal_state_.FlushForTesting(); }
+  // Returns the associated group that this object belongs to. Returns null if:
+  //   - this object is not bound; or
+  //   - the interface doesn't have methods to pass associated interface
+  //     pointers or requests.
+  AssociatedGroup* associated_group() {
+    return internal_state_.associated_group();
+  }
 
   // Exposed for testing, should not generally be used.
   void EnableTestingMode() { internal_state_.EnableTestingMode(); }
 
  private:
-  internal::BindingState<Interface, ImplRefTraits> internal_state_;
+  internal::BindingState<Interface, Interface::PassesAssociatedKinds_>
+      internal_state_;
 
   DISALLOW_COPY_AND_ASSIGN(Binding);
 };
diff --git a/mojo/public/cpp/bindings/binding_set.h b/mojo/public/cpp/bindings/binding_set.h
index 919f9c0..b1baca6 100644
--- a/mojo/public/cpp/bindings/binding_set.h
+++ b/mojo/public/cpp/bindings/binding_set.h
@@ -5,263 +5,111 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_
 
-#include <string>
+#include <algorithm>
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/macros.h"
-#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
 #include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/bindings/connection_error_callback.h"
-#include "mojo/public/cpp/bindings/interface_ptr.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/bindings/message.h"
 
 namespace mojo {
 
-template <typename BindingType>
-struct BindingSetTraits;
-
-template <typename Interface, typename ImplRefTraits>
-struct BindingSetTraits<Binding<Interface, ImplRefTraits>> {
-  using ProxyType = InterfacePtr<Interface>;
-  using RequestType = InterfaceRequest<Interface>;
-  using BindingType = Binding<Interface, ImplRefTraits>;
-  using ImplPointerType = typename BindingType::ImplPointerType;
-
-  static RequestType MakeRequest(ProxyType* proxy) {
-    return mojo::MakeRequest(proxy);
-  }
-};
-
-using BindingId = size_t;
-
-template <typename ContextType>
-struct BindingSetContextTraits {
-  using Type = ContextType;
-
-  static constexpr bool SupportsContext() { return true; }
-};
-
-template <>
-struct BindingSetContextTraits<void> {
-  // NOTE: This choice of Type only matters insofar as it affects the size of
-  // the |context_| field of a BindingSetBase::Entry with void context. The
-  // context value is never used in this case.
-  using Type = bool;
-
-  static constexpr bool SupportsContext() { return false; }
-};
-
-// Generic definition used for BindingSet and AssociatedBindingSet to own a
-// collection of bindings which point to the same implementation.
-//
-// If |ContextType| is non-void, then every added binding must include a context
-// value of that type, and |dispatch_context()| will return that value during
-// the extent of any message dispatch targeting that specific binding.
-template <typename Interface, typename BindingType, typename ContextType>
-class BindingSetBase {
+// Use this class to manage a set of bindings, which are automatically destroyed
+// and removed from the set when the pipe they are bound to is disconnected.
+template <typename Interface>
+class BindingSet {
  public:
-  using ContextTraits = BindingSetContextTraits<ContextType>;
-  using Context = typename ContextTraits::Type;
-  using PreDispatchCallback = base::Callback<void(const Context&)>;
-  using Traits = BindingSetTraits<BindingType>;
-  using ProxyType = typename Traits::ProxyType;
-  using RequestType = typename Traits::RequestType;
-  using ImplPointerType = typename Traits::ImplPointerType;
-
-  BindingSetBase() {}
+  BindingSet() {}
+  ~BindingSet() { CloseAllBindings(); }
 
   void set_connection_error_handler(const base::Closure& error_handler) {
     error_handler_ = error_handler;
-    error_with_reason_handler_.Reset();
   }
 
-  void set_connection_error_with_reason_handler(
-      const ConnectionErrorWithReasonCallback& error_handler) {
-    error_with_reason_handler_ = error_handler;
-    error_handler_.Reset();
+  void AddBinding(Interface* impl, InterfaceRequest<Interface> request) {
+    auto binding = new Element(impl, std::move(request));
+    binding->set_connection_error_handler(
+        base::Bind(&BindingSet::OnConnectionError, base::Unretained(this)));
+    bindings_.push_back(binding->GetWeakPtr());
   }
 
-  // Sets a callback to be invoked immediately before dispatching any message or
-  // error received by any of the bindings in the set. This may only be used
-  // with a non-void |ContextType|.
-  void set_pre_dispatch_handler(const PreDispatchCallback& handler) {
-    static_assert(ContextTraits::SupportsContext(),
-                  "Pre-dispatch handler usage requires non-void context type.");
-    pre_dispatch_handler_ = handler;
+  // Returns an InterfacePtr bound to one end of a pipe whose other end is
+  // bound to |this|.
+  InterfacePtr<Interface> CreateInterfacePtrAndBind(Interface* impl) {
+    InterfacePtr<Interface> interface_ptr;
+    AddBinding(impl, GetProxy(&interface_ptr));
+    return interface_ptr;
   }
 
-  // Adds a new binding to the set which binds |request| to |impl| with no
-  // additional context.
-  BindingId AddBinding(ImplPointerType impl, RequestType request) {
-    static_assert(!ContextTraits::SupportsContext(),
-                  "Context value required for non-void context type.");
-    return AddBindingImpl(std::move(impl), std::move(request), false);
+  void CloseAllBindings() {
+    for (const auto& it : bindings_) {
+      if (it) {
+        it->Close();
+        delete it.get();
+      }
+    }
+    bindings_.clear();
   }
 
-  // Adds a new binding associated with |context|.
-  BindingId AddBinding(ImplPointerType impl,
-                       RequestType request,
-                       Context context) {
-    static_assert(ContextTraits::SupportsContext(),
-                  "Context value unsupported for void context type.");
-    return AddBindingImpl(std::move(impl), std::move(request),
-                          std::move(context));
-  }
-
-  // Removes a binding from the set. Note that this is safe to call even if the
-  // binding corresponding to |id| has already been removed.
-  //
-  // Returns |true| if the binding was removed and |false| if it didn't exist.
-  bool RemoveBinding(BindingId id) {
-    auto it = bindings_.find(id);
-    if (it == bindings_.end())
-      return false;
-    bindings_.erase(it);
-    return true;
-  }
-
-  // Returns a proxy bound to one end of a pipe whose other end is bound to
-  // |this|. If |id_storage| is not null, |*id_storage| will be set to the ID
-  // of the added binding.
-  ProxyType CreateInterfacePtrAndBind(ImplPointerType impl,
-                                      BindingId* id_storage = nullptr) {
-    ProxyType proxy;
-    BindingId id = AddBinding(std::move(impl), Traits::MakeRequest(&proxy));
-    if (id_storage)
-      *id_storage = id;
-    return proxy;
-  }
-
-  void CloseAllBindings() { bindings_.clear(); }
-
   bool empty() const { return bindings_.empty(); }
 
-  // Implementations may call this when processing a dispatched message or
-  // error. During the extent of message or error dispatch, this will return the
-  // context associated with the specific binding which received the message or
-  // error. Use AddBinding() to associated a context with a specific binding.
-  const Context& dispatch_context() const {
-    static_assert(ContextTraits::SupportsContext(),
-                  "dispatch_context() requires non-void context type.");
-    DCHECK(dispatch_context_);
-    return *dispatch_context_;
-  }
-
-  void FlushForTesting() {
-    for (auto& binding : bindings_)
-      binding.second->FlushForTesting();
-  }
-
  private:
-  friend class Entry;
-
-  class Entry {
+  class Element {
    public:
-    Entry(ImplPointerType impl,
-          RequestType request,
-          BindingSetBase* binding_set,
-          BindingId binding_id,
-          Context context)
-        : binding_(std::move(impl), std::move(request)),
-          binding_set_(binding_set),
-          binding_id_(binding_id),
-          context_(std::move(context)) {
-      if (ContextTraits::SupportsContext())
-        binding_.AddFilter(base::MakeUnique<DispatchFilter>(this));
-      binding_.set_connection_error_with_reason_handler(
-          base::Bind(&Entry::OnConnectionError, base::Unretained(this)));
+    Element(Interface* impl, InterfaceRequest<Interface> request)
+        : binding_(impl, std::move(request)), weak_ptr_factory_(this) {
+      binding_.set_connection_error_handler(
+          base::Bind(&Element::OnConnectionError, base::Unretained(this)));
     }
 
-    void FlushForTesting() { binding_.FlushForTesting(); }
+    ~Element() {}
+
+    void set_connection_error_handler(const base::Closure& error_handler) {
+      error_handler_ = error_handler;
+    }
+
+    base::WeakPtr<Element> GetWeakPtr() {
+      return weak_ptr_factory_.GetWeakPtr();
+    }
+
+    void Close() { binding_.Close(); }
+
+    void OnConnectionError() {
+      base::Closure error_handler = error_handler_;
+      delete this;
+      if (!error_handler.is_null())
+        error_handler.Run();
+    }
 
    private:
-    class DispatchFilter : public MessageReceiver {
-     public:
-      explicit DispatchFilter(Entry* entry) : entry_(entry) {}
-      ~DispatchFilter() override {}
+    Binding<Interface> binding_;
+    base::Closure error_handler_;
+    base::WeakPtrFactory<Element> weak_ptr_factory_;
 
-     private:
-      // MessageReceiver:
-      bool Accept(Message* message) override {
-        entry_->WillDispatch();
-        return true;
-      }
-
-      Entry* entry_;
-
-      DISALLOW_COPY_AND_ASSIGN(DispatchFilter);
-    };
-
-    void WillDispatch() {
-      DCHECK(ContextTraits::SupportsContext());
-      binding_set_->SetDispatchContext(&context_);
-    }
-
-    void OnConnectionError(uint32_t custom_reason,
-                           const std::string& description) {
-      if (ContextTraits::SupportsContext())
-        WillDispatch();
-      binding_set_->OnConnectionError(binding_id_, custom_reason, description);
-    }
-
-    BindingType binding_;
-    BindingSetBase* const binding_set_;
-    const BindingId binding_id_;
-    Context const context_;
-
-    DISALLOW_COPY_AND_ASSIGN(Entry);
+    DISALLOW_COPY_AND_ASSIGN(Element);
   };
 
-  void SetDispatchContext(const Context* context) {
-    DCHECK(ContextTraits::SupportsContext());
-    dispatch_context_ = context;
-    if (!pre_dispatch_handler_.is_null())
-      pre_dispatch_handler_.Run(*context);
-  }
-
-  BindingId AddBindingImpl(ImplPointerType impl,
-                           RequestType request,
-                           Context context) {
-    BindingId id = next_binding_id_++;
-    DCHECK_GE(next_binding_id_, 0u);
-    auto entry = base::MakeUnique<Entry>(std::move(impl), std::move(request),
-                                         this, id, std::move(context));
-    bindings_.insert(std::make_pair(id, std::move(entry)));
-    return id;
-  }
-
-  void OnConnectionError(BindingId id,
-                         uint32_t custom_reason,
-                         const std::string& description) {
-    auto it = bindings_.find(id);
-    DCHECK(it != bindings_.end());
-
-    // We keep the Entry alive throughout error dispatch.
-    std::unique_ptr<Entry> entry = std::move(it->second);
-    bindings_.erase(it);
+  void OnConnectionError() {
+    // Clear any deleted bindings.
+    bindings_.erase(std::remove_if(bindings_.begin(), bindings_.end(),
+                                   [](const base::WeakPtr<Element>& p) {
+                                     return p.get() == nullptr;
+                                   }),
+                    bindings_.end());
 
     if (!error_handler_.is_null())
       error_handler_.Run();
-    else if (!error_with_reason_handler_.is_null())
-      error_with_reason_handler_.Run(custom_reason, description);
   }
 
   base::Closure error_handler_;
-  ConnectionErrorWithReasonCallback error_with_reason_handler_;
-  PreDispatchCallback pre_dispatch_handler_;
-  BindingId next_binding_id_ = 0;
-  std::map<BindingId, std::unique_ptr<Entry>> bindings_;
-  const Context* dispatch_context_ = nullptr;
+  std::vector<base::WeakPtr<Element>> bindings_;
 
-  DISALLOW_COPY_AND_ASSIGN(BindingSetBase);
+  DISALLOW_COPY_AND_ASSIGN(BindingSet);
 };
 
-template <typename Interface, typename ContextType = void>
-using BindingSet = BindingSetBase<Interface, Binding<Interface>, ContextType>;
-
 }  // namespace mojo
 
 #endif  // MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_
diff --git a/mojo/public/cpp/bindings/bindings_export.h b/mojo/public/cpp/bindings/bindings_export.h
deleted file mode 100644
index 9fd7a27..0000000
--- a/mojo/public/cpp/bindings/bindings_export.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_BINDINGS_EXPORT_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_BINDINGS_EXPORT_H_
-
-#if defined(COMPONENT_BUILD)
-
-#if defined(WIN32)
-
-#if defined(MOJO_CPP_BINDINGS_IMPLEMENTATION)
-#define MOJO_CPP_BINDINGS_EXPORT __declspec(dllexport)
-#else
-#define MOJO_CPP_BINDINGS_EXPORT __declspec(dllimport)
-#endif
-
-#else  // !defined(WIN32)
-
-#if defined(MOJO_CPP_BINDINGS_IMPLEMENTATION)
-#define MOJO_CPP_BINDINGS_EXPORT __attribute((visibility("default")))
-#else
-#define MOJO_CPP_BINDINGS_EXPORT
-#endif
-
-#endif  // defined(WIN32)
-
-#else  // !defined(COMPONENT_BUILD)
-
-#define MOJO_CPP_BINDINGS_EXPORT
-
-#endif  // defined(COMPONENT_BUILD)
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_BINDINGS_EXPORT_H_
diff --git a/mojo/public/cpp/bindings/clone_traits.h b/mojo/public/cpp/bindings/clone_traits.h
deleted file mode 100644
index 203ab34..0000000
--- a/mojo/public/cpp/bindings/clone_traits.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2017 The Chromium 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_CLONE_TRAITS_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_CLONE_TRAITS_H_
-
-#include <type_traits>
-#include <unordered_map>
-#include <vector>
-
-#include "base/optional.h"
-#include "mojo/public/cpp/bindings/lib/template_util.h"
-
-namespace mojo {
-
-template <typename T>
-struct HasCloneMethod {
-  template <typename U>
-  static char Test(decltype(&U::Clone));
-  template <typename U>
-  static int Test(...);
-  static const bool value = sizeof(Test<T>(0)) == sizeof(char);
-
- private:
-  internal::EnsureTypeIsComplete<T> check_t_;
-};
-
-template <typename T, bool has_clone_method = HasCloneMethod<T>::value>
-struct CloneTraits;
-
-template <typename T>
-T Clone(const T& input);
-
-template <typename T>
-struct CloneTraits<T, true> {
-  static T Clone(const T& input) { return input.Clone(); }
-};
-
-template <typename T>
-struct CloneTraits<T, false> {
-  static T Clone(const T& input) { return input; }
-};
-
-template <typename T>
-struct CloneTraits<base::Optional<T>, false> {
-  static base::Optional<T> Clone(const base::Optional<T>& input) {
-    if (!input)
-      return base::nullopt;
-
-    return base::Optional<T>(mojo::Clone(*input));
-  }
-};
-
-template <typename T>
-struct CloneTraits<std::vector<T>, false> {
-  static std::vector<T> Clone(const std::vector<T>& input) {
-    std::vector<T> result;
-    result.reserve(input.size());
-    for (const auto& element : input)
-      result.push_back(mojo::Clone(element));
-
-    return result;
-  }
-};
-
-template <typename K, typename V>
-struct CloneTraits<std::unordered_map<K, V>, false> {
-  static std::unordered_map<K, V> Clone(const std::unordered_map<K, V>& input) {
-    std::unordered_map<K, V> result;
-    for (const auto& element : input) {
-      result.insert(std::make_pair(mojo::Clone(element.first),
-                                   mojo::Clone(element.second)));
-    }
-    return result;
-  }
-};
-
-template <typename T>
-T Clone(const T& input) {
-  return CloneTraits<T>::Clone(input);
-};
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_CLONE_TRAITS_H_
diff --git a/mojo/public/cpp/bindings/connection_error_callback.h b/mojo/public/cpp/bindings/connection_error_callback.h
deleted file mode 100644
index 306e99e..0000000
--- a/mojo/public/cpp/bindings/connection_error_callback.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_CONNECTION_ERROR_CALLBACK_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_CONNECTION_ERROR_CALLBACK_H_
-
-#include "base/callback.h"
-
-namespace mojo {
-
-// This callback type accepts user-defined disconnect reason and description. If
-// the other side specifies a reason on closing the connection, it will be
-// passed to the error handler.
-using ConnectionErrorWithReasonCallback =
-    base::Callback<void(uint32_t /* custom_reason */,
-                        const std::string& /* description */)>;
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_CONNECTION_ERROR_CALLBACK_H_
diff --git a/mojo/public/cpp/bindings/connector.h b/mojo/public/cpp/bindings/connector.h
index 01e9236..d14ad17 100644
--- a/mojo/public/cpp/bindings/connector.h
+++ b/mojo/public/cpp/bindings/connector.h
@@ -8,13 +8,10 @@
 #include <memory>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/optional.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_checker.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/message.h"
 #include "mojo/public/cpp/bindings/sync_handle_watcher.h"
 #include "mojo/public/cpp/system/core.h"
@@ -36,8 +33,7 @@
 //   - Sending messages can be configured to be thread safe (please see comments
 //     of the constructor). Other than that, the object should only be accessed
 //     on the creating thread.
-class MOJO_CPP_BINDINGS_EXPORT Connector
-    : NON_EXPORTED_BASE(public MessageReceiver) {
+class Connector : public MessageReceiver {
  public:
   enum ConnectorConfig {
     // Connector::Accept() is only called from a single thread.
@@ -142,7 +138,6 @@
 
   // Whether currently the control flow is inside the sync handle watcher
   // callback.
-  // It always returns false after CloseMessagePipe()/PassMessagePipe().
   bool during_sync_handle_watcher_callback() const {
     return sync_handle_watcher_callback_count_ > 0;
   }
@@ -151,10 +146,6 @@
     return task_runner_.get();
   }
 
-  // Sets the tag used by the heap profiler.
-  // |tag| must be a const string literal.
-  void SetWatcherHeapProfilerTag(const char* tag);
-
  private:
   // Callback of mojo::Watcher.
   void OnWatcherHandleReady(MojoResult result);
@@ -164,8 +155,7 @@
 
   void WaitToReadMore();
 
-  // Returns false if it is impossible to receive more messages in the future.
-  // |this| may have been destroyed in that case.
+  // Returns false if |this| was destroyed during message dispatch.
   WARN_UNUSED_RESULT bool ReadSingleMessage(MojoResult* read_result);
 
   // |this| can be destroyed during message dispatch.
@@ -185,40 +175,31 @@
   base::Closure connection_error_handler_;
 
   ScopedMessagePipeHandle message_pipe_;
-  MessageReceiver* incoming_receiver_ = nullptr;
+  MessageReceiver* incoming_receiver_;
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  std::unique_ptr<Watcher> handle_watcher_;
+  Watcher handle_watcher_;
 
-  bool error_ = false;
-  bool drop_writes_ = false;
-  bool enforce_errors_from_incoming_receiver_ = true;
+  bool error_;
+  bool drop_writes_;
+  bool enforce_errors_from_incoming_receiver_;
 
-  bool paused_ = false;
+  bool paused_;
 
   // If sending messages is allowed from multiple threads, |lock_| is used to
   // protect modifications to |message_pipe_| and |drop_writes_|.
-  base::Optional<base::Lock> lock_;
+  std::unique_ptr<base::Lock> lock_;
 
   std::unique_ptr<SyncHandleWatcher> sync_watcher_;
-  bool allow_woken_up_by_others_ = false;
+  bool allow_woken_up_by_others_;
   // If non-zero, currently the control flow is inside the sync handle watcher
   // callback.
-  size_t sync_handle_watcher_callback_count_ = 0;
+  size_t sync_handle_watcher_callback_count_;
 
   base::ThreadChecker thread_checker_;
 
-  base::Lock connected_lock_;
-  bool connected_ = true;
-
-  // The tag used to track heap allocations that originated from a Watcher
-  // notification.
-  const char* heap_profiler_tag_ = nullptr;
-
   // Create a single weak ptr and use it everywhere, to avoid the malloc/free
   // cost of creating a new weak ptr whenever it is needed.
-  // NOTE: This weak pointer is invalidated when the message pipe is closed or
-  // transferred (i.e., when |connected_| is set to false).
   base::WeakPtr<Connector> weak_self_;
   base::WeakPtrFactory<Connector> weak_factory_;
 
diff --git a/mojo/public/cpp/bindings/disconnect_reason.h b/mojo/public/cpp/bindings/disconnect_reason.h
deleted file mode 100644
index c04e8ad..0000000
--- a/mojo/public/cpp/bindings/disconnect_reason.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2017 The Chromium 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_DISCONNECT_REASON_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_DISCONNECT_REASON_H_
-
-#include <stdint.h>
-
-#include <string>
-
-namespace mojo {
-
-struct DisconnectReason {
- public:
-  DisconnectReason(uint32_t in_custom_reason, const std::string& in_description)
-      : custom_reason(in_custom_reason), description(in_description) {}
-
-  uint32_t custom_reason;
-  std::string description;
-};
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_DISCONNECT_REASON_H_
diff --git a/mojo/public/cpp/bindings/filter_chain.h b/mojo/public/cpp/bindings/filter_chain.h
deleted file mode 100644
index 1262f39..0000000
--- a/mojo/public/cpp/bindings/filter_chain.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// 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_FILTER_CHAIN_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_FILTER_CHAIN_H_
-
-#include <utility>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
-#include "mojo/public/cpp/bindings/message.h"
-
-namespace mojo {
-
-class MOJO_CPP_BINDINGS_EXPORT FilterChain
-    : NON_EXPORTED_BASE(public MessageReceiver) {
- public:
-  // Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while
-  // this object is alive.
-  explicit FilterChain(MessageReceiver* sink = nullptr);
-
-  FilterChain(FilterChain&& other);
-  FilterChain& operator=(FilterChain&& other);
-  ~FilterChain() override;
-
-  template <typename FilterType, typename... Args>
-  inline void Append(Args&&... args);
-
-  void Append(std::unique_ptr<MessageReceiver> filter);
-
-  // Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while
-  // this object is alive.
-  void SetSink(MessageReceiver* sink);
-
-  // MessageReceiver:
-  bool Accept(Message* message) override;
-
- private:
-  std::vector<std::unique_ptr<MessageReceiver>> filters_;
-
-  MessageReceiver* sink_;
-
-  DISALLOW_COPY_AND_ASSIGN(FilterChain);
-};
-
-template <typename FilterType, typename... Args>
-inline void FilterChain::Append(Args&&... args) {
-  Append(base::MakeUnique<FilterType>(std::forward<Args>(args)...));
-}
-
-template <>
-inline void FilterChain::Append<PassThroughFilter>() {
-}
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_FILTER_CHAIN_H_
diff --git a/mojo/public/cpp/bindings/interface_data_view.h b/mojo/public/cpp/bindings/interface_data_view.h
deleted file mode 100644
index ef12254..0000000
--- a/mojo/public/cpp/bindings/interface_data_view.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_DATA_VIEW_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_DATA_VIEW_H_
-
-namespace mojo {
-
-// They are used for type identification purpose only.
-template <typename Interface>
-class AssociatedInterfacePtrInfoDataView {};
-
-template <typename Interface>
-class AssociatedInterfaceRequestDataView {};
-
-template <typename Interface>
-class InterfacePtrDataView {};
-
-template <typename Interface>
-class InterfaceRequestDataView {};
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_DATA_VIEW_H_
diff --git a/mojo/public/cpp/bindings/interface_endpoint_client.h b/mojo/public/cpp/bindings/interface_endpoint_client.h
index 0aea756..9dc40a2 100644
--- a/mojo/public/cpp/bindings/interface_endpoint_client.h
+++ b/mojo/public/cpp/bindings/interface_endpoint_client.h
@@ -11,42 +11,34 @@
 #include <memory>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/optional.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_checker.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
-#include "mojo/public/cpp/bindings/connection_error_callback.h"
-#include "mojo/public/cpp/bindings/disconnect_reason.h"
-#include "mojo/public/cpp/bindings/filter_chain.h"
-#include "mojo/public/cpp/bindings/lib/control_message_handler.h"
-#include "mojo/public/cpp/bindings/lib/control_message_proxy.h"
 #include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/bindings/message_filter.h"
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 
 namespace mojo {
 
 class AssociatedGroup;
+class AssociatedGroupController;
 class InterfaceEndpointController;
 
 // InterfaceEndpointClient handles message sending and receiving of an interface
 // endpoint, either the implementation side or the client side.
 // It should only be accessed and destructed on the creating thread.
-class MOJO_CPP_BINDINGS_EXPORT InterfaceEndpointClient
-    : NON_EXPORTED_BASE(public MessageReceiverWithResponder) {
+class InterfaceEndpointClient : public MessageReceiverWithResponder {
  public:
   // |receiver| is okay to be null. If it is not null, it must outlive this
   // object.
   InterfaceEndpointClient(ScopedInterfaceEndpointHandle handle,
                           MessageReceiverWithResponderStatus* receiver,
-                          std::unique_ptr<MessageReceiver> payload_validator,
+                          std::unique_ptr<MessageFilter> payload_validator,
                           bool expect_sync_requests,
-                          scoped_refptr<base::SingleThreadTaskRunner> runner,
-                          uint32_t interface_version);
+                          scoped_refptr<base::SingleThreadTaskRunner> runner);
   ~InterfaceEndpointClient() override;
 
   // Sets the error handler to receive notifications when an error is
@@ -54,14 +46,6 @@
   void set_connection_error_handler(const base::Closure& error_handler) {
     DCHECK(thread_checker_.CalledOnValidThread());
     error_handler_ = error_handler;
-    error_with_reason_handler_.Reset();
-  }
-
-  void set_connection_error_with_reason_handler(
-      const ConnectionErrorWithReasonCallback& error_handler) {
-    DCHECK(thread_checker_.CalledOnValidThread());
-    error_with_reason_handler_ = error_handler;
-    error_handler_.Reset();
   }
 
   // Returns true if an error was encountered.
@@ -76,11 +60,11 @@
     return !async_responders_.empty() || !sync_responses_.empty();
   }
 
+  AssociatedGroupController* group_controller() const {
+    return handle_.group_controller();
+  }
   AssociatedGroup* associated_group();
-
-  // Adds a MessageReceiver which can filter a message after validation but
-  // before dispatch.
-  void AddFilter(std::unique_ptr<MessageReceiver> filter);
+  uint32_t interface_id() const;
 
   // After this call the object is in an invalid state and shouldn't be reused.
   ScopedInterfaceEndpointHandle PassHandle();
@@ -89,11 +73,7 @@
   // and notifies all interfaces running on this pipe.
   void RaiseError();
 
-  void CloseWithReason(uint32_t custom_reason, const std::string& description);
-
   // MessageReceiverWithResponder implementation:
-  // They must only be called when the handle is not in pending association
-  // state.
   bool Accept(Message* message) override;
   bool AcceptWithResponder(Message* message,
                            MessageReceiver* responder) override;
@@ -103,14 +83,7 @@
 
   // NOTE: |message| must have passed message header validation.
   bool HandleIncomingMessage(Message* message);
-  void NotifyError(const base::Optional<DisconnectReason>& reason);
-
-  // The following methods send interface control messages.
-  // They must only be called when the handle is not in pending association
-  // state.
-  void QueryVersion(const base::Callback<void(uint32_t)>& callback);
-  void RequireVersion(uint32_t version);
-  void FlushForTesting();
+  void NotifyError();
 
  private:
   // Maps from the id of a response to the MessageReceiver that handles the
@@ -123,7 +96,7 @@
     explicit SyncResponseInfo(bool* in_response_received);
     ~SyncResponseInfo();
 
-    Message response;
+    std::unique_ptr<Message> response;
 
     // Points to a stack-allocated variable.
     bool* response_received;
@@ -150,37 +123,26 @@
     DISALLOW_COPY_AND_ASSIGN(HandleIncomingMessageThunk);
   };
 
-  void InitControllerIfNecessary();
-
-  void OnAssociationEvent(
-      ScopedInterfaceEndpointHandle::AssociationEvent event);
-
   bool HandleValidatedMessage(Message* message);
 
-  const bool expect_sync_requests_ = false;
-
   ScopedInterfaceEndpointHandle handle_;
   std::unique_ptr<AssociatedGroup> associated_group_;
-  InterfaceEndpointController* controller_ = nullptr;
+  InterfaceEndpointController* controller_;
 
-  MessageReceiverWithResponderStatus* const incoming_receiver_ = nullptr;
+  MessageReceiverWithResponderStatus* const incoming_receiver_;
+  std::unique_ptr<MessageFilter> payload_validator_;
   HandleIncomingMessageThunk thunk_;
-  FilterChain filters_;
 
   AsyncResponderMap async_responders_;
   SyncResponseMap sync_responses_;
 
-  uint64_t next_request_id_ = 1;
+  uint64_t next_request_id_;
 
   base::Closure error_handler_;
-  ConnectionErrorWithReasonCallback error_with_reason_handler_;
-  bool encountered_error_ = false;
+  bool encountered_error_;
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
-  internal::ControlMessageProxy control_message_proxy_;
-  internal::ControlMessageHandler control_message_handler_;
-
   base::ThreadChecker thread_checker_;
 
   base::WeakPtrFactory<InterfaceEndpointClient> weak_ptr_factory_;
diff --git a/mojo/public/cpp/bindings/interface_ptr.h b/mojo/public/cpp/bindings/interface_ptr.h
index e88be74..edcb9bf 100644
--- a/mojo/public/cpp/bindings/interface_ptr.h
+++ b/mojo/public/cpp/bindings/interface_ptr.h
@@ -6,8 +6,6 @@
 #define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_
 
 #include <stdint.h>
-
-#include <string>
 #include <utility>
 
 #include "base/callback_forward.h"
@@ -16,12 +14,13 @@
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "mojo/public/cpp/bindings/connection_error_callback.h"
 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
 #include "mojo/public/cpp/bindings/lib/interface_ptr_state.h"
 
 namespace mojo {
 
+class AssociatedGroup;
+
 // A pointer to a local proxy of a remote Interface implementation. Uses a
 // message pipe to communicate with the remote implementation, and automatically
 // closes the pipe and deletes the proxy on destruction. The pointer must be
@@ -38,9 +37,6 @@
 template <typename Interface>
 class InterfacePtr {
  public:
-  using InterfaceType = Interface;
-  using PtrInfoType = InterfacePtrInfo<Interface>;
-
   // Constructs an unbound InterfacePtr.
   InterfacePtr() {}
   InterfacePtr(decltype(nullptr)) {}
@@ -118,12 +114,6 @@
     internal_state_.RequireVersion(version);
   }
 
-  // Sends a no-op message on the underlying message pipe and runs the current
-  // message loop until its response is received. This can be used in tests to
-  // verify that no message was sent on a message pipe in response to some
-  // stimulus.
-  void FlushForTesting() { internal_state_.FlushForTesting(); }
-
   // Closes the bound message pipe (if any) and returns the pointer to the
   // unbound state.
   void reset() {
@@ -131,13 +121,6 @@
     internal_state_.Swap(&doomed);
   }
 
-  // Similar to the method above, but also specifies a disconnect reason.
-  void ResetWithReason(uint32_t custom_reason, const std::string& description) {
-    if (internal_state_.is_bound())
-      internal_state_.CloseWithReason(custom_reason, description);
-    reset();
-  }
-
   // Whether there are any associated interfaces running on the pipe currently.
   bool HasAssociatedInterfaces() const {
     return internal_state_.HasAssociatedInterfaces();
@@ -157,11 +140,6 @@
     internal_state_.set_connection_error_handler(error_handler);
   }
 
-  void set_connection_error_with_reason_handler(
-      const ConnectionErrorWithReasonCallback& error_handler) {
-    internal_state_.set_connection_error_with_reason_handler(error_handler);
-  }
-
   // Unbinds the InterfacePtr and returns the information which could be used
   // to setup an InterfacePtr again. This method may be used to move the proxy
   // to a different thread (see class comments for details).
@@ -184,6 +162,14 @@
     return state.PassInterface();
   }
 
+  // Returns the associated group that this object belongs to. Returns null if:
+  //   - this object is not bound; or
+  //   - the interface doesn't have methods to pass associated interface
+  //     pointers or requests.
+  AssociatedGroup* associated_group() {
+    return internal_state_.associated_group();
+  }
+
   bool Equals(const InterfacePtr& other) const {
     if (this == &other)
       return true;
@@ -194,7 +180,8 @@
   }
 
   // DO NOT USE. Exposed only for internal use and for testing.
-  internal::InterfacePtrState<Interface>* internal_state() {
+  internal::InterfacePtrState<Interface, Interface::PassesAssociatedKinds_>*
+  internal_state() {
     return &internal_state_;
   }
 
@@ -202,7 +189,9 @@
   // implicitly convertible to a real bool (which is dangerous).
  private:
   // TODO(dcheng): Use an explicit conversion operator.
-  typedef internal::InterfacePtrState<Interface> InterfacePtr::*Testable;
+  typedef internal::InterfacePtrState<Interface,
+                                      Interface::PassesAssociatedKinds_>
+      InterfacePtr::*Testable;
 
  public:
   operator Testable() const {
@@ -218,7 +207,8 @@
   template <typename T>
   bool operator!=(const InterfacePtr<T>& other) const = delete;
 
-  typedef internal::InterfacePtrState<Interface> State;
+  typedef internal::InterfacePtrState<Interface,
+                                      Interface::PassesAssociatedKinds_> State;
   mutable State internal_state_;
 
   DISALLOW_COPY_AND_ASSIGN(InterfacePtr);
diff --git a/mojo/public/cpp/bindings/interface_ptr_set.h b/mojo/public/cpp/bindings/interface_ptr_set.h
index 09a2682..d4b2046 100644
--- a/mojo/public/cpp/bindings/interface_ptr_set.h
+++ b/mojo/public/cpp/bindings/interface_ptr_set.h
@@ -16,10 +16,6 @@
 namespace mojo {
 namespace internal {
 
-// TODO(blundell): This class should be rewritten to be structured
-// similarly to BindingSet if possible, with PtrSet owning its
-// Elements and those Elements calling back into PtrSet on connection
-// error.
 template <typename Interface, template <typename> class Ptr>
 class PtrSet {
  public:
@@ -59,13 +55,7 @@
 
     ~Element() {}
 
-    void Close() {
-      ptr_.reset();
-
-      // Resetting the interface ptr means that it won't call this object back
-      // on connection error anymore, so this object must delete itself now.
-      DeleteElement(this);
-    }
+    void Close() { ptr_.reset(); }
 
     Interface* get() { return ptr_.get(); }
 
diff --git a/mojo/public/cpp/bindings/interface_request.h b/mojo/public/cpp/bindings/interface_request.h
index 29d8836..fc23aec 100644
--- a/mojo/public/cpp/bindings/interface_request.h
+++ b/mojo/public/cpp/bindings/interface_request.h
@@ -5,17 +5,12 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_
 
-#include <string>
 #include <utility>
 
 #include "base/macros.h"
-#include "base/optional.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "mojo/public/cpp/bindings/disconnect_reason.h"
 #include "mojo/public/cpp/bindings/interface_ptr.h"
-#include "mojo/public/cpp/bindings/pipe_control_message_proxy.h"
-#include "mojo/public/cpp/system/message_pipe.h"
 
 namespace mojo {
 
@@ -33,19 +28,6 @@
   InterfaceRequest() {}
   InterfaceRequest(decltype(nullptr)) {}
 
-  // Creates a new message pipe over which Interface is to be served, binding
-  // the specified InterfacePtr to one end of the message pipe and this
-  // InterfaceRequest to the other. For example usage, see comments on
-  // MakeRequest(InterfacePtr*) below.
-  explicit InterfaceRequest(InterfacePtr<Interface>* ptr,
-                            scoped_refptr<base::SingleThreadTaskRunner> runner =
-                                base::ThreadTaskRunnerHandle::Get()) {
-    MessagePipe pipe;
-    ptr->Bind(InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u),
-              std::move(runner));
-    Bind(std::move(pipe.handle1));
-  }
-
   // Takes the message pipe from another InterfaceRequest.
   InterfaceRequest(InterfaceRequest&& other) {
     handle_ = std::move(other.handle_);
@@ -82,20 +64,6 @@
     return !is_pending() && !other.is_pending();
   }
 
-  void ResetWithReason(uint32_t custom_reason, const std::string& description) {
-    if (!handle_.is_valid())
-      return;
-
-    Message message =
-        PipeControlMessageProxy::ConstructPeerEndpointClosedMessage(
-            kMasterInterfaceId, DisconnectReason(custom_reason, description));
-    MojoResult result = WriteMessageNew(
-        handle_.get(), message.TakeMojoMessage(), MOJO_WRITE_MESSAGE_FLAG_NONE);
-    DCHECK_EQ(MOJO_RESULT_OK, result);
-
-    handle_.reset();
-  }
-
  private:
   ScopedMessagePipeHandle handle_;
 
@@ -135,9 +103,9 @@
 //
 //   DatabasePtr database = ...;  // Connect to database.
 //   TablePtr table;
-//   database->OpenTable(MakeRequest(&table));
+//   database->OpenTable(GetProxy(&table));
 //
-// Upon return from MakeRequest, |table| is ready to have methods called on it.
+// Upon return from GetProxy, |table| is ready to have methods called on it.
 //
 // Example #2: Registering a local implementation with a remote service.
 // =====================================================================
@@ -151,16 +119,19 @@
 //
 //   CollectorPtr collector = ...;  // Connect to Collector.
 //   SourcePtr source;
-//   InterfaceRequest<Source> source_request(&source);
+//   InterfaceRequest<Source> source_request = GetProxy(&source);
 //   collector->RegisterSource(std::move(source));
 //   CreateSource(std::move(source_request));  // Create implementation locally.
 //
 template <typename Interface>
-InterfaceRequest<Interface> MakeRequest(
+InterfaceRequest<Interface> GetProxy(
     InterfacePtr<Interface>* ptr,
     scoped_refptr<base::SingleThreadTaskRunner> runner =
         base::ThreadTaskRunnerHandle::Get()) {
-  return InterfaceRequest<Interface>(ptr, runner);
+  MessagePipe pipe;
+  ptr->Bind(InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u),
+            std::move(runner));
+  return MakeRequest<Interface>(std::move(pipe.handle1));
 }
 
 // Fuses an InterfaceRequest<T> endpoint with an InterfacePtrInfo<T> endpoint.
diff --git a/mojo/public/cpp/bindings/lib/array_internal.h b/mojo/public/cpp/bindings/lib/array_internal.h
index eecfcfb..ba6d16e 100644
--- a/mojo/public/cpp/bindings/lib/array_internal.h
+++ b/mojo/public/cpp/bindings/lib/array_internal.h
@@ -13,7 +13,6 @@
 
 #include "base/logging.h"
 #include "mojo/public/c/system/macros.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
 #include "mojo/public/cpp/bindings/lib/buffer.h"
 #include "mojo/public/cpp/bindings/lib/serialization_util.h"
@@ -29,13 +28,13 @@
 template <typename K, typename V>
 class Map_Data;
 
-MOJO_CPP_BINDINGS_EXPORT std::string
-MakeMessageWithArrayIndex(const char* message, size_t size, size_t index);
+std::string MakeMessageWithArrayIndex(const char* message,
+                                      size_t size,
+                                      size_t index);
 
-MOJO_CPP_BINDINGS_EXPORT std::string MakeMessageWithExpectedArraySize(
-    const char* message,
-    size_t size,
-    size_t expected_size);
+std::string MakeMessageWithExpectedArraySize(const char* message,
+                                             size_t size,
+                                             size_t expected_size);
 
 template <typename T>
 struct ArrayDataTraits {
@@ -68,7 +67,7 @@
 struct ArrayDataTraits<bool> {
   // Helper class to emulate a reference to a bool, used for direct element
   // access.
-  class MOJO_CPP_BINDINGS_EXPORT BitRef {
+  class BitRef {
    public:
     ~BitRef();
     BitRef& operator=(bool value);
@@ -110,7 +109,7 @@
 //
 // TODO(yzshen): Validation code should be organzied in a way similar to
 // Serializer<>, or merged into it. It should be templatized with the mojo
-// data view type instead of the data type, that way we can use MojomTypeTraits
+// wrapper type instead of the data type, that way we can use MojomTypeTraits
 // to determine the categories.
 
 template <typename T, bool is_union, bool is_handle_or_interface>
@@ -263,7 +262,7 @@
       T,
       IsUnionDataType<T>::value,
       std::is_same<T, AssociatedInterface_Data>::value ||
-          std::is_same<T, AssociatedEndpointHandle_Data>::value ||
+          std::is_same<T, AssociatedInterfaceRequest_Data>::value ||
           std::is_same<T, Interface_Data>::value ||
           std::is_same<T, Handle_Data>::value>;
   using Element = T;
diff --git a/mojo/public/cpp/bindings/lib/array_serialization.h b/mojo/public/cpp/bindings/lib/array_serialization.h
index d2f8ecf..5db27a5 100644
--- a/mojo/public/cpp/bindings/lib/array_serialization.h
+++ b/mojo/public/cpp/bindings/lib/array_serialization.h
@@ -14,11 +14,12 @@
 #include <vector>
 
 #include "base/logging.h"
-#include "mojo/public/cpp/bindings/array_data_view.h"
+#include "mojo/public/cpp/bindings/array.h"
 #include "mojo/public/cpp/bindings/lib/array_internal.h"
 #include "mojo/public/cpp/bindings/lib/serialization_forward.h"
 #include "mojo/public/cpp/bindings/lib/template_util.h"
 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
+#include "mojo/public/cpp/bindings/map.h"
 
 namespace mojo {
 namespace internal {
@@ -45,7 +46,7 @@
   using GetNextResult =
       decltype(Traits::GetValue(std::declval<IteratorType&>()));
   GetNextResult GetNext() {
-    GetNextResult value = Traits::GetValue(iter_);
+    auto& value = Traits::GetValue(iter_);
     Traits::AdvanceIterator(iter_);
     return value;
   }
@@ -286,19 +287,13 @@
   using Element = typename MojomType::Element;
   using Traits = ArrayTraits<UserType>;
 
+  static_assert(std::is_same<Element, typename Traits::Element>::value,
+                "Incorrect array serializer");
+
   static size_t GetSerializedSize(UserTypeIterator* input,
                                   SerializationContext* context) {
-    size_t element_count = input->GetSize();
-    if (BelongsTo<Element,
-                  MojomTypeCategory::ASSOCIATED_INTERFACE |
-                      MojomTypeCategory::ASSOCIATED_INTERFACE_REQUEST>::value) {
-      for (size_t i = 0; i < element_count; ++i) {
-        typename UserTypeIterator::GetNextResult next = input->GetNext();
-        size_t size = PrepareToSerialize<Element>(next, context);
-        DCHECK_EQ(size, 0u);
-      }
-    }
-    return sizeof(Data) + Align(element_count * sizeof(typename Data::Element));
+    return sizeof(Data) +
+           Align(input->GetSize() * sizeof(typename Data::Element));
   }
 
   static void SerializeElements(UserTypeIterator* input,
@@ -311,8 +306,7 @@
 
     size_t size = input->GetSize();
     for (size_t i = 0; i < size; ++i) {
-      typename UserTypeIterator::GetNextResult next = input->GetNext();
-      Serialize<Element>(next, &output->at(i), context);
+      Serialize<Element>(input->GetNext(), &output->at(i), context);
 
       static const ValidationError kError =
           BelongsTo<Element,
@@ -367,10 +361,8 @@
                                   SerializationContext* context) {
     size_t element_count = input->GetSize();
     size_t size = sizeof(Data) + element_count * sizeof(typename Data::Element);
-    for (size_t i = 0; i < element_count; ++i) {
-      typename UserTypeIterator::GetNextResult next = input->GetNext();
-      size += PrepareToSerialize<Element>(next, context);
-    }
+    for (size_t i = 0; i < element_count; ++i)
+      size += PrepareToSerialize<Element>(input->GetNext(), context);
     return size;
   }
 
@@ -382,8 +374,7 @@
     size_t size = input->GetSize();
     for (size_t i = 0; i < size; ++i) {
       DataElementPtr data_ptr;
-      typename UserTypeIterator::GetNextResult next = input->GetNext();
-      SerializeCaller<Element>::Run(next, buf, &data_ptr,
+      SerializeCaller<Element>::Run(input->GetNext(), buf, &data_ptr,
                                     validate_params->element_validate_params,
                                     context);
       output->at(i).Set(data_ptr);
@@ -453,6 +444,10 @@
   using Element = typename MojomType::Element;
   using Traits = ArrayTraits<UserType>;
 
+  static_assert(std::is_same<typename MojomType::Element,
+                             typename Traits::Element>::value,
+                "Incorrect array serializer");
+
   static size_t GetSerializedSize(UserTypeIterator* input,
                                   SerializationContext* context) {
     size_t element_count = input->GetSize();
@@ -460,8 +455,7 @@
     for (size_t i = 0; i < element_count; ++i) {
       // Call with |inlined| set to false, so that it will account for both the
       // data in the union and the space in the array used to hold the union.
-      typename UserTypeIterator::GetNextResult next = input->GetNext();
-      size += PrepareToSerialize<Element>(next, false, context);
+      size += PrepareToSerialize<Element>(input->GetNext(), false, context);
     }
     return size;
   }
@@ -474,8 +468,7 @@
     size_t size = input->GetSize();
     for (size_t i = 0; i < size; ++i) {
       typename Data::Element* result = output->storage() + i;
-      typename UserTypeIterator::GetNextResult next = input->GetNext();
-      Serialize<Element>(next, buf, &result, true, context);
+      Serialize<Element>(input->GetNext(), buf, &result, true, context);
       MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
           !validate_params->element_is_nullable && output->at(i).is_null(),
           VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
@@ -499,13 +492,13 @@
 };
 
 template <typename Element, typename MaybeConstUserType>
-struct Serializer<ArrayDataView<Element>, MaybeConstUserType> {
+struct Serializer<Array<Element>, MaybeConstUserType> {
   using UserType = typename std::remove_const<MaybeConstUserType>::type;
   using Traits = ArrayTraits<UserType>;
-  using Impl = ArraySerializer<ArrayDataView<Element>,
+  using Impl = ArraySerializer<Array<Element>,
                                MaybeConstUserType,
                                ArrayIterator<Traits, MaybeConstUserType>>;
-  using Data = typename MojomTypeTraits<ArrayDataView<Element>>::Data;
+  using Data = typename MojomTypeTraits<Array<Element>>::Data;
 
   static size_t PrepareToSerialize(MaybeConstUserType& input,
                                    SerializationContext* context) {
diff --git a/mojo/public/cpp/bindings/lib/associated_group.cc b/mojo/public/cpp/bindings/lib/associated_group.cc
index 3e95eeb..a9c53b5 100644
--- a/mojo/public/cpp/bindings/lib/associated_group.cc
+++ b/mojo/public/cpp/bindings/lib/associated_group.cc
@@ -8,27 +8,28 @@
 
 namespace mojo {
 
-AssociatedGroup::AssociatedGroup() = default;
+AssociatedGroup::AssociatedGroup() {}
 
-AssociatedGroup::AssociatedGroup(
-    scoped_refptr<AssociatedGroupController> controller)
-    : controller_(std::move(controller)) {}
+AssociatedGroup::AssociatedGroup(const AssociatedGroup& other)
+    : controller_(other.controller_) {}
 
-AssociatedGroup::AssociatedGroup(const ScopedInterfaceEndpointHandle& handle)
-    : controller_getter_(handle.CreateGroupControllerGetter()) {}
+AssociatedGroup::~AssociatedGroup() {}
 
-AssociatedGroup::AssociatedGroup(const AssociatedGroup& other) = default;
+AssociatedGroup& AssociatedGroup::operator=(const AssociatedGroup& other) {
+  if (this == &other)
+    return *this;
 
-AssociatedGroup::~AssociatedGroup() = default;
+  controller_ = other.controller_;
+  return *this;
+}
 
-AssociatedGroup& AssociatedGroup::operator=(const AssociatedGroup& other) =
-    default;
+void AssociatedGroup::CreateEndpointHandlePair(
+    ScopedInterfaceEndpointHandle* local_endpoint,
+    ScopedInterfaceEndpointHandle* remote_endpoint) {
+  if (!controller_)
+    return;
 
-AssociatedGroupController* AssociatedGroup::GetController() {
-  if (controller_)
-    return controller_.get();
-
-  return controller_getter_.Run();
+  controller_->CreateEndpointHandlePair(local_endpoint, remote_endpoint);
 }
 
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/associated_group_controller.cc b/mojo/public/cpp/bindings/lib/associated_group_controller.cc
index f4a9aa2..42db9b3 100644
--- a/mojo/public/cpp/bindings/lib/associated_group_controller.cc
+++ b/mojo/public/cpp/bindings/lib/associated_group_controller.cc
@@ -8,17 +8,25 @@
 
 namespace mojo {
 
+AssociatedGroupController::AssociatedGroupController(
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+    : base::RefCountedDeleteOnMessageLoop<AssociatedGroupController>(
+          task_runner) {}
+
 AssociatedGroupController::~AssociatedGroupController() {}
 
-ScopedInterfaceEndpointHandle
-AssociatedGroupController::CreateScopedInterfaceEndpointHandle(InterfaceId id) {
-  return ScopedInterfaceEndpointHandle(id, this);
+std::unique_ptr<AssociatedGroup>
+AssociatedGroupController::CreateAssociatedGroup() {
+  std::unique_ptr<AssociatedGroup> group(new AssociatedGroup);
+  group->controller_ = this;
+  return group;
 }
 
-bool AssociatedGroupController::NotifyAssociation(
-    ScopedInterfaceEndpointHandle* handle_to_send,
-    InterfaceId id) {
-  return handle_to_send->NotifyAssociation(id, this);
+ScopedInterfaceEndpointHandle
+AssociatedGroupController::CreateScopedInterfaceEndpointHandle(
+    InterfaceId id,
+    bool is_local) {
+  return ScopedInterfaceEndpointHandle(id, is_local, this);
 }
 
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
index 72f7960..c7f74fb 100644
--- a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
+++ b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
@@ -9,7 +9,6 @@
 
 #include <algorithm>  // For |std::swap()|.
 #include <memory>
-#include <string>
 #include <utility>
 
 #include "base/bind.h"
@@ -19,10 +18,11 @@
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "mojo/public/cpp/bindings/associated_group.h"
+#include "mojo/public/cpp/bindings/associated_group_controller.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
-#include "mojo/public/cpp/bindings/connection_error_callback.h"
 #include "mojo/public/cpp/bindings/interface_endpoint_client.h"
 #include "mojo/public/cpp/bindings/interface_id.h"
+#include "mojo/public/cpp/bindings/lib/control_message_proxy.h"
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 
@@ -46,12 +46,18 @@
 
   uint32_t version() const { return version_; }
 
+  uint32_t interface_id() const {
+    DCHECK(is_bound());
+    return endpoint_client_->interface_id();
+  }
+
   void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
-    // It is safe to capture |this| because the callback won't be run after this
-    // object goes away.
-    endpoint_client_->QueryVersion(
-        base::Bind(&AssociatedInterfacePtrState::OnQueryVersion,
-                   base::Unretained(this), callback));
+    // Do a static cast in case the interface contains methods with the same
+    // name. It is safe to capture |this| because the callback won't be run
+    // after this object goes away.
+    static_cast<ControlMessageProxy*>(proxy_.get())
+        ->QueryVersion(base::Bind(&AssociatedInterfacePtrState::OnQueryVersion,
+                                  base::Unretained(this), callback));
   }
 
   void RequireVersion(uint32_t version) {
@@ -59,13 +65,9 @@
       return;
 
     version_ = version;
-    endpoint_client_->RequireVersion(version);
-  }
-
-  void FlushForTesting() { endpoint_client_->FlushForTesting(); }
-
-  void CloseWithReason(uint32_t custom_reason, const std::string& description) {
-    endpoint_client_->CloseWithReason(custom_reason, description);
+    // Do a static cast in case the interface contains methods with the same
+    // name.
+    static_cast<ControlMessageProxy*>(proxy_.get())->RequireVersion(version);
   }
 
   void Swap(AssociatedInterfacePtrState* other) {
@@ -83,13 +85,13 @@
     DCHECK(info.is_valid());
 
     version_ = info.version();
-    // The version is only queried from the client so the value passed here
-    // will not be used.
     endpoint_client_.reset(new InterfaceEndpointClient(
         info.PassHandle(), nullptr,
         base::WrapUnique(new typename Interface::ResponseValidator_()), false,
-        std::move(runner), 0u));
+        std::move(runner)));
     proxy_.reset(new Proxy(endpoint_client_.get()));
+    proxy_->serialization_context()->group_controller =
+        endpoint_client_->group_controller();
   }
 
   // After this method is called, the object is in an invalid state and
@@ -112,12 +114,6 @@
     endpoint_client_->set_connection_error_handler(error_handler);
   }
 
-  void set_connection_error_with_reason_handler(
-      const ConnectionErrorWithReasonCallback& error_handler) {
-    DCHECK(endpoint_client_);
-    endpoint_client_->set_connection_error_with_reason_handler(error_handler);
-  }
-
   // Returns true if bound and awaiting a response to a message.
   bool has_pending_callbacks() const {
     return endpoint_client_ && endpoint_client_->has_pending_responders();
@@ -127,13 +123,6 @@
     return endpoint_client_ ? endpoint_client_->associated_group() : nullptr;
   }
 
-  void ForwardMessage(Message message) { endpoint_client_->Accept(&message); }
-
-  void ForwardMessageWithResponder(Message message,
-                                   std::unique_ptr<MessageReceiver> responder) {
-    endpoint_client_->AcceptWithResponder(&message, responder.release());
-  }
-
  private:
   using Proxy = typename Interface::Proxy_;
 
diff --git a/mojo/public/cpp/bindings/lib/binding_state.h b/mojo/public/cpp/bindings/lib/binding_state.h
index 0b0dbee..c8d3e83 100644
--- a/mojo/public/cpp/bindings/lib/binding_state.h
+++ b/mojo/public/cpp/bindings/lib/binding_state.h
@@ -6,7 +6,6 @@
 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDING_STATE_H_
 
 #include <memory>
-#include <string>
 #include <utility>
 
 #include "base/bind.h"
@@ -16,15 +15,15 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
-#include "mojo/public/cpp/bindings/connection_error_callback.h"
-#include "mojo/public/cpp/bindings/filter_chain.h"
+#include "mojo/public/cpp/bindings/associated_group.h"
 #include "mojo/public/cpp/bindings/interface_endpoint_client.h"
 #include "mojo/public/cpp/bindings/interface_id.h"
 #include "mojo/public/cpp/bindings/interface_ptr.h"
 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/lib/filter_chain.h"
 #include "mojo/public/cpp/bindings/lib/multiplex_router.h"
+#include "mojo/public/cpp/bindings/lib/router.h"
 #include "mojo/public/cpp/bindings/message_header_validator.h"
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 #include "mojo/public/cpp/system/core.h"
@@ -32,34 +31,76 @@
 namespace mojo {
 namespace internal {
 
-class MOJO_CPP_BINDINGS_EXPORT BindingStateBase {
+template <typename Interface, bool use_multiplex_router>
+class BindingState;
+
+// Uses a single-threaded, dedicated router. If |Interface| doesn't have any
+// methods to pass associated interface pointers or requests, there won't be
+// multiple interfaces running on the underlying message pipe. In that case, we
+// can use this specialization to reduce cost.
+template <typename Interface>
+class BindingState<Interface, false> {
  public:
-  BindingStateBase();
-  ~BindingStateBase();
+  explicit BindingState(Interface* impl) : impl_(impl) {
+    stub_.set_sink(impl_);
+  }
 
-  void AddFilter(std::unique_ptr<MessageReceiver> filter);
+  ~BindingState() { Close(); }
 
-  bool HasAssociatedInterfaces() const;
+  void Bind(ScopedMessagePipeHandle handle,
+            scoped_refptr<base::SingleThreadTaskRunner> runner) {
+    DCHECK(!router_);
+    internal::FilterChain filters;
+    filters.Append<MessageHeaderValidator>(Interface::Name_);
+    filters.Append<typename Interface::RequestValidator_>();
 
-  void PauseIncomingMethodCallProcessing();
-  void ResumeIncomingMethodCallProcessing();
+    router_ =
+        new internal::Router(std::move(handle), std::move(filters),
+                             Interface::HasSyncMethods_, std::move(runner));
+    router_->set_incoming_receiver(&stub_);
+    router_->set_connection_error_handler(
+        base::Bind(&BindingState::RunConnectionErrorHandler,
+                   base::Unretained(this)));
+  }
+
+  bool HasAssociatedInterfaces() const { return false; }
+
+  void PauseIncomingMethodCallProcessing() {
+    DCHECK(router_);
+    router_->PauseIncomingMethodCallProcessing();
+  }
+  void ResumeIncomingMethodCallProcessing() {
+    DCHECK(router_);
+    router_->ResumeIncomingMethodCallProcessing();
+  }
 
   bool WaitForIncomingMethodCall(
-      MojoDeadline deadline = MOJO_DEADLINE_INDEFINITE);
+      MojoDeadline deadline = MOJO_DEADLINE_INDEFINITE) {
+    DCHECK(router_);
+    return router_->WaitForIncomingMessage(deadline);
+  }
 
-  void Close();
-  void CloseWithReason(uint32_t custom_reason, const std::string& description);
+  void Close() {
+    if (!router_)
+      return;
+
+    router_->CloseMessagePipe();
+    DestroyRouter();
+  }
+
+  InterfaceRequest<Interface> Unbind() {
+    InterfaceRequest<Interface> request =
+        MakeRequest<Interface>(router_->PassMessagePipe());
+    DestroyRouter();
+    return std::move(request);
+  }
 
   void set_connection_error_handler(const base::Closure& error_handler) {
     DCHECK(is_bound());
-    endpoint_client_->set_connection_error_handler(error_handler);
+    connection_error_handler_ = error_handler;
   }
 
-  void set_connection_error_with_reason_handler(
-      const ConnectionErrorWithReasonCallback& error_handler) {
-    DCHECK(is_bound());
-    endpoint_client_->set_connection_error_with_reason_handler(error_handler);
-  }
+  Interface* impl() { return impl_; }
 
   bool is_bound() const { return !!router_; }
 
@@ -68,42 +109,90 @@
     return router_->handle();
   }
 
-  void FlushForTesting();
+  AssociatedGroup* associated_group() { return nullptr; }
 
-  void EnableTestingMode();
+  void EnableTestingMode() {
+    DCHECK(is_bound());
+    router_->EnableTestingMode();
+  }
 
- protected:
-  void BindInternal(ScopedMessagePipeHandle handle,
-                    scoped_refptr<base::SingleThreadTaskRunner> runner,
-                    const char* interface_name,
-                    std::unique_ptr<MessageReceiver> request_validator,
-                    bool passes_associated_kinds,
-                    bool has_sync_methods,
-                    MessageReceiverWithResponderStatus* stub,
-                    uint32_t interface_version);
+ private:
+  void DestroyRouter() {
+    router_->set_connection_error_handler(base::Closure());
+    delete router_;
+    router_ = nullptr;
+    connection_error_handler_.Reset();
+  }
 
-  scoped_refptr<internal::MultiplexRouter> router_;
-  std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
+  void RunConnectionErrorHandler() {
+    if (!connection_error_handler_.is_null())
+      connection_error_handler_.Run();
+  }
+
+  internal::Router* router_ = nullptr;
+  typename Interface::Stub_ stub_;
+  Interface* impl_;
+  base::Closure connection_error_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(BindingState);
 };
 
-template <typename Interface, typename ImplRefTraits>
-class BindingState : public BindingStateBase {
+// Uses a multiplexing router. If |Interface| has methods to pass associated
+// interface pointers or requests, this specialization should be used.
+template <typename Interface>
+class BindingState<Interface, true> {
  public:
-  using ImplPointerType = typename ImplRefTraits::PointerType;
-
-  explicit BindingState(ImplPointerType impl) {
-    stub_.set_sink(std::move(impl));
+  explicit BindingState(Interface* impl) : impl_(impl) {
+    stub_.set_sink(impl_);
   }
 
   ~BindingState() { Close(); }
 
   void Bind(ScopedMessagePipeHandle handle,
             scoped_refptr<base::SingleThreadTaskRunner> runner) {
-    BindingStateBase::BindInternal(
-        std::move(handle), runner, Interface::Name_,
-        base::MakeUnique<typename Interface::RequestValidator_>(),
-        Interface::PassesAssociatedKinds_, Interface::HasSyncMethods_, &stub_,
-        Interface::Version_);
+    DCHECK(!router_);
+
+    router_ = new internal::MultiplexRouter(false, std::move(handle), runner);
+    router_->SetMasterInterfaceName(Interface::Name_);
+    stub_.serialization_context()->group_controller = router_;
+
+    endpoint_client_.reset(new InterfaceEndpointClient(
+        router_->CreateLocalEndpointHandle(kMasterInterfaceId),
+        &stub_, base::WrapUnique(new typename Interface::RequestValidator_()),
+        Interface::HasSyncMethods_, std::move(runner)));
+
+    endpoint_client_->set_connection_error_handler(
+        base::Bind(&BindingState::RunConnectionErrorHandler,
+                   base::Unretained(this)));
+  }
+
+  bool HasAssociatedInterfaces() const {
+    return router_ ? router_->HasAssociatedEndpoints() : false;
+  }
+
+  void PauseIncomingMethodCallProcessing() {
+    DCHECK(router_);
+    router_->PauseIncomingMethodCallProcessing();
+  }
+  void ResumeIncomingMethodCallProcessing() {
+    DCHECK(router_);
+    router_->ResumeIncomingMethodCallProcessing();
+  }
+
+  bool WaitForIncomingMethodCall(
+      MojoDeadline deadline = MOJO_DEADLINE_INDEFINITE) {
+    DCHECK(router_);
+    return router_->WaitForIncomingMessage(deadline);
+  }
+
+  void Close() {
+    if (!router_)
+      return;
+
+    endpoint_client_.reset();
+    router_->CloseMessagePipe();
+    router_ = nullptr;
+    connection_error_handler_.Reset();
   }
 
   InterfaceRequest<Interface> Unbind() {
@@ -111,13 +200,45 @@
     InterfaceRequest<Interface> request =
         MakeRequest<Interface>(router_->PassMessagePipe());
     router_ = nullptr;
+    connection_error_handler_.Reset();
     return request;
   }
 
-  Interface* impl() { return ImplRefTraits::GetRawPointer(&stub_.sink()); }
+  void set_connection_error_handler(const base::Closure& error_handler) {
+    DCHECK(is_bound());
+    connection_error_handler_ = error_handler;
+  }
+
+  Interface* impl() { return impl_; }
+
+  bool is_bound() const { return !!router_; }
+
+  MessagePipeHandle handle() const {
+    DCHECK(is_bound());
+    return router_->handle();
+  }
+
+  AssociatedGroup* associated_group() {
+    return endpoint_client_ ? endpoint_client_->associated_group() : nullptr;
+  }
+
+  void EnableTestingMode() {
+    DCHECK(is_bound());
+    router_->EnableTestingMode();
+  }
 
  private:
-  typename Interface::template Stub_<ImplRefTraits> stub_;
+  void RunConnectionErrorHandler() {
+    if (!connection_error_handler_.is_null())
+      connection_error_handler_.Run();
+  }
+
+  scoped_refptr<internal::MultiplexRouter> router_;
+  std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
+
+  typename Interface::Stub_ stub_;
+  Interface* impl_;
+  base::Closure connection_error_handler_;
 
   DISALLOW_COPY_AND_ASSIGN(BindingState);
 };
diff --git a/mojo/public/cpp/bindings/lib/bindings_internal.cc b/mojo/public/cpp/bindings/lib/bindings_internal.cc
new file mode 100644
index 0000000..a3bdb1f
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/bindings_internal.cc
@@ -0,0 +1,47 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/public/cpp/bindings/lib/bindings_internal.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);
+  DCHECK(p_obj > p_slot);
+
+  *offset = static_cast<uint64_t>(p_obj - p_slot);
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/bindings_internal.h b/mojo/public/cpp/bindings/lib/bindings_internal.h
index 631daec..b37d872 100644
--- a/mojo/public/cpp/bindings/lib/bindings_internal.h
+++ b/mojo/public/cpp/bindings/lib/bindings_internal.h
@@ -17,26 +17,30 @@
 namespace mojo {
 
 template <typename T>
-class ArrayDataView;
+class Array;
 
 template <typename T>
-class AssociatedInterfacePtrInfoDataView;
+class AssociatedInterfacePtrInfo;
 
 template <typename T>
-class AssociatedInterfaceRequestDataView;
+class AssociatedInterfaceRequest;
 
 template <typename T>
-class InterfacePtrDataView;
+class InterfacePtr;
 
 template <typename T>
-class InterfaceRequestDataView;
+class InterfaceRequest;
 
 template <typename K, typename V>
-class MapDataView;
+class Map;
 
-class NativeStructDataView;
+class String;
 
-class StringDataView;
+template <typename T>
+class StructPtr;
+
+template <typename T>
+class InlinedStructPtr;
 
 namespace internal {
 
@@ -54,17 +58,12 @@
 template <typename K, typename V>
 class Map_Data;
 
-class NativeStruct_Data;
-
 using String_Data = Array_Data<char>;
 
-inline size_t Align(size_t size) {
-  return (size + 7) & ~0x7;
-}
+size_t Align(size_t size);
+char* AlignPointer(char* ptr);
 
-inline bool IsAligned(const void* ptr) {
-  return !(reinterpret_cast<uintptr_t>(ptr) & 0x7);
-}
+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
@@ -74,19 +73,7 @@
 //
 // A null pointer is encoded as an offset value of 0.
 //
-inline 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);
-  DCHECK(p_obj > p_slot);
-
-  *offset = static_cast<uint64_t>(p_obj - p_slot);
-}
-
+void EncodePointer(const void* ptr, uint64_t* offset);
 // Note: This function doesn't validate the encoded pointer value.
 inline const void* DecodePointer(const uint64_t* offset) {
   if (!*offset)
@@ -124,8 +111,6 @@
 };
 static_assert(sizeof(Pointer<char>) == 8, "Bad_sizeof(Pointer)");
 
-using GenericPointer = Pointer<void>;
-
 struct Handle_Data {
   Handle_Data() = default;
   explicit Handle_Data(uint32_t value) : value(value) {}
@@ -142,24 +127,19 @@
 };
 static_assert(sizeof(Interface_Data) == 8, "Bad_sizeof(Interface_Data)");
 
-struct AssociatedEndpointHandle_Data {
-  AssociatedEndpointHandle_Data() = default;
-  explicit AssociatedEndpointHandle_Data(uint32_t value) : value(value) {}
-
-  bool is_valid() const { return value != kEncodedInvalidHandleValue; }
-
-  uint32_t value;
-};
-static_assert(sizeof(AssociatedEndpointHandle_Data) == 4,
-              "Bad_sizeof(AssociatedEndpointHandle_Data)");
-
 struct AssociatedInterface_Data {
-  AssociatedEndpointHandle_Data handle;
+  InterfaceId interface_id;
   uint32_t version;
 };
 static_assert(sizeof(AssociatedInterface_Data) == 8,
               "Bad_sizeof(AssociatedInterface_Data)");
 
+struct AssociatedInterfaceRequest_Data {
+  InterfaceId interface_id;
+};
+static_assert(sizeof(AssociatedInterfaceRequest_Data) == 4,
+              "Bad_sizeof(AssociatedInterfaceRequest_Data)");
+
 #pragma pack(pop)
 
 template <typename T>
@@ -223,7 +203,7 @@
 };
 
 template <typename T>
-struct MojomTypeTraits<ArrayDataView<T>, false> {
+struct MojomTypeTraits<Array<T>, false> {
   using Data = Array_Data<typename MojomTypeTraits<T>::DataAsArrayElement>;
   using DataAsArrayElement = Pointer<Data>;
 
@@ -231,7 +211,7 @@
 };
 
 template <typename T>
-struct MojomTypeTraits<AssociatedInterfacePtrInfoDataView<T>, false> {
+struct MojomTypeTraits<AssociatedInterfacePtrInfo<T>, false> {
   using Data = AssociatedInterface_Data;
   using DataAsArrayElement = Data;
 
@@ -240,8 +220,8 @@
 };
 
 template <typename T>
-struct MojomTypeTraits<AssociatedInterfaceRequestDataView<T>, false> {
-  using Data = AssociatedEndpointHandle_Data;
+struct MojomTypeTraits<AssociatedInterfaceRequest<T>, false> {
+  using Data = AssociatedInterfaceRequest_Data;
   using DataAsArrayElement = Data;
 
   static const MojomTypeCategory category =
@@ -273,7 +253,7 @@
 };
 
 template <typename T>
-struct MojomTypeTraits<InterfacePtrDataView<T>, false> {
+struct MojomTypeTraits<InterfacePtr<T>, false> {
   using Data = Interface_Data;
   using DataAsArrayElement = Data;
 
@@ -281,7 +261,7 @@
 };
 
 template <typename T>
-struct MojomTypeTraits<InterfaceRequestDataView<T>, false> {
+struct MojomTypeTraits<InterfaceRequest<T>, false> {
   using Data = Handle_Data;
   using DataAsArrayElement = Data;
 
@@ -290,7 +270,7 @@
 };
 
 template <typename K, typename V>
-struct MojomTypeTraits<MapDataView<K, V>, false> {
+struct MojomTypeTraits<Map<K, V>, false> {
   using Data = Map_Data<typename MojomTypeTraits<K>::DataAsArrayElement,
                         typename MojomTypeTraits<V>::DataAsArrayElement>;
   using DataAsArrayElement = Pointer<Data>;
@@ -299,21 +279,39 @@
 };
 
 template <>
-struct MojomTypeTraits<NativeStructDataView, false> {
-  using Data = internal::NativeStruct_Data;
-  using DataAsArrayElement = Pointer<Data>;
-
-  static const MojomTypeCategory category = MojomTypeCategory::STRUCT;
-};
-
-template <>
-struct MojomTypeTraits<StringDataView, false> {
+struct MojomTypeTraits<String, false> {
   using Data = String_Data;
   using DataAsArrayElement = Pointer<Data>;
 
   static const MojomTypeCategory category = MojomTypeCategory::STRING;
 };
 
+template <typename T>
+struct MojomTypeTraits<StructPtr<T>, false> {
+  using Data = typename T::Data_;
+  using DataAsArrayElement =
+      typename std::conditional<IsUnionDataType<Data>::value,
+                                Data,
+                                Pointer<Data>>::type;
+
+  static const MojomTypeCategory category = IsUnionDataType<Data>::value
+                                                ? MojomTypeCategory::UNION
+                                                : MojomTypeCategory::STRUCT;
+};
+
+template <typename T>
+struct MojomTypeTraits<InlinedStructPtr<T>, false> {
+  using Data = typename T::Data_;
+  using DataAsArrayElement =
+      typename std::conditional<IsUnionDataType<Data>::value,
+                                Data,
+                                Pointer<Data>>::type;
+
+  static const MojomTypeCategory category = IsUnionDataType<Data>::value
+                                                ? MojomTypeCategory::UNION
+                                                : MojomTypeCategory::STRUCT;
+};
+
 template <typename T, MojomTypeCategory categories>
 struct BelongsTo {
   static const bool value =
diff --git a/mojo/public/cpp/bindings/lib/buffer.h b/mojo/public/cpp/bindings/lib/buffer.h
index 213a445..c3b570e 100644
--- a/mojo/public/cpp/bindings/lib/buffer.h
+++ b/mojo/public/cpp/bindings/lib/buffer.h
@@ -7,61 +7,15 @@
 
 #include <stddef.h>
 
-#include "base/logging.h"
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
-
 namespace mojo {
 namespace internal {
 
-// Buffer provides an interface to allocate memory blocks which are 8-byte
-// aligned and zero-initialized. It doesn't own the underlying memory. Users
-// must ensure that the memory stays valid while using the allocated blocks from
-// Buffer.
+// 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:
-  Buffer() {}
-
-  // The memory must have been zero-initialized. |data| must be 8-byte
-  // aligned.
-  void Initialize(void* data, size_t size) {
-    DCHECK(IsAligned(data));
-
-    data_ = data;
-    size_ = size;
-    cursor_ = reinterpret_cast<uintptr_t>(data);
-    data_end_ = cursor_ + size;
-  }
-
-  size_t size() const { return size_; }
-
-  void* data() const { return data_; }
-
-  // Allocates |num_bytes| from the buffer and returns a pointer to the start of
-  // the allocated block.
-  // The resulting address is 8-byte aligned, and the content of the memory is
-  // zero-filled.
-  void* Allocate(size_t num_bytes) {
-    num_bytes = Align(num_bytes);
-    uintptr_t result = cursor_;
-    cursor_ += num_bytes;
-    if (cursor_ > data_end_ || cursor_ < result) {
-      NOTREACHED();
-      cursor_ -= num_bytes;
-      return nullptr;
-    }
-
-    return reinterpret_cast<void*>(result);
-  }
-
- private:
-  void* data_ = nullptr;
-  size_t size_ = 0;
-
-  uintptr_t cursor_ = 0;
-  uintptr_t data_end_ = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(Buffer);
+  virtual ~Buffer() {}
+  virtual void* Allocate(size_t num_bytes) = 0;
 };
 
 }  // namespace internal
diff --git a/mojo/public/cpp/bindings/lib/clone_equals_util.h b/mojo/public/cpp/bindings/lib/clone_equals_util.h
new file mode 100644
index 0000000..f7bd898
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/clone_equals_util.h
@@ -0,0 +1,161 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_CLONE_EQUALS_UTIL_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_CLONE_EQUALS_UTIL_H_
+
+#include <type_traits>
+#include <unordered_map>
+#include <vector>
+
+#include "base/optional.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+
+namespace mojo {
+namespace internal {
+
+template <typename T>
+struct HasCloneMethod {
+  template <typename U>
+  static char Test(decltype(&U::Clone));
+  template <typename U>
+  static int Test(...);
+  static const bool value = sizeof(Test<T>(0)) == sizeof(char);
+
+ private:
+  EnsureTypeIsComplete<T> check_t_;
+};
+
+template <typename T, bool has_clone_method = HasCloneMethod<T>::value>
+struct CloneTraits;
+
+template <typename T>
+T Clone(const T& input);
+
+template <typename T>
+struct CloneTraits<T, true> {
+  static T Clone(const T& input) { return input.Clone(); }
+};
+
+template <typename T>
+struct CloneTraits<T, false> {
+  static T Clone(const T& input) { return input; }
+};
+
+template <typename T>
+struct CloneTraits<base::Optional<T>, false> {
+  static base::Optional<T> Clone(const base::Optional<T>& input) {
+    if (!input)
+      return base::nullopt;
+
+    return base::Optional<T>(internal::Clone(*input));
+  }
+};
+
+template <typename T>
+struct CloneTraits<std::vector<T>, false> {
+  static std::vector<T> Clone(const std::vector<T>& input) {
+    std::vector<T> result;
+    result.reserve(input.size());
+    for (const auto& element : input)
+      result.push_back(internal::Clone(element));
+
+    return result;
+  }
+};
+
+template <typename K, typename V>
+struct CloneTraits<std::unordered_map<K, V>, false> {
+  static std::unordered_map<K, V> Clone(const std::unordered_map<K, V>& input) {
+    std::unordered_map<K, V> result;
+    for (const auto& element : input) {
+      result.insert(std::make_pair(internal::Clone(element.first),
+                                   internal::Clone(element.second)));
+    }
+    return result;
+  }
+};
+
+template <typename T>
+T Clone(const T& input) {
+  return CloneTraits<T>::Clone(input);
+};
+
+template <typename T>
+struct HasEqualsMethod {
+  template <typename U>
+  static char Test(decltype(&U::Equals));
+  template <typename U>
+  static int Test(...);
+  static const bool value = sizeof(Test<T>(0)) == sizeof(char);
+
+ private:
+  EnsureTypeIsComplete<T> check_t_;
+};
+
+template <typename T, bool has_equals_method = HasEqualsMethod<T>::value>
+struct EqualsTraits;
+
+template <typename T>
+bool Equals(const T& a, const T& b);
+
+template <typename T>
+struct EqualsTraits<T, true> {
+  static bool Equals(const T& a, const T& b) { return a.Equals(b); }
+};
+
+template <typename T>
+struct EqualsTraits<T, false> {
+  static bool Equals(const T& a, const T& b) { return a == b; }
+};
+
+template <typename T>
+struct EqualsTraits<base::Optional<T>, false> {
+  static bool Equals(const base::Optional<T>& a, const base::Optional<T>& b) {
+    if (!a && !b)
+      return true;
+    if (!a || !b)
+      return false;
+
+    return internal::Equals(*a, *b);
+  }
+};
+
+template <typename T>
+struct EqualsTraits<std::vector<T>, false> {
+  static bool Equals(const std::vector<T>& a, const std::vector<T>& b) {
+    if (a.size() != b.size())
+      return false;
+    for (size_t i = 0; i < a.size(); ++i) {
+      if (!internal::Equals(a[i], b[i]))
+        return false;
+    }
+    return true;
+  }
+};
+
+template <typename K, typename V>
+struct EqualsTraits<std::unordered_map<K, V>, false> {
+  static bool Equals(const std::unordered_map<K, V>& a,
+                     const std::unordered_map<K, V>& b) {
+    if (a.size() != b.size())
+      return false;
+    for (const auto& element : a) {
+      auto iter = b.find(element.first);
+      if (iter == b.end() || !internal::Equals(element.second, iter->second))
+        return false;
+    }
+    return true;
+  }
+};
+
+template <typename T>
+bool Equals(const T& a, const T& b) {
+  return EqualsTraits<T>::Equals(a, b);
+}
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_CLONE_EQUALS_UTIL_H_
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc
index 4426def..1bb38f0 100644
--- a/mojo/public/cpp/bindings/lib/connector.cc
+++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -12,20 +12,52 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/synchronization/lock.h"
-#include "mojo/public/cpp/bindings/lib/may_auto_lock.h"
 #include "mojo/public/cpp/bindings/sync_handle_watcher.h"
 
 namespace mojo {
 
+namespace {
+
+// Similar to base::AutoLock, except that it does nothing if |lock| passed into
+// the constructor is null.
+class MayAutoLock {
+ public:
+  explicit MayAutoLock(base::Lock* lock) : lock_(lock) {
+    if (lock_)
+      lock_->Acquire();
+  }
+
+  ~MayAutoLock() {
+    if (lock_) {
+      lock_->AssertAcquired();
+      lock_->Release();
+    }
+  }
+
+ private:
+  base::Lock* lock_;
+  DISALLOW_COPY_AND_ASSIGN(MayAutoLock);
+};
+
+}  // namespace
+
+// ----------------------------------------------------------------------------
+
 Connector::Connector(ScopedMessagePipeHandle message_pipe,
                      ConnectorConfig config,
                      scoped_refptr<base::SingleThreadTaskRunner> runner)
     : message_pipe_(std::move(message_pipe)),
+      incoming_receiver_(nullptr),
       task_runner_(std::move(runner)),
+      handle_watcher_(task_runner_),
+      error_(false),
+      drop_writes_(false),
+      enforce_errors_from_incoming_receiver_(true),
+      paused_(false),
+      lock_(config == MULTI_THREADED_SEND ? new base::Lock : nullptr),
+      allow_woken_up_by_others_(false),
+      sync_handle_watcher_callback_count_(0),
       weak_factory_(this) {
-  if (config == MULTI_THREADED_SEND)
-    lock_.emplace();
-
   weak_self_ = weak_factory_.GetWeakPtr();
   // 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.
@@ -33,34 +65,25 @@
 }
 
 Connector::~Connector() {
-  {
-    // Allow for quick destruction on any thread if the pipe is already closed.
-    base::AutoLock lock(connected_lock_);
-    if (!connected_)
-      return;
-  }
-
   DCHECK(thread_checker_.CalledOnValidThread());
+
   CancelWait();
 }
 
 void Connector::CloseMessagePipe() {
-  // Throw away the returned message pipe.
-  PassMessagePipe();
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  CancelWait();
+  MayAutoLock locker(lock_.get());
+  message_pipe_.reset();
 }
 
 ScopedMessagePipeHandle Connector::PassMessagePipe() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   CancelWait();
-  internal::MayAutoLock locker(&lock_);
-  ScopedMessagePipeHandle message_pipe = std::move(message_pipe_);
-  weak_factory_.InvalidateWeakPtrs();
-  sync_handle_watcher_callback_count_ = 0;
-
-  base::AutoLock lock(connected_lock_);
-  connected_ = false;
-  return message_pipe;
+  MayAutoLock locker(lock_.get());
+  return std::move(message_pipe_);
 }
 
 void Connector::RaiseError() {
@@ -120,7 +143,7 @@
   if (error_)
     return false;
 
-  internal::MayAutoLock locker(&lock_);
+  MayAutoLock locker(lock_.get());
 
   if (!message_pipe_.is_valid() || drop_writes_)
     return true;
@@ -181,13 +204,6 @@
   return sync_watcher_->SyncWatch(should_stop);
 }
 
-void Connector::SetWatcherHeapProfilerTag(const char* tag) {
-  heap_profiler_tag_ = tag;
-  if (handle_watcher_) {
-    handle_watcher_->set_heap_profiler_tag(tag);
-  }
-}
-
 void Connector::OnWatcherHandleReady(MojoResult result) {
   OnHandleReadyInternal(result);
 }
@@ -198,10 +214,8 @@
   sync_handle_watcher_callback_count_++;
   OnHandleReadyInternal(result);
   // At this point, this object might have been deleted.
-  if (weak_self) {
-    DCHECK_LT(0u, sync_handle_watcher_callback_count_);
+  if (weak_self)
     sync_handle_watcher_callback_count_--;
-  }
 }
 
 void Connector::OnHandleReadyInternal(MojoResult result) {
@@ -217,14 +231,12 @@
 
 void Connector::WaitToReadMore() {
   CHECK(!paused_);
-  DCHECK(!handle_watcher_);
+  DCHECK(!handle_watcher_.IsWatching());
 
-  handle_watcher_.reset(new Watcher(FROM_HERE, task_runner_));
-  if (heap_profiler_tag_)
-    handle_watcher_->set_heap_profiler_tag(heap_profiler_tag_);
-  MojoResult rv = handle_watcher_->Start(
+  MojoResult rv = handle_watcher_.Start(
       message_pipe_.get(), MOJO_HANDLE_SIGNAL_READABLE,
-      base::Bind(&Connector::OnWatcherHandleReady, base::Unretained(this)));
+      base::Bind(&Connector::OnWatcherHandleReady,
+                 base::Unretained(this)));
 
   if (rv != MOJO_RESULT_OK) {
     // If the watch failed because the handle is invalid or its conditions can
@@ -245,8 +257,8 @@
 
   bool receiver_result = false;
 
-  // Detect if |this| was destroyed or the message pipe was closed/transferred
-  // during message dispatch.
+  // Detect if |this| was destroyed during message dispatch. Allow for the
+  // possibility of re-entering ReadMore() through message dispatch.
   base::WeakPtr<Connector> weak_self = weak_self_;
 
   Message message;
@@ -280,11 +292,9 @@
   while (!error_) {
     MojoResult rv;
 
-    if (!ReadSingleMessage(&rv)) {
-      // Return immediately without touching any members. |this| may have been
-      // destroyed.
+    // Return immediately if |this| was destroyed. Do not touch any members!
+    if (!ReadSingleMessage(&rv))
       return;
-    }
 
     if (paused_)
       return;
@@ -295,7 +305,7 @@
 }
 
 void Connector::CancelWait() {
-  handle_watcher_.reset();
+  handle_watcher_.Cancel();
   sync_watcher_.reset();
 }
 
@@ -315,7 +325,7 @@
 
   if (force_pipe_reset) {
     CancelWait();
-    internal::MayAutoLock locker(&lock_);
+    MayAutoLock locker(lock_.get());
     message_pipe_.reset();
     MessagePipe dummy_pipe;
     message_pipe_ = std::move(dummy_pipe.handle0);
diff --git a/mojo/public/cpp/bindings/lib/control_message_handler.cc b/mojo/public/cpp/bindings/lib/control_message_handler.cc
index c90aada..9f44e88 100644
--- a/mojo/public/cpp/bindings/lib/control_message_handler.cc
+++ b/mojo/public/cpp/bindings/lib/control_message_handler.cc
@@ -11,53 +11,15 @@
 #include "base/logging.h"
 #include "mojo/public/cpp/bindings/lib/message_builder.h"
 #include "mojo/public/cpp/bindings/lib/serialization.h"
-#include "mojo/public/cpp/bindings/lib/validation_util.h"
 #include "mojo/public/interfaces/bindings/interface_control_messages.mojom.h"
 
 namespace mojo {
 namespace internal {
-namespace {
-
-bool ValidateControlRequestWithResponse(Message* message) {
-  ValidationContext validation_context(message->payload(),
-                                       message->payload_num_bytes(), 0, 0,
-                                       message, "ControlRequestValidator");
-  if (!ValidateMessageIsRequestExpectingResponse(message, &validation_context))
-    return false;
-
-  switch (message->header()->name) {
-    case interface_control::kRunMessageId:
-      return ValidateMessagePayload<
-          interface_control::internal::RunMessageParams_Data>(
-          message, &validation_context);
-  }
-  return false;
-}
-
-bool ValidateControlRequestWithoutResponse(Message* message) {
-  ValidationContext validation_context(message->payload(),
-                                       message->payload_num_bytes(), 0, 0,
-                                       message, "ControlRequestValidator");
-  if (!ValidateMessageIsRequestWithoutResponse(message, &validation_context))
-    return false;
-
-  switch (message->header()->name) {
-    case interface_control::kRunOrClosePipeMessageId:
-      return ValidateMessageIsRequestWithoutResponse(message,
-                                                     &validation_context) &&
-             ValidateMessagePayload<
-                 interface_control::internal::RunOrClosePipeMessageParams_Data>(
-                 message, &validation_context);
-  }
-  return false;
-}
-
-}  // namespace
 
 // static
 bool ControlMessageHandler::IsControlMessage(const Message* message) {
-  return message->header()->name == interface_control::kRunMessageId ||
-         message->header()->name == interface_control::kRunOrClosePipeMessageId;
+  return message->header()->name == kRunMessageId ||
+         message->header()->name == kRunOrClosePipeMessageId;
 }
 
 ControlMessageHandler::ControlMessageHandler(uint32_t interface_version)
@@ -68,10 +30,7 @@
 }
 
 bool ControlMessageHandler::Accept(Message* message) {
-  if (!ValidateControlRequestWithoutResponse(message))
-    return false;
-
-  if (message->header()->name == interface_control::kRunOrClosePipeMessageId)
+  if (message->header()->name == kRunOrClosePipeMessageId)
     return RunOrClosePipe(message);
 
   NOTREACHED();
@@ -81,10 +40,7 @@
 bool ControlMessageHandler::AcceptWithResponder(
     Message* message,
     MessageReceiverWithStatus* responder) {
-  if (!ValidateControlRequestWithResponse(message))
-    return false;
-
-  if (message->header()->name == interface_control::kRunMessageId)
+  if (message->header()->name == kRunMessageId)
     return Run(message, responder);
 
   NOTREACHED();
@@ -93,37 +49,20 @@
 
 bool ControlMessageHandler::Run(Message* message,
                                 MessageReceiverWithStatus* responder) {
-  interface_control::internal::RunMessageParams_Data* params =
-      reinterpret_cast<interface_control::internal::RunMessageParams_Data*>(
-          message->mutable_payload());
-  interface_control::RunMessageParamsPtr params_ptr;
-  Deserialize<interface_control::RunMessageParamsDataView>(params, &params_ptr,
-                                                           &context_);
-  auto& input = *params_ptr->input;
-  interface_control::RunOutputPtr output = interface_control::RunOutput::New();
-  if (input.is_query_version()) {
-    output->set_query_version_result(
-        interface_control::QueryVersionResult::New());
-    output->get_query_version_result()->version = interface_version_;
-  } else if (input.is_flush_for_testing()) {
-    output.reset();
-  } else {
-    output.reset();
-  }
+  RunResponseMessageParamsPtr response_params_ptr(
+      RunResponseMessageParams::New());
+  response_params_ptr->reserved0 = 16u;
+  response_params_ptr->reserved1 = 0u;
+  response_params_ptr->query_version_result = QueryVersionResult::New();
+  response_params_ptr->query_version_result->version = interface_version_;
 
-  auto response_params_ptr = interface_control::RunResponseMessageParams::New();
-  response_params_ptr->output = std::move(output);
-  size_t size =
-      PrepareToSerialize<interface_control::RunResponseMessageParamsDataView>(
-          response_params_ptr, &context_);
-  MessageBuilder builder(interface_control::kRunMessageId,
-                         Message::kFlagIsResponse, size, 0);
-  builder.message()->set_request_id(message->request_id());
+  size_t size = PrepareToSerialize<RunResponseMessageParamsPtr>(
+      response_params_ptr, &context_);
+  ResponseMessageBuilder builder(kRunMessageId, size, message->request_id());
 
-  interface_control::internal::RunResponseMessageParams_Data* response_params =
-      nullptr;
-  Serialize<interface_control::RunResponseMessageParamsDataView>(
-      response_params_ptr, builder.buffer(), &response_params, &context_);
+  RunResponseMessageParams_Data* response_params = nullptr;
+  Serialize<RunResponseMessageParamsPtr>(response_params_ptr, builder.buffer(),
+                                         &response_params, &context_);
   bool ok = responder->Accept(builder.message());
   ALLOW_UNUSED_LOCAL(ok);
   delete responder;
@@ -132,18 +71,13 @@
 }
 
 bool ControlMessageHandler::RunOrClosePipe(Message* message) {
-  interface_control::internal::RunOrClosePipeMessageParams_Data* params =
-      reinterpret_cast<
-          interface_control::internal::RunOrClosePipeMessageParams_Data*>(
+  RunOrClosePipeMessageParams_Data* params =
+      reinterpret_cast<RunOrClosePipeMessageParams_Data*>(
           message->mutable_payload());
-  interface_control::RunOrClosePipeMessageParamsPtr params_ptr;
-  Deserialize<interface_control::RunOrClosePipeMessageParamsDataView>(
-      params, &params_ptr, &context_);
-  auto& input = *params_ptr->input;
-  if (input.is_require_version())
-    return interface_version_ >= input.get_require_version()->version;
+  RunOrClosePipeMessageParamsPtr params_ptr;
+  Deserialize<RunOrClosePipeMessageParamsPtr>(params, &params_ptr, &context_);
 
-  return false;
+  return interface_version_ >= params_ptr->require_version->version;
 }
 
 }  // namespace internal
diff --git a/mojo/public/cpp/bindings/lib/control_message_handler.h b/mojo/public/cpp/bindings/lib/control_message_handler.h
index 3c385e4..13b5aa6 100644
--- a/mojo/public/cpp/bindings/lib/control_message_handler.h
+++ b/mojo/public/cpp/bindings/lib/control_message_handler.h
@@ -7,9 +7,7 @@
 
 #include <stdint.h>
 
-#include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/lib/serialization_context.h"
 #include "mojo/public/cpp/bindings/message.h"
 
@@ -17,8 +15,7 @@
 namespace internal {
 
 // Handlers for request messages defined in interface_control_messages.mojom.
-class MOJO_CPP_BINDINGS_EXPORT ControlMessageHandler
-    : NON_EXPORTED_BASE(public MessageReceiverWithResponderStatus) {
+class ControlMessageHandler : public MessageReceiverWithResponderStatus {
  public:
   static bool IsControlMessage(const Message* message);
 
diff --git a/mojo/public/cpp/bindings/lib/control_message_proxy.cc b/mojo/public/cpp/bindings/lib/control_message_proxy.cc
index 23de991..7af409d 100644
--- a/mojo/public/cpp/bindings/lib/control_message_proxy.cc
+++ b/mojo/public/cpp/bindings/lib/control_message_proxy.cc
@@ -9,12 +9,9 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/callback_helpers.h"
 #include "base/macros.h"
-#include "base/run_loop.h"
 #include "mojo/public/cpp/bindings/lib/message_builder.h"
 #include "mojo/public/cpp/bindings/lib/serialization.h"
-#include "mojo/public/cpp/bindings/lib/validation_util.h"
 #include "mojo/public/cpp/bindings/message.h"
 #include "mojo/public/interfaces/bindings/interface_control_messages.mojom.h"
 
@@ -23,28 +20,11 @@
 
 namespace {
 
-bool ValidateControlResponse(Message* message) {
-  ValidationContext validation_context(message->payload(),
-                                       message->payload_num_bytes(), 0, 0,
-                                       message, "ControlResponseValidator");
-  if (!ValidateMessageIsResponse(message, &validation_context))
-    return false;
-
-  switch (message->header()->name) {
-    case interface_control::kRunMessageId:
-      return ValidateMessagePayload<
-          interface_control::internal::RunResponseMessageParams_Data>(
-          message, &validation_context);
-  }
-  return false;
-}
-
-using RunCallback =
-    base::Callback<void(interface_control::RunResponseMessageParamsPtr)>;
+using RunCallback = base::Callback<void(QueryVersionResultPtr)>;
 
 class RunResponseForwardToCallback : public MessageReceiver {
  public:
-  explicit RunResponseForwardToCallback(const RunCallback& callback)
+  RunResponseForwardToCallback(const RunCallback& callback)
       : callback_(callback) {}
   bool Accept(Message* message) override;
 
@@ -54,83 +34,59 @@
 };
 
 bool RunResponseForwardToCallback::Accept(Message* message) {
-  if (!ValidateControlResponse(message))
-    return false;
-
-  interface_control::internal::RunResponseMessageParams_Data* params =
-      reinterpret_cast<
-          interface_control::internal::RunResponseMessageParams_Data*>(
+  RunResponseMessageParams_Data* params =
+      reinterpret_cast<RunResponseMessageParams_Data*>(
           message->mutable_payload());
-  interface_control::RunResponseMessageParamsPtr params_ptr;
+  RunResponseMessageParamsPtr params_ptr;
   SerializationContext context;
-  Deserialize<interface_control::RunResponseMessageParamsDataView>(
-      params, &params_ptr, &context);
+  Deserialize<RunResponseMessageParamsPtr>(params, &params_ptr, &context);
 
-  callback_.Run(std::move(params_ptr));
+  callback_.Run(std::move(params_ptr->query_version_result));
   return true;
 }
 
 void SendRunMessage(MessageReceiverWithResponder* receiver,
-                    interface_control::RunInputPtr input_ptr,
-                    const RunCallback& callback) {
-  SerializationContext context;
+                    QueryVersionPtr query_version,
+                    const RunCallback& callback,
+                    SerializationContext* context) {
+  RunMessageParamsPtr params_ptr(RunMessageParams::New());
+  params_ptr->reserved0 = 16u;
+  params_ptr->reserved1 = 0u;
+  params_ptr->query_version = std::move(query_version);
 
-  auto params_ptr = interface_control::RunMessageParams::New();
-  params_ptr->input = std::move(input_ptr);
-  size_t size = PrepareToSerialize<interface_control::RunMessageParamsDataView>(
-      params_ptr, &context);
-  MessageBuilder builder(interface_control::kRunMessageId,
-                         Message::kFlagExpectsResponse, size, 0);
+  size_t size = PrepareToSerialize<RunMessageParamsPtr>(params_ptr, context);
+  RequestMessageBuilder builder(kRunMessageId, size);
 
-  interface_control::internal::RunMessageParams_Data* params = nullptr;
-  Serialize<interface_control::RunMessageParamsDataView>(
-      params_ptr, builder.buffer(), &params, &context);
+  RunMessageParams_Data* params = nullptr;
+  Serialize<RunMessageParamsPtr>(params_ptr, builder.buffer(), &params,
+                                 context);
   MessageReceiver* responder = new RunResponseForwardToCallback(callback);
   if (!receiver->AcceptWithResponder(builder.message(), responder))
     delete responder;
 }
 
-Message ConstructRunOrClosePipeMessage(
-    interface_control::RunOrClosePipeInputPtr input_ptr) {
-  SerializationContext context;
+void SendRunOrClosePipeMessage(MessageReceiverWithResponder* receiver,
+                               RequireVersionPtr require_version,
+                               SerializationContext* context) {
+  RunOrClosePipeMessageParamsPtr params_ptr(RunOrClosePipeMessageParams::New());
+  params_ptr->reserved0 = 16u;
+  params_ptr->reserved1 = 0u;
+  params_ptr->require_version = std::move(require_version);
 
-  auto params_ptr = interface_control::RunOrClosePipeMessageParams::New();
-  params_ptr->input = std::move(input_ptr);
+  size_t size =
+      PrepareToSerialize<RunOrClosePipeMessageParamsPtr>(params_ptr, context);
+  MessageBuilder builder(kRunOrClosePipeMessageId, size);
 
-  size_t size = PrepareToSerialize<
-      interface_control::RunOrClosePipeMessageParamsDataView>(params_ptr,
-                                                              &context);
-  MessageBuilder builder(interface_control::kRunOrClosePipeMessageId, 0, size,
-                         0);
-
-  interface_control::internal::RunOrClosePipeMessageParams_Data* params =
-      nullptr;
-  Serialize<interface_control::RunOrClosePipeMessageParamsDataView>(
-      params_ptr, builder.buffer(), &params, &context);
-  return std::move(*builder.message());
-}
-
-void SendRunOrClosePipeMessage(
-    MessageReceiverWithResponder* receiver,
-    interface_control::RunOrClosePipeInputPtr input_ptr) {
-  Message message(ConstructRunOrClosePipeMessage(std::move(input_ptr)));
-
-  bool ok = receiver->Accept(&message);
+  RunOrClosePipeMessageParams_Data* params = nullptr;
+  Serialize<RunOrClosePipeMessageParamsPtr>(params_ptr, builder.buffer(),
+                                            &params, context);
+  bool ok = receiver->Accept(builder.message());
   ALLOW_UNUSED_LOCAL(ok);
 }
 
-void RunVersionCallback(
-    const base::Callback<void(uint32_t)>& callback,
-    interface_control::RunResponseMessageParamsPtr run_response) {
-  uint32_t version = 0u;
-  if (run_response->output && run_response->output->is_query_version_result())
-    version = run_response->output->get_query_version_result()->version;
-  callback.Run(version);
-}
-
-void RunClosure(const base::Closure& callback,
-                interface_control::RunResponseMessageParamsPtr run_response) {
-  callback.Run();
+void RunVersionCallback(const base::Callback<void(uint32_t)>& callback,
+                        QueryVersionResultPtr query_version_result) {
+  callback.Run(query_version_result->version);
 }
 
 }  // namespace
@@ -139,49 +95,16 @@
     : receiver_(receiver) {
 }
 
-ControlMessageProxy::~ControlMessageProxy() = default;
-
 void ControlMessageProxy::QueryVersion(
     const base::Callback<void(uint32_t)>& callback) {
-  auto input_ptr = interface_control::RunInput::New();
-  input_ptr->set_query_version(interface_control::QueryVersion::New());
-  SendRunMessage(receiver_, std::move(input_ptr),
-                 base::Bind(&RunVersionCallback, callback));
+  SendRunMessage(receiver_, QueryVersion::New(),
+                 base::Bind(&RunVersionCallback, callback), &context_);
 }
 
 void ControlMessageProxy::RequireVersion(uint32_t version) {
-  auto require_version = interface_control::RequireVersion::New();
+  RequireVersionPtr require_version(RequireVersion::New());
   require_version->version = version;
-  auto input_ptr = interface_control::RunOrClosePipeInput::New();
-  input_ptr->set_require_version(std::move(require_version));
-  SendRunOrClosePipeMessage(receiver_, std::move(input_ptr));
-}
-
-void ControlMessageProxy::FlushForTesting() {
-  if (encountered_error_)
-    return;
-
-  auto input_ptr = interface_control::RunInput::New();
-  input_ptr->set_flush_for_testing(interface_control::FlushForTesting::New());
-  base::RunLoop run_loop;
-  run_loop_quit_closure_ = run_loop.QuitClosure();
-  SendRunMessage(
-      receiver_, std::move(input_ptr),
-      base::Bind(&RunClosure,
-                 base::Bind(&ControlMessageProxy::RunFlushForTestingClosure,
-                            base::Unretained(this))));
-  run_loop.Run();
-}
-
-void ControlMessageProxy::RunFlushForTestingClosure() {
-  DCHECK(!run_loop_quit_closure_.is_null());
-  base::ResetAndReturn(&run_loop_quit_closure_).Run();
-}
-
-void ControlMessageProxy::OnConnectionError() {
-  encountered_error_ = true;
-  if (!run_loop_quit_closure_.is_null())
-    RunFlushForTestingClosure();
+  SendRunOrClosePipeMessage(receiver_, std::move(require_version), &context_);
 }
 
 }  // namespace internal
diff --git a/mojo/public/cpp/bindings/lib/control_message_proxy.h b/mojo/public/cpp/bindings/lib/control_message_proxy.h
index 2f9314e..5ec6ddc 100644
--- a/mojo/public/cpp/bindings/lib/control_message_proxy.h
+++ b/mojo/public/cpp/bindings/lib/control_message_proxy.h
@@ -7,9 +7,8 @@
 
 #include <stdint.h>
 
-#include "base/callback.h"
+#include "base/callback_forward.h"
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/lib/serialization_context.h"
 
 namespace mojo {
@@ -19,26 +18,18 @@
 namespace internal {
 
 // Proxy for request messages defined in interface_control_messages.mojom.
-class MOJO_CPP_BINDINGS_EXPORT ControlMessageProxy {
+class ControlMessageProxy {
  public:
   // Doesn't take ownership of |receiver|. It must outlive this object.
   explicit ControlMessageProxy(MessageReceiverWithResponder* receiver);
-  ~ControlMessageProxy();
 
   void QueryVersion(const base::Callback<void(uint32_t)>& callback);
   void RequireVersion(uint32_t version);
 
-  void FlushForTesting();
-  void OnConnectionError();
-
- private:
-  void RunFlushForTestingClosure();
-
+ protected:
   // Not owned.
   MessageReceiverWithResponder* receiver_;
-  bool encountered_error_ = false;
-
-  base::Closure run_loop_quit_closure_;
+  SerializationContext context_;
 
   DISALLOW_COPY_AND_ASSIGN(ControlMessageProxy);
 };
diff --git a/mojo/public/cpp/bindings/lib/equals_traits.h b/mojo/public/cpp/bindings/lib/equals_traits.h
deleted file mode 100644
index 53c7dce..0000000
--- a/mojo/public/cpp/bindings/lib/equals_traits.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_EQUALS_TRAITS_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_LIB_EQUALS_TRAITS_H_
-
-#include <type_traits>
-#include <unordered_map>
-#include <vector>
-
-#include "base/optional.h"
-#include "mojo/public/cpp/bindings/lib/template_util.h"
-
-namespace mojo {
-namespace internal {
-
-template <typename T>
-struct HasEqualsMethod {
-  template <typename U>
-  static char Test(decltype(&U::Equals));
-  template <typename U>
-  static int Test(...);
-  static const bool value = sizeof(Test<T>(0)) == sizeof(char);
-
- private:
-  EnsureTypeIsComplete<T> check_t_;
-};
-
-template <typename T, bool has_equals_method = HasEqualsMethod<T>::value>
-struct EqualsTraits;
-
-template <typename T>
-bool Equals(const T& a, const T& b);
-
-template <typename T>
-struct EqualsTraits<T, true> {
-  static bool Equals(const T& a, const T& b) { return a.Equals(b); }
-};
-
-template <typename T>
-struct EqualsTraits<T, false> {
-  static bool Equals(const T& a, const T& b) { return a == b; }
-};
-
-template <typename T>
-struct EqualsTraits<base::Optional<T>, false> {
-  static bool Equals(const base::Optional<T>& a, const base::Optional<T>& b) {
-    if (!a && !b)
-      return true;
-    if (!a || !b)
-      return false;
-
-    return internal::Equals(*a, *b);
-  }
-};
-
-template <typename T>
-struct EqualsTraits<std::vector<T>, false> {
-  static bool Equals(const std::vector<T>& a, const std::vector<T>& b) {
-    if (a.size() != b.size())
-      return false;
-    for (size_t i = 0; i < a.size(); ++i) {
-      if (!internal::Equals(a[i], b[i]))
-        return false;
-    }
-    return true;
-  }
-};
-
-template <typename K, typename V>
-struct EqualsTraits<std::unordered_map<K, V>, false> {
-  static bool Equals(const std::unordered_map<K, V>& a,
-                     const std::unordered_map<K, V>& b) {
-    if (a.size() != b.size())
-      return false;
-    for (const auto& element : a) {
-      auto iter = b.find(element.first);
-      if (iter == b.end() || !internal::Equals(element.second, iter->second))
-        return false;
-    }
-    return true;
-  }
-};
-
-template <typename T>
-bool Equals(const T& a, const T& b) {
-  return EqualsTraits<T>::Equals(a, b);
-}
-
-}  // namespace internal
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_EQUALS_TRAITS_H_
diff --git a/mojo/public/cpp/bindings/lib/filter_chain.cc b/mojo/public/cpp/bindings/lib/filter_chain.cc
index 5d919fe..899bac1 100644
--- a/mojo/public/cpp/bindings/lib/filter_chain.cc
+++ b/mojo/public/cpp/bindings/lib/filter_chain.cc
@@ -2,13 +2,14 @@
 // 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/filter_chain.h"
+#include "mojo/public/cpp/bindings/lib/filter_chain.h"
 
 #include <algorithm>
 
 #include "base/logging.h"
 
 namespace mojo {
+namespace internal {
 
 FilterChain::FilterChain(MessageReceiver* sink) : sink_(sink) {
 }
@@ -25,23 +26,24 @@
 }
 
 FilterChain::~FilterChain() {
+  for (std::vector<MessageFilter*>::iterator iter = filters_.begin();
+       iter != filters_.end();
+       ++iter) {
+    delete *iter;
+  }
 }
 
 void FilterChain::SetSink(MessageReceiver* sink) {
   DCHECK(!sink_);
   sink_ = sink;
+  if (!filters_.empty())
+    filters_.back()->set_sink(sink);
 }
 
-bool FilterChain::Accept(Message* message) {
+MessageReceiver* FilterChain::GetHead() {
   DCHECK(sink_);
-  for (auto& filter : filters_)
-    if (!filter->Accept(message))
-      return false;
-  return sink_->Accept(message);
+  return filters_.empty() ? sink_ : filters_.front();
 }
 
-void FilterChain::Append(std::unique_ptr<MessageReceiver> filter) {
-  filters_.emplace_back(std::move(filter));
-}
-
+}  // 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..447be3d
--- /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 <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/bindings/message_filter.h"
+
+namespace mojo {
+namespace internal {
+
+class FilterChain {
+ public:
+  // Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while
+  // this object is alive.
+  explicit FilterChain(MessageReceiver* sink = nullptr);
+
+  FilterChain(FilterChain&& other);
+  FilterChain& operator=(FilterChain&& other);
+  ~FilterChain();
+
+  template <typename FilterType, typename... Args>
+  inline void Append(Args&&... args);
+
+  // 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.
+  // TODO(dcheng): Use unique_ptr.
+  std::vector<MessageFilter*> filters_;
+
+  MessageReceiver* sink_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilterChain);
+};
+
+template <typename FilterType, typename... Args>
+inline void FilterChain::Append(Args&&... args) {
+  FilterType* filter = new FilterType(std::forward<Args>(args)..., 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
index 725a193..50b8a21 100644
--- a/mojo/public/cpp/bindings/lib/fixed_buffer.cc
+++ b/mojo/public/cpp/bindings/lib/fixed_buffer.cc
@@ -4,25 +4,56 @@
 
 #include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
 
+#include <stddef.h>
 #include <stdlib.h>
 
+#include <algorithm>
+
+#include "base/logging.h"
+#include "mojo/public/cpp/bindings/lib/serialization_util.h"
+
 namespace mojo {
 namespace internal {
 
+FixedBuffer::FixedBuffer() : ptr_(nullptr), cursor_(0), size_(0) {}
+
+void FixedBuffer::Initialize(void* memory, size_t size) {
+  DCHECK(size == internal::Align(size));
+
+  ptr_ = static_cast<char*>(memory);
+  cursor_ = 0;
+  size_ = size;
+}
+
+void* FixedBuffer::Allocate(size_t delta) {
+  delta = internal::Align(delta);
+
+  if (delta == 0 || delta > size_ - cursor_) {
+    NOTREACHED();
+    return nullptr;
+  }
+
+  char* result = ptr_ + cursor_;
+  cursor_ += delta;
+
+  return result;
+}
+
 FixedBufferForTesting::FixedBufferForTesting(size_t size) {
-  size = internal::Align(size);
+  size_ = internal::Align(size);
   // Use calloc here to ensure all message memory is zero'd out.
-  void* ptr = calloc(size, 1);
-  Initialize(ptr, size);
+  ptr_ = static_cast<char*>(calloc(size_, 1));
 }
 
 FixedBufferForTesting::~FixedBufferForTesting() {
-  free(data());
+  free(ptr_);
 }
 
 void* FixedBufferForTesting::Leak() {
-  void* ptr = data();
-  Initialize(nullptr, 0);
+  char* ptr = ptr_;
+  ptr_ = nullptr;
+  cursor_ = 0;
+  size_ = 0;
   return ptr;
 }
 
diff --git a/mojo/public/cpp/bindings/lib/fixed_buffer.h b/mojo/public/cpp/bindings/lib/fixed_buffer.h
index 070b0c8..9a5704b 100644
--- a/mojo/public/cpp/bindings/lib/fixed_buffer.h
+++ b/mojo/public/cpp/bindings/lib/fixed_buffer.h
@@ -7,21 +7,62 @@
 
 #include <stddef.h>
 
-#include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/lib/buffer.h"
 
 namespace mojo {
 namespace internal {
 
-// FixedBufferForTesting owns its buffer. The Leak method may be used to steal
-// the underlying memory.
-class MOJO_CPP_BINDINGS_EXPORT FixedBufferForTesting
-    : NON_EXPORTED_BASE(public Buffer) {
+// 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:
+  FixedBuffer();
+
+  // |size| should be aligned using internal::Align.
+  void Initialize(void* memory, size_t size);
+
+  size_t size() const { return size_; }
+
+  // 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.
+  void* Allocate(size_t num_bytes) override;
+
+ protected:
+  char* ptr_;
+  size_t cursor_;
+  size_t size_;
+
+  DISALLOW_COPY_AND_ASSIGN(FixedBuffer);
+};
+
+class FixedBufferForTesting : public FixedBuffer {
  public:
   explicit FixedBufferForTesting(size_t size);
-  ~FixedBufferForTesting();
+  ~FixedBufferForTesting() override;
 
   // Returns the internal memory owned by the Buffer to the caller. The Buffer
   // relinquishes its pointer, effectively resetting the state of the Buffer
diff --git a/mojo/public/cpp/bindings/lib/handle_interface_serialization.h b/mojo/public/cpp/bindings/lib/handle_interface_serialization.h
index 14ed21f..344c2ca 100644
--- a/mojo/public/cpp/bindings/lib/handle_interface_serialization.h
+++ b/mojo/public/cpp/bindings/lib/handle_interface_serialization.h
@@ -5,12 +5,9 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_HANDLE_INTERFACE_SERIALIZATION_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_HANDLE_INTERFACE_SERIALIZATION_H_
 
-#include <type_traits>
-
 #include "mojo/public/cpp/bindings/associated_group_controller.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
 #include "mojo/public/cpp/bindings/associated_interface_request.h"
-#include "mojo/public/cpp/bindings/interface_data_view.h"
 #include "mojo/public/cpp/bindings/interface_ptr.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
@@ -21,98 +18,52 @@
 namespace mojo {
 namespace internal {
 
-template <typename Base, typename T>
-struct Serializer<AssociatedInterfacePtrInfoDataView<Base>,
+template <typename T>
+struct Serializer<AssociatedInterfacePtrInfo<T>,
                   AssociatedInterfacePtrInfo<T>> {
-  static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch.");
-
-  static size_t PrepareToSerialize(const AssociatedInterfacePtrInfo<T>& input,
-                                   SerializationContext* context) {
-    if (input.handle().is_valid())
-      context->associated_endpoint_count++;
-    return 0;
-  }
-
   static void Serialize(AssociatedInterfacePtrInfo<T>& input,
                         AssociatedInterface_Data* output,
                         SerializationContext* context) {
-    DCHECK(!input.handle().is_valid() || input.handle().pending_association());
-    if (input.handle().is_valid()) {
-      // Set to the index of the element pushed to the back of the vector.
-      output->handle.value =
-          static_cast<uint32_t>(context->associated_endpoint_handles.size());
-      context->associated_endpoint_handles.push_back(input.PassHandle());
-    } else {
-      output->handle.value = kEncodedInvalidHandleValue;
-    }
+    DCHECK(!input.handle().is_valid() || !input.handle().is_local());
+    DCHECK_EQ(input.handle().group_controller(),
+              context->group_controller.get());
     output->version = input.version();
+    output->interface_id = input.PassHandle().release();
   }
 
   static bool Deserialize(AssociatedInterface_Data* input,
                           AssociatedInterfacePtrInfo<T>* output,
                           SerializationContext* context) {
-    if (input->handle.is_valid()) {
-      DCHECK_LT(input->handle.value,
-                context->associated_endpoint_handles.size());
-      output->set_handle(
-          std::move(context->associated_endpoint_handles[input->handle.value]));
-    } else {
-      output->set_handle(ScopedInterfaceEndpointHandle());
-    }
+    output->set_handle(context->group_controller->CreateLocalEndpointHandle(
+        FetchAndReset(&input->interface_id)));
     output->set_version(input->version);
     return true;
   }
 };
 
-template <typename Base, typename T>
-struct Serializer<AssociatedInterfaceRequestDataView<Base>,
+template <typename T>
+struct Serializer<AssociatedInterfaceRequest<T>,
                   AssociatedInterfaceRequest<T>> {
-  static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch.");
-
-  static size_t PrepareToSerialize(const AssociatedInterfaceRequest<T>& input,
-                                   SerializationContext* context) {
-    if (input.handle().is_valid())
-      context->associated_endpoint_count++;
-    return 0;
-  }
-
   static void Serialize(AssociatedInterfaceRequest<T>& input,
-                        AssociatedEndpointHandle_Data* output,
+                        AssociatedInterfaceRequest_Data* output,
                         SerializationContext* context) {
-    DCHECK(!input.handle().is_valid() || input.handle().pending_association());
-    if (input.handle().is_valid()) {
-      // Set to the index of the element pushed to the back of the vector.
-      output->value =
-          static_cast<uint32_t>(context->associated_endpoint_handles.size());
-      context->associated_endpoint_handles.push_back(input.PassHandle());
-    } else {
-      output->value = kEncodedInvalidHandleValue;
-    }
+    DCHECK(!input.handle().is_valid() || !input.handle().is_local());
+    DCHECK_EQ(input.handle().group_controller(),
+              context->group_controller.get());
+    output->interface_id = input.PassHandle().release();
   }
 
-  static bool Deserialize(AssociatedEndpointHandle_Data* input,
+  static bool Deserialize(AssociatedInterfaceRequest_Data* input,
                           AssociatedInterfaceRequest<T>* output,
                           SerializationContext* context) {
-    if (input->is_valid()) {
-      DCHECK_LT(input->value, context->associated_endpoint_handles.size());
-      output->Bind(
-          std::move(context->associated_endpoint_handles[input->value]));
-    } else {
-      output->Bind(ScopedInterfaceEndpointHandle());
-    }
+    output->Bind(context->group_controller->CreateLocalEndpointHandle(
+        FetchAndReset(&input->interface_id)));
     return true;
   }
 };
 
-template <typename Base, typename T>
-struct Serializer<InterfacePtrDataView<Base>, InterfacePtr<T>> {
-  static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch.");
-
-  static size_t PrepareToSerialize(const InterfacePtr<T>& input,
-                                   SerializationContext* context) {
-    return 0;
-  }
-
+template <typename T>
+struct Serializer<InterfacePtr<T>, InterfacePtr<T>> {
   static void Serialize(InterfacePtr<T>& input,
                         Interface_Data* output,
                         SerializationContext* context) {
@@ -131,15 +82,8 @@
   }
 };
 
-template <typename Base, typename T>
-struct Serializer<InterfaceRequestDataView<Base>, InterfaceRequest<T>> {
-  static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch.");
-
-  static size_t PrepareToSerialize(const InterfaceRequest<T>& input,
-                                   SerializationContext* context) {
-    return 0;
-  }
-
+template <typename T>
+struct Serializer<InterfaceRequest<T>, InterfaceRequest<T>> {
   static void Serialize(InterfaceRequest<T>& input,
                         Handle_Data* output,
                         SerializationContext* context) {
@@ -156,11 +100,6 @@
 
 template <typename T>
 struct Serializer<ScopedHandleBase<T>, ScopedHandleBase<T>> {
-  static size_t PrepareToSerialize(const ScopedHandleBase<T>& input,
-                                   SerializationContext* context) {
-    return 0;
-  }
-
   static void Serialize(ScopedHandleBase<T>& input,
                         Handle_Data* output,
                         SerializationContext* context) {
diff --git a/mojo/public/cpp/bindings/lib/hash_util.h b/mojo/public/cpp/bindings/lib/hash_util.h
deleted file mode 100644
index 93280d6..0000000
--- a/mojo/public/cpp/bindings/lib/hash_util.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_HASH_UTIL_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_LIB_HASH_UTIL_H_
-
-#include <cstring>
-#include <functional>
-#include <type_traits>
-#include <vector>
-
-#include "base/optional.h"
-#include "mojo/public/cpp/bindings/lib/template_util.h"
-
-namespace mojo {
-namespace internal {
-
-template <typename T>
-size_t HashCombine(size_t seed, const T& value) {
-  // Based on proposal in:
-  // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
-  return seed ^ (std::hash<T>()(value) + (seed << 6) + (seed >> 2));
-}
-
-template <typename T>
-struct HasHashMethod {
-  template <typename U>
-  static char Test(decltype(&U::Hash));
-  template <typename U>
-  static int Test(...);
-  static const bool value = sizeof(Test<T>(0)) == sizeof(char);
-
- private:
-  EnsureTypeIsComplete<T> check_t_;
-};
-
-template <typename T, bool has_hash_method = HasHashMethod<T>::value>
-struct HashTraits;
-
-template <typename T>
-size_t Hash(size_t seed, const T& value);
-
-template <typename T>
-struct HashTraits<T, true> {
-  static size_t Hash(size_t seed, const T& value) { return value.Hash(seed); }
-};
-
-template <typename T>
-struct HashTraits<T, false> {
-  static size_t Hash(size_t seed, const T& value) {
-    return HashCombine(seed, value);
-  }
-};
-
-template <typename T>
-struct HashTraits<std::vector<T>, false> {
-  static size_t Hash(size_t seed, const std::vector<T>& value) {
-    for (const auto& element : value) {
-      seed = HashCombine(seed, element);
-    }
-    return seed;
-  }
-};
-
-template <typename T>
-struct HashTraits<base::Optional<std::vector<T>>, false> {
-  static size_t Hash(size_t seed, const base::Optional<std::vector<T>>& value) {
-    if (!value)
-      return HashCombine(seed, 0);
-
-    return Hash(seed, *value);
-  }
-};
-
-template <typename T>
-size_t Hash(size_t seed, const T& value) {
-  return HashTraits<T>::Hash(seed, value);
-}
-
-}  // namespace internal
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_HASH_UTIL_H_
diff --git a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
index 3eca5a1..e1f388a 100644
--- a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
+++ b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
@@ -10,7 +10,6 @@
 
 #include "base/bind.h"
 #include "base/location.h"
-#include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
@@ -18,7 +17,6 @@
 #include "mojo/public/cpp/bindings/associated_group.h"
 #include "mojo/public/cpp/bindings/associated_group_controller.h"
 #include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
-#include "mojo/public/cpp/bindings/lib/validation_util.h"
 #include "mojo/public/cpp/bindings/sync_call_restrictions.h"
 
 namespace mojo {
@@ -47,7 +45,7 @@
         task_runner_(std::move(runner)) {}
   ~ResponderThunk() override {
     if (!accept_was_invoked_) {
-      // The Service handled a message that was expecting a response
+      // The Mojo application handled a message that was expecting a response
       // but did not send a response.
       // We raise an error to signal the calling application that an error
       // condition occurred. Without this the calling application would have no
@@ -134,47 +132,47 @@
 InterfaceEndpointClient::InterfaceEndpointClient(
     ScopedInterfaceEndpointHandle handle,
     MessageReceiverWithResponderStatus* receiver,
-    std::unique_ptr<MessageReceiver> payload_validator,
+    std::unique_ptr<MessageFilter> payload_validator,
     bool expect_sync_requests,
-    scoped_refptr<base::SingleThreadTaskRunner> runner,
-    uint32_t interface_version)
-    : expect_sync_requests_(expect_sync_requests),
-      handle_(std::move(handle)),
+    scoped_refptr<base::SingleThreadTaskRunner> runner)
+    : handle_(std::move(handle)),
       incoming_receiver_(receiver),
+      payload_validator_(std::move(payload_validator)),
       thunk_(this),
-      filters_(&thunk_),
+      next_request_id_(1),
+      encountered_error_(false),
       task_runner_(std::move(runner)),
-      control_message_proxy_(this),
-      control_message_handler_(interface_version),
       weak_ptr_factory_(this) {
   DCHECK(handle_.is_valid());
+  DCHECK(handle_.is_local());
 
   // TODO(yzshen): the way to use validator (or message filter in general)
   // directly is a little awkward.
-  if (payload_validator)
-    filters_.Append(std::move(payload_validator));
+  payload_validator_->set_sink(&thunk_);
 
-  if (handle_.pending_association()) {
-    handle_.SetAssociationEventHandler(base::Bind(
-        &InterfaceEndpointClient::OnAssociationEvent, base::Unretained(this)));
-  } else {
-    InitControllerIfNecessary();
-  }
+  controller_ = handle_.group_controller()->AttachEndpointClient(
+      handle_, this, task_runner_);
+  if (expect_sync_requests)
+    controller_->AllowWokenUpBySyncWatchOnSameThread();
 }
 
 InterfaceEndpointClient::~InterfaceEndpointClient() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (controller_)
-    handle_.group_controller()->DetachEndpointClient(handle_);
+  handle_.group_controller()->DetachEndpointClient(handle_);
 }
 
 AssociatedGroup* InterfaceEndpointClient::associated_group() {
   if (!associated_group_)
-    associated_group_ = base::MakeUnique<AssociatedGroup>(handle_);
+    associated_group_ = handle_.group_controller()->CreateAssociatedGroup();
   return associated_group_.get();
 }
 
+uint32_t InterfaceEndpointClient::interface_id() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return handle_.id();
+}
+
 ScopedInterfaceEndpointHandle InterfaceEndpointClient::PassHandle() {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!has_pending_responders());
@@ -182,73 +180,38 @@
   if (!handle_.is_valid())
     return ScopedInterfaceEndpointHandle();
 
-  handle_.SetAssociationEventHandler(
-      ScopedInterfaceEndpointHandle::AssociationEventCallback());
-
-  if (controller_) {
-    controller_ = nullptr;
-    handle_.group_controller()->DetachEndpointClient(handle_);
-  }
+  controller_ = nullptr;
+  handle_.group_controller()->DetachEndpointClient(handle_);
 
   return std::move(handle_);
 }
 
-void InterfaceEndpointClient::AddFilter(
-    std::unique_ptr<MessageReceiver> filter) {
-  filters_.Append(std::move(filter));
-}
-
 void InterfaceEndpointClient::RaiseError() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (!handle_.pending_association())
-    handle_.group_controller()->RaiseError();
-}
-
-void InterfaceEndpointClient::CloseWithReason(uint32_t custom_reason,
-                                              const std::string& description) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  auto handle = PassHandle();
-  handle.ResetWithReason(custom_reason, description);
+  handle_.group_controller()->RaiseError();
 }
 
 bool InterfaceEndpointClient::Accept(Message* message) {
   DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(controller_);
   DCHECK(!message->has_flag(Message::kFlagExpectsResponse));
-  DCHECK(!handle_.pending_association());
-
-  // This has to been done even if connection error has occurred. For example,
-  // the message contains a pending associated request. The user may try to use
-  // the corresponding associated interface pointer after sending this message.
-  // That associated interface pointer has to join an associated group in order
-  // to work properly.
-  if (!message->associated_endpoint_handles()->empty())
-    message->SerializeAssociatedEndpointHandles(handle_.group_controller());
 
   if (encountered_error_)
     return false;
 
-  InitControllerIfNecessary();
-
   return controller_->SendMessage(message);
 }
 
 bool InterfaceEndpointClient::AcceptWithResponder(Message* message,
                                                   MessageReceiver* responder) {
   DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(controller_);
   DCHECK(message->has_flag(Message::kFlagExpectsResponse));
-  DCHECK(!handle_.pending_association());
-
-  // Please see comments in Accept().
-  if (!message->associated_endpoint_handles()->empty())
-    message->SerializeAssociatedEndpointHandles(handle_.group_controller());
 
   if (encountered_error_)
     return false;
 
-  InitControllerIfNecessary();
-
   // 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)
@@ -271,18 +234,20 @@
   bool response_received = false;
   std::unique_ptr<MessageReceiver> sync_responder(responder);
   sync_responses_.insert(std::make_pair(
-      request_id, base::MakeUnique<SyncResponseInfo>(&response_received)));
+      request_id, base::WrapUnique(new SyncResponseInfo(&response_received))));
 
   base::WeakPtr<InterfaceEndpointClient> weak_self =
       weak_ptr_factory_.GetWeakPtr();
   controller_->SyncWatch(&response_received);
   // Make sure that this instance hasn't been destroyed.
   if (weak_self) {
-    DCHECK(base::ContainsKey(sync_responses_, request_id));
+    DCHECK(ContainsKey(sync_responses_, request_id));
     auto iter = sync_responses_.find(request_id);
     DCHECK_EQ(&response_received, iter->second->response_received);
-    if (response_received)
-      ignore_result(sync_responder->Accept(&iter->second->response));
+    if (response_received) {
+      std::unique_ptr<Message> response = std::move(iter->second->response);
+      ignore_result(sync_responder->Accept(response.get()));
+    }
     sync_responses_.erase(iter);
   }
 
@@ -292,97 +257,30 @@
 
 bool InterfaceEndpointClient::HandleIncomingMessage(Message* message) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  return filters_.Accept(message);
+
+  return payload_validator_->Accept(message);
 }
 
-void InterfaceEndpointClient::NotifyError(
-    const base::Optional<DisconnectReason>& reason) {
+void InterfaceEndpointClient::NotifyError() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   if (encountered_error_)
     return;
   encountered_error_ = true;
-
-  // Response callbacks may hold on to resource, and there's no need to keep
-  // them alive any longer. Note that it's allowed that a pending response
-  // callback may own this endpoint, so we simply move the responders onto the
-  // stack here and let them be destroyed when the stack unwinds.
-  AsyncResponderMap responders = std::move(async_responders_);
-
-  control_message_proxy_.OnConnectionError();
-
-  if (!error_handler_.is_null()) {
-    base::Closure error_handler = std::move(error_handler_);
-    error_handler.Run();
-  } else if (!error_with_reason_handler_.is_null()) {
-    ConnectionErrorWithReasonCallback error_with_reason_handler =
-        std::move(error_with_reason_handler_);
-    if (reason) {
-      error_with_reason_handler.Run(reason->custom_reason, reason->description);
-    } else {
-      error_with_reason_handler.Run(0, std::string());
-    }
-  }
-}
-
-void InterfaceEndpointClient::QueryVersion(
-    const base::Callback<void(uint32_t)>& callback) {
-  control_message_proxy_.QueryVersion(callback);
-}
-
-void InterfaceEndpointClient::RequireVersion(uint32_t version) {
-  control_message_proxy_.RequireVersion(version);
-}
-
-void InterfaceEndpointClient::FlushForTesting() {
-  control_message_proxy_.FlushForTesting();
-}
-
-void InterfaceEndpointClient::InitControllerIfNecessary() {
-  if (controller_ || handle_.pending_association())
-    return;
-
-  controller_ = handle_.group_controller()->AttachEndpointClient(handle_, this,
-                                                                 task_runner_);
-  if (expect_sync_requests_)
-    controller_->AllowWokenUpBySyncWatchOnSameThread();
-}
-
-void InterfaceEndpointClient::OnAssociationEvent(
-    ScopedInterfaceEndpointHandle::AssociationEvent event) {
-  if (event == ScopedInterfaceEndpointHandle::ASSOCIATED) {
-    InitControllerIfNecessary();
-  } else if (event ==
-             ScopedInterfaceEndpointHandle::PEER_CLOSED_BEFORE_ASSOCIATION) {
-    task_runner_->PostTask(FROM_HERE,
-                           base::Bind(&InterfaceEndpointClient::NotifyError,
-                                      weak_ptr_factory_.GetWeakPtr(),
-                                      handle_.disconnect_reason()));
-  }
+  if (!error_handler_.is_null())
+    error_handler_.Run();
 }
 
 bool InterfaceEndpointClient::HandleValidatedMessage(Message* message) {
   DCHECK_EQ(handle_.id(), message->interface_id());
 
-  if (encountered_error_) {
-    // This message is received after error has been encountered. For associated
-    // interfaces, this means the remote side sends a
-    // PeerAssociatedEndpointClosed event but continues to send more messages
-    // for the same interface. Close the pipe because this shouldn't happen.
-    DVLOG(1) << "A message is received for an interface after it has been "
-             << "disconnected. Closing the pipe.";
-    return false;
-  }
-
   if (message->has_flag(Message::kFlagExpectsResponse)) {
+    if (!incoming_receiver_)
+      return false;
+
     MessageReceiverWithStatus* responder =
         new ResponderThunk(weak_ptr_factory_.GetWeakPtr(), task_runner_);
-    bool ok = false;
-    if (mojo::internal::ControlMessageHandler::IsControlMessage(message)) {
-      ok = control_message_handler_.AcceptWithResponder(message, responder);
-    } else {
-      ok = incoming_receiver_->AcceptWithResponder(message, responder);
-    }
+    bool ok = incoming_receiver_->AcceptWithResponder(message, responder);
     if (!ok)
       delete responder;
     return ok;
@@ -393,7 +291,8 @@
       auto it = sync_responses_.find(request_id);
       if (it == sync_responses_.end())
         return false;
-      it->second->response = std::move(*message);
+      it->second->response.reset(new Message());
+      message->MoveTo(it->second->response.get());
       *it->second->response_received = true;
       return true;
     }
@@ -405,8 +304,8 @@
     async_responders_.erase(it);
     return responder->Accept(message);
   } else {
-    if (mojo::internal::ControlMessageHandler::IsControlMessage(message))
-      return control_message_handler_.Accept(message);
+    if (!incoming_receiver_)
+      return false;
 
     return incoming_receiver_->Accept(message);
   }
diff --git a/mojo/public/cpp/bindings/lib/interface_ptr_state.h b/mojo/public/cpp/bindings/lib/interface_ptr_state.h
index 8f5b4ff..584933e 100644
--- a/mojo/public/cpp/bindings/lib/interface_ptr_state.h
+++ b/mojo/public/cpp/bindings/lib/interface_ptr_state.h
@@ -9,7 +9,6 @@
 
 #include <algorithm>  // For |std::swap()|.
 #include <memory>
-#include <string>
 #include <utility>
 
 #include "base/bind.h"
@@ -20,20 +19,174 @@
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "mojo/public/cpp/bindings/associated_group.h"
-#include "mojo/public/cpp/bindings/connection_error_callback.h"
-#include "mojo/public/cpp/bindings/filter_chain.h"
 #include "mojo/public/cpp/bindings/interface_endpoint_client.h"
 #include "mojo/public/cpp/bindings/interface_id.h"
 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
+#include "mojo/public/cpp/bindings/lib/control_message_proxy.h"
+#include "mojo/public/cpp/bindings/lib/filter_chain.h"
 #include "mojo/public/cpp/bindings/lib/multiplex_router.h"
+#include "mojo/public/cpp/bindings/lib/router.h"
 #include "mojo/public/cpp/bindings/message_header_validator.h"
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 
 namespace mojo {
 namespace internal {
 
+template <typename Interface, bool use_multiplex_router>
+class InterfacePtrState;
+
+// Uses a single-threaded, dedicated router. If |Interface| doesn't have any
+// methods to pass associated interface pointers or requests, there won't be
+// multiple interfaces running on the underlying message pipe. In that case, we
+// can use this specialization to reduce cost.
 template <typename Interface>
-class InterfacePtrState {
+class InterfacePtrState<Interface, false> {
+ public:
+  InterfacePtrState() : proxy_(nullptr), router_(nullptr), version_(0u) {}
+
+  ~InterfacePtrState() {
+    // Destruction order matters here. We delete |proxy_| first, even though
+    // |router_| may have a reference to it, so that destructors for any request
+    // callbacks still pending can interact with the InterfacePtr.
+    delete proxy_;
+    delete router_;
+  }
+
+  Interface* instance() {
+    ConfigureProxyIfNecessary();
+
+    // This will be null if the object is not bound.
+    return proxy_;
+  }
+
+  uint32_t version() const { return version_; }
+
+  void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
+    ConfigureProxyIfNecessary();
+
+    // Do a static cast in case the interface contains methods with the same
+    // name. It is safe to capture |this| because the callback won't be run
+    // after this object goes away.
+    static_cast<ControlMessageProxy*>(proxy_)->QueryVersion(
+        base::Bind(&InterfacePtrState::OnQueryVersion, base::Unretained(this),
+                   callback));
+  }
+
+  void RequireVersion(uint32_t version) {
+    ConfigureProxyIfNecessary();
+
+    if (version <= version_)
+      return;
+
+    version_ = version;
+    // Do a static cast in case the interface contains methods with the same
+    // name.
+    static_cast<ControlMessageProxy*>(proxy_)->RequireVersion(version);
+  }
+
+  void Swap(InterfacePtrState* other) {
+    using std::swap;
+    swap(other->proxy_, proxy_);
+    swap(other->router_, router_);
+    handle_.swap(other->handle_);
+    runner_.swap(other->runner_);
+    swap(other->version_, version_);
+  }
+
+  void Bind(InterfacePtrInfo<Interface> info,
+            scoped_refptr<base::SingleThreadTaskRunner> runner) {
+    DCHECK(!proxy_);
+    DCHECK(!router_);
+    DCHECK(!handle_.is_valid());
+    DCHECK_EQ(0u, version_);
+    DCHECK(info.is_valid());
+
+    handle_ = info.PassHandle();
+    version_ = info.version();
+    runner_ = std::move(runner);
+  }
+
+  bool HasAssociatedInterfaces() const { return false; }
+
+  // After this method is called, the object is in an invalid state and
+  // shouldn't be reused.
+  InterfacePtrInfo<Interface> PassInterface() {
+    return InterfacePtrInfo<Interface>(
+        router_ ? router_->PassMessagePipe() : std::move(handle_), version_);
+  }
+
+  bool is_bound() const { return handle_.is_valid() || router_; }
+
+  bool encountered_error() const {
+    return router_ ? router_->encountered_error() : false;
+  }
+
+  void set_connection_error_handler(const base::Closure& error_handler) {
+    ConfigureProxyIfNecessary();
+
+    DCHECK(router_);
+    router_->set_connection_error_handler(error_handler);
+  }
+
+  // Returns true if bound and awaiting a response to a message.
+  bool has_pending_callbacks() const {
+    return router_ && router_->has_pending_responders();
+  }
+
+  AssociatedGroup* associated_group() { return nullptr; }
+
+  void EnableTestingMode() {
+    ConfigureProxyIfNecessary();
+    router_->EnableTestingMode();
+  }
+
+ private:
+  using Proxy = typename Interface::Proxy_;
+
+  void ConfigureProxyIfNecessary() {
+    // The proxy has been configured.
+    if (proxy_) {
+      DCHECK(router_);
+      return;
+    }
+    // The object hasn't been bound.
+    if (!handle_.is_valid())
+      return;
+
+    FilterChain filters;
+    filters.Append<MessageHeaderValidator>(Interface::Name_);
+    filters.Append<typename Interface::ResponseValidator_>();
+
+    router_ = new Router(std::move(handle_), std::move(filters), false,
+                         std::move(runner_));
+
+    proxy_ = new Proxy(router_);
+  }
+
+  void OnQueryVersion(const base::Callback<void(uint32_t)>& callback,
+                      uint32_t version) {
+    version_ = version;
+    callback.Run(version);
+  }
+
+  Proxy* proxy_;
+  Router* router_;
+
+  // |proxy_| and |router_| are not initialized until read/write with the
+  // message pipe handle is needed. |handle_| is valid between the Bind() call
+  // and the initialization of |proxy_| and |router_|.
+  ScopedMessagePipeHandle handle_;
+  scoped_refptr<base::SingleThreadTaskRunner> runner_;
+
+  uint32_t version_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterfacePtrState);
+};
+
+// Uses a multiplexing router. If |Interface| has methods to pass associated
+// interface pointers or requests, this specialization should be used.
+template <typename Interface>
+class InterfacePtrState<Interface, true> {
  public:
   InterfacePtrState() : version_(0u) {}
 
@@ -56,10 +209,13 @@
   void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
     ConfigureProxyIfNecessary();
 
-    // It is safe to capture |this| because the callback won't be run after this
-    // object goes away.
-    endpoint_client_->QueryVersion(base::Bind(
-        &InterfacePtrState::OnQueryVersion, base::Unretained(this), callback));
+
+    // Do a static cast in case the interface contains methods with the same
+    // name. It is safe to capture |this| because the callback won't be run
+    // after this object goes away.
+    static_cast<ControlMessageProxy*>(proxy_.get())->QueryVersion(
+        base::Bind(&InterfacePtrState::OnQueryVersion, base::Unretained(this),
+                   callback));
   }
 
   void RequireVersion(uint32_t version) {
@@ -69,17 +225,9 @@
       return;
 
     version_ = version;
-    endpoint_client_->RequireVersion(version);
-  }
-
-  void FlushForTesting() {
-    ConfigureProxyIfNecessary();
-    endpoint_client_->FlushForTesting();
-  }
-
-  void CloseWithReason(uint32_t custom_reason, const std::string& description) {
-    ConfigureProxyIfNecessary();
-    endpoint_client_->CloseWithReason(custom_reason, description);
+    // Do a static cast in case the interface contains methods with the same
+    // name.
+    static_cast<ControlMessageProxy*>(proxy_.get())->RequireVersion(version);
   }
 
   void Swap(InterfacePtrState* other) {
@@ -132,14 +280,6 @@
     endpoint_client_->set_connection_error_handler(error_handler);
   }
 
-  void set_connection_error_with_reason_handler(
-      const ConnectionErrorWithReasonCallback& error_handler) {
-    ConfigureProxyIfNecessary();
-
-    DCHECK(endpoint_client_);
-    endpoint_client_->set_connection_error_with_reason_handler(error_handler);
-  }
-
   // Returns true if bound and awaiting a response to a message.
   bool has_pending_callbacks() const {
     return endpoint_client_ && endpoint_client_->has_pending_responders();
@@ -155,17 +295,6 @@
     router_->EnableTestingMode();
   }
 
-  void ForwardMessage(Message message) {
-    ConfigureProxyIfNecessary();
-    endpoint_client_->Accept(&message);
-  }
-
-  void ForwardMessageWithResponder(Message message,
-                                   std::unique_ptr<MessageReceiver> responder) {
-    ConfigureProxyIfNecessary();
-    endpoint_client_->AcceptWithResponder(&message, responder.release());
-  }
-
  private:
   using Proxy = typename Interface::Proxy_;
 
@@ -180,22 +309,15 @@
     if (!handle_.is_valid())
       return;
 
-    MultiplexRouter::Config config =
-        Interface::PassesAssociatedKinds_
-            ? MultiplexRouter::MULTI_INTERFACE
-            : (Interface::HasSyncMethods_
-                   ? MultiplexRouter::SINGLE_INTERFACE_WITH_SYNC_METHODS
-                   : MultiplexRouter::SINGLE_INTERFACE);
-    router_ = new MultiplexRouter(std::move(handle_), config, true, runner_);
+    router_ = new MultiplexRouter(true, std::move(handle_), runner_);
     router_->SetMasterInterfaceName(Interface::Name_);
     endpoint_client_.reset(new InterfaceEndpointClient(
         router_->CreateLocalEndpointHandle(kMasterInterfaceId), nullptr,
         base::WrapUnique(new typename Interface::ResponseValidator_()), false,
-        std::move(runner_),
-        // The version is only queried from the client so the value passed here
-        // will not be used.
-        0u));
+        std::move(runner_)));
     proxy_.reset(new Proxy(endpoint_client_.get()));
+    proxy_->serialization_context()->group_controller =
+        endpoint_client_->group_controller();
   }
 
   void OnQueryVersion(const base::Callback<void(uint32_t)>& callback,
diff --git a/mojo/public/cpp/bindings/lib/map_serialization.h b/mojo/public/cpp/bindings/lib/map_serialization.h
index 718a763..c28b835 100644
--- a/mojo/public/cpp/bindings/lib/map_serialization.h
+++ b/mojo/public/cpp/bindings/lib/map_serialization.h
@@ -8,11 +8,11 @@
 #include <type_traits>
 #include <vector>
 
-#include "mojo/public/cpp/bindings/array_data_view.h"
+#include "mojo/public/cpp/bindings/array.h"
 #include "mojo/public/cpp/bindings/lib/array_serialization.h"
 #include "mojo/public/cpp/bindings/lib/map_data_internal.h"
 #include "mojo/public/cpp/bindings/lib/serialization_forward.h"
-#include "mojo/public/cpp/bindings/map_data_view.h"
+#include "mojo/public/cpp/bindings/map.h"
 
 namespace mojo {
 namespace internal {
@@ -46,15 +46,12 @@
  public:
   using Base = MapReaderBase<MaybeConstUserType>;
   using Traits = typename Base::Traits;
-  using MaybeConstIterator = typename Base::MaybeConstIterator;
 
   explicit MapKeyReader(MaybeConstUserType& input) : Base(input) {}
   ~MapKeyReader() {}
 
-  using GetNextResult =
-      decltype(Traits::GetKey(std::declval<MaybeConstIterator&>()));
-  GetNextResult GetNext() {
-    GetNextResult key = Traits::GetKey(this->iter_);
+  const typename Traits::Key& GetNext() {
+    const typename Traits::Key& key = Traits::GetKey(this->iter_);
     Traits::AdvanceIterator(this->iter_);
     return key;
   }
@@ -81,17 +78,17 @@
 };
 
 template <typename Key, typename Value, typename MaybeConstUserType>
-struct Serializer<MapDataView<Key, Value>, MaybeConstUserType> {
+struct Serializer<Map<Key, Value>, MaybeConstUserType> {
   using UserType = typename std::remove_const<MaybeConstUserType>::type;
   using Traits = MapTraits<UserType>;
   using UserKey = typename Traits::Key;
   using UserValue = typename Traits::Value;
-  using Data = typename MojomTypeTraits<MapDataView<Key, Value>>::Data;
-  using KeyArraySerializer = ArraySerializer<ArrayDataView<Key>,
+  using Data = typename MojomTypeTraits<Map<Key, Value>>::Data;
+  using KeyArraySerializer = ArraySerializer<Array<Key>,
                                              std::vector<UserKey>,
                                              MapKeyReader<MaybeConstUserType>>;
   using ValueArraySerializer =
-      ArraySerializer<ArrayDataView<Value>,
+      ArraySerializer<Array<Value>,
                       std::vector<UserValue>,
                       MapValueReader<MaybeConstUserType>>;
 
@@ -125,8 +122,8 @@
 
     auto result = Data::New(buf);
     if (result) {
-      auto keys_ptr = MojomTypeTraits<ArrayDataView<Key>>::Data::New(
-          Traits::GetSize(input), buf);
+      auto keys_ptr =
+          MojomTypeTraits<Array<Key>>::Data::New(Traits::GetSize(input), buf);
       if (keys_ptr) {
         MapKeyReader<MaybeConstUserType> key_reader(input);
         KeyArraySerializer::SerializeElements(
@@ -135,8 +132,8 @@
         result->keys.Set(keys_ptr);
       }
 
-      auto values_ptr = MojomTypeTraits<ArrayDataView<Value>>::Data::New(
-          Traits::GetSize(input), buf);
+      auto values_ptr =
+          MojomTypeTraits<Array<Value>>::Data::New(Traits::GetSize(input), buf);
       if (values_ptr) {
         MapValueReader<MaybeConstUserType> value_reader(input);
         ValueArraySerializer::SerializeElements(
diff --git a/mojo/public/cpp/bindings/lib/may_auto_lock.h b/mojo/public/cpp/bindings/lib/may_auto_lock.h
deleted file mode 100644
index 06091fe..0000000
--- a/mojo/public/cpp/bindings/lib/may_auto_lock.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_MAY_AUTO_LOCK_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MAY_AUTO_LOCK_H_
-
-#include "base/macros.h"
-#include "base/optional.h"
-#include "base/synchronization/lock.h"
-
-namespace mojo {
-namespace internal {
-
-// Similar to base::AutoLock, except that it does nothing if |lock| passed into
-// the constructor is null.
-class MayAutoLock {
- public:
-  explicit MayAutoLock(base::Optional<base::Lock>* lock)
-      : lock_(lock->has_value() ? &lock->value() : nullptr) {
-    if (lock_)
-      lock_->Acquire();
-  }
-
-  ~MayAutoLock() {
-    if (lock_) {
-      lock_->AssertAcquired();
-      lock_->Release();
-    }
-  }
-
- private:
-  base::Lock* lock_;
-  DISALLOW_COPY_AND_ASSIGN(MayAutoLock);
-};
-
-// Similar to base::AutoUnlock, except that it does nothing if |lock| passed
-// into the constructor is null.
-class MayAutoUnlock {
- public:
-  explicit MayAutoUnlock(base::Optional<base::Lock>* lock)
-      : lock_(lock->has_value() ? &lock->value() : nullptr) {
-    if (lock_) {
-      lock_->AssertAcquired();
-      lock_->Release();
-    }
-  }
-
-  ~MayAutoUnlock() {
-    if (lock_)
-      lock_->Acquire();
-  }
-
- private:
-  base::Lock* lock_;
-  DISALLOW_COPY_AND_ASSIGN(MayAutoUnlock);
-};
-
-}  // namespace internal
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_MAY_AUTO_LOCK_H_
diff --git a/mojo/public/cpp/bindings/lib/message.cc b/mojo/public/cpp/bindings/lib/message.cc
index e5f3808..939e064 100644
--- a/mojo/public/cpp/bindings/lib/message.cc
+++ b/mojo/public/cpp/bindings/lib/message.cc
@@ -11,58 +11,18 @@
 #include <algorithm>
 #include <utility>
 
-#include "base/bind.h"
-#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
-#include "base/threading/thread_local.h"
-#include "mojo/public/cpp/bindings/associated_group_controller.h"
-#include "mojo/public/cpp/bindings/lib/array_internal.h"
 
 namespace mojo {
 
-namespace {
-
-base::LazyInstance<base::ThreadLocalPointer<internal::MessageDispatchContext>>::
-    DestructorAtExit g_tls_message_dispatch_context = LAZY_INSTANCE_INITIALIZER;
-
-base::LazyInstance<base::ThreadLocalPointer<SyncMessageResponseContext>>::
-    DestructorAtExit g_tls_sync_response_context = LAZY_INSTANCE_INITIALIZER;
-
-void DoNotifyBadMessage(Message message, const std::string& error) {
-  message.NotifyBadMessage(error);
-}
-
-}  // namespace
-
 Message::Message() {
 }
 
-Message::Message(Message&& other)
-    : buffer_(std::move(other.buffer_)),
-      handles_(std::move(other.handles_)),
-      associated_endpoint_handles_(
-          std::move(other.associated_endpoint_handles_)) {}
-
 Message::~Message() {
   CloseHandles();
 }
 
-Message& Message::operator=(Message&& other) {
-  Reset();
-  std::swap(other.buffer_, buffer_);
-  std::swap(other.handles_, handles_);
-  std::swap(other.associated_endpoint_handles_, associated_endpoint_handles_);
-  return *this;
-}
-
-void Message::Reset() {
-  CloseHandles();
-  handles_.clear();
-  associated_endpoint_handles_.clear();
-  buffer_.reset();
-}
-
 void Message::Initialize(size_t capacity, bool zero_initialized) {
   DCHECK(!buffer_);
   buffer_.reset(new internal::MessageBuffer(capacity, zero_initialized));
@@ -76,52 +36,19 @@
   handles_.swap(*handles);
 }
 
-const uint8_t* Message::payload() const {
-  if (version() < 2)
-    return data() + header()->num_bytes;
+void Message::MoveTo(Message* destination) {
+  DCHECK(this != destination);
 
-  return static_cast<const uint8_t*>(header_v2()->payload.Get());
-}
+  // No copy needed.
+  std::swap(destination->buffer_, buffer_);
+  std::swap(destination->handles_, handles_);
 
-uint32_t Message::payload_num_bytes() const {
-  DCHECK_GE(data_num_bytes(), header()->num_bytes);
-  size_t num_bytes;
-  if (version() < 2) {
-    num_bytes = data_num_bytes() - header()->num_bytes;
-  } else {
-    auto payload = reinterpret_cast<uintptr_t>(header_v2()->payload.Get());
-    if (!payload) {
-      num_bytes = 0;
-    } else {
-      auto payload_end =
-          reinterpret_cast<uintptr_t>(header_v2()->payload_interface_ids.Get());
-      if (!payload_end)
-        payload_end = reinterpret_cast<uintptr_t>(data() + data_num_bytes());
-      DCHECK_GE(payload_end, payload);
-      num_bytes = payload_end - payload;
-    }
-  }
-  DCHECK_LE(num_bytes, std::numeric_limits<uint32_t>::max());
-  return static_cast<uint32_t>(num_bytes);
-}
-
-uint32_t Message::payload_num_interface_ids() const {
-  auto* array_pointer =
-      version() < 2 ? nullptr : header_v2()->payload_interface_ids.Get();
-  return array_pointer ? static_cast<uint32_t>(array_pointer->size()) : 0;
-}
-
-const uint32_t* Message::payload_interface_ids() const {
-  auto* array_pointer =
-      version() < 2 ? nullptr : header_v2()->payload_interface_ids.Get();
-  return array_pointer ? array_pointer->storage() : nullptr;
+  CloseHandles();
+  handles_.clear();
+  buffer_.reset();
 }
 
 ScopedMessageHandle Message::TakeMojoMessage() {
-  // If there are associated endpoints transferred,
-  // SerializeAssociatedEndpointHandles() must be called before this method.
-  DCHECK(associated_endpoint_handles_.empty());
-
   if (handles_.empty())  // Fast path for the common case: No handles.
     return buffer_->TakeMessage();
 
@@ -153,7 +80,6 @@
 }
 
 void Message::NotifyBadMessage(const std::string& error) {
-  DCHECK(buffer_);
   buffer_->NotifyBadMessage(error);
 }
 
@@ -165,88 +91,6 @@
   }
 }
 
-void Message::SerializeAssociatedEndpointHandles(
-    AssociatedGroupController* group_controller) {
-  if (associated_endpoint_handles_.empty())
-    return;
-
-  DCHECK_GE(version(), 2u);
-  DCHECK(header_v2()->payload_interface_ids.is_null());
-
-  size_t size = associated_endpoint_handles_.size();
-  auto* data = internal::Array_Data<uint32_t>::New(size, buffer());
-  header_v2()->payload_interface_ids.Set(data);
-
-  for (size_t i = 0; i < size; ++i) {
-    ScopedInterfaceEndpointHandle& handle = associated_endpoint_handles_[i];
-
-    DCHECK(handle.pending_association());
-    data->storage()[i] =
-        group_controller->AssociateInterface(std::move(handle));
-  }
-  associated_endpoint_handles_.clear();
-}
-
-bool Message::DeserializeAssociatedEndpointHandles(
-    AssociatedGroupController* group_controller) {
-  associated_endpoint_handles_.clear();
-
-  uint32_t num_ids = payload_num_interface_ids();
-  if (num_ids == 0)
-    return true;
-
-  associated_endpoint_handles_.reserve(num_ids);
-  uint32_t* ids = header_v2()->payload_interface_ids.Get()->storage();
-  bool result = true;
-  for (uint32_t i = 0; i < num_ids; ++i) {
-    auto handle = group_controller->CreateLocalEndpointHandle(ids[i]);
-    if (IsValidInterfaceId(ids[i]) && !handle.is_valid()) {
-      // |ids[i]| itself is valid but handle creation failed. In that case, mark
-      // deserialization as failed but continue to deserialize the rest of
-      // handles.
-      result = false;
-    }
-
-    associated_endpoint_handles_.push_back(std::move(handle));
-    ids[i] = kInvalidInterfaceId;
-  }
-  return result;
-}
-
-PassThroughFilter::PassThroughFilter() {}
-
-PassThroughFilter::~PassThroughFilter() {}
-
-bool PassThroughFilter::Accept(Message* message) { return true; }
-
-SyncMessageResponseContext::SyncMessageResponseContext()
-    : outer_context_(current()) {
-  g_tls_sync_response_context.Get().Set(this);
-}
-
-SyncMessageResponseContext::~SyncMessageResponseContext() {
-  DCHECK_EQ(current(), this);
-  g_tls_sync_response_context.Get().Set(outer_context_);
-}
-
-// static
-SyncMessageResponseContext* SyncMessageResponseContext::current() {
-  return g_tls_sync_response_context.Get().Get();
-}
-
-void SyncMessageResponseContext::ReportBadMessage(const std::string& error) {
-  GetBadMessageCallback().Run(error);
-}
-
-const ReportBadMessageCallback&
-SyncMessageResponseContext::GetBadMessageCallback() {
-  if (bad_message_callback_.is_null()) {
-    bad_message_callback_ =
-        base::Bind(&DoNotifyBadMessage, base::Passed(&response_));
-  }
-  return bad_message_callback_;
-}
-
 MojoResult ReadMessage(MessagePipeHandle handle, Message* message) {
   MojoResult rv;
 
@@ -278,55 +122,4 @@
   return MOJO_RESULT_OK;
 }
 
-void ReportBadMessage(const std::string& error) {
-  internal::MessageDispatchContext* context =
-      internal::MessageDispatchContext::current();
-  DCHECK(context);
-  context->GetBadMessageCallback().Run(error);
-}
-
-ReportBadMessageCallback GetBadMessageCallback() {
-  internal::MessageDispatchContext* context =
-      internal::MessageDispatchContext::current();
-  DCHECK(context);
-  return context->GetBadMessageCallback();
-}
-
-namespace internal {
-
-MessageHeaderV2::MessageHeaderV2() = default;
-
-MessageDispatchContext::MessageDispatchContext(Message* message)
-    : outer_context_(current()), message_(message) {
-  g_tls_message_dispatch_context.Get().Set(this);
-}
-
-MessageDispatchContext::~MessageDispatchContext() {
-  DCHECK_EQ(current(), this);
-  g_tls_message_dispatch_context.Get().Set(outer_context_);
-}
-
-// static
-MessageDispatchContext* MessageDispatchContext::current() {
-  return g_tls_message_dispatch_context.Get().Get();
-}
-
-const ReportBadMessageCallback&
-MessageDispatchContext::GetBadMessageCallback() {
-  if (bad_message_callback_.is_null()) {
-    bad_message_callback_ =
-        base::Bind(&DoNotifyBadMessage, base::Passed(message_));
-  }
-  return bad_message_callback_;
-}
-
-// static
-void SyncMessageResponseSetup::SetCurrentSyncResponseMessage(Message* message) {
-  SyncMessageResponseContext* context = SyncMessageResponseContext::current();
-  if (context)
-    context->response_ = std::move(*message);
-}
-
-}  // namespace internal
-
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/message_buffer.cc b/mojo/public/cpp/bindings/lib/message_buffer.cc
index cc12ef6..af79cfd 100644
--- a/mojo/public/cpp/bindings/lib/message_buffer.cc
+++ b/mojo/public/cpp/bindings/lib/message_buffer.cc
@@ -13,35 +13,54 @@
 
 MessageBuffer::MessageBuffer(size_t capacity, bool zero_initialized) {
   DCHECK_LE(capacity, std::numeric_limits<uint32_t>::max());
+  data_num_bytes_ = static_cast<uint32_t>(capacity);
 
   MojoResult rv = AllocMessage(capacity, nullptr, 0,
                                MOJO_ALLOC_MESSAGE_FLAG_NONE, &message_);
   CHECK_EQ(rv, MOJO_RESULT_OK);
 
-  void* buffer = nullptr;
-  if (capacity != 0) {
-    rv = GetMessageBuffer(message_.get(), &buffer);
+  if (capacity == 0) {
+    buffer_ = nullptr;
+  } else {
+    rv = GetMessageBuffer(message_.get(), &buffer_);
     CHECK_EQ(rv, MOJO_RESULT_OK);
 
     if (zero_initialized)
-      memset(buffer, 0, capacity);
+      memset(buffer_, 0, capacity);
   }
-  Initialize(buffer, capacity);
 }
 
 MessageBuffer::MessageBuffer(ScopedMessageHandle message, uint32_t num_bytes) {
   message_ = std::move(message);
+  data_num_bytes_ = num_bytes;
 
-  void* buffer = nullptr;
-  if (num_bytes != 0) {
-    MojoResult rv = GetMessageBuffer(message_.get(), &buffer);
+  if (num_bytes == 0) {
+    buffer_ = nullptr;
+  } else {
+    MojoResult rv = GetMessageBuffer(message_.get(), &buffer_);
     CHECK_EQ(rv, MOJO_RESULT_OK);
   }
-  Initialize(buffer, num_bytes);
 }
 
 MessageBuffer::~MessageBuffer() {}
 
+void* MessageBuffer::Allocate(size_t delta) {
+  delta = internal::Align(delta);
+
+  DCHECK_LE(delta, static_cast<size_t>(data_num_bytes_));
+  DCHECK_GT(bytes_claimed_ + static_cast<uint32_t>(delta), bytes_claimed_);
+
+  uint32_t new_bytes_claimed = bytes_claimed_ + static_cast<uint32_t>(delta);
+  if (new_bytes_claimed > data_num_bytes_) {
+    NOTREACHED();
+    return nullptr;
+  }
+
+  char* start = static_cast<char*>(buffer_) + bytes_claimed_;
+  bytes_claimed_ = new_bytes_claimed;
+  return static_cast<void*>(start);
+}
+
 void MessageBuffer::NotifyBadMessage(const std::string& error) {
   DCHECK(message_.is_valid());
   MojoResult result = mojo::NotifyBadMessage(message_.get(), error);
diff --git a/mojo/public/cpp/bindings/lib/message_buffer.h b/mojo/public/cpp/bindings/lib/message_buffer.h
index 96d5140..0382131 100644
--- a/mojo/public/cpp/bindings/lib/message_buffer.h
+++ b/mojo/public/cpp/bindings/lib/message_buffer.h
@@ -5,6 +5,7 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_LIB_MESSAGE_BUFFER_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_LIB_MESSAGE_BUFFER_H_
 
+#include <stddef.h>
 #include <stdint.h>
 
 #include <utility>
@@ -16,7 +17,7 @@
 namespace mojo {
 namespace internal {
 
-// A fixed-size Buffer using a Mojo message object for storage.
+// A fixed-size Buffer implementation using a Mojo message object for storage.
 class MessageBuffer : public Buffer {
  public:
   // Initializes this buffer to carry a fixed byte capacity and no handles.
@@ -25,14 +26,24 @@
   // Initializes this buffer from an existing Mojo MessageHandle.
   MessageBuffer(ScopedMessageHandle message, uint32_t num_bytes);
 
-  ~MessageBuffer();
+  ~MessageBuffer() override;
+
+  void* data() const { return buffer_; }
+  uint32_t data_num_bytes() const { return data_num_bytes_; }
+
+  // Buffer:
+  void* Allocate(size_t delta) override;
 
   ScopedMessageHandle TakeMessage() { return std::move(message_); }
 
   void NotifyBadMessage(const std::string& error);
 
  private:
+  uint32_t data_num_bytes_ = 0;
   ScopedMessageHandle message_;
+  void* buffer_;
+
+  uint32_t bytes_claimed_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(MessageBuffer);
 };
diff --git a/mojo/public/cpp/bindings/lib/message_builder.cc b/mojo/public/cpp/bindings/lib/message_builder.cc
index 6806a73..4ffa180 100644
--- a/mojo/public/cpp/bindings/lib/message_builder.cc
+++ b/mojo/public/cpp/bindings/lib/message_builder.cc
@@ -4,10 +4,11 @@
 
 #include "mojo/public/cpp/bindings/lib/message_builder.h"
 
-#include "mojo/public/cpp/bindings/lib/array_internal.h"
-#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
-#include "mojo/public/cpp/bindings/lib/buffer.h"
-#include "mojo/public/cpp/bindings/lib/message_internal.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include "mojo/public/cpp/bindings/lib/serialization_util.h"
+#include "mojo/public/cpp/bindings/message.h"
 
 namespace mojo {
 namespace internal {
@@ -18,52 +19,38 @@
   (*header)->num_bytes = sizeof(Header);
 }
 
-MessageBuilder::MessageBuilder(uint32_t name,
-                               uint32_t flags,
-                               size_t payload_size,
-                               size_t payload_interface_id_count) {
-  if (payload_interface_id_count > 0) {
-    // Version 2
-    InitializeMessage(
-        sizeof(MessageHeaderV2) + Align(payload_size) +
-        ArrayDataTraits<uint32_t>::GetStorageSize(
-            static_cast<uint32_t>(payload_interface_id_count)));
+MessageBuilder::MessageBuilder(uint32_t name, size_t payload_size) {
+  InitializeMessage(sizeof(MessageHeader) + payload_size);
 
-    MessageHeaderV2* header;
-    Allocate(message_.buffer(), &header);
-    header->version = 2;
-    header->name = name;
-    header->flags = flags;
-    // The payload immediately follows the header.
-    header->payload.Set(header + 1);
-  } else if (flags &
-             (Message::kFlagExpectsResponse | Message::kFlagIsResponse)) {
-    // Version 1
-    InitializeMessage(sizeof(MessageHeaderV1) + payload_size);
-
-    MessageHeaderV1* header;
-    Allocate(message_.buffer(), &header);
-    header->version = 1;
-    header->name = name;
-    header->flags = flags;
-  } else {
-    InitializeMessage(sizeof(MessageHeader) + payload_size);
-
-    MessageHeader* header;
-    Allocate(message_.buffer(), &header);
-    header->version = 0;
-    header->name = name;
-    header->flags = flags;
-  }
+  MessageHeader* header;
+  Allocate(message_.buffer(), &header);
+  header->version = 0;
+  header->name = name;
 }
 
 MessageBuilder::~MessageBuilder() {
 }
 
+MessageBuilder::MessageBuilder() {}
+
 void MessageBuilder::InitializeMessage(size_t size) {
   message_.Initialize(static_cast<uint32_t>(Align(size)),
                       true /* zero_initialized */);
 }
 
+MessageWithRequestIDBuilder::MessageWithRequestIDBuilder(uint32_t name,
+                                                         size_t payload_size,
+                                                         uint32_t flags,
+                                                         uint64_t request_id) {
+  InitializeMessage(sizeof(MessageHeaderWithRequestID) + payload_size);
+
+  MessageHeaderWithRequestID* header;
+  Allocate(message_.buffer(), &header);
+  header->version = 1;
+  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
index 8a4d5c4..a5a050f 100644
--- a/mojo/public/cpp/bindings/lib/message_builder.h
+++ b/mojo/public/cpp/bindings/lib/message_builder.h
@@ -8,30 +8,24 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
+#include "mojo/public/cpp/bindings/lib/message_internal.h"
 #include "mojo/public/cpp/bindings/message.h"
 
 namespace mojo {
-
 class Message;
 
 namespace internal {
 
-class Buffer;
-
-class MOJO_CPP_BINDINGS_EXPORT MessageBuilder {
+class MessageBuilder {
  public:
-  MessageBuilder(uint32_t name,
-                 uint32_t flags,
-                 size_t payload_size,
-                 size_t payload_interface_id_count);
+  MessageBuilder(uint32_t name, size_t payload_size);
   ~MessageBuilder();
 
   Buffer* buffer() { return message_.buffer(); }
   Message* message() { return &message_; }
 
- private:
+ protected:
+  MessageBuilder();
   void InitializeMessage(size_t size);
 
   Message message_;
@@ -39,6 +33,51 @@
   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,
+                                    Message::kFlagExpectsResponse,
+                                    0) {}
+
+  RequestMessageBuilder(uint32_t name,
+                        size_t payload_size,
+                        uint32_t extra_flags)
+      : MessageWithRequestIDBuilder(name,
+                                    payload_size,
+                                    Message::kFlagExpectsResponse | extra_flags,
+                                    0) {}
+};
+
+class ResponseMessageBuilder : public MessageWithRequestIDBuilder {
+ public:
+  ResponseMessageBuilder(uint32_t name,
+                         size_t payload_size,
+                         uint64_t request_id)
+      : MessageWithRequestIDBuilder(name,
+                                    payload_size,
+                                    Message::kFlagIsResponse,
+                                    request_id) {}
+
+  ResponseMessageBuilder(uint32_t name,
+                         size_t payload_size,
+                         uint64_t request_id,
+                         uint32_t extra_flags)
+      : MessageWithRequestIDBuilder(name,
+                                    payload_size,
+                                    Message::kFlagIsResponse | extra_flags,
+                                    request_id) {}
+};
+
 }  // namespace internal
 }  // namespace mojo
 
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
index 9f8c627..10f7774 100644
--- a/mojo/public/cpp/bindings/lib/message_header_validator.cc
+++ b/mojo/public/cpp/bindings/lib/message_header_validator.cc
@@ -4,8 +4,6 @@
 
 #include "mojo/public/cpp/bindings/message_header_validator.h"
 
-#include "mojo/public/cpp/bindings/lib/array_internal.h"
-#include "mojo/public/cpp/bindings/lib/validate_params.h"
 #include "mojo/public/cpp/bindings/lib/validation_context.h"
 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
 #include "mojo/public/cpp/bindings/lib/validation_util.h"
@@ -13,40 +11,40 @@
 namespace mojo {
 namespace {
 
-// TODO(yzshen): Define a mojom struct for message header and use the generated
-// validation and data view code.
 bool IsValidMessageHeader(const internal::MessageHeader* header,
                           internal::ValidationContext* validation_context) {
   // 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:
-  do {
-    if (header->version == 0) {
-      if (header->num_bytes == sizeof(internal::MessageHeader))
-        break;
-    } else if (header->version == 1) {
-      if (header->num_bytes == sizeof(internal::MessageHeaderV1))
-        break;
-    } else if (header->version == 2) {
-      if (header->num_bytes == sizeof(internal::MessageHeaderV2))
-        break;
-    } else if (header->version > 2) {
-      if (header->num_bytes >= sizeof(internal::MessageHeaderV2))
-        break;
+  if (header->version == 0) {
+    if (header->num_bytes != sizeof(internal::MessageHeader)) {
+      internal::ReportValidationError(
+          validation_context,
+          internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
+      return false;
     }
-    internal::ReportValidationError(
-        validation_context,
-        internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
-    return false;
-  } while (false);
+  } else if (header->version == 1) {
+    if (header->num_bytes != sizeof(internal::MessageHeaderWithRequestID)) {
+      internal::ReportValidationError(
+          validation_context,
+          internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
+      return false;
+    }
+  } else if (header->version > 1) {
+    if (header->num_bytes < sizeof(internal::MessageHeaderWithRequestID)) {
+      internal::ReportValidationError(
+          validation_context,
+          internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
+      return false;
+    }
+  }
 
   // Validate flags (allow unknown bits):
 
   // These flags require a RequestID.
-  constexpr uint32_t kRequestIdFlags =
-      Message::kFlagExpectsResponse | Message::kFlagIsResponse;
-  if (header->version == 0 && (header->flags & kRequestIdFlags)) {
+  if (header->version < 1 && ((header->flags & Message::kFlagExpectsResponse) ||
+                              (header->flags & Message::kFlagIsResponse))) {
     internal::ReportValidationError(
         validation_context,
         internal::VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID);
@@ -54,60 +52,25 @@
   }
 
   // These flags are mutually exclusive.
-  if ((header->flags & kRequestIdFlags) == kRequestIdFlags) {
+  if ((header->flags & Message::kFlagExpectsResponse) &&
+      (header->flags & Message::kFlagIsResponse)) {
     internal::ReportValidationError(
         validation_context,
         internal::VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS);
     return false;
   }
 
-  if (header->version < 2)
-    return true;
-
-  auto* header_v2 = static_cast<const internal::MessageHeaderV2*>(header);
-  // For the payload pointer:
-  // - Check that the pointer can be safely decoded.
-  // - Claim one byte that the pointer points to. It makes sure not only the
-  //   address is within the message, but also the address precedes the array
-  //   storing interface IDs (which is important for safely calculating the
-  //   payload size).
-  // - Validation of the payload contents will be done separately based on the
-  //   payload type.
-  if (!header_v2->payload.is_null() &&
-      (!internal::ValidatePointer(header_v2->payload, validation_context) ||
-       !validation_context->ClaimMemory(header_v2->payload.Get(), 1))) {
-    return false;
-  }
-
-  const internal::ContainerValidateParams validate_params(0, false, nullptr);
-  if (!internal::ValidateContainer(header_v2->payload_interface_ids,
-                                   validation_context, &validate_params)) {
-    return false;
-  }
-
-  if (!header_v2->payload_interface_ids.is_null()) {
-    size_t num_ids = header_v2->payload_interface_ids.Get()->size();
-    const uint32_t* ids = header_v2->payload_interface_ids.Get()->storage();
-    for (size_t i = 0; i < num_ids; ++i) {
-      if (!IsValidInterfaceId(ids[i]) || IsMasterInterfaceId(ids[i])) {
-        internal::ReportValidationError(
-            validation_context,
-            internal::VALIDATION_ERROR_ILLEGAL_INTERFACE_ID);
-        return false;
-      }
-    }
-  }
-
   return true;
 }
 
 }  // namespace
 
-MessageHeaderValidator::MessageHeaderValidator()
-    : MessageHeaderValidator("MessageHeaderValidator") {}
+MessageHeaderValidator::MessageHeaderValidator(MessageReceiver* sink)
+    : MessageHeaderValidator("MessageHeaderValidator", sink) {}
 
-MessageHeaderValidator::MessageHeaderValidator(const std::string& description)
-    : description_(description) {
+MessageHeaderValidator::MessageHeaderValidator(const std::string& description,
+                                               MessageReceiver* sink)
+    : MessageFilter(sink), description_(description) {
 }
 
 void MessageHeaderValidator::SetDescription(const std::string& description) {
@@ -115,10 +78,10 @@
 }
 
 bool MessageHeaderValidator::Accept(Message* message) {
-  // Pass 0 as number of handles and associated endpoint handles because we
-  // don't expect any in the header, even if |message| contains handles.
+  // Pass 0 as number of handles because we don't expect any in the header, even
+  // if |message| contains handles.
   internal::ValidationContext validation_context(
-      message->data(), message->data_num_bytes(), 0, 0, message, description_);
+      message->data(), message->data_num_bytes(), 0, message, description_);
 
   if (!internal::ValidateStructHeaderAndClaimMemory(message->data(),
                                                     &validation_context))
@@ -127,7 +90,7 @@
   if (!IsValidMessageHeader(message->header(), &validation_context))
     return false;
 
-  return true;
+  return sink_->Accept(message);
 }
 
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/message_internal.h b/mojo/public/cpp/bindings/lib/message_internal.h
index 6693198..63edffd 100644
--- a/mojo/public/cpp/bindings/lib/message_internal.h
+++ b/mojo/public/cpp/bindings/lib/message_internal.h
@@ -7,22 +7,11 @@
 
 #include <stdint.h>
 
-#include <string>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
 
 namespace mojo {
-
-class Message;
-
 namespace internal {
 
-template <typename T>
-class Array_Data;
-
 #pragma pack(push, 1)
 
 struct MessageHeader : internal::StructHeader {
@@ -38,44 +27,16 @@
 };
 static_assert(sizeof(MessageHeader) == 24, "Bad sizeof(MessageHeader)");
 
-struct MessageHeaderV1 : MessageHeader {
+struct MessageHeaderWithRequestID : MessageHeader {
   // Only used if either kFlagExpectsResponse or kFlagIsResponse is set in
   // order to match responses with corresponding requests.
   uint64_t request_id;
 };
-static_assert(sizeof(MessageHeaderV1) == 32, "Bad sizeof(MessageHeaderV1)");
-
-struct MessageHeaderV2 : MessageHeaderV1 {
-  MessageHeaderV2();
-  GenericPointer payload;
-  Pointer<Array_Data<uint32_t>> payload_interface_ids;
-};
-static_assert(sizeof(MessageHeaderV2) == 48, "Bad sizeof(MessageHeaderV2)");
+static_assert(sizeof(MessageHeaderWithRequestID) == 32,
+              "Bad sizeof(MessageHeaderWithRequestID)");
 
 #pragma pack(pop)
 
-class MOJO_CPP_BINDINGS_EXPORT MessageDispatchContext {
- public:
-  explicit MessageDispatchContext(Message* message);
-  ~MessageDispatchContext();
-
-  static MessageDispatchContext* current();
-
-  const base::Callback<void(const std::string&)>& GetBadMessageCallback();
-
- private:
-  MessageDispatchContext* outer_context_;
-  Message* message_;
-  base::Callback<void(const std::string&)> bad_message_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(MessageDispatchContext);
-};
-
-class MOJO_CPP_BINDINGS_EXPORT SyncMessageResponseSetup {
- public:
-  static void SetCurrentSyncResponseMessage(Message* message);
-};
-
 }  // namespace internal
 }  // namespace mojo
 
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.cc b/mojo/public/cpp/bindings/lib/multiplex_router.cc
index 2da459a..dcfbab1 100644
--- a/mojo/public/cpp/bindings/lib/multiplex_router.cc
+++ b/mojo/public/cpp/bindings/lib/multiplex_router.cc
@@ -15,9 +15,9 @@
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "mojo/public/cpp/bindings/associated_group.h"
 #include "mojo/public/cpp/bindings/interface_endpoint_client.h"
 #include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
-#include "mojo/public/cpp/bindings/lib/may_auto_lock.h"
 #include "mojo/public/cpp/bindings/sync_handle_watcher.h"
 
 namespace mojo {
@@ -36,7 +36,6 @@
         id_(id),
         closed_(false),
         peer_closed_(false),
-        handle_created_(false),
         client_(nullptr),
         event_signalled_(false) {}
 
@@ -51,31 +50,16 @@
 
   bool closed() const { return closed_; }
   void set_closed() {
-    router_->AssertLockAcquired();
+    router_->lock_.AssertAcquired();
     closed_ = true;
   }
 
   bool peer_closed() const { return peer_closed_; }
   void set_peer_closed() {
-    router_->AssertLockAcquired();
+    router_->lock_.AssertAcquired();
     peer_closed_ = true;
   }
 
-  bool handle_created() const { return handle_created_; }
-  void set_handle_created() {
-    router_->AssertLockAcquired();
-    handle_created_ = true;
-  }
-
-  const base::Optional<DisconnectReason>& disconnect_reason() const {
-    return disconnect_reason_;
-  }
-  void set_disconnect_reason(
-      const base::Optional<DisconnectReason>& disconnect_reason) {
-    router_->AssertLockAcquired();
-    disconnect_reason_ = disconnect_reason;
-  }
-
   base::SingleThreadTaskRunner* task_runner() const {
     return task_runner_.get();
   }
@@ -84,7 +68,7 @@
 
   void AttachClient(InterfaceEndpointClient* client,
                     scoped_refptr<base::SingleThreadTaskRunner> runner) {
-    router_->AssertLockAcquired();
+    router_->lock_.AssertAcquired();
     DCHECK(!client_);
     DCHECK(!closed_);
     DCHECK(runner->BelongsToCurrentThread());
@@ -96,7 +80,7 @@
   // This method must be called on the same thread as the corresponding
   // AttachClient() call.
   void DetachClient() {
-    router_->AssertLockAcquired();
+    router_->lock_.AssertAcquired();
     DCHECK(client_);
     DCHECK(task_runner_->BelongsToCurrentThread());
     DCHECK(!closed_);
@@ -107,36 +91,18 @@
   }
 
   void SignalSyncMessageEvent() {
-    router_->AssertLockAcquired();
+    router_->lock_.AssertAcquired();
     if (event_signalled_)
       return;
 
+    EnsureEventMessagePipeExists();
     event_signalled_ = true;
-    if (!sync_message_event_sender_.is_valid())
-      return;
-
     MojoResult result =
         WriteMessageRaw(sync_message_event_sender_.get(), nullptr, 0, nullptr,
                         0, MOJO_WRITE_MESSAGE_FLAG_NONE);
     DCHECK_EQ(MOJO_RESULT_OK, result);
   }
 
-  void ResetSyncMessageSignal() {
-    router_->AssertLockAcquired();
-
-    if (!event_signalled_)
-      return;
-
-    event_signalled_ = false;
-    if (!sync_message_event_receiver_.is_valid())
-      return;
-
-    MojoResult result =
-        ReadMessageRaw(sync_message_event_receiver_.get(), nullptr, nullptr,
-                       nullptr, nullptr, MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
-    DCHECK_EQ(MOJO_RESULT_OK, result);
-  }
-
   // ---------------------------------------------------------------------------
   // The following public methods (i.e., InterfaceEndpointController
   // implementation) are called by the client on the same thread as the
@@ -166,7 +132,7 @@
   friend class base::RefCounted<InterfaceEndpoint>;
 
   ~InterfaceEndpoint() override {
-    router_->AssertLockAcquired();
+    router_->lock_.AssertAcquired();
 
     DCHECK(!client_);
     DCHECK(closed_);
@@ -176,23 +142,26 @@
 
   void OnHandleReady(MojoResult result) {
     DCHECK(task_runner_->BelongsToCurrentThread());
+    scoped_refptr<InterfaceEndpoint> self_protector(this);
     scoped_refptr<MultiplexRouter> router_protector(router_);
 
     // Because we never close |sync_message_event_{sender,receiver}_| before
     // destruction or set a deadline, |result| should always be MOJO_RESULT_OK.
     DCHECK_EQ(MOJO_RESULT_OK, result);
+    bool reset_sync_watcher = false;
+    {
+      base::AutoLock locker(router_->lock_);
 
-    MayAutoLock locker(&router_->lock_);
-    scoped_refptr<InterfaceEndpoint> self_protector(this);
+      bool more_to_process = router_->ProcessFirstSyncMessageForEndpoint(id_);
 
-    bool more_to_process = router_->ProcessFirstSyncMessageForEndpoint(id_);
+      if (!more_to_process)
+        ResetSyncMessageSignal();
 
-    if (!more_to_process)
-      ResetSyncMessageSignal();
-
-    // Currently there are no queued sync messages and the peer has closed so
-    // there won't be incoming sync messages in the future.
-    if (!more_to_process && peer_closed_) {
+      // Currently there are no queued sync messages and the peer has closed so
+      // there won't be incoming sync messages in the future.
+      reset_sync_watcher = !more_to_process && peer_closed_;
+    }
+    if (reset_sync_watcher) {
       // If a SyncWatch() call (or multiple ones) of this interface endpoint is
       // on the call stack, resetting the sync watcher will allow it to exit
       // when the call stack unwinds to that frame.
@@ -206,21 +175,12 @@
       return;
 
     {
-      MayAutoLock locker(&router_->lock_);
+      base::AutoLock locker(router_->lock_);
+      EnsureEventMessagePipeExists();
 
-      if (!sync_message_event_sender_.is_valid()) {
-        MojoResult result =
-            CreateMessagePipe(nullptr, &sync_message_event_sender_,
-                              &sync_message_event_receiver_);
-        DCHECK_EQ(MOJO_RESULT_OK, result);
-
-        if (event_signalled_) {
-          // Reset the flag so that SignalSyncMessageEvent() will actually
-          // signal using the newly-created message pipe.
-          event_signalled_ = false;
-          SignalSyncMessageEvent();
-        }
-      }
+      auto iter = router_->sync_message_tasks_.find(id_);
+      if (iter != router_->sync_message_tasks_.end() && !iter->second.empty())
+        SignalSyncMessageEvent();
     }
 
     sync_watcher_.reset(new SyncHandleWatcher(
@@ -228,6 +188,31 @@
         base::Bind(&InterfaceEndpoint::OnHandleReady, base::Unretained(this))));
   }
 
+  void EnsureEventMessagePipeExists() {
+    router_->lock_.AssertAcquired();
+
+    if (sync_message_event_receiver_.is_valid())
+      return;
+
+    MojoResult result = CreateMessagePipe(nullptr, &sync_message_event_sender_,
+                                          &sync_message_event_receiver_);
+    DCHECK_EQ(MOJO_RESULT_OK, result);
+  }
+
+  void ResetSyncMessageSignal() {
+    router_->lock_.AssertAcquired();
+
+    if (!event_signalled_)
+      return;
+
+    DCHECK(sync_message_event_receiver_.is_valid());
+    MojoResult result = ReadMessageRaw(sync_message_event_receiver_.get(),
+                                       nullptr, nullptr, nullptr, nullptr,
+                                       MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
+    DCHECK_EQ(MOJO_RESULT_OK, result);
+    event_signalled_ = false;
+  }
+
   // ---------------------------------------------------------------------------
   // The following members are safe to access from any threads.
 
@@ -242,12 +227,6 @@
   // Whether the peer endpoint has been closed.
   bool peer_closed_;
 
-  // Whether there is already a ScopedInterfaceEndpointHandle created for this
-  // endpoint.
-  bool handle_created_;
-
-  base::Optional<DisconnectReason> disconnect_reason_;
-
   // The task runner on which |client_|'s methods can be called.
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   // Not owned. It is null if no client is attached to this endpoint.
@@ -271,53 +250,13 @@
   DISALLOW_COPY_AND_ASSIGN(InterfaceEndpoint);
 };
 
-// MessageWrapper objects are always destroyed under the router's lock. On
-// destruction, if the message it wrappers contains
-// ScopedInterfaceEndpointHandles (which cannot be destructed under the
-// router's lock), the wrapper unlocks to clean them up.
-class MultiplexRouter::MessageWrapper {
- public:
-  MessageWrapper() = default;
-
-  MessageWrapper(MultiplexRouter* router, Message message)
-      : router_(router), value_(std::move(message)) {}
-
-  MessageWrapper(MessageWrapper&& other)
-      : router_(other.router_), value_(std::move(other.value_)) {}
-
-  ~MessageWrapper() {
-    if (value_.associated_endpoint_handles()->empty())
-      return;
-
-    router_->AssertLockAcquired();
-    {
-      MayAutoUnlock unlocker(&router_->lock_);
-      value_.mutable_associated_endpoint_handles()->clear();
-    }
-  }
-
-  MessageWrapper& operator=(MessageWrapper&& other) {
-    router_ = other.router_;
-    value_ = std::move(other.value_);
-    return *this;
-  }
-
-  Message& value() { return value_; }
-
- private:
-  MultiplexRouter* router_ = nullptr;
-  Message value_;
-
-  DISALLOW_COPY_AND_ASSIGN(MessageWrapper);
-};
-
 struct MultiplexRouter::Task {
  public:
   // Doesn't take ownership of |message| but takes its contents.
-  static std::unique_ptr<Task> CreateMessageTask(
-      MessageWrapper message_wrapper) {
+  static std::unique_ptr<Task> CreateMessageTask(Message* message) {
     Task* task = new Task(MESSAGE);
-    task->message_wrapper = std::move(message_wrapper);
+    task->message.reset(new Message);
+    message->MoveTo(task->message.get());
     return base::WrapUnique(task);
   }
   static std::unique_ptr<Task> CreateNotifyErrorTask(
@@ -332,7 +271,7 @@
   bool IsMessageTask() const { return type == MESSAGE; }
   bool IsNotifyErrorTask() const { return type == NOTIFY_ERROR; }
 
-  MessageWrapper message_wrapper;
+  std::unique_ptr<Message> message;
   scoped_refptr<InterfaceEndpoint> endpoint_to_notify;
 
   enum Type { MESSAGE, NOTIFY_ERROR };
@@ -340,56 +279,36 @@
 
  private:
   explicit Task(Type in_type) : type(in_type) {}
-
-  DISALLOW_COPY_AND_ASSIGN(Task);
 };
 
 MultiplexRouter::MultiplexRouter(
-    ScopedMessagePipeHandle message_pipe,
-    Config config,
     bool set_interface_id_namesapce_bit,
+    ScopedMessagePipeHandle message_pipe,
     scoped_refptr<base::SingleThreadTaskRunner> runner)
-    : set_interface_id_namespace_bit_(set_interface_id_namesapce_bit),
-      task_runner_(runner),
-      header_validator_(nullptr),
-      filters_(this),
+    : AssociatedGroupController(base::ThreadTaskRunnerHandle::Get()),
+      set_interface_id_namespace_bit_(set_interface_id_namesapce_bit),
+      header_validator_(this),
       connector_(std::move(message_pipe),
-                 config == MULTI_INTERFACE ? Connector::MULTI_THREADED_SEND
-                                           : Connector::SINGLE_THREADED_SEND,
+                 Connector::MULTI_THREADED_SEND,
                  std::move(runner)),
       control_message_handler_(this),
       control_message_proxy_(&connector_),
       next_interface_id_value_(1),
       posted_to_process_tasks_(false),
       encountered_error_(false),
-      paused_(false),
       testing_mode_(false) {
-  DCHECK(task_runner_->BelongsToCurrentThread());
-
-  if (config == MULTI_INTERFACE)
-    lock_.emplace();
-
-  if (config == SINGLE_INTERFACE_WITH_SYNC_METHODS ||
-      config == MULTI_INTERFACE) {
-    // Always participate in sync handle watching in multi-interface mode,
-    // because even if it doesn't expect sync requests during sync handle
-    // watching, it may still need to dispatch messages to associated endpoints
-    // on a different thread.
-    connector_.AllowWokenUpBySyncWatchOnSameThread();
-  }
-  connector_.set_incoming_receiver(&filters_);
+  // Always participate in sync handle watching, because even if it doesn't
+  // expect sync requests during sync handle watching, it may still need to
+  // dispatch messages to associated endpoints on a different thread.
+  connector_.AllowWokenUpBySyncWatchOnSameThread();
+  connector_.set_incoming_receiver(&header_validator_);
   connector_.set_connection_error_handler(
       base::Bind(&MultiplexRouter::OnPipeConnectionError,
                  base::Unretained(this)));
-
-  std::unique_ptr<MessageHeaderValidator> header_validator =
-      base::MakeUnique<MessageHeaderValidator>();
-  header_validator_ = header_validator.get();
-  filters_.Append(std::move(header_validator));
 }
 
 MultiplexRouter::~MultiplexRouter() {
-  MayAutoLock locker(&lock_);
+  base::AutoLock locker(lock_);
 
   sync_message_tasks_.clear();
   tasks_.clear();
@@ -400,66 +319,40 @@
     // because it may remove the corresponding value from the map.
     ++iter;
 
-    if (!endpoint->closed()) {
-      // This happens when a NotifyPeerEndpointClosed message been received, but
-      // the interface ID hasn't been used to create local endpoint handle.
-      DCHECK(!endpoint->client());
-      DCHECK(endpoint->peer_closed());
-      UpdateEndpointStateMayRemove(endpoint, ENDPOINT_CLOSED);
-    } else {
-      UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
-    }
+    DCHECK(endpoint->closed());
+    UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
   }
 
   DCHECK(endpoints_.empty());
 }
 
-void MultiplexRouter::SetMasterInterfaceName(const char* name) {
+void MultiplexRouter::SetMasterInterfaceName(const std::string& name) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  header_validator_->SetDescription(
-      std::string(name) + " [master] MessageHeaderValidator");
+  header_validator_.SetDescription(name + " [master] MessageHeaderValidator");
   control_message_handler_.SetDescription(
-      std::string(name) + " [master] PipeControlMessageHandler");
-  connector_.SetWatcherHeapProfilerTag(name);
+      name + " [master] PipeControlMessageHandler");
 }
 
-InterfaceId MultiplexRouter::AssociateInterface(
-    ScopedInterfaceEndpointHandle handle_to_send) {
-  if (!handle_to_send.pending_association())
-    return kInvalidInterfaceId;
-
+void MultiplexRouter::CreateEndpointHandlePair(
+    ScopedInterfaceEndpointHandle* local_endpoint,
+    ScopedInterfaceEndpointHandle* remote_endpoint) {
+  base::AutoLock locker(lock_);
   uint32_t id = 0;
-  {
-    MayAutoLock locker(&lock_);
-    do {
-      if (next_interface_id_value_ >= kInterfaceIdNamespaceMask)
-        next_interface_id_value_ = 1;
-      id = next_interface_id_value_++;
-      if (set_interface_id_namespace_bit_)
-        id |= kInterfaceIdNamespaceMask;
-    } while (base::ContainsKey(endpoints_, id));
+  do {
+    if (next_interface_id_value_ >= kInterfaceIdNamespaceMask)
+      next_interface_id_value_ = 1;
+    id = next_interface_id_value_++;
+    if (set_interface_id_namespace_bit_)
+      id |= kInterfaceIdNamespaceMask;
+  } while (ContainsKey(endpoints_, id));
 
-    InterfaceEndpoint* endpoint = new InterfaceEndpoint(this, id);
-    endpoints_[id] = endpoint;
-    if (encountered_error_)
-      UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
-    endpoint->set_handle_created();
-  }
+  InterfaceEndpoint* endpoint = new InterfaceEndpoint(this, id);
+  endpoints_[id] = endpoint;
+  if (encountered_error_)
+    UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
 
-  if (!NotifyAssociation(&handle_to_send, id)) {
-    // The peer handle of |handle_to_send|, which is supposed to join this
-    // associated group, has been closed.
-    {
-      MayAutoLock locker(&lock_);
-      InterfaceEndpoint* endpoint = FindEndpoint(id);
-      if (endpoint)
-        UpdateEndpointStateMayRemove(endpoint, ENDPOINT_CLOSED);
-    }
-
-    control_message_proxy_.NotifyPeerEndpointClosed(
-        id, handle_to_send.disconnect_reason());
-  }
-  return id;
+  *local_endpoint = CreateScopedInterfaceEndpointHandle(id, true);
+  *remote_endpoint = CreateScopedInterfaceEndpointHandle(id, false);
 }
 
 ScopedInterfaceEndpointHandle MultiplexRouter::CreateLocalEndpointHandle(
@@ -467,12 +360,10 @@
   if (!IsValidInterfaceId(id))
     return ScopedInterfaceEndpointHandle();
 
-  MayAutoLock locker(&lock_);
+  base::AutoLock locker(lock_);
   bool inserted = false;
   InterfaceEndpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
   if (inserted) {
-    DCHECK(!endpoint->handle_created());
-
     if (encountered_error_)
       UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
   } else {
@@ -480,32 +371,34 @@
     // notification that the peer endpoint has closed.
     CHECK(!endpoint->closed());
     CHECK(endpoint->peer_closed());
-
-    if (endpoint->handle_created())
-      return ScopedInterfaceEndpointHandle();
   }
-
-  endpoint->set_handle_created();
-  return CreateScopedInterfaceEndpointHandle(id);
+  return CreateScopedInterfaceEndpointHandle(id, true);
 }
 
-void MultiplexRouter::CloseEndpointHandle(
-    InterfaceId id,
-    const base::Optional<DisconnectReason>& reason) {
+void MultiplexRouter::CloseEndpointHandle(InterfaceId id, bool is_local) {
   if (!IsValidInterfaceId(id))
     return;
 
-  MayAutoLock locker(&lock_);
-  DCHECK(base::ContainsKey(endpoints_, id));
+  base::AutoLock locker(lock_);
+
+  if (!is_local) {
+    DCHECK(ContainsKey(endpoints_, id));
+    DCHECK(!IsMasterInterfaceId(id));
+
+    // We will receive a NotifyPeerEndpointClosed message from the other side.
+    control_message_proxy_.NotifyEndpointClosedBeforeSent(id);
+
+    return;
+  }
+
+  DCHECK(ContainsKey(endpoints_, id));
   InterfaceEndpoint* endpoint = endpoints_[id].get();
   DCHECK(!endpoint->client());
   DCHECK(!endpoint->closed());
   UpdateEndpointStateMayRemove(endpoint, ENDPOINT_CLOSED);
 
-  if (!IsMasterInterfaceId(id) || reason) {
-    MayAutoUnlock unlocker(&lock_);
-    control_message_proxy_.NotifyPeerEndpointClosed(id, reason);
-  }
+  if (!IsMasterInterfaceId(id))
+    control_message_proxy_.NotifyPeerEndpointClosed(id);
 
   ProcessTasks(NO_DIRECT_CLIENT_CALLS, nullptr);
 }
@@ -519,8 +412,8 @@
   DCHECK(IsValidInterfaceId(id));
   DCHECK(client);
 
-  MayAutoLock locker(&lock_);
-  DCHECK(base::ContainsKey(endpoints_, id));
+  base::AutoLock locker(lock_);
+  DCHECK(ContainsKey(endpoints_, id));
 
   InterfaceEndpoint* endpoint = endpoints_[id].get();
   endpoint->AttachClient(client, std::move(runner));
@@ -538,8 +431,8 @@
 
   DCHECK(IsValidInterfaceId(id));
 
-  MayAutoLock locker(&lock_);
-  DCHECK(base::ContainsKey(endpoints_, id));
+  base::AutoLock locker(lock_);
+  DCHECK(ContainsKey(endpoints_, id));
 
   InterfaceEndpoint* endpoint = endpoints_[id].get();
   endpoint->DetachClient();
@@ -563,51 +456,21 @@
   OnPipeConnectionError();
 }
 
-void MultiplexRouter::PauseIncomingMethodCallProcessing() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  connector_.PauseIncomingMethodCallProcessing();
-
-  MayAutoLock locker(&lock_);
-  paused_ = true;
-
-  for (auto iter = endpoints_.begin(); iter != endpoints_.end(); ++iter)
-    iter->second->ResetSyncMessageSignal();
-}
-
-void MultiplexRouter::ResumeIncomingMethodCallProcessing() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  connector_.ResumeIncomingMethodCallProcessing();
-
-  MayAutoLock locker(&lock_);
-  paused_ = false;
-
-  for (auto iter = endpoints_.begin(); iter != endpoints_.end(); ++iter) {
-    auto sync_iter = sync_message_tasks_.find(iter->first);
-    if (iter->second->peer_closed() ||
-        (sync_iter != sync_message_tasks_.end() &&
-         !sync_iter->second.empty())) {
-      iter->second->SignalSyncMessageEvent();
-    }
-  }
-
-  ProcessTasks(NO_DIRECT_CLIENT_CALLS, nullptr);
-}
-
 bool MultiplexRouter::HasAssociatedEndpoints() const {
   DCHECK(thread_checker_.CalledOnValidThread());
-  MayAutoLock locker(&lock_);
+  base::AutoLock locker(lock_);
 
   if (endpoints_.size() > 1)
     return true;
   if (endpoints_.size() == 0)
     return false;
 
-  return !base::ContainsKey(endpoints_, kMasterInterfaceId);
+  return !ContainsKey(endpoints_, kMasterInterfaceId);
 }
 
 void MultiplexRouter::EnableTestingMode() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  MayAutoLock locker(&lock_);
+  base::AutoLock locker(lock_);
 
   testing_mode_ = true;
   connector_.set_enforce_errors_from_incoming_receiver(false);
@@ -616,13 +479,8 @@
 bool MultiplexRouter::Accept(Message* message) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (!message->DeserializeAssociatedEndpointHandles(this))
-    return false;
-
   scoped_refptr<MultiplexRouter> protector(this);
-  MayAutoLock locker(&lock_);
-
-  DCHECK(!paused_);
+  base::AutoLock locker(lock_);
 
   ClientCallBehavior client_call_behavior =
       connector_.during_sync_handle_watcher_callback()
@@ -636,16 +494,15 @@
   if (!processed) {
     // Either the task queue is not empty or we cannot process the message
     // directly. In both cases, there is no need to call ProcessTasks().
-    tasks_.push_back(
-        Task::CreateMessageTask(MessageWrapper(this, std::move(*message))));
+    tasks_.push_back(Task::CreateMessageTask(message));
     Task* task = tasks_.back().get();
 
-    if (task->message_wrapper.value().has_flag(Message::kFlagIsSync)) {
-      InterfaceId id = task->message_wrapper.value().interface_id();
+    if (task->message->has_flag(Message::kFlagIsSync)) {
+      InterfaceId id = task->message->interface_id();
       sync_message_tasks_[id].push_back(task);
-      InterfaceEndpoint* endpoint = FindEndpoint(id);
-      if (endpoint)
-        endpoint->SignalSyncMessageEvent();
+      auto iter = endpoints_.find(id);
+      if (iter != endpoints_.end())
+        iter->second->SignalSyncMessageEvent();
     }
   } else if (!tasks_.empty()) {
     // Processing the message may result in new tasks (for error notification)
@@ -659,17 +516,14 @@
   return true;
 }
 
-bool MultiplexRouter::OnPeerAssociatedEndpointClosed(
-    InterfaceId id,
-    const base::Optional<DisconnectReason>& reason) {
-  DCHECK(!IsMasterInterfaceId(id) || reason);
+bool MultiplexRouter::OnPeerAssociatedEndpointClosed(InterfaceId id) {
+  lock_.AssertAcquired();
 
-  MayAutoLock locker(&lock_);
+  if (IsMasterInterfaceId(id))
+    return false;
+
   InterfaceEndpoint* endpoint = FindOrInsertEndpoint(id, nullptr);
 
-  if (reason)
-    endpoint->set_disconnect_reason(reason);
-
   // It is possible that this endpoint has been set as peer closed. That is
   // because when the message pipe is closed, all the endpoints are updated with
   // PEER_ENDPOINT_CLOSED. We continue to process remaining tasks in the queue,
@@ -687,11 +541,26 @@
   return true;
 }
 
+bool MultiplexRouter::OnAssociatedEndpointClosedBeforeSent(InterfaceId id) {
+  lock_.AssertAcquired();
+
+  if (IsMasterInterfaceId(id))
+    return false;
+
+  InterfaceEndpoint* endpoint = FindOrInsertEndpoint(id, nullptr);
+  DCHECK(!endpoint->closed());
+  UpdateEndpointStateMayRemove(endpoint, ENDPOINT_CLOSED);
+
+  control_message_proxy_.NotifyPeerEndpointClosed(id);
+
+  return true;
+}
+
 void MultiplexRouter::OnPipeConnectionError() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   scoped_refptr<MultiplexRouter> protector(this);
-  MayAutoLock locker(&lock_);
+  base::AutoLock locker(lock_);
 
   encountered_error_ = true;
 
@@ -716,21 +585,20 @@
 void MultiplexRouter::ProcessTasks(
     ClientCallBehavior client_call_behavior,
     base::SingleThreadTaskRunner* current_task_runner) {
-  AssertLockAcquired();
+  lock_.AssertAcquired();
 
   if (posted_to_process_tasks_)
     return;
 
-  while (!tasks_.empty() && !paused_) {
+  while (!tasks_.empty()) {
     std::unique_ptr<Task> task(std::move(tasks_.front()));
     tasks_.pop_front();
 
     InterfaceId id = kInvalidInterfaceId;
-    bool sync_message =
-        task->IsMessageTask() && !task->message_wrapper.value().IsNull() &&
-        task->message_wrapper.value().has_flag(Message::kFlagIsSync);
+    bool sync_message = task->IsMessageTask() && task->message &&
+                        task->message->has_flag(Message::kFlagIsSync);
     if (sync_message) {
-      id = task->message_wrapper.value().interface_id();
+      id = task->message->interface_id();
       auto& sync_message_queue = sync_message_tasks_[id];
       DCHECK_EQ(task.get(), sync_message_queue.front());
       sync_message_queue.pop_front();
@@ -740,8 +608,8 @@
         task->IsNotifyErrorTask()
             ? ProcessNotifyErrorTask(task.get(), client_call_behavior,
                                      current_task_runner)
-            : ProcessIncomingMessage(&task->message_wrapper.value(),
-                                     client_call_behavior, current_task_runner);
+            : ProcessIncomingMessage(task->message.get(), client_call_behavior,
+                                     current_task_runner);
 
     if (!processed) {
       if (sync_message) {
@@ -761,25 +629,21 @@
 }
 
 bool MultiplexRouter::ProcessFirstSyncMessageForEndpoint(InterfaceId id) {
-  AssertLockAcquired();
+  lock_.AssertAcquired();
 
   auto iter = sync_message_tasks_.find(id);
   if (iter == sync_message_tasks_.end())
     return false;
 
-  if (paused_)
-    return true;
-
   MultiplexRouter::Task* task = iter->second.front();
   iter->second.pop_front();
 
   DCHECK(task->IsMessageTask());
-  MessageWrapper message_wrapper = std::move(task->message_wrapper);
+  std::unique_ptr<Message> message(std::move(task->message));
 
-  // Note: after this call, |task| and |iter| may be invalidated.
+  // Note: after this call, |task| and  |iter| may be invalidated.
   bool processed = ProcessIncomingMessage(
-      &message_wrapper.value(), ALLOW_DIRECT_CLIENT_CALLS_FOR_SYNC_MESSAGES,
-      nullptr);
+      message.get(), ALLOW_DIRECT_CLIENT_CALLS_FOR_SYNC_MESSAGES, nullptr);
   DCHECK(processed);
 
   iter = sync_message_tasks_.find(id);
@@ -799,9 +663,7 @@
     ClientCallBehavior client_call_behavior,
     base::SingleThreadTaskRunner* current_task_runner) {
   DCHECK(!current_task_runner || current_task_runner->BelongsToCurrentThread());
-  DCHECK(!paused_);
-
-  AssertLockAcquired();
+  lock_.AssertAcquired();
   InterfaceEndpoint* endpoint = task->endpoint_to_notify.get();
   if (!endpoint->client())
     return true;
@@ -815,17 +677,14 @@
   DCHECK(endpoint->task_runner()->BelongsToCurrentThread());
 
   InterfaceEndpointClient* client = endpoint->client();
-  base::Optional<DisconnectReason> disconnect_reason(
-      endpoint->disconnect_reason());
-
   {
     // We must unlock before calling into |client| because it may call this
     // object within NotifyError(). Holding the lock will lead to deadlock.
     //
     // It is safe to call into |client| without the lock. Because |client| is
     // always accessed on the same thread, including DetachEndpointClient().
-    MayAutoUnlock unlocker(&lock_);
-    client->NotifyError(disconnect_reason);
+    base::AutoUnlock unlocker(lock_);
+    client->NotifyError();
   }
   return true;
 }
@@ -835,35 +694,47 @@
     ClientCallBehavior client_call_behavior,
     base::SingleThreadTaskRunner* current_task_runner) {
   DCHECK(!current_task_runner || current_task_runner->BelongsToCurrentThread());
-  DCHECK(!paused_);
-  DCHECK(message);
-  AssertLockAcquired();
+  lock_.AssertAcquired();
 
-  if (message->IsNull()) {
+  if (!message) {
     // This is a sync message and has been processed during sync handle
     // watching.
     return true;
   }
 
   if (PipeControlMessageHandler::IsPipeControlMessage(message)) {
-    bool result = false;
-
-    {
-      MayAutoUnlock unlocker(&lock_);
-      result = control_message_handler_.Accept(message);
-    }
-
-    if (!result)
+    if (!control_message_handler_.Accept(message))
       RaiseErrorInNonTestingMode();
-
     return true;
   }
 
   InterfaceId id = message->interface_id();
   DCHECK(IsValidInterfaceId(id));
 
-  InterfaceEndpoint* endpoint = FindEndpoint(id);
-  if (!endpoint || endpoint->closed())
+  bool inserted = false;
+  InterfaceEndpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
+  if (inserted) {
+    // Currently, it is legitimate to receive messages for an endpoint
+    // that is not registered. For example, the endpoint is transferred in
+    // a message that is discarded. Once we add support to specify all
+    // enclosing endpoints in message header, we should be able to remove
+    // this.
+    UpdateEndpointStateMayRemove(endpoint, ENDPOINT_CLOSED);
+
+    // It is also possible that this newly-inserted endpoint is the master
+    // endpoint. When the master InterfacePtr/Binding goes away, the message
+    // pipe is closed and we explicitly trigger a pipe connection error. The
+    // error updates all the endpoints, including the master endpoint, with
+    // PEER_ENDPOINT_CLOSED and removes the master endpoint from the
+    // registration. We continue to process remaining tasks in the queue, as
+    // long as there are refs keeping the router alive. If there are remaining
+    // messages for the master endpoint, we will get here.
+    if (!IsMasterInterfaceId(id))
+      control_message_proxy_.NotifyPeerEndpointClosed(id);
+    return true;
+  }
+
+  if (endpoint->closed())
     return true;
 
   if (!endpoint->client()) {
@@ -897,7 +768,7 @@
     //
     // It is safe to call into |client| without the lock. Because |client| is
     // always accessed on the same thread, including DetachEndpointClient().
-    MayAutoUnlock unlocker(&lock_);
+    base::AutoUnlock unlocker(lock_);
     result = client->HandleIncomingMessage(message);
   }
   if (!result)
@@ -908,7 +779,7 @@
 
 void MultiplexRouter::MaybePostToProcessTasks(
     base::SingleThreadTaskRunner* task_runner) {
-  AssertLockAcquired();
+  lock_.AssertAcquired();
   if (posted_to_process_tasks_)
     return;
 
@@ -921,7 +792,7 @@
 void MultiplexRouter::LockAndCallProcessTasks() {
   // There is no need to hold a ref to this class in this case because this is
   // always called using base::Bind(), which holds a ref.
-  MayAutoLock locker(&lock_);
+  base::AutoLock locker(lock_);
   posted_to_process_tasks_ = false;
   scoped_refptr<base::SingleThreadTaskRunner> runner(
       std::move(posted_to_task_runner_));
@@ -931,20 +802,23 @@
 void MultiplexRouter::UpdateEndpointStateMayRemove(
     InterfaceEndpoint* endpoint,
     EndpointStateUpdateType type) {
-  if (type == ENDPOINT_CLOSED) {
-    endpoint->set_closed();
-  } else {
-    endpoint->set_peer_closed();
-    // If the interface endpoint is performing a sync watch, this makes sure
-    // it is notified and eventually exits the sync watch.
-    endpoint->SignalSyncMessageEvent();
+  switch (type) {
+    case ENDPOINT_CLOSED:
+      endpoint->set_closed();
+      break;
+    case PEER_ENDPOINT_CLOSED:
+      endpoint->set_peer_closed();
+      // If the interface endpoint is performing a sync watch, this makes sure
+      // it is notified and eventually exits the sync watch.
+      endpoint->SignalSyncMessageEvent();
+      break;
   }
   if (endpoint->closed() && endpoint->peer_closed())
     endpoints_.erase(endpoint->id());
 }
 
 void MultiplexRouter::RaiseErrorInNonTestingMode() {
-  AssertLockAcquired();
+  lock_.AssertAcquired();
   if (!testing_mode_)
     RaiseError();
 }
@@ -952,35 +826,24 @@
 MultiplexRouter::InterfaceEndpoint* MultiplexRouter::FindOrInsertEndpoint(
     InterfaceId id,
     bool* inserted) {
-  AssertLockAcquired();
+  lock_.AssertAcquired();
   // Either |inserted| is nullptr or it points to a boolean initialized as
   // false.
   DCHECK(!inserted || !*inserted);
 
-  InterfaceEndpoint* endpoint = FindEndpoint(id);
-  if (!endpoint) {
+  auto iter = endpoints_.find(id);
+  InterfaceEndpoint* endpoint;
+  if (iter == endpoints_.end()) {
     endpoint = new InterfaceEndpoint(this, id);
     endpoints_[id] = endpoint;
     if (inserted)
       *inserted = true;
+  } else {
+    endpoint = iter->second.get();
   }
 
   return endpoint;
 }
 
-MultiplexRouter::InterfaceEndpoint* MultiplexRouter::FindEndpoint(
-    InterfaceId id) {
-  AssertLockAcquired();
-  auto iter = endpoints_.find(id);
-  return iter != endpoints_.end() ? iter->second.get() : nullptr;
-}
-
-void MultiplexRouter::AssertLockAcquired() {
-#if DCHECK_IS_ON()
-  if (lock_)
-    lock_->AssertAcquired();
-#endif
-}
-
 }  // namespace internal
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.h b/mojo/public/cpp/bindings/lib/multiplex_router.h
index cac138b..dc66e8e 100644
--- a/mojo/public/cpp/bindings/lib/multiplex_router.h
+++ b/mojo/public/cpp/bindings/lib/multiplex_router.h
@@ -12,19 +12,15 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/optional.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
 #include "mojo/public/cpp/bindings/associated_group_controller.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/connector.h"
-#include "mojo/public/cpp/bindings/filter_chain.h"
 #include "mojo/public/cpp/bindings/interface_id.h"
 #include "mojo/public/cpp/bindings/message_header_validator.h"
 #include "mojo/public/cpp/bindings/pipe_control_message_handler.h"
@@ -38,6 +34,8 @@
 
 namespace mojo {
 
+class AssociatedGroup;
+
 namespace internal {
 
 // MultiplexRouter supports routing messages for multiple interfaces over a
@@ -49,51 +47,31 @@
 // Some public methods are only allowed to be called on the creating thread;
 // while the others are safe to call from any threads. Please see the method
 // comments for more details.
-//
-// NOTE: CloseMessagePipe() or PassMessagePipe() MUST be called on |runner|'s
-// thread before this object is destroyed.
-class MOJO_CPP_BINDINGS_EXPORT MultiplexRouter
-    : NON_EXPORTED_BASE(public MessageReceiver),
+class MultiplexRouter
+    : public MessageReceiver,
       public AssociatedGroupController,
-      NON_EXPORTED_BASE(public PipeControlMessageHandlerDelegate) {
+      public PipeControlMessageHandlerDelegate {
  public:
-  enum Config {
-    // There is only the master interface running on this router. Please note
-    // that because of interface versioning, the other side of the message pipe
-    // may use a newer master interface definition which passes associated
-    // interfaces. In that case, this router may still receive pipe control
-    // messages or messages targetting associated interfaces.
-    SINGLE_INTERFACE,
-    // Similar to the mode above, there is only the master interface running on
-    // this router. Besides, the master interface has sync methods.
-    SINGLE_INTERFACE_WITH_SYNC_METHODS,
-    // There may be associated interfaces running on this router.
-    MULTI_INTERFACE
-  };
-
   // If |set_interface_id_namespace_bit| is true, the interface IDs generated by
   // this router will have the highest bit set.
-  MultiplexRouter(ScopedMessagePipeHandle message_pipe,
-                  Config config,
-                  bool set_interface_id_namespace_bit,
+  MultiplexRouter(bool set_interface_id_namespace_bit,
+                  ScopedMessagePipeHandle message_pipe,
                   scoped_refptr<base::SingleThreadTaskRunner> runner);
 
   // Sets the master interface name for this router. Only used when reporting
   // message header or control message validation errors.
-  // |name| must be a string literal.
-  void SetMasterInterfaceName(const char* name);
+  void SetMasterInterfaceName(const std::string& name);
 
   // ---------------------------------------------------------------------------
   // The following public methods are safe to call from any threads.
 
   // AssociatedGroupController implementation:
-  InterfaceId AssociateInterface(
-      ScopedInterfaceEndpointHandle handle_to_send) override;
+  void CreateEndpointHandlePair(
+      ScopedInterfaceEndpointHandle* local_endpoint,
+      ScopedInterfaceEndpointHandle* remote_endpoint) override;
   ScopedInterfaceEndpointHandle CreateLocalEndpointHandle(
       InterfaceId id) override;
-  void CloseEndpointHandle(
-      InterfaceId id,
-      const base::Optional<DisconnectReason>& reason) override;
+  void CloseEndpointHandle(InterfaceId id, bool is_local) override;
   InterfaceEndpointController* AttachEndpointClient(
       const ScopedInterfaceEndpointHandle& handle,
       InterfaceEndpointClient* endpoint_client,
@@ -124,8 +102,14 @@
   }
 
   // See Binding for details of pause/resume.
-  void PauseIncomingMethodCallProcessing();
-  void ResumeIncomingMethodCallProcessing();
+  void PauseIncomingMethodCallProcessing() {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    connector_.PauseIncomingMethodCallProcessing();
+  }
+  void ResumeIncomingMethodCallProcessing() {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    connector_.ResumeIncomingMethodCallProcessing();
+  }
 
   // Whether there are any associated interfaces running currently.
   bool HasAssociatedEndpoints() const;
@@ -147,13 +131,8 @@
     return connector_.handle();
   }
 
-  bool SimulateReceivingMessageForTesting(Message* message) {
-    return filters_.Accept(message);
-  }
-
  private:
   class InterfaceEndpoint;
-  class MessageWrapper;
   struct Task;
 
   ~MultiplexRouter() override;
@@ -162,9 +141,8 @@
   bool Accept(Message* message) override;
 
   // PipeControlMessageHandlerDelegate implementation:
-  bool OnPeerAssociatedEndpointClosed(
-      InterfaceId id,
-      const base::Optional<DisconnectReason>& reason) override;
+  bool OnPeerAssociatedEndpointClosed(InterfaceId id) override;
+  bool OnAssociatedEndpointClosedBeforeSent(InterfaceId id) override;
 
   void OnPipeConnectionError();
 
@@ -224,30 +202,19 @@
   void RaiseErrorInNonTestingMode();
 
   InterfaceEndpoint* FindOrInsertEndpoint(InterfaceId id, bool* inserted);
-  InterfaceEndpoint* FindEndpoint(InterfaceId id);
-
-  void AssertLockAcquired();
 
   // Whether to set the namespace bit when generating interface IDs. Please see
   // comments of kInterfaceIdNamespaceMask.
   const bool set_interface_id_namespace_bit_;
 
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-
-  // Owned by |filters_| below.
-  MessageHeaderValidator* header_validator_;
-
-  FilterChain filters_;
+  MessageHeaderValidator header_validator_;
   Connector connector_;
 
   base::ThreadChecker thread_checker_;
 
   // Protects the following members.
-  // Not set in Config::SINGLE_INTERFACE* mode.
-  mutable base::Optional<base::Lock> lock_;
+  mutable base::Lock lock_;
   PipeControlMessageHandler control_message_handler_;
-
-  // NOTE: It is unsafe to call into this object while holding |lock_|.
   PipeControlMessageProxy control_message_proxy_;
 
   std::map<InterfaceId, scoped_refptr<InterfaceEndpoint>> endpoints_;
@@ -262,8 +229,6 @@
 
   bool encountered_error_;
 
-  bool paused_;
-
   bool testing_mode_;
 
   DISALLOW_COPY_AND_ASSIGN(MultiplexRouter);
diff --git a/mojo/public/cpp/bindings/lib/native_struct.cc b/mojo/public/cpp/bindings/lib/native_struct.cc
index 7b1a1a6..837b75a 100644
--- a/mojo/public/cpp/bindings/lib/native_struct.cc
+++ b/mojo/public/cpp/bindings/lib/native_struct.cc
@@ -4,31 +4,27 @@
 
 #include "mojo/public/cpp/bindings/native_struct.h"
 
-#include "mojo/public/cpp/bindings/lib/hash_util.h"
-
 namespace mojo {
 
 // static
 NativeStructPtr NativeStruct::New() {
-  return NativeStructPtr(base::in_place);
+  NativeStructPtr rv;
+  internal::StructHelper<NativeStruct>::Initialize(&rv);
+  return rv;
 }
 
-NativeStruct::NativeStruct() {}
+NativeStruct::NativeStruct() : data(nullptr) {}
 
 NativeStruct::~NativeStruct() {}
 
 NativeStructPtr NativeStruct::Clone() const {
   NativeStructPtr rv(New());
-  rv->data = data;
+  rv->data = data.Clone();
   return rv;
 }
 
 bool NativeStruct::Equals(const NativeStruct& other) const {
-  return data == other.data;
-}
-
-size_t NativeStruct::Hash(size_t seed) const {
-  return internal::Hash(seed, data);
+  return data.Equals(other.data);
 }
 
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/native_struct_data.h b/mojo/public/cpp/bindings/lib/native_struct_data.h
index 1c7cd81..5c58774 100644
--- a/mojo/public/cpp/bindings/lib/native_struct_data.h
+++ b/mojo/public/cpp/bindings/lib/native_struct_data.h
@@ -7,16 +7,16 @@
 
 #include <vector>
 
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/lib/array_internal.h"
 #include "mojo/public/cpp/system/handle.h"
 
 namespace mojo {
 namespace internal {
 
+class Buffer;
 class ValidationContext;
 
-class MOJO_CPP_BINDINGS_EXPORT NativeStruct_Data {
+class NativeStruct_Data {
  public:
   static bool Validate(const void* data, ValidationContext* validation_context);
 
diff --git a/mojo/public/cpp/bindings/lib/native_struct_serialization.cc b/mojo/public/cpp/bindings/lib/native_struct_serialization.cc
index fa0dbf3..ac06059 100644
--- a/mojo/public/cpp/bindings/lib/native_struct_serialization.cc
+++ b/mojo/public/cpp/bindings/lib/native_struct_serialization.cc
@@ -15,8 +15,7 @@
     SerializationContext* context) {
   if (!input)
     return 0;
-  return internal::PrepareToSerialize<ArrayDataView<uint8_t>>(input->data,
-                                                              context);
+  return internal::PrepareToSerialize<Array<uint8_t>>(input->data, context);
 }
 
 // static
@@ -32,8 +31,8 @@
 
   Array_Data<uint8_t>* data = nullptr;
   const ContainerValidateParams params(0, false, nullptr);
-  internal::Serialize<ArrayDataView<uint8_t>>(input->data, buffer, &data,
-                                              &params, context);
+  internal::Serialize<Array<uint8_t>>(input->data, buffer, &data, &params,
+                                      context);
   *output = reinterpret_cast<NativeStruct_Data*>(data);
 }
 
@@ -45,8 +44,7 @@
   Array_Data<uint8_t>* data = reinterpret_cast<Array_Data<uint8_t>*>(input);
 
   NativeStructPtr result(NativeStruct::New());
-  if (!internal::Deserialize<ArrayDataView<uint8_t>>(data, &result->data,
-                                                     context)) {
+  if (!internal::Deserialize<Array<uint8_t>>(data, &result->data, context)) {
     output = nullptr;
     return false;
   }
diff --git a/mojo/public/cpp/bindings/lib/native_struct_serialization.h b/mojo/public/cpp/bindings/lib/native_struct_serialization.h
index 457435b..e64b862 100644
--- a/mojo/public/cpp/bindings/lib/native_struct_serialization.h
+++ b/mojo/public/cpp/bindings/lib/native_struct_serialization.h
@@ -13,14 +13,12 @@
 #include "base/logging.h"
 #include "base/pickle.h"
 #include "ipc/ipc_param_traits.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/lib/array_internal.h"
 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
 #include "mojo/public/cpp/bindings/lib/native_struct_data.h"
 #include "mojo/public/cpp/bindings/lib/serialization_forward.h"
 #include "mojo/public/cpp/bindings/lib/serialization_util.h"
 #include "mojo/public/cpp/bindings/native_struct.h"
-#include "mojo/public/cpp/bindings/native_struct_data_view.h"
 
 namespace mojo {
 namespace internal {
@@ -104,7 +102,7 @@
   }
 };
 
-struct MOJO_CPP_BINDINGS_EXPORT UnmappedNativeStructSerializerImpl {
+struct UnmappedNativeStructSerializerImpl {
   static size_t PrepareToSerialize(const NativeStructPtr& input,
                                    SerializationContext* context);
   static void Serialize(const NativeStructPtr& input,
@@ -125,7 +123,7 @@
     : public UnmappedNativeStructSerializerImpl {};
 
 template <typename MaybeConstUserType>
-struct Serializer<NativeStructDataView, MaybeConstUserType>
+struct Serializer<NativeStructPtr, MaybeConstUserType>
     : public NativeStructSerializerImpl<MaybeConstUserType> {};
 
 }  // namespace internal
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/pipe_control_message_handler.cc b/mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc
index d451c05..7ee9f8a 100644
--- a/mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc
+++ b/mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc
@@ -5,10 +5,8 @@
 #include "mojo/public/cpp/bindings/pipe_control_message_handler.h"
 
 #include "base/logging.h"
-#include "mojo/public/cpp/bindings/interface_id.h"
 #include "mojo/public/cpp/bindings/lib/message_builder.h"
 #include "mojo/public/cpp/bindings/lib/serialization.h"
-#include "mojo/public/cpp/bindings/lib/serialization_context.h"
 #include "mojo/public/cpp/bindings/lib/validation_context.h"
 #include "mojo/public/cpp/bindings/lib/validation_util.h"
 #include "mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h"
@@ -43,9 +41,8 @@
 }
 
 bool PipeControlMessageHandler::Validate(Message* message) {
-  internal::ValidationContext validation_context(message->payload(),
-                                                 message->payload_num_bytes(),
-                                                 0, 0, message, description_);
+  internal::ValidationContext validation_context(
+      message->data(), message->data_num_bytes(), 0, message, description_);
 
   if (message->name() == pipe_control::kRunOrClosePipeMessageId) {
     if (!internal::ValidateMessageIsRequestWithoutResponse(
@@ -61,25 +58,22 @@
 }
 
 bool PipeControlMessageHandler::RunOrClosePipe(Message* message) {
-  internal::SerializationContext context;
   pipe_control::internal::RunOrClosePipeMessageParams_Data* params =
       reinterpret_cast<
           pipe_control::internal::RunOrClosePipeMessageParams_Data*>(
           message->mutable_payload());
   pipe_control::RunOrClosePipeMessageParamsPtr params_ptr;
-  internal::Deserialize<pipe_control::RunOrClosePipeMessageParamsDataView>(
-      params, &params_ptr, &context);
+  internal::Deserialize<pipe_control::RunOrClosePipeMessageParamsPtr>(
+      params, &params_ptr, &context_);
 
   if (params_ptr->input->is_peer_associated_endpoint_closed_event()) {
-    const auto& event =
-        params_ptr->input->get_peer_associated_endpoint_closed_event();
-
-    base::Optional<DisconnectReason> reason;
-    if (event->disconnect_reason) {
-      reason.emplace(event->disconnect_reason->custom_reason,
-                     event->disconnect_reason->description);
-    }
-    return delegate_->OnPeerAssociatedEndpointClosed(event->id, reason);
+    return delegate_->OnPeerAssociatedEndpointClosed(
+        params_ptr->input->get_peer_associated_endpoint_closed_event()->id);
+  }
+  if (params_ptr->input->is_associated_endpoint_closed_before_sent_event()) {
+    return delegate_->OnAssociatedEndpointClosedBeforeSent(
+        params_ptr->input->get_associated_endpoint_closed_before_sent_event()
+            ->id);
   }
 
   DVLOG(1) << "Unsupported command in a RunOrClosePipe message pipe control "
diff --git a/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc b/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc
index 701108e..55ee64b 100644
--- a/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc
+++ b/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc
@@ -11,28 +11,33 @@
 #include "base/logging.h"
 #include "mojo/public/cpp/bindings/lib/message_builder.h"
 #include "mojo/public/cpp/bindings/lib/serialization.h"
+#include "mojo/public/cpp/bindings/message.h"
 #include "mojo/public/interfaces/bindings/pipe_control_messages.mojom.h"
 
 namespace mojo {
 namespace {
 
-Message ConstructRunOrClosePipeMessage(
-    pipe_control::RunOrClosePipeInputPtr input_ptr) {
-  internal::SerializationContext context;
+void SendRunOrClosePipeMessage(MessageReceiver* receiver,
+                               pipe_control::RunOrClosePipeInputPtr input,
+                               internal::SerializationContext* context) {
+  pipe_control::RunOrClosePipeMessageParamsPtr params_ptr(
+      pipe_control::RunOrClosePipeMessageParams::New());
+  params_ptr->input = std::move(input);
 
-  auto params_ptr = pipe_control::RunOrClosePipeMessageParams::New();
-  params_ptr->input = std::move(input_ptr);
-
-  size_t size = internal::PrepareToSerialize<
-      pipe_control::RunOrClosePipeMessageParamsDataView>(params_ptr, &context);
-  internal::MessageBuilder builder(pipe_control::kRunOrClosePipeMessageId, 0,
-                                   size, 0);
+  size_t size =
+      internal::PrepareToSerialize<
+          pipe_control::RunOrClosePipeMessageParamsPtr>(params_ptr, context);
+  internal::MessageBuilder builder(pipe_control::kRunOrClosePipeMessageId,
+                                   size);
 
   pipe_control::internal::RunOrClosePipeMessageParams_Data* params = nullptr;
-  internal::Serialize<pipe_control::RunOrClosePipeMessageParamsDataView>(
-      params_ptr, builder.buffer(), &params, &context);
+  internal::Serialize<pipe_control::RunOrClosePipeMessageParamsPtr>(
+      params_ptr, builder.buffer(), &params, context);
   builder.message()->set_interface_id(kInvalidInterfaceId);
-  return std::move(*builder.message());
+  bool ok = receiver->Accept(builder.message());
+  // This return value may be ignored as !ok implies the underlying message pipe
+  // has encountered an error, which will be visible through other means.
+  ALLOW_UNUSED_LOCAL(ok);
 }
 
 }  // namespace
@@ -40,30 +45,30 @@
 PipeControlMessageProxy::PipeControlMessageProxy(MessageReceiver* receiver)
     : receiver_(receiver) {}
 
-void PipeControlMessageProxy::NotifyPeerEndpointClosed(
-    InterfaceId id,
-    const base::Optional<DisconnectReason>& reason) {
-  Message message(ConstructPeerEndpointClosedMessage(id, reason));
-  bool ok = receiver_->Accept(&message);
-  ALLOW_UNUSED_LOCAL(ok);
-}
-
-// static
-Message PipeControlMessageProxy::ConstructPeerEndpointClosedMessage(
-    InterfaceId id,
-    const base::Optional<DisconnectReason>& reason) {
-  auto event = pipe_control::PeerAssociatedEndpointClosedEvent::New();
+void PipeControlMessageProxy::NotifyPeerEndpointClosed(InterfaceId id) {
+  DCHECK(!IsMasterInterfaceId(id));
+  pipe_control::PeerAssociatedEndpointClosedEventPtr event(
+      pipe_control::PeerAssociatedEndpointClosedEvent::New());
   event->id = id;
-  if (reason) {
-    event->disconnect_reason = pipe_control::DisconnectReason::New();
-    event->disconnect_reason->custom_reason = reason->custom_reason;
-    event->disconnect_reason->description = reason->description;
-  }
 
-  auto input = pipe_control::RunOrClosePipeInput::New();
+  pipe_control::RunOrClosePipeInputPtr input(
+      pipe_control::RunOrClosePipeInput::New());
   input->set_peer_associated_endpoint_closed_event(std::move(event));
 
-  return ConstructRunOrClosePipeMessage(std::move(input));
+  SendRunOrClosePipeMessage(receiver_, std::move(input), &context_);
+}
+
+void PipeControlMessageProxy::NotifyEndpointClosedBeforeSent(InterfaceId id) {
+  DCHECK(!IsMasterInterfaceId(id));
+  pipe_control::AssociatedEndpointClosedBeforeSentEventPtr event(
+      pipe_control::AssociatedEndpointClosedBeforeSentEvent::New());
+  event->id = id;
+
+  pipe_control::RunOrClosePipeInputPtr input(
+      pipe_control::RunOrClosePipeInput::New());
+  input->set_associated_endpoint_closed_before_sent_event(std::move(event));
+
+  SendRunOrClosePipeMessage(receiver_, std::move(input), &context_);
 }
 
 }  // 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..8c1b77d
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/router.cc
@@ -0,0 +1,323 @@
+// 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 <stdint.h>
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
+#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
+
+namespace mojo {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+void DCheckIfInvalid(const base::WeakPtr<Router>& router,
+                   const std::string& message) {
+  bool is_valid = router && !router->encountered_error() && router->is_valid();
+  DCHECK(!is_valid) << message;
+}
+
+class ResponderThunk : public MessageReceiverWithStatus {
+ public:
+  explicit ResponderThunk(const base::WeakPtr<Router>& router,
+                          scoped_refptr<base::SingleThreadTaskRunner> runner)
+      : router_(router),
+        accept_was_invoked_(false),
+        task_runner_(std::move(runner)) {}
+  ~ResponderThunk() override {
+    if (!accept_was_invoked_) {
+      // The Mojo application handled a message that was expecting a response
+      // but did not send a response.
+      // We raise an error to signal the calling application that an error
+      // condition occurred. Without this the calling application would have no
+      // way of knowing it should stop waiting for a response.
+      if (task_runner_->RunsTasksOnCurrentThread()) {
+        // Please note that even if this code is run from a different task
+        // runner on the same thread as |task_runner_|, it is okay to directly
+        // call Router::RaiseError(), because it will raise error from the
+        // correct task runner asynchronously.
+        if (router_)
+          router_->RaiseError();
+      } else {
+        task_runner_->PostTask(FROM_HERE,
+                               base::Bind(&Router::RaiseError, router_));
+      }
+    }
+  }
+
+  // MessageReceiver implementation:
+  bool Accept(Message* message) override {
+    DCHECK(task_runner_->RunsTasksOnCurrentThread());
+    accept_was_invoked_ = true;
+    DCHECK(message->has_flag(Message::kFlagIsResponse));
+
+    bool result = false;
+
+    if (router_)
+      result = router_->Accept(message);
+
+    return result;
+  }
+
+  // MessageReceiverWithStatus implementation:
+  bool IsValid() override {
+    DCHECK(task_runner_->RunsTasksOnCurrentThread());
+    return router_ && !router_->encountered_error() && router_->is_valid();
+  }
+
+  void DCheckInvalid(const std::string& message) override {
+    if (task_runner_->RunsTasksOnCurrentThread()) {
+      DCheckIfInvalid(router_, message);
+    } else {
+      task_runner_->PostTask(FROM_HERE,
+                             base::Bind(&DCheckIfInvalid, router_, message));
+    }
+  }
+
+ private:
+  base::WeakPtr<Router> router_;
+  bool accept_was_invoked_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+};
+
+}  // namespace
+
+// ----------------------------------------------------------------------------
+
+Router::SyncResponseInfo::SyncResponseInfo(bool* in_response_received)
+    : response_received(in_response_received) {}
+
+Router::SyncResponseInfo::~SyncResponseInfo() {}
+
+// ----------------------------------------------------------------------------
+
+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,
+               bool expects_sync_requests,
+               scoped_refptr<base::SingleThreadTaskRunner> runner)
+    : thunk_(this),
+      filters_(std::move(filters)),
+      connector_(std::move(message_pipe),
+                 Connector::SINGLE_THREADED_SEND,
+                 std::move(runner)),
+      incoming_receiver_(nullptr),
+      next_request_id_(0),
+      testing_mode_(false),
+      pending_task_for_messages_(false),
+      encountered_error_(false),
+      weak_factory_(this) {
+  filters_.SetSink(&thunk_);
+  if (expects_sync_requests)
+    connector_.AllowWokenUpBySyncWatchOnSameThread();
+  connector_.set_incoming_receiver(filters_.GetHead());
+  connector_.set_connection_error_handler(
+      base::Bind(&Router::OnConnectionError, base::Unretained(this)));
+}
+
+Router::~Router() {}
+
+bool Router::Accept(Message* message) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(!message->has_flag(Message::kFlagExpectsResponse));
+  return connector_.Accept(message);
+}
+
+bool Router::AcceptWithResponder(Message* message, MessageReceiver* responder) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(message->has_flag(Message::kFlagExpectsResponse));
+
+  // 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_++;
+
+  bool is_sync = message->has_flag(Message::kFlagIsSync);
+  message->set_request_id(request_id);
+  if (!connector_.Accept(message))
+    return false;
+
+  if (!is_sync) {
+    // We assume ownership of |responder|.
+    async_responders_[request_id] = base::WrapUnique(responder);
+    return true;
+  }
+
+  SyncCallRestrictions::AssertSyncCallAllowed();
+
+  bool response_received = false;
+  std::unique_ptr<MessageReceiver> sync_responder(responder);
+  sync_responses_.insert(std::make_pair(
+      request_id, base::WrapUnique(new SyncResponseInfo(&response_received))));
+
+  base::WeakPtr<Router> weak_self = weak_factory_.GetWeakPtr();
+  connector_.SyncWatch(&response_received);
+  // Make sure that this instance hasn't been destroyed.
+  if (weak_self) {
+    DCHECK(ContainsKey(sync_responses_, request_id));
+    auto iter = sync_responses_.find(request_id);
+    DCHECK_EQ(&response_received, iter->second->response_received);
+    if (response_received) {
+      std::unique_ptr<Message> response = std::move(iter->second->response);
+      ignore_result(sync_responder->Accept(response.get()));
+    }
+    sync_responses_.erase(iter);
+  }
+
+  // Return true means that we take ownership of |responder|.
+  return true;
+}
+
+void Router::EnableTestingMode() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  testing_mode_ = true;
+  connector_.set_enforce_errors_from_incoming_receiver(false);
+}
+
+bool Router::HandleIncomingMessage(Message* message) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  const bool during_sync_call =
+      connector_.during_sync_handle_watcher_callback();
+  if (!message->has_flag(Message::kFlagIsSync) &&
+      (during_sync_call || !pending_messages_.empty())) {
+    std::unique_ptr<Message> pending_message(new Message);
+    message->MoveTo(pending_message.get());
+    pending_messages_.push(std::move(pending_message));
+
+    if (!pending_task_for_messages_) {
+      pending_task_for_messages_ = true;
+      connector_.task_runner()->PostTask(
+          FROM_HERE, base::Bind(&Router::HandleQueuedMessages,
+                                weak_factory_.GetWeakPtr()));
+    }
+
+    return true;
+  }
+
+  return HandleMessageInternal(message);
+}
+
+void Router::HandleQueuedMessages() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(pending_task_for_messages_);
+
+  base::WeakPtr<Router> weak_self = weak_factory_.GetWeakPtr();
+  while (!pending_messages_.empty()) {
+    std::unique_ptr<Message> message(std::move(pending_messages_.front()));
+    pending_messages_.pop();
+
+    bool result = HandleMessageInternal(message.get());
+    if (!weak_self)
+      return;
+
+    if (!result && !testing_mode_) {
+      connector_.RaiseError();
+      break;
+    }
+  }
+
+  pending_task_for_messages_ = false;
+
+  // We may have already seen a connection error from the connector, but
+  // haven't notified the user because we want to process all the queued
+  // messages first. We should do it now.
+  if (connector_.encountered_error() && !encountered_error_)
+    OnConnectionError();
+}
+
+bool Router::HandleMessageInternal(Message* message) {
+  if (message->has_flag(Message::kFlagExpectsResponse)) {
+    if (!incoming_receiver_)
+      return false;
+
+    MessageReceiverWithStatus* responder = new ResponderThunk(
+        weak_factory_.GetWeakPtr(), connector_.task_runner());
+    bool ok = incoming_receiver_->AcceptWithResponder(message, responder);
+    if (!ok)
+      delete responder;
+    return ok;
+
+  } else if (message->has_flag(Message::kFlagIsResponse)) {
+    uint64_t request_id = message->request_id();
+
+    if (message->has_flag(Message::kFlagIsSync)) {
+      auto it = sync_responses_.find(request_id);
+      if (it == sync_responses_.end()) {
+        DCHECK(testing_mode_);
+        return false;
+      }
+      it->second->response.reset(new Message());
+      message->MoveTo(it->second->response.get());
+      *it->second->response_received = true;
+      return true;
+    }
+
+    auto it = async_responders_.find(request_id);
+    if (it == async_responders_.end()) {
+      DCHECK(testing_mode_);
+      return false;
+    }
+    std::unique_ptr<MessageReceiver> responder = std::move(it->second);
+    async_responders_.erase(it);
+    return responder->Accept(message);
+  } else {
+    if (!incoming_receiver_)
+      return false;
+
+    return incoming_receiver_->Accept(message);
+  }
+}
+
+void Router::OnConnectionError() {
+  if (encountered_error_)
+    return;
+
+  if (!pending_messages_.empty()) {
+    // After all the pending messages are processed, we will check whether an
+    // error has been encountered and run the user's connection error handler
+    // if necessary.
+    DCHECK(pending_task_for_messages_);
+    return;
+  }
+
+  if (connector_.during_sync_handle_watcher_callback()) {
+    // We don't want the error handler to reenter an ongoing sync call.
+    connector_.task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&Router::OnConnectionError, weak_factory_.GetWeakPtr()));
+    return;
+  }
+
+  encountered_error_ = true;
+  if (!error_handler_.is_null())
+    error_handler_.Run();
+}
+
+// ----------------------------------------------------------------------------
+
+}  // 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..6dbe08d
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/router.h
@@ -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.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <queue>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_checker.h"
+#include "mojo/public/cpp/bindings/connector.h"
+#include "mojo/public/cpp/bindings/lib/filter_chain.h"
+
+namespace mojo {
+namespace internal {
+
+// TODO(yzshen): Consider removing this class and use MultiplexRouter in all
+// cases. crbug.com/594244
+class Router : public MessageReceiverWithResponder {
+ public:
+  Router(ScopedMessagePipeHandle message_pipe,
+         FilterChain filters,
+         bool expects_sync_requests,
+         scoped_refptr<base::SingleThreadTaskRunner> runner);
+  ~Router() override;
+
+  // Sets the receiver to handle messages read from the message pipe that do
+  // not have the Message::kFlagIsResponse flag set.
+  void set_incoming_receiver(MessageReceiverWithResponderStatus* 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_connection_error_handler(const base::Closure& 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 {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    return encountered_error_;
+  }
+
+  // Is the router bound to a MessagePipe handle?
+  bool is_valid() const {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    return connector_.is_valid();
+  }
+
+  // Please note that this method shouldn't be called unless it results from an
+  // explicit request of the user of bindings (e.g., the user sets an
+  // InterfacePtr to null or closes a Binding).
+  void CloseMessagePipe() {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    connector_.CloseMessagePipe();
+  }
+
+  ScopedMessagePipeHandle PassMessagePipe() {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    return connector_.PassMessagePipe();
+  }
+
+  void RaiseError() {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    connector_.RaiseError();
+  }
+
+  // MessageReceiver implementation:
+  bool Accept(Message* message) override;
+  bool AcceptWithResponder(Message* message,
+                           MessageReceiver* responder) override;
+
+  // Blocks the current thread until the first incoming method call, i.e.,
+  // either a call to a client method or a callback method, or |deadline|.
+  bool WaitForIncomingMessage(MojoDeadline deadline) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    return connector_.WaitForIncomingMessage(deadline);
+  }
+
+  // See Binding for details of pause/resume.
+  void PauseIncomingMethodCallProcessing() {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    connector_.PauseIncomingMethodCallProcessing();
+  }
+  void ResumeIncomingMethodCallProcessing() {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    connector_.ResumeIncomingMethodCallProcessing();
+  }
+
+  // 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();
+
+  MessagePipeHandle handle() const { return connector_.handle(); }
+
+  // Returns true if this Router has any pending callbacks.
+  bool has_pending_responders() const {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    return !async_responders_.empty() || !sync_responses_.empty();
+  }
+
+ private:
+  // Maps from the id of a response to the MessageReceiver that handles the
+  // response.
+  using AsyncResponderMap =
+      std::map<uint64_t, std::unique_ptr<MessageReceiver>>;
+
+  struct SyncResponseInfo {
+   public:
+    explicit SyncResponseInfo(bool* in_response_received);
+    ~SyncResponseInfo();
+
+    std::unique_ptr<Message> response;
+
+    // Points to a stack-allocated variable.
+    bool* response_received;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(SyncResponseInfo);
+  };
+
+  using SyncResponseMap = std::map<uint64_t, std::unique_ptr<SyncResponseInfo>>;
+
+  class HandleIncomingMessageThunk : public MessageReceiver {
+   public:
+    HandleIncomingMessageThunk(Router* router);
+    ~HandleIncomingMessageThunk() override;
+
+    // MessageReceiver implementation:
+    bool Accept(Message* message) override;
+
+   private:
+    Router* router_;
+  };
+
+  bool HandleIncomingMessage(Message* message);
+  void HandleQueuedMessages();
+  bool HandleMessageInternal(Message* message);
+
+  void OnConnectionError();
+
+  HandleIncomingMessageThunk thunk_;
+  FilterChain filters_;
+  Connector connector_;
+  MessageReceiverWithResponderStatus* incoming_receiver_;
+  AsyncResponderMap async_responders_;
+  SyncResponseMap sync_responses_;
+  uint64_t next_request_id_;
+  bool testing_mode_;
+  std::queue<std::unique_ptr<Message>> pending_messages_;
+  // Whether a task has been posted to trigger processing of
+  // |pending_messages_|.
+  bool pending_task_for_messages_;
+  bool encountered_error_;
+  base::Closure error_handler_;
+  base::ThreadChecker thread_checker_;
+  base::WeakPtrFactory<Router> weak_factory_;
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_
diff --git a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
index c134507..f54c3f7 100644
--- a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
+++ b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
@@ -4,379 +4,69 @@
 
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 
-#include "base/bind.h"
 #include "base/logging.h"
-#include "base/synchronization/lock.h"
 #include "mojo/public/cpp/bindings/associated_group_controller.h"
-#include "mojo/public/cpp/bindings/lib/may_auto_lock.h"
 
 namespace mojo {
 
-// ScopedInterfaceEndpointHandle::State ----------------------------------------
-
-// State could be called from multiple threads.
-class ScopedInterfaceEndpointHandle::State
-    : public base::RefCountedThreadSafe<State> {
- public:
-  State() = default;
-
-  State(InterfaceId id,
-        scoped_refptr<AssociatedGroupController> group_controller)
-      : id_(id), group_controller_(group_controller) {}
-
-  void InitPendingState(scoped_refptr<State> peer) {
-    DCHECK(!lock_);
-    DCHECK(!pending_association_);
-
-    lock_.emplace();
-    pending_association_ = true;
-    peer_state_ = std::move(peer);
-  }
-
-  void Close(const base::Optional<DisconnectReason>& reason) {
-    scoped_refptr<AssociatedGroupController> cached_group_controller;
-    InterfaceId cached_id = kInvalidInterfaceId;
-    scoped_refptr<State> cached_peer_state;
-
-    {
-      internal::MayAutoLock locker(&lock_);
-
-      if (!association_event_handler_.is_null()) {
-        association_event_handler_.Reset();
-        runner_ = nullptr;
-      }
-
-      if (!pending_association_) {
-        if (IsValidInterfaceId(id_)) {
-          // Intentionally keep |group_controller_| unchanged.
-          // That is because the callback created by
-          // CreateGroupControllerGetter() could still be used after this point,
-          // potentially from another thread. We would like it to continue
-          // returning the same group controller.
-          //
-          // Imagine there is a ThreadSafeForwarder A:
-          // (1) On the IO thread, A's underlying associated interface pointer
-          //     is closed.
-          // (2) On the proxy thread, the user makes a call on A to pass an
-          //     associated request B_asso_req. The callback returned by
-          //     CreateGroupControllerGetter() is used to associate B_asso_req.
-          // (3) On the proxy thread, the user immediately binds B_asso_ptr_info
-          //     to B_asso_ptr and makes calls on it.
-          //
-          // If we reset |group_controller_| in step (1), step (2) won't be able
-          // to associate B_asso_req. Therefore, in step (3) B_asso_ptr won't be
-          // able to serialize associated endpoints or send message because it
-          // is still in "pending_association" state and doesn't have a group
-          // controller.
-          //
-          // We could "address" this issue by ignoring messages if there isn't a
-          // group controller. But the side effect is that we cannot detect
-          // programming errors of "using associated interface pointer before
-          // sending associated request".
-
-          cached_group_controller = group_controller_;
-          cached_id = id_;
-          id_ = kInvalidInterfaceId;
-        }
-      } else {
-        pending_association_ = false;
-        cached_peer_state = std::move(peer_state_);
-      }
-    }
-
-    if (cached_group_controller) {
-      cached_group_controller->CloseEndpointHandle(cached_id, reason);
-    } else if (cached_peer_state) {
-      cached_peer_state->OnPeerClosedBeforeAssociation(reason);
-    }
-  }
-
-  void SetAssociationEventHandler(AssociationEventCallback handler) {
-    internal::MayAutoLock locker(&lock_);
-
-    if (!pending_association_ && !IsValidInterfaceId(id_))
-      return;
-
-    association_event_handler_ = std::move(handler);
-    if (association_event_handler_.is_null()) {
-      runner_ = nullptr;
-      return;
-    }
-
-    runner_ = base::ThreadTaskRunnerHandle::Get();
-    if (!pending_association_) {
-      runner_->PostTask(
-          FROM_HERE,
-          base::Bind(
-              &ScopedInterfaceEndpointHandle::State::RunAssociationEventHandler,
-              this, runner_, ASSOCIATED));
-    } else if (!peer_state_) {
-      runner_->PostTask(
-          FROM_HERE,
-          base::Bind(
-              &ScopedInterfaceEndpointHandle::State::RunAssociationEventHandler,
-              this, runner_, PEER_CLOSED_BEFORE_ASSOCIATION));
-    }
-  }
-
-  bool NotifyAssociation(
-      InterfaceId id,
-      scoped_refptr<AssociatedGroupController> peer_group_controller) {
-    scoped_refptr<State> cached_peer_state;
-    {
-      internal::MayAutoLock locker(&lock_);
-
-      DCHECK(pending_association_);
-      pending_association_ = false;
-      cached_peer_state = std::move(peer_state_);
-    }
-
-    if (cached_peer_state) {
-      cached_peer_state->OnAssociated(id, std::move(peer_group_controller));
-      return true;
-    }
-    return false;
-  }
-
-  bool is_valid() const {
-    internal::MayAutoLock locker(&lock_);
-    return pending_association_ || IsValidInterfaceId(id_);
-  }
-
-  bool pending_association() const {
-    internal::MayAutoLock locker(&lock_);
-    return pending_association_;
-  }
-
-  InterfaceId id() const {
-    internal::MayAutoLock locker(&lock_);
-    return id_;
-  }
-
-  AssociatedGroupController* group_controller() const {
-    internal::MayAutoLock locker(&lock_);
-    return group_controller_.get();
-  }
-
-  const base::Optional<DisconnectReason>& disconnect_reason() const {
-    internal::MayAutoLock locker(&lock_);
-    return disconnect_reason_;
-  }
-
- private:
-  friend class base::RefCountedThreadSafe<State>;
-
-  ~State() {
-    DCHECK(!pending_association_);
-    DCHECK(!IsValidInterfaceId(id_));
-  }
-
-  // Called by the peer, maybe from a different thread.
-  void OnAssociated(InterfaceId id,
-                    scoped_refptr<AssociatedGroupController> group_controller) {
-    AssociationEventCallback handler;
-    {
-      internal::MayAutoLock locker(&lock_);
-
-      // There may be race between Close() of endpoint A and
-      // NotifyPeerAssociation() of endpoint A_peer on different threads.
-      // Therefore, it is possible that endpoint A has been closed but it
-      // still gets OnAssociated() call from its peer.
-      if (!pending_association_)
-        return;
-
-      pending_association_ = false;
-      peer_state_ = nullptr;
-      id_ = id;
-      group_controller_ = std::move(group_controller);
-
-      if (!association_event_handler_.is_null()) {
-        if (runner_->BelongsToCurrentThread()) {
-          handler = std::move(association_event_handler_);
-          runner_ = nullptr;
-        } else {
-          runner_->PostTask(FROM_HERE,
-                            base::Bind(&ScopedInterfaceEndpointHandle::State::
-                                           RunAssociationEventHandler,
-                                       this, runner_, ASSOCIATED));
-        }
-      }
-    }
-
-    if (!handler.is_null())
-      std::move(handler).Run(ASSOCIATED);
-  }
-
-  // Called by the peer, maybe from a different thread.
-  void OnPeerClosedBeforeAssociation(
-      const base::Optional<DisconnectReason>& reason) {
-    AssociationEventCallback handler;
-    {
-      internal::MayAutoLock locker(&lock_);
-
-      // There may be race between Close()/NotifyPeerAssociation() of endpoint
-      // A and Close() of endpoint A_peer on different threads.
-      // Therefore, it is possible that endpoint A is not in pending association
-      // state but still gets OnPeerClosedBeforeAssociation() call from its
-      // peer.
-      if (!pending_association_)
-        return;
-
-      disconnect_reason_ = reason;
-      // NOTE: This handle itself is still pending.
-      peer_state_ = nullptr;
-
-      if (!association_event_handler_.is_null()) {
-        if (runner_->BelongsToCurrentThread()) {
-          handler = std::move(association_event_handler_);
-          runner_ = nullptr;
-        } else {
-          runner_->PostTask(
-              FROM_HERE,
-              base::Bind(&ScopedInterfaceEndpointHandle::State::
-                             RunAssociationEventHandler,
-                         this, runner_, PEER_CLOSED_BEFORE_ASSOCIATION));
-        }
-      }
-    }
-
-    if (!handler.is_null())
-      std::move(handler).Run(PEER_CLOSED_BEFORE_ASSOCIATION);
-  }
-
-  void RunAssociationEventHandler(
-      scoped_refptr<base::SingleThreadTaskRunner> posted_to_runner,
-      AssociationEvent event) {
-    AssociationEventCallback handler;
-
-    {
-      internal::MayAutoLock locker(&lock_);
-      if (posted_to_runner == runner_) {
-        runner_ = nullptr;
-        handler = std::move(association_event_handler_);
-      }
-    }
-
-    if (!handler.is_null())
-      std::move(handler).Run(event);
-  }
-
-  // Protects the following members if the handle is initially set to pending
-  // association.
-  mutable base::Optional<base::Lock> lock_;
-
-  bool pending_association_ = false;
-  base::Optional<DisconnectReason> disconnect_reason_;
-
-  scoped_refptr<State> peer_state_;
-
-  AssociationEventCallback association_event_handler_;
-  scoped_refptr<base::SingleThreadTaskRunner> runner_;
-
-  InterfaceId id_ = kInvalidInterfaceId;
-  scoped_refptr<AssociatedGroupController> group_controller_;
-
-  DISALLOW_COPY_AND_ASSIGN(State);
-};
-
-// ScopedInterfaceEndpointHandle -----------------------------------------------
-
-// static
-void ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(
-    ScopedInterfaceEndpointHandle* handle0,
-    ScopedInterfaceEndpointHandle* handle1) {
-  ScopedInterfaceEndpointHandle result0;
-  ScopedInterfaceEndpointHandle result1;
-  result0.state_->InitPendingState(result1.state_);
-  result1.state_->InitPendingState(result0.state_);
-
-  *handle0 = std::move(result0);
-  *handle1 = std::move(result1);
-}
-
 ScopedInterfaceEndpointHandle::ScopedInterfaceEndpointHandle()
-    : state_(new State) {}
+    : ScopedInterfaceEndpointHandle(kInvalidInterfaceId, true, nullptr) {}
 
 ScopedInterfaceEndpointHandle::ScopedInterfaceEndpointHandle(
     ScopedInterfaceEndpointHandle&& other)
-    : state_(new State) {
-  state_.swap(other.state_);
+    : id_(other.id_), is_local_(other.is_local_) {
+  group_controller_.swap(other.group_controller_);
+  other.id_ = kInvalidInterfaceId;
 }
 
 ScopedInterfaceEndpointHandle::~ScopedInterfaceEndpointHandle() {
-  state_->Close(base::nullopt);
+  reset();
 }
 
 ScopedInterfaceEndpointHandle& ScopedInterfaceEndpointHandle::operator=(
     ScopedInterfaceEndpointHandle&& other) {
   reset();
-  state_.swap(other.state_);
+  swap(other);
+
   return *this;
 }
 
-bool ScopedInterfaceEndpointHandle::is_valid() const {
-  return state_->is_valid();
-}
-
-bool ScopedInterfaceEndpointHandle::pending_association() const {
-  return state_->pending_association();
-}
-
-InterfaceId ScopedInterfaceEndpointHandle::id() const {
-  return state_->id();
-}
-
-AssociatedGroupController* ScopedInterfaceEndpointHandle::group_controller()
-    const {
-  return state_->group_controller();
-}
-
-const base::Optional<DisconnectReason>&
-ScopedInterfaceEndpointHandle::disconnect_reason() const {
-  return state_->disconnect_reason();
-}
-
-void ScopedInterfaceEndpointHandle::SetAssociationEventHandler(
-    AssociationEventCallback handler) {
-  state_->SetAssociationEventHandler(std::move(handler));
-}
-
 void ScopedInterfaceEndpointHandle::reset() {
-  ResetInternal(base::nullopt);
+  if (!IsValidInterfaceId(id_))
+    return;
+
+  group_controller_->CloseEndpointHandle(id_, is_local_);
+
+  id_ = kInvalidInterfaceId;
+  is_local_ = true;
+  group_controller_ = nullptr;
 }
 
-void ScopedInterfaceEndpointHandle::ResetWithReason(
-    uint32_t custom_reason,
-    const std::string& description) {
-  ResetInternal(DisconnectReason(custom_reason, description));
+void ScopedInterfaceEndpointHandle::swap(ScopedInterfaceEndpointHandle& other) {
+  using std::swap;
+  swap(other.id_, id_);
+  swap(other.is_local_, is_local_);
+  swap(other.group_controller_, group_controller_);
+}
+
+InterfaceId ScopedInterfaceEndpointHandle::release() {
+  InterfaceId result = id_;
+
+  id_ = kInvalidInterfaceId;
+  is_local_ = true;
+  group_controller_ = nullptr;
+
+  return result;
 }
 
 ScopedInterfaceEndpointHandle::ScopedInterfaceEndpointHandle(
     InterfaceId id,
+    bool is_local,
     scoped_refptr<AssociatedGroupController> group_controller)
-    : state_(new State(id, std::move(group_controller))) {
-  DCHECK(!IsValidInterfaceId(state_->id()) || state_->group_controller());
-}
-
-bool ScopedInterfaceEndpointHandle::NotifyAssociation(
-    InterfaceId id,
-    scoped_refptr<AssociatedGroupController> peer_group_controller) {
-  return state_->NotifyAssociation(id, peer_group_controller);
-}
-
-void ScopedInterfaceEndpointHandle::ResetInternal(
-    const base::Optional<DisconnectReason>& reason) {
-  scoped_refptr<State> new_state(new State);
-  state_->Close(reason);
-  state_.swap(new_state);
-}
-
-base::Callback<AssociatedGroupController*()>
-ScopedInterfaceEndpointHandle::CreateGroupControllerGetter() const {
-  // We allow this callback to be run on any thread. If this handle is created
-  // in non-pending state, we don't have a lock but it should still be safe
-  // because the group controller never changes.
-  return base::Bind(&State::group_controller, state_);
+    : id_(id),
+      is_local_(is_local),
+      group_controller_(std::move(group_controller)) {
+  DCHECK(!IsValidInterfaceId(id) || group_controller_);
 }
 
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/serialization.h b/mojo/public/cpp/bindings/lib/serialization.h
index 359b02b..6d7dd8e 100644
--- a/mojo/public/cpp/bindings/lib/serialization.h
+++ b/mojo/public/cpp/bindings/lib/serialization.h
@@ -8,16 +8,19 @@
 #include <string.h>
 
 #include "mojo/public/cpp/bindings/array_traits_carray.h"
+#include "mojo/public/cpp/bindings/array_traits_standard.h"
 #include "mojo/public/cpp/bindings/array_traits_stl.h"
 #include "mojo/public/cpp/bindings/lib/array_serialization.h"
-#include "mojo/public/cpp/bindings/lib/buffer.h"
+#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
 #include "mojo/public/cpp/bindings/lib/handle_interface_serialization.h"
 #include "mojo/public/cpp/bindings/lib/map_serialization.h"
 #include "mojo/public/cpp/bindings/lib/native_enum_serialization.h"
 #include "mojo/public/cpp/bindings/lib/native_struct_serialization.h"
 #include "mojo/public/cpp/bindings/lib/string_serialization.h"
 #include "mojo/public/cpp/bindings/lib/template_util.h"
+#include "mojo/public/cpp/bindings/map_traits_standard.h"
 #include "mojo/public/cpp/bindings/map_traits_stl.h"
+#include "mojo/public/cpp/bindings/string_traits_standard.h"
 #include "mojo/public/cpp/bindings/string_traits_stl.h"
 #include "mojo/public/cpp/bindings/string_traits_string16.h"
 #include "mojo/public/cpp/bindings/string_traits_string_piece.h"
@@ -41,7 +44,7 @@
   void* result_buffer = &result.front();
   // The serialization logic requires that the buffer is 8-byte aligned. If the
   // result buffer is not properly aligned, we have to do an extra copy. In
-  // practice, this should never happen for std::vector.
+  // practice, this should never happen for mojo::Array (backed by std::vector).
   bool need_copy = !IsAligned(result_buffer);
 
   if (need_copy) {
@@ -50,9 +53,9 @@
     DCHECK(IsAligned(result_buffer));
   }
 
-  Buffer buffer;
+  FixedBuffer buffer;
   buffer.Initialize(result_buffer, size);
-  typename MojomTypeTraits<MojomType>::Data* data = nullptr;
+  typename MojomType::Struct::Data_* data = nullptr;
   Serialize<MojomType>(*input, &buffer, &data, &context);
 
   if (need_copy) {
@@ -67,11 +70,13 @@
 bool StructDeserializeImpl(const DataArrayType& input, UserType* output) {
   static_assert(BelongsTo<MojomType, MojomTypeCategory::STRUCT>::value,
                 "Unexpected type.");
-  using DataType = typename MojomTypeTraits<MojomType>::Data;
+  using DataType = typename MojomType::Struct::Data_;
 
-  // TODO(sammc): Use DataArrayType::empty() once WTF::Vector::empty() exists.
+  if (input.is_null())
+    return false;
+
   void* input_buffer =
-      input.size() == 0
+      input.empty()
           ? nullptr
           : const_cast<void*>(reinterpret_cast<const void*>(&input.front()));
 
@@ -84,7 +89,7 @@
     memcpy(input_buffer, &input.front(), input.size());
   }
 
-  ValidationContext validation_context(input_buffer, input.size(), 0, 0);
+  ValidationContext validation_context(input_buffer, input.size(), 0);
   bool result = false;
   if (DataType::Validate(input_buffer, &validation_context)) {
     auto data = reinterpret_cast<DataType*>(input_buffer);
diff --git a/mojo/public/cpp/bindings/lib/serialization_context.cc b/mojo/public/cpp/bindings/lib/serialization_context.cc
index e2fd5c6..7fd80be 100644
--- a/mojo/public/cpp/bindings/lib/serialization_context.cc
+++ b/mojo/public/cpp/bindings/lib/serialization_context.cc
@@ -7,6 +7,7 @@
 #include <limits>
 
 #include "base/logging.h"
+#include "mojo/public/cpp/bindings/associated_group_controller.h"
 #include "mojo/public/cpp/system/core.h"
 
 namespace mojo {
@@ -49,6 +50,10 @@
 
 SerializationContext::SerializationContext() {}
 
+SerializationContext::SerializationContext(
+    scoped_refptr<AssociatedGroupController> in_group_controller)
+    : group_controller(std::move(in_group_controller)) {}
+
 SerializationContext::~SerializationContext() {
   DCHECK(!custom_contexts || custom_contexts->empty());
 }
diff --git a/mojo/public/cpp/bindings/lib/serialization_context.h b/mojo/public/cpp/bindings/lib/serialization_context.h
index a34fe3d..64d2a1a 100644
--- a/mojo/public/cpp/bindings/lib/serialization_context.h
+++ b/mojo/public/cpp/bindings/lib/serialization_context.h
@@ -12,16 +12,18 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
+#include "base/memory/ref_counted.h"
 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
-#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 #include "mojo/public/cpp/system/handle.h"
 
 namespace mojo {
+
+class AssociatedGroupController;
+
 namespace internal {
 
 // A container for handles during serialization/deserialization.
-class MOJO_CPP_BINDINGS_EXPORT SerializedHandleVector {
+class SerializedHandleVector {
  public:
   SerializedHandleVector();
   ~SerializedHandleVector();
@@ -52,23 +54,21 @@
 };
 
 // Context information for serialization/deserialization routines.
-struct MOJO_CPP_BINDINGS_EXPORT SerializationContext {
+struct SerializationContext {
   SerializationContext();
+  explicit SerializationContext(
+      scoped_refptr<AssociatedGroupController> in_group_controller);
 
   ~SerializationContext();
 
+  // Used to serialize/deserialize associated interface pointers and requests.
+  scoped_refptr<AssociatedGroupController> group_controller;
+
   // Opaque context pointers returned by StringTraits::SetUpContext().
   std::unique_ptr<std::queue<void*>> custom_contexts;
 
   // Stashes handles encoded in a message by index.
   SerializedHandleVector handles;
-
-  // The number of ScopedInterfaceEndpointHandles that need to be serialized.
-  // It is calculated by PrepareToSerialize().
-  uint32_t associated_endpoint_count = 0;
-
-  // Stashes ScopedInterfaceEndpointHandles encoded in a message by index.
-  std::vector<ScopedInterfaceEndpointHandle> associated_endpoint_handles;
 };
 
 }  // namespace internal
diff --git a/mojo/public/cpp/bindings/lib/serialization_forward.h b/mojo/public/cpp/bindings/lib/serialization_forward.h
index 55c9982..5bed126 100644
--- a/mojo/public/cpp/bindings/lib/serialization_forward.h
+++ b/mojo/public/cpp/bindings/lib/serialization_forward.h
@@ -12,7 +12,6 @@
 #include "mojo/public/cpp/bindings/map_traits.h"
 #include "mojo/public/cpp/bindings/string_traits.h"
 #include "mojo/public/cpp/bindings/struct_traits.h"
-#include "mojo/public/cpp/bindings/union_traits.h"
 
 // This file is included by serialization implementation files to avoid circular
 // includes.
diff --git a/mojo/public/cpp/bindings/lib/string_serialization.h b/mojo/public/cpp/bindings/lib/string_serialization.h
index 6e0c758..5e65891 100644
--- a/mojo/public/cpp/bindings/lib/string_serialization.h
+++ b/mojo/public/cpp/bindings/lib/string_serialization.h
@@ -11,14 +11,14 @@
 #include "mojo/public/cpp/bindings/lib/array_internal.h"
 #include "mojo/public/cpp/bindings/lib/serialization_forward.h"
 #include "mojo/public/cpp/bindings/lib/serialization_util.h"
-#include "mojo/public/cpp/bindings/string_data_view.h"
+#include "mojo/public/cpp/bindings/string.h"
 #include "mojo/public/cpp/bindings/string_traits.h"
 
 namespace mojo {
 namespace internal {
 
 template <typename MaybeConstUserType>
-struct Serializer<StringDataView, MaybeConstUserType> {
+struct Serializer<String, MaybeConstUserType> {
   using UserType = typename std::remove_const<MaybeConstUserType>::type;
   using Traits = StringTraits<UserType>;
 
@@ -60,7 +60,7 @@
                           SerializationContext* context) {
     if (!input)
       return CallSetToNullIfExists<Traits>(output);
-    return Traits::Read(StringDataView(input, context), output);
+    return Traits::Read(StringDataView(input), output);
   }
 };
 
diff --git a/mojo/public/cpp/bindings/lib/string_traits_wtf.cc b/mojo/public/cpp/bindings/lib/string_traits_wtf.cc
index 203f6f5..19fa907 100644
--- a/mojo/public/cpp/bindings/lib/string_traits_wtf.cc
+++ b/mojo/public/cpp/bindings/lib/string_traits_wtf.cc
@@ -16,7 +16,7 @@
 struct UTF8AdaptorInfo {
   explicit UTF8AdaptorInfo(const WTF::String& input) : utf8_adaptor(input) {
 #if DCHECK_IS_ON()
-    original_size_in_bytes = input.charactersSizeInBytes();
+    original_size_in_bytes = static_cast<size_t>(input.sizeInBytes());
 #endif
   }
 
@@ -34,7 +34,8 @@
   UTF8AdaptorInfo* adaptor = static_cast<UTF8AdaptorInfo*>(context);
 
 #if DCHECK_IS_ON()
-  DCHECK_EQ(adaptor->original_size_in_bytes, input.charactersSizeInBytes());
+  DCHECK_EQ(adaptor->original_size_in_bytes,
+            static_cast<size_t>(input.sizeInBytes()));
 #endif
   return adaptor;
 }
diff --git a/mojo/public/cpp/bindings/lib/sync_call_restrictions.cc b/mojo/public/cpp/bindings/lib/sync_call_restrictions.cc
index 585a8f0..3d864af 100644
--- a/mojo/public/cpp/bindings/lib/sync_call_restrictions.cc
+++ b/mojo/public/cpp/bindings/lib/sync_call_restrictions.cc
@@ -6,7 +6,6 @@
 
 #if ENABLE_SYNC_CALL_RESTRICTIONS
 
-#include "base/debug/leak_annotations.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/threading/thread_local.h"
@@ -38,7 +37,7 @@
   size_t scoped_allow_count_ = 0;
 };
 
-base::LazyInstance<base::ThreadLocalPointer<SyncCallSettings>>::DestructorAtExit
+base::LazyInstance<base::ThreadLocalPointer<SyncCallSettings>>
     g_sync_call_settings = LAZY_INSTANCE_INITIALIZER;
 
 // static
@@ -46,7 +45,6 @@
   SyncCallSettings* result = g_sync_call_settings.Pointer()->Get();
   if (!result) {
     result = new SyncCallSettings();
-    ANNOTATE_LEAKING_OBJECT_PTR(result);
     DCHECK_EQ(result, g_sync_call_settings.Pointer()->Get());
   }
   return result;
diff --git a/mojo/public/cpp/bindings/lib/sync_handle_registry.cc b/mojo/public/cpp/bindings/lib/sync_handle_registry.cc
index 5ae763b..f6372d9 100644
--- a/mojo/public/cpp/bindings/lib/sync_handle_registry.cc
+++ b/mojo/public/cpp/bindings/lib/sync_handle_registry.cc
@@ -13,7 +13,7 @@
 namespace mojo {
 namespace {
 
-base::LazyInstance<base::ThreadLocalPointer<SyncHandleRegistry>>::Leaky
+base::LazyInstance<base::ThreadLocalPointer<SyncHandleRegistry>>
     g_current_sync_handle_watcher = LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
@@ -34,7 +34,7 @@
                                         const HandleCallback& callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (base::ContainsKey(handles_, handle))
+  if (ContainsKey(handles_, handle))
     return false;
 
   MojoResult result = MojoAddHandle(wait_set_handle_.get().value(),
@@ -48,7 +48,7 @@
 
 void SyncHandleRegistry::UnregisterHandle(const Handle& handle) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  if (!base::ContainsKey(handles_, handle))
+  if (!ContainsKey(handles_, handle))
     return;
 
   MojoResult result =
@@ -107,19 +107,6 @@
 
 SyncHandleRegistry::~SyncHandleRegistry() {
   DCHECK(thread_checker_.CalledOnValidThread());
-
-  // This object may be destructed after the thread local storage slot used by
-  // |g_current_sync_handle_watcher| is reset during thread shutdown.
-  // For example, another slot in the thread local storage holds a referrence to
-  // this object, and that slot is cleaned up after
-  // |g_current_sync_handle_watcher|.
-  if (!g_current_sync_handle_watcher.Pointer()->Get())
-    return;
-
-  // If this breaks, it is likely that the global variable is bulit into and
-  // accessed from multiple modules.
-  DCHECK_EQ(this, g_current_sync_handle_watcher.Pointer()->Get());
-
   g_current_sync_handle_watcher.Pointer()->Set(nullptr);
 }
 
diff --git a/mojo/public/cpp/bindings/lib/sync_handle_registry.h b/mojo/public/cpp/bindings/lib/sync_handle_registry.h
new file mode 100644
index 0000000..d6b8c38
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/sync_handle_registry.h
@@ -0,0 +1,67 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_SYNC_HANDLE_REGISTRY_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_SYNC_HANDLE_REGISTRY_H_
+
+#include <unordered_map>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_checker.h"
+#include "mojo/public/cpp/system/core.h"
+
+namespace mojo {
+namespace internal {
+
+// SyncHandleRegistry is a thread-local storage to register handles that want to
+// be watched together.
+//
+// This class is not thread safe.
+class SyncHandleRegistry : public base::RefCounted<SyncHandleRegistry> {
+ public:
+  // Returns a thread-local object.
+  static scoped_refptr<SyncHandleRegistry> current();
+
+  using HandleCallback = base::Callback<void(MojoResult)>;
+  bool RegisterHandle(const Handle& handle,
+                      MojoHandleSignals handle_signals,
+                      const HandleCallback& callback);
+
+  void UnregisterHandle(const Handle& handle);
+
+  // Waits on all the registered handles and runs callbacks synchronously for
+  // those ready handles.
+  // The method:
+  //   - returns true when any element of |should_stop| is set to true;
+  //   - returns false when any error occurs.
+  bool WatchAllHandles(const bool* should_stop[], size_t count);
+
+ private:
+  friend class base::RefCounted<SyncHandleRegistry>;
+
+  struct HandleHasher {
+    size_t operator()(const Handle& handle) const {
+      return std::hash<uint32_t>()(static_cast<uint32_t>(handle.value()));
+    }
+  };
+  using HandleMap = std::unordered_map<Handle, HandleCallback, HandleHasher>;
+
+  SyncHandleRegistry();
+  ~SyncHandleRegistry();
+
+  HandleMap handles_;
+
+  ScopedHandle wait_set_handle_;
+
+  base::ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(SyncHandleRegistry);
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_SYNC_HANDLE_REGISTRY_H_
diff --git a/mojo/public/cpp/bindings/lib/validation_context.cc b/mojo/public/cpp/bindings/lib/validation_context.cc
index ad0a364..a95e07e 100644
--- a/mojo/public/cpp/bindings/lib/validation_context.cc
+++ b/mojo/public/cpp/bindings/lib/validation_context.cc
@@ -4,7 +4,13 @@
 
 #include "mojo/public/cpp/bindings/lib/validation_context.h"
 
+#include <stddef.h>
+#include <stdint.h>
+
 #include "base/logging.h"
+#include "mojo/public/cpp/bindings/lib/serialization_util.h"
+#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/system/handle.h"
 
 namespace mojo {
 namespace internal {
@@ -12,39 +18,69 @@
 ValidationContext::ValidationContext(const void* data,
                                      size_t data_num_bytes,
                                      size_t num_handles,
-                                     size_t num_associated_endpoint_handles,
                                      Message* message,
-                                     const base::StringPiece& description,
-                                     int stack_depth)
+                                     const base::StringPiece& description)
     : message_(message),
       description_(description),
       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)),
-      associated_endpoint_handle_begin_(0),
-      associated_endpoint_handle_end_(
-          static_cast<uint32_t>(num_associated_endpoint_handles)),
-      stack_depth_(stack_depth) {
-  // Check whether the calculation of |data_end_| or static_cast from size_t to
-  // uint32_t causes overflow.
-  // They shouldn't happen but they do, set the corresponding range to empty.
+      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.
     NOTREACHED();
     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.
     NOTREACHED();
     handle_end_ = 0;
   }
-  if (associated_endpoint_handle_end_ < num_associated_endpoint_handles) {
-    NOTREACHED();
-    associated_endpoint_handle_end_ = 0;
-  }
 }
 
 ValidationContext::~ValidationContext() {
 }
 
+bool ValidationContext::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 ValidationContext::ClaimHandle(const Handle_Data& 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 ValidationContext::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 ValidationContext::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/validation_context.h b/mojo/public/cpp/bindings/lib/validation_context.h
index ed6c654..6045ca8 100644
--- a/mojo/public/cpp/bindings/lib/validation_context.h
+++ b/mojo/public/cpp/bindings/lib/validation_context.h
@@ -8,28 +8,23 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
 
-static const int kMaxRecursionDepth = 100;
-
 namespace mojo {
 
+class Handle;
 class Message;
 
 namespace internal {
 
 // ValidationContext is used when validating object sizes, pointers and handle
 // indices in the payload of incoming messages.
-class MOJO_CPP_BINDINGS_EXPORT ValidationContext {
+class ValidationContext {
  public:
   // [data, data + data_num_bytes) specifies the initial valid memory range.
   // [0, num_handles) specifies the initial valid range of handle indices.
-  // [0, num_associated_endpoint_handles) specifies the initial valid range of
-  // associated endpoint handle indices.
   //
   // If provided, |message| and |description| provide additional information
   // to use when reporting validation errors. In addition if |message| is
@@ -38,10 +33,8 @@
   ValidationContext(const void* data,
                     size_t data_num_bytes,
                     size_t num_handles,
-                    size_t num_associated_endpoint_handles,
                     Message* message = nullptr,
-                    const base::StringPiece& description = "",
-                    int stack_depth = 0);
+                    const base::StringPiece& description = "");
 
   ~ValidationContext();
 
@@ -50,97 +43,24 @@
   // 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) {
-    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 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_Data& 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;
-  }
-
-  // Claims the specified encoded associated endpoint handle.
-  // The method succeeds if:
-  // - |encoded_handle|'s value is |kEncodedInvalidHandleValue|.
-  // - the handle is contained inside the valid range of associated endpoint
-  //   handle indices. In this case, the valid range is shinked to begin right
-  //   after the claimed handle.
-  bool ClaimAssociatedEndpointHandle(
-      const AssociatedEndpointHandle_Data& encoded_handle) {
-    uint32_t index = encoded_handle.value;
-    if (index == kEncodedInvalidHandleValue)
-      return true;
-
-    if (index < associated_endpoint_handle_begin_ ||
-        index >= associated_endpoint_handle_end_)
-      return false;
-
-    // |index| + 1 shouldn't overflow, because |index| is not the max value of
-    // uint32_t (it is less than |associated_endpoint_handle_end_|).
-    associated_endpoint_handle_begin_ = index + 1;
-    return true;
-  }
+  bool ClaimHandle(const Handle_Data& 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 {
-    uintptr_t begin = reinterpret_cast<uintptr_t>(position);
-    uintptr_t end = begin + num_bytes;
-
-    return InternalIsValidRange(begin, end);
-  }
-
-  // This object should be created on the stack once every time we recurse down
-  // into a subfield during validation to make sure we don't recurse too deep
-  // and blow the stack.
-  class ScopedDepthTracker {
-   public:
-    // |ctx| must outlive this object.
-    explicit ScopedDepthTracker(ValidationContext* ctx) : ctx_(ctx) {
-      ++ctx_->stack_depth_;
-    }
-
-    ~ScopedDepthTracker() { --ctx_->stack_depth_; }
-
-   private:
-    ValidationContext* ctx_;
-
-    DISALLOW_COPY_AND_ASSIGN(ScopedDepthTracker);
-  };
-
-  // Returns true if the recursion depth limit has been reached.
-  bool ExceedsMaxDepth() WARN_UNUSED_RESULT {
-    return stack_depth_ > kMaxRecursionDepth;
-  }
+  bool IsValidRange(const void* position, uint32_t num_bytes) const;
 
   Message* message() const { return message_; }
   const base::StringPiece& description() const { return description_; }
 
  private:
-  bool InternalIsValidRange(uintptr_t begin, uintptr_t end) const {
-    return end > begin && begin >= data_begin_ && end <= data_end_;
-  }
+  bool InternalIsValidRange(uintptr_t begin, uintptr_t end) const;
 
   Message* const message_;
   const base::StringPiece description_;
@@ -153,13 +73,6 @@
   uint32_t handle_begin_;
   uint32_t handle_end_;
 
-  // [associated_endpoint_handle_begin_, associated_endpoint_handle_end_) is the
-  // valid associated endpoint handle index range.
-  uint32_t associated_endpoint_handle_begin_;
-  uint32_t associated_endpoint_handle_end_;
-
-  int stack_depth_;
-
   DISALLOW_COPY_AND_ASSIGN(ValidationContext);
 };
 
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.cc b/mojo/public/cpp/bindings/lib/validation_errors.cc
index 904f5e4..90652de 100644
--- a/mojo/public/cpp/bindings/lib/validation_errors.cc
+++ b/mojo/public/cpp/bindings/lib/validation_errors.cc
@@ -14,7 +14,6 @@
 ValidationErrorObserverForTesting* g_validation_error_observer = nullptr;
 SerializationWarningObserverForTesting* g_serialization_warning_observer =
     nullptr;
-bool g_suppress_logging = false;
 
 }  // namespace
 
@@ -56,8 +55,6 @@
       return "VALIDATION_ERROR_UNKNOWN_ENUM_VALUE";
     case VALIDATION_ERROR_DESERIALIZATION_FAILED:
       return "VALIDATION_ERROR_DESERIALIZATION_FAILED";
-    case VALIDATION_ERROR_MAX_RECURSION_DEPTH:
-      return "VALIDATION_ERROR_MAX_RECURSION_DEPTH";
   }
 
   return "Unknown error";
@@ -72,10 +69,8 @@
   }
 
   if (description) {
-    if (!g_suppress_logging) {
-      LOG(ERROR) << "Invalid message: " << ValidationErrorToString(error)
-                 << " (" << description << ")";
-    }
+    LOG(ERROR) << "Invalid message: " << ValidationErrorToString(error) << " ("
+               << description << ")";
     if (context->message()) {
       context->message()->NotifyBadMessage(
           base::StringPrintf("Validation failed for %s [%s (%s)]",
@@ -83,8 +78,7 @@
                              ValidationErrorToString(error), description));
     }
   } else {
-    if (!g_suppress_logging)
-      LOG(ERROR) << "Invalid message: " << ValidationErrorToString(error);
+    LOG(ERROR) << "Invalid message: " << ValidationErrorToString(error);
     if (context->message()) {
       context->message()->NotifyBadMessage(
           base::StringPrintf("Validation failed for %s [%s]",
@@ -94,25 +88,6 @@
   }
 }
 
-void ReportValidationErrorForMessage(
-    mojo::Message* message,
-    ValidationError error,
-    const char* description) {
-  ValidationContext validation_context(nullptr, 0, 0, 0, message, description);
-  ReportValidationError(&validation_context, error);
-}
-
-ScopedSuppressValidationErrorLoggingForTests
-    ::ScopedSuppressValidationErrorLoggingForTests()
-    : was_suppressed_(g_suppress_logging) {
-  g_suppress_logging = true;
-}
-
-ScopedSuppressValidationErrorLoggingForTests
-    ::~ScopedSuppressValidationErrorLoggingForTests() {
-  g_suppress_logging = was_suppressed_;
-}
-
 ValidationErrorObserverForTesting::ValidationErrorObserverForTesting(
     const base::Closure& callback)
     : last_error_(VALIDATION_ERROR_NONE), callback_(callback) {
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.h b/mojo/public/cpp/bindings/lib/validation_errors.h
index 122418d..ec0aa27 100644
--- a/mojo/public/cpp/bindings/lib/validation_errors.h
+++ b/mojo/public/cpp/bindings/lib/validation_errors.h
@@ -8,13 +8,9 @@
 #include "base/callback.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/lib/validation_context.h"
 
 namespace mojo {
-
-class Message;
-
 namespace internal {
 
 enum ValidationError {
@@ -71,41 +67,17 @@
   // Message deserialization failure, for example due to rejection by custom
   // validation logic.
   VALIDATION_ERROR_DESERIALIZATION_FAILED,
-  // The message contains a too deeply nested value, for example a recursively
-  // defined field which runtime value is too large.
-  VALIDATION_ERROR_MAX_RECURSION_DEPTH,
 };
 
-MOJO_CPP_BINDINGS_EXPORT const char* ValidationErrorToString(
-    ValidationError error);
+const char* ValidationErrorToString(ValidationError error);
 
-MOJO_CPP_BINDINGS_EXPORT void ReportValidationError(
-    ValidationContext* context,
-    ValidationError error,
-    const char* description = nullptr);
-
-MOJO_CPP_BINDINGS_EXPORT void ReportValidationErrorForMessage(
-    mojo::Message* message,
-    ValidationError error,
-    const char* description = nullptr);
-
-// This class may be used by tests to suppress validation error logging. This is
-// not thread-safe and must only be instantiated on the main thread with no
-// other threads using Mojo bindings at the time of construction or destruction.
-class MOJO_CPP_BINDINGS_EXPORT ScopedSuppressValidationErrorLoggingForTests {
- public:
-  ScopedSuppressValidationErrorLoggingForTests();
-  ~ScopedSuppressValidationErrorLoggingForTests();
-
- private:
-  const bool was_suppressed_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedSuppressValidationErrorLoggingForTests);
-};
+void ReportValidationError(ValidationContext* context,
+                           ValidationError error,
+                           const char* description = nullptr);
 
 // Only used by validation tests and when there is only one thread doing message
 // validation.
-class MOJO_CPP_BINDINGS_EXPORT ValidationErrorObserverForTesting {
+class ValidationErrorObserverForTesting {
  public:
   explicit ValidationErrorObserverForTesting(const base::Closure& callback);
   ~ValidationErrorObserverForTesting();
@@ -127,11 +99,11 @@
 //
 // The function returns true if the error is recorded (by a
 // SerializationWarningObserverForTesting object), false otherwise.
-MOJO_CPP_BINDINGS_EXPORT bool ReportSerializationWarning(ValidationError error);
+bool ReportSerializationWarning(ValidationError error);
 
 // Only used by serialization tests and when there is only one thread doing
 // message serialization.
-class MOJO_CPP_BINDINGS_EXPORT SerializationWarningObserverForTesting {
+class SerializationWarningObserverForTesting {
  public:
   SerializationWarningObserverForTesting();
   ~SerializationWarningObserverForTesting();
diff --git a/mojo/public/cpp/bindings/lib/validation_util.cc b/mojo/public/cpp/bindings/lib/validation_util.cc
index 7614df5..9e63521 100644
--- a/mojo/public/cpp/bindings/lib/validation_util.cc
+++ b/mojo/public/cpp/bindings/lib/validation_util.cc
@@ -16,6 +16,16 @@
 namespace mojo {
 namespace internal {
 
+bool ValidateEncodedPointer(const uint64_t* offset) {
+  // - Make sure |*offset| is no more than 32-bits.
+  // - Cast |offset| to uintptr_t so overflow behavior is well defined across
+  //   32-bit and 64-bit systems.
+  return *offset <= std::numeric_limits<uint32_t>::max() &&
+         (reinterpret_cast<uintptr_t>(offset) +
+              static_cast<uint32_t>(*offset) >=
+          reinterpret_cast<uintptr_t>(offset));
+}
+
 bool ValidateStructHeaderAndClaimMemory(const void* data,
                                         ValidationContext* validation_context) {
   if (!IsAligned(data)) {
@@ -46,17 +56,20 @@
   return true;
 }
 
-bool ValidateNonInlinedUnionHeaderAndClaimMemory(
-    const void* data,
-    ValidationContext* validation_context) {
+bool ValidateUnionHeaderAndClaimMemory(const void* data,
+                                       bool inlined,
+                                       ValidationContext* validation_context) {
   if (!IsAligned(data)) {
     ReportValidationError(validation_context,
                           VALIDATION_ERROR_MISALIGNED_OBJECT);
     return false;
   }
 
-  if (!validation_context->ClaimMemory(data, kUnionDataSize) ||
-      *static_cast<const uint32_t*>(data) != kUnionDataSize) {
+  // If the union is inlined in another structure its memory was already
+  // claimed.
+  // This ONLY applies to the union itself, NOT anything which the union points
+  // to.
+  if (!inlined && !validation_context->ClaimMemory(data, kUnionDataSize)) {
     ReportValidationError(validation_context,
                           VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
     return false;
@@ -100,12 +113,41 @@
   return true;
 }
 
-bool IsHandleOrInterfaceValid(const AssociatedInterface_Data& input) {
-  return input.handle.is_valid();
+bool ValidateControlRequest(const Message* message,
+                            ValidationContext* validation_context) {
+  switch (message->header()->name) {
+    case kRunMessageId:
+      return ValidateMessageIsRequestExpectingResponse(message,
+                                                       validation_context) &&
+             ValidateMessagePayload<RunMessageParams_Data>(message,
+                                                           validation_context);
+    case kRunOrClosePipeMessageId:
+      return ValidateMessageIsRequestWithoutResponse(message,
+                                                     validation_context) &&
+          ValidateMessagePayload<RunOrClosePipeMessageParams_Data>(
+              message, validation_context);
+  }
+  return false;
 }
 
-bool IsHandleOrInterfaceValid(const AssociatedEndpointHandle_Data& input) {
-  return input.is_valid();
+bool ValidateControlResponse(const Message* message,
+                             ValidationContext* validation_context) {
+  if (!ValidateMessageIsResponse(message, validation_context))
+    return false;
+  switch (message->header()->name) {
+    case kRunMessageId:
+      return ValidateMessagePayload<RunResponseMessageParams_Data>(
+          message, validation_context);
+  }
+  return false;
+}
+
+bool IsHandleOrInterfaceValid(const AssociatedInterface_Data& input) {
+  return IsValidInterfaceId(input.interface_id);
+}
+
+bool IsHandleOrInterfaceValid(const AssociatedInterfaceRequest_Data& input) {
+  return IsValidInterfaceId(input.interface_id);
 }
 
 bool IsHandleOrInterfaceValid(const Interface_Data& input) {
@@ -130,7 +172,7 @@
 }
 
 bool ValidateHandleOrInterfaceNonNullable(
-    const AssociatedEndpointHandle_Data& input,
+    const AssociatedInterfaceRequest_Data& input,
     const char* error_message,
     ValidationContext* validation_context) {
   if (IsHandleOrInterfaceValid(input))
@@ -170,7 +212,7 @@
 
 bool ValidateHandleOrInterface(const AssociatedInterface_Data& input,
                                ValidationContext* validation_context) {
-  if (validation_context->ClaimAssociatedEndpointHandle(input.handle))
+  if (!IsMasterInterfaceId(input.interface_id))
     return true;
 
   ReportValidationError(validation_context,
@@ -178,9 +220,9 @@
   return false;
 }
 
-bool ValidateHandleOrInterface(const AssociatedEndpointHandle_Data& input,
+bool ValidateHandleOrInterface(const AssociatedInterfaceRequest_Data& input,
                                ValidationContext* validation_context) {
-  if (validation_context->ClaimAssociatedEndpointHandle(input))
+  if (!IsMasterInterfaceId(input.interface_id))
     return true;
 
   ReportValidationError(validation_context,
diff --git a/mojo/public/cpp/bindings/lib/validation_util.h b/mojo/public/cpp/bindings/lib/validation_util.h
index ea5a991..c883392 100644
--- a/mojo/public/cpp/bindings/lib/validation_util.h
+++ b/mojo/public/cpp/bindings/lib/validation_util.h
@@ -7,7 +7,6 @@
 
 #include <stdint.h>
 
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
 #include "mojo/public/cpp/bindings/lib/serialization_util.h"
 #include "mojo/public/cpp/bindings/lib/validate_params.h"
@@ -20,15 +19,7 @@
 
 // Checks whether decoding the pointer will overflow and produce a pointer
 // smaller than |offset|.
-inline bool ValidateEncodedPointer(const uint64_t* offset) {
-  // - Make sure |*offset| is no more than 32-bits.
-  // - Cast |offset| to uintptr_t so overflow behavior is well defined across
-  //   32-bit and 64-bit systems.
-  return *offset <= std::numeric_limits<uint32_t>::max() &&
-         (reinterpret_cast<uintptr_t>(offset) +
-              static_cast<uint32_t>(*offset) >=
-          reinterpret_cast<uintptr_t>(offset));
-}
+bool ValidateEncodedPointer(const uint64_t* offset);
 
 template <typename T>
 bool ValidatePointer(const Pointer<T>& input,
@@ -47,32 +38,30 @@
 // |validation_context|. On success, the memory range is marked as occupied.
 // Note: Does not verify |version| or that |num_bytes| is correct for the
 // claimed version.
-MOJO_CPP_BINDINGS_EXPORT bool ValidateStructHeaderAndClaimMemory(
-    const void* data,
-    ValidationContext* validation_context);
+bool ValidateStructHeaderAndClaimMemory(const void* data,
+                                        ValidationContext* validation_context);
 
 // Validates that |data| contains a valid union header, in terms of alignment
-// and size. It checks that the memory range [data, data + kUnionDataSize) is
-// not marked as occupied by other objects in |validation_context|. On success,
-// the memory range is marked as occupied.
-MOJO_CPP_BINDINGS_EXPORT bool ValidateNonInlinedUnionHeaderAndClaimMemory(
-    const void* data,
-    ValidationContext* validation_context);
+// and size. If not inlined, it checks that the memory range
+// [data, data + num_bytes) is not marked as occupied by other objects in
+// |validation_context|. On success, the memory range is marked as occupied.
+bool ValidateUnionHeaderAndClaimMemory(const void* data,
+                                       bool inlined,
+                                       ValidationContext* validation_context);
 
 // Validates that the message is a request which doesn't expect a response.
-MOJO_CPP_BINDINGS_EXPORT bool ValidateMessageIsRequestWithoutResponse(
+bool ValidateMessageIsRequestWithoutResponse(
     const Message* message,
     ValidationContext* validation_context);
 
 // Validates that the message is a request expecting a response.
-MOJO_CPP_BINDINGS_EXPORT bool ValidateMessageIsRequestExpectingResponse(
+bool ValidateMessageIsRequestExpectingResponse(
     const Message* message,
     ValidationContext* validation_context);
 
 // Validates that the message is a response.
-MOJO_CPP_BINDINGS_EXPORT bool ValidateMessageIsResponse(
-    const Message* message,
-    ValidationContext* validation_context);
+bool ValidateMessageIsResponse(const Message* message,
+                               ValidationContext* validation_context);
 
 // Validates that the message payload is a valid struct of type ParamsType.
 template <typename ParamsType>
@@ -81,6 +70,13 @@
   return ParamsType::Validate(message->payload(), validation_context);
 }
 
+// The following methods validate control messages defined in
+// interface_control_messages.mojom.
+bool ValidateControlRequest(const Message* message,
+                            ValidationContext* validation_context);
+bool ValidateControlResponse(const Message* message,
+                             ValidationContext* validation_context);
+
 // The following Validate.*NonNullable() functions validate that the given
 // |input| is not null/invalid.
 template <typename T>
@@ -109,28 +105,24 @@
   return false;
 }
 
-MOJO_CPP_BINDINGS_EXPORT bool IsHandleOrInterfaceValid(
-    const AssociatedInterface_Data& input);
-MOJO_CPP_BINDINGS_EXPORT bool IsHandleOrInterfaceValid(
-    const AssociatedEndpointHandle_Data& input);
-MOJO_CPP_BINDINGS_EXPORT bool IsHandleOrInterfaceValid(
-    const Interface_Data& input);
-MOJO_CPP_BINDINGS_EXPORT bool IsHandleOrInterfaceValid(
-    const Handle_Data& input);
+bool IsHandleOrInterfaceValid(const AssociatedInterface_Data& input);
+bool IsHandleOrInterfaceValid(const AssociatedInterfaceRequest_Data& input);
+bool IsHandleOrInterfaceValid(const Interface_Data& input);
+bool IsHandleOrInterfaceValid(const Handle_Data& input);
 
-MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterfaceNonNullable(
+bool ValidateHandleOrInterfaceNonNullable(
     const AssociatedInterface_Data& input,
     const char* error_message,
     ValidationContext* validation_context);
-MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterfaceNonNullable(
-    const AssociatedEndpointHandle_Data& input,
+bool ValidateHandleOrInterfaceNonNullable(
+    const AssociatedInterfaceRequest_Data& input,
     const char* error_message,
     ValidationContext* validation_context);
-MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterfaceNonNullable(
+bool ValidateHandleOrInterfaceNonNullable(
     const Interface_Data& input,
     const char* error_message,
     ValidationContext* validation_context);
-MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterfaceNonNullable(
+bool ValidateHandleOrInterfaceNonNullable(
     const Handle_Data& input,
     const char* error_message,
     ValidationContext* validation_context);
@@ -139,12 +131,6 @@
 bool ValidateContainer(const Pointer<T>& input,
                        ValidationContext* validation_context,
                        const ContainerValidateParams* validate_params) {
-  ValidationContext::ScopedDepthTracker depth_tracker(validation_context);
-  if (validation_context->ExceedsMaxDepth()) {
-    ReportValidationError(validation_context,
-                          VALIDATION_ERROR_MAX_RECURSION_DEPTH);
-    return false;
-  }
   return ValidatePointer(input, validation_context) &&
          T::Validate(input.Get(), validation_context, validate_params);
 }
@@ -152,12 +138,6 @@
 template <typename T>
 bool ValidateStruct(const Pointer<T>& input,
                     ValidationContext* validation_context) {
-  ValidationContext::ScopedDepthTracker depth_tracker(validation_context);
-  if (validation_context->ExceedsMaxDepth()) {
-    ReportValidationError(validation_context,
-                          VALIDATION_ERROR_MAX_RECURSION_DEPTH);
-    return false;
-  }
   return ValidatePointer(input, validation_context) &&
          T::Validate(input.Get(), validation_context);
 }
@@ -165,40 +145,24 @@
 template <typename T>
 bool ValidateInlinedUnion(const T& input,
                           ValidationContext* validation_context) {
-  ValidationContext::ScopedDepthTracker depth_tracker(validation_context);
-  if (validation_context->ExceedsMaxDepth()) {
-    ReportValidationError(validation_context,
-                          VALIDATION_ERROR_MAX_RECURSION_DEPTH);
-    return false;
-  }
   return T::Validate(&input, validation_context, true);
 }
 
 template <typename T>
 bool ValidateNonInlinedUnion(const Pointer<T>& input,
                              ValidationContext* validation_context) {
-  ValidationContext::ScopedDepthTracker depth_tracker(validation_context);
-  if (validation_context->ExceedsMaxDepth()) {
-    ReportValidationError(validation_context,
-                          VALIDATION_ERROR_MAX_RECURSION_DEPTH);
-    return false;
-  }
   return ValidatePointer(input, validation_context) &&
          T::Validate(input.Get(), validation_context, false);
 }
 
-MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterface(
-    const AssociatedInterface_Data& input,
-    ValidationContext* validation_context);
-MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterface(
-    const AssociatedEndpointHandle_Data& input,
-    ValidationContext* validation_context);
-MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterface(
-    const Interface_Data& input,
-    ValidationContext* validation_context);
-MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterface(
-    const Handle_Data& input,
-    ValidationContext* validation_context);
+bool ValidateHandleOrInterface(const AssociatedInterface_Data& input,
+                               ValidationContext* validation_context);
+bool ValidateHandleOrInterface(const AssociatedInterfaceRequest_Data& input,
+                               ValidationContext* validation_context);
+bool ValidateHandleOrInterface(const Interface_Data& input,
+                               ValidationContext* validation_context);
+bool ValidateHandleOrInterface(const Handle_Data& input,
+                               ValidationContext* validation_context);
 
 }  // namespace internal
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h b/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h
index cb24bc4..edbf27b 100644
--- a/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h
+++ b/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h
@@ -7,14 +7,14 @@
 
 #include <type_traits>
 
-#include "mojo/public/cpp/bindings/clone_traits.h"
-#include "mojo/public/cpp/bindings/lib/equals_traits.h"
+#include "mojo/public/cpp/bindings/lib/clone_equals_util.h"
 #include "third_party/WebKit/Source/wtf/HashMap.h"
 #include "third_party/WebKit/Source/wtf/Optional.h"
 #include "third_party/WebKit/Source/wtf/Vector.h"
 #include "third_party/WebKit/Source/wtf/text/WTFString.h"
 
 namespace mojo {
+namespace internal {
 
 template <typename T>
 struct CloneTraits<WTF::Vector<T>, false> {
@@ -22,7 +22,7 @@
     WTF::Vector<T> result;
     result.reserveCapacity(input.size());
     for (const auto& element : input)
-      result.push_back(mojo::Clone(element));
+      result.append(internal::Clone(element));
 
     return result;
   }
@@ -34,13 +34,11 @@
     WTF::HashMap<K, V> result;
     auto input_end = input.end();
     for (auto it = input.begin(); it != input_end; ++it)
-      result.add(mojo::Clone(it->key), mojo::Clone(it->value));
+      result.add(internal::Clone(it->key), internal::Clone(it->value));
     return result;
   }
 };
 
-namespace internal {
-
 template <typename T>
 struct EqualsTraits<WTF::Vector<T>, false> {
   static bool Equals(const WTF::Vector<T>& a, const WTF::Vector<T>& b) {
diff --git a/mojo/public/cpp/bindings/lib/wtf_serialization.h b/mojo/public/cpp/bindings/lib/wtf_serialization.h
index 0f112b9..132e19c 100644
--- a/mojo/public/cpp/bindings/lib/wtf_serialization.h
+++ b/mojo/public/cpp/bindings/lib/wtf_serialization.h
@@ -5,7 +5,9 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_SERIALIZATION_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_SERIALIZATION_H_
 
+#include "mojo/public/cpp/bindings/array_traits_wtf.h"
 #include "mojo/public/cpp/bindings/array_traits_wtf_vector.h"
+#include "mojo/public/cpp/bindings/map_traits_wtf.h"
 #include "mojo/public/cpp/bindings/map_traits_wtf_hash_map.h"
 #include "mojo/public/cpp/bindings/string_traits_wtf.h"
 
diff --git a/mojo/public/cpp/bindings/map.h b/mojo/public/cpp/bindings/map.h
index c1ba075..d4c7952 100644
--- a/mojo/public/cpp/bindings/map.h
+++ b/mojo/public/cpp/bindings/map.h
@@ -5,37 +5,299 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_MAP_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_MAP_H_
 
+#include <stddef.h>
 #include <map>
 #include <unordered_map>
 #include <utility>
 
+#include "base/logging.h"
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/array.h"
+#include "mojo/public/cpp/bindings/lib/map_data_internal.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+#include "mojo/public/cpp/bindings/type_converter.h"
+
 namespace mojo {
 
-// TODO(yzshen): These conversion functions should be removed and callsites
-// should be revisited and changed to use the same map type.
-template <typename Key, typename Value>
-std::unordered_map<Key, Value> MapToUnorderedMap(
-    const std::map<Key, Value>& input) {
-  return std::unordered_map<Key, Value>(input.begin(), input.end());
-}
+// A move-only map that can handle move-only values. Map has the following
+// characteristics:
+//   - The map itself can be null, and this is distinct from empty.
+//   - Keys must not be move-only.
+//   - The Key-type's "<" operator is used to sort the entries, and also is
+//     used to determine equality of the key values.
+//   - There can only be one entry per unique key.
+//   - Values of move-only types will be moved into the Map when they are added
+//     using the insert() method.
+template <typename K, typename V>
+class Map {
+ public:
+  using Key = K;
+  using Value = V;
 
-template <typename Key, typename Value>
-std::unordered_map<Key, Value> MapToUnorderedMap(std::map<Key, Value>&& input) {
-  return std::unordered_map<Key, Value>(std::make_move_iterator(input.begin()),
-                                        std::make_move_iterator(input.end()));
-}
+  // Map keys cannot be move only classes.
+  static_assert(!internal::IsMoveOnlyType<Key>::value,
+                "Map keys cannot be move only types.");
 
-template <typename Key, typename Value>
-std::map<Key, Value> UnorderedMapToMap(
-    const std::unordered_map<Key, Value>& input) {
-  return std::map<Key, Value>(input.begin(), input.end());
-}
+  using Iterator = typename std::map<Key, Value>::iterator;
+  using ConstIterator = typename std::map<Key, Value>::const_iterator;
 
-template <typename Key, typename Value>
-std::map<Key, Value> UnorderedMapToMap(std::unordered_map<Key, Value>&& input) {
-  return std::map<Key, Value>(std::make_move_iterator(input.begin()),
-                              std::make_move_iterator(input.end()));
-}
+  // Constructs an empty map.
+  Map() : is_null_(false) {}
+  // Constructs a null map.
+  Map(std::nullptr_t null_pointer) : is_null_(true) {}
+
+  // Constructs a non-null Map containing the specified |keys| mapped to the
+  // corresponding |values|.
+  Map(mojo::Array<Key> keys, mojo::Array<Value> values) : is_null_(false) {
+    DCHECK(keys.size() == values.size());
+    for (size_t i = 0; i < keys.size(); ++i)
+      map_.insert(std::make_pair(keys[i], std::move(values[i])));
+  }
+
+  ~Map() {}
+
+  Map(std::map<Key, Value>&& other) : map_(std::move(other)), is_null_(false) {}
+  Map(Map&& other) : is_null_(true) { Take(&other); }
+
+  Map& operator=(std::map<Key, Value>&& other) {
+    is_null_ = false;
+    map_ = std::move(other);
+    return *this;
+  }
+  Map& operator=(Map&& other) {
+    Take(&other);
+    return *this;
+  }
+
+  Map& operator=(std::nullptr_t null_pointer) {
+    is_null_ = true;
+    map_.clear();
+    return *this;
+  }
+
+  // Copies the contents of some other type of map into a new Map using a
+  // TypeConverter. A TypeConverter for std::map to Map is defined below.
+  template <typename U>
+  static Map From(const U& other) {
+    return TypeConverter<Map, U>::Convert(other);
+  }
+
+  // Copies the contents of the Map into some other type of map. A TypeConverter
+  // for Map to std::map is defined below.
+  template <typename U>
+  U To() const {
+    return TypeConverter<U, Map>::Convert(*this);
+  }
+
+  // Indicates whether the map is null (which is distinct from empty).
+  bool is_null() const { return is_null_; }
+
+  // Indicates whether the map is empty (which is distinct from null).
+  bool empty() const { return map_.empty() && !is_null_; }
+
+  // Indicates the number of keys in the map, which will be zero if the map is
+  // null.
+  size_t size() const { return map_.size(); }
+
+  // Inserts a key-value pair into the map. Like std::map, this does not insert
+  // |value| if |key| is already a member of the map.
+  void insert(const Key& key, const Value& value) {
+    is_null_ = false;
+    map_.insert(std::make_pair(key, value));
+  }
+  void insert(const Key& key, Value&& value) {
+    is_null_ = false;
+    map_.insert(std::make_pair(key, std::move(value)));
+  }
+
+  // Returns a reference to the value associated with the specified key,
+  // crashing the process if the key is not present in the map.
+  Value& at(const Key& key) { return map_.at(key); }
+  const Value& at(const Key& key) const { return map_.at(key); }
+
+  // Returns a reference to the value associated with the specified key,
+  // creating a new entry if the key is not already present in the map. A
+  // newly-created value will be value-initialized (meaning that it will be
+  // initialized by the default constructor of the value type, if any, or else
+  // will be zero-initialized).
+  Value& operator[](const Key& key) {
+    is_null_ = false;
+    return map_[key];
+  }
+
+  // Sets the map to empty (even if previously it was null).
+  void SetToEmpty() {
+    is_null_ = false;
+    map_.clear();
+  }
+
+  // Returns a const reference to the std::map managed by this class. If this
+  // object is null, the return value will be an empty map.
+  const std::map<Key, Value>& storage() const { return map_; }
+
+  // Passes the underlying storage and resets this map to null.
+  std::map<Key, Value> PassStorage() {
+    is_null_ = true;
+    return std::move(map_);
+  }
+
+  operator const std::map<Key, Value>&() const { return map_; }
+
+  // Swaps the contents of this Map with another Map of the same type (including
+  // nullness).
+  void Swap(Map<Key, Value>* other) {
+    std::swap(is_null_, other->is_null_);
+    map_.swap(other->map_);
+  }
+
+  // Swaps the contents of this Map with an std::map containing keys and values
+  // of the same type. Since std::map cannot represent the null state, the
+  // std::map will be empty if Map is null. The Map will always be left in a
+  // non-null state.
+  void Swap(std::map<Key, Value>* other) {
+    is_null_ = false;
+    map_.swap(*other);
+  }
+
+  // Removes all contents from the Map and places them into parallel key/value
+  // arrays. Each key will be copied from the source to the destination, and
+  // values will be copied unless their type is designated move-only, in which
+  // case they will be moved. Either way, the Map will be left in a null state.
+  void DecomposeMapTo(mojo::Array<Key>* keys, mojo::Array<Value>* values) {
+    std::vector<Key> key_vector;
+    key_vector.reserve(map_.size());
+    std::vector<Value> value_vector;
+    value_vector.reserve(map_.size());
+
+    for (auto& entry : map_) {
+      key_vector.push_back(entry.first);
+      value_vector.push_back(std::move(entry.second));
+    }
+
+    map_.clear();
+    is_null_ = true;
+
+    keys->Swap(&key_vector);
+    values->Swap(&value_vector);
+  }
+
+  // Returns a new Map that contains a copy of the contents of this map. If the
+  // key/value type defines a Clone() method, it will be used; otherwise copy
+  // constructor/assignment will be used.
+  //
+  // Please note that calling this method will fail compilation if the key/value
+  // type cannot be cloned (which usually means that it is a Mojo handle type or
+  // a type containing Mojo handles).
+  Map Clone() const {
+    Map result;
+    result.is_null_ = is_null_;
+    for (auto it = map_.begin(); it != map_.end(); ++it) {
+      result.map_.insert(std::make_pair(internal::Clone(it->first),
+                                        internal::Clone(it->second)));
+    }
+    return result;
+  }
+
+  // Indicates whether the contents of this map are equal to those of another
+  // Map (including nullness). If the key/value type defines an Equals() method,
+  // it will be used; otherwise == operator will be used.
+  bool Equals(const Map& other) const {
+    if (is_null() != other.is_null())
+      return false;
+    if (size() != other.size())
+      return false;
+    auto i = begin();
+    auto j = other.begin();
+    while (i != end()) {
+      if (!internal::Equals(i->first, j->first))
+        return false;
+      if (!internal::Equals(i->second, j->second))
+        return false;
+      ++i;
+      ++j;
+    }
+    return true;
+  }
+
+  // Provide read-only iteration over map members in a way similar to STL
+  // collections.
+  ConstIterator begin() const { return map_.begin(); }
+  Iterator begin() { return map_.begin(); }
+
+  ConstIterator end() const { return map_.end(); }
+  Iterator end() { return map_.end(); }
+
+  // Returns the iterator pointing to the entry for |key|, if present, or else
+  // returns end().
+  ConstIterator find(const Key& key) const { return map_.find(key); }
+  Iterator find(const Key& key) { return map_.find(key); }
+
+ private:
+  typedef std::map<Key, Value> Map::*Testable;
+
+ public:
+  // The Map may be used in boolean expressions to determine if it is non-null,
+  // but is not implicitly convertible to an actual bool value (which would be
+  // dangerous).
+  operator Testable() const { return is_null_ ? 0 : &Map::map_; }
+
+ private:
+  // Forbid the == and != operators explicitly, otherwise Map will be converted
+  // to Testable to do == or != comparison.
+  template <typename T, typename U>
+  bool operator==(const Map<T, U>& other) const = delete;
+  template <typename T, typename U>
+  bool operator!=(const Map<T, U>& other) const = delete;
+
+  void Take(Map* other) {
+    operator=(nullptr);
+    Swap(other);
+  }
+
+  std::map<Key, Value> map_;
+  bool is_null_;
+
+  DISALLOW_COPY_AND_ASSIGN(Map);
+};
+
+// Copies the contents of an std::map to a new Map, optionally changing the
+// types of the keys and values along the way using TypeConverter.
+template <typename MojoKey,
+          typename MojoValue,
+          typename STLKey,
+          typename STLValue>
+struct TypeConverter<Map<MojoKey, MojoValue>, std::map<STLKey, STLValue>> {
+  static Map<MojoKey, MojoValue> Convert(
+      const std::map<STLKey, STLValue>& input) {
+    Map<MojoKey, MojoValue> result;
+    for (auto& pair : input) {
+      result.insert(TypeConverter<MojoKey, STLKey>::Convert(pair.first),
+                    TypeConverter<MojoValue, STLValue>::Convert(pair.second));
+    }
+    return result;
+  }
+};
+
+// Copies the contents of a Map to an std::map, optionally changing the types of
+// the keys and values along the way using TypeConverter.
+template <typename MojoKey,
+          typename MojoValue,
+          typename STLKey,
+          typename STLValue>
+struct TypeConverter<std::map<STLKey, STLValue>, Map<MojoKey, MojoValue>> {
+  static std::map<STLKey, STLValue> Convert(
+      const Map<MojoKey, MojoValue>& input) {
+    std::map<STLKey, STLValue> result;
+    if (!input.is_null()) {
+      for (auto it = input.begin(); it != input.end(); ++it) {
+        result.insert(std::make_pair(
+            TypeConverter<STLKey, MojoKey>::Convert(it->first),
+            TypeConverter<STLValue, MojoValue>::Convert(it->second)));
+      }
+    }
+    return result;
+  }
+};
 
 }  // namespace mojo
 
diff --git a/mojo/public/cpp/bindings/map_data_view.h b/mojo/public/cpp/bindings/map_data_view.h
deleted file mode 100644
index a65bb9e..0000000
--- a/mojo/public/cpp/bindings/map_data_view.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_MAP_DATA_VIEW_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_MAP_DATA_VIEW_H_
-
-#include "base/logging.h"
-#include "mojo/public/cpp/bindings/array_data_view.h"
-#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
-#include "mojo/public/cpp/bindings/lib/map_data_internal.h"
-#include "mojo/public/cpp/bindings/lib/serialization_context.h"
-#include "mojo/public/cpp/bindings/lib/serialization_forward.h"
-
-namespace mojo {
-
-template <typename K, typename V>
-class MapDataView {
- public:
-  using Data_ = typename internal::MojomTypeTraits<MapDataView<K, V>>::Data;
-
-  MapDataView() {}
-
-  MapDataView(Data_* data, internal::SerializationContext* context)
-      : keys_(data ? data->keys.Get() : nullptr, context),
-        values_(data ? data->values.Get() : nullptr, context) {}
-
-  bool is_null() const {
-    DCHECK_EQ(keys_.is_null(), values_.is_null());
-    return keys_.is_null();
-  }
-
-  size_t size() const {
-    DCHECK_EQ(keys_.size(), values_.size());
-    return keys_.size();
-  }
-
-  ArrayDataView<K>& keys() { return keys_; }
-  const ArrayDataView<K>& keys() const { return keys_; }
-
-  template <typename U>
-  bool ReadKeys(U* output) {
-    return internal::Deserialize<ArrayDataView<K>>(keys_.data_, output,
-                                                   keys_.context_);
-  }
-
-  ArrayDataView<V>& values() { return values_; }
-  const ArrayDataView<V>& values() const { return values_; }
-
-  template <typename U>
-  bool ReadValues(U* output) {
-    return internal::Deserialize<ArrayDataView<V>>(values_.data_, output,
-                                                   values_.context_);
-  }
-
- private:
-  ArrayDataView<K> keys_;
-  ArrayDataView<V> values_;
-};
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_MAP_DATA_VIEW_H_
diff --git a/mojo/public/cpp/bindings/map_traits.h b/mojo/public/cpp/bindings/map_traits.h
index 5c0d8b2..01dd66d 100644
--- a/mojo/public/cpp/bindings/map_traits.h
+++ b/mojo/public/cpp/bindings/map_traits.h
@@ -37,13 +37,13 @@
 //     static const V& GetValue(CustomConstIterator& iterator);
 //
 //     // Returning false results in deserialization failure and causes the
-//     // message pipe receiving it to be disconnected. |IK| and |IV| are
-//     // separate input key/value template parameters that allows for the
-//     // the key/value types to be forwarded.
-//     template <typename IK, typename IV>
+//     // message pipe receiving it to be disconnected.
 //     static bool Insert(CustomMap<K, V>& input,
-//                        IK&& key,
-//                        IV&& value);
+//                        const K& key,
+//                        V&& value);
+//     static bool Insert(CustomMap<K, V>& input,
+//                        const K& key,
+//                        const V& value);
 //
 //     static void SetToEmpty(CustomMap<K, V>* output);
 //   };
diff --git a/mojo/public/cpp/bindings/map_traits_standard.h b/mojo/public/cpp/bindings/map_traits_standard.h
new file mode 100644
index 0000000..0c76890
--- /dev/null
+++ b/mojo/public/cpp/bindings/map_traits_standard.h
@@ -0,0 +1,53 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_MAP_TRAITS_STANDARD_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_MAP_TRAITS_STANDARD_H_
+
+#include "mojo/public/cpp/bindings/map.h"
+#include "mojo/public/cpp/bindings/map_traits.h"
+
+namespace mojo {
+
+template <typename K, typename V>
+struct MapTraits<Map<K, V>> {
+  using Key = K;
+  using Value = V;
+  using Iterator = typename Map<K, V>::Iterator;
+  using ConstIterator = typename Map<K, V>::ConstIterator;
+
+  static bool IsNull(const Map<K, V>& input) { return input.is_null(); }
+  static void SetToNull(Map<K, V>* output) { *output = nullptr; }
+
+  static size_t GetSize(const Map<K, V>& input) { return input.size(); }
+
+  static ConstIterator GetBegin(const Map<K, V>& input) {
+    return input.begin();
+  }
+  static Iterator GetBegin(Map<K, V>& input) { return input.begin(); }
+
+  static void AdvanceIterator(ConstIterator& iterator) { iterator++; }
+  static void AdvanceIterator(Iterator& iterator) { iterator++; }
+
+  static const K& GetKey(Iterator& iterator) { return iterator->first; }
+  static const K& GetKey(ConstIterator& iterator) { return iterator->first; }
+
+  static V& GetValue(Iterator& iterator) { return iterator->second; }
+  static const V& GetValue(ConstIterator& iterator) { return iterator->second; }
+
+  static bool Insert(Map<K, V>& input, const K& key, V&& value) {
+    input.insert(key, std::forward<V>(value));
+    return true;
+  }
+  static bool Insert(Map<K, V>& input, const K& key, const V& value) {
+    input.insert(key, value);
+    return true;
+  }
+
+  static void SetToEmpty(Map<K, V>* output) { output->SetToEmpty(); }
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_MAP_TRAITS_STANDARD_H_
diff --git a/mojo/public/cpp/bindings/map_traits_stl.h b/mojo/public/cpp/bindings/map_traits_stl.h
index 83a4399..ff79a20 100644
--- a/mojo/public/cpp/bindings/map_traits_stl.h
+++ b/mojo/public/cpp/bindings/map_traits_stl.h
@@ -94,10 +94,14 @@
   static V& GetValue(Iterator& iterator) { return iterator->second; }
   static const V& GetValue(ConstIterator& iterator) { return iterator->second; }
 
-  template <typename IK, typename IV>
-  static bool Insert(std::unordered_map<K, V>& input, IK&& key, IV&& value) {
-    input.insert(
-        std::make_pair(std::forward<IK>(key), std::forward<IV>(value)));
+  static bool Insert(std::unordered_map<K, V>& input, const K& key, V&& value) {
+    input.insert(std::make_pair(key, std::forward<V>(value)));
+    return true;
+  }
+  static bool Insert(std::unordered_map<K, V>& input,
+                     const K& key,
+                     const V& value) {
+    input.insert(std::make_pair(key, value));
     return true;
   }
 
diff --git a/mojo/public/cpp/bindings/map_traits_wtf.h b/mojo/public/cpp/bindings/map_traits_wtf.h
new file mode 100644
index 0000000..805e4c9
--- /dev/null
+++ b/mojo/public/cpp/bindings/map_traits_wtf.h
@@ -0,0 +1,62 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_MAP_TRAITS_WTF_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_MAP_TRAITS_WTF_H_
+
+#include "base/logging.h"
+#include "mojo/public/cpp/bindings/map_traits.h"
+#include "mojo/public/cpp/bindings/wtf_map.h"
+
+namespace mojo {
+
+template <typename K, typename V>
+struct MapTraits<WTFMap<K, V>> {
+  using Key = K;
+  using Value = V;
+  using Iterator = typename WTFMap<K, V>::Iterator;
+  using ConstIterator = typename WTFMap<K, V>::ConstIterator;
+
+  static bool IsNull(const WTFMap<K, V>& input) { return input.is_null(); }
+  static void SetToNull(WTFMap<K, V>* output) { *output = nullptr; }
+
+  static size_t GetSize(const WTFMap<K, V>& input) { return input.size(); }
+
+  static ConstIterator GetBegin(const WTFMap<K, V>& input) {
+    return input.begin();
+  }
+  static Iterator GetBegin(WTFMap<K, V>& input) { return input.begin(); }
+
+  static void AdvanceIterator(ConstIterator& iterator) { ++iterator; }
+  static void AdvanceIterator(Iterator& iterator) { ++iterator; }
+
+  static const K& GetKey(Iterator& iterator) { return iterator->key; }
+  static const K& GetKey(ConstIterator& iterator) { return iterator->key; }
+
+  static V& GetValue(Iterator& iterator) { return iterator->value; }
+  static const V& GetValue(ConstIterator& iterator) { return iterator->value; }
+
+  static bool Insert(WTFMap<K, V>& input, const K& key, V&& value) {
+    if (!WTFMap<K, V>::IsValidKey(key)) {
+      LOG(ERROR) << "The key value is disallowed by WTF::HashMap: " << key;
+      return false;
+    }
+    input.insert(key, std::forward<V>(value));
+    return true;
+  }
+  static bool Insert(WTFMap<K, V>& input, const K& key, const V& value) {
+    if (!WTFMap<K, V>::IsValidKey(key)) {
+      LOG(ERROR) << "The key value is disallowed by WTF::HashMap: " << key;
+      return false;
+    }
+    input.insert(key, value);
+    return true;
+  }
+
+  static void SetToEmpty(WTFMap<K, V>* output) { output->SetToEmpty(); }
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_MAP_TRAITS_WTF_H_
diff --git a/mojo/public/cpp/bindings/map_traits_wtf_hash_map.h b/mojo/public/cpp/bindings/map_traits_wtf_hash_map.h
index dd68b36..4392201 100644
--- a/mojo/public/cpp/bindings/map_traits_wtf_hash_map.h
+++ b/mojo/public/cpp/bindings/map_traits_wtf_hash_map.h
@@ -46,13 +46,20 @@
   static V& GetValue(Iterator& iterator) { return iterator->value; }
   static const V& GetValue(ConstIterator& iterator) { return iterator->value; }
 
-  template <typename IK, typename IV>
-  static bool Insert(WTF::HashMap<K, V>& input, IK&& key, IV&& value) {
+  static bool Insert(WTF::HashMap<K, V>& input, const K& key, V&& value) {
     if (!WTF::HashMap<K, V>::isValidKey(key)) {
-      LOG(ERROR) << "The key value is disallowed by WTF::HashMap";
+      LOG(ERROR) << "The key value is disallowed by WTF::HashMap: " << key;
       return false;
     }
-    input.insert(std::forward<IK>(key), std::forward<IV>(value));
+    input.add(key, std::forward<V>(value));
+    return true;
+  }
+  static bool Insert(WTF::HashMap<K, V>& input, const K& key, const V& value) {
+    if (!WTF::HashMap<K, V>::isValidKey(key)) {
+      LOG(ERROR) << "The key value is disallowed by WTF::HashMap: " << key;
+      return false;
+    }
+    input.add(key, value);
     return true;
   }
 
diff --git a/mojo/public/cpp/bindings/message.h b/mojo/public/cpp/bindings/message.h
index 65d6cec..e758432 100644
--- a/mojo/public/cpp/bindings/message.h
+++ b/mojo/public/cpp/bindings/message.h
@@ -13,46 +13,26 @@
 #include <string>
 #include <vector>
 
-#include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/logging.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/lib/message_buffer.h"
 #include "mojo/public/cpp/bindings/lib/message_internal.h"
-#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 #include "mojo/public/cpp/system/message.h"
 
 namespace mojo {
 
-class AssociatedGroupController;
-
-using ReportBadMessageCallback = base::Callback<void(const std::string& error)>;
-
 // 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 MOJO_CPP_BINDINGS_EXPORT Message {
+class Message {
  public:
   static const uint32_t kFlagExpectsResponse = 1 << 0;
   static const uint32_t kFlagIsResponse = 1 << 1;
   static const uint32_t kFlagIsSync = 1 << 2;
 
   Message();
-  Message(Message&& other);
-
   ~Message();
 
-  Message& operator=(Message&& other);
-
-  // Resets the Message to an uninitialized state. Upon reset, the Message
-  // exists as if it were default-constructed: it has no data buffer and owns no
-  // handles.
-  void Reset();
-
-  // Indicates whether this Message is uninitialized.
-  bool IsNull() const { return !buffer_; }
-
   // Initializes a Message with enough space for |capacity| bytes.
   void Initialize(size_t capacity, bool zero_initialized);
 
@@ -61,9 +41,10 @@
                                  uint32_t num_bytes,
                                  std::vector<Handle>* handles);
 
-  uint32_t data_num_bytes() const {
-    return static_cast<uint32_t>(buffer_->size());
-  }
+  // Transfers data and handles to |destination|.
+  void MoveTo(Message* destination);
+
+  uint32_t data_num_bytes() const { return buffer_->data_num_bytes(); }
 
   // Access the raw bytes of the message.
   const uint8_t* data() const {
@@ -76,30 +57,12 @@
   const internal::MessageHeader* header() const {
     return static_cast<const internal::MessageHeader*>(buffer_->data());
   }
+
   internal::MessageHeader* header() {
-    return static_cast<internal::MessageHeader*>(buffer_->data());
+    return const_cast<internal::MessageHeader*>(
+        static_cast<const Message*>(this)->header());
   }
 
-  const internal::MessageHeaderV1* header_v1() const {
-    DCHECK_GE(version(), 1u);
-    return static_cast<const internal::MessageHeaderV1*>(buffer_->data());
-  }
-  internal::MessageHeaderV1* header_v1() {
-    DCHECK_GE(version(), 1u);
-    return static_cast<internal::MessageHeaderV1*>(buffer_->data());
-  }
-
-  const internal::MessageHeaderV2* header_v2() const {
-    DCHECK_GE(version(), 2u);
-    return static_cast<const internal::MessageHeaderV2*>(buffer_->data());
-  }
-  internal::MessageHeaderV2* header_v2() {
-    DCHECK_GE(version(), 2u);
-    return static_cast<internal::MessageHeaderV2*>(buffer_->data());
-  }
-
-  uint32_t version() const { return header()->version; }
-
   uint32_t interface_id() const { return header()->interface_id; }
   void set_interface_id(uint32_t id) { header()->interface_id = id; }
 
@@ -107,32 +70,32 @@
   bool has_flag(uint32_t flag) const { return !!(header()->flags & flag); }
 
   // Access the request_id field (if present).
-  uint64_t request_id() const { return header_v1()->request_id; }
+  bool has_request_id() const { return header()->version >= 1; }
+  uint64_t request_id() const {
+    DCHECK(has_request_id());
+    return static_cast<const internal::MessageHeaderWithRequestID*>(
+               header())->request_id;
+  }
   void set_request_id(uint64_t request_id) {
-    header_v1()->request_id = request_id;
+    DCHECK(has_request_id());
+    static_cast<internal::MessageHeaderWithRequestID*>(header())
+        ->request_id = request_id;
   }
 
   // Access the payload.
-  const uint8_t* payload() const;
+  const uint8_t* payload() const { return data() + header()->num_bytes; }
   uint8_t* mutable_payload() { return const_cast<uint8_t*>(payload()); }
-  uint32_t payload_num_bytes() const;
-
-  uint32_t payload_num_interface_ids() const;
-  const uint32_t* payload_interface_ids() const;
+  uint32_t payload_num_bytes() const {
+    DCHECK(buffer_->data_num_bytes() >= header()->num_bytes);
+    size_t num_bytes = buffer_->data_num_bytes() - header()->num_bytes;
+    DCHECK(num_bytes <= std::numeric_limits<uint32_t>::max());
+    return static_cast<uint32_t>(num_bytes);
+  }
 
   // Access the handles.
   const std::vector<Handle>* handles() const { return &handles_; }
   std::vector<Handle>* mutable_handles() { return &handles_; }
 
-  const std::vector<ScopedInterfaceEndpointHandle>*
-  associated_endpoint_handles() const {
-    return &associated_endpoint_handles_;
-  }
-  std::vector<ScopedInterfaceEndpointHandle>*
-  mutable_associated_endpoint_handles() {
-    return &associated_endpoint_handles_;
-  }
-
   // Access the underlying Buffer interface.
   internal::Buffer* buffer() { return buffer_.get(); }
 
@@ -145,22 +108,11 @@
   // rejected by bindings validation code.
   void NotifyBadMessage(const std::string& error);
 
-  // Serializes |associated_endpoint_handles_| into the payload_interface_ids
-  // field.
-  void SerializeAssociatedEndpointHandles(
-      AssociatedGroupController* group_controller);
-
-  // Deserializes |associated_endpoint_handles_| from the payload_interface_ids
-  // field.
-  bool DeserializeAssociatedEndpointHandles(
-      AssociatedGroupController* group_controller);
-
  private:
   void CloseHandles();
 
   std::unique_ptr<internal::MessageBuffer> buffer_;
   std::vector<Handle> handles_;
-  std::vector<ScopedInterfaceEndpointHandle> associated_endpoint_handles_;
 
   DISALLOW_COPY_AND_ASSIGN(Message);
 };
@@ -234,57 +186,6 @@
       WARN_UNUSED_RESULT = 0;
 };
 
-class MOJO_CPP_BINDINGS_EXPORT PassThroughFilter
-    : NON_EXPORTED_BASE(public MessageReceiver) {
- public:
-  PassThroughFilter();
-  ~PassThroughFilter() override;
-
-  // MessageReceiver:
-  bool Accept(Message* message) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(PassThroughFilter);
-};
-
-namespace internal {
-class SyncMessageResponseSetup;
-}
-
-// An object which should be constructed on the stack immediately before making
-// a sync request for which the caller wishes to perform custom validation of
-// the response value(s). It is illegal to make more than one sync call during
-// the lifetime of the topmost SyncMessageResponseContext, but it is legal to
-// nest contexts to support reentrancy.
-//
-// Usage should look something like:
-//
-//     SyncMessageResponseContext response_context;
-//     foo_interface->SomeSyncCall(&response_value);
-//     if (response_value.IsBad())
-//       response_context.ReportBadMessage("Bad response_value!");
-//
-class MOJO_CPP_BINDINGS_EXPORT SyncMessageResponseContext {
- public:
-  SyncMessageResponseContext();
-  ~SyncMessageResponseContext();
-
-  static SyncMessageResponseContext* current();
-
-  void ReportBadMessage(const std::string& error);
-
-  const ReportBadMessageCallback& GetBadMessageCallback();
-
- private:
-  friend class internal::SyncMessageResponseSetup;
-
-  SyncMessageResponseContext* outer_context_;
-  Message response_;
-  ReportBadMessageCallback bad_message_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(SyncMessageResponseContext);
-};
-
 // Read a single message from the pipe. The caller should have created the
 // Message, but not called Initialize(). Returns MOJO_RESULT_SHOULD_WAIT if
 // the caller should wait on the handle to become readable. Returns
@@ -294,22 +195,6 @@
 // NOTE: The message hasn't been validated and may be malformed!
 MojoResult ReadMessage(MessagePipeHandle handle, Message* message);
 
-// Reports the currently dispatching Message as bad. Note that this is only
-// legal to call from directly within the stack frame of a message dispatch. If
-// you need to do asynchronous work before you can determine the legitimacy of
-// a message, use TakeBadMessageCallback() and retain its result until you're
-// ready to invoke or discard it.
-MOJO_CPP_BINDINGS_EXPORT
-void ReportBadMessage(const std::string& error);
-
-// Acquires a callback which may be run to report the currently dispatching
-// Message as bad. Note that this is only legal to call from directly within the
-// stack frame of a message dispatch, but the returned callback may be called
-// exactly once any time thereafter to report the message as bad. This may only
-// be called once per message.
-MOJO_CPP_BINDINGS_EXPORT
-ReportBadMessageCallback GetBadMessageCallback();
-
 }  // 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..638c53b
--- /dev/null
+++ b/mojo/public/cpp/bindings/message_filter.h
@@ -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.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_FILTER_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_FILTER_H_
+
+#include "mojo/public/cpp/bindings/message.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);
+  ~MessageFilter() override;
+
+  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);
+
+  bool Accept(Message* message) override;
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_FILTER_H_
diff --git a/mojo/public/cpp/bindings/message_header_validator.h b/mojo/public/cpp/bindings/message_header_validator.h
index 50c19db..3bcbd0a 100644
--- a/mojo/public/cpp/bindings/message_header_validator.h
+++ b/mojo/public/cpp/bindings/message_header_validator.h
@@ -5,17 +5,16 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_HEADER_VALIDATOR_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_HEADER_VALIDATOR_H_
 
-#include "base/compiler_specific.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/bindings/message_filter.h"
 
 namespace mojo {
 
-class MOJO_CPP_BINDINGS_EXPORT MessageHeaderValidator
-    : NON_EXPORTED_BASE(public MessageReceiver) {
+class MessageHeaderValidator : public MessageFilter {
  public:
-  MessageHeaderValidator();
-  explicit MessageHeaderValidator(const std::string& description);
+  explicit MessageHeaderValidator(MessageReceiver* sink = nullptr);
+  MessageHeaderValidator(const std::string& description,
+                         MessageReceiver* sink = nullptr);
 
   // Sets the description associated with this validator. Used for reporting
   // more detailed validation errors.
diff --git a/mojo/public/cpp/bindings/native_struct.h b/mojo/public/cpp/bindings/native_struct.h
index ac27250..882c970 100644
--- a/mojo/public/cpp/bindings/native_struct.h
+++ b/mojo/public/cpp/bindings/native_struct.h
@@ -5,10 +5,7 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_H_
 
-#include <vector>
-
-#include "base/optional.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
+#include "mojo/public/cpp/bindings/array.h"
 #include "mojo/public/cpp/bindings/lib/native_struct_data.h"
 #include "mojo/public/cpp/bindings/struct_ptr.h"
 #include "mojo/public/cpp/bindings/type_converter.h"
@@ -20,7 +17,7 @@
 
 // Native-only structs correspond to "[Native] struct Foo;" definitions in
 // mojom.
-class MOJO_CPP_BINDINGS_EXPORT NativeStruct {
+class NativeStruct {
  public:
   using Data_ = internal::NativeStruct_Data;
 
@@ -41,9 +38,8 @@
 
   NativeStructPtr Clone() const;
   bool Equals(const NativeStruct& other) const;
-  size_t Hash(size_t seed) const;
 
-  base::Optional<std::vector<uint8_t>> data;
+  Array<uint8_t> data;
 };
 
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/native_struct_data_view.h b/mojo/public/cpp/bindings/native_struct_data_view.h
deleted file mode 100644
index 613bd7a..0000000
--- a/mojo/public/cpp/bindings/native_struct_data_view.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_DATA_VIEW_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_DATA_VIEW_H_
-
-#include "mojo/public/cpp/bindings/lib/native_struct_data.h"
-#include "mojo/public/cpp/bindings/lib/serialization_context.h"
-
-namespace mojo {
-
-class NativeStructDataView {
- public:
-  using Data_ = internal::NativeStruct_Data;
-
-  NativeStructDataView() {}
-
-  NativeStructDataView(Data_* data, internal::SerializationContext* context)
-      : data_(data) {}
-
-  bool is_null() const { return !data_; }
-
-  size_t size() const { return data_->data.size(); }
-
-  uint8_t operator[](size_t index) const { return data_->data.at(index); }
-
-  const uint8_t* data() const { return data_->data.storage(); }
-
- private:
-  Data_* data_ = nullptr;
-};
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_DATA_VIEW_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..d8915cd
--- /dev/null
+++ b/mojo/public/cpp/bindings/no_interface.h
@@ -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.
+
+#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.
+
+class NoInterfaceProxy;
+class NoInterfaceStub;
+
+class NoInterface {
+ public:
+  static const char* Name_;
+  typedef NoInterfaceProxy Proxy_;
+  typedef NoInterfaceStub Stub_;
+  typedef PassThroughFilter RequestValidator_;
+  typedef PassThroughFilter ResponseValidator_;
+  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; }
+  bool Accept(Message* message) override;
+  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/pipe_control_message_handler.h b/mojo/public/cpp/bindings/pipe_control_message_handler.h
index a5c04da..b387b06 100644
--- a/mojo/public/cpp/bindings/pipe_control_message_handler.h
+++ b/mojo/public/cpp/bindings/pipe_control_message_handler.h
@@ -5,11 +5,9 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_PIPE_CONTROL_MESSAGE_HANDLER_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_PIPE_CONTROL_MESSAGE_HANDLER_H_
 
-#include <string>
-
-#include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
+#include "mojo/public/cpp/bindings/interface_id.h"
+#include "mojo/public/cpp/bindings/lib/serialization_context.h"
 #include "mojo/public/cpp/bindings/message.h"
 
 namespace mojo {
@@ -17,8 +15,7 @@
 class PipeControlMessageHandlerDelegate;
 
 // Handler for messages defined in pipe_control_messages.mojom.
-class MOJO_CPP_BINDINGS_EXPORT PipeControlMessageHandler
-    : NON_EXPORTED_BASE(public MessageReceiver) {
+class PipeControlMessageHandler : public MessageReceiver {
  public:
   explicit PipeControlMessageHandler(
       PipeControlMessageHandlerDelegate* delegate);
@@ -46,6 +43,7 @@
 
   std::string description_;
   PipeControlMessageHandlerDelegate* const delegate_;
+  internal::SerializationContext context_;
 
   DISALLOW_COPY_AND_ASSIGN(PipeControlMessageHandler);
 };
diff --git a/mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h b/mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h
index 16fd918..06f0695 100644
--- a/mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h
+++ b/mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h
@@ -5,8 +5,6 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_PIPE_CONTROL_MESSAGE_HANDLER_DELEGATE_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_PIPE_CONTROL_MESSAGE_HANDLER_DELEGATE_H_
 
-#include "base/optional.h"
-#include "mojo/public/cpp/bindings/disconnect_reason.h"
 #include "mojo/public/cpp/bindings/interface_id.h"
 
 namespace mojo {
@@ -16,9 +14,8 @@
   // The implementation of the following methods should return false if the
   // notification is unexpected. In that case, the user of this delegate is
   // expected to close the message pipe.
-  virtual bool OnPeerAssociatedEndpointClosed(
-      InterfaceId id,
-      const base::Optional<DisconnectReason>& reason) = 0;
+  virtual bool OnPeerAssociatedEndpointClosed(InterfaceId id) = 0;
+  virtual bool OnAssociatedEndpointClosedBeforeSent(InterfaceId id) = 0;
 
  protected:
   virtual ~PipeControlMessageHandlerDelegate() {}
diff --git a/mojo/public/cpp/bindings/pipe_control_message_proxy.h b/mojo/public/cpp/bindings/pipe_control_message_proxy.h
index 52c408f..7f3e006 100644
--- a/mojo/public/cpp/bindings/pipe_control_message_proxy.h
+++ b/mojo/public/cpp/bindings/pipe_control_message_proxy.h
@@ -6,36 +6,26 @@
 #define MOJO_PUBLIC_CPP_BINDINGS_PIPE_CONTROL_MESSAGE_PROXY_H_
 
 #include "base/macros.h"
-#include "base/optional.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
-#include "mojo/public/cpp/bindings/disconnect_reason.h"
 #include "mojo/public/cpp/bindings/interface_id.h"
 #include "mojo/public/cpp/bindings/lib/serialization_context.h"
-#include "mojo/public/cpp/bindings/message.h"
 
 namespace mojo {
 
 class MessageReceiver;
 
 // Proxy for request messages defined in pipe_control_messages.mojom.
-//
-// NOTE: This object may be used from multiple threads.
-class MOJO_CPP_BINDINGS_EXPORT PipeControlMessageProxy {
+class PipeControlMessageProxy {
  public:
-  // Doesn't take ownership of |receiver|. If This PipeControlMessageProxy will
-  // be used from multiple threads, |receiver| must be thread-safe.
+  // Doesn't take ownership of |receiver|. It must outlive this object.
   explicit PipeControlMessageProxy(MessageReceiver* receiver);
 
-  void NotifyPeerEndpointClosed(InterfaceId id,
-                                const base::Optional<DisconnectReason>& reason);
-
-  static Message ConstructPeerEndpointClosedMessage(
-      InterfaceId id,
-      const base::Optional<DisconnectReason>& reason);
+  void NotifyPeerEndpointClosed(InterfaceId id);
+  void NotifyEndpointClosedBeforeSent(InterfaceId id);
 
  private:
   // Not owned.
   MessageReceiver* receiver_;
+  internal::SerializationContext context_;
 
   DISALLOW_COPY_AND_ASSIGN(PipeControlMessageProxy);
 };
diff --git a/mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h b/mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h
deleted file mode 100644
index 4d40cdf..0000000
--- a/mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_RAW_PTR_IMPL_REF_TRAITS_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_RAW_PTR_IMPL_REF_TRAITS_H_
-
-namespace mojo {
-
-// Default traits for a binding's implementation reference type. This
-// corresponds to a raw pointer.
-template <typename Interface>
-struct RawPtrImplRefTraits {
-  using PointerType = Interface*;
-
-  static bool IsNull(PointerType ptr) { return !ptr; }
-  static Interface* GetRawPointer(PointerType* ptr) { return *ptr; }
-};
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_RAW_PTR_IMPL_REF_TRAITS_H_
diff --git a/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h b/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h
index 16527cf..1f45b0c 100644
--- a/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h
+++ b/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h
@@ -5,16 +5,8 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_SCOPED_INTERFACE_ENDPOINT_HANDLE_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_SCOPED_INTERFACE_ENDPOINT_HANDLE_H_
 
-#include <string>
-
-#include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/optional.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
-#include "mojo/public/cpp/bindings/disconnect_reason.h"
 #include "mojo/public/cpp/bindings/interface_id.h"
 
 namespace mojo {
@@ -23,16 +15,8 @@
 
 // ScopedInterfaceEndpointHandle refers to one end of an interface, either the
 // implementation side or the client side.
-// Threading: At any given time, a ScopedInterfaceEndpointHandle should only
-// be accessed from a single thread.
-class MOJO_CPP_BINDINGS_EXPORT ScopedInterfaceEndpointHandle {
+class ScopedInterfaceEndpointHandle {
  public:
-  // Creates a pair of handles representing the two endpoints of an interface,
-  // which are not yet associated with a message pipe.
-  static void CreatePairPendingAssociation(
-      ScopedInterfaceEndpointHandle* handle0,
-      ScopedInterfaceEndpointHandle* handle1);
-
   // Creates an invalid endpoint handle.
   ScopedInterfaceEndpointHandle();
 
@@ -43,77 +27,39 @@
   ScopedInterfaceEndpointHandle& operator=(
       ScopedInterfaceEndpointHandle&& other);
 
-  bool is_valid() const;
+  bool is_valid() const { return IsValidInterfaceId(id_); }
 
-  // Returns true if the interface hasn't associated with a message pipe.
-  bool pending_association() const;
-
-  // Returns kInvalidInterfaceId when in pending association state or the handle
-  // is invalid.
-  InterfaceId id() const;
-
-  // Returns null when in pending association state or the handle is invalid.
-  AssociatedGroupController* group_controller() const;
-
-  // Returns the disconnect reason if the peer handle is closed before
-  // association and specifies a custom disconnect reason.
-  const base::Optional<DisconnectReason>& disconnect_reason() const;
-
-  enum AssociationEvent {
-    // The interface has been associated with a message pipe.
-    ASSOCIATED,
-    // The peer of this object has been closed before association.
-    PEER_CLOSED_BEFORE_ASSOCIATION
-  };
-
-  using AssociationEventCallback = base::OnceCallback<void(AssociationEvent)>;
-  // Note:
-  // - |handler| won't run if the handle is invalid. Otherwise, |handler| is run
-  //   on the calling thread asynchronously, even if the interface has already
-  //   been associated or the peer has been closed before association.
-  // - |handler| won't be called after this object is destroyed or reset.
-  // - A null |handler| can be used to cancel the previous callback.
-  void SetAssociationEventHandler(AssociationEventCallback handler);
+  bool is_local() const { return is_local_; }
 
   void reset();
-  void ResetWithReason(uint32_t custom_reason, const std::string& description);
+  void swap(ScopedInterfaceEndpointHandle& other);
+
+  // DO NOT USE METHODS BELOW THIS LINE. These are for internal use and testing.
+
+  InterfaceId id() const { return id_; }
+
+  AssociatedGroupController* group_controller() const {
+    return group_controller_.get();
+  }
+
+  // Releases the handle without closing it.
+  InterfaceId release();
 
  private:
   friend class AssociatedGroupController;
-  friend class AssociatedGroup;
 
-  class State;
-
-  // Used by AssociatedGroupController.
+  // This is supposed to be used by AssociatedGroupController only.
+  // |id| is the corresponding interface ID.
+  // If |is_local| is false, this handle is meant to be passed over a message
+  // pipe the remote side of the associated group.
   ScopedInterfaceEndpointHandle(
       InterfaceId id,
+      bool is_local,
       scoped_refptr<AssociatedGroupController> group_controller);
 
-  // Used by AssociatedGroupController.
-  // The peer of this handle will join |peer_group_controller|.
-  bool NotifyAssociation(
-      InterfaceId id,
-      scoped_refptr<AssociatedGroupController> peer_group_controller);
-
-  void ResetInternal(const base::Optional<DisconnectReason>& reason);
-
-  // Used by AssociatedGroup.
-  // It is safe to run the returned callback on any thread, or after this handle
-  // is destroyed.
-  // The return value of the getter:
-  //   - If the getter is retrieved when the handle is invalid, the return value
-  //     of the getter will always be null.
-  //   - If the getter is retrieved when the handle is valid and non-pending,
-  //     the return value of the getter will be non-null and remain unchanged
-  //     even if the handle is later reset.
-  //   - If the getter is retrieved when the handle is valid but pending
-  //     asssociation, the return value of the getter will initially be null,
-  //     change to non-null when the handle is associated, and remain unchanged
-  //     ever since.
-  base::Callback<AssociatedGroupController*()> CreateGroupControllerGetter()
-      const;
-
-  scoped_refptr<State> state_;
+  InterfaceId id_;
+  bool is_local_;
+  scoped_refptr<AssociatedGroupController> group_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(ScopedInterfaceEndpointHandle);
 };
diff --git a/mojo/public/cpp/bindings/stl_converters.h b/mojo/public/cpp/bindings/stl_converters.h
new file mode 100644
index 0000000..92b2924
--- /dev/null
+++ b/mojo/public/cpp/bindings/stl_converters.h
@@ -0,0 +1,245 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_STL_CONVERTERS_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_STL_CONVERTERS_H_
+
+#include <map>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "mojo/public/cpp/bindings/array.h"
+#include "mojo/public/cpp/bindings/map.h"
+#include "mojo/public/cpp/bindings/string.h"
+
+// Two functions are defined to facilitate conversion between
+// mojo::Array/Map/String and std::vector/map/string: mojo::UnwrapToSTLType()
+// recursively convert mojo types to STL types; mojo::WrapSTLType() does the
+// opposite. For example:
+//   mojo::Array<mojo::Map<mojo::String, mojo::Array<int32_t>>> mojo_obj;
+//
+//   std::vector<std::map<std::string, std::vector<int32_t>>> stl_obj =
+//       mojo::UnwrapToSTLType(std::move(mojo_obj));
+//
+//   mojo_obj = mojo::WrapSTLType(std::move(stl_obj));
+//
+// Notes:
+//   - The conversion moves as much contents as possible. The two functions both
+//     take an rvalue ref as input in order to avoid accidental copies.
+//   - Because std::vector/map/string cannot express null, UnwrapToSTLType()
+//     converts null mojo::Array/Map/String to empty.
+//   - The recursive conversion stops at any types that are not the types listed
+//     above. For example, unwrapping mojo::Array<StructContainingMojoMap> will
+//     result in std::vector<StructContainingMojoMap>. It won't convert
+//     mojo::Map inside the struct.
+
+namespace mojo {
+namespace internal {
+
+template <typename T>
+struct UnwrapTraits;
+
+template <typename T>
+struct UnwrapShouldGoDeeper {
+ public:
+  static const bool value =
+      !std::is_same<T, typename UnwrapTraits<T>::Type>::value;
+};
+
+template <typename T>
+struct UnwrapTraits {
+ public:
+  using Type = T;
+  static Type Unwrap(T input) { return input; }
+};
+
+template <typename T>
+struct UnwrapTraits<Array<T>> {
+ public:
+  using Type = std::vector<typename UnwrapTraits<T>::Type>;
+
+  static Type Unwrap(Array<T> input) {
+    return Helper<T>::Run(std::move(input));
+  }
+
+ private:
+  template <typename U, bool should_go_deeper = UnwrapShouldGoDeeper<U>::value>
+  struct Helper {};
+
+  template <typename U>
+  struct Helper<U, true> {
+   public:
+    static Type Run(Array<T> input) {
+      Type output;
+      output.reserve(input.size());
+      for (size_t i = 0; i < input.size(); ++i)
+        output.push_back(UnwrapTraits<T>::Unwrap(std::move(input[i])));
+      return output;
+    }
+  };
+
+  template <typename U>
+  struct Helper<U, false> {
+   public:
+    static Type Run(Array<T> input) { return input.PassStorage(); }
+  };
+};
+
+template <typename K, typename V>
+struct UnwrapTraits<Map<K, V>> {
+ public:
+  using Type =
+      std::map<typename UnwrapTraits<K>::Type, typename UnwrapTraits<V>::Type>;
+
+  static Type Unwrap(Map<K, V> input) {
+    return Helper<K, V>::Run(std::move(input));
+  }
+
+ private:
+  template <typename X,
+            typename Y,
+            bool should_go_deeper = UnwrapShouldGoDeeper<X>::value ||
+                                    UnwrapShouldGoDeeper<Y>::value>
+  struct Helper {};
+
+  template <typename X, typename Y>
+  struct Helper<X, Y, true> {
+   public:
+    static Type Run(Map<K, V> input) {
+      std::map<K, V> input_storage = input.PassStorage();
+      Type output;
+      for (auto& pair : input_storage) {
+        output.insert(
+            std::make_pair(UnwrapTraits<K>::Unwrap(pair.first),
+                           UnwrapTraits<V>::Unwrap(std::move(pair.second))));
+      }
+      return output;
+    }
+  };
+
+  template <typename X, typename Y>
+  struct Helper<X, Y, false> {
+   public:
+    static Type Run(Map<K, V> input) { return input.PassStorage(); }
+  };
+};
+
+template <>
+struct UnwrapTraits<String> {
+ public:
+  using Type = std::string;
+
+  static std::string Unwrap(const String& input) { return input; }
+};
+
+template <typename T>
+struct WrapTraits;
+
+template <typename T>
+struct WrapShouldGoDeeper {
+ public:
+  static const bool value =
+      !std::is_same<T, typename WrapTraits<T>::Type>::value;
+};
+
+template <typename T>
+struct WrapTraits {
+ public:
+  using Type = T;
+
+  static T Wrap(T input) { return input; }
+};
+
+template <typename T>
+struct WrapTraits<std::vector<T>> {
+ public:
+  using Type = Array<typename WrapTraits<T>::Type>;
+
+  static Type Wrap(std::vector<T> input) {
+    return Helper<T>::Run(std::move(input));
+  }
+
+ private:
+  template <typename U, bool should_go_deeper = WrapShouldGoDeeper<U>::value>
+  struct Helper {};
+
+  template <typename U>
+  struct Helper<U, true> {
+   public:
+    static Type Run(std::vector<T> input) {
+      std::vector<typename WrapTraits<T>::Type> output_storage;
+      output_storage.reserve(input.size());
+      for (auto& element : input)
+        output_storage.push_back(WrapTraits<T>::Wrap(std::move(element)));
+      return Type(std::move(output_storage));
+    }
+  };
+
+  template <typename U>
+  struct Helper<U, false> {
+   public:
+    static Type Run(std::vector<T> input) { return Type(std::move(input)); }
+  };
+};
+
+template <typename K, typename V>
+struct WrapTraits<std::map<K, V>> {
+ public:
+  using Type = Map<typename WrapTraits<K>::Type, typename WrapTraits<V>::Type>;
+
+  static Type Wrap(std::map<K, V> input) {
+    return Helper<K, V>::Run(std::move(input));
+  }
+
+ private:
+  template <typename X,
+            typename Y,
+            bool should_go_deeper =
+                WrapShouldGoDeeper<X>::value || WrapShouldGoDeeper<Y>::value>
+  struct Helper {};
+
+  template <typename X, typename Y>
+  struct Helper<X, Y, true> {
+   public:
+    static Type Run(std::map<K, V> input) {
+      Type output;
+      for (auto& pair : input) {
+        output.insert(WrapTraits<K>::Wrap(pair.first),
+                      WrapTraits<V>::Wrap(std::move(pair.second)));
+      }
+      return output;
+    }
+  };
+
+  template <typename X, typename Y>
+  struct Helper<X, Y, false> {
+   public:
+    static Type Run(std::map<K, V> input) { return Type(std::move(input)); }
+  };
+};
+
+template <>
+struct WrapTraits<std::string> {
+ public:
+  using Type = String;
+
+  static String Wrap(const std::string& input) { return input; }
+};
+
+}  // namespace internal
+
+template <typename T>
+typename internal::UnwrapTraits<T>::Type UnwrapToSTLType(T&& input) {
+  return internal::UnwrapTraits<T>::Unwrap(std::move(input));
+}
+
+template <typename T>
+typename internal::WrapTraits<T>::Type WrapSTLType(T&& input) {
+  return internal::WrapTraits<T>::Wrap(std::move(input));
+}
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_STL_CONVERTERS_H_
diff --git a/mojo/public/cpp/bindings/string.h b/mojo/public/cpp/bindings/string.h
new file mode 100644
index 0000000..7cfd713
--- /dev/null
+++ b/mojo/public/cpp/bindings/string.h
@@ -0,0 +1,196 @@
+// 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 <stddef.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/type_converter.h"
+
+namespace mojo {
+
+// A UTF-8 encoded character string that can be null. Provides functions that
+// are similar to std::string, along with access to the underlying std::string
+// object.
+class String {
+ public:
+  // Constructs an empty string.
+  String() : is_null_(false) {}
+  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) {}
+  String(const mojo::String& str)
+      : value_(str.value_), is_null_(str.is_null_) {}
+
+  template <size_t N>
+  String(const char chars[N])
+      : value_(chars, N - 1), is_null_(false) {}
+
+  String(std::string&& other) : value_(std::move(other)), is_null_(false) {}
+  String(String&& other) : is_null_(true) { Swap(&other); }
+
+  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 mojo::String& str) {
+    value_ = str.value_;
+    is_null_ = str.is_null_;
+    return *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;
+  }
+
+  String& operator=(std::string&& other) {
+    value_ = std::move(other);
+    is_null_ = false;
+    return *this;
+  }
+  String& operator=(String&& other) {
+    is_null_ = true;
+    value_.clear();
+    Swap(&other);
+    return *this;
+  }
+
+  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_; }
+
+  // Returns a const reference to the |std::string| managed by this class. If
+  // the string is null, this will be an empty std::string.
+  const std::string& storage() const { return value_; }
+
+  // Passes the underlying storage and resets this string to null.
+  std::string PassStorage() {
+    is_null_ = true;
+    return std::move(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();
+}
+
+inline bool operator<(const String& a, const String& b) {
+  if (a.is_null())
+    return !b.is_null();
+  if (b.is_null())
+    return false;
+
+  return a.get() < b.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]) {
+    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]) {
+    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/string_data_view.h b/mojo/public/cpp/bindings/string_data_view.h
deleted file mode 100644
index 2b091b4..0000000
--- a/mojo/public/cpp/bindings/string_data_view.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_STRING_DATA_VIEW_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_STRING_DATA_VIEW_H_
-
-#include "mojo/public/cpp/bindings/lib/array_internal.h"
-#include "mojo/public/cpp/bindings/lib/serialization_context.h"
-
-namespace mojo {
-
-// Access to the contents of a serialized string.
-class StringDataView {
- public:
-  StringDataView() {}
-
-  StringDataView(internal::String_Data* data,
-                 internal::SerializationContext* context)
-      : data_(data) {}
-
-  bool is_null() const { return !data_; }
-
-  const char* storage() const { return data_->storage(); }
-
-  size_t size() const { return data_->size(); }
-
- private:
-  internal::String_Data* data_ = nullptr;
-};
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_STRING_DATA_VIEW_H_
diff --git a/mojo/public/cpp/bindings/string_traits.h b/mojo/public/cpp/bindings/string_traits.h
index 7d3075a..a6ade6f 100644
--- a/mojo/public/cpp/bindings/string_traits.h
+++ b/mojo/public/cpp/bindings/string_traits.h
@@ -5,10 +5,26 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_H_
 
-#include "mojo/public/cpp/bindings/string_data_view.h"
+#include "base/logging.h"
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
 
 namespace mojo {
 
+// Access to the contents of a serialized string.
+class StringDataView {
+ public:
+  explicit StringDataView(internal::String_Data* data) : data_(data) {
+    DCHECK(data_);
+  }
+
+  const char* storage() const { return data_->storage(); }
+
+  size_t size() const { return data_->size(); }
+
+ private:
+  internal::String_Data* data_;
+};
+
 // This must be specialized for any type |T| to be serialized/deserialized as
 // a mojom string.
 //
@@ -24,7 +40,6 @@
 //     static size_t GetSize(const CustomString& input);
 //     static const char* GetData(const CustomString& input);
 //
-//     // The caller guarantees that |!input.is_null()|.
 //     static bool Read(StringDataView input, CustomString* output);
 //   };
 //
diff --git a/mojo/public/cpp/bindings/string_traits_standard.h b/mojo/public/cpp/bindings/string_traits_standard.h
new file mode 100644
index 0000000..9b78d24
--- /dev/null
+++ b/mojo/public/cpp/bindings/string_traits_standard.h
@@ -0,0 +1,31 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STANDARD_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STANDARD_H_
+
+#include "mojo/public/cpp/bindings/string.h"
+#include "mojo/public/cpp/bindings/string_traits.h"
+
+namespace mojo {
+
+template <>
+struct StringTraits<String> {
+  static bool IsNull(const String& input) { return input.is_null(); }
+  static void SetToNull(String* output) { *output = nullptr; }
+
+  static size_t GetSize(const String& input) { return input.size(); }
+
+  static const char* GetData(const String& input) { return input.data(); }
+
+  static bool Read(StringDataView input, String* output) {
+    String result(input.storage(), input.size());
+    result.Swap(output);
+    return true;
+  }
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STANDARD_H_
diff --git a/mojo/public/cpp/bindings/string_traits_string16.h b/mojo/public/cpp/bindings/string_traits_string16.h
index f96973a..5a08908 100644
--- a/mojo/public/cpp/bindings/string_traits_string16.h
+++ b/mojo/public/cpp/bindings/string_traits_string16.h
@@ -6,13 +6,12 @@
 #define MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STRING16_H_
 
 #include "base/strings/string16.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/string_traits.h"
 
 namespace mojo {
 
 template <>
-struct MOJO_CPP_BINDINGS_EXPORT StringTraits<base::string16> {
+struct StringTraits<base::string16> {
   static bool IsNull(const base::string16& input) {
     // base::string16 is always converted to non-null mojom string.
     return false;
diff --git a/mojo/public/cpp/bindings/strong_binding.h b/mojo/public/cpp/bindings/strong_binding.h
index f4b4a06..7fb7eea 100644
--- a/mojo/public/cpp/bindings/strong_binding.h
+++ b/mojo/public/cpp/bindings/strong_binding.h
@@ -5,54 +5,94 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_STRONG_BINDING_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_STRONG_BINDING_H_
 
-#include <memory>
-#include <string>
 #include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
 #include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/bindings/connection_error_callback.h"
-#include "mojo/public/cpp/bindings/filter_chain.h"
 #include "mojo/public/cpp/bindings/interface_ptr.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/lib/filter_chain.h"
+#include "mojo/public/cpp/bindings/lib/router.h"
 #include "mojo/public/cpp/bindings/message_header_validator.h"
 #include "mojo/public/cpp/system/core.h"
 
 namespace mojo {
 
-template <typename Interface>
-class StrongBinding;
-
-template <typename Interface>
-using StrongBindingPtr = base::WeakPtr<StrongBinding<Interface>>;
-
 // This connects an interface implementation strongly to a pipe. When a
-// connection error is detected the implementation is deleted. If the task
-// runner that a StrongBinding is bound on is stopped, the connection error
-// handler will not be invoked and the implementation will not be deleted.
+// connection error is detected the implementation is deleted. Deleting the
+// connector also closes the pipe.
 //
-// To use, call StrongBinding<T>::Create() (see below) or the helper
-// MakeStrongBinding function:
+// Example of an implementation that is always bound strongly to a pipe
 //
-//   mojo::MakeStrongBinding(base::MakeUnique<FooImpl>(),
-//                           std::move(foo_request));
+//   class StronglyBound : public Foo {
+//    public:
+//     explicit StronglyBound(InterfaceRequest<Foo> request)
+//         : binding_(this, std::move(request)) {}
 //
+//     // Foo implementation here
+//
+//    private:
+//     StrongBinding<Foo> binding_;
+//   };
+//
+//   class MyFooFactory : public InterfaceFactory<Foo> {
+//    public:
+//     void Create(..., InterfaceRequest<Foo> request) override {
+//       new StronglyBound(std::move(request));  // The binding now owns the
+//                                               // instance of StronglyBound.
+//     }
+//   };
+//
+// This class is thread hostile once it is bound to a message pipe. Until it is
+// bound, it may be bound or destroyed on any thread.
 template <typename Interface>
 class StrongBinding {
  public:
-  // Create a new StrongBinding instance. The instance owns itself, cleaning up
-  // only in the event of a pipe connection error. Returns a WeakPtr to the new
-  // StrongBinding instance.
-  static StrongBindingPtr<Interface> Create(
-      std::unique_ptr<Interface> impl,
-      InterfaceRequest<Interface> request) {
-    StrongBinding* binding =
-        new StrongBinding(std::move(impl), std::move(request));
-    return binding->weak_factory_.GetWeakPtr();
+  explicit StrongBinding(Interface* impl) : binding_(impl) {}
+
+  StrongBinding(Interface* impl, ScopedMessagePipeHandle handle)
+      : StrongBinding(impl) {
+    Bind(std::move(handle));
+  }
+
+  StrongBinding(Interface* impl, InterfacePtr<Interface>* ptr)
+      : StrongBinding(impl) {
+    Bind(ptr);
+  }
+
+  StrongBinding(Interface* impl, InterfaceRequest<Interface> request)
+      : StrongBinding(impl) {
+    Bind(std::move(request));
+  }
+
+  ~StrongBinding() {}
+
+  void Bind(ScopedMessagePipeHandle handle) {
+    DCHECK(!binding_.is_bound());
+    binding_.Bind(std::move(handle));
+    binding_.set_connection_error_handler(
+        base::Bind(&StrongBinding::OnConnectionError, base::Unretained(this)));
+  }
+
+  void Bind(InterfacePtr<Interface>* ptr) {
+    DCHECK(!binding_.is_bound());
+    binding_.Bind(ptr);
+    binding_.set_connection_error_handler(
+        base::Bind(&StrongBinding::OnConnectionError, base::Unretained(this)));
+  }
+
+  void Bind(InterfaceRequest<Interface> request) {
+    DCHECK(!binding_.is_bound());
+    binding_.Bind(std::move(request));
+    binding_.set_connection_error_handler(
+        base::Bind(&StrongBinding::OnConnectionError, base::Unretained(this)));
+  }
+
+  bool WaitForIncomingMethodCall() {
+    return binding_.WaitForIncomingMethodCall();
   }
 
   // Note: The error handler must not delete the interface implementation.
@@ -62,64 +102,25 @@
   void set_connection_error_handler(const base::Closure& error_handler) {
     DCHECK(binding_.is_bound());
     connection_error_handler_ = error_handler;
-    connection_error_with_reason_handler_.Reset();
   }
 
-  void set_connection_error_with_reason_handler(
-      const ConnectionErrorWithReasonCallback& error_handler) {
-    DCHECK(binding_.is_bound());
-    connection_error_with_reason_handler_ = error_handler;
-    connection_error_handler_.Reset();
-  }
+  Interface* impl() { return binding_.impl(); }
+  // Exposed for testing, should not generally be used.
+  internal::Router* internal_router() { return binding_.internal_router(); }
 
-  // Forces the binding to close. This destroys the StrongBinding instance.
-  void Close() { delete this; }
-
-  Interface* impl() { return impl_.get(); }
-
-  // Sends a message on the underlying message pipe and runs the current
-  // message loop until its response is received. This can be used in tests to
-  // verify that no message was sent on a message pipe in response to some
-  // stimulus.
-  void FlushForTesting() { binding_.FlushForTesting(); }
-
- private:
-  StrongBinding(std::unique_ptr<Interface> impl,
-                InterfaceRequest<Interface> request)
-      : impl_(std::move(impl)),
-        binding_(impl_.get(), std::move(request)),
-        weak_factory_(this) {
-    binding_.set_connection_error_with_reason_handler(
-        base::Bind(&StrongBinding::OnConnectionError, base::Unretained(this)));
-  }
-
-  ~StrongBinding() {}
-
-  void OnConnectionError(uint32_t custom_reason,
-                         const std::string& description) {
+  void OnConnectionError() {
     if (!connection_error_handler_.is_null())
       connection_error_handler_.Run();
-    else if (!connection_error_with_reason_handler_.is_null())
-      connection_error_with_reason_handler_.Run(custom_reason, description);
-    Close();
+    delete binding_.impl();
   }
 
-  std::unique_ptr<Interface> impl_;
+ private:
   base::Closure connection_error_handler_;
-  ConnectionErrorWithReasonCallback connection_error_with_reason_handler_;
   Binding<Interface> binding_;
-  base::WeakPtrFactory<StrongBinding> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(StrongBinding);
 };
 
-template <typename Interface, typename Impl>
-StrongBindingPtr<Interface> MakeStrongBinding(
-    std::unique_ptr<Impl> impl,
-    InterfaceRequest<Interface> request) {
-  return StrongBinding<Interface>::Create(std::move(impl), std::move(request));
-}
-
 }  // namespace mojo
 
 #endif  // MOJO_PUBLIC_CPP_BINDINGS_STRONG_BINDING_H_
diff --git a/mojo/public/cpp/bindings/struct_ptr.h b/mojo/public/cpp/bindings/struct_ptr.h
index b135312..92f2728 100644
--- a/mojo/public/cpp/bindings/struct_ptr.h
+++ b/mojo/public/cpp/bindings/struct_ptr.h
@@ -5,26 +5,23 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
 
-#include <functional>
-#include <memory>
 #include <new>
 
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/optional.h"
-#include "mojo/public/cpp/bindings/lib/hash_util.h"
 #include "mojo/public/cpp/bindings/type_converter.h"
 
 namespace mojo {
 namespace internal {
 
-constexpr size_t kHashSeed = 31;
-
 template <typename Struct>
-class StructPtrWTFHelper;
-
-template <typename Struct>
-class InlinedStructPtrWTFHelper;
+class StructHelper {
+ public:
+  template <typename Ptr>
+  static void Initialize(Ptr* ptr) {
+    ptr->Initialize();
+  }
+};
 
 }  // namespace internal
 
@@ -34,34 +31,35 @@
  public:
   using Struct = S;
 
-  StructPtr() = default;
-  StructPtr(decltype(nullptr)) {}
+  StructPtr() : ptr_(nullptr) {}
+  StructPtr(decltype(nullptr)) : ptr_(nullptr) {}
 
-  ~StructPtr() = default;
+  ~StructPtr() { delete ptr_; }
 
   StructPtr& operator=(decltype(nullptr)) {
     reset();
     return *this;
   }
 
-  StructPtr(StructPtr&& other) { Take(&other); }
+  StructPtr(StructPtr&& other) : ptr_(nullptr) { Take(&other); }
   StructPtr& operator=(StructPtr&& other) {
     Take(&other);
     return *this;
   }
 
-  template <typename... Args>
-  StructPtr(base::in_place_t, Args&&... args)
-      : ptr_(new Struct(std::forward<Args>(args)...)) {}
-
   template <typename U>
   U To() const {
     return TypeConverter<U, StructPtr>::Convert(*this);
   }
 
-  void reset() { ptr_.reset(); }
+  void reset() {
+    if (ptr_) {
+      delete ptr_;
+      ptr_ = nullptr;
+    }
+  }
 
-  bool is_null() const { return !ptr_; }
+  bool is_null() const { return ptr_ == nullptr; }
 
   Struct& operator*() const {
     DCHECK(ptr_);
@@ -69,9 +67,9 @@
   }
   Struct* operator->() const {
     DCHECK(ptr_);
-    return ptr_.get();
+    return ptr_;
   }
-  Struct* get() const { return ptr_.get(); }
+  Struct* get() const { return ptr_; }
 
   void Swap(StructPtr* other) { std::swap(ptr_, other->ptr_); }
 
@@ -80,52 +78,52 @@
   // that it contains Mojo handles).
   StructPtr Clone() const { return is_null() ? StructPtr() : ptr_->Clone(); }
 
-  // Compares the pointees (which might both be null).
-  // TODO(tibell): Get rid of Equals in favor of the operator. Same for Hash.
   bool Equals(const StructPtr& other) const {
     if (is_null() || other.is_null())
       return is_null() && other.is_null();
     return ptr_->Equals(*other.ptr_);
   }
 
-  // Hashes based on the pointee (which might be null).
-  size_t Hash(size_t seed) const {
-    if (is_null())
-      return internal::HashCombine(seed, 0);
-    return ptr_->Hash(seed);
-  }
+ private:
+  // TODO(dcheng): Use an explicit conversion operator.
+  typedef Struct* StructPtr::*Testable;
 
-  explicit operator bool() const { return !is_null(); }
+ public:
+  operator Testable() const { return ptr_ ? &StructPtr::ptr_ : 0; }
 
  private:
-  friend class internal::StructPtrWTFHelper<Struct>;
+  friend class internal::StructHelper<Struct>;
+
+  // Forbid the == and != operators explicitly, otherwise StructPtr will be
+  // converted to Testable to do == or != comparison.
+  template <typename T>
+  bool operator==(const StructPtr<T>& other) const = delete;
+  template <typename T>
+  bool operator!=(const StructPtr<T>& other) const = delete;
+
+  void Initialize() {
+    DCHECK(!ptr_);
+    ptr_ = new Struct();
+  }
+
   void Take(StructPtr* other) {
     reset();
     Swap(other);
   }
 
-  std::unique_ptr<Struct> ptr_;
+  Struct* ptr_;
 
   DISALLOW_COPY_AND_ASSIGN(StructPtr);
 };
 
-template <typename T>
-bool operator==(const StructPtr<T>& lhs, const StructPtr<T>& rhs) {
-  return lhs.Equals(rhs);
-}
-template <typename T>
-bool operator!=(const StructPtr<T>& lhs, const StructPtr<T>& rhs) {
-  return !(lhs == rhs);
-}
-
 // Designed to be used when Struct is small and copyable.
 template <typename S>
 class InlinedStructPtr {
  public:
   using Struct = S;
 
-  InlinedStructPtr() : state_(NIL) {}
-  InlinedStructPtr(decltype(nullptr)) : state_(NIL) {}
+  InlinedStructPtr() : is_null_(true) {}
+  InlinedStructPtr(decltype(nullptr)) : is_null_(true) {}
 
   ~InlinedStructPtr() {}
 
@@ -134,150 +132,79 @@
     return *this;
   }
 
-  InlinedStructPtr(InlinedStructPtr&& other) : state_(NIL) { Take(&other); }
+  InlinedStructPtr(InlinedStructPtr&& other) : is_null_(true) { Take(&other); }
   InlinedStructPtr& operator=(InlinedStructPtr&& other) {
     Take(&other);
     return *this;
   }
 
-  template <typename... Args>
-  InlinedStructPtr(base::in_place_t, Args&&... args)
-      : value_(std::forward<Args>(args)...), state_(VALID) {}
-
   template <typename U>
   U To() const {
     return TypeConverter<U, InlinedStructPtr>::Convert(*this);
   }
 
   void reset() {
-    state_ = NIL;
+    is_null_ = true;
     value_. ~Struct();
     new (&value_) Struct();
   }
 
-  bool is_null() const { return state_ == NIL; }
+  bool is_null() const { return is_null_; }
 
   Struct& operator*() const {
-    DCHECK(state_ == VALID);
+    DCHECK(!is_null_);
     return value_;
   }
   Struct* operator->() const {
-    DCHECK(state_ == VALID);
+    DCHECK(!is_null_);
     return &value_;
   }
   Struct* get() const { return &value_; }
 
   void Swap(InlinedStructPtr* other) {
     std::swap(value_, other->value_);
-    std::swap(state_, other->state_);
+    std::swap(is_null_, other->is_null_);
   }
 
   InlinedStructPtr Clone() const {
     return is_null() ? InlinedStructPtr() : value_.Clone();
   }
-
-  // Compares the pointees (which might both be null).
   bool Equals(const InlinedStructPtr& other) const {
     if (is_null() || other.is_null())
       return is_null() && other.is_null();
     return value_.Equals(other.value_);
   }
 
-  // Hashes based on the pointee (which might be null).
-  size_t Hash(size_t seed) const {
-    if (is_null())
-      return internal::HashCombine(seed, 0);
-    return value_.Hash(seed);
-  }
+ private:
+  // TODO(dcheng): Use an explicit conversion operator.
+  typedef Struct InlinedStructPtr::*Testable;
 
-  explicit operator bool() const { return !is_null(); }
+ public:
+  operator Testable() const { return is_null_ ? 0 : &InlinedStructPtr::value_; }
 
  private:
-  friend class internal::InlinedStructPtrWTFHelper<Struct>;
+  friend class internal::StructHelper<Struct>;
+
+  // Forbid the == and != operators explicitly, otherwise InlinedStructPtr will
+  // be converted to Testable to do == or != comparison.
+  template <typename T>
+  bool operator==(const InlinedStructPtr<T>& other) const = delete;
+  template <typename T>
+  bool operator!=(const InlinedStructPtr<T>& other) const = delete;
+
+  void Initialize() { is_null_ = false; }
+
   void Take(InlinedStructPtr* other) {
     reset();
     Swap(other);
   }
 
-  enum State {
-    VALID,
-    NIL,
-    DELETED,  // For use in WTF::HashMap only
-  };
-
   mutable Struct value_;
-  State state_;
+  bool is_null_;
 
   DISALLOW_COPY_AND_ASSIGN(InlinedStructPtr);
 };
 
-template <typename T>
-bool operator==(const InlinedStructPtr<T>& lhs,
-                const InlinedStructPtr<T>& rhs) {
-  return lhs.Equals(rhs);
-}
-template <typename T>
-bool operator!=(const InlinedStructPtr<T>& lhs,
-                const InlinedStructPtr<T>& rhs) {
-  return !(lhs == rhs);
-}
-
-namespace internal {
-
-template <typename Struct>
-class StructPtrWTFHelper {
- public:
-  static bool IsHashTableDeletedValue(const StructPtr<Struct>& value) {
-    return value.ptr_.get() == reinterpret_cast<Struct*>(1u);
-  }
-
-  static void ConstructDeletedValue(mojo::StructPtr<Struct>& slot) {
-    // |slot| refers to a previous, real value that got deleted and had its
-    // destructor run, so this is the first time the "deleted value" has its
-    // constructor called.
-    //
-    // Dirty trick: implant an invalid pointer in |ptr_|. Destructor isn't
-    // called for deleted buckets, so this is okay.
-    new (&slot) StructPtr<Struct>();
-    slot.ptr_.reset(reinterpret_cast<Struct*>(1u));
-  }
-};
-
-template <typename Struct>
-class InlinedStructPtrWTFHelper {
- public:
-  static bool IsHashTableDeletedValue(const InlinedStructPtr<Struct>& value) {
-    return value.state_ == InlinedStructPtr<Struct>::DELETED;
-  }
-
-  static void ConstructDeletedValue(mojo::InlinedStructPtr<Struct>& slot) {
-    // |slot| refers to a previous, real value that got deleted and had its
-    // destructor run, so this is the first time the "deleted value" has its
-    // constructor called.
-    new (&slot) InlinedStructPtr<Struct>();
-    slot.state_ = InlinedStructPtr<Struct>::DELETED;
-  }
-};
-
-}  // namespace internal
 }  // namespace mojo
 
-namespace std {
-
-template <typename T>
-struct hash<mojo::StructPtr<T>> {
-  size_t operator()(const mojo::StructPtr<T>& value) const {
-    return value.Hash(mojo::internal::kHashSeed);
-  }
-};
-
-template <typename T>
-struct hash<mojo::InlinedStructPtr<T>> {
-  size_t operator()(const mojo::InlinedStructPtr<T>& value) const {
-    return value.Hash(mojo::internal::kHashSeed);
-  }
-};
-
-}  // namespace std
-
 #endif  // MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
diff --git a/mojo/public/cpp/bindings/struct_traits.h b/mojo/public/cpp/bindings/struct_traits.h
index 6cc070f..0f0bea7 100644
--- a/mojo/public/cpp/bindings/struct_traits.h
+++ b/mojo/public/cpp/bindings/struct_traits.h
@@ -8,11 +8,7 @@
 namespace mojo {
 
 // This must be specialized for any type |T| to be serialized/deserialized as
-// a mojom struct. |DataViewType| is the corresponding data view type of the
-// mojom struct. For example, if the mojom struct is example.Foo,
-// |DataViewType| will be example::FooDataView, which can also be referred to by
-// example::Foo::DataView (in chromium) and example::blink::Foo::DataView (in
-// blink).
+// a mojom struct of type |MojomType|.
 //
 // Each specialization needs to implement a few things:
 //   1. Static getters for each field in the Mojom type. These should be
@@ -24,21 +20,19 @@
 //      from |input|.
 //
 //      Serializable form of a field:
-//        Value or reference of the same type used in the generated stuct
-//        wrapper type, or the following alternatives:
+//        Value or reference of the same type used in |MojomType|, or the
+//        following alternatives:
 //        - string:
 //          Value or reference of any type that has a StringTraits defined.
-//          Supported by default: base::StringPiece, std::string,
-//          WTF::String (in blink).
+//          Supported by default: base::StringPiece, std::string.
 //
 //        - array:
 //          Value or reference of any type that has an ArrayTraits defined.
-//          Supported by default: std::vector, CArray, WTF::Vector (in blink)
+//          Supported by default: std::vector, WTF::Vector (in blink), CArray.
 //
 //        - map:
 //          Value or reference of any type that has a MapTraits defined.
-//          Supported by default: std::map, std::unordered_map,
-//          WTF::HashMap (in blink).
+//          Supported by default: std::map.
 //
 //        - struct:
 //          Value or reference of any type that has a StructTraits defined.
@@ -46,10 +40,6 @@
 //        - enum:
 //          Value of any type that has an EnumTraits defined.
 //
-//      For any nullable string/struct/array/map/union field you could also
-//      return value or reference of base::Optional<T>/WTF::Optional<T>, if T
-//      has the right *Traits defined.
-//
 //      During serialization, getters for string/struct/array/map/union fields
 //      are called twice (one for size calculation and one for actual
 //      serialization). If you want to return a value (as opposed to a
@@ -59,13 +49,13 @@
 //      Getters for fields of other types are called once.
 //
 //   2. A static Read() method to set the contents of a |T| instance from a
-//      DataViewType.
+//      |MojomType|DataView (e.g., if |MojomType| is test::Example, the data
+//      view will be test::ExampleDataView).
 //
-//        static bool Read(DataViewType data, T* output);
+//        static bool Read(|MojomType|DataView data, T* output);
 //
-//      The generated DataViewType provides a convenient, inexpensive view of a
-//      serialized struct's field data. The caller guarantees that
-//      |!data.is_null()|.
+//      The generated |MojomType|DataView type provides a convenient,
+//      inexpensive view of a serialized struct's field data.
 //
 //      Returning false indicates invalid incoming data and causes the message
 //      pipe receiving it to be disconnected. Therefore, you can do custom
@@ -121,12 +111,9 @@
 // reference/value to the Mojo bindings for serialization:
 //    - if T is used in the "type_mappings" section of a typemap config file,
 //      you need to declare it as pass-by-value:
-//        type_mappings = [ "MojomType=T[move_only]" ]
-//      or
-//        type_mappings = [ "MojomType=T[copyable_pass_by_value]" ]
-//
-//    - if another type U's StructTraits/UnionTraits has a getter for T, it
-//      needs to return non-const reference/value.
+//        type_mappings = [ "MojomType=T(pass_by_value)" ]
+//    - if another type U's StructTraits has a getter for T, it needs to return
+//      non-const reference/value.
 //
 // EXAMPLE:
 //
@@ -141,7 +128,7 @@
 //
 // StructTraits for Foo:
 //   template <>
-//   struct StructTraits<FooDataView, CustomFoo> {
+//   struct StructTraits<Foo, CustomFoo> {
 //     // Optional methods dealing with null:
 //     static bool IsNull(const CustomFoo& input);
 //     static void SetToNull(CustomFoo* output);
@@ -157,7 +144,7 @@
 //     static bool Read(FooDataView data, CustomFoo* output);
 //   };
 //
-template <typename DataViewType, typename T>
+template <typename MojomType, typename T>
 struct StructTraits;
 
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/sync_call_restrictions.h b/mojo/public/cpp/bindings/sync_call_restrictions.h
index 39a77a8..e8fc1c4 100644
--- a/mojo/public/cpp/bindings/sync_call_restrictions.h
+++ b/mojo/public/cpp/bindings/sync_call_restrictions.h
@@ -7,7 +7,6 @@
 
 #include "base/macros.h"
 #include "base/threading/thread_restrictions.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 
 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
 #define ENABLE_SYNC_CALL_RESTRICTIONS 1
@@ -15,12 +14,8 @@
 #define ENABLE_SYNC_CALL_RESTRICTIONS 0
 #endif
 
-namespace leveldb {
-class LevelDBMojoProxy;
-}
-
 namespace ui {
-class Gpu;
+class GpuService;
 }
 
 namespace views {
@@ -41,7 +36,7 @@
 // a very compelling reason to disregard that (which should be very very rare),
 // you can override it by constructing a ScopedAllowSyncCall object, which
 // allows making sync calls on the current thread during its lifetime.
-class MOJO_CPP_BINDINGS_EXPORT SyncCallRestrictions {
+class SyncCallRestrictions {
  public:
 #if ENABLE_SYNC_CALL_RESTRICTIONS
   // Checks whether the current thread is allowed to make sync calls, and causes
@@ -55,9 +50,7 @@
  private:
   // DO NOT ADD ANY OTHER FRIEND STATEMENTS, talk to mojo/OWNERS first.
   // BEGIN ALLOWED USAGE.
-  friend class ui::Gpu;  // http://crbug.com/620058
-  // LevelDBMojoProxy makes same-process sync calls from the DB thread.
-  friend class leveldb::LevelDBMojoProxy;
+  friend class ui::GpuService;  // http://crbug.com/620058
   // END ALLOWED USAGE.
 
   // BEGIN USAGE THAT NEEDS TO BE FIXED.
diff --git a/mojo/public/cpp/bindings/sync_handle_registry.h b/mojo/public/cpp/bindings/sync_handle_registry.h
index b5415af..6c0701e 100644
--- a/mojo/public/cpp/bindings/sync_handle_registry.h
+++ b/mojo/public/cpp/bindings/sync_handle_registry.h
@@ -11,7 +11,6 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread_checker.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/system/core.h"
 
 namespace mojo {
@@ -20,8 +19,7 @@
 // be watched together.
 //
 // This class is not thread safe.
-class MOJO_CPP_BINDINGS_EXPORT SyncHandleRegistry
-    : public base::RefCounted<SyncHandleRegistry> {
+class SyncHandleRegistry : public base::RefCounted<SyncHandleRegistry> {
  public:
   // Returns a thread-local object.
   static scoped_refptr<SyncHandleRegistry> current();
diff --git a/mojo/public/cpp/bindings/sync_handle_watcher.h b/mojo/public/cpp/bindings/sync_handle_watcher.h
index eff73dd..36b796b 100644
--- a/mojo/public/cpp/bindings/sync_handle_watcher.h
+++ b/mojo/public/cpp/bindings/sync_handle_watcher.h
@@ -8,7 +8,6 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread_checker.h"
-#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/sync_handle_registry.h"
 #include "mojo/public/cpp/system/core.h"
 
@@ -26,7 +25,7 @@
 // associated endpoints on different threads.
 //
 // This class is not thread safe.
-class MOJO_CPP_BINDINGS_EXPORT SyncHandleWatcher {
+class SyncHandleWatcher {
  public:
   // Note: |handle| must outlive this object.
   SyncHandleWatcher(const Handle& handle,
diff --git a/mojo/public/cpp/bindings/thread_safe_interface_ptr.h b/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
deleted file mode 100644
index bab6d22..0000000
--- a/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
+++ /dev/null
@@ -1,278 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "mojo/public/cpp/bindings/associated_group.h"
-#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
-#include "mojo/public/cpp/bindings/interface_ptr.h"
-#include "mojo/public/cpp/bindings/message.h"
-
-namespace mojo {
-
-// Instances of this class may be used from any thread to serialize |Interface|
-// messages and forward them elsewhere. In general you should use one of the
-// ThreadSafeInterfacePtrBase helper aliases defined below, but this type may be
-// useful if you need/want to manually manage the lifetime of the underlying
-// proxy object which will be used to ultimately send messages.
-template <typename Interface>
-class ThreadSafeForwarder : public MessageReceiverWithResponder {
- public:
-  using ProxyType = typename Interface::Proxy_;
-  using ForwardMessageCallback = base::Callback<void(Message)>;
-  using ForwardMessageWithResponderCallback =
-      base::Callback<void(Message, std::unique_ptr<MessageReceiver>)>;
-
-  // Constructs a ThreadSafeForwarder through which Messages are forwarded to
-  // |forward| or |forward_with_responder| by posting to |task_runner|.
-  //
-  // Any message sent through this forwarding interface will dispatch its reply,
-  // if any, back to the thread which called the corresponding interface method.
-  ThreadSafeForwarder(
-      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-      const ForwardMessageCallback& forward,
-      const ForwardMessageWithResponderCallback& forward_with_responder,
-      const AssociatedGroup& associated_group)
-      : proxy_(this),
-        task_runner_(task_runner),
-        forward_(forward),
-        forward_with_responder_(forward_with_responder),
-        associated_group_(associated_group) {}
-
-  ~ThreadSafeForwarder() override {}
-
-  ProxyType& proxy() { return proxy_; }
-
- private:
-  // MessageReceiverWithResponder implementation:
-  bool Accept(Message* message) override {
-    if (!message->associated_endpoint_handles()->empty()) {
-      // If this DCHECK fails, it is likely because:
-      // - This is a non-associated interface pointer setup using
-      //     PtrWrapper::BindOnTaskRunner(
-      //         InterfacePtrInfo<InterfaceType> ptr_info);
-      //   Please see the TODO in that method.
-      // - This is an associated interface which hasn't been associated with a
-      //   message pipe. In other words, the corresponding
-      //   AssociatedInterfaceRequest hasn't been sent.
-      DCHECK(associated_group_.GetController());
-      message->SerializeAssociatedEndpointHandles(
-          associated_group_.GetController());
-    }
-    task_runner_->PostTask(FROM_HERE,
-                           base::Bind(forward_, base::Passed(message)));
-    return true;
-  }
-
-  bool AcceptWithResponder(Message* message,
-                           MessageReceiver* response_receiver) override {
-    if (!message->associated_endpoint_handles()->empty()) {
-      // Please see comment for the DCHECK in the previous method.
-      DCHECK(associated_group_.GetController());
-      message->SerializeAssociatedEndpointHandles(
-          associated_group_.GetController());
-    }
-    auto responder = base::MakeUnique<ForwardToCallingThread>(
-        base::WrapUnique(response_receiver));
-    task_runner_->PostTask(
-        FROM_HERE, base::Bind(forward_with_responder_, base::Passed(message),
-                              base::Passed(&responder)));
-    return true;
-  }
-
-  class ForwardToCallingThread : public MessageReceiver {
-   public:
-    explicit ForwardToCallingThread(std::unique_ptr<MessageReceiver> responder)
-        : responder_(std::move(responder)),
-          caller_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
-    }
-
-   private:
-    bool Accept(Message* message) {
-      // The current instance will be deleted when this method returns, so we
-      // have to relinquish the responder's ownership so it does not get
-      // deleted.
-      caller_task_runner_->PostTask(FROM_HERE,
-          base::Bind(&ForwardToCallingThread::CallAcceptAndDeleteResponder,
-                     base::Passed(std::move(responder_)),
-                     base::Passed(std::move(*message))));
-      return true;
-    }
-
-    static void CallAcceptAndDeleteResponder(
-        std::unique_ptr<MessageReceiver> responder,
-        Message message) {
-      ignore_result(responder->Accept(&message));
-    }
-
-    std::unique_ptr<MessageReceiver> responder_;
-    scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
-  };
-
-  ProxyType proxy_;
-  const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  const ForwardMessageCallback forward_;
-  const ForwardMessageWithResponderCallback forward_with_responder_;
-  AssociatedGroup associated_group_;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadSafeForwarder);
-};
-
-template <typename InterfacePtrType>
-class ThreadSafeInterfacePtrBase
-    : public base::RefCountedThreadSafe<
-          ThreadSafeInterfacePtrBase<InterfacePtrType>> {
- public:
-  using InterfaceType = typename InterfacePtrType::InterfaceType;
-  using PtrInfoType = typename InterfacePtrType::PtrInfoType;
-
-  explicit ThreadSafeInterfacePtrBase(
-      std::unique_ptr<ThreadSafeForwarder<InterfaceType>> forwarder)
-      : forwarder_(std::move(forwarder)) {}
-
-  // Creates a ThreadSafeInterfacePtrBase wrapping an underlying non-thread-safe
-  // InterfacePtrType which is bound to the calling thread. All messages sent
-  // via this thread-safe proxy will internally be sent by first posting to this
-  // (the calling) thread's TaskRunner.
-  static scoped_refptr<ThreadSafeInterfacePtrBase> Create(
-      InterfacePtrType interface_ptr) {
-    scoped_refptr<PtrWrapper> wrapper =
-        new PtrWrapper(std::move(interface_ptr));
-    return new ThreadSafeInterfacePtrBase(wrapper->CreateForwarder());
-  }
-
-  // Creates a ThreadSafeInterfacePtrBase which binds the underlying
-  // non-thread-safe InterfacePtrType on the specified TaskRunner. All messages
-  // sent via this thread-safe proxy will internally be sent by first posting to
-  // that TaskRunner.
-  static scoped_refptr<ThreadSafeInterfacePtrBase> Create(
-      PtrInfoType ptr_info,
-      const scoped_refptr<base::SingleThreadTaskRunner>& bind_task_runner) {
-    scoped_refptr<PtrWrapper> wrapper = new PtrWrapper(bind_task_runner);
-    wrapper->BindOnTaskRunner(std::move(ptr_info));
-    return new ThreadSafeInterfacePtrBase(wrapper->CreateForwarder());
-  }
-
-  InterfaceType* get() { return &forwarder_->proxy(); }
-  InterfaceType* operator->() { return get(); }
-  InterfaceType& operator*() { return *get(); }
-
- private:
-  friend class base::RefCountedThreadSafe<
-      ThreadSafeInterfacePtrBase<InterfacePtrType>>;
-
-  struct PtrWrapperDeleter;
-
-  // Helper class which owns an |InterfacePtrType| instance on an appropriate
-  // thread. This is kept alive as long its bound within some
-  // ThreadSafeForwarder's callbacks.
-  class PtrWrapper
-      : public base::RefCountedThreadSafe<PtrWrapper, PtrWrapperDeleter> {
-   public:
-    explicit PtrWrapper(InterfacePtrType ptr)
-        : PtrWrapper(base::ThreadTaskRunnerHandle::Get()) {
-      ptr_ = std::move(ptr);
-      associated_group_ = *ptr_.internal_state()->associated_group();
-    }
-
-    explicit PtrWrapper(
-        const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
-        : task_runner_(task_runner) {}
-
-    void BindOnTaskRunner(AssociatedInterfacePtrInfo<InterfaceType> ptr_info) {
-      associated_group_ = AssociatedGroup(ptr_info.handle());
-      task_runner_->PostTask(FROM_HERE, base::Bind(&PtrWrapper::Bind, this,
-                                                   base::Passed(&ptr_info)));
-    }
-
-    void BindOnTaskRunner(InterfacePtrInfo<InterfaceType> ptr_info) {
-      // TODO(yzhsen): At the momment we don't have a group controller
-      // available. That means the user won't be able to pass associated
-      // endpoints on this interface (at least not immediately). In order to fix
-      // this, we need to create a MultiplexRouter immediately and bind it to
-      // the interface pointer on the |task_runner_|. Therefore, MultiplexRouter
-      // should be able to be created on a thread different than the one that it
-      // is supposed to listen on. crbug.com/682334
-      task_runner_->PostTask(FROM_HERE, base::Bind(&PtrWrapper::Bind, this,
-                                                   base::Passed(&ptr_info)));
-    }
-
-    std::unique_ptr<ThreadSafeForwarder<InterfaceType>> CreateForwarder() {
-      return base::MakeUnique<ThreadSafeForwarder<InterfaceType>>(
-          task_runner_, base::Bind(&PtrWrapper::Accept, this),
-          base::Bind(&PtrWrapper::AcceptWithResponder, this),
-          associated_group_);
-    }
-
-   private:
-    friend struct PtrWrapperDeleter;
-
-    ~PtrWrapper() {}
-
-    void Bind(PtrInfoType ptr_info) {
-      DCHECK(task_runner_->RunsTasksOnCurrentThread());
-      ptr_.Bind(std::move(ptr_info));
-    }
-
-    void Accept(Message message) {
-      ptr_.internal_state()->ForwardMessage(std::move(message));
-    }
-
-    void AcceptWithResponder(Message message,
-                             std::unique_ptr<MessageReceiver> responder) {
-      ptr_.internal_state()->ForwardMessageWithResponder(std::move(message),
-                                                         std::move(responder));
-    }
-
-    void DeleteOnCorrectThread() const {
-      if (!task_runner_->RunsTasksOnCurrentThread()) {
-        // NOTE: This is only called when there are no more references to
-        // |this|, so binding it unretained is both safe and necessary.
-        task_runner_->PostTask(FROM_HERE,
-                               base::Bind(&PtrWrapper::DeleteOnCorrectThread,
-                                          base::Unretained(this)));
-      } else {
-        delete this;
-      }
-    }
-
-    InterfacePtrType ptr_;
-    const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-    AssociatedGroup associated_group_;
-
-    DISALLOW_COPY_AND_ASSIGN(PtrWrapper);
-  };
-
-  struct PtrWrapperDeleter {
-    static void Destruct(const PtrWrapper* interface_ptr) {
-      interface_ptr->DeleteOnCorrectThread();
-    }
-  };
-
-  ~ThreadSafeInterfacePtrBase() {}
-
-  const std::unique_ptr<ThreadSafeForwarder<InterfaceType>> forwarder_;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadSafeInterfacePtrBase);
-};
-
-template <typename Interface>
-using ThreadSafeAssociatedInterfacePtr =
-    ThreadSafeInterfacePtrBase<AssociatedInterfacePtr<Interface>>;
-
-template <typename Interface>
-using ThreadSafeInterfacePtr =
-    ThreadSafeInterfacePtrBase<InterfacePtr<Interface>>;
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_
diff --git a/mojo/public/cpp/bindings/type_converter.h b/mojo/public/cpp/bindings/type_converter.h
index 395eeb4..1446ab3 100644
--- a/mojo/public/cpp/bindings/type_converter.h
+++ b/mojo/public/cpp/bindings/type_converter.h
@@ -7,15 +7,8 @@
 
 #include <stdint.h>
 
-#include <vector>
-
 namespace mojo {
 
-// NOTE: TypeConverter is deprecated. Please consider StructTraits /
-// UnionTraits / EnumTraits / ArrayTraits / MapTraits / StringTraits if you
-// would like to convert between custom types and the wire format of mojom
-// types.
-//
 // Specialize the following class:
 //   template <typename T, typename U> struct TypeConverter;
 // to perform type conversion for Mojom-defined structs and arrays. Here, T is
@@ -81,9 +74,6 @@
 template <typename T, typename U>
 struct TypeConverter;
 
-template <typename T, typename U>
-inline T ConvertTo(const U& obj);
-
 // The following specialization is useful when you are converting between
 // Array<POD> and std::vector<POD>.
 template <typename T>
@@ -91,18 +81,6 @@
   static T Convert(const T& obj) { return obj; }
 };
 
-template <typename T, typename Container>
-struct TypeConverter<std::vector<T>, Container> {
-  static std::vector<T> Convert(const Container& container) {
-    std::vector<T> output;
-    output.reserve(container.size());
-    for (const auto& obj : container) {
-      output.push_back(ConvertTo<T>(obj));
-    }
-    return output;
-  }
-};
-
 // The following helper function is useful for shorthand. The compiler can infer
 // the input type, so you can write:
 //   OutputType out = ConvertTo<OutputType>(input);
diff --git a/mojo/public/cpp/bindings/union_traits.h b/mojo/public/cpp/bindings/union_traits.h
deleted file mode 100644
index 292ee58..0000000
--- a/mojo/public/cpp/bindings/union_traits.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_UNION_TRAITS_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_UNION_TRAITS_H_
-
-namespace mojo {
-
-// This must be specialized for any type |T| to be serialized/deserialized as
-// a mojom union. |DataViewType| is the corresponding data view type of the
-// mojom union. For example, if the mojom union is example.Foo, |DataViewType|
-// will be example::FooDataView, which can also be referred to by
-// example::Foo::DataView (in chromium) and example::blink::Foo::DataView (in
-// blink).
-//
-// Similar to StructTraits, each specialization of UnionTraits implements the
-// following methods:
-//   1. Getters for each field in the Mojom type.
-//   2. Read() method.
-//   3. [Optional] IsNull() and SetToNull().
-//   4. [Optional] SetUpContext() and TearDownContext().
-// Please see the documentation of StructTraits for details of these methods.
-//
-// Unlike StructTraits, there is one more method to implement:
-//   5. A static GetTag() method indicating which field is the current active
-//      field for serialization:
-//
-//        static DataViewType::Tag GetTag(const T& input);
-//
-//      During serialization, only the field getter corresponding to this tag
-//      will be called.
-//
-template <typename DataViewType, typename T>
-struct UnionTraits;
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_UNION_TRAITS_H_
diff --git a/mojo/public/cpp/bindings/wtf_array.h b/mojo/public/cpp/bindings/wtf_array.h
new file mode 100644
index 0000000..46d9a69
--- /dev/null
+++ b/mojo/public/cpp/bindings/wtf_array.h
@@ -0,0 +1,197 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_WTF_ARRAY_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_WTF_ARRAY_H_
+
+#include <stddef.h>
+#include <utility>
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+#include "mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h"
+#include "mojo/public/cpp/bindings/type_converter.h"
+#include "third_party/WebKit/Source/wtf/Vector.h"
+
+namespace mojo {
+
+// Represents an array backed by WTF::Vector. Comparing with WTF::Vector,
+// mojo::WTFArray is move-only and can be null.
+// It is easy to convert between WTF::Vector<T> and mojo::WTFArray<T>:
+//   - constructor WTFArray(WTF::Vector<T>&&) takes the contents of a
+//     WTF::Vector<T>;
+//   - method PassStorage() passes the underlying WTF::Vector.
+template <typename T>
+class WTFArray {
+ public:
+  // Constructs an empty array.
+  WTFArray() : is_null_(false) {}
+  // Constructs a null array.
+  WTFArray(std::nullptr_t null_pointer) : is_null_(true) {}
+
+  // Constructs a new non-null array of the specified size. The elements will
+  // be value-initialized (meaning that they will be initialized by their
+  // default constructor, if any, or else zero-initialized).
+  explicit WTFArray(size_t size) : vec_(size), is_null_(false) {}
+  ~WTFArray() {}
+
+  // Moves the contents of |other| into this array.
+  WTFArray(WTF::Vector<T>&& other) : vec_(std::move(other)), is_null_(false) {}
+  WTFArray(WTFArray&& other) : is_null_(true) { Take(&other); }
+
+  WTFArray& operator=(WTF::Vector<T>&& other) {
+    vec_ = std::move(other);
+    is_null_ = false;
+    return *this;
+  }
+  WTFArray& operator=(WTFArray&& other) {
+    Take(&other);
+    return *this;
+  }
+
+  WTFArray& operator=(std::nullptr_t null_pointer) {
+    is_null_ = true;
+    vec_.clear();
+    return *this;
+  }
+
+  // Creates a non-null array of the specified size. The elements will be
+  // value-initialized (meaning that they will be initialized by their default
+  // constructor, if any, or else zero-initialized).
+  static WTFArray New(size_t size) { return WTFArray(size); }
+
+  // Creates a new array with a copy of the contents of |other|.
+  template <typename U>
+  static WTFArray From(const U& other) {
+    return TypeConverter<WTFArray, U>::Convert(other);
+  }
+
+  // Copies the contents of this array to a new object of type |U|.
+  template <typename U>
+  U To() const {
+    return TypeConverter<U, WTFArray>::Convert(*this);
+  }
+
+  // Indicates whether the array is null (which is distinct from empty).
+  bool is_null() const {
+    // When the array is set to null, the underlying storage |vec_| shouldn't
+    // contain any elements.
+    DCHECK(!is_null_ || vec_.isEmpty());
+    return is_null_;
+  }
+
+  // Indicates whether the array is empty (which is distinct from null).
+  bool empty() const { return vec_.isEmpty() && !is_null_; }
+
+  // Returns a reference to the first element of the array. Calling this on a
+  // null or empty array causes undefined behavior.
+  const T& front() const { return vec_.first(); }
+  T& front() { return vec_.first(); }
+
+  // Returns the size of the array, which will be zero if the array is null.
+  size_t size() const { return vec_.size(); }
+
+  // Returns a reference to the element at zero-based |offset|. Calling this on
+  // an array with size less than |offset|+1 causes undefined behavior.
+  const T& at(size_t offset) const { return vec_.at(offset); }
+  const T& operator[](size_t offset) const { return at(offset); }
+  T& at(size_t offset) { return vec_.at(offset); }
+  T& operator[](size_t offset) { return at(offset); }
+
+  // Resizes the array to |size| and makes it non-null. Otherwise, works just
+  // like the resize method of |WTF::Vector|.
+  void resize(size_t size) {
+    is_null_ = false;
+    vec_.resize(size);
+  }
+
+  // Sets the array to empty (even if previously it was null.)
+  void SetToEmpty() { resize(0); }
+
+  // Returns a const reference to the |WTF::Vector| managed by this class. If
+  // the array is null, this will be an empty vector.
+  const WTF::Vector<T>& storage() const { return vec_; }
+
+  // Passes the underlying storage and resets this array to null.
+  //
+  // TODO(yzshen): Consider changing this to a rvalue-ref-qualified conversion
+  // to WTF::Vector<T> after we move to MSVC 2015.
+  WTF::Vector<T> PassStorage() {
+    is_null_ = true;
+    return std::move(vec_);
+  }
+
+  void Swap(WTFArray* other) {
+    std::swap(is_null_, other->is_null_);
+    vec_.swap(other->vec_);
+  }
+
+  // Swaps the contents of this array with the specified vector, making this
+  // array non-null. Since the vector cannot represent null, it will just be
+  // made empty if this array is null.
+  void Swap(WTF::Vector<T>* other) {
+    is_null_ = false;
+    vec_.swap(*other);
+  }
+
+  // Returns a copy of the array where each value of the new array has been
+  // "cloned" from the corresponding value of this array. If the element type
+  // defines a Clone() method, it will be used; otherwise copy
+  // constructor/assignment will be used.
+  //
+  // 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 containing Mojo handles).
+  WTFArray Clone() const {
+    WTFArray result;
+    result.is_null_ = is_null_;
+    result.vec_ = internal::Clone(vec_);
+    return result;
+  }
+
+  // Indicates whether the contents of this array are equal to |other|. A null
+  // array is only equal to another null array. If the element type defines an
+  // Equals() method, it will be used; otherwise == operator will be used.
+  bool Equals(const WTFArray& other) const {
+    if (is_null() != other.is_null())
+      return false;
+    return internal::Equals(vec_, other.vec_);
+  }
+
+ private:
+  // TODO(dcheng): Use an explicit conversion operator.
+  typedef WTF::Vector<T> WTFArray::*Testable;
+
+ public:
+  operator Testable() const {
+    // When the array is set to null, the underlying storage |vec_| shouldn't
+    // contain any elements.
+    DCHECK(!is_null_ || vec_.isEmpty());
+    return is_null_ ? 0 : &WTFArray::vec_;
+  }
+
+ private:
+  // Forbid the == and != operators explicitly, otherwise WTFArray will be
+  // converted to Testable to do == or != comparison.
+  template <typename U>
+  bool operator==(const WTFArray<U>& other) const = delete;
+  template <typename U>
+  bool operator!=(const WTFArray<U>& other) const = delete;
+
+  void Take(WTFArray* other) {
+    operator=(nullptr);
+    Swap(other);
+  }
+
+  WTF::Vector<T> vec_;
+  bool is_null_;
+
+  DISALLOW_COPY_AND_ASSIGN(WTFArray);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_WTF_ARRAY_H_
diff --git a/mojo/public/cpp/bindings/wtf_map.h b/mojo/public/cpp/bindings/wtf_map.h
new file mode 100644
index 0000000..0aba959
--- /dev/null
+++ b/mojo/public/cpp/bindings/wtf_map.h
@@ -0,0 +1,200 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_WTF_MAP_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_WTF_MAP_H_
+
+#include <stddef.h>
+#include <utility>
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+#include "mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h"
+#include "mojo/public/cpp/bindings/type_converter.h"
+#include "third_party/WebKit/Source/wtf/HashMap.h"
+#include "third_party/WebKit/Source/wtf/text/StringHash.h"
+
+namespace mojo {
+
+// Represents a map backed by WTF::HashMap. Comparing with WTF::HashMap,
+// mojo::WTFMap is move-only and can be null.
+//
+// It is easy to convert between WTF::HashMap<K, V> and mojo::WTFMap<K, V>:
+//   - constructor WTFMap(WTF::HashMap<K, V>&&) takes the contents of a
+//     WTF::HashMap<K, V>;
+//   - method PassStorage() passes the underlying WTF::HashMap.
+//
+// NOTE: WTF::HashMap disallows certain key values. For integer types, those are
+// 0 and -1 (max value instead of -1 for unsigned). For string, that is null.
+template <typename Key, typename Value>
+class WTFMap {
+ public:
+  using Iterator = typename WTF::HashMap<Key, Value>::iterator;
+  using ConstIterator = typename WTF::HashMap<Key, Value>::const_iterator;
+
+  // Constructs an empty map.
+  WTFMap() : is_null_(false) {}
+  // Constructs a null map.
+  WTFMap(std::nullptr_t null_pointer) : is_null_(true) {}
+
+  ~WTFMap() {}
+
+  WTFMap(WTF::HashMap<Key, Value>&& other)
+      : map_(std::move(other)), is_null_(false) {}
+  WTFMap(WTFMap&& other) : is_null_(true) { Take(&other); }
+
+  WTFMap& operator=(WTF::HashMap<Key, Value>&& other) {
+    is_null_ = false;
+    map_ = std::move(other);
+    return *this;
+  }
+  WTFMap& operator=(WTFMap&& other) {
+    Take(&other);
+    return *this;
+  }
+
+  WTFMap& operator=(std::nullptr_t null_pointer) {
+    is_null_ = true;
+    map_.clear();
+    return *this;
+  }
+
+  static bool IsValidKey(const Key& key) {
+    return WTF::HashMap<Key, Value>::isValidKey(key);
+  }
+
+  // Copies the contents of some other type of map into a new WTFMap using a
+  // TypeConverter.
+  template <typename U>
+  static WTFMap From(const U& other) {
+    return TypeConverter<WTFMap, U>::Convert(other);
+  }
+
+  // Copies the contents of the WTFMap into some other type of map.
+  template <typename U>
+  U To() const {
+    return TypeConverter<U, WTFMap>::Convert(*this);
+  }
+
+  // Indicates whether the map is null (which is distinct from empty).
+  bool is_null() const { return is_null_; }
+
+  // Indicates whether the map is empty (which is distinct from null).
+  bool empty() const { return map_.isEmpty() && !is_null_; }
+
+  // Indicates the number of keys in the map, which will be zero if the map is
+  // null.
+  size_t size() const { return map_.size(); }
+
+  // Inserts a key-value pair into the map. Like WTF::HashMap::add(), this does
+  // not insert |value| if |key| is already a member of the map.
+  void insert(const Key& key, const Value& value) {
+    is_null_ = false;
+    map_.add(key, value);
+  }
+  void insert(const Key& key, Value&& value) {
+    is_null_ = false;
+    map_.add(key, std::move(value));
+  }
+
+  // Returns a reference to the value associated with the specified key,
+  // crashing the process if the key is not present in the map.
+  Value& at(const Key& key) { return map_.find(key)->value; }
+  const Value& at(const Key& key) const { return map_.find(key)->value; }
+
+  // Returns a reference to the value associated with the specified key,
+  // creating a new entry if the key is not already present in the map. A
+  // newly-created value will be value-initialized (meaning that it will be
+  // initialized by the default constructor of the value type, if any, or else
+  // will be zero-initialized).
+  Value& operator[](const Key& key) {
+    is_null_ = false;
+    if (!map_.contains(key))
+      map_.add(key, Value());
+    return at(key);
+  }
+
+  // Sets the map to empty (even if previously it was null).
+  void SetToEmpty() {
+    is_null_ = false;
+    map_.clear();
+  }
+
+  // Returns a const reference to the WTF::HashMap managed by this class. If
+  // this object is null, the return value will be an empty map.
+  const WTF::HashMap<Key, Value>& storage() const { return map_; }
+
+  // Passes the underlying storage and resets this map to null.
+  WTF::HashMap<Key, Value> PassStorage() {
+    is_null_ = true;
+    return std::move(map_);
+  }
+
+  // Swaps the contents of this WTFMap with another WTFMap of the same type
+  // (including nullness).
+  void Swap(WTFMap<Key, Value>* other) {
+    std::swap(is_null_, other->is_null_);
+    map_.swap(other->map_);
+  }
+
+  // Swaps the contents of this WTFMap with an WTF::HashMap containing keys and
+  // values of the same type. Since WTF::HashMap cannot represent the null
+  // state, the WTF::HashMap will be empty if WTFMap is null. The WTFMap will
+  // always be left in a non-null state.
+  void Swap(WTF::HashMap<Key, Value>* other) {
+    is_null_ = false;
+    map_.swap(*other);
+  }
+
+  // Returns a new WTFMap that contains a copy of the contents of this map. If
+  // the key/value type defines a Clone() method, it will be used; otherwise
+  // copy constructor/assignment will be used.
+  //
+  // Please note that calling this method will fail compilation if the key/value
+  // type cannot be cloned (which usually means that it is a Mojo handle type or
+  // a type containing Mojo handles).
+  WTFMap Clone() const {
+    WTFMap result;
+    result.is_null_ = is_null_;
+    result.map_ = internal::Clone(map_);
+    return result;
+  }
+
+  // Indicates whether the contents of this map are equal to those of another
+  // WTFMap (including nullness). If the key/value type defines an Equals()
+  // method, it will be used; otherwise == operator will be used.
+  bool Equals(const WTFMap& other) const {
+    if (is_null() != other.is_null())
+      return false;
+    return internal::Equals(map_, other.map_);
+  }
+
+  ConstIterator begin() const { return map_.begin(); }
+  Iterator begin() { return map_.begin(); }
+
+  ConstIterator end() const { return map_.end(); }
+  Iterator end() { return map_.end(); }
+
+  // Returns the iterator pointing to the entry for |key|, if present, or else
+  // returns end().
+  ConstIterator find(const Key& key) const { return map_.find(key); }
+  Iterator find(const Key& key) { return map_.find(key); }
+
+  explicit operator bool() const { return !is_null_; }
+
+ private:
+  void Take(WTFMap* other) {
+    operator=(nullptr);
+    Swap(other);
+  }
+
+  WTF::HashMap<Key, Value> map_;
+  bool is_null_;
+
+  DISALLOW_COPY_AND_ASSIGN(WTFMap);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_WTF_MAP_H_
diff --git a/mojo/public/cpp/system/BUILD.gn b/mojo/public/cpp/system/BUILD.gn
index 0dc7af9..8dcec71 100644
--- a/mojo/public/cpp/system/BUILD.gn
+++ b/mojo/public/cpp/system/BUILD.gn
@@ -2,26 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# Deletes libsystem.dylib from the build dir, since it shadows
-# /usr/lib/libSystem.dylib on macOS.
-# TODO(thakis): Remove this after a while.
-action("clean_up_old_dylib") {
-  script = "//build/rm.py"
-  stamp = "$target_gen_dir/clean_up_stamp"
-  outputs = [
-    stamp,
-  ]
-  args = [
-    "--stamp",
-    rebase_path(stamp, root_build_dir),
-    "-f",
-    "libsystem.dylib",
-  ]
-}
-
-component("system") {
-  output_name = "mojo_public_system_cpp"
-
+source_set("system") {
   sources = [
     "buffer.cc",
     "buffer.h",
@@ -33,7 +14,6 @@
     "message_pipe.h",
     "platform_handle.cc",
     "platform_handle.h",
-    "system_export.h",
     "watcher.cc",
     "watcher.h",
   ]
@@ -42,9 +22,4 @@
     "//base",
     "//mojo/public/c/system",
   ]
-  deps = [
-    ":clean_up_old_dylib",
-  ]
-
-  defines = [ "MOJO_CPP_SYSTEM_IMPLEMENTATION" ]
 }
diff --git a/mojo/public/cpp/system/buffer.h b/mojo/public/cpp/system/buffer.h
index 1ae923c..449c6ce 100644
--- a/mojo/public/cpp/system/buffer.h
+++ b/mojo/public/cpp/system/buffer.h
@@ -20,7 +20,6 @@
 #include "base/logging.h"
 #include "mojo/public/c/system/buffer.h"
 #include "mojo/public/cpp/system/handle.h"
-#include "mojo/public/cpp/system/system_export.h"
 
 namespace mojo {
 namespace internal {
@@ -42,8 +41,7 @@
 
 // A strongly-typed representation of a |MojoHandle| referring to a shared
 // buffer.
-class MOJO_CPP_SYSTEM_EXPORT SharedBufferHandle
-    : NON_EXPORTED_BASE(public Handle) {
+class SharedBufferHandle : public Handle {
  public:
   enum class AccessMode {
     READ_WRITE,
diff --git a/mojo/public/cpp/system/platform_handle.cc b/mojo/public/cpp/system/platform_handle.cc
index 42e4aba..e4a6088 100644
--- a/mojo/public/cpp/system/platform_handle.cc
+++ b/mojo/public/cpp/system/platform_handle.cc
@@ -4,11 +4,6 @@
 
 #include "mojo/public/cpp/system/platform_handle.h"
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-#include <mach/mach.h>
-#include "base/mac/mach_logging.h"
-#endif
-
 namespace mojo {
 
 namespace {
@@ -66,13 +61,6 @@
     const base::SharedMemoryHandle& memory_handle,
     size_t size,
     bool read_only) {
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
-  if (memory_handle.fd == base::kInvalidPlatformFile)
-    return ScopedSharedBufferHandle();
-#else
-  if (!memory_handle.IsValid())
-    return ScopedSharedBufferHandle();
-#endif
   MojoPlatformHandle platform_handle;
   platform_handle.struct_size = sizeof(MojoPlatformHandle);
   platform_handle.type = kPlatformSharedBufferHandleType;
@@ -103,8 +91,6 @@
                                     base::SharedMemoryHandle* memory_handle,
                                     size_t* size,
                                     bool* read_only) {
-  if (!handle.is_valid())
-    return MOJO_RESULT_INVALID_ARGUMENT;
   MojoPlatformHandle platform_handle;
   platform_handle.struct_size = sizeof(MojoPlatformHandle);
 
@@ -140,39 +126,4 @@
   return MOJO_RESULT_OK;
 }
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-ScopedHandle WrapMachPort(mach_port_t port) {
-  kern_return_t kr =
-      mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, 1);
-  MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
-      << "MachPortAttachmentMac mach_port_mod_refs";
-  if (kr != KERN_SUCCESS)
-    return ScopedHandle();
-
-  MojoPlatformHandle platform_handle;
-  platform_handle.struct_size = sizeof(MojoPlatformHandle);
-  platform_handle.type = MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT;
-  platform_handle.value = static_cast<uint64_t>(port);
-
-  MojoHandle mojo_handle;
-  MojoResult result = MojoWrapPlatformHandle(&platform_handle, &mojo_handle);
-  CHECK_EQ(result, MOJO_RESULT_OK);
-
-  return ScopedHandle(Handle(mojo_handle));
-}
-
-MojoResult UnwrapMachPort(ScopedHandle handle, mach_port_t* port) {
-  MojoPlatformHandle platform_handle;
-  platform_handle.struct_size = sizeof(MojoPlatformHandle);
-  MojoResult result =
-      MojoUnwrapPlatformHandle(handle.release().value(), &platform_handle);
-  if (result != MOJO_RESULT_OK)
-    return result;
-
-  CHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT);
-  *port = static_cast<mach_port_t>(platform_handle.value);
-  return MOJO_RESULT_OK;
-}
-#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
-
 }  // namespace mojo
diff --git a/mojo/public/cpp/system/platform_handle.h b/mojo/public/cpp/system/platform_handle.h
index 801264e..2a81734 100644
--- a/mojo/public/cpp/system/platform_handle.h
+++ b/mojo/public/cpp/system/platform_handle.h
@@ -22,7 +22,6 @@
 #include "mojo/public/c/system/platform_handle.h"
 #include "mojo/public/cpp/system/buffer.h"
 #include "mojo/public/cpp/system/handle.h"
-#include "mojo/public/cpp/system/system_export.h"
 
 #if defined(OS_WIN)
 #include <windows.h>
@@ -51,18 +50,15 @@
 #endif  // defined(OS_POSIX)
 
 // Wraps a PlatformFile as a Mojo handle. Takes ownership of the file object.
-MOJO_CPP_SYSTEM_EXPORT
 ScopedHandle WrapPlatformFile(base::PlatformFile platform_file);
 
 // Unwraps a PlatformFile from a Mojo handle.
-MOJO_CPP_SYSTEM_EXPORT
 MojoResult UnwrapPlatformFile(ScopedHandle handle, base::PlatformFile* file);
 
 // Wraps a base::SharedMemoryHandle as a Mojo handle. Takes ownership of the
 // SharedMemoryHandle. Note that |read_only| is only an indicator of whether
 // |memory_handle| only supports read-only mapping. It does NOT have any
 // influence on the access control of the shared buffer object.
-MOJO_CPP_SYSTEM_EXPORT
 ScopedSharedBufferHandle WrapSharedMemoryHandle(
     const base::SharedMemoryHandle& memory_handle,
     size_t size,
@@ -70,22 +66,10 @@
 
 // Unwraps a base::SharedMemoryHandle from a Mojo handle. The caller assumes
 // responsibility for the lifetime of the SharedMemoryHandle.
-MOJO_CPP_SYSTEM_EXPORT MojoResult
-UnwrapSharedMemoryHandle(ScopedSharedBufferHandle handle,
-                         base::SharedMemoryHandle* memory_handle,
-                         size_t* size,
-                         bool* read_only);
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-// Wraps a mach_port_t as a Mojo handle. This takes a reference to the
-// Mach port.
-MOJO_CPP_SYSTEM_EXPORT ScopedHandle WrapMachPort(mach_port_t port);
-
-// Unwraps a mach_port_t from a Mojo handle. The caller gets ownership of the
-// Mach port.
-MOJO_CPP_SYSTEM_EXPORT MojoResult UnwrapMachPort(ScopedHandle handle,
-                                                 mach_port_t* port);
-#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+MojoResult UnwrapSharedMemoryHandle(ScopedSharedBufferHandle handle,
+                                    base::SharedMemoryHandle* memory_handle,
+                                    size_t* size,
+                                    bool* read_only);
 
 }  // namespace mojo
 
diff --git a/mojo/public/cpp/system/system_export.h b/mojo/public/cpp/system/system_export.h
deleted file mode 100644
index c9bb140..0000000
--- a/mojo/public/cpp/system/system_export.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_SYSTEM_SYSTEM_EXPORT_H_
-#define MOJO_PUBLIC_CPP_SYSTEM_SYSTEM_EXPORT_H_
-
-#if defined(COMPONENT_BUILD)
-
-#if defined(WIN32)
-
-#if defined(MOJO_CPP_SYSTEM_IMPLEMENTATION)
-#define MOJO_CPP_SYSTEM_EXPORT __declspec(dllexport)
-#else
-#define MOJO_CPP_SYSTEM_EXPORT __declspec(dllimport)
-#endif
-
-#else  // !defined(WIN32)
-
-#if defined(MOJO_CPP_SYSTEM_IMPLEMENTATION)
-#define MOJO_CPP_SYSTEM_EXPORT __attribute((visibility("default")))
-#else
-#define MOJO_CPP_SYSTEM_EXPORT
-#endif
-
-#endif  // defined(WIN32)
-
-#else  // !defined(COMPONENT_BUILD)
-
-#define MOJO_CPP_SYSTEM_EXPORT
-
-#endif  // defined(COMPONENT_BUILD)
-
-#endif  // MOJO_PUBLIC_CPP_SYSTEM_SYSTEM_EXPORT_H_
diff --git a/mojo/public/cpp/system/watcher.cc b/mojo/public/cpp/system/watcher.cc
index 55dcf40..d9319fb 100644
--- a/mojo/public/cpp/system/watcher.cc
+++ b/mojo/public/cpp/system/watcher.cc
@@ -7,17 +7,49 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/macros.h"
-#include "base/trace_event/heap_profiler.h"
+#include "base/message_loop/message_loop.h"
 #include "mojo/public/c/system/functions.h"
 
 namespace mojo {
 
-Watcher::Watcher(const tracked_objects::Location& from_here,
-                 scoped_refptr<base::SingleThreadTaskRunner> runner)
+class Watcher::MessageLoopObserver
+    : public base::MessageLoop::DestructionObserver {
+ public:
+  explicit MessageLoopObserver(Watcher* watcher) : watcher_(watcher) {
+    base::MessageLoop::current()->AddDestructionObserver(this);
+  }
+
+  ~MessageLoopObserver() override {
+    StopObservingIfNecessary();
+  }
+
+ private:
+  // base::MessageLoop::DestructionObserver:
+  void WillDestroyCurrentMessageLoop() override {
+    StopObservingIfNecessary();
+    if (watcher_->IsWatching()) {
+      // TODO(yzshen): Remove this notification. crbug.com/604762
+      watcher_->OnHandleReady(MOJO_RESULT_ABORTED);
+    }
+  }
+
+  void StopObservingIfNecessary() {
+    if (is_observing_) {
+      is_observing_ = false;
+      base::MessageLoop::current()->RemoveDestructionObserver(this);
+    }
+  }
+
+  bool is_observing_ = true;
+  Watcher* watcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver);
+};
+
+Watcher::Watcher(scoped_refptr<base::SingleThreadTaskRunner> runner)
     : task_runner_(std::move(runner)),
       is_default_task_runner_(task_runner_ ==
                               base::ThreadTaskRunnerHandle::Get()),
-      heap_profiler_tag_(from_here.file_name()),
       weak_factory_(this) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   weak_self_ = weak_factory_.GetWeakPtr();
@@ -40,6 +72,7 @@
   DCHECK(!IsWatching());
   DCHECK(!callback.is_null());
 
+  message_loop_observer_.reset(new MessageLoopObserver(this));
   callback_ = callback;
   handle_ = handle;
   MojoResult result = MojoWatch(handle_.value(), signals,
@@ -48,6 +81,7 @@
   if (result != MOJO_RESULT_OK) {
     handle_.set_value(kInvalidHandleValue);
     callback_.Reset();
+    message_loop_observer_.reset();
     DCHECK(result == MOJO_RESULT_FAILED_PRECONDITION ||
            result == MOJO_RESULT_INVALID_ARGUMENT);
     return result;
@@ -65,6 +99,7 @@
 
   MojoResult result =
       MojoCancelWatch(handle_.value(), reinterpret_cast<uintptr_t>(this));
+  message_loop_observer_.reset();
   // |result| may be MOJO_RESULT_INVALID_ARGUMENT if |handle_| has closed, but
   // OnHandleReady has not yet been called.
   DCHECK(result == MOJO_RESULT_INVALID_ARGUMENT || result == MOJO_RESULT_OK);
@@ -77,15 +112,14 @@
 
   ReadyCallback callback = callback_;
   if (result == MOJO_RESULT_CANCELLED) {
+    message_loop_observer_.reset();
     handle_.set_value(kInvalidHandleValue);
     callback_.Reset();
   }
 
   // NOTE: It's legal for |callback| to delete |this|.
-  if (!callback.is_null()) {
-    TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event(heap_profiler_tag_);
+  if (!callback.is_null())
     callback.Run(result);
-  }
 }
 
 // static
@@ -99,7 +133,6 @@
   // TODO: Maybe we should also expose |signals_state| through the Watcher API.
   // Current HandleWatcher users have no need for it, so it's omitted here.
   Watcher* watcher = reinterpret_cast<Watcher*>(context);
-
   if ((flags & MOJO_WATCH_NOTIFICATION_FLAG_FROM_SYSTEM) &&
       watcher->task_runner_->RunsTasksOnCurrentThread() &&
       watcher->is_default_task_runner_) {
diff --git a/mojo/public/cpp/system/watcher.h b/mojo/public/cpp/system/watcher.h
index 236788b..82f3e81 100644
--- a/mojo/public/cpp/system/watcher.h
+++ b/mojo/public/cpp/system/watcher.h
@@ -5,6 +5,8 @@
 #ifndef MOJO_PUBLIC_CPP_SYSTEM_WATCHER_H_
 #define MOJO_PUBLIC_CPP_SYSTEM_WATCHER_H_
 
+#include <memory>
+
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -14,14 +16,13 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "mojo/public/c/system/types.h"
 #include "mojo/public/cpp/system/handle.h"
-#include "mojo/public/cpp/system/system_export.h"
 
 namespace mojo {
 
 // A Watcher watches a single Mojo handle for signal state changes.
 //
 // NOTE: Watchers may only be used on threads which have a running MessageLoop.
-class MOJO_CPP_SYSTEM_EXPORT Watcher {
+class Watcher {
  public:
   // A callback to be called any time a watched handle changes state in some
   // interesting way. The |result| argument indicates one of the following
@@ -34,11 +35,15 @@
   //
   //   |MOJO_RESULT_CANCELLED|: The handle has been closed and the watch has
   //       been cancelled implicitly.
+  //
+  //   |MOJO_RESULT_ABORTED|: Notifications can no longer be delivered for this
+  //       watcher for some unspecified reason, e.g., the watching thread may
+  //       be shutting down soon. Note that it is still necessary to explicitly
+  //       Cancel() the watch in this case.
   using ReadyCallback = base::Callback<void(MojoResult result)>;
 
-  Watcher(const tracked_objects::Location& from_here,
-          scoped_refptr<base::SingleThreadTaskRunner> runner =
-              base::ThreadTaskRunnerHandle::Get());
+  explicit Watcher(scoped_refptr<base::SingleThreadTaskRunner> runner =
+                       base::ThreadTaskRunnerHandle::Get());
 
   // NOTE: This destructor automatically calls |Cancel()| if the Watcher is
   // still active.
@@ -75,13 +80,10 @@
   Handle handle() const { return handle_; }
   ReadyCallback ready_callback() const { return callback_; }
 
- // Sets the tag used by the heap profiler.
- // |tag| must be a const string literal.
- void set_heap_profiler_tag(const char* heap_profiler_tag) {
-   heap_profiler_tag_ = heap_profiler_tag;
- }
-
  private:
+  class MessageLoopObserver;
+  friend class MessageLoopObserver;
+
   void OnHandleReady(MojoResult result);
 
   static void CallOnHandleReady(uintptr_t context,
@@ -98,6 +100,8 @@
   // for the thread.
   const bool is_default_task_runner_;
 
+  std::unique_ptr<MessageLoopObserver> message_loop_observer_;
+
   // A persistent weak reference to this Watcher which can be passed to the
   // Dispatcher any time this object should be signalled. Safe to access (but
   // not to dereference!) from any thread.
@@ -111,10 +115,6 @@
   // The callback to call when the handle is signaled.
   ReadyCallback callback_;
 
-  // Tag used to ID memory allocations that originated from notifications in
-  // this watcher.
-  const char* heap_profiler_tag_ = nullptr;
-
   base::WeakPtrFactory<Watcher> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(Watcher);
diff --git a/mojo/public/cpp/test_support/BUILD.gn b/mojo/public/cpp/test_support/BUILD.gn
index efa1712..3d33b4a 100644
--- a/mojo/public/cpp/test_support/BUILD.gn
+++ b/mojo/public/cpp/test_support/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+# GYP version: mojo/public/mojo_public.gyp:mojo_public_test_utils
 static_library("test_utils") {
   testonly = true