aboutsummaryrefslogtreecommitdiff
path: root/mojo/public/cpp/bindings
diff options
context:
space:
mode:
authorLuis Hector Chavez <lhchavez@google.com>2017-07-26 17:38:05 +0000
committerLuis Hector Chavez <lhchavez@google.com>2017-07-26 17:38:05 +0000
commit21a249e4d9cb0b2ec6f0ff84ed5f7939ea67ac52 (patch)
treed380c2689495d31fd250cf8f1d0ceebbdd4cf250 /mojo/public/cpp/bindings
parent8ac9103e05b66812c25348943383f9365d1ce3e0 (diff)
downloadlibmojo-21a249e4d9cb0b2ec6f0ff84ed5f7939ea67ac52.tar.gz
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
Diffstat (limited to 'mojo/public/cpp/bindings')
-rw-r--r--mojo/public/cpp/bindings/BUILD.gn68
-rw-r--r--mojo/public/cpp/bindings/array.h279
-rw-r--r--mojo/public/cpp/bindings/array_data_view.h244
-rw-r--r--mojo/public/cpp/bindings/array_traits.h4
-rw-r--r--mojo/public/cpp/bindings/array_traits_carray.h23
-rw-r--r--mojo/public/cpp/bindings/array_traits_standard.h43
-rw-r--r--mojo/public/cpp/bindings/array_traits_stl.h77
-rw-r--r--mojo/public/cpp/bindings/array_traits_wtf.h40
-rw-r--r--mojo/public/cpp/bindings/associated_binding.h162
-rw-r--r--mojo/public/cpp/bindings/associated_group.h77
-rw-r--r--mojo/public/cpp/bindings/associated_group_controller.h60
-rw-r--r--mojo/public/cpp/bindings/associated_interface_ptr.h143
-rw-r--r--mojo/public/cpp/bindings/associated_interface_ptr_info.h1
-rw-r--r--mojo/public/cpp/bindings/associated_interface_request.h5
-rw-r--r--mojo/public/cpp/bindings/binding.h58
-rw-r--r--mojo/public/cpp/bindings/binding_set.h272
-rw-r--r--mojo/public/cpp/bindings/bindings_export.h34
-rw-r--r--mojo/public/cpp/bindings/clone_traits.h86
-rw-r--r--mojo/public/cpp/bindings/connection_error_callback.h21
-rw-r--r--mojo/public/cpp/bindings/connector.h41
-rw-r--r--mojo/public/cpp/bindings/disconnect_reason.h25
-rw-r--r--mojo/public/cpp/bindings/interface_data_view.h25
-rw-r--r--mojo/public/cpp/bindings/interface_endpoint_client.h70
-rw-r--r--mojo/public/cpp/bindings/interface_ptr.h44
-rw-r--r--mojo/public/cpp/bindings/interface_ptr_set.h12
-rw-r--r--mojo/public/cpp/bindings/interface_request.h45
-rw-r--r--mojo/public/cpp/bindings/lib/array_internal.h19
-rw-r--r--mojo/public/cpp/bindings/lib/array_serialization.h49
-rw-r--r--mojo/public/cpp/bindings/lib/associated_group.cc31
-rw-r--r--mojo/public/cpp/bindings/lib/associated_group_controller.cc22
-rw-r--r--mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h49
-rw-r--r--mojo/public/cpp/bindings/lib/binding_state.h213
-rw-r--r--mojo/public/cpp/bindings/lib/bindings_internal.cc47
-rw-r--r--mojo/public/cpp/bindings/lib/bindings_internal.h114
-rw-r--r--mojo/public/cpp/bindings/lib/buffer.h54
-rw-r--r--mojo/public/cpp/bindings/lib/clone_equals_util.h (renamed from mojo/public/cpp/bindings/lib/equals_traits.h)73
-rw-r--r--mojo/public/cpp/bindings/lib/connector.cc102
-rw-r--r--mojo/public/cpp/bindings/lib/control_message_handler.cc112
-rw-r--r--mojo/public/cpp/bindings/lib/control_message_handler.h5
-rw-r--r--mojo/public/cpp/bindings/lib/control_message_proxy.cc165
-rw-r--r--mojo/public/cpp/bindings/lib/control_message_proxy.h17
-rw-r--r--mojo/public/cpp/bindings/lib/filter_chain.cc22
-rw-r--r--mojo/public/cpp/bindings/lib/filter_chain.h (renamed from mojo/public/cpp/bindings/filter_chain.h)35
-rw-r--r--mojo/public/cpp/bindings/lib/fixed_buffer.cc43
-rw-r--r--mojo/public/cpp/bindings/lib/fixed_buffer.h55
-rw-r--r--mojo/public/cpp/bindings/lib/handle_interface_serialization.h105
-rw-r--r--mojo/public/cpp/bindings/lib/hash_util.h84
-rw-r--r--mojo/public/cpp/bindings/lib/interface_endpoint_client.cc189
-rw-r--r--mojo/public/cpp/bindings/lib/interface_ptr_state.h220
-rw-r--r--mojo/public/cpp/bindings/lib/map_serialization.h27
-rw-r--r--mojo/public/cpp/bindings/lib/may_auto_lock.h62
-rw-r--r--mojo/public/cpp/bindings/lib/message.cc223
-rw-r--r--mojo/public/cpp/bindings/lib/message_buffer.cc37
-rw-r--r--mojo/public/cpp/bindings/lib/message_buffer.h15
-rw-r--r--mojo/public/cpp/bindings/lib/message_builder.cc67
-rw-r--r--mojo/public/cpp/bindings/lib/message_builder.h61
-rw-r--r--mojo/public/cpp/bindings/lib/message_filter.cc23
-rw-r--r--mojo/public/cpp/bindings/lib/message_header_validator.cc105
-rw-r--r--mojo/public/cpp/bindings/lib/message_internal.h45
-rw-r--r--mojo/public/cpp/bindings/lib/multiplex_router.cc543
-rw-r--r--mojo/public/cpp/bindings/lib/multiplex_router.h83
-rw-r--r--mojo/public/cpp/bindings/lib/native_struct.cc16
-rw-r--r--mojo/public/cpp/bindings/lib/native_struct_data.h4
-rw-r--r--mojo/public/cpp/bindings/lib/native_struct_serialization.cc10
-rw-r--r--mojo/public/cpp/bindings/lib/native_struct_serialization.h6
-rw-r--r--mojo/public/cpp/bindings/lib/no_interface.cc20
-rw-r--r--mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc28
-rw-r--r--mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc69
-rw-r--r--mojo/public/cpp/bindings/lib/router.cc323
-rw-r--r--mojo/public/cpp/bindings/lib/router.h177
-rw-r--r--mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc370
-rw-r--r--mojo/public/cpp/bindings/lib/serialization.h21
-rw-r--r--mojo/public/cpp/bindings/lib/serialization_context.cc5
-rw-r--r--mojo/public/cpp/bindings/lib/serialization_context.h22
-rw-r--r--mojo/public/cpp/bindings/lib/serialization_forward.h1
-rw-r--r--mojo/public/cpp/bindings/lib/string_serialization.h6
-rw-r--r--mojo/public/cpp/bindings/lib/string_traits_wtf.cc5
-rw-r--r--mojo/public/cpp/bindings/lib/sync_call_restrictions.cc4
-rw-r--r--mojo/public/cpp/bindings/lib/sync_handle_registry.cc19
-rw-r--r--mojo/public/cpp/bindings/lib/sync_handle_registry.h67
-rw-r--r--mojo/public/cpp/bindings/lib/validation_context.cc66
-rw-r--r--mojo/public/cpp/bindings/lib/validation_context.h101
-rw-r--r--mojo/public/cpp/bindings/lib/validation_errors.cc31
-rw-r--r--mojo/public/cpp/bindings/lib/validation_errors.h42
-rw-r--r--mojo/public/cpp/bindings/lib/validation_util.cc66
-rw-r--r--mojo/public/cpp/bindings/lib/validation_util.h110
-rw-r--r--mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h10
-rw-r--r--mojo/public/cpp/bindings/lib/wtf_serialization.h2
-rw-r--r--mojo/public/cpp/bindings/map.h312
-rw-r--r--mojo/public/cpp/bindings/map_data_view.h63
-rw-r--r--mojo/public/cpp/bindings/map_traits.h12
-rw-r--r--mojo/public/cpp/bindings/map_traits_standard.h53
-rw-r--r--mojo/public/cpp/bindings/map_traits_stl.h12
-rw-r--r--mojo/public/cpp/bindings/map_traits_wtf.h62
-rw-r--r--mojo/public/cpp/bindings/map_traits_wtf_hash_map.h15
-rw-r--r--mojo/public/cpp/bindings/message.h163
-rw-r--r--mojo/public/cpp/bindings/message_filter.h38
-rw-r--r--mojo/public/cpp/bindings/message_header_validator.h11
-rw-r--r--mojo/public/cpp/bindings/native_struct.h10
-rw-r--r--mojo/public/cpp/bindings/native_struct_data_view.h36
-rw-r--r--mojo/public/cpp/bindings/no_interface.h52
-rw-r--r--mojo/public/cpp/bindings/pipe_control_message_handler.h10
-rw-r--r--mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h7
-rw-r--r--mojo/public/cpp/bindings/pipe_control_message_proxy.h20
-rw-r--r--mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h22
-rw-r--r--mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h94
-rw-r--r--mojo/public/cpp/bindings/stl_converters.h245
-rw-r--r--mojo/public/cpp/bindings/string.h196
-rw-r--r--mojo/public/cpp/bindings/string_data_view.h34
-rw-r--r--mojo/public/cpp/bindings/string_traits.h19
-rw-r--r--mojo/public/cpp/bindings/string_traits_standard.h31
-rw-r--r--mojo/public/cpp/bindings/string_traits_string16.h3
-rw-r--r--mojo/public/cpp/bindings/strong_binding.h143
-rw-r--r--mojo/public/cpp/bindings/struct_ptr.h203
-rw-r--r--mojo/public/cpp/bindings/struct_traits.h45
-rw-r--r--mojo/public/cpp/bindings/sync_call_restrictions.h13
-rw-r--r--mojo/public/cpp/bindings/sync_handle_registry.h4
-rw-r--r--mojo/public/cpp/bindings/sync_handle_watcher.h3
-rw-r--r--mojo/public/cpp/bindings/thread_safe_interface_ptr.h278
-rw-r--r--mojo/public/cpp/bindings/type_converter.h22
-rw-r--r--mojo/public/cpp/bindings/union_traits.h39
-rw-r--r--mojo/public/cpp/bindings/wtf_array.h197
-rw-r--r--mojo/public/cpp/bindings/wtf_map.h200
123 files changed, 4561 insertions, 4782 deletions
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 @@ component("bindings") {
"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 @@ component("bindings") {
"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 @@ component("bindings") {
"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 @@ component("bindings") {
"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 @@ component("bindings") {
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 @@ if (!is_ios) {
# 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 @@ namespace mojo {
// 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 @@ struct CArray {
};
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 @@ struct ArrayTraits<CArray<T>> {
}
};
-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 @@ struct ArrayTraits<std::vector<T>> {
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 @@ struct ArrayTraits<std::vector<T>> {
}
};
-// 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 @@ class MOJO_CPP_BINDINGS_EXPORT AssociatedBindingBase {
// 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 @@ class AssociatedBinding : public AssociatedBindingBase {
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 @@ class AssociatedBinding : public AssociatedBindingBase {
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 @@ namespace mojo {
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:
- AssociatedGroup();
-
- explicit AssociatedGroup(scoped_refptr<AssociatedGroupController> controller);
-
- explicit AssociatedGroup(const ScopedInterfaceEndpointHandle& handle);
+ // Configuration used by CreateAssociatedInterface(). Please see the comments
+ // of that method for more details.
+ enum AssociatedInterfaceConfig { WILL_PASS_PTR, WILL_PASS_REQUEST };
+ AssociatedGroup();
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 @@ class MOJO_CPP_BINDINGS_EXPORT AssociatedGroupController
// 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 @@ namespace mojo {
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 @@ class AssociatedInterfacePtr {
// 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 @@ class AssociatedInterfacePtr {
// 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 @@ class AssociatedInterfacePtr {
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 @@ class AssociatedInterfacePtr {
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 @@ class AssociatedInterfacePtr {
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 @@ class AssociatedInterfacePtr {
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 @@ class AssociatedInterfacePtr {
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()) {
- AssociatedInterfacePtrInfo<Interface> ptr_info;
- auto request = MakeRequest(&ptr_info);
- 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_));
+ AssociatedInterfacePtrInfo<Interface> ptr_info;
+ group->CreateAssociatedInterface(AssociatedGroup::WILL_PASS_REQUEST,
+ &ptr_info, &request);
- AssociatedInterfaceRequest<Interface> request;
- request.Bind(std::move(endpoint1));
+ ptr->Bind(std::move(ptr_info), std::move(runner));
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 @@ template <typename Interface>
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 @@ class AssociatedInterfaceRequest {
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 @@ class MessageReceiver;
// 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 @@ class Binding {
// 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 @@ class Binding {
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 @@ class Binding {
// 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 @@ class Binding {
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 @@ class Binding {
// 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();
- }
-
- // 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;
- }
-
- // 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);
}
- // 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));
+ 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());
}
- // 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 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;
}
- // 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() {
+ for (const auto& it : bindings_) {
+ if (it) {
+ it->Close();
+ delete it.get();
+ }
+ }
+ bindings_.clear();
}
- 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(); }
-
- private:
- class DispatchFilter : public MessageReceiver {
- public:
- explicit DispatchFilter(Entry* entry) : entry_(entry) {}
- ~DispatchFilter() override {}
-
- private:
- // MessageReceiver:
- bool Accept(Message* message) override {
- entry_->WillDispatch();
- return true;
- }
-
- Entry* entry_;
-
- DISALLOW_COPY_AND_ASSIGN(DispatchFilter);
- };
+ ~Element() {}
- void WillDispatch() {
- DCHECK(ContextTraits::SupportsContext());
- binding_set_->SetDispatchContext(&context_);
+ void set_connection_error_handler(const base::Closure& error_handler) {
+ error_handler_ = error_handler;
}
- void OnConnectionError(uint32_t custom_reason,
- const std::string& description) {
- if (ContextTraits::SupportsContext())
- WillDispatch();
- binding_set_->OnConnectionError(binding_id_, custom_reason, description);
+ base::WeakPtr<Element> GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
}
- BindingType binding_;
- BindingSetBase* const binding_set_;
- const BindingId binding_id_;
- Context const context_;
+ void Close() { binding_.Close(); }
- DISALLOW_COPY_AND_ASSIGN(Entry);
- };
-
- void SetDispatchContext(const Context* context) {
- DCHECK(ContextTraits::SupportsContext());
- dispatch_context_ = context;
- if (!pre_dispatch_handler_.is_null())
- pre_dispatch_handler_.Run(*context);
- }
+ void OnConnectionError() {
+ base::Closure error_handler = error_handler_;
+ delete this;
+ if (!error_handler.is_null())
+ error_handler.Run();
+ }
- 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;
- }
+ private:
+ Binding<Interface> binding_;
+ base::Closure error_handler_;
+ base::WeakPtrFactory<Element> weak_ptr_factory_;
- void OnConnectionError(BindingId id,
- uint32_t custom_reason,
- const std::string& description) {
- auto it = bindings_.find(id);
- DCHECK(it != bindings_.end());
+ DISALLOW_COPY_AND_ASSIGN(Element);
+ };
- // 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 @@ namespace mojo {
// - 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 @@ class MOJO_CPP_BINDINGS_EXPORT Connector
// 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 @@ class MOJO_CPP_BINDINGS_EXPORT Connector
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 @@ class MOJO_CPP_BINDINGS_EXPORT Connector
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 @@ class MOJO_CPP_BINDINGS_EXPORT Connector
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/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 @@ class MOJO_CPP_BINDINGS_EXPORT InterfaceEndpointClient
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 @@ class MOJO_CPP_BINDINGS_EXPORT InterfaceEndpointClient
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 @@ class MOJO_CPP_BINDINGS_EXPORT InterfaceEndpointClient
// 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 @@ class MOJO_CPP_BINDINGS_EXPORT InterfaceEndpointClient
// 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 @@ class MOJO_CPP_BINDINGS_EXPORT InterfaceEndpointClient
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 @@ class MOJO_CPP_BINDINGS_EXPORT InterfaceEndpointClient
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 @@ namespace mojo {
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 @@ class InterfacePtr {
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 @@ class InterfacePtr {
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 @@ class InterfacePtr {
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 @@ class InterfacePtr {
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 @@ class InterfacePtr {
}
// 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 @@ class InterfacePtr {
// 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 @@ class InterfacePtr {
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 @@ class PtrSet {
~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 @@ class InterfaceRequest {
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 @@ class InterfaceRequest {
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 @@ InterfaceRequest<Interface> MakeRequest(ScopedMessagePipeHandle handle) {
//
// 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 @@ InterfaceRequest<Interface> MakeRequest(ScopedMessagePipeHandle handle) {
//
// 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 @@ namespace internal {
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 @@ template <>
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 @@ struct ArrayDataTraits<bool> {
//
// 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 @@ class Array_Data {
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 @@ class ArrayIterator<Traits, MaybeConstUserType, true> {
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 @@ struct ArraySerializer<
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 @@ struct ArraySerializer<
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 @@ struct ArraySerializer<MojomType,
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 @@ struct ArraySerializer<MojomType,
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 @@ struct ArraySerializer<
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 @@ struct ArraySerializer<
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 @@ struct ArraySerializer<
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 @@ struct ArraySerializer<
};
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;
-
-AssociatedGroup& AssociatedGroup::operator=(const AssociatedGroup& other) =
- default;
+ controller_ = other.controller_;
+ return *this;
+}
-AssociatedGroupController* AssociatedGroup::GetController() {
- if (controller_)
- return controller_.get();
+void AssociatedGroup::CreateEndpointHandlePair(
+ ScopedInterfaceEndpointHandle* local_endpoint,
+ ScopedInterfaceEndpointHandle* remote_endpoint) {
+ if (!controller_)
+ return;
- 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 @@ class AssociatedInterfacePtrState {
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 @@ class AssociatedInterfacePtrState {
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 @@ class AssociatedInterfacePtrState {
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 @@ class AssociatedInterfacePtrState {
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 @@ class AssociatedInterfacePtrState {
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,35 +31,77 @@
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_>();
+
+ 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();
- void ResumeIncomingMethodCallProcessing();
+ 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;
- void set_connection_error_handler(const base::Closure& error_handler) {
- DCHECK(is_bound());
- endpoint_client_->set_connection_error_handler(error_handler);
+ router_->CloseMessagePipe();
+ DestroyRouter();
+ }
+
+ InterfaceRequest<Interface> Unbind() {
+ InterfaceRequest<Interface> request =
+ MakeRequest<Interface>(router_->PassMessagePipe());
+ DestroyRouter();
+ return std::move(request);
}
- void set_connection_error_with_reason_handler(
- const ConnectionErrorWithReasonCallback& error_handler) {
+ void set_connection_error_handler(const base::Closure& error_handler) {
DCHECK(is_bound());
- endpoint_client_->set_connection_error_with_reason_handler(error_handler);
+ connection_error_handler_ = error_handler;
}
+ Interface* impl() { return impl_; }
+
bool is_bound() const { return !!router_; }
MessagePipeHandle handle() const {
@@ -68,42 +109,90 @@ class MOJO_CPP_BINDINGS_EXPORT BindingStateBase {
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 @@ class BindingState : public BindingStateBase {
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 @@ class Array_Data;
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 @@ inline bool IsAligned(const void* ptr) {
//
// 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 @@ struct Pointer {
};
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 @@ struct Interface_Data {
};
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 @@ struct MojomTypeTraits {
};
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 @@ struct MojomTypeTraits<ArrayDataView<T>, false> {
};
template <typename T>
-struct MojomTypeTraits<AssociatedInterfacePtrInfoDataView<T>, false> {
+struct MojomTypeTraits<AssociatedInterfacePtrInfo<T>, false> {
using Data = AssociatedInterface_Data;
using DataAsArrayElement = Data;
@@ -240,8 +220,8 @@ struct MojomTypeTraits<AssociatedInterfacePtrInfoDataView<T>, false> {
};
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 @@ struct MojomTypeTraits<ScopedHandleBase<T>, false> {
};
template <typename T>
-struct MojomTypeTraits<InterfacePtrDataView<T>, false> {
+struct MojomTypeTraits<InterfacePtr<T>, false> {
using Data = Interface_Data;
using DataAsArrayElement = Data;
@@ -281,7 +261,7 @@ struct MojomTypeTraits<InterfacePtrDataView<T>, false> {
};
template <typename T>
-struct MojomTypeTraits<InterfaceRequestDataView<T>, false> {
+struct MojomTypeTraits<InterfaceRequest<T>, false> {
using Data = Handle_Data;
using DataAsArrayElement = Data;
@@ -290,7 +270,7 @@ struct MojomTypeTraits<InterfaceRequestDataView<T>, false> {
};
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,19 +279,37 @@ struct MojomTypeTraits<MapDataView<K, V>, false> {
};
template <>
-struct MojomTypeTraits<NativeStructDataView, false> {
- using Data = internal::NativeStruct_Data;
+struct MojomTypeTraits<String, false> {
+ using Data = String_Data;
using DataAsArrayElement = Pointer<Data>;
- static const MojomTypeCategory category = MojomTypeCategory::STRUCT;
+ static const MojomTypeCategory category = MojomTypeCategory::STRING;
};
-template <>
-struct MojomTypeTraits<StringDataView, false> {
- using Data = String_Data;
- using DataAsArrayElement = Pointer<Data>;
+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;
+};
- static const MojomTypeCategory category = MojomTypeCategory::STRING;
+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>
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/equals_traits.h b/mojo/public/cpp/bindings/lib/clone_equals_util.h
index 53c7dce..f7bd898 100644
--- a/mojo/public/cpp/bindings/lib/equals_traits.h
+++ b/mojo/public/cpp/bindings/lib/clone_equals_util.h
@@ -2,8 +2,8 @@
// 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_
+#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>
@@ -16,6 +16,73 @@ 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));
@@ -91,4 +158,4 @@ bool Equals(const T& a, const T& b) {
} // namespace internal
} // namespace mojo
-#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_EQUALS_TRAITS_H_
+#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(ScopedMessagePipeHandle message_pipe,
}
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 @@ bool Connector::Accept(Message* message) {
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 @@ bool Connector::SyncWatch(const bool* should_stop) {
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 @@ void Connector::OnSyncHandleWatcherHandleReady(MojoResult result) {
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::OnHandleReadyInternal(MojoResult result) {
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 Connector::ReadSingleMessage(MojoResult* read_result) {
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 @@ void Connector::ReadAllAvailableMessages() {
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::ReadAllAvailableMessages() {
}
void Connector::CancelWait() {
- handle_watcher_.reset();
+ handle_watcher_.Cancel();
sync_watcher_.reset();
}
@@ -315,7 +325,7 @@ void Connector::HandleError(bool force_pipe_reset, bool force_async_handler) {
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 @@ ControlMessageHandler::~ControlMessageHandler() {
}
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::Accept(Message* message) {
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::AcceptWithResponder(
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();
- }
-
- 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());
-
- interface_control::internal::RunResponseMessageParams_Data* response_params =
- nullptr;
- Serialize<interface_control::RunResponseMessageParamsDataView>(
- response_params_ptr, builder.buffer(), &response_params, &context_);
+ 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_;
+
+ size_t size = PrepareToSerialize<RunResponseMessageParamsPtr>(
+ response_params_ptr, &context_);
+ ResponseMessageBuilder builder(kRunMessageId, size, message->request_id());
+
+ 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::Run(Message* message,
}
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 mojo {
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 internal {
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 @@ class RunResponseForwardToCallback : public MessageReceiver {
};
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;
-
- 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);
-
- interface_control::internal::RunMessageParams_Data* params = nullptr;
- Serialize<interface_control::RunMessageParamsDataView>(
- params_ptr, builder.buffer(), &params, &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);
+
+ size_t size = PrepareToSerialize<RunMessageParamsPtr>(params_ptr, context);
+ RequestMessageBuilder builder(kRunMessageId, size);
+
+ 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;
-
- auto params_ptr = interface_control::RunOrClosePipeMessageParams::New();
- params_ptr->input = std::move(input_ptr);
-
- 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);
+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);
+
+ size_t size =
+ PrepareToSerialize<RunOrClosePipeMessageParamsPtr>(params_ptr, context);
+ MessageBuilder builder(kRunOrClosePipeMessageId, size);
+
+ 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 @@ ControlMessageProxy::ControlMessageProxy(MessageReceiverWithResponder* receiver)
: 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 @@ class MessageReceiverWithResponder;
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/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::operator=(FilterChain&& other) {
}
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);
-}
-
-void FilterChain::Append(std::unique_ptr<MessageReceiver> filter) {
- filters_.emplace_back(std::move(filter));
+ return filters_.empty() ? sink_ : filters_.front();
}
+} // namespace internal
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/filter_chain.h b/mojo/public/cpp/bindings/lib/filter_chain.h
index 1262f39..447be3d 100644
--- a/mojo/public/cpp/bindings/filter_chain.h
+++ b/mojo/public/cpp/bindings/lib/filter_chain.h
@@ -2,22 +2,20 @@
// 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_
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_FILTER_CHAIN_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_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"
+#include "mojo/public/cpp/bindings/message_filter.h"
namespace mojo {
+namespace internal {
-class MOJO_CPP_BINDINGS_EXPORT FilterChain
- : NON_EXPORTED_BASE(public MessageReceiver) {
+class FilterChain {
public:
// Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while
// this object is alive.
@@ -25,22 +23,25 @@ class MOJO_CPP_BINDINGS_EXPORT FilterChain
FilterChain(FilterChain&& other);
FilterChain& operator=(FilterChain&& other);
- ~FilterChain() override;
+ ~FilterChain();
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;
+ // 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:
- std::vector<std::unique_ptr<MessageReceiver>> filters_;
+ // Owned by this object.
+ // TODO(dcheng): Use unique_ptr.
+ std::vector<MessageFilter*> filters_;
MessageReceiver* sink_;
@@ -49,13 +50,17 @@ class MOJO_CPP_BINDINGS_EXPORT FilterChain
template <typename FilterType, typename... Args>
inline void FilterChain::Append(Args&&... args) {
- Append(base::MakeUnique<FilterType>(std::forward<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_FILTER_CHAIN_H_
+#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 @@ struct Serializer<InterfacePtrDataView<Base>, InterfacePtr<T>> {
}
};
-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 @@ struct Serializer<InterfaceRequestDataView<Base>, InterfaceRequest<T>> {
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 @@ class ResponderThunk : public MessageReceiverWithStatus {
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 @@ bool InterfaceEndpointClient::HandleIncomingMessageThunk::Accept(
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 @@ ScopedInterfaceEndpointHandle InterfaceEndpointClient::PassHandle() {
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 InterfaceEndpointClient::AcceptWithResponder(Message* message,
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::AcceptWithResponder(Message* message,
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 @@ bool InterfaceEndpointClient::HandleValidatedMessage(Message* message) {
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 @@ bool InterfaceEndpointClient::HandleValidatedMessage(Message* message) {
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,35 +19,44 @@
#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() : version_(0u) {}
+ InterfacePtrState() : proxy_(nullptr), router_(nullptr), version_(0u) {}
~InterfacePtrState() {
- endpoint_client_.reset();
- proxy_.reset();
- if (router_)
- router_->CloseMessagePipe();
+ // 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_.get();
+ return proxy_;
}
uint32_t version() const { return version_; }
@@ -56,10 +64,12 @@ class InterfacePtrState {
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_)->QueryVersion(
+ base::Bind(&InterfacePtrState::OnQueryVersion, base::Unretained(this),
+ callback));
}
void RequireVersion(uint32_t version) {
@@ -69,17 +79,155 @@ class InterfacePtrState {
return;
version_ = version;
- endpoint_client_->RequireVersion(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) {}
+
+ ~InterfacePtrState() {
+ endpoint_client_.reset();
+ proxy_.reset();
+ if (router_)
+ router_->CloseMessagePipe();
+ }
+
+ Interface* instance() {
+ ConfigureProxyIfNecessary();
+
+ // This will be null if the object is not bound.
+ return proxy_.get();
}
- void FlushForTesting() {
+ uint32_t version() const { return version_; }
+
+ void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
ConfigureProxyIfNecessary();
- endpoint_client_->FlushForTesting();
+
+
+ // 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 CloseWithReason(uint32_t custom_reason, const std::string& description) {
+ void RequireVersion(uint32_t version) {
ConfigureProxyIfNecessary();
- endpoint_client_->CloseWithReason(custom_reason, description);
+
+ if (version <= version_)
+ return;
+
+ version_ = version;
+ // 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 @@ class InterfacePtrState {
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 @@ class InterfacePtrState {
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 @@ class InterfacePtrState {
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 @@ class MapKeyReader : public MapReaderBase<MaybeConstUserType> {
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 @@ class MapValueReader : public MapReaderBase<MaybeConstUserType> {
};
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 @@ struct Serializer<MapDataView<Key, Value>, MaybeConstUserType> {
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 @@ struct Serializer<MapDataView<Key, Value>, MaybeConstUserType> {
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 @@ void Message::InitializeFromMojoMessage(ScopedMessageHandle message,
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());
-}
-
-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);
-}
+ // No copy needed.
+ std::swap(destination->buffer_, buffer_);
+ std::swap(destination->handles_, handles_);
-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 @@ ScopedMessageHandle Message::TakeMojoMessage() {
}
void Message::NotifyBadMessage(const std::string& error) {
- DCHECK(buffer_);
buffer_->NotifyBadMessage(error);
}
@@ -165,88 +91,6 @@ void Message::CloseHandles() {
}
}
-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 @@ MojoResult ReadMessage(MessagePipeHandle handle, Message* message) {
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 @@ namespace internal {
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 @@ class MessageBuffer : public Buffer {
// 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 @@ void Allocate(Buffer* buf, Header** header) {
(*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)));
-
- 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);
+MessageBuilder::MessageBuilder(uint32_t name, size_t payload_size) {
+ 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 @@ class MOJO_CPP_BINDINGS_EXPORT MessageBuilder {
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 @@ bool IsValidMessageHeader(const internal::MessageHeader* header,
}
// 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 @@ void MessageHeaderValidator::SetDescription(const std::string& description) {
}
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 @@ bool MessageHeaderValidator::Accept(Message* message) {
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 @@ struct MessageHeader : internal::StructHeader {
};
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 @@ class MultiplexRouter::InterfaceEndpoint
id_(id),
closed_(false),
peer_closed_(false),
- handle_created_(false),
client_(nullptr),
event_signalled_(false) {}
@@ -51,31 +50,16 @@ class MultiplexRouter::InterfaceEndpoint
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 @@ class MultiplexRouter::InterfaceEndpoint
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 @@ class MultiplexRouter::InterfaceEndpoint
// 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 @@ class MultiplexRouter::InterfaceEndpoint
}
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 @@ class MultiplexRouter::InterfaceEndpoint
friend class base::RefCounted<InterfaceEndpoint>;
~InterfaceEndpoint() override {
- router_->AssertLockAcquired();
+ router_->lock_.AssertAcquired();
DCHECK(!client_);
DCHECK(closed_);
@@ -176,23 +142,26 @@ class MultiplexRouter::InterfaceEndpoint
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 @@ class MultiplexRouter::InterfaceEndpoint
return;
{
- MayAutoLock locker(&router_->lock_);
-
- 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();
- }
- }
+ base::AutoLock locker(router_->lock_);
+ EnsureEventMessagePipeExists();
+
+ 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 @@ class MultiplexRouter::InterfaceEndpoint
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 @@ class MultiplexRouter::InterfaceEndpoint
// 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 @@ class MultiplexRouter::InterfaceEndpoint
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 @@ struct MultiplexRouter::Task {
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 @@ struct MultiplexRouter::Task {
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 @@ MultiplexRouter::~MultiplexRouter() {
// 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));
-
- InterfaceEndpoint* endpoint = new InterfaceEndpoint(this, id);
- endpoints_[id] = endpoint;
- if (encountered_error_)
- UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
- endpoint->set_handle_created();
- }
-
- 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);
- }
+ 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);
- 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 @@ ScopedInterfaceEndpointHandle MultiplexRouter::CreateLocalEndpointHandle(
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 @@ ScopedInterfaceEndpointHandle MultiplexRouter::CreateLocalEndpointHandle(
// 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 @@ InterfaceEndpointController* MultiplexRouter::AttachEndpointClient(
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 @@ void MultiplexRouter::DetachEndpointClient(
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 @@ void MultiplexRouter::CloseMessagePipe() {
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 @@ void MultiplexRouter::EnableTestingMode() {
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 @@ bool MultiplexRouter::Accept(Message* message) {
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,16 +516,13 @@ bool MultiplexRouter::Accept(Message* message) {
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_);
- InterfaceEndpoint* endpoint = FindOrInsertEndpoint(id, nullptr);
+ if (IsMasterInterfaceId(id))
+ return false;
- if (reason)
- endpoint->set_disconnect_reason(reason);
+ InterfaceEndpoint* endpoint = FindOrInsertEndpoint(id, nullptr);
// 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
@@ -687,11 +541,26 @@ bool MultiplexRouter::OnPeerAssociatedEndpointClosed(
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::OnPipeConnectionError() {
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 @@ void MultiplexRouter::ProcessTasks(
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 @@ void MultiplexRouter::ProcessTasks(
}
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 @@ bool MultiplexRouter::ProcessNotifyErrorTask(
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 @@ bool MultiplexRouter::ProcessNotifyErrorTask(
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 @@ bool MultiplexRouter::ProcessIncomingMessage(
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 @@ bool MultiplexRouter::ProcessIncomingMessage(
//
// 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 @@ bool MultiplexRouter::ProcessIncomingMessage(
void MultiplexRouter::MaybePostToProcessTasks(
base::SingleThreadTaskRunner* task_runner) {
- AssertLockAcquired();
+ lock_.AssertAcquired();
if (posted_to_process_tasks_)
return;
@@ -921,7 +792,7 @@ void MultiplexRouter::MaybePostToProcessTasks(
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::LockAndCallProcessTasks() {
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 @@ void MultiplexRouter::RaiseErrorInNonTestingMode() {
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 @@ class SingleThreadTaskRunner;
namespace mojo {
+class AssociatedGroup;
+
namespace internal {
// MultiplexRouter supports routing messages for multiple interfaces over a
@@ -49,51 +47,31 @@ namespace internal {
// 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 @@ class MOJO_CPP_BINDINGS_EXPORT MultiplexRouter
}
// 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 @@ class MOJO_CPP_BINDINGS_EXPORT MultiplexRouter
return connector_.handle();
}
- bool SimulateReceivingMessageForTesting(Message* message) {
- return filters_.Accept(message);
- }
-
private:
class InterfaceEndpoint;
- class MessageWrapper;
struct Task;
~MultiplexRouter() override;
@@ -162,9 +141,8 @@ class MOJO_CPP_BINDINGS_EXPORT MultiplexRouter
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 @@ class MOJO_CPP_BINDINGS_EXPORT MultiplexRouter
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 @@ class MOJO_CPP_BINDINGS_EXPORT MultiplexRouter
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 @@ size_t UnmappedNativeStructSerializerImpl::PrepareToSerialize(
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 @@ void UnmappedNativeStructSerializerImpl::Serialize(
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 @@ bool UnmappedNativeStructSerializerImpl::Deserialize(
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 NativeStructSerializerImpl {
}
};
-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 @@ struct NativeStructSerializerImpl<const NativeStructPtr>
: 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::Accept(Message* message) {
}
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::Validate(Message* message) {
}
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 @@ Message ConstructRunOrClosePipeMessage(
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);
+void PipeControlMessageProxy::NotifyPeerEndpointClosed(InterfaceId id) {
+ DCHECK(!IsMasterInterfaceId(id));
+ pipe_control::PeerAssociatedEndpointClosedEventPtr event(
+ pipe_control::PeerAssociatedEndpointClosedEvent::New());
+ event->id = id;
+
+ pipe_control::RunOrClosePipeInputPtr input(
+ pipe_control::RunOrClosePipeInput::New());
+ input->set_peer_associated_endpoint_closed_event(std::move(event));
+
+ SendRunOrClosePipeMessage(receiver_, std::move(input), &context_);
}
-// static
-Message PipeControlMessageProxy::ConstructPeerEndpointClosedMessage(
- InterfaceId id,
- const base::Optional<DisconnectReason>& reason) {
- auto event = pipe_control::PeerAssociatedEndpointClosedEvent::New();
+void PipeControlMessageProxy::NotifyEndpointClosedBeforeSent(InterfaceId id) {
+ DCHECK(!IsMasterInterfaceId(id));
+ pipe_control::AssociatedEndpointClosedBeforeSentEventPtr event(
+ pipe_control::AssociatedEndpointClosedBeforeSentEvent::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();
- input->set_peer_associated_endpoint_closed_event(std::move(event));
+ pipe_control::RunOrClosePipeInputPtr input(
+ pipe_control::RunOrClosePipeInput::New());
+ input->set_associated_endpoint_closed_before_sent_event(std::move(event));
- return ConstructRunOrClosePipeMessage(std::move(input));
+ 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_);
- return *this;
-}
+ swap(other);
-bool ScopedInterfaceEndpointHandle::is_valid() const {
- return state_->is_valid();
+ return *this;
}
-bool ScopedInterfaceEndpointHandle::pending_association() const {
- return state_->pending_association();
-}
+void ScopedInterfaceEndpointHandle::reset() {
+ if (!IsValidInterfaceId(id_))
+ return;
-InterfaceId ScopedInterfaceEndpointHandle::id() const {
- return state_->id();
-}
+ group_controller_->CloseEndpointHandle(id_, is_local_);
-AssociatedGroupController* ScopedInterfaceEndpointHandle::group_controller()
- const {
- return state_->group_controller();
+ id_ = kInvalidInterfaceId;
+ is_local_ = true;
+ group_controller_ = nullptr;
}
-const base::Optional<DisconnectReason>&
-ScopedInterfaceEndpointHandle::disconnect_reason() const {
- return state_->disconnect_reason();
+void ScopedInterfaceEndpointHandle::swap(ScopedInterfaceEndpointHandle& other) {
+ using std::swap;
+ swap(other.id_, id_);
+ swap(other.is_local_, is_local_);
+ swap(other.group_controller_, group_controller_);
}
-void ScopedInterfaceEndpointHandle::SetAssociationEventHandler(
- AssociationEventCallback handler) {
- state_->SetAssociationEventHandler(std::move(handler));
-}
+InterfaceId ScopedInterfaceEndpointHandle::release() {
+ InterfaceId result = id_;
-void ScopedInterfaceEndpointHandle::reset() {
- ResetInternal(base::nullopt);
-}
+ id_ = kInvalidInterfaceId;
+ is_local_ = true;
+ group_controller_ = nullptr;
-void ScopedInterfaceEndpointHandle::ResetWithReason(
- uint32_t custom_reason,
- const std::string& description) {
- ResetInternal(DisconnectReason(custom_reason, description));
+ 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 @@ DataArrayType StructSerializeImpl(UserType* input) {
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 @@ DataArrayType StructSerializeImpl(UserType* input) {
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 @@ template <typename MojomType, typename DataArrayType, typename UserType>
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_;
+
+ if (input.is_null())
+ return false;
- // TODO(sammc): Use DataArrayType::empty() once WTF::Vector::empty() exists.
void* input_buffer =
- input.size() == 0
+ input.empty()
? nullptr
: const_cast<void*>(reinterpret_cast<const void*>(&input.front()));
@@ -84,7 +89,7 @@ bool StructDeserializeImpl(const DataArrayType& input, UserType* output) {
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 @@ void SerializedHandleVector::Swap(std::vector<mojo::Handle>* other) {
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 @@ class MOJO_CPP_BINDINGS_EXPORT SerializedHandleVector {
};
// 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 @@ struct Serializer<StringDataView, MaybeConstUserType> {
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 @@ namespace {
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* ToAdaptor(const WTF::String& input, void* context) {
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 @@ class SyncCallSettings {
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* SyncCallSettings::current() {
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 @@ bool SyncHandleRegistry::RegisterHandle(const Handle& handle,
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 @@ bool SyncHandleRegistry::RegisterHandle(const Handle& handle,
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() {
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 @@ namespace internal {
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 @@ class MOJO_CPP_BINDINGS_EXPORT ValidationContext {
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 @@ class MOJO_CPP_BINDINGS_EXPORT ValidationContext {
// 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 @@ class MOJO_CPP_BINDINGS_EXPORT ValidationContext {
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 @@ namespace {
ValidationErrorObserverForTesting* g_validation_error_observer = nullptr;
SerializationWarningObserverForTesting* g_serialization_warning_observer =
nullptr;
-bool g_suppress_logging = false;
} // namespace
@@ -56,8 +55,6 @@ const char* ValidationErrorToString(ValidationError error) {
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 @@ void ReportValidationError(ValidationContext* context,
}
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 @@ void ReportValidationError(ValidationContext* context,
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 ReportValidationError(ValidationContext* context,
}
}
-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 @@ enum ValidationError {
// 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);
-
-MOJO_CPP_BINDINGS_EXPORT void ReportValidationError(
- ValidationContext* context,
- ValidationError error,
- const char* description = nullptr);
+const char* ValidationErrorToString(ValidationError error);
-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 @@ class MOJO_CPP_BINDINGS_EXPORT ValidationErrorObserverForTesting {
//
// 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 @@ bool ValidateStructHeaderAndClaimMemory(const void* data,
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 @@ bool ValidateMessageIsResponse(const Message* message,
return true;
}
+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 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 input.handle.is_valid();
+ return IsValidInterfaceId(input.interface_id);
}
-bool IsHandleOrInterfaceValid(const AssociatedEndpointHandle_Data& input) {
- return input.is_valid();
+bool IsHandleOrInterfaceValid(const AssociatedInterfaceRequest_Data& input) {
+ return IsValidInterfaceId(input.interface_id);
}
bool IsHandleOrInterfaceValid(const Interface_Data& input) {
@@ -130,7 +172,7 @@ bool ValidateHandleOrInterfaceNonNullable(
}
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 ValidateHandleOrInterfaceNonNullable(
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 @@ bool ValidateHandleOrInterface(const AssociatedInterface_Data& input,
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 @@ namespace internal {
// 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 @@ bool ValidatePointer(const Pointer<T>& input,
// |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 @@ bool ValidateMessagePayload(const Message* message,
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 @@ bool ValidateInlinedUnionNonNullable(const T& input,
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 @@ template <typename T>
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 @@ bool ValidateContainer(const Pointer<T>& input,
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 @@ bool ValidateStruct(const Pointer<T>& input,
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 @@ struct CloneTraits<WTF::Vector<T>, false> {
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 @@ struct CloneTraits<WTF::HashMap<K, V>, false> {
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());
-}
-
-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()));
-}
-
-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());
-}
-
-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()));
-}
+// 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;
+
+ // Map keys cannot be move only classes.
+ static_assert(!internal::IsMoveOnlyType<Key>::value,
+ "Map keys cannot be move only types.");
+
+ using Iterator = typename std::map<Key, Value>::iterator;
+ using ConstIterator = typename std::map<Key, Value>::const_iterator;
+
+ // 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 @@ namespace mojo {
// 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 @@ struct MapTraits<std::unordered_map<K, V>> {
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 @@ struct MapTraits<WTF::HashMap<K, V>> {
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 @@ class MOJO_CPP_BINDINGS_EXPORT Message {
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 @@ class MOJO_CPP_BINDINGS_EXPORT Message {
const internal::MessageHeader* header() const {
return static_cast<const internal::MessageHeader*>(buffer_->data());
}
- internal::MessageHeader* header() {
- return static_cast<internal::MessageHeader*>(buffer_->data());
- }
- 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());
+ internal::MessageHeader* header() {
+ return const_cast<internal::MessageHeader*>(
+ static_cast<const Message*>(this)->header());
}
- 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 @@ class MOJO_CPP_BINDINGS_EXPORT Message {
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 @@ class MOJO_CPP_BINDINGS_EXPORT Message {
// 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 @@ class MessageReceiverWithResponderStatus : public MessageReceiver {
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 @@ class MOJO_CPP_BINDINGS_EXPORT SyncMessageResponseContext {
// 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 @@ using NativeStructPtr = StructPtr<NativeStruct>;
// 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 @@ class MOJO_CPP_BINDINGS_EXPORT NativeStruct {
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 @@ namespace mojo {
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 @@ class MOJO_CPP_BINDINGS_EXPORT PipeControlMessageHandler
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 @@ class PipeControlMessageHandlerDelegate {
// 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 @@ class AssociatedGroupController;
// 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 @@ class MOJO_CPP_BINDINGS_EXPORT ScopedInterfaceEndpointHandle {
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;
+ bool is_local() const { return is_local_; }
- // Returns kInvalidInterfaceId when in pending association state or the handle
- // is invalid.
- InterfaceId id() const;
+ void reset();
+ void swap(ScopedInterfaceEndpointHandle& other);
- // Returns null when in pending association state or the handle is invalid.
- AssociatedGroupController* group_controller() const;
+ // DO NOT USE METHODS BELOW THIS LINE. These are for internal use and testing.
- // 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;
+ InterfaceId id() const { return id_; }
- 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
- };
+ AssociatedGroupController* group_controller() const {
+ return group_controller_.get();
+ }
- 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);
-
- void reset();
- void ResetWithReason(uint32_t custom_reason, const std::string& description);
+ // 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 @@ namespace mojo {
// 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,121 +5,122 @@
#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.
+//
+// Example of an implementation that is always bound strongly to a pipe
//
-// To use, call StrongBinding<T>::Create() (see below) or the helper
-// MakeStrongBinding function:
+// class StronglyBound : public Foo {
+// public:
+// explicit StronglyBound(InterfaceRequest<Foo> request)
+// : binding_(this, std::move(request)) {}
//
-// mojo::MakeStrongBinding(base::MakeUnique<FooImpl>(),
-// std::move(foo_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));
}
- // Note: The error handler must not delete the interface implementation.
- //
- // This method may only be called after this StrongBinding has been bound to a
- // message pipe.
- 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();
+ StrongBinding(Interface* impl, InterfacePtr<Interface>* ptr)
+ : StrongBinding(impl) {
+ Bind(ptr);
}
- 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();
+ StrongBinding(Interface* impl, InterfaceRequest<Interface> request)
+ : StrongBinding(impl) {
+ Bind(std::move(request));
}
- // Forces the binding to close. This destroys the StrongBinding instance.
- void Close() { delete this; }
+ ~StrongBinding() {}
- Interface* impl() { return impl_.get(); }
+ 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)));
+ }
- // 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(); }
+ void Bind(InterfacePtr<Interface>* ptr) {
+ DCHECK(!binding_.is_bound());
+ binding_.Bind(ptr);
+ binding_.set_connection_error_handler(
+ base::Bind(&StrongBinding::OnConnectionError, base::Unretained(this)));
+ }
- 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(
+ 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)));
}
- ~StrongBinding() {}
+ bool WaitForIncomingMethodCall() {
+ return binding_.WaitForIncomingMethodCall();
+ }
+
+ // Note: The error handler must not delete the interface implementation.
+ //
+ // This method may only be called after this StrongBinding has been bound to a
+ // message pipe.
+ void set_connection_error_handler(const base::Closure& error_handler) {
+ DCHECK(binding_.is_bound());
+ connection_error_handler_ = error_handler;
+ }
+
+ Interface* impl() { return binding_.impl(); }
+ // Exposed for testing, should not generally be used.
+ internal::Router* internal_router() { return binding_.internal_router(); }
- 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 @@ class StructPtr {
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 @@ class StructPtr {
}
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 @@ class StructPtr {
// 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 @@ class InlinedStructPtr {
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 @@ namespace mojo {
// 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 @@ namespace mojo {
// - 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 @@ namespace mojo {
// 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 @@ namespace mojo {
// 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 @@ namespace mojo {
//
// 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 @@ namespace mojo {
// 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 @@ namespace mojo {
// 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 @@ class MOJO_CPP_BINDINGS_EXPORT SyncCallRestrictions {
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 @@ namespace mojo {
// 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 @@ namespace mojo {
// 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 @@ namespace mojo {
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 @@ struct TypeConverter<T, T> {
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_