diff options
Diffstat (limited to 'chromium/mojo/public/cpp/bindings')
98 files changed, 2930 insertions, 2232 deletions
diff --git a/chromium/mojo/public/cpp/bindings/BUILD.gn b/chromium/mojo/public/cpp/bindings/BUILD.gn index c8d2883d0c7..c66853cf8e5 100644 --- a/chromium/mojo/public/cpp/bindings/BUILD.gn +++ b/chromium/mojo/public/cpp/bindings/BUILD.gn @@ -5,6 +5,9 @@ source_set("bindings") { sources = [ "array.h", + "array_traits.h", + "array_traits_standard.h", + "array_traits_stl.h", "associated_binding.h", "associated_group.h", "associated_interface_ptr.h", @@ -19,13 +22,10 @@ source_set("bindings") { "lib/array_internal.cc", "lib/array_internal.h", "lib/array_serialization.h", - "lib/array_serialization_traits.h", "lib/associated_group.cc", "lib/associated_interface_ptr_state.h", "lib/binding_state.h", "lib/bindings_internal.h", - "lib/bindings_serialization.cc", - "lib/bindings_serialization.h", "lib/bounds_checker.cc", "lib/bounds_checker.h", "lib/buffer.h", @@ -44,11 +44,12 @@ source_set("bindings") { "lib/interface_endpoint_controller.h", "lib/interface_id.h", "lib/interface_ptr_state.h", - "lib/macros.h", "lib/map_data_internal.h", "lib/map_internal.h", "lib/map_serialization.h", "lib/message.cc", + "lib/message_buffer.cc", + "lib/message_buffer.h", "lib/message_builder.cc", "lib/message_builder.h", "lib/message_filter.cc", @@ -57,9 +58,12 @@ source_set("bindings") { "lib/message_internal.h", "lib/multiplex_router.cc", "lib/multiplex_router.h", + "lib/native_struct.cc", + "lib/native_struct_data.cc", + "lib/native_struct_data.h", + "lib/native_struct_serialization.cc", + "lib/native_struct_serialization.h", "lib/no_interface.cc", - "lib/pickle_buffer.cc", - "lib/pickle_buffer.h", "lib/pipe_control_message_handler.cc", "lib/pipe_control_message_handler.h", "lib/pipe_control_message_handler_delegate.h", @@ -68,11 +72,14 @@ source_set("bindings") { "lib/router.cc", "lib/router.h", "lib/scoped_interface_endpoint_handle.cc", - "lib/scoped_interface_endpoint_handle.h", "lib/serialization.h", + "lib/serialization_context.cc", + "lib/serialization_context.h", "lib/serialization_forward.h", - "lib/string_serialization.cc", + "lib/serialization_util.cc", + "lib/serialization_util.h", "lib/string_serialization.h", + "lib/string_traits_string16.cc", "lib/sync_handle_registry.cc", "lib/sync_handle_registry.h", "lib/sync_handle_watcher.cc", @@ -84,24 +91,27 @@ source_set("bindings") { "lib/validation_util.cc", "lib/validation_util.h", "lib/value_traits.h", - - # Include the .h but not the .cc file. The .h file is used by - # serialization_forward.h. - "lib/wtf_string_serialization.h", "map.h", "message.h", "message_filter.h", + "native_struct.h", "no_interface.h", + "scoped_interface_endpoint_handle.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_binding.h", "struct_ptr.h", - "struct_traits.h", "type_converter.h", ] public_deps = [ ":callback", + ":struct_traits", "//base", "//ipc:param_traits", "//mojo/public/cpp/system", @@ -128,12 +138,19 @@ source_set("callback") { ] } +source_set("struct_traits") { + sources = [ + "struct_traits.h", + ] +} + source_set("wtf_support") { sources = [ - "lib/wtf_array_serialization.h", + "array_traits_wtf.h", + "array_traits_wtf_vector.h", + "lib/string_traits_wtf.cc", "lib/wtf_serialization.h", - "lib/wtf_string_serialization.cc", - "lib/wtf_string_serialization.h", + "string_traits_wtf.h", "wtf_array.h", ] diff --git a/chromium/mojo/public/cpp/bindings/array.h b/chromium/mojo/public/cpp/bindings/array.h index e9bd6838412..d94feb0768c 100644 --- a/chromium/mojo/public/cpp/bindings/array.h +++ b/chromium/mojo/public/cpp/bindings/array.h @@ -30,10 +30,10 @@ class Array { public: using ConstRefType = typename std::vector<T>::const_reference; using RefType = typename std::vector<T>::reference; - using ElementType = T; - using Data_ = - internal::Array_Data<typename internal::WrapperTraits<T>::DataType>; + using Element = T; + using Data_ = internal::Array_Data< + typename internal::GetDataTypeAsArrayElement<T>::Data>; using iterator = typename std::vector<T>::iterator; using const_iterator = typename std::vector<T>::const_iterator; diff --git a/chromium/mojo/public/cpp/bindings/array_traits.h b/chromium/mojo/public/cpp/bindings/array_traits.h new file mode 100644 index 00000000000..c9512fbfd51 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/array_traits.h @@ -0,0 +1,41 @@ +// 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_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_H_ + +namespace mojo { + +// This must be specialized for any type |T| to be serialized/deserialized as +// a mojom array. +// +// Usually you would like to do a partial specialization for an array/vector +// template. Imagine you want to specialize it for CustomArray<>, you need to +// implement: +// +// template <typename T> +// struct ArrayTraits<CustomArray<T>> { +// using Element = T; +// +// // These two methods are optional. Please see comments in struct_traits.h +// static bool IsNull(const CustomArray<T>& input); +// static void SetToNull(CustomArray<T>* output); +// +// static size_t GetSize(const CustomArray<T>& input); +// +// static T* GetData(CustomArray<T>& input); +// static const T* GetData(const CustomArray<T>& input); +// +// static T& GetAt(CustomArray<T>& input, size_t index); +// static const T& GetAt(const CustomArray<T>& input, size_t index); +// +// static void Resize(CustomArray<T>& input, size_t size); +// }; +// +template <typename T> +struct ArrayTraits; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_H_ diff --git a/chromium/mojo/public/cpp/bindings/array_traits_standard.h b/chromium/mojo/public/cpp/bindings/array_traits_standard.h new file mode 100644 index 00000000000..7ee4bd2661a --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/array_traits_standard.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_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 void Resize(Array<T>& input, size_t size) { input.resize(size); } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STANDARD_H_ diff --git a/chromium/mojo/public/cpp/bindings/array_traits_stl.h b/chromium/mojo/public/cpp/bindings/array_traits_stl.h new file mode 100644 index 00000000000..f78ae2f84cb --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/array_traits_stl.h @@ -0,0 +1,50 @@ +// 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_STL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STL_H_ + +#include <vector> + +#include "mojo/public/cpp/bindings/array_traits.h" + +namespace mojo { + +template <typename T> +struct ArrayTraits<std::vector<T>> { + using Element = T; + + static bool IsNull(const std::vector<T>& input) { + // std::vector<> is always converted to non-null mojom array. + return false; + } + + static void SetToNull(std::vector<T>* output) { + // std::vector<> doesn't support null state. Set it to empty instead. + output->clear(); + } + + static size_t GetSize(const std::vector<T>& input) { return input.size(); } + + static T* GetData(std::vector<T>& input) { return input.data(); } + + static const T* GetData(const std::vector<T>& input) { return input.data(); } + + static typename std::vector<T>::reference GetAt(std::vector<T>& input, + size_t index) { + return input[index]; + } + + static typename std::vector<T>::const_reference GetAt( + const std::vector<T>& input, + size_t index) { + return input[index]; + } + + static void Resize(std::vector<T>& input, size_t size) { input.resize(size); } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STL_H_ diff --git a/chromium/mojo/public/cpp/bindings/array_traits_wtf.h b/chromium/mojo/public/cpp/bindings/array_traits_wtf.h new file mode 100644 index 00000000000..71f1da1116a --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/array_traits_wtf.h @@ -0,0 +1,37 @@ +// 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 void Resize(WTFArray<U>& input, size_t size) { input.resize(size); } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_WTF_H_ diff --git a/chromium/mojo/public/cpp/bindings/array_traits_wtf_vector.h b/chromium/mojo/public/cpp/bindings/array_traits_wtf_vector.h new file mode 100644 index 00000000000..9b3755ad4f1 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/array_traits_wtf_vector.h @@ -0,0 +1,44 @@ +// 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_VECTOR_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_WTF_VECTOR_H_ + +#include "mojo/public/cpp/bindings/array_traits.h" +#include "third_party/WebKit/Source/wtf/Vector.h" + +namespace mojo { + +template <typename U> +struct ArrayTraits<WTF::Vector<U>> { + using Element = U; + + static bool IsNull(const WTF::Vector<U>& input) { + // WTF::Vector<> is always converted to non-null mojom array. + return false; + } + + static void SetToNull(WTF::Vector<U>* output) { + // WTF::Vector<> doesn't support null state. Set it to empty instead. + output->clear(); + } + + static size_t GetSize(const WTF::Vector<U>& input) { return input.size(); } + + static U* GetData(WTF::Vector<U>& input) { return input.data(); } + + static const U* GetData(const WTF::Vector<U>& input) { return input.data(); } + + static U& GetAt(WTF::Vector<U>& input, size_t index) { return input[index]; } + + static const U& GetAt(const WTF::Vector<U>& input, size_t index) { + return input[index]; + } + + static void Resize(WTF::Vector<U>& input, size_t size) { input.resize(size); } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_WTF_VECTOR_H_ diff --git a/chromium/mojo/public/cpp/bindings/associated_binding.h b/chromium/mojo/public/cpp/bindings/associated_binding.h index a7263635fef..2d4e3392230 100644 --- a/chromium/mojo/public/cpp/bindings/associated_binding.h +++ b/chromium/mojo/public/cpp/bindings/associated_binding.h @@ -5,21 +5,33 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_BINDING_H_ #define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_BINDING_H_ +#include <memory> #include <utility> #include "base/macros.h" -#include "base/memory/scoped_ptr.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_group.h" #include "mojo/public/cpp/bindings/associated_interface_request.h" #include "mojo/public/cpp/bindings/callback.h" #include "mojo/public/cpp/bindings/lib/interface_endpoint_client.h" #include "mojo/public/cpp/bindings/lib/multiplex_router.h" -#include "mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h" +#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" namespace mojo { // Represents the implementation side of an associated interface. It is similar // to Binding, except that it doesn't own a message pipe handle. +// +// When you bind this class to a request, optionally you can specify a +// base::SingleThreadTaskRunner. This task runner must belong to the same +// thread. It will be used to dispatch incoming method calls and connection +// error notification. It is useful when you attach multiple task runners to a +// 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> class AssociatedBinding { public: @@ -37,17 +49,21 @@ class AssociatedBinding { // pointer. |impl| must outlive this object. AssociatedBinding(Interface* impl, AssociatedInterfacePtrInfo<Interface>* ptr_info, - AssociatedGroup* associated_group) + AssociatedGroup* associated_group, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) : AssociatedBinding(impl) { - Bind(ptr_info, associated_group); + Bind(ptr_info, associated_group, std::move(runner)); } // Constructs a completed associated binding of |impl|. |impl| must outlive // the binding. AssociatedBinding(Interface* impl, - AssociatedInterfaceRequest<Interface> request) + AssociatedInterfaceRequest<Interface> request, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) : AssociatedBinding(impl) { - Bind(std::move(request)); + Bind(std::move(request), std::move(runner)); } ~AssociatedBinding() {} @@ -57,17 +73,20 @@ class AssociatedBinding { // message pipe endpoint referred to by |associated_group| to setup the // corresponding asssociated interface pointer. void Bind(AssociatedInterfacePtrInfo<Interface>* ptr_info, - AssociatedGroup* associated_group) { + AssociatedGroup* associated_group, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) { AssociatedInterfaceRequest<Interface> request; associated_group->CreateAssociatedInterface(AssociatedGroup::WILL_PASS_PTR, ptr_info, &request); - Bind(std::move(request)); + Bind(std::move(request), std::move(runner)); } // Sets up this object as the implementation side of an associated interface. - void Bind(AssociatedInterfaceRequest<Interface> request) { - internal::ScopedInterfaceEndpointHandle handle = - internal::AssociatedInterfaceRequestHelper::PassHandle(&request); + void Bind(AssociatedInterfaceRequest<Interface> request, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) { + ScopedInterfaceEndpointHandle handle = request.PassHandle(); DCHECK(handle.is_local()) << "The AssociatedInterfaceRequest is supposed to be used at the " @@ -80,8 +99,8 @@ class AssociatedBinding { endpoint_client_.reset(new internal::InterfaceEndpointClient( std::move(handle), &stub_, - make_scoped_ptr(new typename Interface::RequestValidator_()), - Interface::HasSyncMethods_)); + base::WrapUnique(new typename Interface::RequestValidator_()), + Interface::HasSyncMethods_, std::move(runner))); endpoint_client_->set_connection_error_handler( [this]() { connection_error_handler_.Run(); }); @@ -103,8 +122,7 @@ class AssociatedBinding { DCHECK(endpoint_client_); AssociatedInterfaceRequest<Interface> request; - internal::AssociatedInterfaceRequestHelper::SetHandle( - &request, endpoint_client_->PassHandle()); + request.Bind(endpoint_client_->PassHandle()); endpoint_client_.reset(); connection_error_handler_.reset(); @@ -135,7 +153,7 @@ class AssociatedBinding { } private: - scoped_ptr<internal::InterfaceEndpointClient> endpoint_client_; + std::unique_ptr<internal::InterfaceEndpointClient> endpoint_client_; typename Interface::Stub_ stub_; Interface* impl_; diff --git a/chromium/mojo/public/cpp/bindings/associated_group.h b/chromium/mojo/public/cpp/bindings/associated_group.h index ea3b5a16265..5f7a39632a4 100644 --- a/chromium/mojo/public/cpp/bindings/associated_group.h +++ b/chromium/mojo/public/cpp/bindings/associated_group.h @@ -10,7 +10,7 @@ #include "base/memory/ref_counted.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/lib/scoped_interface_endpoint_handle.h" +#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" namespace mojo { @@ -50,8 +50,8 @@ class AssociatedGroup { AssociatedInterfaceConfig config, AssociatedInterfacePtrInfo<T>* ptr_info, AssociatedInterfaceRequest<T>* request) { - internal::ScopedInterfaceEndpointHandle local; - internal::ScopedInterfaceEndpointHandle remote; + ScopedInterfaceEndpointHandle local; + ScopedInterfaceEndpointHandle remote; CreateEndpointHandlePair(&local, &remote); if (!local.is_valid() || !remote.is_valid()) { @@ -61,21 +61,19 @@ class AssociatedGroup { } if (config == WILL_PASS_PTR) { - internal::AssociatedInterfacePtrInfoHelper::SetHandle(ptr_info, - std::move(remote)); + 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_); - internal::AssociatedInterfaceRequestHelper::SetHandle(request, - std::move(local)); + request->Bind(std::move(local)); } else { - internal::AssociatedInterfacePtrInfoHelper::SetHandle(ptr_info, - std::move(local)); + 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); - internal::AssociatedInterfaceRequestHelper::SetHandle(request, - std::move(remote)); + request->Bind(std::move(remote)); } } @@ -83,8 +81,8 @@ class AssociatedGroup { friend class internal::MultiplexRouter; void CreateEndpointHandlePair( - internal::ScopedInterfaceEndpointHandle* local_endpoint, - internal::ScopedInterfaceEndpointHandle* remote_endpoint); + ScopedInterfaceEndpointHandle* local_endpoint, + ScopedInterfaceEndpointHandle* remote_endpoint); scoped_refptr<internal::MultiplexRouter> router_; }; diff --git a/chromium/mojo/public/cpp/bindings/associated_interface_ptr.h b/chromium/mojo/public/cpp/bindings/associated_interface_ptr.h index 48caad654e3..c4435ee599b 100644 --- a/chromium/mojo/public/cpp/bindings/associated_interface_ptr.h +++ b/chromium/mojo/public/cpp/bindings/associated_interface_ptr.h @@ -10,6 +10,9 @@ #include "base/logging.h" #include "base/macros.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_group.h" #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h" #include "mojo/public/cpp/bindings/associated_interface_request.h" @@ -52,20 +55,26 @@ class AssociatedInterfacePtr { // Calling with an invalid |info| has the same effect as reset(). In this // case, the AssociatedInterfacePtr is not considered as bound. // + // |runner| must belong to the same thread. It will be used to dispatch all + // callbacks and connection error notification. It is useful when you attach + // multiple task runners to a single thread for the purposes of task + // scheduling. + // // NOTE: Please see the comments of // AssociatedGroup.CreateAssociatedInterface() about when you can use this // object to make calls. - void Bind(AssociatedInterfacePtrInfo<Interface> info) { + void Bind(AssociatedInterfacePtrInfo<Interface> info, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) { reset(); - bool is_local = - internal::AssociatedInterfacePtrInfoHelper::GetHandle(&info).is_local(); + 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)); + internal_state_.Bind(std::move(info), std::move(runner)); } bool is_bound() const { return internal_state_.is_bound(); } @@ -181,13 +190,15 @@ class AssociatedInterfacePtr { template <typename Interface> AssociatedInterfaceRequest<Interface> GetProxy( AssociatedInterfacePtr<Interface>* ptr, - AssociatedGroup* group) { + AssociatedGroup* group, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) { AssociatedInterfaceRequest<Interface> request; AssociatedInterfacePtrInfo<Interface> ptr_info; group->CreateAssociatedInterface(AssociatedGroup::WILL_PASS_REQUEST, &ptr_info, &request); - ptr->Bind(std::move(ptr_info)); + ptr->Bind(std::move(ptr_info), std::move(runner)); return request; } diff --git a/chromium/mojo/public/cpp/bindings/associated_interface_ptr_info.h b/chromium/mojo/public/cpp/bindings/associated_interface_ptr_info.h index 8340eeade62..a393bcea1d7 100644 --- a/chromium/mojo/public/cpp/bindings/associated_interface_ptr_info.h +++ b/chromium/mojo/public/cpp/bindings/associated_interface_ptr_info.h @@ -9,14 +9,10 @@ #include <utility> #include "base/macros.h" -#include "mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h" +#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" namespace mojo { -namespace internal { -class AssociatedInterfacePtrInfoHelper; -} - // AssociatedInterfacePtrInfo stores necessary information to construct an // associated interface pointer. It is similar to InterfacePtrInfo except that // it doesn't own a message pipe handle. @@ -32,6 +28,10 @@ class AssociatedInterfacePtrInfo { other.version_ = 0u; } + AssociatedInterfacePtrInfo(ScopedInterfaceEndpointHandle handle, + uint32_t version) + : handle_(std::move(handle)), version_(version) {} + ~AssociatedInterfacePtrInfo() {} AssociatedInterfacePtrInfo& operator=(AssociatedInterfacePtrInfo&& other) { @@ -46,43 +46,22 @@ class AssociatedInterfacePtrInfo { bool is_valid() const { return handle_.is_valid(); } + ScopedInterfaceEndpointHandle PassHandle() { + return std::move(handle_); + } + const ScopedInterfaceEndpointHandle& handle() const { return handle_; } + void set_handle(ScopedInterfaceEndpointHandle handle) { + handle_ = std::move(handle); + } + uint32_t version() const { return version_; } void set_version(uint32_t version) { version_ = version; } private: - friend class internal::AssociatedInterfacePtrInfoHelper; - - internal::ScopedInterfaceEndpointHandle handle_; + ScopedInterfaceEndpointHandle handle_; uint32_t version_; }; -namespace internal { - -// With this helper, AssociatedInterfacePtrInfo doesn't have to expose any -// operations related to ScopedInterfaceEndpointHandle, which is an internal -// class. -class AssociatedInterfacePtrInfoHelper { - public: - template <typename Interface> - static ScopedInterfaceEndpointHandle PassHandle( - AssociatedInterfacePtrInfo<Interface>* info) { - return std::move(info->handle_); - } - - template <typename Interface> - static const ScopedInterfaceEndpointHandle& GetHandle( - AssociatedInterfacePtrInfo<Interface>* info) { - return info->handle_; - } - - template <typename Interface> - static void SetHandle(AssociatedInterfacePtrInfo<Interface>* info, - ScopedInterfaceEndpointHandle handle) { - info->handle_ = std::move(handle); - } -}; - -} // namespace internal } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_INFO_H_ diff --git a/chromium/mojo/public/cpp/bindings/associated_interface_request.h b/chromium/mojo/public/cpp/bindings/associated_interface_request.h index 36cbe3eb48c..a7a7f662166 100644 --- a/chromium/mojo/public/cpp/bindings/associated_interface_request.h +++ b/chromium/mojo/public/cpp/bindings/associated_interface_request.h @@ -8,14 +8,10 @@ #include <utility> #include "base/macros.h" -#include "mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h" +#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" namespace mojo { -namespace internal { -class AssociatedInterfaceRequestHelper; -} - // AssociatedInterfaceRequest represents an associated interface request. It is // similar to InterfaceRequest except that it doesn't own a message pipe handle. template <typename Interface> @@ -51,39 +47,30 @@ class AssociatedInterfaceRequest { // handle. bool is_pending() const { return handle_.is_valid(); } - private: - friend class internal::AssociatedInterfaceRequestHelper; - - internal::ScopedInterfaceEndpointHandle handle_; -}; - -namespace internal { - -// With this helper, AssociatedInterfaceRequest doesn't have to expose any -// operations related to ScopedInterfaceEndpointHandle, which is an internal -// class. -class AssociatedInterfaceRequestHelper { - public: - template <typename Interface> - static ScopedInterfaceEndpointHandle PassHandle( - AssociatedInterfaceRequest<Interface>* request) { - return std::move(request->handle_); + void Bind(ScopedInterfaceEndpointHandle handle) { + handle_ = std::move(handle); } - template <typename Interface> - static const ScopedInterfaceEndpointHandle& GetHandle( - AssociatedInterfaceRequest<Interface>* request) { - return request->handle_; + ScopedInterfaceEndpointHandle PassHandle() { + return std::move(handle_); } - template <typename Interface> - static void SetHandle(AssociatedInterfaceRequest<Interface>* request, - ScopedInterfaceEndpointHandle handle) { - request->handle_ = std::move(handle); - } + const ScopedInterfaceEndpointHandle& handle() const { return handle_; } + + private: + ScopedInterfaceEndpointHandle handle_; }; -} // namespace internal +// Makes an AssociatedInterfaceRequest bound to the specified associated +// endpoint. +template <typename Interface> +AssociatedInterfaceRequest<Interface> MakeAssociatedRequest( + ScopedInterfaceEndpointHandle handle) { + AssociatedInterfaceRequest<Interface> request; + request.Bind(std::move(handle)); + return request; +} + } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_REQUEST_H_ diff --git a/chromium/mojo/public/cpp/bindings/binding.h b/chromium/mojo/public/cpp/bindings/binding.h index 68dd32239c4..84b4f90d62d 100644 --- a/chromium/mojo/public/cpp/bindings/binding.h +++ b/chromium/mojo/public/cpp/bindings/binding.h @@ -8,6 +8,9 @@ #include <utility> #include "base/macros.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/callback.h" #include "mojo/public/cpp/bindings/interface_ptr.h" #include "mojo/public/cpp/bindings/interface_ptr_info.h" @@ -52,6 +55,14 @@ class AssociatedGroup; // class must be from the thread that bound it. The interface implementation's // methods will be called from the thread that bound this. If a Binding is not // bound to a message pipe, it may be bound or destroyed on any thread. +// +// When you bind this class to a message pipe, optionally you can specify a +// base::SingleThreadTaskRunner. This task runner must belong to the same +// thread. It will be used to dispatch incoming method calls and connection +// error notification. It is useful when you attach multiple task runners to a +// 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> class Binding { public: @@ -62,8 +73,12 @@ class Binding { // Constructs a completed binding of message pipe |handle| to implementation // |impl|. Does not take ownership of |impl|, which must outlive the binding. - Binding(Interface* impl, ScopedMessagePipeHandle handle) : Binding(impl) { - Bind(std::move(handle)); + Binding(Interface* impl, + ScopedMessagePipeHandle handle, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) + : Binding(impl) { + Bind(std::move(handle), std::move(runner)); } // Constructs a completed binding of |impl| to a new message pipe, passing the @@ -71,16 +86,23 @@ 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(Interface* impl, InterfacePtr<Interface>* ptr) : Binding(impl) { - Bind(ptr); + Binding(Interface* impl, + InterfacePtr<Interface>* ptr, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) + : 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(Interface* impl, InterfaceRequest<Interface> request) + Binding(Interface* impl, + InterfaceRequest<Interface> request, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) : Binding(impl) { - Bind(request.PassMessagePipe()); + Bind(request.PassMessagePipe(), std::move(runner)); } // Tears down the binding, closing the message pipe and leaving the interface @@ -89,17 +111,21 @@ class Binding { // Returns an InterfacePtr bound to one end of a pipe whose other end is // bound to |this|. - InterfacePtr<Interface> CreateInterfacePtrAndBind() { + InterfacePtr<Interface> CreateInterfacePtrAndBind( + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) { InterfacePtr<Interface> interface_ptr; - Bind(&interface_ptr); + Bind(&interface_ptr, std::move(runner)); return interface_ptr; } // Completes a binding that was constructed with only an interface // implementation. Takes ownership of |handle| and binds it to the previously // specified implementation. - void Bind(ScopedMessagePipeHandle handle) { - internal_state_.Bind(std::move(handle)); + void Bind(ScopedMessagePipeHandle handle, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) { + internal_state_.Bind(std::move(handle), std::move(runner)); } // Completes a binding that was constructed with only an interface @@ -107,18 +133,23 @@ class Binding { // previously specified implementation, and passing the other to |ptr|, which // takes ownership of it. The caller is expected to pass |ptr| on to the // eventual client of the service. Does not take ownership of |ptr|. - void Bind(InterfacePtr<Interface>* ptr) { + void Bind(InterfacePtr<Interface>* ptr, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) { MessagePipe pipe; ptr->Bind(InterfacePtrInfo<Interface>(std::move(pipe.handle0), - Interface::Version_)); - Bind(std::move(pipe.handle1)); + Interface::Version_), + runner); + Bind(std::move(pipe.handle1), std::move(runner)); } // Completes a binding that was constructed with only an interface // implementation by removing the message pipe endpoint from |request| and // binding it to the previously specified implementation. - void Bind(InterfaceRequest<Interface> request) { - Bind(request.PassMessagePipe()); + void Bind(InterfaceRequest<Interface> request, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) { + Bind(request.PassMessagePipe(), std::move(runner)); } // Whether there are any associated interfaces running on the pipe currently. diff --git a/chromium/mojo/public/cpp/bindings/callback.h b/chromium/mojo/public/cpp/bindings/callback.h index 91f37d03fef..c5e328927f4 100644 --- a/chromium/mojo/public/cpp/bindings/callback.h +++ b/chromium/mojo/public/cpp/bindings/callback.h @@ -5,11 +5,11 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ #define MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ +#include <memory> #include <type_traits> #include <utility> #include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" #include "mojo/public/cpp/bindings/lib/callback_internal.h" #include "mojo/public/cpp/bindings/lib/template_util.h" @@ -143,7 +143,7 @@ class Callback<void(Args...)> { struct RunnableHolder : public base::RefCountedThreadSafe<RunnableHolder> { explicit RunnableHolder(Runnable* runnable) : runnable(runnable) {} - scoped_ptr<Runnable> runnable; + std::unique_ptr<Runnable> runnable; private: friend class base::RefCountedThreadSafe<RunnableHolder>; diff --git a/chromium/mojo/public/cpp/bindings/interface_ptr.h b/chromium/mojo/public/cpp/bindings/interface_ptr.h index 9b005eee815..e427dc4668d 100644 --- a/chromium/mojo/public/cpp/bindings/interface_ptr.h +++ b/chromium/mojo/public/cpp/bindings/interface_ptr.h @@ -10,6 +10,9 @@ #include "base/logging.h" #include "base/macros.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/callback.h" #include "mojo/public/cpp/bindings/interface_ptr_info.h" #include "mojo/public/cpp/bindings/lib/interface_ptr_state.h" @@ -68,10 +71,17 @@ class InterfacePtr { // Calling with an invalid |info| (containing an invalid message pipe handle) // has the same effect as reset(). In this case, the InterfacePtr is not // considered as bound. - void Bind(InterfacePtrInfo<Interface> info) { + // + // |runner| must belong to the same thread. It will be used to dispatch all + // callbacks and connection error notification. It is useful when you attach + // multiple task runners to a single thread for the purposes of task + // scheduling. + void Bind(InterfacePtrInfo<Interface> info, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) { reset(); if (info.is_valid()) - internal_state_.Bind(std::move(info)); + internal_state_.Bind(std::move(info), std::move(runner)); } // Returns whether or not this InterfacePtr is bound to a message pipe. @@ -208,10 +218,13 @@ class InterfacePtr { // If |info| is valid (containing a valid message pipe handle), returns an // InterfacePtr bound to it. Otherwise, returns an unbound InterfacePtr. template <typename Interface> -InterfacePtr<Interface> MakeProxy(InterfacePtrInfo<Interface> info) { +InterfacePtr<Interface> MakeProxy( + InterfacePtrInfo<Interface> info, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) { InterfacePtr<Interface> ptr; if (info.is_valid()) - ptr.Bind(std::move(info)); + ptr.Bind(std::move(info), std::move(runner)); return std::move(ptr); } diff --git a/chromium/mojo/public/cpp/bindings/interface_request.h b/chromium/mojo/public/cpp/bindings/interface_request.h index 807cd5dc94c..3d6b27c0a0e 100644 --- a/chromium/mojo/public/cpp/bindings/interface_request.h +++ b/chromium/mojo/public/cpp/bindings/interface_request.h @@ -7,6 +7,8 @@ #include <utility> +#include "base/single_thread_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" #include "mojo/public/cpp/bindings/interface_ptr.h" namespace mojo { @@ -111,9 +113,13 @@ InterfaceRequest<Interface> MakeRequest(ScopedMessagePipeHandle handle) { // CreateSource(std::move(source_request)); // Create implementation locally. // template <typename Interface> -InterfaceRequest<Interface> GetProxy(InterfacePtr<Interface>* ptr) { +InterfaceRequest<Interface> GetProxy( + InterfacePtr<Interface>* ptr, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()) { MessagePipe pipe; - ptr->Bind(InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u)); + ptr->Bind(InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u), + std::move(runner)); return MakeRequest<Interface>(std::move(pipe.handle1)); } diff --git a/chromium/mojo/public/cpp/bindings/lib/TODO b/chromium/mojo/public/cpp/bindings/lib/TODO deleted file mode 100644 index ea4ce81a2f4..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/TODO +++ /dev/null @@ -1,4 +0,0 @@ -TODOs: - - Optimize Buffer classes? - - Add compile-time asserts to verify object packing and padding. - - Investigate making arrays of objects not be arrays of pointers. diff --git a/chromium/mojo/public/cpp/bindings/lib/array_internal.cc b/chromium/mojo/public/cpp/bindings/lib/array_internal.cc index 542ab3d71e9..dd24eac4702 100644 --- a/chromium/mojo/public/cpp/bindings/lib/array_internal.cc +++ b/chromium/mojo/public/cpp/bindings/lib/array_internal.cc @@ -55,23 +55,5 @@ ArrayDataTraits<bool>::BitRef::operator bool() const { return (*storage_ & mask_) != 0; } -// static -void ArraySerializationHelper<Handle, true, false>::EncodePointersAndHandles( - const ArrayHeader* header, - ElementType* elements, - std::vector<Handle>* handles) { - for (uint32_t i = 0; i < header->num_elements; ++i) - EncodeHandle(&elements[i], handles); -} - -// static -void ArraySerializationHelper<Handle, true, false>::DecodePointersAndHandles( - const ArrayHeader* header, - ElementType* elements, - std::vector<Handle>* handles) { - for (uint32_t i = 0; i < header->num_elements; ++i) - DecodeHandle(&elements[i], handles); -} - } // namespace internal } // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/array_internal.h b/chromium/mojo/public/cpp/bindings/lib/array_internal.h index d01484e2a1c..00ae00b7011 100644 --- a/chromium/mojo/public/cpp/bindings/lib/array_internal.h +++ b/chromium/mojo/public/cpp/bindings/lib/array_internal.h @@ -14,10 +14,10 @@ #include "base/logging.h" #include "mojo/public/c/system/macros.h" #include "mojo/public/cpp/bindings/lib/bindings_internal.h" -#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" #include "mojo/public/cpp/bindings/lib/bounds_checker.h" #include "mojo/public/cpp/bindings/lib/buffer.h" #include "mojo/public/cpp/bindings/lib/map_data_internal.h" +#include "mojo/public/cpp/bindings/lib/serialization_util.h" #include "mojo/public/cpp/bindings/lib/template_util.h" #include "mojo/public/cpp/bindings/lib/validate_params.h" #include "mojo/public/cpp/bindings/lib/validation_errors.h" @@ -60,7 +60,7 @@ struct ArrayDataTraits { template <typename P> struct ArrayDataTraits<P*> { - typedef StructPointer<P> StorageType; + typedef Pointer<P> StorageType; typedef P*& Ref; typedef P* const& ConstRef; @@ -79,27 +79,6 @@ struct ArrayDataTraits<P*> { } }; -template <typename T> -struct ArrayDataTraits<Array_Data<T>*> { - typedef ArrayPointer<T> StorageType; - typedef Array_Data<T>*& Ref; - typedef Array_Data<T>* const& ConstRef; - - static const uint32_t kMaxNumElements = - (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType); - - static uint32_t GetStorageSize(uint32_t num_elements) { - DCHECK(num_elements <= kMaxNumElements); - return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements; - } - static Ref ToRef(StorageType* storage, size_t offset) { - return storage[offset].ptr; - } - static ConstRef ToConstRef(const StorageType* storage, size_t offset) { - return storage[offset].ptr; - } -}; - // Specialization of Arrays for bools, optimized for space. It has the // following differences from a generalized Array: // * Each element takes up a single bit of memory. @@ -149,20 +128,18 @@ struct ArrayDataTraits<bool> { // of unions are inlined so they are not pointers, but comparing with primitives // they require more work for serialization/validation. -template <typename T, bool is_handle, bool is_union> +template <typename T, bool is_union> struct ArraySerializationHelper; template <typename T> -struct ArraySerializationHelper<T, false, false> { +struct ArraySerializationHelper<T, false> { typedef typename ArrayDataTraits<T>::StorageType ElementType; - static void EncodePointersAndHandles(const ArrayHeader* header, - ElementType* elements, - std::vector<Handle>* handles) {} + static void EncodePointers(const ArrayHeader* header, + ElementType* elements) {} - static void DecodePointersAndHandles(const ArrayHeader* header, - ElementType* elements, - std::vector<Handle>* handles) {} + static void DecodePointers(const ArrayHeader* header, + ElementType* elements) {} static bool ValidateElements(const ArrayHeader* header, const ElementType* elements, @@ -173,43 +150,27 @@ struct ArraySerializationHelper<T, false, false> { DCHECK(!validate_params->element_validate_params) << "Primitive type should not have array validate params"; - return ValidateCaller<ElementType>::Run(header, elements); - } - - private: - template <typename U, bool is_enum = IsEnumDataType<U>::value> - struct ValidateCaller {}; - - template <typename U> - struct ValidateCaller<U, false> { - static bool Run(const ArrayHeader* header, const ElementType* elements) { + if (!validate_params->validate_enum_func) return true; - } - }; - template <typename U> - struct ValidateCaller<U, true> { - static bool Run(const ArrayHeader* header, const ElementType* elements) { - for (uint32_t i = 0; i < header->num_elements; ++i) { - if (!ValidateEnum(elements[i])) - return false; - } - return true; + // Enum validation. + for (uint32_t i = 0; i < header->num_elements; ++i) { + if (!validate_params->validate_enum_func(elements[i])) + return false; } - }; + return true; + } }; template <> -struct ArraySerializationHelper<Handle, true, false> { - typedef ArrayDataTraits<Handle>::StorageType ElementType; +struct ArraySerializationHelper<Handle_Data, false> { + typedef ArrayDataTraits<Handle_Data>::StorageType ElementType; - static void EncodePointersAndHandles(const ArrayHeader* header, - ElementType* elements, - std::vector<Handle>* handles); + static void EncodePointers(const ArrayHeader* header, + ElementType* elements) {} - static void DecodePointersAndHandles(const ArrayHeader* header, - ElementType* elements, - std::vector<Handle>* handles); + static void DecodePointers(const ArrayHeader* header, + ElementType* elements) {} static bool ValidateElements(const ArrayHeader* header, const ElementType* elements, @@ -219,8 +180,7 @@ struct ArraySerializationHelper<Handle, true, false> { << "Handle type should not have array validate params"; for (uint32_t i = 0; i < header->num_elements; ++i) { - if (!validate_params->element_is_nullable && - elements[i].value() == kEncodedInvalidHandleValue) { + if (!validate_params->element_is_nullable && !elements[i].is_valid()) { ReportValidationError( VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, MakeMessageWithArrayIndex( @@ -238,49 +198,18 @@ struct ArraySerializationHelper<Handle, true, false> { } }; -template <typename H> -struct ArraySerializationHelper<H, true, false> { - typedef typename ArrayDataTraits<H>::StorageType ElementType; - - static void EncodePointersAndHandles(const ArrayHeader* header, - ElementType* elements, - std::vector<Handle>* handles) { - ArraySerializationHelper<Handle, true, false>::EncodePointersAndHandles( - header, elements, handles); - } - - static void DecodePointersAndHandles(const ArrayHeader* header, - ElementType* elements, - std::vector<Handle>* handles) { - ArraySerializationHelper<Handle, true, false>::DecodePointersAndHandles( - header, elements, handles); - } - - static bool ValidateElements(const ArrayHeader* header, - const ElementType* elements, - BoundsChecker* bounds_checker, - const ArrayValidateParams* validate_params) { - return ArraySerializationHelper<Handle, true, false>::ValidateElements( - header, elements, bounds_checker, validate_params); - } -}; - template <typename P> -struct ArraySerializationHelper<P*, false, false> { +struct ArraySerializationHelper<P*, false> { typedef typename ArrayDataTraits<P*>::StorageType ElementType; - static void EncodePointersAndHandles(const ArrayHeader* header, - ElementType* elements, - std::vector<Handle>* handles) { + static void EncodePointers(const ArrayHeader* header, ElementType* elements) { for (uint32_t i = 0; i < header->num_elements; ++i) - Encode(&elements[i], handles); + Encode(&elements[i]); } - static void DecodePointersAndHandles(const ArrayHeader* header, - ElementType* elements, - std::vector<Handle>* handles) { + static void DecodePointers(const ArrayHeader* header, ElementType* elements) { for (uint32_t i = 0; i < header->num_elements; ++i) - Decode(&elements[i], handles); + Decode(&elements[i]); } static bool ValidateElements(const ArrayHeader* header, @@ -343,21 +272,17 @@ struct ArraySerializationHelper<P*, false, false> { }; template <typename U> -struct ArraySerializationHelper<U, false, true> { +struct ArraySerializationHelper<U, true> { typedef typename ArrayDataTraits<U>::StorageType ElementType; - static void EncodePointersAndHandles(const ArrayHeader* header, - ElementType* elements, - std::vector<Handle>* handles) { + static void EncodePointers(const ArrayHeader* header, ElementType* elements) { for (uint32_t i = 0; i < header->num_elements; ++i) - elements[i].EncodePointersAndHandles(handles); + elements[i].EncodePointers(); } - static void DecodePointersAndHandles(const ArrayHeader* header, - ElementType* elements, - std::vector<Handle>* handles) { + static void DecodePointers(const ArrayHeader* header, ElementType* elements) { for (uint32_t i = 0; i < header->num_elements; ++i) - elements[i].DecodePointersAndHandles(handles); + elements[i].DecodePointers(); } static bool ValidateElements(const ArrayHeader* header, @@ -383,14 +308,12 @@ struct ArraySerializationHelper<U, false, true> { template <typename T> class Array_Data { public: - typedef ArrayDataTraits<T> Traits; - typedef typename Traits::StorageType StorageType; - typedef typename Traits::Ref Ref; - typedef typename Traits::ConstRef ConstRef; - typedef ArraySerializationHelper<T, - IsHandle<T>::value, - IsUnionDataType<T>::value> - Helper; + using Traits = ArrayDataTraits<T>; + using StorageType = typename Traits::StorageType; + using Ref = typename Traits::Ref; + using ConstRef = typename Traits::ConstRef; + using Helper = ArraySerializationHelper<T, IsUnionDataType<T>::value>; + using Element = T; // Returns null if |num_elements| or the corresponding storage size cannot be // stored in uint32_t. @@ -465,13 +388,8 @@ class Array_Data { reinterpret_cast<const char*>(this) + sizeof(*this)); } - void EncodePointersAndHandles(std::vector<Handle>* handles) { - Helper::EncodePointersAndHandles(&header_, storage(), handles); - } - - void DecodePointersAndHandles(std::vector<Handle>* handles) { - Helper::DecodePointersAndHandles(&header_, storage(), handles); - } + void EncodePointers() { Helper::EncodePointers(&header_, storage()); } + void DecodePointers() { Helper::DecodePointers(&header_, storage()); } private: Array_Data(uint32_t num_bytes, uint32_t num_elements) { diff --git a/chromium/mojo/public/cpp/bindings/lib/array_serialization.h b/chromium/mojo/public/cpp/bindings/lib/array_serialization.h index d5a59af2c19..3b4033b4fdf 100644 --- a/chromium/mojo/public/cpp/bindings/lib/array_serialization.h +++ b/chromium/mojo/public/cpp/bindings/lib/array_serialization.h @@ -6,38 +6,397 @@ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ #include <stddef.h> +#include <string.h> // For |memcpy()|. +#include <limits> +#include <type_traits> +#include <utility> +#include <vector> + +#include "base/logging.h" #include "mojo/public/cpp/bindings/array.h" -#include "mojo/public/cpp/bindings/lib/array_serialization_traits.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" + +namespace WTF { +class String; +} namespace mojo { +namespace internal { -template <typename E> -inline size_t GetSerializedSize_(const Array<E>& input, - internal::SerializationContext* context) { - return internal::ArraySerializationImpl<Array<E>>::GetSerializedSize(input, - context); -} +enum class ArraySerializerType { + BOOLEAN, + // Except boolean. + POD, + HANDLE, + // String, array, map and struct. + POINTER, + UNION +}; -template <typename E, typename F> -inline void SerializeArray_( - Array<E> input, - internal::Buffer* buf, - internal::Array_Data<F>** output, - const internal::ArrayValidateParams* validate_params, - internal::SerializationContext* context) { - return internal::ArraySerializationImpl<Array<E>>::template Serialize<F>( - std::move(input), buf, output, validate_params, context); -} +template <typename T> +struct GetArraySerializerType { + static const ArraySerializerType value = + IsUnionDataType<T>::value + ? ArraySerializerType::UNION + : (std::is_pointer<T>::value + ? ArraySerializerType::POINTER + : (IsHandle<T>::value ? ArraySerializerType::HANDLE + : (std::is_same<T, bool>::value + ? ArraySerializerType::BOOLEAN + : ArraySerializerType::POD))); +}; -template <typename E, typename F> -inline bool Deserialize_(internal::Array_Data<F>* input, - Array<E>* output, - internal::SerializationContext* context) { - return internal::ArraySerializationImpl<Array<E>>::template Deserialize<F>( - input, output, context); -} +template <typename MojomType, + typename MaybeConstUserType, + ArraySerializerType type = + GetArraySerializerType<typename MojomType::Data_::Element>::value> +struct ArraySerializer; + +// Handles serialization and deserialization of arrays of pod types. +template <typename MojomType, typename MaybeConstUserType> +struct ArraySerializer<MojomType, + MaybeConstUserType, + ArraySerializerType::POD> { + using UserType = typename std::remove_const<MaybeConstUserType>::type; + using Data = typename MojomType::Data_; + using DataElement = typename Data::Element; + using Element = typename MojomType::Element; + using Traits = ArrayTraits<UserType>; + + static_assert(sizeof(Element) == sizeof(DataElement), + "Incorrect array serializer"); + static_assert(std::is_same<Element, typename Traits::Element>::value, + "Incorrect array serializer"); + + static size_t GetSerializedSize(MaybeConstUserType& input, + SerializationContext* context) { + return sizeof(Data) + Align(Traits::GetSize(input) * sizeof(DataElement)); + } + + static void SerializeElements(MaybeConstUserType& input, + Buffer* buf, + Data* output, + const ArrayValidateParams* validate_params, + SerializationContext* context) { + DCHECK(!validate_params->element_is_nullable) + << "Primitive type should be non-nullable"; + DCHECK(!validate_params->element_validate_params) + << "Primitive type should not have array validate params"; + + if (Traits::GetSize(input)) { + memcpy(output->storage(), Traits::GetData(input), + Traits::GetSize(input) * sizeof(DataElement)); + } + } + + static bool DeserializeElements(Data* input, + UserType* output, + SerializationContext* context) { + Traits::Resize(*output, input->size()); + if (input->size()) { + memcpy(Traits::GetData(*output), input->storage(), + input->size() * sizeof(DataElement)); + } + return true; + } +}; + +// Serializes and deserializes arrays of bools. +template <typename MojomType, typename MaybeConstUserType> +struct ArraySerializer<MojomType, + MaybeConstUserType, + ArraySerializerType::BOOLEAN> { + using UserType = typename std::remove_const<MaybeConstUserType>::type; + using Traits = ArrayTraits<UserType>; + using Data = typename MojomType::Data_; + + static_assert(std::is_same<bool, typename UserType::Element>::value, + "Incorrect array serializer"); + + static size_t GetSerializedSize(MaybeConstUserType& input, + SerializationContext* context) { + return sizeof(Data) + Align((Traits::GetSize(input) + 7) / 8); + } + + static void SerializeElements(MaybeConstUserType& input, + Buffer* buf, + Data* output, + const ArrayValidateParams* validate_params, + SerializationContext* context) { + DCHECK(!validate_params->element_is_nullable) + << "Primitive type should be non-nullable"; + DCHECK(!validate_params->element_validate_params) + << "Primitive type should not have array validate params"; + + // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? + size_t size = Traits::GetSize(input); + for (size_t i = 0; i < size; ++i) + output->at(i) = Traits::GetAt(input, i); + } + static bool DeserializeElements(Data* input, + UserType* output, + SerializationContext* context) { + Traits::Resize(*output, input->size()); + // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? + for (size_t i = 0; i < input->size(); ++i) + Traits::GetAt(*output, i) = input->at(i); + return true; + } +}; + +// Serializes and deserializes arrays of handles. +template <typename MojomType, typename MaybeConstUserType> +struct ArraySerializer<MojomType, + MaybeConstUserType, + ArraySerializerType::HANDLE> { + using UserType = typename std::remove_const<MaybeConstUserType>::type; + using Data = typename MojomType::Data_; + 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(MaybeConstUserType& input, + SerializationContext* context) { + return sizeof(Data) + + Align(Traits::GetSize(input) * sizeof(typename Data::Element)); + } + + static void SerializeElements(MaybeConstUserType& input, + Buffer* buf, + Data* output, + const ArrayValidateParams* validate_params, + SerializationContext* context) { + DCHECK(!validate_params->element_validate_params) + << "Handle type should not have array validate params"; + + size_t size = Traits::GetSize(input); + for (size_t i = 0; i < size; ++i) { + // Transfer ownership of the handle. + output->at(i) = + context->handles.AddHandle(Traits::GetAt(input, i).release()); + MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( + !validate_params->element_is_nullable && !output->at(i).is_valid(), + VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, + MakeMessageWithArrayIndex( + "invalid handle in array expecting valid handles", size, i)); + } + } + static bool DeserializeElements(Data* input, + UserType* output, + SerializationContext* context) { + using HandleType = typename Element::RawHandleType; + Traits::Resize(*output, input->size()); + for (size_t i = 0; i < input->size(); ++i) { + Traits::GetAt(*output, i) = MakeScopedHandle( + HandleType(context->handles.TakeHandle(input->at(i)).value())); + } + return true; + } +}; + +// This template must only apply to pointer mojo entity (strings, structs, +// arrays and maps). +template <typename MojomType, typename MaybeConstUserType> +struct ArraySerializer<MojomType, + MaybeConstUserType, + ArraySerializerType::POINTER> { + using UserType = typename std::remove_const<MaybeConstUserType>::type; + using Data = typename MojomType::Data_; + using DataElement = typename Data::Element; + using Element = typename MojomType::Element; + using Traits = ArrayTraits<UserType>; + + static size_t GetSerializedSize(MaybeConstUserType& input, + SerializationContext* context) { + size_t element_count = Traits::GetSize(input); + size_t size = + sizeof(Data) + + element_count * + sizeof(Pointer<typename std::remove_pointer<DataElement>::type>); + for (size_t i = 0; i < element_count; ++i) + size += PrepareToSerialize<Element>(Traits::GetAt(input, i), context); + return size; + } + + static void SerializeElements(MaybeConstUserType& input, + Buffer* buf, + Data* output, + const ArrayValidateParams* validate_params, + SerializationContext* context) { + size_t size = Traits::GetSize(input); + for (size_t i = 0; i < size; ++i) { + DataElement element; + SerializeCaller<Element>::Run(Traits::GetAt(input, i), buf, &element, + validate_params->element_validate_params, + context); + output->at(i) = element; + MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( + !validate_params->element_is_nullable && !element, + VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, + MakeMessageWithArrayIndex("null in array expecting valid pointers", + size, i)); + } + } + static bool DeserializeElements(Data* input, + UserType* output, + SerializationContext* context) { + bool success = true; + Traits::Resize(*output, input->size()); + for (size_t i = 0; i < input->size(); ++i) { + // Note that we rely on complete deserialization taking place in order to + // transfer ownership of all encoded handles. Therefore we don't + // short-circuit on failure here. + if (!Deserialize<Element>(input->at(i), &Traits::GetAt(*output, i), + context)) { + success = false; + } + } + return success; + } + + private: + template <typename T, + bool is_array_or_map = IsSpecializationOf<Array, T>::value || + IsSpecializationOf<Map, T>::value> + struct SerializeCaller { + template <typename InputElementType> + static void Run(InputElementType&& input, + Buffer* buf, + DataElement* output, + const ArrayValidateParams* validate_params, + SerializationContext* context) { + Serialize<T>(std::forward<InputElementType>(input), buf, output, context); + } + }; + + template <typename T> + struct SerializeCaller<T, true> { + template <typename InputElementType> + static void Run(InputElementType&& input, + Buffer* buf, + DataElement* output, + const ArrayValidateParams* validate_params, + SerializationContext* context) { + Serialize<T>(std::forward<InputElementType>(input), buf, output, + validate_params, context); + } + }; +}; + +// Handles serialization and deserialization of arrays of unions. +template <typename MojomType, typename MaybeConstUserType> +struct ArraySerializer<MojomType, + MaybeConstUserType, + ArraySerializerType::UNION> { + using UserType = typename std::remove_const<MaybeConstUserType>::type; + using Data = typename MojomType::Data_; + 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(MaybeConstUserType& input, + SerializationContext* context) { + size_t element_count = Traits::GetSize(input); + size_t size = sizeof(Data); + 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. + size += + PrepareToSerialize<Element>(Traits::GetAt(input, i), false, context); + } + return size; + } + + static void SerializeElements(MaybeConstUserType& input, + Buffer* buf, + Data* output, + const ArrayValidateParams* validate_params, + SerializationContext* context) { + size_t size = Traits::GetSize(input); + for (size_t i = 0; i < size; ++i) { + typename Data::Element* result = output->storage() + i; + Serialize<Element>(Traits::GetAt(input, i), buf, &result, true, context); + MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( + !validate_params->element_is_nullable && output->at(i).is_null(), + VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, + MakeMessageWithArrayIndex("null in array expecting valid unions", + size, i)); + } + } + + static bool DeserializeElements(Data* input, + UserType* output, + SerializationContext* context) { + bool success = true; + Traits::Resize(*output, input->size()); + for (size_t i = 0; i < input->size(); ++i) { + // Note that we rely on complete deserialization taking place in order to + // transfer ownership of all encoded handles. Therefore we don't + // short-circuit on failure here. + if (!Deserialize<Element>(&input->at(i), &Traits::GetAt(*output, i), + context)) { + success = false; + } + } + return success; + } +}; + +template <typename Element, typename MaybeConstUserType> +struct Serializer<Array<Element>, MaybeConstUserType> { + using UserType = typename std::remove_const<MaybeConstUserType>::type; + using Impl = ArraySerializer<Array<Element>, MaybeConstUserType>; + using Traits = ArrayTraits<UserType>; + using Data = typename Array<Element>::Data_; + + static size_t PrepareToSerialize(MaybeConstUserType& input, + SerializationContext* context) { + if (CallIsNullIfExists<Traits>(input)) + return 0; + return Impl::GetSerializedSize(input, context); + } + + static void Serialize(MaybeConstUserType& input, + Buffer* buf, + Data** output, + const ArrayValidateParams* validate_params, + SerializationContext* context) { + if (!CallIsNullIfExists<Traits>(input)) { + MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( + validate_params->expected_num_elements != 0 && + Traits::GetSize(input) != validate_params->expected_num_elements, + internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER, + internal::MakeMessageWithExpectedArraySize( + "fixed-size array has wrong number of elements", + Traits::GetSize(input), validate_params->expected_num_elements)); + Data* result = Data::New(Traits::GetSize(input), buf); + if (result) + Impl::SerializeElements(input, buf, result, validate_params, context); + *output = result; + } else { + *output = nullptr; + } + } + + static bool Deserialize(Data* input, + UserType* output, + SerializationContext* context) { + if (!input) + return CallSetToNullIfExists<Traits>(output); + return Impl::DeserializeElements(input, output, context); + } +}; +} // namespace internal } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/array_serialization_traits.h b/chromium/mojo/public/cpp/bindings/lib/array_serialization_traits.h deleted file mode 100644 index 17817e01951..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/array_serialization_traits.h +++ /dev/null @@ -1,456 +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_ARRAY_SERIALIZATION_TRAITS_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_TRAITS_H_ - -#include <stddef.h> -#include <string.h> // For |memcpy()|. - -#include <limits> -#include <type_traits> -#include <utility> -#include <vector> - -#include "base/logging.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" - -namespace WTF { -class String; -} - -namespace mojo { -namespace internal { - -template <typename ArrayType, - typename ElementType, - typename ElementDataType, - bool is_union = IsUnionDataType< - typename RemovePointer<ElementDataType>::type>::value> -struct ArraySerializer; - -// Handles serialization and deserialization of arrays of pod types. -template <typename ArrayType, typename E, typename F> -struct ArraySerializer<ArrayType, E, F, false> { - static_assert(sizeof(E) == sizeof(F), "Incorrect array serializer"); - static size_t GetSerializedSize(const ArrayType& input, - SerializationContext* context) { - return sizeof(Array_Data<F>) + Align(input.size() * sizeof(E)); - } - - static void SerializeElements(ArrayType input, - Buffer* buf, - Array_Data<F>* output, - const ArrayValidateParams* validate_params, - SerializationContext* context) { - DCHECK(!validate_params->element_is_nullable) - << "Primitive type should be non-nullable"; - DCHECK(!validate_params->element_validate_params) - << "Primitive type should not have array validate params"; - - if (input.size()) - memcpy(output->storage(), &input.storage()[0], input.size() * sizeof(E)); - } - static bool DeserializeElements(Array_Data<F>* input, - ArrayType* output, - SerializationContext* context) { - ArrayType result(input->size()); - if (input->size()) - memcpy(&result.front(), input->storage(), input->size() * sizeof(E)); - output->Swap(&result); - return true; - } -}; - -// Serializes and deserializes arrays of bools. -template <typename ArrayType> -struct ArraySerializer<ArrayType, bool, bool, false> { - static size_t GetSerializedSize(const ArrayType& input, - SerializationContext* context) { - return sizeof(Array_Data<bool>) + Align((input.size() + 7) / 8); - } - - static void SerializeElements(ArrayType input, - Buffer* buf, - Array_Data<bool>* output, - const ArrayValidateParams* validate_params, - SerializationContext* context) { - DCHECK(!validate_params->element_is_nullable) - << "Primitive type should be non-nullable"; - DCHECK(!validate_params->element_validate_params) - << "Primitive type should not have array validate params"; - - // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? - for (size_t i = 0; i < input.size(); ++i) - output->at(i) = input[i]; - } - static bool DeserializeElements(Array_Data<bool>* input, - ArrayType* output, - SerializationContext* context) { - ArrayType result(input->size()); - // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? - for (size_t i = 0; i < input->size(); ++i) - result.at(i) = input->at(i); - output->Swap(&result); - return true; - } -}; - -// Serializes and deserializes arrays of handles. -template <typename ArrayType, typename H> -struct ArraySerializer<ArrayType, ScopedHandleBase<H>, H, false> { - static size_t GetSerializedSize(const ArrayType& input, - SerializationContext* context) { - return sizeof(Array_Data<H>) + Align(input.size() * sizeof(H)); - } - - static void SerializeElements(ArrayType input, - Buffer* buf, - Array_Data<H>* output, - const ArrayValidateParams* validate_params, - SerializationContext* context) { - DCHECK(!validate_params->element_validate_params) - << "Handle type should not have array validate params"; - - for (size_t i = 0; i < input.size(); ++i) { - output->at(i) = input[i].release(); // Transfer ownership of the handle. - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( - !validate_params->element_is_nullable && !output->at(i).is_valid(), - VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, - MakeMessageWithArrayIndex( - "invalid handle in array expecting valid handles", input.size(), - i)); - } - } - static bool DeserializeElements(Array_Data<H>* input, - ArrayType* output, - SerializationContext* context) { - ArrayType result(input->size()); - for (size_t i = 0; i < input->size(); ++i) - result.at(i) = MakeScopedHandle(FetchAndReset(&input->at(i))); - output->Swap(&result); - return true; - } -}; - -// This template must only apply to pointer mojo entity (strings, structs, -// arrays and maps). This is done by ensuring that WrapperTraits<S>::DataType is -// a pointer. -template <typename ArrayType, typename S> -struct ArraySerializer< - ArrayType, - S, - typename EnableIf<IsPointer<typename WrapperTraits<S>::DataType>::value, - typename WrapperTraits<S>::DataType>::type, - false> { - typedef - typename RemovePointer<typename WrapperTraits<S>::DataType>::type S_Data; - static size_t GetSerializedSize(const ArrayType& input, - SerializationContext* context) { - size_t size = sizeof(Array_Data<S_Data*>) + - input.size() * sizeof(StructPointer<S_Data>); - for (size_t i = 0; i < input.size(); ++i) - size += GetSerializedSize_(input[i], context); - return size; - } - - static void SerializeElements(ArrayType input, - Buffer* buf, - Array_Data<S_Data*>* output, - const ArrayValidateParams* validate_params, - SerializationContext* context) { - for (size_t i = 0; i < input.size(); ++i) { - S_Data* element; - SerializeCaller<S>::Run(std::move(input[i]), buf, &element, - validate_params->element_validate_params, - context); - output->at(i) = element; - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( - !validate_params->element_is_nullable && !element, - VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, - MakeMessageWithArrayIndex("null in array expecting valid pointers", - input.size(), i)); - } - } - static bool DeserializeElements(Array_Data<S_Data*>* input, - ArrayType* output, - SerializationContext* context) { - bool success = true; - ArrayType result(input->size()); - for (size_t i = 0; i < input->size(); ++i) { - // Note that we rely on complete deserialization taking place in order to - // transfer ownership of all encoded handles. Therefore we don't - // short-circuit on failure here. - if (!Deserialize_(input->at(i), &result[i], context)) - success = false; - } - output->Swap(&result); - return success; - } - - private: - template <typename T, - bool is_array = IsSpecializationOf<Array, T>::value || - IsSpecializationOf<WTFArray, T>::value, - bool is_string = std::is_same<T, String>::value || - std::is_same<T, WTF::String>::value> - struct SerializeCaller { - static void Run(T input, - Buffer* buf, - typename WrapperTraits<T>::DataType* output, - const ArrayValidateParams* validate_params, - SerializationContext* context) { - DCHECK(!validate_params) - << "Struct type should not have array validate params"; - - Serialize_(std::move(input), buf, output, context); - } - }; - - template <typename T> - struct SerializeCaller<T, true, false> { - static void Run(T input, - Buffer* buf, - typename T::Data_** output, - const ArrayValidateParams* validate_params, - SerializationContext* context) { - SerializeArray_(std::move(input), buf, output, validate_params, context); - } - }; - - template <typename T, typename U> - struct SerializeCaller<Map<T, U>, false, false> { - static void Run(Map<T, U> input, - Buffer* buf, - typename Map<T, U>::Data_** output, - const ArrayValidateParams* validate_params, - SerializationContext* context) { - SerializeMap_(std::move(input), buf, output, validate_params, context); - } - }; - - template <typename T> - struct SerializeCaller<T, false, true> { - static void Run(const T& input, - Buffer* buf, - String_Data** output, - const ArrayValidateParams* validate_params, - SerializationContext* context) { - DCHECK(validate_params && !validate_params->element_validate_params && - !validate_params->element_is_nullable && - validate_params->expected_num_elements == 0) - << "String type has unexpected array validate params"; - - Serialize_(input, buf, output, context); - } - }; -}; - -// Handles serialization and deserialization of arrays of unions. -template <typename ArrayType, typename U, typename U_Data> -struct ArraySerializer<ArrayType, U, U_Data, true> { - static size_t GetSerializedSize(const ArrayType& input, - SerializationContext* context) { - size_t size = sizeof(Array_Data<U_Data>); - for (size_t i = 0; i < input.size(); ++i) { - // GetSerializedSize_ will account for both the data in the union and the - // space in the array used to hold the union. - size += GetSerializedSize_(input[i], false, context); - } - return size; - } - - static void SerializeElements(ArrayType input, - Buffer* buf, - Array_Data<U_Data>* output, - const ArrayValidateParams* validate_params, - SerializationContext* context) { - for (size_t i = 0; i < input.size(); ++i) { - U_Data* result = output->storage() + i; - SerializeUnion_(std::move(input[i]), buf, &result, true, context); - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( - !validate_params->element_is_nullable && output->at(i).is_null(), - VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, - MakeMessageWithArrayIndex("null in array expecting valid unions", - input.size(), i)); - } - } - - static bool DeserializeElements(Array_Data<U_Data>* input, - ArrayType* output, - SerializationContext* context) { - bool success = true; - ArrayType result(input->size()); - for (size_t i = 0; i < input->size(); ++i) { - // Note that we rely on complete deserialization taking place in order to - // transfer ownership of all encoded handles. Therefore we don't - // short-circuit on failure here. - if (!Deserialize_(&input->at(i), &result[i], context)) - success = false; - } - output->Swap(&result); - return success; - } -}; - -// Another layer of abstraction to switch between standard mojom type -// serializers and native-only serializers. -template <typename ArrayType, - bool use_native = - ShouldUseNativeSerializer<typename ArrayType::ElementType>::value> -struct ArraySerializationStrategy; - -// Serialization strategy for standard mojom types. This branches further -// by choosing an ArraySerializer specialization from above. -template <typename ArrayType> -struct ArraySerializationStrategy<ArrayType, false> { - template <class DataType> - using Serializer = - ArraySerializer<ArrayType, typename ArrayType::ElementType, DataType>; - - static size_t GetSerializedSize(const ArrayType& input, - SerializationContext* context) { - DCHECK(input); - return Serializer<typename WrapperTraits< - typename ArrayType::ElementType>::DataType>::GetSerializedSize(input, - context); - } - - template <typename F> - static void Serialize(ArrayType input, - Buffer* buf, - Array_Data<F>** output, - const ArrayValidateParams* validate_params, - SerializationContext* context) { - DCHECK(input); - Array_Data<F>* result = Array_Data<F>::New(input.size(), buf); - if (result) { - Serializer<F>::SerializeElements(std::move(input), buf, result, - validate_params, context); - } - *output = result; - } - - template <typename F> - static bool Deserialize(Array_Data<F>* input, - ArrayType* output, - SerializationContext* context) { - DCHECK(input); - return Serializer<F>::DeserializeElements(input, output, context); - } -}; - -// Serialization for arrays of native-only types, which are opaquely serialized -// as arrays of uint8_t arrays. -template <typename ArrayType> -struct ArraySerializationStrategy<ArrayType, true> { - static size_t GetSerializedSize(const ArrayType& input, - SerializationContext* context) { - DCHECK(input); - DCHECK_LE(input.size(), std::numeric_limits<uint32_t>::max()); - size_t size = ArrayDataTraits<Array_Data<uint8_t>*>::GetStorageSize( - static_cast<uint32_t>(input.size())); - for (size_t i = 0; i < input.size(); ++i) { - size_t element_size = GetSerializedSizeNative_(input[i], context); - DCHECK_LT(element_size, std::numeric_limits<uint32_t>::max()); - size += ArrayDataTraits<uint8_t>::GetStorageSize( - static_cast<uint32_t>(element_size)); - } - return size; - } - - template <typename F> - static void Serialize(ArrayType input, - Buffer* buf, - Array_Data<F>** output, - const ArrayValidateParams* validate_params, - SerializationContext* context) { - static_assert( - std::is_same<F, Array_Data<uint8_t>*>::value, - "Native-only type array must serialize to array of byte arrays."); - DCHECK(input); - DCHECK(validate_params); - // TODO(rockot): We may want to support nullable (i.e. scoped_ptr<T>) - // elements here. - DCHECK(!validate_params->element_is_nullable); - Array_Data<Array_Data<uint8_t>*>* result = - Array_Data<Array_Data<uint8_t>*>::New(input.size(), buf); - for (size_t i = 0; i < input.size(); ++i) - SerializeNative_(input[i], buf, &result->at(i), context); - *output = result; - } - - template <typename F> - static bool Deserialize(Array_Data<F>* input, - ArrayType* output, - SerializationContext* context) { - static_assert( - std::is_same<F, Array_Data<uint8_t>*>::value, - "Native-only type array must deserialize from array of byte arrays."); - DCHECK(input); - - ArrayType result(input->size()); - bool success = true; - for (size_t i = 0; i < input->size(); ++i) { - // We don't short-circuit on failure since we can't know what the native - // type's ParamTraits' expectations are. - if (!DeserializeNative_(input->at(i), &result[i], context)) - success = false; - } - output->Swap(&result); - return success; - } -}; - -template <typename ArrayType> -struct ArraySerializationImpl { - using Strategy = ArraySerializationStrategy<ArrayType>; - - static size_t GetSerializedSize(const ArrayType& input, - SerializationContext* context) { - if (!input) - return 0; - return Strategy::GetSerializedSize(input, context); - } - - template <typename F> - static void Serialize(ArrayType input, - internal::Buffer* buf, - internal::Array_Data<F>** output, - const internal::ArrayValidateParams* validate_params, - SerializationContext* context) { - if (input) { - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( - validate_params->expected_num_elements != 0 && - input.size() != validate_params->expected_num_elements, - internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER, - internal::MakeMessageWithExpectedArraySize( - "fixed-size array has wrong number of elements", input.size(), - validate_params->expected_num_elements)); - Strategy::template Serialize<F>(std::move(input), buf, output, - validate_params, context); - } else { - *output = nullptr; - } - } - - template <typename F> - static bool Deserialize(internal::Array_Data<F>* input, - ArrayType* output, - internal::SerializationContext* context) { - if (input) - return Strategy::template Deserialize<F>(input, output, context); - *output = nullptr; - return true; - } -}; - -} // namespace internal - -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_TRAITS_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/associated_group.cc b/chromium/mojo/public/cpp/bindings/lib/associated_group.cc index 0bdf809d1ed..c3bde6f1b47 100644 --- a/chromium/mojo/public/cpp/bindings/lib/associated_group.cc +++ b/chromium/mojo/public/cpp/bindings/lib/associated_group.cc @@ -24,8 +24,8 @@ AssociatedGroup& AssociatedGroup::operator=(const AssociatedGroup& other) { } void AssociatedGroup::CreateEndpointHandlePair( - internal::ScopedInterfaceEndpointHandle* local_endpoint, - internal::ScopedInterfaceEndpointHandle* remote_endpoint) { + ScopedInterfaceEndpointHandle* local_endpoint, + ScopedInterfaceEndpointHandle* remote_endpoint) { if (!router_) return; diff --git a/chromium/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h b/chromium/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h index 6f5f830d629..e214335a9ea 100644 --- a/chromium/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h +++ b/chromium/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h @@ -6,11 +6,15 @@ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_ASSOCIATED_INTERFACE_PTR_STATE_H_ #include <stdint.h> + #include <algorithm> // For |std::swap()|. +#include <memory> #include <utility> #include "base/macros.h" -#include "base/memory/scoped_ptr.h" +#include "base/memory/ptr_util.h" +#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_interface_ptr_info.h" #include "mojo/public/cpp/bindings/callback.h" @@ -18,7 +22,7 @@ #include "mojo/public/cpp/bindings/lib/interface_endpoint_client.h" #include "mojo/public/cpp/bindings/lib/interface_id.h" #include "mojo/public/cpp/bindings/lib/multiplex_router.h" -#include "mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h" +#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" #include "mojo/public/cpp/system/message_pipe.h" namespace mojo { @@ -77,7 +81,8 @@ class AssociatedInterfacePtrState { swap(other->version_, version_); } - void Bind(AssociatedInterfacePtrInfo<Interface> info) { + void Bind(AssociatedInterfacePtrInfo<Interface> info, + scoped_refptr<base::SingleThreadTaskRunner> runner) { DCHECK(!endpoint_client_); DCHECK(!proxy_); DCHECK_EQ(0u, version_); @@ -85,8 +90,9 @@ class AssociatedInterfacePtrState { version_ = info.version(); endpoint_client_.reset(new InterfaceEndpointClient( - AssociatedInterfacePtrInfoHelper::PassHandle(&info), nullptr, - make_scoped_ptr(new typename Interface::ResponseValidator_()), false)); + info.PassHandle(), nullptr, + base::WrapUnique(new typename Interface::ResponseValidator_()), false, + std::move(runner))); proxy_.reset(new Proxy(endpoint_client_.get())); proxy_->serialization_context()->router = endpoint_client_->router(); } @@ -97,11 +103,7 @@ class AssociatedInterfacePtrState { ScopedInterfaceEndpointHandle handle = endpoint_client_->PassHandle(); endpoint_client_.reset(); proxy_.reset(); - - AssociatedInterfacePtrInfo<Interface> result; - result.set_version(version_); - AssociatedInterfacePtrInfoHelper::SetHandle(&result, std::move(handle)); - return result; + return AssociatedInterfacePtrInfo<Interface>(std::move(handle), version_); } bool is_bound() const { return !!endpoint_client_; } @@ -127,8 +129,8 @@ class AssociatedInterfacePtrState { private: using Proxy = typename Interface::Proxy_; - scoped_ptr<InterfaceEndpointClient> endpoint_client_; - scoped_ptr<Proxy> proxy_; + std::unique_ptr<InterfaceEndpointClient> endpoint_client_; + std::unique_ptr<Proxy> proxy_; uint32_t version_; diff --git a/chromium/mojo/public/cpp/bindings/lib/binding_state.h b/chromium/mojo/public/cpp/bindings/lib/binding_state.h index b3588da724e..77a59f5d0ed 100644 --- a/chromium/mojo/public/cpp/bindings/lib/binding_state.h +++ b/chromium/mojo/public/cpp/bindings/lib/binding_state.h @@ -5,12 +5,14 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDING_STATE_H_ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDING_STATE_H_ +#include <memory> #include <utility> #include "base/logging.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" +#include "base/single_thread_task_runner.h" #include "mojo/public/cpp/bindings/associated_group.h" #include "mojo/public/cpp/bindings/callback.h" #include "mojo/public/cpp/bindings/interface_ptr.h" @@ -22,7 +24,7 @@ #include "mojo/public/cpp/bindings/lib/message_header_validator.h" #include "mojo/public/cpp/bindings/lib/multiplex_router.h" #include "mojo/public/cpp/bindings/lib/router.h" -#include "mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h" +#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" #include "mojo/public/cpp/system/core.h" namespace mojo { @@ -47,14 +49,16 @@ class BindingState<Interface, false> { Close(); } - void Bind(ScopedMessagePipeHandle handle) { + void Bind(ScopedMessagePipeHandle handle, + scoped_refptr<base::SingleThreadTaskRunner> runner) { DCHECK(!router_); internal::FilterChain filters; filters.Append<internal::MessageHeaderValidator>(); filters.Append<typename Interface::RequestValidator_>(); - router_ = new internal::Router(std::move(handle), std::move(filters), - Interface::HasSyncMethods_); + 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( [this]() { connection_error_handler_.Run(); }); @@ -141,16 +145,17 @@ class BindingState<Interface, true> { Close(); } - void Bind(ScopedMessagePipeHandle handle) { + void Bind(ScopedMessagePipeHandle handle, + scoped_refptr<base::SingleThreadTaskRunner> runner) { DCHECK(!router_); - router_ = new internal::MultiplexRouter(false, std::move(handle)); + router_ = new internal::MultiplexRouter(false, std::move(handle), runner); stub_.serialization_context()->router = router_; endpoint_client_.reset(new internal::InterfaceEndpointClient( router_->CreateLocalEndpointHandle(internal::kMasterInterfaceId), - &stub_, make_scoped_ptr(new typename Interface::RequestValidator_()), - Interface::HasSyncMethods_)); + &stub_, base::WrapUnique(new typename Interface::RequestValidator_()), + Interface::HasSyncMethods_, std::move(runner))); endpoint_client_->set_connection_error_handler( [this]() { connection_error_handler_.Run(); }); @@ -217,7 +222,7 @@ class BindingState<Interface, true> { private: scoped_refptr<internal::MultiplexRouter> router_; - scoped_ptr<internal::InterfaceEndpointClient> endpoint_client_; + std::unique_ptr<internal::InterfaceEndpointClient> endpoint_client_; typename Interface::Stub_ stub_; Interface* impl_; diff --git a/chromium/mojo/public/cpp/bindings/lib/bindings_internal.h b/chromium/mojo/public/cpp/bindings/lib/bindings_internal.h index 8d320823139..f38c7645eb9 100644 --- a/chromium/mojo/public/cpp/bindings/lib/bindings_internal.h +++ b/chromium/mojo/public/cpp/bindings/lib/bindings_internal.h @@ -25,6 +25,14 @@ class InlinedStructPtr; namespace internal { +// Please note that this is a different value than |mojo::kInvalidHandleValue|, +// which is the "decoded" invalid handle. +const uint32_t kEncodedInvalidHandleValue = static_cast<uint32_t>(-1); + +// A serialized union always takes 16 bytes: +// 4-byte size + 4-byte tag + 8-byte payload. +const uint32_t kUnionDataSize = 16; + template <typename T> class Array_Data; @@ -45,32 +53,24 @@ struct ArrayHeader { static_assert(sizeof(ArrayHeader) == 8, "Bad_sizeof(ArrayHeader)"); template <typename T> -union StructPointer { +union Pointer { uint64_t offset; T* ptr; }; -static_assert(sizeof(StructPointer<char>) == 8, "Bad_sizeof(StructPointer)"); +static_assert(sizeof(Pointer<char>) == 8, "Bad_sizeof(Pointer)"); -template <typename T> -union ArrayPointer { - uint64_t offset; - Array_Data<T>* ptr; -}; -static_assert(sizeof(ArrayPointer<char>) == 8, "Bad_sizeof(ArrayPointer)"); - -using StringPointer = ArrayPointer<char>; -static_assert(sizeof(StringPointer) == 8, "Bad_sizeof(StringPointer)"); +struct Handle_Data { + Handle_Data() = default; + explicit Handle_Data(uint32_t value) : value(value) {} + bool is_valid() const { return value != kEncodedInvalidHandleValue; } -template <typename T> -union UnionPointer { - uint64_t offset; - T* ptr; + uint32_t value; }; -static_assert(sizeof(UnionPointer<char>) == 8, "Bad_sizeof(UnionPointer)"); +static_assert(sizeof(Handle_Data) == 4, "Bad_sizeof(Handle_Data)"); struct Interface_Data { - MessagePipeHandle handle; + Handle_Data handle; uint32_t version; }; static_assert(sizeof(Interface_Data) == 8, "Bad_sizeof(Interface_Data)"); @@ -101,30 +101,19 @@ T FetchAndReset(T* ptr) { template <typename H> struct IsHandle { - enum { value = IsBaseOf<Handle, H>::value }; + enum { value = 0 }; }; -template <typename T> -struct IsUnionDataType { - private: - template <typename U> - static YesType Test(const typename U::MojomUnionDataType*); - - template <typename U> - static NoType Test(...); - - EnsureTypeIsComplete<T> check_t_; - - public: - static const bool value = - sizeof(Test<T>(0)) == sizeof(YesType) && !IsConst<T>::value; +template <> +struct IsHandle<Handle_Data> { + enum { value = 1 }; }; template <typename T> -struct IsEnumDataType { +struct IsUnionDataType { private: template <typename U> - static YesType Test(const typename U::MojomEnumDataType*); + static YesType Test(const typename U::MojomUnionDataType*); template <typename U> static NoType Test(...); @@ -136,38 +125,48 @@ struct IsEnumDataType { sizeof(Test<T>(0)) == sizeof(YesType) && !IsConst<T>::value; }; -template <typename T, bool move_only = IsMoveOnlyType<T>::value> -struct WrapperTraits; +template <typename MojomType, bool move_only = IsMoveOnlyType<MojomType>::value> +struct GetDataTypeAsArrayElement; template <typename T> -struct WrapperTraits<T, false> { - typedef T DataType; +struct GetDataTypeAsArrayElement<T, false> { + using Data = + typename std::conditional<std::is_enum<T>::value, int32_t, T>::type; }; template <typename H> -struct WrapperTraits<ScopedHandleBase<H>, true> { - typedef H DataType; +struct GetDataTypeAsArrayElement<ScopedHandleBase<H>, true> { + using Data = Handle_Data; }; template <typename S> -struct WrapperTraits<StructPtr<S>, true> { - typedef typename S::Data_* DataType; +struct GetDataTypeAsArrayElement<StructPtr<S>, true> { + using Data = + typename std::conditional<IsUnionDataType<typename S::Data_>::value, + typename S::Data_, + typename S::Data_*>::type; }; template <typename S> -struct WrapperTraits<InlinedStructPtr<S>, true> { - typedef typename S::Data_* DataType; +struct GetDataTypeAsArrayElement<InlinedStructPtr<S>, true> { + using Data = + typename std::conditional<IsUnionDataType<typename S::Data_>::value, + typename S::Data_, + typename S::Data_*>::type; }; template <typename S> -struct WrapperTraits<S, true> { - typedef typename S::Data_* DataType; +struct GetDataTypeAsArrayElement<S, true> { + using Data = + typename std::conditional<IsUnionDataType<typename S::Data_>::value, + typename S::Data_, + typename S::Data_*>::type; }; template <> -struct WrapperTraits<String, false> { - typedef String_Data* DataType; +struct GetDataTypeAsArrayElement<String, false> { + using Data = String_Data*; }; template <> -struct WrapperTraits<WTF::String, false> { - typedef String_Data* DataType; +struct GetDataTypeAsArrayElement<WTF::String, false> { + using Data = String_Data*; }; } // namespace internal diff --git a/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.cc b/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.cc deleted file mode 100644 index 48c52ddab5a..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.cc +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" - -#include <stddef.h> -#include <stdint.h> - -#include "base/logging.h" - -namespace mojo { -namespace internal { - -namespace { - -const size_t kAlignment = 8; - -template <typename T> -T AlignImpl(T t) { - return t + (kAlignment - (t % kAlignment)) % kAlignment; -} - -} // namespace - -size_t Align(size_t size) { - return AlignImpl(size); -} - -char* AlignPointer(char* ptr) { - return reinterpret_cast<char*>(AlignImpl(reinterpret_cast<uintptr_t>(ptr))); -} - -bool IsAligned(const void* ptr) { - return !(reinterpret_cast<uintptr_t>(ptr) % kAlignment); -} - -void EncodePointer(const void* ptr, uint64_t* offset) { - if (!ptr) { - *offset = 0; - return; - } - - const char* p_obj = reinterpret_cast<const char*>(ptr); - const char* p_slot = reinterpret_cast<const char*>(offset); - DCHECK(p_obj > p_slot); - - *offset = static_cast<uint64_t>(p_obj - p_slot); -} - -const void* DecodePointerRaw(const uint64_t* offset) { - if (!*offset) - return nullptr; - return reinterpret_cast<const char*>(offset) + *offset; -} - -void EncodeHandle(Handle* handle, std::vector<Handle>* handles) { - if (handle->is_valid()) { - handles->push_back(*handle); - handle->set_value(static_cast<MojoHandle>(handles->size() - 1)); - } else { - handle->set_value(kEncodedInvalidHandleValue); - } -} - -void EncodeHandle(Interface_Data* data, std::vector<Handle>* handles) { - EncodeHandle(&data->handle, handles); -} - -void EncodeHandle(MojoHandle* handle, std::vector<Handle>* handles) { - EncodeHandle(reinterpret_cast<Handle*>(handle), handles); -} - -void DecodeHandle(Handle* handle, std::vector<Handle>* handles) { - if (handle->value() == kEncodedInvalidHandleValue) { - *handle = Handle(); - return; - } - DCHECK(handle->value() < handles->size()); - // Just leave holes in the vector so we don't screw up other indices. - *handle = FetchAndReset(&handles->at(handle->value())); -} - -void DecodeHandle(Interface_Data* data, std::vector<Handle>* handles) { - DecodeHandle(&data->handle, handles); -} - -void DecodeHandle(MojoHandle* handle, std::vector<Handle>* handles) { - DecodeHandle(reinterpret_cast<Handle*>(handle), handles); -} - -SerializationContext::SerializationContext() {} - -SerializationContext::SerializationContext( - scoped_refptr<MultiplexRouter> in_router) - : router(std::move(in_router)) {} - -SerializationContext::~SerializationContext() {} - -} // namespace internal -} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.h b/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.h deleted file mode 100644 index 7a10b1cb753..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.h +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ - -#include <stddef.h> -#include <stdint.h> - -#include <vector> - -#include "base/memory/ref_counted.h" -#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h" -#include "mojo/public/cpp/bindings/interface_ptr.h" -#include "mojo/public/cpp/bindings/lib/bindings_internal.h" -#include "mojo/public/cpp/system/core.h" - -namespace mojo { -namespace internal { - -class MultiplexRouter; - -// Please note that this is a different value than |mojo::kInvalidHandleValue|, -// which is the "decoded" invalid handle. -const MojoHandle kEncodedInvalidHandleValue = static_cast<MojoHandle>(-1); - -size_t Align(size_t size); -char* AlignPointer(char* ptr); - -bool IsAligned(const void* ptr); - -// Pointers are encoded as relative offsets. The offsets are relative to the -// address of where the offset value is stored, such that the pointer may be -// recovered with the expression: -// -// ptr = reinterpret_cast<char*>(offset) + *offset -// -// A null pointer is encoded as an offset value of 0. -// -void EncodePointer(const void* ptr, uint64_t* offset); -// Note: This function doesn't validate the encoded pointer value. -const void* DecodePointerRaw(const uint64_t* offset); - -// Note: This function doesn't validate the encoded pointer value. -template <typename T> -inline void DecodePointer(const uint64_t* offset, T** ptr) { - *ptr = reinterpret_cast<T*>(const_cast<void*>(DecodePointerRaw(offset))); -} - -// Handles are encoded as indices into a vector of handles. These functions -// manipulate the value of |handle|, mapping it to and from an index. - -void EncodeHandle(Handle* handle, std::vector<Handle>* handles); -void EncodeHandle(Interface_Data* data, std::vector<Handle>* handles); -void EncodeHandle(MojoHandle* handle, std::vector<Handle>* handles); -// Note: The following three functions don't validate the encoded handle value. -void DecodeHandle(Handle* handle, std::vector<Handle>* handles); -void DecodeHandle(Interface_Data* data, std::vector<Handle>* handles); -void DecodeHandle(MojoHandle* handle, std::vector<Handle>* handles); - -// The following 2 functions are used to encode/decode all objects (structs and -// arrays) in a consistent manner. - -template <typename T> -inline void Encode(T* obj, std::vector<Handle>* handles) { - if (obj->ptr) - obj->ptr->EncodePointersAndHandles(handles); - EncodePointer(obj->ptr, &obj->offset); -} - -// Note: This function doesn't validate the encoded pointer and handle values. -template <typename T> -inline void Decode(T* obj, std::vector<Handle>* handles) { - DecodePointer(&obj->offset, &obj->ptr); - if (obj->ptr) - obj->ptr->DecodePointersAndHandles(handles); -} - -template <typename T> -inline void InterfacePointerToData(InterfacePtr<T> input, - Interface_Data* output) { - InterfacePtrInfo<T> info = input.PassInterface(); - output->handle = info.PassHandle().release(); - output->version = info.version(); -} - -template <typename T> -inline void InterfaceDataToPointer(Interface_Data* input, - InterfacePtr<T>* output) { - output->Bind(InterfacePtrInfo<T>( - MakeScopedHandle(FetchAndReset(&input->handle)), input->version)); -} - -template <typename T> -inline void AssociatedInterfacePtrInfoToData( - AssociatedInterfacePtrInfo<T> input, - AssociatedInterface_Data* output) { - output->version = input.version(); - output->interface_id = - AssociatedInterfacePtrInfoHelper::PassHandle(&input).release(); -} - -template <typename T> -inline void AssociatedInterfaceDataToPtrInfo( - AssociatedInterface_Data* input, - AssociatedInterfacePtrInfo<T>* output, - MultiplexRouter* router) { - AssociatedInterfacePtrInfoHelper::SetHandle( - output, - router->CreateLocalEndpointHandle(FetchAndReset(&input->interface_id))); - output->set_version(input->version); -} - -class WTFStringContext { - public: - virtual ~WTFStringContext() {} -}; - -// Context information for serialization/deserialization routines. -struct SerializationContext { - SerializationContext(); - explicit SerializationContext(scoped_refptr<MultiplexRouter> in_router); - - ~SerializationContext(); - - // Used to serialize/deserialize associated interface pointers and requests. - scoped_refptr<MultiplexRouter> router; - - scoped_ptr<WTFStringContext> wtf_string_context; -}; - -} // namespace internal -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/bounds_checker.cc b/chromium/mojo/public/cpp/bindings/lib/bounds_checker.cc index 64314ec21d2..49416d1116c 100644 --- a/chromium/mojo/public/cpp/bindings/lib/bounds_checker.cc +++ b/chromium/mojo/public/cpp/bindings/lib/bounds_checker.cc @@ -8,7 +8,7 @@ #include <stdint.h> #include "base/logging.h" -#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" +#include "mojo/public/cpp/bindings/lib/serialization_util.h" #include "mojo/public/cpp/system/handle.h" namespace mojo { @@ -50,8 +50,8 @@ bool BoundsChecker::ClaimMemory(const void* position, uint32_t num_bytes) { return true; } -bool BoundsChecker::ClaimHandle(const Handle& encoded_handle) { - uint32_t index = encoded_handle.value(); +bool BoundsChecker::ClaimHandle(const Handle_Data& encoded_handle) { + uint32_t index = encoded_handle.value; if (index == kEncodedInvalidHandleValue) return true; diff --git a/chromium/mojo/public/cpp/bindings/lib/bounds_checker.h b/chromium/mojo/public/cpp/bindings/lib/bounds_checker.h index aac3b665c94..d59a68aa034 100644 --- a/chromium/mojo/public/cpp/bindings/lib/bounds_checker.h +++ b/chromium/mojo/public/cpp/bindings/lib/bounds_checker.h @@ -9,6 +9,7 @@ #include <stdint.h> #include "base/macros.h" +#include "mojo/public/cpp/bindings/lib/bindings_internal.h" namespace mojo { @@ -38,7 +39,7 @@ class BoundsChecker { // - |encoded_handle|'s value is |kEncodedInvalidHandleValue|. // - the handle is contained inside the valid range of handle indices. In this // case, the valid range is shinked to begin right after the claimed handle. - bool ClaimHandle(const Handle& encoded_handle); + 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. diff --git a/chromium/mojo/public/cpp/bindings/lib/buffer.h b/chromium/mojo/public/cpp/bindings/lib/buffer.h index 98bbce0e6ae..c3b570e7767 100644 --- a/chromium/mojo/public/cpp/bindings/lib/buffer.h +++ b/chromium/mojo/public/cpp/bindings/lib/buffer.h @@ -10,18 +10,12 @@ namespace mojo { namespace internal { -class PickleBuffer; - // Buffer provides a way to allocate memory. Allocations are 8-byte aligned and // zero-initialized. Allocations remain valid for the lifetime of the Buffer. class Buffer { public: virtual ~Buffer() {} virtual void* Allocate(size_t num_bytes) = 0; - - // TODO(rockot): Remove this. It's a hack to get a PickleBuffer in - // Serialize_ calls without having to update every call site. - virtual PickleBuffer* AsPickleBuffer() = 0; }; } // namespace internal diff --git a/chromium/mojo/public/cpp/bindings/lib/connector.cc b/chromium/mojo/public/cpp/bindings/lib/connector.cc index 70f9fd78b2a..9f1037ceae8 100644 --- a/chromium/mojo/public/cpp/bindings/lib/connector.cc +++ b/chromium/mojo/public/cpp/bindings/lib/connector.cc @@ -8,10 +8,10 @@ #include <utility> #include "base/bind.h" +#include "base/location.h" #include "base/logging.h" #include "base/macros.h" #include "base/synchronization/lock.h" -#include "base/thread_task_runner_handle.h" #include "mojo/public/cpp/bindings/lib/sync_handle_watcher.h" namespace mojo { @@ -45,9 +45,12 @@ class MayAutoLock { // ---------------------------------------------------------------------------- Connector::Connector(ScopedMessagePipeHandle message_pipe, - ConnectorConfig config) + 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), @@ -147,21 +150,11 @@ bool Connector::Accept(Message* message) { return true; MojoResult rv = - WriteMessageRaw(message_pipe_.get(), - message->data(), - message->data_num_bytes(), - message->mutable_handles()->empty() - ? nullptr - : reinterpret_cast<const MojoHandle*>( - &message->mutable_handles()->front()), - static_cast<uint32_t>(message->mutable_handles()->size()), + WriteMessageNew(message_pipe_.get(), message->TakeMojoMessage(), MOJO_WRITE_MESSAGE_FLAG_NONE); switch (rv) { case MOJO_RESULT_OK: - // The handles were successfully transferred, so we don't need the message - // to track their lifetime any longer. - message->mutable_handles()->clear(); break; case MOJO_RESULT_FAILED_PRECONDITION: // There's no point in continuing to write to this pipe since the other @@ -249,7 +242,7 @@ void Connector::WaitToReadMore() { if (rv != MOJO_RESULT_OK) { // If the watch failed because the handle is invalid or its conditions can // no longer be met, we signal the error asynchronously to avoid reentry. - base::ThreadTaskRunnerHandle::Get()->PostTask( + task_runner_->PostTask( FROM_HERE, base::Bind(&Connector::OnWatcherHandleReady, weak_self_, rv)); } diff --git a/chromium/mojo/public/cpp/bindings/lib/connector.h b/chromium/mojo/public/cpp/bindings/lib/connector.h index f61c18fb897..243159ef32f 100644 --- a/chromium/mojo/public/cpp/bindings/lib/connector.h +++ b/chromium/mojo/public/cpp/bindings/lib/connector.h @@ -5,9 +5,11 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_CONNECTOR_H_ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_CONNECTOR_H_ +#include <memory> + #include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.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/callback.h" #include "mojo/public/cpp/bindings/lib/sync_handle_watcher.h" @@ -42,7 +44,9 @@ class Connector : public MessageReceiver { }; // The Connector takes ownership of |message_pipe|. - Connector(ScopedMessagePipeHandle message_pipe, ConnectorConfig config); + Connector(ScopedMessagePipeHandle message_pipe, + ConnectorConfig config, + scoped_refptr<base::SingleThreadTaskRunner> runner); ~Connector() override; // Sets the receiver to handle messages read from the message pipe. The @@ -139,6 +143,10 @@ class Connector : public MessageReceiver { return sync_handle_watcher_callback_count_ > 0; } + base::SingleThreadTaskRunner* task_runner() const { + return task_runner_.get(); + } + private: // Callback of mojo::Watcher. void OnWatcherHandleReady(MojoResult result); @@ -170,6 +178,7 @@ class Connector : public MessageReceiver { ScopedMessagePipeHandle message_pipe_; MessageReceiver* incoming_receiver_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; Watcher handle_watcher_; bool error_; @@ -180,9 +189,9 @@ class Connector : public MessageReceiver { // If sending messages is allowed from multiple threads, |lock_| is used to // protect modifications to |message_pipe_| and |drop_writes_|. - scoped_ptr<base::Lock> lock_; + std::unique_ptr<base::Lock> lock_; - scoped_ptr<SyncHandleWatcher> sync_watcher_; + std::unique_ptr<SyncHandleWatcher> sync_watcher_; bool allow_woken_up_by_others_; // If non-zero, currently the control flow is inside the sync handle watcher // callback. diff --git a/chromium/mojo/public/cpp/bindings/lib/control_message_handler.cc b/chromium/mojo/public/cpp/bindings/lib/control_message_handler.cc index 1316b6d7d5c..1bcd87daf9e 100644 --- a/chromium/mojo/public/cpp/bindings/lib/control_message_handler.cc +++ b/chromium/mojo/public/cpp/bindings/lib/control_message_handler.cc @@ -10,6 +10,7 @@ #include "base/logging.h" #include "mojo/public/cpp/bindings/lib/message_builder.h" +#include "mojo/public/cpp/bindings/lib/serialization.h" #include "mojo/public/interfaces/bindings/interface_control_messages.mojom.h" namespace mojo { @@ -55,14 +56,14 @@ bool ControlMessageHandler::Run(Message* message, response_params_ptr->query_version_result = QueryVersionResult::New(); response_params_ptr->query_version_result->version = interface_version_; - size_t size = GetSerializedSize_(response_params_ptr, nullptr); + size_t size = PrepareToSerialize<RunResponseMessageParamsPtr>( + response_params_ptr, &context_); ResponseMessageBuilder builder(kRunMessageId, size, message->request_id()); RunResponseMessageParams_Data* response_params = nullptr; - Serialize_(std::move(response_params_ptr), builder.buffer(), &response_params, - nullptr); - response_params->EncodePointersAndHandles( - builder.message()->mutable_handles()); + Serialize<RunResponseMessageParamsPtr>(response_params_ptr, builder.buffer(), + &response_params, &context_); + response_params->EncodePointers(); bool ok = responder->Accept(builder.message()); ALLOW_UNUSED_LOCAL(ok); delete responder; @@ -74,10 +75,10 @@ bool ControlMessageHandler::RunOrClosePipe(Message* message) { RunOrClosePipeMessageParams_Data* params = reinterpret_cast<RunOrClosePipeMessageParams_Data*>( message->mutable_payload()); - params->DecodePointersAndHandles(message->mutable_handles()); + params->DecodePointers(); RunOrClosePipeMessageParamsPtr params_ptr; - Deserialize_(params, ¶ms_ptr, nullptr); + Deserialize<RunOrClosePipeMessageParamsPtr>(params, ¶ms_ptr, &context_); return interface_version_ >= params_ptr->require_version->version; } diff --git a/chromium/mojo/public/cpp/bindings/lib/control_message_handler.h b/chromium/mojo/public/cpp/bindings/lib/control_message_handler.h index 27acde8cbdf..13b5aa6214e 100644 --- a/chromium/mojo/public/cpp/bindings/lib/control_message_handler.h +++ b/chromium/mojo/public/cpp/bindings/lib/control_message_handler.h @@ -8,6 +8,7 @@ #include <stdint.h> #include "base/macros.h" +#include "mojo/public/cpp/bindings/lib/serialization_context.h" #include "mojo/public/cpp/bindings/message.h" namespace mojo { @@ -32,6 +33,7 @@ class ControlMessageHandler : public MessageReceiverWithResponderStatus { bool RunOrClosePipe(Message* message); uint32_t interface_version_; + SerializationContext context_; DISALLOW_COPY_AND_ASSIGN(ControlMessageHandler); }; diff --git a/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.cc b/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.cc index 620806502c2..6189e6973e7 100644 --- a/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.cc +++ b/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.cc @@ -10,6 +10,7 @@ #include "base/macros.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/interface_control_messages.mojom.h" @@ -35,10 +36,11 @@ bool RunResponseForwardToCallback::Accept(Message* message) { RunResponseMessageParams_Data* params = reinterpret_cast<RunResponseMessageParams_Data*>( message->mutable_payload()); - params->DecodePointersAndHandles(message->mutable_handles()); + params->DecodePointers(); RunResponseMessageParamsPtr params_ptr; - Deserialize_(params, ¶ms_ptr, nullptr); + SerializationContext context; + Deserialize<RunResponseMessageParamsPtr>(params, ¶ms_ptr, &context); callback_.Run(std::move(params_ptr->query_version_result)); return true; @@ -46,36 +48,41 @@ bool RunResponseForwardToCallback::Accept(Message* message) { void SendRunMessage(MessageReceiverWithResponder* receiver, QueryVersionPtr query_version, - const RunCallback& callback) { + 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 = GetSerializedSize_(params_ptr, nullptr); + size_t size = PrepareToSerialize<RunMessageParamsPtr>(params_ptr, context); RequestMessageBuilder builder(kRunMessageId, size); RunMessageParams_Data* params = nullptr; - Serialize_(std::move(params_ptr), builder.buffer(), ¶ms, nullptr); - params->EncodePointersAndHandles(builder.message()->mutable_handles()); + Serialize<RunMessageParamsPtr>(params_ptr, builder.buffer(), ¶ms, + context); + params->EncodePointers(); MessageReceiver* responder = new RunResponseForwardToCallback(callback); if (!receiver->AcceptWithResponder(builder.message(), responder)) delete responder; } void SendRunOrClosePipeMessage(MessageReceiverWithResponder* receiver, - RequireVersionPtr require_version) { + 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 = GetSerializedSize_(params_ptr, nullptr); + size_t size = + PrepareToSerialize<RunOrClosePipeMessageParamsPtr>(params_ptr, context); MessageBuilder builder(kRunOrClosePipeMessageId, size); RunOrClosePipeMessageParams_Data* params = nullptr; - Serialize_(std::move(params_ptr), builder.buffer(), ¶ms, nullptr); - params->EncodePointersAndHandles(builder.message()->mutable_handles()); + Serialize<RunOrClosePipeMessageParamsPtr>(params_ptr, builder.buffer(), + ¶ms, context); + params->EncodePointers(); bool ok = receiver->Accept(builder.message()); ALLOW_UNUSED_LOCAL(ok); } @@ -91,13 +98,13 @@ void ControlMessageProxy::QueryVersion( auto run_callback = [callback](QueryVersionResultPtr query_version_result) { callback.Run(query_version_result->version); }; - SendRunMessage(receiver_, QueryVersion::New(), run_callback); + SendRunMessage(receiver_, QueryVersion::New(), run_callback, &context_); } void ControlMessageProxy::RequireVersion(uint32_t version) { RequireVersionPtr require_version(RequireVersion::New()); require_version->version = version; - SendRunOrClosePipeMessage(receiver_, std::move(require_version)); + SendRunOrClosePipeMessage(receiver_, std::move(require_version), &context_); } } // namespace internal diff --git a/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.h b/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.h index 33aaf82a9f3..ce20fc8415f 100644 --- a/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.h +++ b/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.h @@ -9,6 +9,7 @@ #include "base/macros.h" #include "mojo/public/cpp/bindings/callback.h" +#include "mojo/public/cpp/bindings/lib/serialization_context.h" namespace mojo { @@ -28,6 +29,7 @@ class ControlMessageProxy { protected: // Not owned. MessageReceiverWithResponder* receiver_; + SerializationContext context_; DISALLOW_COPY_AND_ASSIGN(ControlMessageProxy); }; diff --git a/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.cc b/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.cc index 9653345532e..50b8a21c56b 100644 --- a/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.cc +++ b/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.cc @@ -10,7 +10,7 @@ #include <algorithm> #include "base/logging.h" -#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" +#include "mojo/public/cpp/bindings/lib/serialization_util.h" namespace mojo { namespace internal { @@ -39,8 +39,6 @@ void* FixedBuffer::Allocate(size_t delta) { return result; } -PickleBuffer* FixedBuffer::AsPickleBuffer() { return nullptr; } - FixedBufferForTesting::FixedBufferForTesting(size_t size) { size_ = internal::Align(size); // Use calloc here to ensure all message memory is zero'd out. diff --git a/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.h b/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.h index d087c3b36a5..9a5704b4bfa 100644 --- a/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.h +++ b/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.h @@ -51,8 +51,6 @@ class FixedBuffer : public Buffer { // memory is zero-filled. void* Allocate(size_t num_bytes) override; - PickleBuffer* AsPickleBuffer() override; - protected: char* ptr_; size_t cursor_; diff --git a/chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc b/chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc index 574d627888a..9e32c5af239 100644 --- a/chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc +++ b/chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc @@ -5,15 +5,15 @@ #include "mojo/public/cpp/bindings/lib/interface_endpoint_client.h" #include <stdint.h> + #include <utility> #include "base/bind.h" #include "base/location.h" #include "base/macros.h" -#include "base/message_loop/message_loop.h" +#include "base/memory/ptr_util.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" -#include "base/thread_task_runner_handle.h" #include "mojo/public/cpp/bindings/associated_group.h" #include "mojo/public/cpp/bindings/lib/interface_endpoint_controller.h" #include "mojo/public/cpp/bindings/lib/multiplex_router.h" @@ -38,18 +38,24 @@ void DCheckIfInvalid(const base::WeakPtr<InterfaceEndpointClient>& client, class ResponderThunk : public MessageReceiverWithStatus { public: explicit ResponderThunk( - const base::WeakPtr<InterfaceEndpointClient>& endpoint_client) - : endpoint_client_(endpoint_client), accept_was_invoked_(false), - task_runner_(base::ThreadTaskRunnerHandle::Get()) {} + const base::WeakPtr<InterfaceEndpointClient>& endpoint_client, + scoped_refptr<base::SingleThreadTaskRunner> runner) + : endpoint_client_(endpoint_client), + 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 InterfaceEndpointClient::RaiseError(), because it will raise + // error from the correct task runner asynchronously. if (endpoint_client_) { - // 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. endpoint_client_->RaiseError(); } } else { @@ -126,14 +132,16 @@ bool InterfaceEndpointClient::HandleIncomingMessageThunk::Accept( InterfaceEndpointClient::InterfaceEndpointClient( ScopedInterfaceEndpointHandle handle, MessageReceiverWithResponderStatus* receiver, - scoped_ptr<MessageFilter> payload_validator, - bool expect_sync_requests) + std::unique_ptr<MessageFilter> payload_validator, + bool expect_sync_requests, + scoped_refptr<base::SingleThreadTaskRunner> runner) : handle_(std::move(handle)), incoming_receiver_(receiver), payload_validator_(std::move(payload_validator)), thunk_(this), next_request_id_(1), encountered_error_(false), + task_runner_(std::move(runner)), weak_ptr_factory_(this) { DCHECK(handle_.is_valid()); DCHECK(handle_.is_local()); @@ -142,7 +150,8 @@ InterfaceEndpointClient::InterfaceEndpointClient( // directly is a little awkward. payload_validator_->set_sink(&thunk_); - controller_ = handle_.router()->AttachEndpointClient(handle_, this); + controller_ = + handle_.router()->AttachEndpointClient(handle_, this, task_runner_); if (expect_sync_requests) controller_->AllowWokenUpBySyncWatchOnSameThread(); } @@ -210,19 +219,20 @@ bool InterfaceEndpointClient::AcceptWithResponder(Message* message, message->set_request_id(request_id); + bool is_sync = message->has_flag(kMessageIsSync); if (!controller_->SendMessage(message)) return false; - if (!message->has_flag(kMessageIsSync)) { + if (!is_sync) { // We assume ownership of |responder|. - async_responders_[request_id] = make_scoped_ptr(responder); + async_responders_[request_id] = base::WrapUnique(responder); return true; } bool response_received = false; - scoped_ptr<MessageReceiver> sync_responder(responder); + std::unique_ptr<MessageReceiver> sync_responder(responder); sync_responses_.insert(std::make_pair( - request_id, make_scoped_ptr(new SyncResponseInfo(&response_received)))); + request_id, base::WrapUnique(new SyncResponseInfo(&response_received)))); base::WeakPtr<InterfaceEndpointClient> weak_self = weak_ptr_factory_.GetWeakPtr(); @@ -233,7 +243,7 @@ bool InterfaceEndpointClient::AcceptWithResponder(Message* message, auto iter = sync_responses_.find(request_id); DCHECK_EQ(&response_received, iter->second->response_received); if (response_received) { - scoped_ptr<Message> response = std::move(iter->second->response); + std::unique_ptr<Message> response = std::move(iter->second->response); ignore_result(sync_responder->Accept(response.get())); } sync_responses_.erase(iter); @@ -266,7 +276,7 @@ bool InterfaceEndpointClient::HandleValidatedMessage(Message* message) { return false; MessageReceiverWithStatus* responder = - new ResponderThunk(weak_ptr_factory_.GetWeakPtr()); + new ResponderThunk(weak_ptr_factory_.GetWeakPtr(), task_runner_); bool ok = incoming_receiver_->AcceptWithResponder(message, responder); if (!ok) delete responder; @@ -287,7 +297,7 @@ bool InterfaceEndpointClient::HandleValidatedMessage(Message* message) { auto it = async_responders_.find(request_id); if (it == async_responders_.end()) return false; - scoped_ptr<MessageReceiver> responder = std::move(it->second); + std::unique_ptr<MessageReceiver> responder = std::move(it->second); async_responders_.erase(it); return responder->Accept(message); } else { diff --git a/chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.h b/chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.h index 2560cfc42dc..3f820db3c30 100644 --- a/chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.h +++ b/chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.h @@ -8,16 +8,18 @@ #include <stdint.h> #include <map> +#include <memory> #include "base/logging.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.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/callback.h" -#include "mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.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 { @@ -37,8 +39,9 @@ class InterfaceEndpointClient : public MessageReceiverWithResponder { // object. InterfaceEndpointClient(ScopedInterfaceEndpointHandle handle, MessageReceiverWithResponderStatus* receiver, - scoped_ptr<MessageFilter> payload_validator, - bool expect_sync_requests); + std::unique_ptr<MessageFilter> payload_validator, + bool expect_sync_requests, + scoped_refptr<base::SingleThreadTaskRunner> runner); ~InterfaceEndpointClient() override; // Sets the error handler to receive notifications when an error is @@ -86,14 +89,15 @@ class InterfaceEndpointClient : public MessageReceiverWithResponder { private: // Maps from the id of a response to the MessageReceiver that handles the // response. - using AsyncResponderMap = std::map<uint64_t, scoped_ptr<MessageReceiver>>; + using AsyncResponderMap = + std::map<uint64_t, std::unique_ptr<MessageReceiver>>; struct SyncResponseInfo { public: explicit SyncResponseInfo(bool* in_response_received); ~SyncResponseInfo(); - scoped_ptr<Message> response; + std::unique_ptr<Message> response; // Points to a stack-allocated variable. bool* response_received; @@ -102,7 +106,7 @@ class InterfaceEndpointClient : public MessageReceiverWithResponder { DISALLOW_COPY_AND_ASSIGN(SyncResponseInfo); }; - using SyncResponseMap = std::map<uint64_t, scoped_ptr<SyncResponseInfo>>; + using SyncResponseMap = std::map<uint64_t, std::unique_ptr<SyncResponseInfo>>; // Used as the sink for |payload_validator_| and forwards messages to // HandleValidatedMessage(). @@ -123,11 +127,11 @@ class InterfaceEndpointClient : public MessageReceiverWithResponder { bool HandleValidatedMessage(Message* message); ScopedInterfaceEndpointHandle handle_; - scoped_ptr<AssociatedGroup> associated_group_; + std::unique_ptr<AssociatedGroup> associated_group_; InterfaceEndpointController* controller_; MessageReceiverWithResponderStatus* const incoming_receiver_; - scoped_ptr<MessageFilter> payload_validator_; + std::unique_ptr<MessageFilter> payload_validator_; HandleIncomingMessageThunk thunk_; AsyncResponderMap async_responders_; @@ -138,6 +142,8 @@ class InterfaceEndpointClient : public MessageReceiverWithResponder { Closure error_handler_; bool encountered_error_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + base::ThreadChecker thread_checker_; base::WeakPtrFactory<InterfaceEndpointClient> weak_ptr_factory_; diff --git a/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.h b/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.h index 3f7d938e2dd..8cda57d2bdf 100644 --- a/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.h +++ b/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.h @@ -6,13 +6,16 @@ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_ #include <stdint.h> + #include <algorithm> // For |std::swap()|. +#include <memory> #include <utility> #include "base/logging.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" +#include "base/single_thread_task_runner.h" #include "mojo/public/cpp/bindings/associated_group.h" #include "mojo/public/cpp/bindings/callback.h" #include "mojo/public/cpp/bindings/interface_ptr_info.h" @@ -23,7 +26,7 @@ #include "mojo/public/cpp/bindings/lib/message_header_validator.h" #include "mojo/public/cpp/bindings/lib/multiplex_router.h" #include "mojo/public/cpp/bindings/lib/router.h" -#include "mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h" +#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" namespace mojo { namespace internal { @@ -89,10 +92,12 @@ class InterfacePtrState<Interface, false> { 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) { + void Bind(InterfacePtrInfo<Interface> info, + scoped_refptr<base::SingleThreadTaskRunner> runner) { DCHECK(!proxy_); DCHECK(!router_); DCHECK(!handle_.is_valid()); @@ -101,6 +106,7 @@ class InterfacePtrState<Interface, false> { handle_ = info.PassHandle(); version_ = info.version(); + runner_ = std::move(runner); } bool HasAssociatedInterfaces() const { return false; } @@ -161,7 +167,8 @@ class InterfacePtrState<Interface, false> { filters.Append<MessageHeaderValidator>(); filters.Append<typename Interface::ResponseValidator_>(); - router_ = new Router(std::move(handle_), std::move(filters), false); + router_ = new Router(std::move(handle_), std::move(filters), false, + std::move(runner_)); proxy_ = new Proxy(router_); } @@ -173,6 +180,7 @@ class InterfacePtrState<Interface, false> { // 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_; @@ -236,10 +244,12 @@ class InterfacePtrState<Interface, true> { swap(other->endpoint_client_, endpoint_client_); swap(other->proxy_, proxy_); handle_.swap(other->handle_); + runner_.swap(other->runner_); swap(other->version_, version_); } - void Bind(InterfacePtrInfo<Interface> info) { + void Bind(InterfacePtrInfo<Interface> info, + scoped_refptr<base::SingleThreadTaskRunner> runner) { DCHECK(!router_); DCHECK(!endpoint_client_); DCHECK(!proxy_); @@ -249,6 +259,7 @@ class InterfacePtrState<Interface, true> { handle_ = info.PassHandle(); version_ = info.version(); + runner_ = std::move(runner); } bool HasAssociatedInterfaces() const { @@ -313,23 +324,25 @@ class InterfacePtrState<Interface, true> { if (!handle_.is_valid()) return; - router_ = new MultiplexRouter(true, std::move(handle_)); + router_ = new MultiplexRouter(true, std::move(handle_), runner_); endpoint_client_.reset(new InterfaceEndpointClient( router_->CreateLocalEndpointHandle(kMasterInterfaceId), nullptr, - make_scoped_ptr(new typename Interface::ResponseValidator_()), false)); + base::WrapUnique(new typename Interface::ResponseValidator_()), false, + std::move(runner_))); proxy_.reset(new Proxy(endpoint_client_.get())); proxy_->serialization_context()->router = endpoint_client_->router(); } scoped_refptr<MultiplexRouter> router_; - scoped_ptr<InterfaceEndpointClient> endpoint_client_; - scoped_ptr<Proxy> proxy_; + std::unique_ptr<InterfaceEndpointClient> endpoint_client_; + std::unique_ptr<Proxy> proxy_; // |router_| (as well as other members above) is not initialized until // read/write with the message pipe handle is needed. |handle_| is valid // between the Bind() call and the initialization of |router_|. ScopedMessagePipeHandle handle_; + scoped_refptr<base::SingleThreadTaskRunner> runner_; uint32_t version_; diff --git a/chromium/mojo/public/cpp/bindings/lib/macros.h b/chromium/mojo/public/cpp/bindings/lib/macros.h deleted file mode 100644 index 62f4292c1ee..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/macros.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_MACROS_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MACROS_H_ - -// This file defines macros that are only used by generated bindings. - -// The C++ standard requires that static const members have an out-of-class -// definition (in a single compilation unit), but MSVC chokes on this (when -// language extensions, which are required, are enabled). (You're only likely to -// notice the need for a definition if you take the address of the member or, -// more commonly, pass it to a function that takes it as a reference argument -- -// probably an STL function.) This macro makes MSVC do the right thing. See -// http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx for more -// information. This workaround does not appear to be necessary after VS2015. -// Use like: -// -// In the .h file: -// struct Foo { -// static const int kBar = 5; -// }; -// -// In the .cc file: -// MOJO_STATIC_CONST_MEMBER_DEFINITION const int Foo::kBar; -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define MOJO_STATIC_CONST_MEMBER_DEFINITION __declspec(selectany) -#else -#define MOJO_STATIC_CONST_MEMBER_DEFINITION -#endif - -#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MACROS_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/map_data_internal.h b/chromium/mojo/public/cpp/bindings/lib/map_data_internal.h index 8315dbc8e10..a5363617817 100644 --- a/chromium/mojo/public/cpp/bindings/lib/map_data_internal.h +++ b/chromium/mojo/public/cpp/bindings/lib/map_data_internal.h @@ -113,17 +113,17 @@ class Map_Data { StructHeader header_; - ArrayPointer<Key> keys; - ArrayPointer<Value> values; + Pointer<Array_Data<Key>> keys; + Pointer<Array_Data<Value>> values; - void EncodePointersAndHandles(std::vector<mojo::Handle>* handles) { - Encode(&keys, handles); - Encode(&values, handles); + void EncodePointers() { + Encode(&keys); + Encode(&values); } - void DecodePointersAndHandles(std::vector<mojo::Handle>* handles) { - Decode(&keys, handles); - Decode(&values, handles); + void DecodePointers() { + Decode(&keys); + Decode(&values); } private: diff --git a/chromium/mojo/public/cpp/bindings/lib/map_serialization.h b/chromium/mojo/public/cpp/bindings/lib/map_serialization.h index bca23796bba..56ef68d3162 100644 --- a/chromium/mojo/public/cpp/bindings/lib/map_serialization.h +++ b/chromium/mojo/public/cpp/bindings/lib/map_serialization.h @@ -5,191 +5,115 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_MAP_SERIALIZATION_H_ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_MAP_SERIALIZATION_H_ -#include <stddef.h> -#include <utility> - -#include "mojo/public/cpp/bindings/lib/array_internal.h" +#include "mojo/public/cpp/bindings/array.h" #include "mojo/public/cpp/bindings/lib/map_data_internal.h" -#include "mojo/public/cpp/bindings/lib/map_internal.h" #include "mojo/public/cpp/bindings/lib/serialization_forward.h" #include "mojo/public/cpp/bindings/map.h" namespace mojo { namespace internal { -template <typename MapType, - typename DataType, - bool value_is_move_only_type = IsMoveOnlyType<MapType>::value, - bool is_union = - IsUnionDataType<typename RemovePointer<DataType>::type>::value> -struct MapSerializer; - -template <typename MapType, typename DataType> -struct MapSerializer<MapType, DataType, false, false> { - static size_t GetBaseArraySize(size_t count) { - return Align(count * sizeof(DataType)); - } - static size_t GetItemSize(const MapType& item, - SerializationContext* context) { - return 0; - } -}; - -template <> -struct MapSerializer<bool, bool, false, false> { - static size_t GetBaseArraySize(size_t count) { - return Align((count + 7) / 8); - } - static size_t GetItemSize(bool item, SerializationContext* context) { - return 0; - } -}; - -template <typename H> -struct MapSerializer<ScopedHandleBase<H>, H, true, false> { - static size_t GetBaseArraySize(size_t count) { - return Align(count * sizeof(H)); - } - static size_t GetItemSize(const ScopedHandleBase<H>& item, - SerializationContext* context) { - return 0; - } -}; - -// This template must only apply to pointer mojo entity (structs and arrays). -// This is done by ensuring that WrapperTraits<S>::DataType is a pointer. -template <typename S> -struct MapSerializer< - S, - typename EnableIf<IsPointer<typename WrapperTraits<S>::DataType>::value, - typename WrapperTraits<S>::DataType>::type, - true, - false> { - typedef - typename RemovePointer<typename WrapperTraits<S>::DataType>::type S_Data; - static size_t GetBaseArraySize(size_t count) { - return count * sizeof(StructPointer<S_Data>); - } - static size_t GetItemSize(const S& item, SerializationContext* context) { - return GetSerializedSize_(item, context); - } -}; +template <typename Key, typename Value> +struct MapContext { + explicit MapContext(bool in_is_null) : is_null(in_is_null) {} -template <typename U, typename U_Data> -struct MapSerializer<U, U_Data*, true, true> { - static size_t GetBaseArraySize(size_t count) { - return count * sizeof(U_Data); - } - static size_t GetItemSize(const U& item, SerializationContext* context) { - return GetSerializedSize_(item, true, context); - } + bool is_null; + Array<Key> keys; + Array<Value> values; }; -template <> -struct MapSerializer<String, String_Data*, false, false> { - static size_t GetBaseArraySize(size_t count) { - return count * sizeof(StringPointer); +template <typename Key, typename Value, typename MaybeConstUserType> +struct Serializer<Map<Key, Value>, MaybeConstUserType> { + using UserType = typename std::remove_const<MaybeConstUserType>::type; + using UserKey = typename UserType::Key; + using UserValue = typename UserType::Value; + using Data = typename Map<Key, Value>::Data_; + + static_assert(std::is_same<MaybeConstUserType, UserType>::value, + "Only support serialization of non-const Maps."); + static_assert(IsSpecializationOf<Map, UserType>::value, + "Custom mapping of mojom map is not supported yet."); + + static size_t PrepareToSerialize(UserType& input, + SerializationContext* context) { + auto map_context = new MapContext<UserKey, UserValue>(input.is_null()); + if (!context->custom_contexts) + context->custom_contexts.reset(new std::queue<void*>()); + context->custom_contexts->push(map_context); + + if (!input) + return 0; + + input.DecomposeMapTo(&map_context->keys, &map_context->values); + + size_t struct_overhead = sizeof(Data); + size_t keys_size = + internal::PrepareToSerialize<Array<Key>>(map_context->keys, context); + size_t values_size = internal::PrepareToSerialize<Array<Value>>( + map_context->values, context); + + return struct_overhead + keys_size + values_size; } - static size_t GetItemSize(const String& item, SerializationContext* context) { - return GetSerializedSize_(item, context); - } -}; - -} // namespace internal -// TODO(erg): This can't go away yet. We still need to calculate out the size -// of a struct header, and two arrays. -template <typename MapKey, typename MapValue> -inline size_t GetSerializedSize_(const Map<MapKey, MapValue>& input, - internal::SerializationContext* context) { - if (!input) - return 0; - typedef typename internal::WrapperTraits<MapKey>::DataType DataKey; - typedef typename internal::WrapperTraits<MapValue>::DataType DataValue; - - size_t count = input.size(); - size_t struct_overhead = sizeof(mojo::internal::Map_Data<DataKey, DataValue>); - size_t key_base_size = - sizeof(internal::ArrayHeader) + - internal::MapSerializer<MapKey, DataKey>::GetBaseArraySize(count); - size_t value_base_size = - sizeof(internal::ArrayHeader) + - internal::MapSerializer<MapValue, DataValue>::GetBaseArraySize(count); - - size_t key_data_size = 0; - size_t value_data_size = 0; - for (auto it = input.begin(); it != input.end(); ++it) { - key_data_size += internal::MapSerializer<MapKey, DataKey>::GetItemSize( - it->first, context); - value_data_size += - internal::MapSerializer<MapValue, DataValue>::GetItemSize(it->second, - context); - } + // We don't need an ArrayValidateParams instance for key validation since + // we can deduce it from the Key type. (which can only be primitive types or + // non-nullable strings.) + static void Serialize(UserType& input, + Buffer* buf, + Data** output, + const ArrayValidateParams* value_validate_params, + SerializationContext* context) { + std::unique_ptr<MapContext<UserKey, UserValue>> map_context( + static_cast<MapContext<UserKey, UserValue>*>( + context->custom_contexts->front())); + context->custom_contexts->pop(); + + if (map_context->is_null) { + *output = nullptr; + return; + } - return struct_overhead + key_base_size + key_data_size + value_base_size + - value_data_size; -} - -// We don't need an ArrayValidateParams instance for key validation since -// we can deduce it from the Key type. (which can only be primitive types or -// non-nullable strings.) -template <typename MapKey, - typename MapValue, - typename DataKey, - typename DataValue> -inline void SerializeMap_( - Map<MapKey, MapValue> input, - internal::Buffer* buf, - internal::Map_Data<DataKey, DataValue>** output, - const internal::ArrayValidateParams* value_validate_params, - internal::SerializationContext* context) { - if (input) { - internal::Map_Data<DataKey, DataValue>* result = - internal::Map_Data<DataKey, DataValue>::New(buf); + auto result = Data::New(buf); if (result) { - Array<MapKey> keys; - Array<MapValue> values; - input.DecomposeMapTo(&keys, &values); - const internal::ArrayValidateParams* key_validate_params = - internal::MapKeyValidateParamsFactory<DataKey>::Get(); - SerializeArray_(std::move(keys), buf, &result->keys.ptr, - key_validate_params, context); - SerializeArray_(std::move(values), buf, &result->values.ptr, - value_validate_params, context); + const ArrayValidateParams* key_validate_params = + MapKeyValidateParamsFactory< + typename GetDataTypeAsArrayElement<Key>::Data>::Get(); + internal::Serialize<Array<Key>>(map_context->keys, buf, &result->keys.ptr, + key_validate_params, context); + internal::Serialize<Array<Value>>(map_context->values, buf, + &result->values.ptr, + value_validate_params, context); } *output = result; - } else { - *output = nullptr; } -} - -template <typename MapKey, - typename MapValue, - typename DataKey, - typename DataValue> -inline bool Deserialize_(internal::Map_Data<DataKey, DataValue>* input, - Map<MapKey, MapValue>* output, - internal::SerializationContext* context) { - bool success = true; - if (input) { - Array<MapKey> keys; - Array<MapValue> values; - - // Note that we rely on complete deserialization taking place in order to - // transfer ownership of all encoded handles. Therefore we don't - // short-circuit on failure here. - if (!Deserialize_(input->keys.ptr, &keys, context)) - success = false; - if (!Deserialize_(input->values.ptr, &values, context)) - success = false; - - *output = Map<MapKey, MapValue>(std::move(keys), std::move(values)); - } else { - *output = nullptr; + + static bool Deserialize(Data* input, + UserType* output, + SerializationContext* context) { + bool success = true; + if (input) { + Array<UserKey> keys; + Array<UserValue> values; + + // Note that we rely on complete deserialization taking place in order to + // transfer ownership of all encoded handles. Therefore we don't + // short-circuit on failure here. + if (!internal::Deserialize<Array<Key>>(input->keys.ptr, &keys, context)) + success = false; + if (!internal::Deserialize<Array<Value>>(input->values.ptr, &values, + context)) { + success = false; + } + + *output = UserType(std::move(keys), std::move(values)); + } else { + *output = nullptr; + } + return success; } - return success; -} +}; +} // namespace internal } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MAP_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/message.cc b/chromium/mojo/public/cpp/bindings/lib/message.cc index e1e8f190df9..4274cc86cb1 100644 --- a/chromium/mojo/public/cpp/bindings/lib/message.cc +++ b/chromium/mojo/public/cpp/bindings/lib/message.cc @@ -9,6 +9,7 @@ #include <stdlib.h> #include <algorithm> +#include <utility> #include "base/logging.h" @@ -23,7 +24,15 @@ Message::~Message() { void Message::Initialize(size_t capacity, bool zero_initialized) { DCHECK(!buffer_); - buffer_.reset(new internal::PickleBuffer(capacity, zero_initialized)); + buffer_.reset(new internal::MessageBuffer(capacity, zero_initialized)); +} + +void Message::InitializeFromMojoMessage(ScopedMessageHandle message, + uint32_t num_bytes, + std::vector<Handle>* handles) { + DCHECK(!buffer_); + buffer_.reset(new internal::MessageBuffer(std::move(message), num_bytes)); + handles_.swap(*handles); } void Message::MoveTo(Message* destination) { @@ -38,6 +47,37 @@ void Message::MoveTo(Message* destination) { buffer_.reset(); } +ScopedMessageHandle Message::TakeMojoMessage() { + if (handles_.empty()) // Fast path for the common case: No handles. + return buffer_->TakeMessage(); + + // Allocate a new message with space for the handles, then copy the buffer + // contents into it. + // + // TODO(rockot): We could avoid this copy by extending GetSerializedSize() + // behavior to collect handles. It's unoptimized for now because it's much + // more common to have messages with no handles. + ScopedMessageHandle new_message; + MojoResult rv = AllocMessage( + data_num_bytes(), + handles_.empty() ? nullptr + : reinterpret_cast<const MojoHandle*>(handles_.data()), + handles_.size(), + MOJO_ALLOC_MESSAGE_FLAG_NONE, + &new_message); + CHECK_EQ(rv, MOJO_RESULT_OK); + handles_.clear(); + + void* new_buffer = nullptr; + rv = GetMessageBuffer(new_message.get(), &new_buffer); + CHECK_EQ(rv, MOJO_RESULT_OK); + + memcpy(new_buffer, data(), data_num_bytes()); + buffer_.reset(); + + return new_message; +} + void Message::CloseHandles() { for (std::vector<Handle>::iterator it = handles_.begin(); it != handles_.end(); ++it) { @@ -49,28 +89,32 @@ void Message::CloseHandles() { MojoResult ReadMessage(MessagePipeHandle handle, Message* message) { MojoResult rv; + std::vector<Handle> handles; + ScopedMessageHandle mojo_message; uint32_t num_bytes = 0, num_handles = 0; - rv = ReadMessageRaw(handle, - nullptr, + rv = ReadMessageNew(handle, + &mojo_message, &num_bytes, nullptr, &num_handles, MOJO_READ_MESSAGE_FLAG_NONE); - if (rv != MOJO_RESULT_RESOURCE_EXHAUSTED) - return rv; - - message->Initialize(num_bytes, false /* zero_initialized */); + if (rv == MOJO_RESULT_RESOURCE_EXHAUSTED) { + DCHECK_GT(num_handles, 0u); + handles.resize(num_handles); + rv = ReadMessageNew(handle, + &mojo_message, + &num_bytes, + reinterpret_cast<MojoHandle*>(handles.data()), + &num_handles, + MOJO_READ_MESSAGE_FLAG_NONE); + } - void* mutable_data = message->buffer()->Allocate(num_bytes); - message->mutable_handles()->resize(num_handles); + if (rv != MOJO_RESULT_OK) + return rv; - rv = ReadMessageRaw( - handle, mutable_data, &num_bytes, - message->mutable_handles()->empty() - ? nullptr - : reinterpret_cast<MojoHandle*>(message->mutable_handles()->data()), - &num_handles, MOJO_READ_MESSAGE_FLAG_NONE); - return rv; + message->InitializeFromMojoMessage( + std::move(mojo_message), num_bytes, &handles); + return MOJO_RESULT_OK; } } // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/message_buffer.cc b/chromium/mojo/public/cpp/bindings/lib/message_buffer.cc new file mode 100644 index 00000000000..7a153647f8f --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message_buffer.cc @@ -0,0 +1,65 @@ +// 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/message_buffer.h" + +#include <limits> + +#include "mojo/public/cpp/bindings/lib/serialization_util.h" + +namespace mojo { +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); + + if (capacity == 0) { + buffer_ = nullptr; + } else { + rv = GetMessageBuffer(message_.get(), &buffer_); + CHECK_EQ(rv, MOJO_RESULT_OK); + + if (zero_initialized) + memset(buffer_, 0, capacity); + } +} + +MessageBuffer::MessageBuffer(ScopedMessageHandle message, uint32_t num_bytes) { + message_ = std::move(message); + data_num_bytes_ = num_bytes; + + if (num_bytes == 0) { + buffer_ = nullptr; + } else { + MojoResult rv = GetMessageBuffer(message_.get(), &buffer_); + CHECK_EQ(rv, MOJO_RESULT_OK); + } +} + +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); +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/message_buffer.h b/chromium/mojo/public/cpp/bindings/lib/message_buffer.h new file mode 100644 index 00000000000..47ffea01514 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message_buffer.h @@ -0,0 +1,52 @@ +// 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_MESSAGE_LIB_MESSAGE_BUFFER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_LIB_MESSAGE_BUFFER_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <utility> + +#include "base/macros.h" +#include "mojo/public/cpp/bindings/lib/buffer.h" +#include "mojo/public/cpp/system/message.h" + +namespace mojo { +namespace internal { + +// 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. + MessageBuffer(size_t capacity, bool zero_initialized); + + // Initializes this buffer from an existing Mojo MessageHandle. + MessageBuffer(ScopedMessageHandle message, uint32_t num_bytes); + + ~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_); } + + private: + uint32_t data_num_bytes_ = 0; + ScopedMessageHandle message_; + void* buffer_; + + uint32_t bytes_claimed_ = 0; + + DISALLOW_COPY_AND_ASSIGN(MessageBuffer); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_LIB_MESSAGE_BUFFER_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/message_builder.cc b/chromium/mojo/public/cpp/bindings/lib/message_builder.cc index 428fa91fda1..4ffa1808cc9 100644 --- a/chromium/mojo/public/cpp/bindings/lib/message_builder.cc +++ b/chromium/mojo/public/cpp/bindings/lib/message_builder.cc @@ -7,7 +7,7 @@ #include <stddef.h> #include <stdint.h> -#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" +#include "mojo/public/cpp/bindings/lib/serialization_util.h" #include "mojo/public/cpp/bindings/message.h" namespace mojo { diff --git a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc index 75d14467e5a..d081b0155ba 100644 --- a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc +++ b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc @@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" @@ -64,12 +65,14 @@ class MultiplexRouter::InterfaceEndpoint InterfaceEndpointClient* client() const { return client_; } - void AttachClient(InterfaceEndpointClient* client) { + void AttachClient(InterfaceEndpointClient* client, + scoped_refptr<base::SingleThreadTaskRunner> runner) { router_->lock_.AssertAcquired(); DCHECK(!client_); DCHECK(!closed_); + DCHECK(runner->BelongsToCurrentThread()); - task_runner_ = base::MessageLoop::current()->task_runner(); + task_runner_ = std::move(runner); client_ = client; } @@ -241,7 +244,7 @@ class MultiplexRouter::InterfaceEndpoint // used exclusively on the client's thread. They may be accessed outside of // the router's lock. - scoped_ptr<SyncHandleWatcher> sync_watcher_; + std::unique_ptr<SyncHandleWatcher> sync_watcher_; DISALLOW_COPY_AND_ASSIGN(InterfaceEndpoint); }; @@ -249,16 +252,17 @@ class MultiplexRouter::InterfaceEndpoint struct MultiplexRouter::Task { public: // Doesn't take ownership of |message| but takes its contents. - static scoped_ptr<Task> CreateMessageTask(Message* message) { + static std::unique_ptr<Task> CreateMessageTask(Message* message) { Task* task = new Task(MESSAGE); task->message.reset(new Message); message->MoveTo(task->message.get()); - return make_scoped_ptr(task); + return base::WrapUnique(task); } - static scoped_ptr<Task> CreateNotifyErrorTask(InterfaceEndpoint* endpoint) { + static std::unique_ptr<Task> CreateNotifyErrorTask( + InterfaceEndpoint* endpoint) { Task* task = new Task(NOTIFY_ERROR); task->endpoint_to_notify = endpoint; - return make_scoped_ptr(task); + return base::WrapUnique(task); } ~Task() {} @@ -266,7 +270,7 @@ struct MultiplexRouter::Task { bool IsMessageTask() const { return type == MESSAGE; } bool IsNotifyErrorTask() const { return type == NOTIFY_ERROR; } - scoped_ptr<Message> message; + std::unique_ptr<Message> message; scoped_refptr<InterfaceEndpoint> endpoint_to_notify; enum Type { MESSAGE, NOTIFY_ERROR }; @@ -276,13 +280,17 @@ struct MultiplexRouter::Task { explicit Task(Type in_type) : type(in_type) {} }; -MultiplexRouter::MultiplexRouter(bool set_interface_id_namesapce_bit, - ScopedMessagePipeHandle message_pipe) +MultiplexRouter::MultiplexRouter( + bool set_interface_id_namesapce_bit, + ScopedMessagePipeHandle message_pipe, + scoped_refptr<base::SingleThreadTaskRunner> runner) : RefCountedDeleteOnMessageLoop( base::MessageLoop::current()->task_runner()), set_interface_id_namespace_bit_(set_interface_id_namesapce_bit), header_validator_(this), - connector_(std::move(message_pipe), Connector::MULTI_THREADED_SEND), + connector_(std::move(message_pipe), + Connector::MULTI_THREADED_SEND, + std::move(runner)), control_message_handler_(this), control_message_proxy_(&connector_), next_interface_id_value_(1), @@ -384,12 +392,13 @@ void MultiplexRouter::CloseEndpointHandle(InterfaceId id, bool is_local) { if (!IsMasterInterfaceId(id)) control_message_proxy_.NotifyPeerEndpointClosed(id); - ProcessTasks(NO_DIRECT_CLIENT_CALLS); + ProcessTasks(NO_DIRECT_CLIENT_CALLS, nullptr); } InterfaceEndpointController* MultiplexRouter::AttachEndpointClient( const ScopedInterfaceEndpointHandle& handle, - InterfaceEndpointClient* client) { + InterfaceEndpointClient* client, + scoped_refptr<base::SingleThreadTaskRunner> runner) { const InterfaceId id = handle.id(); DCHECK(IsValidInterfaceId(id)); @@ -399,11 +408,11 @@ InterfaceEndpointController* MultiplexRouter::AttachEndpointClient( DCHECK(ContainsKey(endpoints_, id)); InterfaceEndpoint* endpoint = endpoints_[id].get(); - endpoint->AttachClient(client); + endpoint->AttachClient(client, std::move(runner)); if (endpoint->peer_closed()) tasks_.push_back(Task::CreateNotifyErrorTask(endpoint)); - ProcessTasks(NO_DIRECT_CLIENT_CALLS); + ProcessTasks(NO_DIRECT_CLIENT_CALLS, nullptr); return endpoint; } @@ -430,8 +439,8 @@ void MultiplexRouter::RaiseError() { } } -scoped_ptr<AssociatedGroup> MultiplexRouter::CreateAssociatedGroup() { - scoped_ptr<AssociatedGroup> group(new AssociatedGroup); +std::unique_ptr<AssociatedGroup> MultiplexRouter::CreateAssociatedGroup() { + std::unique_ptr<AssociatedGroup> group(new AssociatedGroup); group->router_ = this; return group; } @@ -482,7 +491,8 @@ bool MultiplexRouter::Accept(Message* message) { : ALLOW_DIRECT_CLIENT_CALLS; bool processed = - tasks_.empty() && ProcessIncomingMessage(message, client_call_behavior); + tasks_.empty() && ProcessIncomingMessage(message, client_call_behavior, + connector_.task_runner()); if (!processed) { // Either the task queue is not empty or we cannot process the message @@ -501,7 +511,7 @@ bool MultiplexRouter::Accept(Message* message) { // Processing the message may result in new tasks (for error notification) // being added to the queue. In this case, we have to attempt to process the // tasks. - ProcessTasks(client_call_behavior); + ProcessTasks(client_call_behavior, connector_.task_runner()); } // Always return true. If we see errors during message processing, we will @@ -564,17 +574,20 @@ void MultiplexRouter::OnPipeConnectionError() { ProcessTasks(connector_.during_sync_handle_watcher_callback() ? ALLOW_DIRECT_CLIENT_CALLS_FOR_SYNC_MESSAGES - : ALLOW_DIRECT_CLIENT_CALLS); + : ALLOW_DIRECT_CLIENT_CALLS, + connector_.task_runner()); } -void MultiplexRouter::ProcessTasks(ClientCallBehavior client_call_behavior) { +void MultiplexRouter::ProcessTasks( + ClientCallBehavior client_call_behavior, + base::SingleThreadTaskRunner* current_task_runner) { lock_.AssertAcquired(); if (posted_to_process_tasks_) return; while (!tasks_.empty()) { - scoped_ptr<Task> task(std::move(tasks_.front())); + std::unique_ptr<Task> task(std::move(tasks_.front())); tasks_.pop_front(); InterfaceId id = kInvalidInterfaceId; @@ -589,8 +602,10 @@ void MultiplexRouter::ProcessTasks(ClientCallBehavior client_call_behavior) { bool processed = task->IsNotifyErrorTask() - ? ProcessNotifyErrorTask(task.get(), client_call_behavior) - : ProcessIncomingMessage(task->message.get(), client_call_behavior); + ? ProcessNotifyErrorTask(task.get(), client_call_behavior, + current_task_runner) + : ProcessIncomingMessage(task->message.get(), client_call_behavior, + current_task_runner); if (!processed) { tasks_.push_front(std::move(task)); @@ -620,11 +635,11 @@ bool MultiplexRouter::ProcessFirstSyncMessageForEndpoint(InterfaceId id) { iter->second.pop_front(); DCHECK(task->IsMessageTask()); - scoped_ptr<Message> message(std::move(task->message)); + std::unique_ptr<Message> message(std::move(task->message)); // Note: after this call, |task| and |iter| may be invalidated. bool processed = ProcessIncomingMessage( - message.get(), ALLOW_DIRECT_CLIENT_CALLS_FOR_SYNC_MESSAGES); + message.get(), ALLOW_DIRECT_CLIENT_CALLS_FOR_SYNC_MESSAGES, nullptr); DCHECK(processed); iter = sync_message_tasks_.find(id); @@ -633,18 +648,22 @@ bool MultiplexRouter::ProcessFirstSyncMessageForEndpoint(InterfaceId id) { bool MultiplexRouter::ProcessNotifyErrorTask( Task* task, - ClientCallBehavior client_call_behavior) { + ClientCallBehavior client_call_behavior, + base::SingleThreadTaskRunner* current_task_runner) { + DCHECK(!current_task_runner || current_task_runner->BelongsToCurrentThread()); lock_.AssertAcquired(); InterfaceEndpoint* endpoint = task->endpoint_to_notify.get(); if (!endpoint->client()) return true; - if (!endpoint->task_runner()->BelongsToCurrentThread() || - client_call_behavior != ALLOW_DIRECT_CLIENT_CALLS) { + if (client_call_behavior != ALLOW_DIRECT_CLIENT_CALLS || + endpoint->task_runner() != current_task_runner) { MaybePostToProcessTasks(endpoint->task_runner()); return false; } + DCHECK(endpoint->task_runner()->BelongsToCurrentThread()); + InterfaceEndpointClient* client = endpoint->client(); { // We must unlock before calling into |client| because it may call this @@ -660,7 +679,9 @@ bool MultiplexRouter::ProcessNotifyErrorTask( bool MultiplexRouter::ProcessIncomingMessage( Message* message, - ClientCallBehavior client_call_behavior) { + ClientCallBehavior client_call_behavior, + base::SingleThreadTaskRunner* current_task_runner) { + DCHECK(!current_task_runner || current_task_runner->BelongsToCurrentThread()); lock_.AssertAcquired(); if (!message) { @@ -703,16 +724,22 @@ bool MultiplexRouter::ProcessIncomingMessage( return false; } - bool can_direct_call = - (client_call_behavior == ALLOW_DIRECT_CLIENT_CALLS) || - (client_call_behavior == ALLOW_DIRECT_CLIENT_CALLS_FOR_SYNC_MESSAGES && - message->has_flag(kMessageIsSync)); + bool can_direct_call; + if (message->has_flag(kMessageIsSync)) { + can_direct_call = client_call_behavior != NO_DIRECT_CLIENT_CALLS && + endpoint->task_runner()->BelongsToCurrentThread(); + } else { + can_direct_call = client_call_behavior == ALLOW_DIRECT_CLIENT_CALLS && + endpoint->task_runner() == current_task_runner; + } - if (!endpoint->task_runner()->BelongsToCurrentThread() || !can_direct_call) { + if (!can_direct_call) { MaybePostToProcessTasks(endpoint->task_runner()); return false; } + DCHECK(endpoint->task_runner()->BelongsToCurrentThread()); + InterfaceEndpointClient* client = endpoint->client(); bool result = false; { @@ -738,6 +765,7 @@ void MultiplexRouter::MaybePostToProcessTasks( return; posted_to_process_tasks_ = true; + posted_to_task_runner_ = task_runner; task_runner->PostTask( FROM_HERE, base::Bind(&MultiplexRouter::LockAndCallProcessTasks, this)); } @@ -747,7 +775,9 @@ void MultiplexRouter::LockAndCallProcessTasks() { // always called using base::Bind(), which holds a ref. base::AutoLock locker(lock_); posted_to_process_tasks_ = false; - ProcessTasks(ALLOW_DIRECT_CLIENT_CALLS); + scoped_refptr<base::SingleThreadTaskRunner> runner( + std::move(posted_to_task_runner_)); + ProcessTasks(ALLOW_DIRECT_CLIENT_CALLS, runner.get()); } void MultiplexRouter::UpdateEndpointStateMayRemove( diff --git a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h index e9cd35b9c9b..c348c7d8954 100644 --- a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h +++ b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h @@ -9,13 +9,14 @@ #include <deque> #include <map> +#include <memory> #include "base/logging.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/ref_counted_delete_on_message_loop.h" -#include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" #include "base/synchronization/lock.h" #include "base/threading/thread_checker.h" #include "mojo/public/cpp/bindings/callback.h" @@ -25,7 +26,7 @@ #include "mojo/public/cpp/bindings/lib/pipe_control_message_handler.h" #include "mojo/public/cpp/bindings/lib/pipe_control_message_handler_delegate.h" #include "mojo/public/cpp/bindings/lib/pipe_control_message_proxy.h" -#include "mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h" +#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" namespace base { class SingleThreadTaskRunner; @@ -57,7 +58,8 @@ class MultiplexRouter // If |set_interface_id_namespace_bit| is true, the interface IDs generated by // this router will have the highest bit set. MultiplexRouter(bool set_interface_id_namespace_bit, - ScopedMessagePipeHandle message_pipe); + ScopedMessagePipeHandle message_pipe, + scoped_refptr<base::SingleThreadTaskRunner> runner); // --------------------------------------------------------------------------- // The following public methods are safe to call from any threads. @@ -84,7 +86,8 @@ class MultiplexRouter // DetachEndpointClient(). InterfaceEndpointController* AttachEndpointClient( const ScopedInterfaceEndpointHandle& handle, - InterfaceEndpointClient* endpoint_client); + InterfaceEndpointClient* endpoint_client, + scoped_refptr<base::SingleThreadTaskRunner> runner); // Detaches the client attached to the specified endpoint. It must be called // on the same thread as the corresponding AttachEndpointClient() call. @@ -94,7 +97,7 @@ class MultiplexRouter // and notifies all interfaces running on this pipe. void RaiseError(); - scoped_ptr<AssociatedGroup> CreateAssociatedGroup(); + std::unique_ptr<AssociatedGroup> CreateAssociatedGroup(); static MultiplexRouter* GetRouter(AssociatedGroup* associated_group); @@ -181,11 +184,16 @@ class MultiplexRouter }; // Processes enqueued tasks (incoming messages and error notifications). + // |current_task_runner| is only used when |client_call_behavior| is + // ALLOW_DIRECT_CLIENT_CALLS to determine whether we are on the right task + // runner to make client calls for async messages or connection error + // notifications. // // Note: Because calling into InterfaceEndpointClient may lead to destruction // of this object, if direct calls are allowed, the caller needs to hold on to // a ref outside of |lock_| before calling this method. - void ProcessTasks(ClientCallBehavior client_call_behavior); + void ProcessTasks(ClientCallBehavior client_call_behavior, + base::SingleThreadTaskRunner* current_task_runner); // Processes the first queued sync message for the endpoint corresponding to // |id|; returns whether there are more sync messages for that endpoint in the @@ -196,10 +204,14 @@ class MultiplexRouter bool ProcessFirstSyncMessageForEndpoint(InterfaceId id); // Returns true to indicate that |task|/|message| has been processed. - bool ProcessNotifyErrorTask(Task* task, - ClientCallBehavior client_call_behavior); - bool ProcessIncomingMessage(Message* message, - ClientCallBehavior client_call_behavior); + bool ProcessNotifyErrorTask( + Task* task, + ClientCallBehavior client_call_behavior, + base::SingleThreadTaskRunner* current_task_runner); + bool ProcessIncomingMessage( + Message* message, + ClientCallBehavior client_call_behavior, + base::SingleThreadTaskRunner* current_task_runner); void MaybePostToProcessTasks(base::SingleThreadTaskRunner* task_runner); void LockAndCallProcessTasks(); @@ -232,11 +244,12 @@ class MultiplexRouter std::map<InterfaceId, scoped_refptr<InterfaceEndpoint>> endpoints_; uint32_t next_interface_id_value_; - std::deque<scoped_ptr<Task>> tasks_; + std::deque<std::unique_ptr<Task>> tasks_; // It refers to tasks in |tasks_| and doesn't own any of them. std::map<InterfaceId, std::deque<Task*>> sync_message_tasks_; bool posted_to_process_tasks_; + scoped_refptr<base::SingleThreadTaskRunner> posted_to_task_runner_; bool encountered_error_; diff --git a/chromium/mojo/public/cpp/bindings/lib/native_serialization.h b/chromium/mojo/public/cpp/bindings/lib/native_serialization.h deleted file mode 100644 index 835e072a8f3..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/native_serialization.h +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2015 The Chromium 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_NATIVE_SERIALIZATION_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_SERIALIZATION_H_ - -#include <stddef.h> -#include <stdint.h> - -#include <limits> - -#include "base/logging.h" -#include "base/pickle.h" -#include "ipc/ipc_param_traits.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/bindings_serialization.h" -#include "mojo/public/cpp/bindings/lib/pickle_buffer.h" - -namespace mojo { -namespace internal { - -// Generated bindings for native-only types will specialize this to |true|. -// It can be used as a signal (by e.g. the Array serializer) for when to use -// SerializeNative_ with a type. -template <typename E> -struct ShouldUseNativeSerializer { static const bool value = false; }; - -template <typename T> -size_t GetSerializedSizeNative_(const T& value, SerializationContext* context) { - base::PickleSizer sizer; - IPC::ParamTraits<T>::GetSize(&sizer, value); - return Align(sizer.payload_size() + sizeof(ArrayHeader)); -} - -template <typename T> -void SerializeNative_(const T& value, - Buffer* buffer, - Array_Data<uint8_t>** out, - SerializationContext* context) { - PickleBuffer* pickler = buffer->AsPickleBuffer(); - DCHECK(pickler) << "Native types can only be used with PickleBuffers."; - - ArrayHeader* header = - reinterpret_cast<ArrayHeader*>(buffer->Allocate(sizeof(ArrayHeader))); - - // Remember where the Pickle started before writing. - base::Pickle* pickle = pickler->pickle(); - const char* data_start = pickle->end_of_payload(); - -#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) - const char* payload_base = pickle->payload(); - size_t size_before_write = pickle->payload_size(); -#endif - - IPC::ParamTraits<T>::Write(pickle, value); - -#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) - // Ensure the pickle buffer hasn't moved. - DCHECK_EQ(payload_base, pickle->payload()); - // Explicitly validate that the value returned by GetSize() always equals the - // number of bytes actually written by Write(). - DCHECK_GE(pickle->payload_size(), size_before_write); - size_t bytes_written = pickle->payload_size() - size_before_write; - DCHECK_EQ(Align(bytes_written + sizeof(ArrayHeader)), - GetSerializedSizeNative_(value, context)); -#endif - - // Fix up the ArrayHeader so that num_elements contains the length of the - // pickled data. - size_t pickled_size = pickle->end_of_payload() - data_start; - size_t total_size = pickled_size + sizeof(ArrayHeader); - DCHECK_LT(total_size, std::numeric_limits<uint32_t>::max()); - header->num_bytes = static_cast<uint32_t>(total_size); - header->num_elements = static_cast<uint32_t>(pickled_size); - - *out = reinterpret_cast<Array_Data<uint8_t>*>(header); -} - -template <typename T> -bool DeserializeNative_(Array_Data<uint8_t>* data, - T* out, - SerializationContext* context) { - if (!data) - return true; - - // Construct a temporary base::Pickle view over the array data. Note that - // the Array_Data is laid out like this: - // - // [num_bytes (4 bytes)] [num_elements (4 bytes)] [elements...] - // - // and base::Pickle expects to view data like this: - // - // [payload_size (4 bytes)] [header bytes ...] [payload...] - // - // Because ArrayHeader's num_bytes includes the length of the header and - // Pickle's payload_size does not, we need to adjust the stored value - // momentarily so Pickle can view the data. - ArrayHeader* header = reinterpret_cast<ArrayHeader*>(data); - DCHECK_GE(header->num_bytes, sizeof(ArrayHeader)); - header->num_bytes -= sizeof(ArrayHeader); - - { - // Construct a view over the full Array_Data, including our hacked up - // header. Pickle will infer from this that the header is 8 bytes long, - // and the payload will contain all of the pickled bytes. - base::Pickle pickle_view(reinterpret_cast<const char*>(header), - header->num_bytes + sizeof(ArrayHeader)); - base::PickleIterator iter(pickle_view); - if (!IPC::ParamTraits<T>::Read(&pickle_view, &iter, out)) - return false; - } - - // Return the header to its original state. - header->num_bytes += sizeof(ArrayHeader); - - return true; -} - -} // namespace internal -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/native_struct.cc b/chromium/mojo/public/cpp/bindings/lib/native_struct.cc new file mode 100644 index 00000000000..837b75a60e3 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/native_struct.cc @@ -0,0 +1,30 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/bindings/native_struct.h" + +namespace mojo { + +// static +NativeStructPtr NativeStruct::New() { + NativeStructPtr rv; + internal::StructHelper<NativeStruct>::Initialize(&rv); + return rv; +} + +NativeStruct::NativeStruct() : data(nullptr) {} + +NativeStruct::~NativeStruct() {} + +NativeStructPtr NativeStruct::Clone() const { + NativeStructPtr rv(New()); + rv->data = data.Clone(); + return rv; +} + +bool NativeStruct::Equals(const NativeStruct& other) const { + return data.Equals(other.data); +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/native_struct_data.cc b/chromium/mojo/public/cpp/bindings/lib/native_struct_data.cc new file mode 100644 index 00000000000..1d6bf6f873f --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/native_struct_data.cc @@ -0,0 +1,22 @@ +// 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/native_struct_data.h" + +#include "mojo/public/cpp/bindings/lib/bounds_checker.h" +#include "mojo/public/cpp/bindings/lib/buffer.h" + +namespace mojo { +namespace internal { + +// static +bool NativeStruct_Data::Validate(const void* data, + BoundsChecker* bounds_checker) { + const ArrayValidateParams data_validate_params(0, false, nullptr); + return Array_Data<uint8_t>::Validate(data, bounds_checker, + &data_validate_params); +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/native_struct_data.h b/chromium/mojo/public/cpp/bindings/lib/native_struct_data.h new file mode 100644 index 00000000000..0c2cccd1488 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/native_struct_data.h @@ -0,0 +1,41 @@ +// 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_NATIVE_STRUCT_DATA_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_STRUCT_DATA_H_ + +#include <vector> + +#include "mojo/public/cpp/bindings/lib/array_internal.h" +#include "mojo/public/cpp/system/handle.h" + +namespace mojo { +namespace internal { + +class BoundsChecker; +class Buffer; + +class NativeStruct_Data { + public: + static bool Validate(const void* data, BoundsChecker* bounds_checker); + + void EncodePointers() {} + void DecodePointers() {} + + // Unlike normal structs, the memory layout is exactly the same as an array + // of uint8_t. + Array_Data<uint8_t> data; + + private: + NativeStruct_Data() = delete; + ~NativeStruct_Data() = delete; +}; + +static_assert(sizeof(Array_Data<uint8_t>) == sizeof(NativeStruct_Data), + "Mismatched NativeStruct_Data and Array_Data<uint8_t> size"); + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_STRUCT_DATA_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.cc b/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.cc new file mode 100644 index 00000000000..fe65f147c61 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.cc @@ -0,0 +1,59 @@ +// 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/native_struct_serialization.h" + +#include "mojo/public/cpp/bindings/lib/serialization.h" + +namespace mojo { +namespace internal { + +// static +size_t UnmappedNativeStructSerializerImpl::PrepareToSerialize( + const NativeStructPtr& input, + SerializationContext* context) { + if (!input) + return 0; + return internal::PrepareToSerialize<Array<uint8_t>>(input->data, context); +} + +// static +void UnmappedNativeStructSerializerImpl::Serialize( + const NativeStructPtr& input, + Buffer* buffer, + NativeStruct_Data** output, + SerializationContext* context) { + if (!input) { + *output = nullptr; + return; + } + + Array_Data<uint8_t>* data = nullptr; + const ArrayValidateParams params(0, false, nullptr); + internal::Serialize<Array<uint8_t>>(input->data, buffer, &data, ¶ms, + context); + *output = reinterpret_cast<NativeStruct_Data*>(data); +} + +// static +bool UnmappedNativeStructSerializerImpl::Deserialize( + NativeStruct_Data* input, + NativeStructPtr* output, + SerializationContext* context) { + Array_Data<uint8_t>* data = reinterpret_cast<Array_Data<uint8_t>*>(input); + + NativeStructPtr result(NativeStruct::New()); + if (!internal::Deserialize<Array<uint8_t>>(data, &result->data, context)) { + output = nullptr; + return false; + } + if (!result->data) + *output = nullptr; + else + result.Swap(output); + return true; +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.h b/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.h new file mode 100644 index 00000000000..09f3c883131 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.h @@ -0,0 +1,132 @@ +// Copyright 2015 The Chromium 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_NATIVE_STRUCT_SERIALIZATION_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_STRUCT_SERIALIZATION_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <limits> + +#include "base/logging.h" +#include "base/pickle.h" +#include "ipc/ipc_param_traits.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" + +namespace mojo { +namespace internal { + +template <typename MaybeConstUserType> +struct NativeStructSerializerImpl { + using UserType = typename std::remove_const<MaybeConstUserType>::type; + using Traits = IPC::ParamTraits<UserType>; + + static size_t PrepareToSerialize(MaybeConstUserType& value, + SerializationContext* context) { + base::PickleSizer sizer; + Traits::GetSize(&sizer, value); + return Align(sizer.payload_size() + sizeof(ArrayHeader)); + } + + static void Serialize(MaybeConstUserType& value, + Buffer* buffer, + NativeStruct_Data** out, + SerializationContext* context) { + base::Pickle pickle; + Traits::Write(&pickle, value); + +#if DCHECK_IS_ON() + base::PickleSizer sizer; + Traits::GetSize(&sizer, value); + DCHECK_EQ(sizer.payload_size(), pickle.payload_size()); +#endif + + size_t total_size = pickle.payload_size() + sizeof(ArrayHeader); + DCHECK_LT(total_size, std::numeric_limits<uint32_t>::max()); + + // Allocate a uint8 array, initialize its header, and copy the Pickle in. + ArrayHeader* header = + reinterpret_cast<ArrayHeader*>(buffer->Allocate(total_size)); + header->num_bytes = static_cast<uint32_t>(total_size); + header->num_elements = static_cast<uint32_t>(pickle.payload_size()); + memcpy(reinterpret_cast<char*>(header) + sizeof(ArrayHeader), + pickle.payload(), pickle.payload_size()); + + *out = reinterpret_cast<NativeStruct_Data*>(header); + } + + static bool Deserialize(NativeStruct_Data* data, + UserType* out, + SerializationContext* context) { + if (!data) + return true; + + // Construct a temporary base::Pickle view over the array data. Note that + // the Array_Data is laid out like this: + // + // [num_bytes (4 bytes)] [num_elements (4 bytes)] [elements...] + // + // and base::Pickle expects to view data like this: + // + // [payload_size (4 bytes)] [header bytes ...] [payload...] + // + // Because ArrayHeader's num_bytes includes the length of the header and + // Pickle's payload_size does not, we need to adjust the stored value + // momentarily so Pickle can view the data. + ArrayHeader* header = reinterpret_cast<ArrayHeader*>(data); + DCHECK_GE(header->num_bytes, sizeof(ArrayHeader)); + header->num_bytes -= sizeof(ArrayHeader); + + { + // Construct a view over the full Array_Data, including our hacked up + // header. Pickle will infer from this that the header is 8 bytes long, + // and the payload will contain all of the pickled bytes. + base::Pickle pickle_view(reinterpret_cast<const char*>(header), + header->num_bytes + sizeof(ArrayHeader)); + base::PickleIterator iter(pickle_view); + if (!Traits::Read(&pickle_view, &iter, out)) + return false; + } + + // Return the header to its original state. + header->num_bytes += sizeof(ArrayHeader); + + return true; + } +}; + +struct UnmappedNativeStructSerializerImpl { + static size_t PrepareToSerialize(const NativeStructPtr& input, + SerializationContext* context); + static void Serialize(const NativeStructPtr& input, + Buffer* buffer, + NativeStruct_Data** output, + SerializationContext* context); + static bool Deserialize(NativeStruct_Data* input, + NativeStructPtr* output, + SerializationContext* context); +}; + +template <> +struct NativeStructSerializerImpl<NativeStructPtr> + : public UnmappedNativeStructSerializerImpl {}; + +template <> +struct NativeStructSerializerImpl<const NativeStructPtr> + : public UnmappedNativeStructSerializerImpl {}; + +template <typename MaybeConstUserType> +struct Serializer<NativeStructPtr, MaybeConstUserType> + : public NativeStructSerializerImpl<MaybeConstUserType> {}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_STRUCT_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/pickle_buffer.cc b/chromium/mojo/public/cpp/bindings/lib/pickle_buffer.cc deleted file mode 100644 index ecd75dba69d..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/pickle_buffer.cc +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2015 The Chromium 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/pickle_buffer.h" - -#include <stddef.h> -#include <stdint.h> -#include <stdlib.h> - -#include "base/logging.h" -#include "base/macros.h" -#include "base/pickle.h" -#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" - -namespace mojo { -namespace internal { - -class PickleBuffer::Storage : public base::Pickle { - public: - explicit Storage(size_t num_bytes); - ~Storage() override {} - - size_t available_capacity() const { - return capacity_after_header() - payload_size(); - } - - void* GetData() { return static_cast<void*>(mutable_payload()); } - void* Claim(size_t num_bytes) { return ClaimBytes(num_bytes); } - - private: - // TODO(rockot): Stop wasting 8 bytes per buffer. - // - // We don't use Pickle's header at all, but its base header type consumes 4 - // bytes. We waste another 4 bytes to keep our actual buffer aligned to an - // 8-byte boundary. - // - // The reason we don't use base::Pickle's header is that it stores payload - // length in the first 4 bytes. Mojo Messages are packed like mojom structs, - // where the first 4 bytes are header size rather than payload size. - struct PaddedHeader : public base::Pickle::Header { - uint32_t padding; - }; - - static_assert(sizeof(PaddedHeader) % 8 == 0, - "PickleBuffer requires a Pickle header size with 8-byte alignment."); - - DISALLOW_COPY_AND_ASSIGN(Storage); -}; - -PickleBuffer::Storage::Storage(size_t num_bytes) - : base::Pickle(sizeof(PaddedHeader)) { - headerT<PaddedHeader>()->padding = 0; - Resize(num_bytes); -} - -PickleBuffer::PickleBuffer(size_t num_bytes, bool zero_initialized) - : storage_(new Storage(num_bytes)) { - if (zero_initialized) - memset(storage_->GetData(), 0, num_bytes); -} - -PickleBuffer::~PickleBuffer() { -} - -const void* PickleBuffer::data() const { return storage_->GetData(); } - -size_t PickleBuffer::data_num_bytes() const { return storage_->payload_size(); } - -base::Pickle* PickleBuffer::pickle() const { - return storage_.get(); -} - -void* PickleBuffer::Allocate(size_t num_bytes) { - DCHECK(storage_); - - // The last allocation may terminate in between 8-byte boundaries. Pad the - // front of this allocation if that's the case. - size_t padded_capacity = Align(storage_->payload_size()); - DCHECK_GE(padded_capacity, storage_->payload_size()); - - size_t padding_bytes = padded_capacity - storage_->payload_size(); - size_t allocation_size = padding_bytes + num_bytes; - const void* previous_data_location = storage_->GetData(); - if (storage_->available_capacity() < allocation_size) { - NOTREACHED() << - "Message buffers must be fully allocated before serialization."; - return nullptr; - } - char* p = static_cast<char*>(storage_->Claim(allocation_size)); - DCHECK_EQ(storage_->GetData(), previous_data_location); - return p + padding_bytes; -} - -PickleBuffer* PickleBuffer::AsPickleBuffer() { return this; } - -} // namespace internal -} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/pickle_buffer.h b/chromium/mojo/public/cpp/bindings/lib/pickle_buffer.h deleted file mode 100644 index c940b38f786..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/pickle_buffer.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2015 The Chromium 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_PICKLE_BUFFER_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_LIB_PICKLE_BUFFER_H_ - -#include <stddef.h> - -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "base/pickle.h" -#include "mojo/public/cpp/bindings/lib/buffer.h" - -namespace mojo { -namespace internal { - -// An implementation of Buffer which uses base::Pickle for its backing. Note -// that this does not use Pickle's header structure at all, instead storing -// the complete Message (including header) in the Pickle's payload. -class PickleBuffer : public Buffer { - public: - PickleBuffer(size_t num_bytes, bool zero_initialized); - ~PickleBuffer() override; - - const void* data() const; - - void* data() { - return const_cast<void*>(static_cast<const PickleBuffer*>(this)->data()); - } - - size_t data_num_bytes() const; - - base::Pickle* pickle() const; - - private: - class Storage; - - // Buffer implementation. Note that this cannot grow the Pickle's capacity and - // it is an error to Allocate() more bytes in total than have been - // pre-allocated using ReserveCapacity() or ReserveUninitializedCapacity(). - // - // This guarantees that the returned data is aligned on an 8-byte boundary. - void* Allocate(size_t num_bytes) override; - PickleBuffer* AsPickleBuffer() override; - - scoped_ptr<Storage> storage_; - - DISALLOW_COPY_AND_ASSIGN(PickleBuffer); -}; - -} // namespace internal -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_PICKLE_BUFFER_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc b/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc index 6a5c224ed68..ae952c503f2 100644 --- a/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc +++ b/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc @@ -7,6 +7,7 @@ #include "base/logging.h" #include "mojo/public/cpp/bindings/lib/message_builder.h" #include "mojo/public/cpp/bindings/lib/pipe_control_message_handler_delegate.h" +#include "mojo/public/cpp/bindings/lib/serialization.h" #include "mojo/public/cpp/bindings/lib/validation_util.h" #include "mojo/public/interfaces/bindings/pipe_control_messages.mojom.h" @@ -51,10 +52,11 @@ bool PipeControlMessageHandler::RunOrClosePipe(Message* message) { reinterpret_cast< pipe_control::internal::RunOrClosePipeMessageParams_Data*>( message->mutable_payload()); - params->DecodePointersAndHandles(message->mutable_handles()); + params->DecodePointers(); pipe_control::RunOrClosePipeMessageParamsPtr params_ptr; - Deserialize_(params, ¶ms_ptr, nullptr); + Deserialize<pipe_control::RunOrClosePipeMessageParamsPtr>(params, ¶ms_ptr, + &context_); if (params_ptr->input->is_peer_associated_endpoint_closed_event()) { return delegate_->OnPeerAssociatedEndpointClosed( diff --git a/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_handler.h b/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_handler.h index 091e7c28758..c42d0bae3d1 100644 --- a/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_handler.h +++ b/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_handler.h @@ -7,6 +7,7 @@ #include "base/macros.h" #include "mojo/public/cpp/bindings/lib/interface_id.h" +#include "mojo/public/cpp/bindings/lib/serialization_context.h" #include "mojo/public/cpp/bindings/message.h" namespace mojo { @@ -38,6 +39,7 @@ class PipeControlMessageHandler : public MessageReceiver { bool RunOrClosePipe(Message* message); PipeControlMessageHandlerDelegate* const delegate_; + SerializationContext context_; DISALLOW_COPY_AND_ASSIGN(PipeControlMessageHandler); }; diff --git a/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc b/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc index 4ea0353e29f..492bc02d85a 100644 --- a/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc +++ b/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc @@ -9,6 +9,7 @@ #include "base/compiler_specific.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" @@ -17,17 +18,21 @@ namespace internal { namespace { void SendRunOrClosePipeMessage(MessageReceiver* receiver, - pipe_control::RunOrClosePipeInputPtr input) { + pipe_control::RunOrClosePipeInputPtr input, + SerializationContext* context) { pipe_control::RunOrClosePipeMessageParamsPtr params_ptr( pipe_control::RunOrClosePipeMessageParams::New()); params_ptr->input = std::move(input); - size_t size = GetSerializedSize_(params_ptr, nullptr); + size_t size = + PrepareToSerialize<pipe_control::RunOrClosePipeMessageParamsPtr>( + params_ptr, context); MessageBuilder builder(pipe_control::kRunOrClosePipeMessageId, size); pipe_control::internal::RunOrClosePipeMessageParams_Data* params = nullptr; - Serialize_(std::move(params_ptr), builder.buffer(), ¶ms, nullptr); - params->EncodePointersAndHandles(builder.message()->mutable_handles()); + Serialize<pipe_control::RunOrClosePipeMessageParamsPtr>( + params_ptr, builder.buffer(), ¶ms, context); + params->EncodePointers(); builder.message()->set_interface_id(kInvalidInterfaceId); bool ok = receiver->Accept(builder.message()); // This return value may be ignored as !ok implies the underlying message pipe @@ -49,7 +54,7 @@ void PipeControlMessageProxy::NotifyPeerEndpointClosed(InterfaceId id) { pipe_control::RunOrClosePipeInput::New()); input->set_peer_associated_endpoint_closed_event(std::move(event)); - SendRunOrClosePipeMessage(receiver_, std::move(input)); + SendRunOrClosePipeMessage(receiver_, std::move(input), &context_); } void PipeControlMessageProxy::NotifyEndpointClosedBeforeSent(InterfaceId id) { @@ -61,7 +66,7 @@ void PipeControlMessageProxy::NotifyEndpointClosedBeforeSent(InterfaceId id) { pipe_control::RunOrClosePipeInput::New()); input->set_associated_endpoint_closed_before_sent_event(std::move(event)); - SendRunOrClosePipeMessage(receiver_, std::move(input)); + SendRunOrClosePipeMessage(receiver_, std::move(input), &context_); } } // namespace internal diff --git a/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.h b/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.h index 3804c4ce063..87a8d478c8a 100644 --- a/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.h +++ b/chromium/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.h @@ -7,6 +7,7 @@ #include "base/macros.h" #include "mojo/public/cpp/bindings/lib/interface_id.h" +#include "mojo/public/cpp/bindings/lib/serialization_context.h" namespace mojo { @@ -26,6 +27,7 @@ class PipeControlMessageProxy { private: // Not owned. MessageReceiver* receiver_; + SerializationContext context_; DISALLOW_COPY_AND_ASSIGN(PipeControlMessageProxy); }; diff --git a/chromium/mojo/public/cpp/bindings/lib/router.cc b/chromium/mojo/public/cpp/bindings/lib/router.cc index 9e93f0cfd62..da5f34b1df5 100644 --- a/chromium/mojo/public/cpp/bindings/lib/router.cc +++ b/chromium/mojo/public/cpp/bindings/lib/router.cc @@ -5,15 +5,14 @@ #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/message_loop/message_loop.h" -#include "base/single_thread_task_runner.h" +#include "base/memory/ptr_util.h" #include "base/stl_util.h" -#include "base/thread_task_runner_handle.h" namespace mojo { namespace internal { @@ -30,20 +29,25 @@ void DCheckIfInvalid(const base::WeakPtr<Router>& router, class ResponderThunk : public MessageReceiverWithStatus { public: - explicit ResponderThunk(const base::WeakPtr<Router>& router) - : router_(router), accept_was_invoked_(false), - task_runner_(base::ThreadTaskRunnerHandle::Get()) {} + 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()) { - if (router_) { - // 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. + // 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_)); @@ -112,10 +116,13 @@ bool Router::HandleIncomingMessageThunk::Accept(Message* message) { Router::Router(ScopedMessagePipeHandle message_pipe, FilterChain filters, - bool expects_sync_requests) + bool expects_sync_requests, + scoped_refptr<base::SingleThreadTaskRunner> runner) : thunk_(this), filters_(std::move(filters)), - connector_(std::move(message_pipe), Connector::SINGLE_THREADED_SEND), + connector_(std::move(message_pipe), + Connector::SINGLE_THREADED_SEND, + std::move(runner)), incoming_receiver_(nullptr), next_request_id_(0), testing_mode_(false), @@ -146,20 +153,21 @@ bool Router::AcceptWithResponder(Message* message, MessageReceiver* responder) { if (request_id == 0) request_id = next_request_id_++; + bool is_sync = message->has_flag(kMessageIsSync); message->set_request_id(request_id); if (!connector_.Accept(message)) return false; - if (!message->has_flag(kMessageIsSync)) { + if (!is_sync) { // We assume ownership of |responder|. - async_responders_[request_id] = make_scoped_ptr(responder); + async_responders_[request_id] = base::WrapUnique(responder); return true; } bool response_received = false; - scoped_ptr<MessageReceiver> sync_responder(responder); + std::unique_ptr<MessageReceiver> sync_responder(responder); sync_responses_.insert(std::make_pair( - request_id, make_scoped_ptr(new SyncResponseInfo(&response_received)))); + request_id, base::WrapUnique(new SyncResponseInfo(&response_received)))); base::WeakPtr<Router> weak_self = weak_factory_.GetWeakPtr(); connector_.SyncWatch(&response_received); @@ -169,7 +177,7 @@ bool Router::AcceptWithResponder(Message* message, MessageReceiver* responder) { auto iter = sync_responses_.find(request_id); DCHECK_EQ(&response_received, iter->second->response_received); if (response_received) { - scoped_ptr<Message> response = std::move(iter->second->response); + std::unique_ptr<Message> response = std::move(iter->second->response); ignore_result(sync_responder->Accept(response.get())); } sync_responses_.erase(iter); @@ -192,13 +200,13 @@ bool Router::HandleIncomingMessage(Message* message) { connector_.during_sync_handle_watcher_callback(); if (!message->has_flag(kMessageIsSync) && (during_sync_call || !pending_messages_.empty())) { - scoped_ptr<Message> pending_message(new Message); + 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; - base::MessageLoop::current()->PostTask( + connector_.task_runner()->PostTask( FROM_HERE, base::Bind(&Router::HandleQueuedMessages, weak_factory_.GetWeakPtr())); } @@ -215,7 +223,7 @@ void Router::HandleQueuedMessages() { base::WeakPtr<Router> weak_self = weak_factory_.GetWeakPtr(); while (!pending_messages_.empty()) { - scoped_ptr<Message> message(std::move(pending_messages_.front())); + std::unique_ptr<Message> message(std::move(pending_messages_.front())); pending_messages_.pop(); bool result = HandleMessageInternal(message.get()); @@ -242,8 +250,8 @@ bool Router::HandleMessageInternal(Message* message) { if (!incoming_receiver_) return false; - MessageReceiverWithStatus* responder = - new ResponderThunk(weak_factory_.GetWeakPtr()); + MessageReceiverWithStatus* responder = new ResponderThunk( + weak_factory_.GetWeakPtr(), connector_.task_runner()); bool ok = incoming_receiver_->AcceptWithResponder(message, responder); if (!ok) delete responder; @@ -269,7 +277,7 @@ bool Router::HandleMessageInternal(Message* message) { DCHECK(testing_mode_); return false; } - scoped_ptr<MessageReceiver> responder = std::move(it->second); + std::unique_ptr<MessageReceiver> responder = std::move(it->second); async_responders_.erase(it); return responder->Accept(message); } else { @@ -294,7 +302,7 @@ void Router::OnConnectionError() { if (connector_.during_sync_handle_watcher_callback()) { // We don't want the error handler to reenter an ongoing sync call. - base::MessageLoop::current()->PostTask( + connector_.task_runner()->PostTask( FROM_HERE, base::Bind(&Router::OnConnectionError, weak_factory_.GetWeakPtr())); return; diff --git a/chromium/mojo/public/cpp/bindings/lib/router.h b/chromium/mojo/public/cpp/bindings/lib/router.h index 054bcc115a2..2f5e8e2a971 100644 --- a/chromium/mojo/public/cpp/bindings/lib/router.h +++ b/chromium/mojo/public/cpp/bindings/lib/router.h @@ -8,11 +8,13 @@ #include <stdint.h> #include <map> +#include <memory> #include <queue> #include "base/macros.h" -#include "base/memory/scoped_ptr.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/callback.h" #include "mojo/public/cpp/bindings/lib/connector.h" @@ -27,7 +29,8 @@ class Router : public MessageReceiverWithResponder { public: Router(ScopedMessagePipeHandle message_pipe, FilterChain filters, - bool expects_sync_requests); + bool expects_sync_requests, + scoped_refptr<base::SingleThreadTaskRunner> runner); ~Router() override; // Sets the receiver to handle messages read from the message pipe that do @@ -113,14 +116,15 @@ class Router : public MessageReceiverWithResponder { private: // Maps from the id of a response to the MessageReceiver that handles the // response. - using AsyncResponderMap = std::map<uint64_t, scoped_ptr<MessageReceiver>>; + using AsyncResponderMap = + std::map<uint64_t, std::unique_ptr<MessageReceiver>>; struct SyncResponseInfo { public: explicit SyncResponseInfo(bool* in_response_received); ~SyncResponseInfo(); - scoped_ptr<Message> response; + std::unique_ptr<Message> response; // Points to a stack-allocated variable. bool* response_received; @@ -129,7 +133,7 @@ class Router : public MessageReceiverWithResponder { DISALLOW_COPY_AND_ASSIGN(SyncResponseInfo); }; - using SyncResponseMap = std::map<uint64_t, scoped_ptr<SyncResponseInfo>>; + using SyncResponseMap = std::map<uint64_t, std::unique_ptr<SyncResponseInfo>>; class HandleIncomingMessageThunk : public MessageReceiver { public: @@ -157,7 +161,7 @@ class Router : public MessageReceiverWithResponder { SyncResponseMap sync_responses_; uint64_t next_request_id_; bool testing_mode_; - std::queue<scoped_ptr<Message>> pending_messages_; + 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_; diff --git a/chromium/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc b/chromium/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc index dfe4e234241..83db0d9533a 100644 --- a/chromium/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc +++ b/chromium/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc @@ -2,30 +2,30 @@ // 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/scoped_interface_endpoint_handle.h" +#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" #include "base/logging.h" #include "mojo/public/cpp/bindings/lib/multiplex_router.h" namespace mojo { -namespace internal { ScopedInterfaceEndpointHandle::ScopedInterfaceEndpointHandle() - : ScopedInterfaceEndpointHandle(kInvalidInterfaceId, true, nullptr) {} + : ScopedInterfaceEndpointHandle(internal::kInvalidInterfaceId, true, + nullptr) {} ScopedInterfaceEndpointHandle::ScopedInterfaceEndpointHandle( - InterfaceId id, + internal::InterfaceId id, bool is_local, - scoped_refptr<MultiplexRouter> router) + scoped_refptr<internal::MultiplexRouter> router) : id_(id), is_local_(is_local), router_(std::move(router)) { - DCHECK(!IsValidInterfaceId(id) || router_); + DCHECK(!internal::IsValidInterfaceId(id) || router_); } ScopedInterfaceEndpointHandle::ScopedInterfaceEndpointHandle( ScopedInterfaceEndpointHandle&& other) : id_(other.id_), is_local_(other.is_local_) { router_.swap(other.router_); - other.id_ = kInvalidInterfaceId; + other.id_ = internal::kInvalidInterfaceId; } ScopedInterfaceEndpointHandle::~ScopedInterfaceEndpointHandle() { @@ -41,12 +41,12 @@ ScopedInterfaceEndpointHandle& ScopedInterfaceEndpointHandle::operator=( } void ScopedInterfaceEndpointHandle::reset() { - if (!IsValidInterfaceId(id_)) + if (!internal::IsValidInterfaceId(id_)) return; router_->CloseEndpointHandle(id_, is_local_); - id_ = kInvalidInterfaceId; + id_ = internal::kInvalidInterfaceId; is_local_ = true; router_ = nullptr; } @@ -58,15 +58,14 @@ void ScopedInterfaceEndpointHandle::swap(ScopedInterfaceEndpointHandle& other) { swap(other.router_, router_); } -InterfaceId ScopedInterfaceEndpointHandle::release() { - InterfaceId result = id_; +internal::InterfaceId ScopedInterfaceEndpointHandle::release() { + internal::InterfaceId result = id_; - id_ = kInvalidInterfaceId; + id_ = internal::kInvalidInterfaceId; is_local_ = true; router_ = nullptr; return result; } -} // namespace internal } // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/serialization.h b/chromium/mojo/public/cpp/bindings/lib/serialization.h index c3af9ffdfc7..b37cc2761e8 100644 --- a/chromium/mojo/public/cpp/bindings/lib/serialization.h +++ b/chromium/mojo/public/cpp/bindings/lib/serialization.h @@ -5,9 +5,15 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_H_ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_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/map_serialization.h" -#include "mojo/public/cpp/bindings/lib/native_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/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" #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/serialization_context.cc b/chromium/mojo/public/cpp/bindings/lib/serialization_context.cc new file mode 100644 index 00000000000..f0cf730f1a4 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/serialization_context.cc @@ -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. + +#include "mojo/public/cpp/bindings/lib/serialization_context.h" + +#include <limits> + +#include "base/logging.h" +#include "mojo/public/cpp/bindings/lib/multiplex_router.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { +namespace internal { + +SerializedHandleVector::SerializedHandleVector() {} + +SerializedHandleVector::~SerializedHandleVector() { + for (auto handle : handles_) { + if (handle.is_valid()) { + MojoResult rv = MojoClose(handle.value()); + DCHECK_EQ(rv, MOJO_RESULT_OK); + } + } +} + +Handle_Data SerializedHandleVector::AddHandle(mojo::Handle handle) { + Handle_Data data; + if (!handle.is_valid()) { + data.value = kEncodedInvalidHandleValue; + } else { + DCHECK_LT(handles_.size(), std::numeric_limits<uint32_t>::max()); + data.value = static_cast<uint32_t>(handles_.size()); + handles_.push_back(handle); + } + return data; +} + +mojo::Handle SerializedHandleVector::TakeHandle( + const Handle_Data& encoded_handle) { + if (!encoded_handle.is_valid()) + return mojo::Handle(); + DCHECK_LT(encoded_handle.value, handles_.size()); + return FetchAndReset(&handles_[encoded_handle.value]); +} + +void SerializedHandleVector::Swap(std::vector<mojo::Handle>* other) { + handles_.swap(*other); +} + +SerializationContext::SerializationContext() {} + +SerializationContext::SerializationContext( + scoped_refptr<MultiplexRouter> in_router) + : router(std::move(in_router)) {} + +SerializationContext::~SerializationContext() { + DCHECK(!custom_contexts || custom_contexts->empty()); +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/serialization_context.h b/chromium/mojo/public/cpp/bindings/lib/serialization_context.h new file mode 100644 index 00000000000..48d37cf713a --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/serialization_context.h @@ -0,0 +1,75 @@ +// 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_BINDINGS_SERIALIZATION_CONTEXT_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_CONTEXT_H_ + +#include <stddef.h> + +#include <memory> +#include <queue> +#include <vector> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "mojo/public/cpp/bindings/lib/bindings_internal.h" +#include "mojo/public/cpp/system/handle.h" + +namespace mojo { +namespace internal { + +class MultiplexRouter; + +// A container for handles during serialization/deserialization. +class SerializedHandleVector { + public: + SerializedHandleVector(); + ~SerializedHandleVector(); + + size_t size() const { return handles_.size(); } + + // Adds a handle to the handle list and returns its index for encoding. + Handle_Data AddHandle(mojo::Handle handle); + + // Takes a handle from the list of serialized handle data. + mojo::Handle TakeHandle(const Handle_Data& encoded_handle); + + // Takes a handle from the list of serialized handle data and returns it in + // |*out_handle| as a specific scoped handle type. + template <typename T> + ScopedHandleBase<T> TakeHandleAs(const Handle_Data& encoded_handle) { + return MakeScopedHandle(T(TakeHandle(encoded_handle).value())); + } + + // Swaps all owned handles out with another Handle vector. + void Swap(std::vector<mojo::Handle>* other); + + private: + // Handles are owned by this object. + std::vector<mojo::Handle> handles_; + + DISALLOW_COPY_AND_ASSIGN(SerializedHandleVector); +}; + +// Context information for serialization/deserialization routines. +struct SerializationContext { + SerializationContext(); + explicit SerializationContext(scoped_refptr<MultiplexRouter> in_router); + + ~SerializationContext(); + + // Used to serialize/deserialize associated interface pointers and requests. + scoped_refptr<MultiplexRouter> router; + + // 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; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_CONTEXT_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/serialization_forward.h b/chromium/mojo/public/cpp/bindings/lib/serialization_forward.h index b6050498d87..266b3a89757 100644 --- a/chromium/mojo/public/cpp/bindings/lib/serialization_forward.h +++ b/chromium/mojo/public/cpp/bindings/lib/serialization_forward.h @@ -5,10 +5,9 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_FORWARD_H_ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_FORWARD_H_ -#include <stddef.h> - -#include "mojo/public/cpp/bindings/lib/string_serialization.h" -#include "mojo/public/cpp/bindings/lib/wtf_string_serialization.h" +#include "mojo/public/cpp/bindings/array_traits.h" +#include "mojo/public/cpp/bindings/string_traits.h" +#include "mojo/public/cpp/bindings/struct_traits.h" // This file is included by serialization implementation files to avoid circular // includes. @@ -16,118 +15,40 @@ // wtf_serialization.h if necessary). namespace mojo { - -template <typename T> -class Array; - -template <typename K, typename V> -class Map; - -template <typename T> -class WTFArray; - namespace internal { -template <typename T> -class Array_Data; - -class ArrayValidateParams; - -class Buffer; - -template <typename K, typename V> -class Map_Data; - -struct SerializationContext; - -template <typename T> -struct ShouldUseNativeSerializer; - -// ----------------------------------------------------------------------------- -// Forward declaration for native types. - -template <typename T> -size_t GetSerializedSizeNative_(const T& value, SerializationContext* context); - -template <typename T> -void SerializeNative_(const T& value, - Buffer* buffer, - Array_Data<uint8_t>** out, - SerializationContext* context); - -template <typename T> -bool DeserializeNative_(Array_Data<uint8_t>* data, - T* out, - SerializationContext* context); +template <typename MojomType, typename MaybeConstUserType> +struct Serializer; + +// PrepareToSerialize() must be matched by a Serialize() for the same input +// later. Moreover, within the same SerializationContext if PrepareToSerialize() +// is called for |input_1|, ..., |input_n|, Serialize() must be called for +// those objects in the exact same order. +template <typename MojomType, typename InputUserType, typename... Args> +size_t PrepareToSerialize(InputUserType&& input, Args&&... args) { + return Serializer<MojomType, + typename std::remove_reference<InputUserType>::type>:: + PrepareToSerialize(std::forward<InputUserType>(input), + std::forward<Args>(args)...); +} + +template <typename MojomType, typename InputUserType, typename... Args> +void Serialize(InputUserType&& input, Args&&... args) { + Serializer<MojomType, typename std::remove_reference<InputUserType>::type>:: + Serialize(std::forward<InputUserType>(input), + std::forward<Args>(args)...); +} + +template <typename MojomType, + typename DataType, + typename InputUserType, + typename... Args> +bool Deserialize(DataType&& input, InputUserType* output, Args&&... args) { + return Serializer<MojomType, InputUserType>::Deserialize( + std::forward<DataType>(input), output, std::forward<Args>(args)...); +} } // namespace internal - -// ----------------------------------------------------------------------------- -// Forward declaration for Array. - -template <typename E> -inline size_t GetSerializedSize_(const Array<E>& input, - internal::SerializationContext* context); - -template <typename E, typename F> -inline void SerializeArray_( - Array<E> input, - internal::Buffer* buf, - internal::Array_Data<F>** output, - const internal::ArrayValidateParams* validate_params, - internal::SerializationContext* context); - -template <typename E, typename F> -inline bool Deserialize_(internal::Array_Data<F>* input, - Array<E>* output, - internal::SerializationContext* context); - -// ----------------------------------------------------------------------------- -// Forward declaration for WTFArray. - -template <typename E> -inline size_t GetSerializedSize_(const WTFArray<E>& input, - internal::SerializationContext* context); - -template <typename E, typename F> -inline void SerializeArray_( - WTFArray<E> input, - internal::Buffer* buf, - internal::Array_Data<F>** output, - const internal::ArrayValidateParams* validate_params, - internal::SerializationContext* context); - -template <typename E, typename F> -inline bool Deserialize_(internal::Array_Data<F>* input, - WTFArray<E>* output, - internal::SerializationContext* context); - -// ----------------------------------------------------------------------------- -// Forward declaration for Map. - -template <typename MapKey, typename MapValue> -inline size_t GetSerializedSize_(const Map<MapKey, MapValue>& input, - internal::SerializationContext* context); - -template <typename MapKey, - typename MapValue, - typename DataKey, - typename DataValue> -inline void SerializeMap_( - Map<MapKey, MapValue> input, - internal::Buffer* buf, - internal::Map_Data<DataKey, DataValue>** output, - const internal::ArrayValidateParams* value_validate_params, - internal::SerializationContext* context); - -template <typename MapKey, - typename MapValue, - typename DataKey, - typename DataValue> -inline bool Deserialize_(internal::Map_Data<DataKey, DataValue>* input, - Map<MapKey, MapValue>* output, - internal::SerializationContext* context); - } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_FORWARD_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/serialization_util.cc b/chromium/mojo/public/cpp/bindings/lib/serialization_util.cc new file mode 100644 index 00000000000..d672243b779 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/serialization_util.cc @@ -0,0 +1,53 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/bindings/lib/serialization_util.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); +} + +const void* DecodePointerRaw(const uint64_t* offset) { + if (!*offset) + return nullptr; + return reinterpret_cast<const char*>(offset) + *offset; +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/serialization_util.h b/chromium/mojo/public/cpp/bindings/lib/serialization_util.h new file mode 100644 index 00000000000..698e90d9628 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/serialization_util.h @@ -0,0 +1,233 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_UTIL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_UTIL_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <queue> + +#include "base/logging.h" +#include "base/macros.h" +#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h" +#include "mojo/public/cpp/bindings/interface_ptr.h" +#include "mojo/public/cpp/bindings/lib/bindings_internal.h" +#include "mojo/public/cpp/bindings/lib/serialization_context.h" +#include "mojo/public/cpp/system/handle.h" + +namespace mojo { +namespace internal { + +class MultiplexRouter; + +size_t Align(size_t size); +char* AlignPointer(char* ptr); + +bool IsAligned(const void* ptr); + +// Pointers are encoded as relative offsets. The offsets are relative to the +// address of where the offset value is stored, such that the pointer may be +// recovered with the expression: +// +// ptr = reinterpret_cast<char*>(offset) + *offset +// +// A null pointer is encoded as an offset value of 0. +// +void EncodePointer(const void* ptr, uint64_t* offset); +// Note: This function doesn't validate the encoded pointer value. +const void* DecodePointerRaw(const uint64_t* offset); + +// Note: This function doesn't validate the encoded pointer value. +template <typename T> +inline void DecodePointer(const uint64_t* offset, T** ptr) { + *ptr = reinterpret_cast<T*>(const_cast<void*>(DecodePointerRaw(offset))); +} + +// The following 2 functions are used to encode/decode all objects (structs and +// arrays) in a consistent manner. + +template <typename T> +inline void Encode(T* obj) { + if (obj->ptr) + obj->ptr->EncodePointers(); + EncodePointer(obj->ptr, &obj->offset); +} + +// Note: This function doesn't validate the encoded pointer and handle values. +template <typename T> +inline void Decode(T* obj) { + DecodePointer(&obj->offset, &obj->ptr); + if (obj->ptr) + obj->ptr->DecodePointers(); +} + +template <typename T> +inline void AssociatedInterfacePtrInfoToData( + AssociatedInterfacePtrInfo<T> input, + AssociatedInterface_Data* output) { + output->version = input.version(); + output->interface_id = input.PassHandle().release(); +} + +template <typename T> +inline void AssociatedInterfaceDataToPtrInfo( + AssociatedInterface_Data* input, + AssociatedInterfacePtrInfo<T>* output, + MultiplexRouter* router) { + output->set_handle( + router->CreateLocalEndpointHandle(FetchAndReset(&input->interface_id))); + output->set_version(input->version); +} + +template <typename T> +inline void InterfacePointerToData(InterfacePtr<T> input, + Interface_Data* output, + SerializationContext* context) { + InterfacePtrInfo<T> info = input.PassInterface(); + output->handle = context->handles.AddHandle(info.PassHandle().release()); + output->version = info.version(); +} + +template <typename T> +inline void InterfaceDataToPointer(Interface_Data* input, + InterfacePtr<T>* output, + SerializationContext* context) { + output->Bind(InterfacePtrInfo<T>( + context->handles.TakeHandleAs<mojo::MessagePipeHandle>(input->handle), + input->version)); +} + +template <typename T> +struct HasIsNullMethod { + template <typename U> + static char Test(decltype(U::IsNull)*); + template <typename U> + static int Test(...); + static const bool value = sizeof(Test<T>(0)) == sizeof(char); + + private: + EnsureTypeIsComplete<T> check_t_; +}; + +template < + typename Traits, + typename UserType, + typename std::enable_if<HasIsNullMethod<Traits>::value>::type* = nullptr> +bool CallIsNullIfExists(const UserType& input) { + return Traits::IsNull(input); +} + +template < + typename Traits, + typename UserType, + typename std::enable_if<!HasIsNullMethod<Traits>::value>::type* = nullptr> +bool CallIsNullIfExists(const UserType& input) { + return false; +} +template <typename T> +struct HasSetToNullMethod { + template <typename U> + static char Test(decltype(U::SetToNull)*); + template <typename U> + static int Test(...); + static const bool value = sizeof(Test<T>(0)) == sizeof(char); + + private: + EnsureTypeIsComplete<T> check_t_; +}; + +template < + typename Traits, + typename UserType, + typename std::enable_if<HasSetToNullMethod<Traits>::value>::type* = nullptr> +bool CallSetToNullIfExists(UserType* output) { + Traits::SetToNull(output); + return true; +} + +template <typename Traits, + typename UserType, + typename std::enable_if<!HasSetToNullMethod<Traits>::value>::type* = + nullptr> +bool CallSetToNullIfExists(UserType* output) { + LOG(ERROR) << "A null value is received. But the Struct/Array/StringTraits " + << "class doesn't define a SetToNull() function and therefore is " + << "unable to deserialize the value."; + return false; +} + +template <typename T> +struct HasSetUpContextMethod { + template <typename U> + static char Test(decltype(U::SetUpContext)*); + template <typename U> + static int Test(...); + static const bool value = sizeof(Test<T>(0)) == sizeof(char); + + private: + EnsureTypeIsComplete<T> check_t_; +}; + +template <typename Traits, + bool has_context = HasSetUpContextMethod<Traits>::value> +struct CustomContextHelper; + +template <typename Traits> +struct CustomContextHelper<Traits, true> { + template <typename MaybeConstUserType> + static void* SetUp(MaybeConstUserType& input, SerializationContext* context) { + void* custom_context = Traits::SetUpContext(input); + if (!context->custom_contexts) + context->custom_contexts.reset(new std::queue<void*>()); + context->custom_contexts->push(custom_context); + return custom_context; + } + + static void* GetNext(SerializationContext* context) { + void* custom_context = context->custom_contexts->front(); + context->custom_contexts->pop(); + return custom_context; + } + + template <typename MaybeConstUserType> + static void TearDown(MaybeConstUserType& input, void* custom_context) { + Traits::TearDownContext(input, custom_context); + } +}; + +template <typename Traits> +struct CustomContextHelper<Traits, false> { + template <typename MaybeConstUserType> + static void* SetUp(MaybeConstUserType& input, SerializationContext* context) { + return nullptr; + } + + static void* GetNext(SerializationContext* context) { return nullptr; } + + template <typename MaybeConstUserType> + static void TearDown(MaybeConstUserType& input, void* custom_context) { + DCHECK(!custom_context); + } +}; + +template <typename ReturnType, typename ParamType, typename MaybeConstUserType> +ReturnType CallWithContext(ReturnType (*f)(ParamType, void*), + MaybeConstUserType& input, + void* context) { + return f(input, context); +} + +template <typename ReturnType, typename ParamType, typename MaybeConstUserType> +ReturnType CallWithContext(ReturnType (*f)(ParamType), + MaybeConstUserType& input, + void* context) { + return f(input); +} + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_UTIL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/string_serialization.cc b/chromium/mojo/public/cpp/bindings/lib/string_serialization.cc deleted file mode 100644 index 6b9f741457c..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/string_serialization.cc +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/public/cpp/bindings/lib/string_serialization.h" - -#include <stddef.h> -#include <string.h> - -namespace mojo { - -size_t GetSerializedSize_(const String& input, - internal::SerializationContext* context) { - if (!input) - return 0; - return internal::Align(sizeof(internal::String_Data) + input.size()); -} - -void Serialize_(const String& input, - internal::Buffer* buf, - internal::String_Data** output, - internal::SerializationContext* context) { - if (input) { - internal::String_Data* result = - internal::String_Data::New(input.size(), buf); - if (result) - memcpy(result->storage(), input.data(), input.size()); - *output = result; - } else { - *output = nullptr; - } -} - -bool Deserialize_(internal::String_Data* input, - String* output, - internal::SerializationContext* context) { - if (input) { - String result(input->storage(), input->size()); - result.Swap(output); - } else { - *output = nullptr; - } - return true; -} - -} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/string_serialization.h b/chromium/mojo/public/cpp/bindings/lib/string_serialization.h index a1ae951bdb2..5e65891ef5e 100644 --- a/chromium/mojo/public/cpp/bindings/lib/string_serialization.h +++ b/chromium/mojo/public/cpp/bindings/lib/string_serialization.h @@ -6,22 +6,65 @@ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_STRING_SERIALIZATION_H_ #include <stddef.h> +#include <string.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/serialization_util.h" #include "mojo/public/cpp/bindings/string.h" +#include "mojo/public/cpp/bindings/string_traits.h" namespace mojo { +namespace internal { -size_t GetSerializedSize_(const String& input, - internal::SerializationContext* context); -void Serialize_(const String& input, - internal::Buffer* buffer, - internal::String_Data** output, - internal::SerializationContext* context); -bool Deserialize_(internal::String_Data* input, - String* output, - internal::SerializationContext* context); +template <typename MaybeConstUserType> +struct Serializer<String, MaybeConstUserType> { + using UserType = typename std::remove_const<MaybeConstUserType>::type; + using Traits = StringTraits<UserType>; + static size_t PrepareToSerialize(MaybeConstUserType& input, + SerializationContext* context) { + if (CallIsNullIfExists<Traits>(input)) + return 0; + + void* custom_context = CustomContextHelper<Traits>::SetUp(input, context); + return Align(sizeof(String_Data) + + CallWithContext(Traits::GetSize, input, custom_context)); + } + + static void Serialize(MaybeConstUserType& input, + Buffer* buffer, + String_Data** output, + SerializationContext* context) { + if (CallIsNullIfExists<Traits>(input)) { + *output = nullptr; + return; + } + + void* custom_context = CustomContextHelper<Traits>::GetNext(context); + + String_Data* result = String_Data::New( + CallWithContext(Traits::GetSize, input, custom_context), buffer); + if (result) { + memcpy(result->storage(), + CallWithContext(Traits::GetData, input, custom_context), + CallWithContext(Traits::GetSize, input, custom_context)); + } + *output = result; + + CustomContextHelper<Traits>::TearDown(input, custom_context); + } + + static bool Deserialize(String_Data* input, + UserType* output, + SerializationContext* context) { + if (!input) + return CallSetToNullIfExists<Traits>(output); + return Traits::Read(StringDataView(input), output); + } +}; + +} // namespace internal } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_STRING_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/string_traits_string16.cc b/chromium/mojo/public/cpp/bindings/lib/string_traits_string16.cc new file mode 100644 index 00000000000..95ff6ccf257 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/string_traits_string16.cc @@ -0,0 +1,42 @@ +// 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/string_traits_string16.h" + +#include <string> + +#include "base/strings/utf_string_conversions.h" + +namespace mojo { + +// static +void* StringTraits<base::string16>::SetUpContext(const base::string16& input) { + return new std::string(base::UTF16ToUTF8(input)); +} + +// static +void StringTraits<base::string16>::TearDownContext(const base::string16& input, + void* context) { + delete static_cast<std::string*>(context); +} + +// static +size_t StringTraits<base::string16>::GetSize(const base::string16& input, + void* context) { + return static_cast<std::string*>(context)->size(); +} + +// static +const char* StringTraits<base::string16>::GetData(const base::string16& input, + void* context) { + return static_cast<std::string*>(context)->data(); +} + +// static +bool StringTraits<base::string16>::Read(StringDataView input, + base::string16* output) { + return base::UTF8ToUTF16(input.storage(), input.size(), output); +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/string_traits_wtf.cc b/chromium/mojo/public/cpp/bindings/lib/string_traits_wtf.cc new file mode 100644 index 00000000000..19fa9074483 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/string_traits_wtf.cc @@ -0,0 +1,85 @@ +// 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/string_traits_wtf.h" + +#include <string.h> + +#include "base/logging.h" +#include "mojo/public/cpp/bindings/lib/array_internal.h" +#include "third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h" + +namespace mojo { +namespace { + +struct UTF8AdaptorInfo { + explicit UTF8AdaptorInfo(const WTF::String& input) : utf8_adaptor(input) { +#if DCHECK_IS_ON() + original_size_in_bytes = static_cast<size_t>(input.sizeInBytes()); +#endif + } + + ~UTF8AdaptorInfo() {} + + WTF::StringUTF8Adaptor utf8_adaptor; + +#if DCHECK_IS_ON() + // For sanity check only. + size_t original_size_in_bytes; +#endif +}; + +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, + static_cast<size_t>(input.sizeInBytes())); +#endif + return adaptor; +} + +} // namespace + +// static +void StringTraits<WTF::String>::SetToNull(WTF::String* output) { + if (output->isNull()) + return; + + WTF::String result; + output->swap(result); +} + +// static +void* StringTraits<WTF::String>::SetUpContext(const WTF::String& input) { + return new UTF8AdaptorInfo(input); +} + +// static +void StringTraits<WTF::String>::TearDownContext(const WTF::String& input, + void* context) { + delete ToAdaptor(input, context); +} + +// static +size_t StringTraits<WTF::String>::GetSize(const WTF::String& input, + void* context) { + return ToAdaptor(input, context)->utf8_adaptor.length(); +} + +// static +const char* StringTraits<WTF::String>::GetData(const WTF::String& input, + void* context) { + return ToAdaptor(input, context)->utf8_adaptor.data(); +} + +// static +bool StringTraits<WTF::String>::Read(StringDataView input, + WTF::String* output) { + WTF::String result = WTF::String::fromUTF8(input.storage(), input.size()); + output->swap(result); + return true; +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/sync_handle_registry.cc b/chromium/mojo/public/cpp/bindings/lib/sync_handle_registry.cc index 3d88ec96da7..e4b49557937 100644 --- a/chromium/mojo/public/cpp/bindings/lib/sync_handle_registry.cc +++ b/chromium/mojo/public/cpp/bindings/lib/sync_handle_registry.cc @@ -20,11 +20,12 @@ base::LazyInstance<base::ThreadLocalPointer<SyncHandleRegistry>> } // namespace // static -SyncHandleRegistry* SyncHandleRegistry::current() { - SyncHandleRegistry* result = g_current_sync_handle_watcher.Pointer()->Get(); +scoped_refptr<SyncHandleRegistry> SyncHandleRegistry::current() { + scoped_refptr<SyncHandleRegistry> result( + g_current_sync_handle_watcher.Pointer()->Get()); if (!result) { result = new SyncHandleRegistry(); - DCHECK_EQ(result, g_current_sync_handle_watcher.Pointer()->Get()); + DCHECK_EQ(result.get(), g_current_sync_handle_watcher.Pointer()->Get()); } return result; } @@ -66,10 +67,8 @@ bool SyncHandleRegistry::WatchAllHandles(const bool* should_stop[], MojoHandle ready_handle; MojoResult ready_handle_result; - // This object may be destroyed during a callback. So we have to preserve - // the boolean. - scoped_refptr<base::RefCountedData<bool>> destroyed = destroyed_; - while (!destroyed->data) { + scoped_refptr<SyncHandleRegistry> preserver(this); + while (true) { for (size_t i = 0; i < count; ++i) if (*should_stop[i]) return true; @@ -96,8 +95,7 @@ bool SyncHandleRegistry::WatchAllHandles(const bool* should_stop[], return false; } -SyncHandleRegistry::SyncHandleRegistry() - : destroyed_(new base::RefCountedData<bool>(false)) { +SyncHandleRegistry::SyncHandleRegistry() { MojoHandle handle; MojoResult result = MojoCreateWaitSet(&handle); CHECK_EQ(MOJO_RESULT_OK, result); @@ -106,24 +104,12 @@ SyncHandleRegistry::SyncHandleRegistry() DCHECK(!g_current_sync_handle_watcher.Pointer()->Get()); g_current_sync_handle_watcher.Pointer()->Set(this); - - base::MessageLoop::current()->AddDestructionObserver(this); } SyncHandleRegistry::~SyncHandleRegistry() { DCHECK(thread_checker_.CalledOnValidThread()); - destroyed_->data = true; g_current_sync_handle_watcher.Pointer()->Set(nullptr); } -void SyncHandleRegistry::WillDestroyCurrentMessageLoop() { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_EQ(this, g_current_sync_handle_watcher.Pointer()->Get()); - - base::MessageLoop::current()->RemoveDestructionObserver(this); - - delete this; -} - } // namespace internal } // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/sync_handle_registry.h b/chromium/mojo/public/cpp/bindings/lib/sync_handle_registry.h index df927dbb543..d6b8c38e0ce 100644 --- a/chromium/mojo/public/cpp/bindings/lib/sync_handle_registry.h +++ b/chromium/mojo/public/cpp/bindings/lib/sync_handle_registry.h @@ -9,7 +9,7 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/message_loop/message_loop.h" +#include "base/memory/ref_counted.h" #include "base/threading/thread_checker.h" #include "mojo/public/cpp/system/core.h" @@ -20,10 +20,10 @@ namespace internal { // be watched together. // // This class is not thread safe. -class SyncHandleRegistry : public base::MessageLoop::DestructionObserver { +class SyncHandleRegistry : public base::RefCounted<SyncHandleRegistry> { public: // Returns a thread-local object. - static SyncHandleRegistry* current(); + static scoped_refptr<SyncHandleRegistry> current(); using HandleCallback = base::Callback<void(MojoResult)>; bool RegisterHandle(const Handle& handle, @@ -40,6 +40,8 @@ class SyncHandleRegistry : public base::MessageLoop::DestructionObserver { 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())); @@ -48,17 +50,12 @@ class SyncHandleRegistry : public base::MessageLoop::DestructionObserver { using HandleMap = std::unordered_map<Handle, HandleCallback, HandleHasher>; SyncHandleRegistry(); - ~SyncHandleRegistry() override; - - // base::MessageLoop::DestructionObserver implementation: - void WillDestroyCurrentMessageLoop() override; + ~SyncHandleRegistry(); HandleMap handles_; ScopedHandle wait_set_handle_; - scoped_refptr<base::RefCountedData<bool>> destroyed_; - base::ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(SyncHandleRegistry); diff --git a/chromium/mojo/public/cpp/bindings/lib/sync_handle_watcher.cc b/chromium/mojo/public/cpp/bindings/lib/sync_handle_watcher.cc index e259578634b..44092038e78 100644 --- a/chromium/mojo/public/cpp/bindings/lib/sync_handle_watcher.cc +++ b/chromium/mojo/public/cpp/bindings/lib/sync_handle_watcher.cc @@ -18,12 +18,13 @@ SyncHandleWatcher::SyncHandleWatcher( callback_(callback), registered_(false), register_request_count_(0), + registry_(SyncHandleRegistry::current()), destroyed_(new base::RefCountedData<bool>(false)) {} SyncHandleWatcher::~SyncHandleWatcher() { DCHECK(thread_checker_.CalledOnValidThread()); if (registered_) - SyncHandleRegistry::current()->UnregisterHandle(handle_); + registry_->UnregisterHandle(handle_); destroyed_->data = true; } @@ -45,8 +46,7 @@ bool SyncHandleWatcher::SyncWatch(const bool* should_stop) { // to preserve the boolean that WatchAllHandles uses. auto destroyed = destroyed_; const bool* should_stop_array[] = {should_stop, &destroyed->data}; - bool result = - SyncHandleRegistry::current()->WatchAllHandles(should_stop_array, 2); + bool result = registry_->WatchAllHandles(should_stop_array, 2); // This object has been destroyed. if (destroyed->data) @@ -59,8 +59,8 @@ bool SyncHandleWatcher::SyncWatch(const bool* should_stop) { void SyncHandleWatcher::IncrementRegisterCount() { register_request_count_++; if (!registered_) { - registered_ = SyncHandleRegistry::current()->RegisterHandle( - handle_, handle_signals_, callback_); + registered_ = + registry_->RegisterHandle(handle_, handle_signals_, callback_); } } @@ -69,7 +69,7 @@ void SyncHandleWatcher::DecrementRegisterCount() { register_request_count_--; if (register_request_count_ == 0 && registered_) { - SyncHandleRegistry::current()->UnregisterHandle(handle_); + registry_->UnregisterHandle(handle_); registered_ = false; } } diff --git a/chromium/mojo/public/cpp/bindings/lib/sync_handle_watcher.h b/chromium/mojo/public/cpp/bindings/lib/sync_handle_watcher.h index 8d4fd5510a5..93d527bdc83 100644 --- a/chromium/mojo/public/cpp/bindings/lib/sync_handle_watcher.h +++ b/chromium/mojo/public/cpp/bindings/lib/sync_handle_watcher.h @@ -61,6 +61,8 @@ class SyncHandleWatcher { // If non-zero, |handle_| should be registered with SyncHandleRegistry. size_t register_request_count_; + scoped_refptr<SyncHandleRegistry> registry_; + scoped_refptr<base::RefCountedData<bool>> destroyed_; base::ThreadChecker thread_checker_; diff --git a/chromium/mojo/public/cpp/bindings/lib/validate_params.h b/chromium/mojo/public/cpp/bindings/lib/validate_params.h index 78c05892f4f..2509b6bb0a6 100644 --- a/chromium/mojo/public/cpp/bindings/lib/validate_params.h +++ b/chromium/mojo/public/cpp/bindings/lib/validate_params.h @@ -12,6 +12,8 @@ namespace mojo { namespace internal { +using ValidateEnumFunc = bool (*)(int32_t); + class ArrayValidateParams { public: // ArrayValidateParams takes ownership of |in_element_validate params|. @@ -20,15 +22,22 @@ class ArrayValidateParams { ArrayValidateParams* in_element_validate_params) : expected_num_elements(in_expected_num_elements), element_is_nullable(in_element_is_nullable), - element_validate_params(in_element_validate_params) {} + element_validate_params(in_element_validate_params), + validate_enum_func(nullptr) {} + + // Validates an array of enums. + ArrayValidateParams(uint32_t in_expected_num_elements, + ValidateEnumFunc in_validate_enum_func) + : expected_num_elements(in_expected_num_elements), + element_is_nullable(false), + element_validate_params(nullptr), + validate_enum_func(in_validate_enum_func) {} ~ArrayValidateParams() { if (element_validate_params) delete element_validate_params; } - // TODO(vtl): The members of this class shouldn't be public. - // If |expected_num_elements| is not 0, the array is expected to have exactly // that number of elements. uint32_t expected_num_elements; @@ -41,6 +50,9 @@ class ArrayValidateParams { // nullptr. In the case of maps, this is used to validate the value array. ArrayValidateParams* element_validate_params; + // Validation function for enum elements. + ValidateEnumFunc validate_enum_func; + private: DISALLOW_COPY_AND_ASSIGN(ArrayValidateParams); }; diff --git a/chromium/mojo/public/cpp/bindings/lib/validation_util.cc b/chromium/mojo/public/cpp/bindings/lib/validation_util.cc index 70dcb29c5e2..28d52884cdc 100644 --- a/chromium/mojo/public/cpp/bindings/lib/validation_util.cc +++ b/chromium/mojo/public/cpp/bindings/lib/validation_util.cc @@ -8,8 +8,8 @@ #include <limits> -#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" #include "mojo/public/cpp/bindings/lib/message_internal.h" +#include "mojo/public/cpp/bindings/lib/serialization_util.h" #include "mojo/public/cpp/bindings/lib/validation_errors.h" #include "mojo/public/interfaces/bindings/interface_control_messages.mojom.h" @@ -52,6 +52,26 @@ bool ValidateStructHeaderAndClaimMemory(const void* data, return true; } +bool ValidateUnionHeaderAndClaimMemory(const void* data, + bool inlined, + BoundsChecker* bounds_checker) { + if (!IsAligned(data)) { + ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT); + return false; + } + + // 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 && !bounds_checker->ClaimMemory(data, kUnionDataSize)) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); + return false; + } + + return true; +} + bool ValidateMessageIsRequestWithoutResponse(const Message* message) { if (message->has_flag(kMessageIsResponse) || message->has_flag(kMessageExpectsResponse)) { @@ -101,8 +121,9 @@ bool ValidateControlResponse(const Message* message) { return false; } -bool ValidateHandleNonNullable(const Handle& input, const char* error_message) { - if (input.value() != kEncodedInvalidHandleValue) +bool ValidateHandleNonNullable(const Handle_Data& input, + const char* error_message) { + if (input.is_valid()) return true; ReportValidationError(VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, @@ -120,7 +141,7 @@ bool ValidateInterfaceIdNonNullable(InterfaceId input, return false; } -bool ValidateHandle(const Handle& input, BoundsChecker* bounds_checker) { +bool ValidateHandle(const Handle_Data& input, BoundsChecker* bounds_checker) { if (bounds_checker->ClaimHandle(input)) return true; diff --git a/chromium/mojo/public/cpp/bindings/lib/validation_util.h b/chromium/mojo/public/cpp/bindings/lib/validation_util.h index 5314a362702..6189ffda40b 100644 --- a/chromium/mojo/public/cpp/bindings/lib/validation_util.h +++ b/chromium/mojo/public/cpp/bindings/lib/validation_util.h @@ -9,6 +9,7 @@ #include "mojo/public/cpp/bindings/lib/bindings_internal.h" #include "mojo/public/cpp/bindings/lib/bounds_checker.h" +#include "mojo/public/cpp/bindings/lib/serialization_util.h" #include "mojo/public/cpp/bindings/lib/validate_params.h" #include "mojo/public/cpp/bindings/lib/validation_errors.h" #include "mojo/public/cpp/bindings/message.h" @@ -30,6 +31,14 @@ bool ValidateEncodedPointer(const uint64_t* offset); bool ValidateStructHeaderAndClaimMemory(const void* data, BoundsChecker* bounds_checker); +// Validates that |data| contains a valid union header, in terms of alignment +// and size. If not inlined, it checks that the memory range +// [data, data + num_bytes) is not marked as occupied by other objects in +// |bounds_checker|. On success, the memory range is marked as occupied. +bool ValidateUnionHeaderAndClaimMemory(const void* data, + bool inlined, + BoundsChecker* bounds_checker); + // Validates that the message is a request which doesn't expect a response. bool ValidateMessageIsRequestWithoutResponse(const Message* message); // Validates that the message is a request expecting a response. @@ -73,13 +82,14 @@ bool ValidateInlinedUnionNonNullable(const T& input, return false; } -bool ValidateHandleNonNullable(const Handle& input, const char* error_message); +bool ValidateHandleNonNullable(const Handle_Data& input, + const char* error_message); bool ValidateInterfaceIdNonNullable(InterfaceId input, const char* error_message); template <typename T> -bool ValidateArray(const ArrayPointer<T>& input, +bool ValidateArray(const Pointer<Array_Data<T>>& input, BoundsChecker* bounds_checker, const ArrayValidateParams* validate_params) { if (!ValidateEncodedPointer(&input.offset)) { @@ -92,7 +102,7 @@ bool ValidateArray(const ArrayPointer<T>& input, } template <typename T> -bool ValidateMap(const StructPointer<T>& input, +bool ValidateMap(const Pointer<T>& input, BoundsChecker* bounds_checker, const ArrayValidateParams* value_validate_params) { if (!ValidateEncodedPointer(&input.offset)) { @@ -105,8 +115,7 @@ bool ValidateMap(const StructPointer<T>& input, } template <typename T> -bool ValidateStruct(const StructPointer<T>& input, - BoundsChecker* bounds_checker) { +bool ValidateStruct(const Pointer<T>& input, BoundsChecker* bounds_checker) { if (!ValidateEncodedPointer(&input.offset)) { ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER); return false; @@ -120,25 +129,21 @@ bool ValidateInlinedUnion(const T& input, BoundsChecker* bounds_checker) { return T::Validate(&input, bounds_checker, true); } -bool ValidateHandle(const Handle& input, BoundsChecker* bounds_checker); - -bool ValidateAssociatedInterfaceId(InterfaceId input); - -// Checks whether the given enum value is valid. Please note that any value is -// valid for an extensible enum, although it may be from a newer version and -// thus unknown. template <typename T> -bool ValidateEnum(const T& input) { - if (T::kIsExtensible) - return true; - - if (T::IsKnownValue(input.value)) - return true; +bool ValidateNonInlinedUnion(const Pointer<T>& input, + BoundsChecker* bounds_checker) { + if (!ValidateEncodedPointer(&input.offset)) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER); + return false; + } - ReportValidationError(VALIDATION_ERROR_UNKNOWN_ENUM_VALUE); - return false; + return T::Validate(DecodePointerRaw(&input.offset), bounds_checker, false); } +bool ValidateHandle(const Handle_Data& input, BoundsChecker* bounds_checker); + +bool ValidateAssociatedInterfaceId(InterfaceId input); + } // namespace internal } // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/wtf_array_serialization.h b/chromium/mojo/public/cpp/bindings/lib/wtf_array_serialization.h deleted file mode 100644 index 70edbf1fe6b..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/wtf_array_serialization.h +++ /dev/null @@ -1,43 +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_WTF_ARRAY_SERIALIZATION_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_ARRAY_SERIALIZATION_H_ - -#include <stddef.h> - -#include "mojo/public/cpp/bindings/lib/array_serialization_traits.h" -#include "mojo/public/cpp/bindings/wtf_array.h" - -namespace mojo { - -template <typename E> -inline size_t GetSerializedSize_(const WTFArray<E>& input, - internal::SerializationContext* context) { - return internal::ArraySerializationImpl<WTFArray<E>>::GetSerializedSize( - input, context); -} - -template <typename E, typename F> -inline void SerializeArray_( - WTFArray<E> input, - internal::Buffer* buf, - internal::Array_Data<F>** output, - const internal::ArrayValidateParams* validate_params, - internal::SerializationContext* context) { - return internal::ArraySerializationImpl<WTFArray<E>>::template Serialize<F>( - std::move(input), buf, output, validate_params, context); -} - -template <typename E, typename F> -inline bool Deserialize_(internal::Array_Data<F>* input, - WTFArray<E>* output, - internal::SerializationContext* context) { - return internal::ArraySerializationImpl<WTFArray<E>>::template Deserialize<F>( - input, output, context); -} - -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_ARRAY_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/wtf_serialization.h b/chromium/mojo/public/cpp/bindings/lib/wtf_serialization.h index 318d1522231..dbb3f9edbca 100644 --- a/chromium/mojo/public/cpp/bindings/lib/wtf_serialization.h +++ b/chromium/mojo/public/cpp/bindings/lib/wtf_serialization.h @@ -5,7 +5,8 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_SERIALIZATION_H_ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_SERIALIZATION_H_ -#include "mojo/public/cpp/bindings/lib/wtf_array_serialization.h" -#include "mojo/public/cpp/bindings/lib/wtf_string_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/string_traits_wtf.h" #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/wtf_string_serialization.cc b/chromium/mojo/public/cpp/bindings/lib/wtf_string_serialization.cc deleted file mode 100644 index febd073ff5e..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/wtf_string_serialization.cc +++ /dev/null @@ -1,118 +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. - -#include "mojo/public/cpp/bindings/lib/wtf_string_serialization.h" - -#include <string.h> - -#include <queue> - -#include "base/logging.h" -#include "third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h" -#include "third_party/WebKit/Source/wtf/text/WTFString.h" - -namespace WTF { -namespace { - -struct UTF8AdaptorInfo { - explicit UTF8AdaptorInfo(const WTF::String& input) : utf8_adaptor(input) { -#if DCHECK_IS_ON() - original_size_in_bytes = static_cast<size_t>(input.sizeInBytes()); -#endif - } - - ~UTF8AdaptorInfo() {} - - WTF::StringUTF8Adaptor utf8_adaptor; - -#if DCHECK_IS_ON() - // For sanity check only. - size_t original_size_in_bytes; -#endif -}; - -class WTFStringContextImpl : public mojo::internal::WTFStringContext { - public: - WTFStringContextImpl() {} - ~WTFStringContextImpl() override {} - - std::queue<UTF8AdaptorInfo>& utf8_adaptors() { return utf8_adaptors_; } - - private: - // When serializing an object, we call GetSerializedSize_() recursively on - // all its elements/members to compute the total size, and then call - // Serialize*_() recursively in the same order to do the actual - // serialization. If some WTF::Strings need to be converted to UTF8, we don't - // want to do that twice. Therefore, we store a WTF::StringUTF8Adaptor for - // each in the first pass, and reuse it in the second pass. - std::queue<UTF8AdaptorInfo> utf8_adaptors_; - - DISALLOW_COPY_AND_ASSIGN(WTFStringContextImpl); -}; - -} // namespace - -size_t GetSerializedSize_(const WTF::String& input, - mojo::internal::SerializationContext* context) { - if (input.isNull()) - return 0; - - if (!context->wtf_string_context) - context->wtf_string_context.reset(new WTFStringContextImpl); - - auto& utf8_adaptors = - static_cast<WTFStringContextImpl*>(context->wtf_string_context.get()) - ->utf8_adaptors(); - - utf8_adaptors.emplace(input); - - return mojo::internal::Align(sizeof(mojo::internal::String_Data) + - utf8_adaptors.back().utf8_adaptor.length()); -} - -void Serialize_(const WTF::String& input, - mojo::internal::Buffer* buf, - mojo::internal::String_Data** output, - mojo::internal::SerializationContext* context) { - if (input.isNull()) { - *output = nullptr; - return; - } - - auto& utf8_adaptors = - static_cast<WTFStringContextImpl*>(context->wtf_string_context.get()) - ->utf8_adaptors(); - - DCHECK(!utf8_adaptors.empty()); -#if DCHECK_IS_ON() - DCHECK_EQ(utf8_adaptors.front().original_size_in_bytes, - static_cast<size_t>(input.sizeInBytes())); -#endif - - const WTF::StringUTF8Adaptor& adaptor = utf8_adaptors.front().utf8_adaptor; - - mojo::internal::String_Data* result = - mojo::internal::String_Data::New(adaptor.length(), buf); - if (result) - memcpy(result->storage(), adaptor.data(), adaptor.length()); - - utf8_adaptors.pop(); - - *output = result; -} - -bool Deserialize_(mojo::internal::String_Data* input, - WTF::String* output, - mojo::internal::SerializationContext* context) { - if (input) { - WTF::String result = WTF::String::fromUTF8(input->storage(), input->size()); - output->swap(result); - } else if (!output->isNull()) { - WTF::String result; - output->swap(result); - } - return true; -} - -} // namespace WTF diff --git a/chromium/mojo/public/cpp/bindings/lib/wtf_string_serialization.h b/chromium/mojo/public/cpp/bindings/lib/wtf_string_serialization.h deleted file mode 100644 index a1102654dcd..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/wtf_string_serialization.h +++ /dev/null @@ -1,28 +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_WTF_STRING_SERIALIZATION_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_STRING_SERIALIZATION_H_ - -#include <stddef.h> - -#include "mojo/public/cpp/bindings/lib/array_internal.h" -#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" - -namespace WTF { -class String; - -size_t GetSerializedSize_(const WTF::String& input, - mojo::internal::SerializationContext* context); -void Serialize_(const WTF::String& input, - mojo::internal::Buffer* buffer, - mojo::internal::String_Data** output, - mojo::internal::SerializationContext* context); -bool Deserialize_(mojo::internal::String_Data* input, - WTF::String* output, - mojo::internal::SerializationContext* context); - -} // namespace WTF - -#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_STRING_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/map.h b/chromium/mojo/public/cpp/bindings/map.h index 6d0d57d6793..f1cdd41ae7c 100644 --- a/chromium/mojo/public/cpp/bindings/map.h +++ b/chromium/mojo/public/cpp/bindings/map.h @@ -24,20 +24,23 @@ namespace mojo { // - 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 Key, typename Value> +template <typename K, typename V> class Map { MOVE_ONLY_TYPE_FOR_CPP_03(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 ConstIterator = typename std::map<Key, Value>::const_iterator; - using Data_ = - internal::Map_Data<typename internal::WrapperTraits<Key>::DataType, - typename internal::WrapperTraits<Value>::DataType>; + using Data_ = internal::Map_Data< + typename internal::GetDataTypeAsArrayElement<Key>::Data, + typename internal::GetDataTypeAsArrayElement<Value>::Data>; // Constructs an empty map. Map() : is_null_(false) {} diff --git a/chromium/mojo/public/cpp/bindings/message.h b/chromium/mojo/public/cpp/bindings/message.h index 51636693c71..d8eed2bfc3e 100644 --- a/chromium/mojo/public/cpp/bindings/message.h +++ b/chromium/mojo/public/cpp/bindings/message.h @@ -9,12 +9,13 @@ #include <stdint.h> #include <limits> +#include <memory> #include <vector> #include "base/logging.h" -#include "base/memory/scoped_ptr.h" +#include "mojo/public/cpp/bindings/lib/message_buffer.h" #include "mojo/public/cpp/bindings/lib/message_internal.h" -#include "mojo/public/cpp/bindings/lib/pickle_buffer.h" +#include "mojo/public/cpp/system/message.h" namespace mojo { @@ -27,15 +28,18 @@ class Message { Message(); ~Message(); + // Initializes a Message with enough space for |capacity| bytes. void Initialize(size_t capacity, bool zero_initialized); + // Initializes a Message from an existing Mojo MessageHandle. + void InitializeFromMojoMessage(ScopedMessageHandle message, + uint32_t num_bytes, + std::vector<Handle>* handles); + // Transfers data and handles to |destination|. void MoveTo(Message* destination); - uint32_t data_num_bytes() const { - DCHECK(buffer_->data_num_bytes() <= std::numeric_limits<uint32_t>::max()); - return static_cast<uint32_t>(buffer_->data_num_bytes()); - } + uint32_t data_num_bytes() const { return buffer_->data_num_bytes(); } // Access the raw bytes of the message. const uint8_t* data() const { @@ -90,10 +94,15 @@ class Message { // Access the underlying Buffer interface. internal::Buffer* buffer() { return buffer_.get(); } + // Takes a scoped MessageHandle which may be passed to |WriteMessageNew()| for + // transmission. Note that this invalidates this Message object, taking + // ownership of its internal storage and any attached handles. + ScopedMessageHandle TakeMojoMessage(); + private: void CloseHandles(); - scoped_ptr<internal::PickleBuffer> buffer_; + std::unique_ptr<internal::MessageBuffer> buffer_; std::vector<Handle> handles_; DISALLOW_COPY_AND_ASSIGN(Message); @@ -122,7 +131,8 @@ class MessageReceiverWithResponder : public MessageReceiver { // |responder| and will delete it after calling |responder->Accept| or upon // its own destruction. // - // TODO(yzshen): consider changing |responder| to scoped_ptr<MessageReceiver>. + // TODO(yzshen): consider changing |responder| to + // std::unique_ptr<MessageReceiver>. virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) WARN_UNUSED_RESULT = 0; }; @@ -160,7 +170,8 @@ class MessageReceiverWithResponderStatus : public MessageReceiver { // |responder| and will delete it after calling |responder->Accept| or upon // its own destruction. // - // TODO(yzshen): consider changing |responder| to scoped_ptr<MessageReceiver>. + // TODO(yzshen): consider changing |responder| to + // std::unique_ptr<MessageReceiver>. virtual bool AcceptWithResponder(Message* message, MessageReceiverWithStatus* responder) WARN_UNUSED_RESULT = 0; diff --git a/chromium/mojo/public/cpp/bindings/native_struct.h b/chromium/mojo/public/cpp/bindings/native_struct.h new file mode 100644 index 00000000000..882c970ce25 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/native_struct.h @@ -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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_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" + +namespace mojo { + +class NativeStruct; +using NativeStructPtr = StructPtr<NativeStruct>; + +// Native-only structs correspond to "[Native] struct Foo;" definitions in +// mojom. +class NativeStruct { + public: + using Data_ = internal::NativeStruct_Data; + + static NativeStructPtr New(); + + template <typename U> + static NativeStructPtr From(const U& u) { + return TypeConverter<NativeStructPtr, U>::Convert(u); + } + + template <typename U> + U To() const { + return TypeConverter<U, NativeStruct>::Convert(*this); + } + + NativeStruct(); + ~NativeStruct(); + + NativeStructPtr Clone() const; + bool Equals(const NativeStruct& other) const; + + Array<uint8_t> data; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h b/chromium/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h index cb941812071..d13676470f0 100644 --- a/chromium/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h +++ b/chromium/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.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_SCOPED_INTERFACE_ENDPOINT_HANDLE_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_LIB_SCOPED_INTERFACE_ENDPOINT_HANDLE_H_ +#ifndef MOJO_PUBLIC_CPP_BINDINGS_SCOPED_INTERFACE_ENDPOINT_HANDLE_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_SCOPED_INTERFACE_ENDPOINT_HANDLE_H_ #include "base/macros.h" #include "base/memory/ref_counted.h" @@ -11,9 +11,10 @@ #include "mojo/public/cpp/bindings/lib/interface_id.h" namespace mojo { -namespace internal { +namespace internal { class MultiplexRouter; +} // ScopedInterfaceEndpointHandle refers to one end of an interface, either the // implementation side or the client side. @@ -24,14 +25,6 @@ class ScopedInterfaceEndpointHandle { // Creates an invalid endpoint handle. ScopedInterfaceEndpointHandle(); - // This is supposed to be used by MultiplexRouter only. - // |id| is the corresponding interface ID. - // If |is_local| is false, this handle is meant to be passed over |router| to - // the remote side. - ScopedInterfaceEndpointHandle(InterfaceId id, - bool is_local, - scoped_refptr<MultiplexRouter> router); - ScopedInterfaceEndpointHandle(ScopedInterfaceEndpointHandle&& other); ~ScopedInterfaceEndpointHandle(); @@ -39,25 +32,39 @@ class ScopedInterfaceEndpointHandle { ScopedInterfaceEndpointHandle& operator=( ScopedInterfaceEndpointHandle&& other); - bool is_valid() const { return IsValidInterfaceId(id_); } + bool is_valid() const { return internal::IsValidInterfaceId(id_); } - InterfaceId id() const { return id_; } bool is_local() const { return is_local_; } - MultiplexRouter* router() const { return router_.get(); } void reset(); void swap(ScopedInterfaceEndpointHandle& other); + // DO NOT USE METHODS BELOW THIS LINE. These are for internal use and testing. + + internal::InterfaceId id() const { return id_; } + + internal::MultiplexRouter* router() const { return router_.get(); } + // Releases the handle without closing it. - InterfaceId release(); + internal::InterfaceId release(); private: - InterfaceId id_; + friend class internal::MultiplexRouter; + + // This is supposed to be used by MultiplexRouter only. + // |id| is the corresponding interface ID. + // If |is_local| is false, this handle is meant to be passed over |router| to + // the remote side. + ScopedInterfaceEndpointHandle( + internal::InterfaceId id, + bool is_local, + scoped_refptr<internal::MultiplexRouter> router); + + internal::InterfaceId id_; bool is_local_; - scoped_refptr<MultiplexRouter> router_; + scoped_refptr<internal::MultiplexRouter> router_; }; -} // namespace internal } // namespace mojo -#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_SCOPED_INTERFACE_ENDPOINT_HANDLE_H_ +#endif // MOJO_PUBLIC_CPP_BINDINGS_SCOPED_INTERFACE_ENDPOINT_HANDLE_H_ diff --git a/chromium/mojo/public/cpp/bindings/string_traits.h b/chromium/mojo/public/cpp/bindings/string_traits.h new file mode 100644 index 00000000000..a6ade6fdf68 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/string_traits.h @@ -0,0 +1,69 @@ +// 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_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_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. +// +// Imagine you want to specialize it for CustomString, usually you need to +// implement: +// +// template <T> +// struct StringTraits<CustomString> { +// // These two methods are optional. Please see comments in struct_traits.h +// static bool IsNull(const CustomString& input); +// static void SetToNull(CustomString* output); +// +// static size_t GetSize(const CustomString& input); +// static const char* GetData(const CustomString& input); +// +// static bool Read(StringDataView input, CustomString* output); +// }; +// +// In some cases, you may need to do conversion before you can return the size +// and data as 8-bit characters for serialization. (For example, CustomString is +// UTF-16 string). In that case, you can add two optional methods: +// +// static void* SetUpContext(const CustomString& input); +// static void TearDownContext(const CustomString& input, void* context); +// +// And then you append a second parameter, void* context, to GetSize() and +// GetData(): +// +// static size_t GetSize(const CustomString& input, void* context); +// static const char* GetData(const CustomString& input, void* context); +// +// If a CustomString instance is not null, the serialization code will call +// SetUpContext() at the beginning, and pass the resulting context pointer to +// GetSize()/GetData(). After serialization is done, it calls TearDownContext() +// so that you can do any necessary cleanup. +// +template <typename T> +struct StringTraits; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_H_ diff --git a/chromium/mojo/public/cpp/bindings/string_traits_standard.h b/chromium/mojo/public/cpp/bindings/string_traits_standard.h new file mode 100644 index 00000000000..9b78d2473ec --- /dev/null +++ b/chromium/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/chromium/mojo/public/cpp/bindings/string_traits_stl.h b/chromium/mojo/public/cpp/bindings/string_traits_stl.h new file mode 100644 index 00000000000..f6cc8ad098f --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/string_traits_stl.h @@ -0,0 +1,38 @@ +// 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_STL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STL_H_ + +#include <string> + +#include "mojo/public/cpp/bindings/string_traits.h" + +namespace mojo { + +template <> +struct StringTraits<std::string> { + static bool IsNull(const std::string& input) { + // std::string is always converted to non-null mojom string. + return false; + } + + static void SetToNull(std::string* output) { + // std::string doesn't support null state. Set it to empty instead. + output->clear(); + } + + static size_t GetSize(const std::string& input) { return input.size(); } + + static const char* GetData(const std::string& input) { return input.data(); } + + static bool Read(StringDataView input, std::string* output) { + output->assign(input.storage(), input.size()); + return true; + } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STL_H_ diff --git a/chromium/mojo/public/cpp/bindings/string_traits_string16.h b/chromium/mojo/public/cpp/bindings/string_traits_string16.h new file mode 100644 index 00000000000..5a089080bd0 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/string_traits_string16.h @@ -0,0 +1,36 @@ +// 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_STRING16_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STRING16_H_ + +#include "base/strings/string16.h" +#include "mojo/public/cpp/bindings/string_traits.h" + +namespace mojo { + +template <> +struct StringTraits<base::string16> { + static bool IsNull(const base::string16& input) { + // base::string16 is always converted to non-null mojom string. + return false; + } + + static void SetToNull(base::string16* output) { + // Convert null to an "empty" base::string16. + output->clear(); + } + + static void* SetUpContext(const base::string16& input); + static void TearDownContext(const base::string16& input, void* context); + + static size_t GetSize(const base::string16& input, void* context); + static const char* GetData(const base::string16& input, void* context); + + static bool Read(StringDataView input, base::string16* output); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STRING16_H_ diff --git a/chromium/mojo/public/cpp/bindings/string_traits_string_piece.h b/chromium/mojo/public/cpp/bindings/string_traits_string_piece.h new file mode 100644 index 00000000000..af6be893ac0 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/string_traits_string_piece.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_STRING_TRAITS_STRING_PIECE_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STRING_PIECE_H_ + +#include "base/strings/string_piece.h" +#include "mojo/public/cpp/bindings/string_traits.h" + +namespace mojo { + +template <> +struct StringTraits<base::StringPiece> { + static bool IsNull(const base::StringPiece& input) { + // base::StringPiece is always converted to non-null mojom string. We could + // have let StringPiece containing a null data pointer map to null mojom + // string, but StringPiece::empty() returns true in this case. It seems + // confusing to mix the concept of empty and null strings, especially + // because they mean different things in mojom. + return false; + } + + static void SetToNull(base::StringPiece* output) { + // Convert null to an "empty" base::StringPiece. + output->set(nullptr, 0); + } + + static size_t GetSize(const base::StringPiece& input) { return input.size(); } + + static const char* GetData(const base::StringPiece& input) { + return input.data(); + } + + static bool Read(StringDataView input, base::StringPiece* output) { + output->set(input.storage(), input.size()); + return true; + } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STRING_PIECE_H_ diff --git a/chromium/mojo/public/cpp/bindings/string_traits_wtf.h b/chromium/mojo/public/cpp/bindings/string_traits_wtf.h new file mode 100644 index 00000000000..238c2eb1199 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/string_traits_wtf.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_WTF_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_WTF_H_ + +#include "mojo/public/cpp/bindings/lib/bindings_internal.h" +#include "mojo/public/cpp/bindings/string_traits.h" +#include "third_party/WebKit/Source/wtf/text/WTFString.h" + +namespace mojo { + +template <> +struct StringTraits<WTF::String> { + static bool IsNull(const WTF::String& input) { return input.isNull(); } + static void SetToNull(WTF::String* output); + + static void* SetUpContext(const WTF::String& input); + static void TearDownContext(const WTF::String& input, void* context); + + static size_t GetSize(const WTF::String& input, void* context); + + static const char* GetData(const WTF::String& input, void* context); + + static bool Read(StringDataView input, WTF::String* output); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_WTF_H_ diff --git a/chromium/mojo/public/cpp/bindings/struct_traits.h b/chromium/mojo/public/cpp/bindings/struct_traits.h index fb7290b20ab..ee9a336ba18 100644 --- a/chromium/mojo/public/cpp/bindings/struct_traits.h +++ b/chromium/mojo/public/cpp/bindings/struct_traits.h @@ -10,22 +10,97 @@ namespace mojo { // This must be specialized for any type |T| to be serialized/deserialized as // a mojom struct of type |MojomType|. // -// Each specialization must implement a few things: -// +// Each specialization needs to implement a few things: // 1. Static getters for each field in the Mojom type. These should be // of the form: // -// static <return type> <field name>(const T&) +// static <return type> <field name>(const T& input); // // and should return a serializable form of the named field as extracted -// from the referenced |T| instance. +// from |input|. +// +// Serializable form of a field: +// 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. +// +// - array: +// Value or reference of any type that has an ArrayTraits defined. +// Supported by default: std::vector, WTF::Vector (in blink). +// +// - struct: +// Value or reference of any type that has a StructTraits defined. +// +// 2. A static Read() method to set the contents of a |T| instance from a +// |MojomType|DataView (e.g., if |MojomType| is test::Example, the data +// view will be test::ExampleDataView). +// +// static bool Read(|MojomType|DataView data, T* output); +// +// 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 +// validation for |T| in this method. +// +// 3. [Optional] A static IsNull() method indicating whether a given |T| +// instance is null: +// +// static bool IsNull(const T& input); +// +// If this method returns true, it is guaranteed that none of the getters +// (described in section 1) will be called for the same |input|. So you +// don't have to check whether |input| is null in those getters. +// +// If it is not defined, |T| instances are always considered non-null. +// +// [Optional] A static SetToNull() method to set the contents of a given +// |T| instance to null. +// +// static void SetToNull(T* output); +// +// When a null serialized struct is received, the deserialization code +// calls this method instead of Read(). +// +// NOTE: It is to set |*output|'s contents to a null state, not to set the +// |output| pointer itself to null. "Null state" means whatever state you +// think it makes sense to map a null serialized struct to. +// +// If it is not defined, null is not allowed to be converted to |T|. In +// that case, an incoming null value is considered invalid and causes the +// message pipe to be disconnected. +// +// EXAMPLE: +// +// Mojom definition: +// struct Bar {}; +// struct Foo { +// int32 f_integer; +// string f_string; +// array<string> f_string_array; +// Bar f_bar; +// }; // -// 2. A static Read method to initialize a new |T| from a MojomType::Reader: +// StructTraits for Foo: +// template <> +// struct StructTraits<Foo, CustomFoo> { +// // Optional methods dealing with null: +// static bool IsNull(const CustomFoo& input); +// static void SetToNull(CustomFoo* output); // -// static bool Read(MojomType::Reader r, T* out); +// // Field getters: +// static int32_t f_integer(const CustomFoo& input); +// static const std::string& f_string(const CustomFoo& input); +// static const std::vector<std::string>& f_string_array( +// const CustomFoo& input); +// // Assuming there is a StructTraits<Bar, CustomBar> defined. +// static const CustomBar& f_bar(const CustomFoo& input); // -// The generated MojomType::Reader type provides a convenient, inexpensive -// view of a serialized struct's field data. +// static bool Read(FooDataView data, CustomFoo* output); +// }; // template <typename MojomType, typename T> struct StructTraits; diff --git a/chromium/mojo/public/cpp/bindings/wtf_array.h b/chromium/mojo/public/cpp/bindings/wtf_array.h index b5d1a30c363..06c910d5996 100644 --- a/chromium/mojo/public/cpp/bindings/wtf_array.h +++ b/chromium/mojo/public/cpp/bindings/wtf_array.h @@ -29,9 +29,9 @@ class WTFArray { MOVE_ONLY_TYPE_FOR_CPP_03(WTFArray); public: - using Data_ = - internal::Array_Data<typename internal::WrapperTraits<T>::DataType>; - using ElementType = T; + using Data_ = internal::Array_Data< + typename internal::GetDataTypeAsArrayElement<T>::Data>; + using Element = T; // Constructs an empty array. WTFArray() : is_null_(false) {} |