From dcab72d3dd89fb0b296bcf7d7f5937cd449183c0 Mon Sep 17 00:00:00 2001 From: rockot Date: Fri, 24 Apr 2015 14:53:03 -0700 Subject: [PATCH] Update mojo sdk to rev e7270700d671fa8e458b4d8c9e47f7bcfb65da0b This cherry-picks two mojo changes past e7270700, namely: mojo.gni fix: https://chromium.googlesource.com/external/mojo/+/c88997f930c71b7e6748948263c4c01d7e10bc75 generated C++ interface definition fix: https://chromium.googlesource.com/external/mojo/+/6f41dc4d98fc17a447cd48837cc8ff7edf8df465 Finally this CL also adds a default TaskTracker to the chromium mojo environment. BUG= TBR=ben@chromium.org Review URL: https://codereview.chromium.org/1101303002 Cr-Commit-Position: refs/heads/master@{#326890} --- .../content/browser/ServiceRegistryTest.java | 6 +- .../org/chromium/mojo/bindings/InterfacesTest.java | 2 +- mojo/environment/BUILD.gn | 5 + mojo/environment/default_task_tracker_impl.cc | 35 +++ mojo/environment/default_task_tracker_impl.h | 19 ++ mojo/environment/environment.cc | 8 + mojo/mojo_base.gyp | 7 +- third_party/mojo/mojo_public.gyp | 7 + third_party/mojo/src/mojo/public/VERSION | 2 +- .../mojo/src/mojo/public/cpp/bindings/BUILD.gn | 3 + .../cpp/bindings/lib/bindings_serialization.cc | 34 --- .../cpp/bindings/lib/bindings_serialization.h | 16 -- .../public/cpp/bindings/lib/map_data_internal.h | 1 + .../public/cpp/bindings/lib/map_serialization.h | 25 +- .../cpp/bindings/lib/message_header_validator.cc | 2 +- .../public/cpp/bindings/lib/validation_util.cc | 74 ++++++ .../mojo/public/cpp/bindings/lib/validation_util.h | 48 ++++ .../public/cpp/bindings/tests/union_unittest.cc | 296 +++++++++++++++++++++ .../mojo/src/mojo/public/cpp/environment/BUILD.gn | 8 +- .../src/mojo/public/cpp/environment/environment.h | 6 +- .../cpp/environment/lib/default_task_tracker.cc | 38 +++ .../cpp/environment/lib/default_task_tracker.h | 18 ++ .../mojo/public/cpp/environment/lib/environment.cc | 21 +- .../cpp/environment/lib/scoped_task_tracking.cc | 37 +++ .../cpp/environment/lib/scoped_task_tracking.h | 34 +++ .../src/mojo/public/cpp/environment/task_tracker.h | 34 +++ .../cpp/environment/tests/logging_unittest.cc | 2 +- third_party/mojo/src/mojo/public/dart/README | 17 -- third_party/mojo/src/mojo/public/dart/README.md | 126 +++++++++ .../mojo/src/mojo/public/dart/application.dart | 6 +- .../mojo/src/mojo/public/go/bindings/decoder.go | 28 +- .../mojo/src/mojo/public/go/bindings/message.go | 45 +++- third_party/mojo/src/mojo/public/go/system/core.go | 6 +- .../mojo/src/mojo/public/go/system/mojo_types.go | 12 +- .../src/mojo/public/go/system/shared_buffer.go | 2 +- .../interfaces/bindings/tests/test_unions.mojom | 5 + .../src/org/chromium/mojo/bindings/Encoder.java | 7 +- .../src/org/chromium/mojo/bindings/Interface.java | 133 ++++++--- .../cpp_templates/interface_definition.tmpl | 88 +++--- .../generators/cpp_templates/module.cc.tmpl | 2 + .../cpp_templates/union_declaration.tmpl | 2 +- .../generators/cpp_templates/union_definition.tmpl | 30 ++- .../union_serialization_definition.tmpl | 31 ++- .../wrapper_union_class_declaration.tmpl | 2 +- .../wrapper_union_class_definition.tmpl | 14 +- .../generators/go_templates/interface.tmpl | 33 ++- .../bindings/generators/go_templates/struct.tmpl | 16 +- .../java_templates/interface_definition.tmpl | 8 +- .../bindings/generators/mojom_cpp_generator.py | 9 +- .../bindings/generators/mojom_dart_generator.py | 23 +- .../mojo/src/mojo/public/tools/bindings/mojom.gni | 100 ++++++- .../tools/bindings/mojom_bindings_generator.py | 2 +- .../bindings/pylib/mojom/generate/generator.py | 14 + .../pylib/mojom/generate/generator_unittest.py | 24 ++ .../mojo/src/mojo/public/tools/dart_analyze.py | 2 + 55 files changed, 1314 insertions(+), 261 deletions(-) create mode 100644 mojo/environment/default_task_tracker_impl.cc create mode 100644 mojo/environment/default_task_tracker_impl.h create mode 100644 third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_util.cc create mode 100644 third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_util.h create mode 100644 third_party/mojo/src/mojo/public/cpp/environment/lib/default_task_tracker.cc create mode 100644 third_party/mojo/src/mojo/public/cpp/environment/lib/default_task_tracker.h create mode 100644 third_party/mojo/src/mojo/public/cpp/environment/lib/scoped_task_tracking.cc create mode 100644 third_party/mojo/src/mojo/public/cpp/environment/lib/scoped_task_tracking.h create mode 100644 third_party/mojo/src/mojo/public/cpp/environment/task_tracker.h delete mode 100644 third_party/mojo/src/mojo/public/dart/README create mode 100644 third_party/mojo/src/mojo/public/dart/README.md create mode 100644 third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator_unittest.py diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ServiceRegistryTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ServiceRegistryTest.java index a0b8d42ee77f..4947f26b8aac 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ServiceRegistryTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ServiceRegistryTest.java @@ -136,7 +136,7 @@ public class ServiceRegistryTest extends ContentShellTestBase { // Perform a few operations on the Calculator. Calculator.Proxy calculator = requestPair.first; CalcConnectionErrorHandler errorHandler = new CalcConnectionErrorHandler(); - calculator.setErrorHandler(errorHandler); + calculator.getProxyHandler().setErrorHandler(errorHandler); CalcCallback callback = new CalcCallback(); calculator.add(21, callback); @@ -163,7 +163,7 @@ public class ServiceRegistryTest extends ContentShellTestBase { Calculator.MANAGER.getInterfaceRequest(mCore); Calculator.Proxy calculator = requestPair.first; CalcConnectionErrorHandler errorHandler = new CalcConnectionErrorHandler(); - calculator.setErrorHandler(errorHandler); + calculator.getProxyHandler().setErrorHandler(errorHandler); mCloseablesToClose.add(calculator); serviceRegistryB.connectToRemoteService(Calculator.MANAGER, requestPair.second); @@ -192,7 +192,7 @@ public class ServiceRegistryTest extends ContentShellTestBase { requestPair = Calculator.MANAGER.getInterfaceRequest(mCore); calculator = requestPair.first; errorHandler = new CalcConnectionErrorHandler(); - calculator.setErrorHandler(errorHandler); + calculator.getProxyHandler().setErrorHandler(errorHandler); mCloseablesToClose.add(calculator); serviceRegistryB.connectToRemoteService(Calculator.MANAGER, requestPair.second); diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfacesTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfacesTest.java index b7916f805361..58e2351073f6 100644 --- a/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfacesTest.java +++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfacesTest.java @@ -192,7 +192,7 @@ public class InterfacesTest extends MojoTestCase { private void checkProxy(NamedObject.Proxy proxy, MockNamedObjectImpl impl) { RecordingGetNameResponse callback = new RecordingGetNameResponse(); CapturingErrorHandler errorHandler = new CapturingErrorHandler(); - proxy.setErrorHandler(errorHandler); + proxy.getProxyHandler().setErrorHandler(errorHandler); if (impl != null) { assertNull(impl.getLastMojoException()); diff --git a/mojo/environment/BUILD.gn b/mojo/environment/BUILD.gn index 49e5c78f331e..4dbe7c4d5b8d 100644 --- a/mojo/environment/BUILD.gn +++ b/mojo/environment/BUILD.gn @@ -13,7 +13,10 @@ source_set("chromium") { "//third_party/mojo/src/mojo/public/cpp/environment/async_waiter.h", "//third_party/mojo/src/mojo/public/cpp/environment/lib/async_waiter.cc", "//third_party/mojo/src/mojo/public/cpp/environment/lib/logging.cc", + "//third_party/mojo/src/mojo/public/cpp/environment/lib/scoped_task_tracking.cc", + "//third_party/mojo/src/mojo/public/cpp/environment/lib/scoped_task_tracking.h", "//third_party/mojo/src/mojo/public/cpp/environment/logging.h", + "//third_party/mojo/src/mojo/public/cpp/environment/task_tracker.h", ] public_deps = [ @@ -40,6 +43,8 @@ component("chromium_impl") { "default_logger_impl.h", "default_run_loop_impl.cc", "default_run_loop_impl.h", + "default_task_tracker_impl.cc", + "default_task_tracker_impl.h", ] defines = [ "MOJO_ENVIRONMENT_IMPL_IMPLEMENTATION" ] diff --git a/mojo/environment/default_task_tracker_impl.cc b/mojo/environment/default_task_tracker_impl.cc new file mode 100644 index 000000000000..a53f1b9fe11d --- /dev/null +++ b/mojo/environment/default_task_tracker_impl.cc @@ -0,0 +1,35 @@ +// 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/environment/default_task_tracker_impl.h" + +namespace mojo { +namespace internal { +namespace { + +TaskTrackingId StartTracking(const char* function_name, + const char* file_name, + int line_number, + const void* program_counter) { + return TaskTrackingId(0); +} + +void EndTracking(const TaskTrackingId id) { +} + +void SetEnabled(bool enabled) { +} + +const TaskTracker kDefaultTaskTracker = {&StartTracking, + &EndTracking, + &SetEnabled}; + +} // namespace + +const TaskTracker* GetDefaultTaskTracker() { + return &kDefaultTaskTracker; +} + +} // namespace internal +} // namespace mojo diff --git a/mojo/environment/default_task_tracker_impl.h b/mojo/environment/default_task_tracker_impl.h new file mode 100644 index 000000000000..0a417cfb1b30 --- /dev/null +++ b/mojo/environment/default_task_tracker_impl.h @@ -0,0 +1,19 @@ +// 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_ENVIRONMENT_DEFAULT_TASK_TRACKER_IMPL_H_ +#define MOJO_ENVIRONMENT_DEFAULT_TASK_TRACKER_IMPL_H_ + +#include "mojo/environment/mojo_environment_impl_export.h" +#include "third_party/mojo/src/mojo/public/cpp/environment/task_tracker.h" + +namespace mojo { +namespace internal { + +MOJO_ENVIRONMENT_IMPL_EXPORT const TaskTracker* GetDefaultTaskTracker(); + +} // namespace internal +} // namespace mojo + +#endif // MOJO_ENVIRONMENT_DEFAULT_TASK_TRACKER_IMPL_H_ diff --git a/mojo/environment/environment.cc b/mojo/environment/environment.cc index ec1816618a83..7cc9b1cb05bc 100644 --- a/mojo/environment/environment.cc +++ b/mojo/environment/environment.cc @@ -7,6 +7,7 @@ #include "mojo/environment/default_async_waiter_impl.h" #include "mojo/environment/default_logger_impl.h" #include "mojo/environment/default_run_loop_impl.h" +#include "mojo/environment/default_task_tracker_impl.h" namespace mojo { @@ -35,6 +36,11 @@ const MojoLogger* Environment::GetDefaultLogger() { } // static +const TaskTracker* Environment::GetDefaultTaskTracker() { + return internal::GetDefaultTaskTracker(); +} + +// static void Environment::InstantiateDefaultRunLoop() { internal::InstantiateDefaultRunLoopImpl(); } @@ -44,4 +50,6 @@ void Environment::DestroyDefaultRunLoop() { internal::DestroyDefaultRunLoopImpl(); } + + } // namespace mojo diff --git a/mojo/mojo_base.gyp b/mojo/mojo_base.gyp index 9f73e5de8e01..c40a9499e8a0 100644 --- a/mojo/mojo_base.gyp +++ b/mojo/mojo_base.gyp @@ -120,8 +120,11 @@ # TODO(vtl): This is kind of ugly. (See TODO in logging.h.) "../third_party/mojo/src/mojo/public/cpp/environment/async_waiter.h", "../third_party/mojo/src/mojo/public/cpp/environment/lib/async_waiter.cc", - "../third_party/mojo/src/mojo/public/cpp/environment/logging.h", "../third_party/mojo/src/mojo/public/cpp/environment/lib/logging.cc", + "../third_party/mojo/src/mojo/public/cpp/environment/lib/scoped_task_tracking.cc", + "../third_party/mojo/src/mojo/public/cpp/environment/lib/scoped_task_tracking.cc", + "../third_party/mojo/src/mojo/public/cpp/environment/logging.h", + "../third_party/mojo/src/mojo/public/cpp/environment/task_tracker.h", ], 'include_dirs': [ '..', @@ -156,6 +159,8 @@ 'environment/default_logger_impl.h', 'environment/default_run_loop_impl.cc', 'environment/default_run_loop_impl.h', + 'environment/default_task_tracker_impl.cc', + 'environment/default_task_tracker_impl.h', ], 'include_dirs': [ '..', diff --git a/third_party/mojo/mojo_public.gyp b/third_party/mojo/mojo_public.gyp index 683791db037d..673e1c42cbb5 100644 --- a/third_party/mojo/mojo_public.gyp +++ b/third_party/mojo/mojo_public.gyp @@ -127,6 +127,8 @@ 'src/mojo/public/cpp/bindings/lib/validate_params.h', 'src/mojo/public/cpp/bindings/lib/validation_errors.cc', 'src/mojo/public/cpp/bindings/lib/validation_errors.h', + 'src/mojo/public/cpp/bindings/lib/validation_util.cc', + 'src/mojo/public/cpp/bindings/lib/validation_util.h', ], }, { @@ -155,9 +157,14 @@ 'src/mojo/public/cpp/environment/lib/default_async_waiter.h', 'src/mojo/public/cpp/environment/lib/default_logger.cc', 'src/mojo/public/cpp/environment/lib/default_logger.h', + 'src/mojo/public/cpp/environment/lib/default_task_tracker.cc', + 'src/mojo/public/cpp/environment/lib/default_task_tracker.h', 'src/mojo/public/cpp/environment/lib/environment.cc', 'src/mojo/public/cpp/environment/lib/logging.cc', + 'src/mojo/public/cpp/environment/lib/scoped_task_tracking.cc', + 'src/mojo/public/cpp/environment/lib/scoped_task_tracking.h', 'src/mojo/public/cpp/environment/logging.h', + 'src/mojo/public/cpp/environment/task_tracker.h', ], 'include_dirs': [ '../..', diff --git a/third_party/mojo/src/mojo/public/VERSION b/third_party/mojo/src/mojo/public/VERSION index 686ad23f79c7..d6b3e50cba75 100644 --- a/third_party/mojo/src/mojo/public/VERSION +++ b/third_party/mojo/src/mojo/public/VERSION @@ -1 +1 @@ -8563c3d4162bd74e96783e823e076e99869d7385 \ No newline at end of file +e7270700d671fa8e458b4d8c9e47f7bcfb65da0b \ No newline at end of file diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/BUILD.gn b/third_party/mojo/src/mojo/public/cpp/bindings/BUILD.gn index f6a9b1bbfbcc..7de82a5e4400 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/BUILD.gn +++ b/third_party/mojo/src/mojo/public/cpp/bindings/BUILD.gn @@ -27,6 +27,7 @@ mojo_sdk_source_set("bindings") { "lib/filter_chain.h", "lib/fixed_buffer.cc", "lib/fixed_buffer.h", + "lib/interface_ptr_internal.h", "lib/map_data_internal.h", "lib/map_internal.h", "lib/map_serialization.h", @@ -48,6 +49,8 @@ mojo_sdk_source_set("bindings") { "lib/validate_params.h", "lib/validation_errors.cc", "lib/validation_errors.h", + "lib/validation_util.cc", + "lib/validation_util.h", "map.h", "message.h", "message_filter.h", diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.cc b/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.cc index 257d129b2e44..9bfbd694f42a 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.cc @@ -4,8 +4,6 @@ #include "mojo/public/cpp/bindings/lib/bindings_serialization.h" -#include "mojo/public/cpp/bindings/lib/bounds_checker.h" -#include "mojo/public/cpp/bindings/lib/validation_errors.h" #include "mojo/public/cpp/environment/logging.h" namespace mojo { @@ -53,12 +51,6 @@ const void* DecodePointerRaw(const uint64_t* offset) { return reinterpret_cast(offset) + *offset; } -bool ValidateEncodedPointer(const uint64_t* offset) { - // Cast to uintptr_t so overflow behavior is well defined. - return reinterpret_cast(offset) + *offset >= - reinterpret_cast(offset); -} - void EncodeHandle(Handle* handle, std::vector* handles) { if (handle->is_valid()) { handles->push_back(*handle); @@ -86,31 +78,5 @@ void DecodeHandle(Interface_Data* data, std::vector* handles) { DecodeHandle(&data->handle, handles); } -bool ValidateStructHeaderAndClaimMemory(const void* data, - BoundsChecker* bounds_checker) { - if (!IsAligned(data)) { - ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT); - return false; - } - if (!bounds_checker->IsValidRange(data, sizeof(StructHeader))) { - ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); - return false; - } - - const StructHeader* header = static_cast(data); - - if (header->num_bytes < sizeof(StructHeader)) { - ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); - return false; - } - - if (!bounds_checker->ClaimMemory(data, header->num_bytes)) { - ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); - return false; - } - - return true; -} - } // namespace internal } // namespace mojo diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.h b/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.h index 34046a54b569..609a380e5466 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/bindings_serialization.h @@ -14,8 +14,6 @@ namespace mojo { namespace internal { -class BoundsChecker; - // Please note that this is a different value than |mojo::kInvalidHandleValue|, // which is the "decoded" invalid handle. const MojoHandle kEncodedInvalidHandleValue = static_cast(-1); @@ -43,10 +41,6 @@ inline void DecodePointer(const uint64_t* offset, T** ptr) { *ptr = reinterpret_cast(const_cast(DecodePointerRaw(offset))); } -// Checks whether decoding the pointer will overflow and produce a pointer -// smaller than |offset|. -bool ValidateEncodedPointer(const uint64_t* offset); - // Handles are encoded as indices into a vector of handles. These functions // manipulate the value of |handle|, mapping it to and from an index. @@ -74,16 +68,6 @@ inline void Decode(T* obj, std::vector* handles) { obj->ptr->DecodePointersAndHandles(handles); } -// Validates that |data| contains a valid struct header, in terms of alignment -// and size (i.e., the |num_bytes| field of the header is sufficient for storing -// the header itself). Besides, 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. -// Note: Does not verify |version| or that |num_bytes| is correct for the -// claimed version. -bool ValidateStructHeaderAndClaimMemory(const void* data, - BoundsChecker* bounds_checker); - template inline void InterfacePointerToData(InterfacePtr input, Interface_Data* output) { diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_data_internal.h b/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_data_internal.h index cf0d5ccb737b..97554b767e47 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_data_internal.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_data_internal.h @@ -8,6 +8,7 @@ #include "mojo/public/cpp/bindings/lib/array_internal.h" #include "mojo/public/cpp/bindings/lib/validate_params.h" #include "mojo/public/cpp/bindings/lib/validation_errors.h" +#include "mojo/public/cpp/bindings/lib/validation_util.h" namespace mojo { namespace internal { diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_serialization.h b/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_serialization.h index 21567792cf88..632da5dd099a 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_serialization.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_serialization.h @@ -27,11 +27,13 @@ namespace internal { template ::value> + bool value_is_move_only_type = IsMoveOnlyType::value, + bool is_union = + IsUnionDataType::type>::value> struct MapSerializer; template -struct MapSerializer { +struct MapSerializer { static size_t GetBaseArraySize(size_t count) { return Align(count * sizeof(DataType)); } @@ -39,7 +41,7 @@ struct MapSerializer { }; template <> -struct MapSerializer { +struct MapSerializer { static size_t GetBaseArraySize(size_t count) { return Align((count + 7) / 8); } @@ -47,7 +49,7 @@ struct MapSerializer { }; template -struct MapSerializer, H, true> { +struct MapSerializer, H, true, false> { static size_t GetBaseArraySize(size_t count) { return Align(count * sizeof(H)); } @@ -61,7 +63,8 @@ struct MapSerializer< S, typename EnableIf::DataType>::value, typename WrapperTraits::DataType>::type, - true> { + true, + false> { typedef typename RemovePointer::DataType>::type S_Data; static size_t GetBaseArraySize(size_t count) { @@ -70,8 +73,18 @@ struct MapSerializer< static size_t GetItemSize(const S& item) { return GetSerializedSize_(item); } }; +template +struct MapSerializer { + static size_t GetBaseArraySize(size_t count) { + return count * sizeof(U_Data); + } + static size_t GetItemSize(const U& item) { + return GetSerializedSize_(item, true); + } +}; + template <> -struct MapSerializer { +struct MapSerializer { static size_t GetBaseArraySize(size_t count) { return count * sizeof(StringPointer); } diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/message_header_validator.cc b/third_party/mojo/src/mojo/public/cpp/bindings/lib/message_header_validator.cc index 0870d61e990a..ff507f3f3183 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/message_header_validator.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/message_header_validator.cc @@ -4,9 +4,9 @@ #include "mojo/public/cpp/bindings/lib/message_header_validator.h" -#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" #include "mojo/public/cpp/bindings/lib/bounds_checker.h" #include "mojo/public/cpp/bindings/lib/validation_errors.h" +#include "mojo/public/cpp/bindings/lib/validation_util.h" namespace mojo { namespace internal { diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_util.cc b/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_util.cc new file mode 100644 index 000000000000..5614cca4a25c --- /dev/null +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_util.cc @@ -0,0 +1,74 @@ +// 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/validation_util.h" + +#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" +#include "mojo/public/cpp/bindings/lib/message_internal.h" +#include "mojo/public/cpp/bindings/lib/validation_errors.h" + +namespace mojo { +namespace internal { + +bool ValidateEncodedPointer(const uint64_t* offset) { + // Cast to uintptr_t so overflow behavior is well defined. + return reinterpret_cast(offset) + *offset >= + reinterpret_cast(offset); +} + +bool ValidateStructHeaderAndClaimMemory(const void* data, + BoundsChecker* bounds_checker) { + if (!IsAligned(data)) { + ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT); + return false; + } + if (!bounds_checker->IsValidRange(data, sizeof(StructHeader))) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); + return false; + } + + const StructHeader* header = static_cast(data); + + if (header->num_bytes < sizeof(StructHeader)) { + ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); + return false; + } + + if (!bounds_checker->ClaimMemory(data, header->num_bytes)) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); + return false; + } + + return true; +} + +bool ValidateMessageIsRequestWithoutResponse(const Message* message) { + if (message->has_flag(kMessageIsResponse) || + message->has_flag(kMessageExpectsResponse)) { + ReportValidationError(VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS); + return false; + } + return true; +} + +bool ValidateMessageIsRequestExpectingResponse(const Message* message) { + if (message->has_flag(kMessageIsResponse) || + !message->has_flag(kMessageExpectsResponse)) { + ReportValidationError(VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS); + return false; + } + return true; +} + +bool ValidateMessageIsResponse(const Message* message) { + if (message->has_flag(kMessageExpectsResponse) || + !message->has_flag(kMessageIsResponse)) { + ReportValidationError(VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS); + return false; + } + return true; +} + +} // namespace internal +} // namespace mojo diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_util.h b/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_util.h new file mode 100644 index 000000000000..1b80a5b19fa8 --- /dev/null +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_util.h @@ -0,0 +1,48 @@ +// 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_VALIDATION_UTIL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_UTIL_H_ + +#include + +#include "mojo/public/cpp/bindings/lib/bounds_checker.h" +#include "mojo/public/cpp/bindings/message.h" + +namespace mojo { +namespace internal { + +// Checks whether decoding the pointer will overflow and produce a pointer +// smaller than |offset|. +bool ValidateEncodedPointer(const uint64_t* offset); + +// Validates that |data| contains a valid struct header, in terms of alignment +// and size (i.e., the |num_bytes| field of the header is sufficient for storing +// the header itself). Besides, 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. +// Note: Does not verify |version| or that |num_bytes| is correct for the +// claimed version. +bool ValidateStructHeaderAndClaimMemory(const void* data, + 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. +bool ValidateMessageIsRequestExpectingResponse(const Message* message); +// Validates that the message is a response. +bool ValidateMessageIsResponse(const Message* message); + +// Validates that the message payload is a valid struct of type ParamsType. +template +bool ValidateMessagePayload(const Message* message) { + BoundsChecker bounds_checker(message->payload(), message->payload_num_bytes(), + message->handles()->size()); + return ParamsType::Validate(message->payload(), &bounds_checker); +} + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_UTIL_H_ diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/tests/union_unittest.cc b/third_party/mojo/src/mojo/public/cpp/bindings/tests/union_unittest.cc index 0803b9932111..5017d979d2dd 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/tests/union_unittest.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/tests/union_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include #include "mojo/public/cpp/bindings/array.h" #include "mojo/public/cpp/bindings/lib/array_internal.h" #include "mojo/public/cpp/bindings/lib/array_serialization.h" @@ -524,5 +525,300 @@ TEST(UnionTest, Validation_NullableUnion) { free(raw_buf); } +// TODO(azani): Move back in map_unittest.cc when possible. +// Map Tests +TEST(UnionTest, PodUnionInMap) { + SmallStructPtr small_struct(SmallStruct::New()); + small_struct->pod_union_map = Map(); + small_struct->pod_union_map.insert("one", PodUnion::New()); + small_struct->pod_union_map.insert("two", PodUnion::New()); + + small_struct->pod_union_map["one"]->set_f_int8(8); + small_struct->pod_union_map["two"]->set_f_int16(16); + + EXPECT_EQ(8, small_struct->pod_union_map["one"]->get_f_int8()); + EXPECT_EQ(16, small_struct->pod_union_map["two"]->get_f_int16()); +} + +TEST(UnionTest, PodUnionInMapSerialization) { + Environment environment; + Map map; + map.insert("one", PodUnion::New()); + map.insert("two", PodUnion::New()); + + map["one"]->set_f_int8(8); + map["two"]->set_f_int16(16); + + size_t size = GetSerializedSize_(map); + EXPECT_EQ(120U, size); + + mojo::internal::FixedBuffer buf(size); + mojo::internal::Map_Data* data; + mojo::internal::ArrayValidateParams validate_params(0, false, nullptr); + SerializeMap_(map.Pass(), &buf, &data, &validate_params); + + Map map2; + Deserialize_(data, &map2); + + EXPECT_EQ(8, map2["one"]->get_f_int8()); + EXPECT_EQ(16, map2["two"]->get_f_int16()); +} + +TEST(UnionTest, PodUnionInMapSerializationWithNull) { + Environment environment; + Map map; + map.insert("one", PodUnion::New()); + map.insert("two", nullptr); + + map["one"]->set_f_int8(8); + + size_t size = GetSerializedSize_(map); + EXPECT_EQ(120U, size); + + mojo::internal::FixedBuffer buf(size); + mojo::internal::Map_Data* data; + mojo::internal::ArrayValidateParams validate_params(0, true, nullptr); + SerializeMap_(map.Pass(), &buf, &data, &validate_params); + + Map map2; + Deserialize_(data, &map2); + + EXPECT_EQ(8, map2["one"]->get_f_int8()); + EXPECT_TRUE(map2["two"].is_null()); +} + +TEST(UnionTest, StructInUnionGetterSetterPasser) { + DummyStructPtr dummy(DummyStruct::New()); + dummy->f_int8 = 8; + + ObjectUnionPtr obj(ObjectUnion::New()); + obj->set_f_dummy(dummy.Pass()); + + EXPECT_EQ(8, obj->get_f_dummy()->f_int8); +} + +TEST(UnionTest, StructInUnionSerialization) { + Environment environment; + DummyStructPtr dummy(DummyStruct::New()); + dummy->f_int8 = 8; + + ObjectUnionPtr obj(ObjectUnion::New()); + obj->set_f_dummy(dummy.Pass()); + + size_t size = GetSerializedSize_(obj, false); + EXPECT_EQ(32U, size); + + mojo::internal::FixedBuffer buf(size); + internal::ObjectUnion_Data* data = nullptr; + SerializeUnion_(obj.Pass(), &buf, &data, false); + + ObjectUnionPtr obj2; + Deserialize_(data, &obj2); + EXPECT_EQ(8, obj2->get_f_dummy()->f_int8); +} + +TEST(UnionTest, StructInUnionValidation) { + Environment environment; + DummyStructPtr dummy(DummyStruct::New()); + dummy->f_int8 = 8; + + ObjectUnionPtr obj(ObjectUnion::New()); + obj->set_f_dummy(dummy.Pass()); + + size_t size = GetSerializedSize_(obj, false); + + mojo::internal::FixedBuffer buf(size); + internal::ObjectUnion_Data* data = nullptr; + SerializeUnion_(obj.Pass(), &buf, &data, false); + + void* raw_buf = buf.Leak(); + mojo::internal::BoundsChecker bounds_checker(data, + static_cast(size), 0); + EXPECT_TRUE( + internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker, false)); + free(raw_buf); +} + +TEST(UnionTest, StructInUnionValidationNonNullable) { + Environment environment; + DummyStructPtr dummy(nullptr); + + ObjectUnionPtr obj(ObjectUnion::New()); + obj->set_f_dummy(dummy.Pass()); + + size_t size = GetSerializedSize_(obj, false); + + mojo::internal::FixedBuffer buf(size); + internal::ObjectUnion_Data* data = nullptr; + SerializeUnion_(obj.Pass(), &buf, &data, false); + + void* raw_buf = buf.Leak(); + mojo::internal::BoundsChecker bounds_checker(data, + static_cast(size), 0); + EXPECT_FALSE( + internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker, false)); + free(raw_buf); +} + +TEST(UnionTest, StructInUnionValidationNullable) { + Environment environment; + DummyStructPtr dummy(nullptr); + + ObjectUnionPtr obj(ObjectUnion::New()); + obj->set_f_nullable(dummy.Pass()); + + size_t size = GetSerializedSize_(obj, false); + + mojo::internal::FixedBuffer buf(size); + internal::ObjectUnion_Data* data = nullptr; + SerializeUnion_(obj.Pass(), &buf, &data, false); + + void* raw_buf = buf.Leak(); + mojo::internal::BoundsChecker bounds_checker(data, + static_cast(size), 0); + EXPECT_TRUE( + internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker, false)); + free(raw_buf); +} + +TEST(UnionTest, ArrayInUnionGetterSetter) { + Environment environment; + + Array array(2); + array[0] = 8; + array[1] = 9; + + ObjectUnionPtr obj(ObjectUnion::New()); + obj->set_f_array_int8(array.Pass()); + + EXPECT_EQ(8, obj->get_f_array_int8()[0]); + EXPECT_EQ(9, obj->get_f_array_int8()[1]); +} + +TEST(UnionTest, ArrayInUnionSerialization) { + Environment environment; + + Array array(2); + array[0] = 8; + array[1] = 9; + + ObjectUnionPtr obj(ObjectUnion::New()); + obj->set_f_array_int8(array.Pass()); + + size_t size = GetSerializedSize_(obj, false); + EXPECT_EQ(32U, size); + + mojo::internal::FixedBuffer buf(size); + internal::ObjectUnion_Data* data = nullptr; + SerializeUnion_(obj.Pass(), &buf, &data, false); + + std::vector handles; + data->EncodePointersAndHandles(&handles); + data->DecodePointersAndHandles(&handles); + + ObjectUnionPtr obj2; + Deserialize_(data, &obj2); + + EXPECT_EQ(8, obj2->get_f_array_int8()[0]); + EXPECT_EQ(9, obj2->get_f_array_int8()[1]); +} + +TEST(UnionTest, ArrayInUnionValidation) { + Environment environment; + + Array array(2); + array[0] = 8; + array[1] = 9; + + ObjectUnionPtr obj(ObjectUnion::New()); + obj->set_f_array_int8(array.Pass()); + + size_t size = GetSerializedSize_(obj, false); + mojo::internal::FixedBuffer buf(size); + internal::ObjectUnion_Data* data = nullptr; + SerializeUnion_(obj.Pass(), &buf, &data, false); + + std::vector handles; + data->EncodePointersAndHandles(&handles); + + void* raw_buf = buf.Leak(); + mojo::internal::BoundsChecker bounds_checker(data, + static_cast(size), 0); + + EXPECT_TRUE( + internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker, false)); + free(raw_buf); +} + +TEST(UnionTest, MapInUnionGetterSetter) { + Environment environment; + Map map; + map.insert("one", 1); + map.insert("two", 2); + + ObjectUnionPtr obj(ObjectUnion::New()); + obj->set_f_map_int8(map.Pass()); + + EXPECT_EQ(1, obj->get_f_map_int8()["one"]); + EXPECT_EQ(2, obj->get_f_map_int8()["two"]); +} + +TEST(UnionTest, MapInUnionSerialization) { + Environment environment; + Map map; + map.insert("one", 1); + map.insert("two", 2); + + ObjectUnionPtr obj(ObjectUnion::New()); + obj->set_f_map_int8(map.Pass()); + + size_t size = GetSerializedSize_(obj, false); + EXPECT_EQ(112U, size); + + mojo::internal::FixedBuffer buf(size); + internal::ObjectUnion_Data* data = nullptr; + SerializeUnion_(obj.Pass(), &buf, &data, false); + + std::vector handles; + data->EncodePointersAndHandles(&handles); + data->DecodePointersAndHandles(&handles); + + ObjectUnionPtr obj2; + Deserialize_(data, &obj2); + + EXPECT_EQ(1, obj2->get_f_map_int8()["one"]); + EXPECT_EQ(2, obj2->get_f_map_int8()["two"]); +} + +TEST(UnionTest, MapInUnionValidation) { + Environment environment; + Map map; + map.insert("one", 1); + map.insert("two", 2); + + ObjectUnionPtr obj(ObjectUnion::New()); + obj->set_f_map_int8(map.Pass()); + + size_t size = GetSerializedSize_(obj, false); + EXPECT_EQ(112U, size); + + mojo::internal::FixedBuffer buf(size); + internal::ObjectUnion_Data* data = nullptr; + SerializeUnion_(obj.Pass(), &buf, &data, false); + + std::vector handles; + data->EncodePointersAndHandles(&handles); + + void* raw_buf = buf.Leak(); + mojo::internal::BoundsChecker bounds_checker(data, + static_cast(size), 0); + + EXPECT_TRUE( + internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker, false)); + free(raw_buf); +} + } // namespace test } // namespace mojo diff --git a/third_party/mojo/src/mojo/public/cpp/environment/BUILD.gn b/third_party/mojo/src/mojo/public/cpp/environment/BUILD.gn index 87f24fff0c3d..fe3a0113af7d 100644 --- a/third_party/mojo/src/mojo/public/cpp/environment/BUILD.gn +++ b/third_party/mojo/src/mojo/public/cpp/environment/BUILD.gn @@ -7,8 +7,9 @@ import("../../mojo_sdk.gni") mojo_sdk_source_set("environment") { sources = [ "async_waiter.h", - "logging.h", "environment.h", + "logging.h", + "task_tracker.h", ] mojo_sdk_public_deps = [ "mojo/public/c/environment" ] @@ -26,8 +27,12 @@ mojo_sdk_source_set("standalone") { "lib/default_async_waiter.h", "lib/default_logger.cc", "lib/default_logger.h", + "lib/default_task_tracker.cc", + "lib/default_task_tracker.h", "lib/environment.cc", "lib/logging.cc", + "lib/scoped_task_tracking.cc", + "lib/scoped_task_tracking.h", ] public_deps = [ @@ -36,6 +41,7 @@ mojo_sdk_source_set("standalone") { mojo_sdk_deps = [ "mojo/public/c/environment", + "mojo/public/cpp/system", "mojo/public/cpp/utility", ] } diff --git a/third_party/mojo/src/mojo/public/cpp/environment/environment.h b/third_party/mojo/src/mojo/public/cpp/environment/environment.h index ce3f7d01ad96..3a544286de35 100644 --- a/third_party/mojo/src/mojo/public/cpp/environment/environment.h +++ b/third_party/mojo/src/mojo/public/cpp/environment/environment.h @@ -12,6 +12,8 @@ struct MojoLogger; namespace mojo { +struct TaskTracker; + // Other parts of the Mojo C++ APIs use the *static* methods of this class. // // The "standalone" implementation of this class requires that this class (in @@ -26,11 +28,13 @@ class Environment { // This constructor allows the standard implementations to be overridden (set // a parameter to null to get the standard implementation). Environment(const MojoAsyncWaiter* default_async_waiter, - const MojoLogger* default_logger); + const MojoLogger* default_logger, + const TaskTracker* default_task_tracker); ~Environment(); static const MojoAsyncWaiter* GetDefaultAsyncWaiter(); static const MojoLogger* GetDefaultLogger(); + static const TaskTracker* GetDefaultTaskTracker(); // These instantiate and destroy an environment-specific run loop for the // current thread, allowing |GetDefaultAsyncWaiter()| to be used. (The run diff --git a/third_party/mojo/src/mojo/public/cpp/environment/lib/default_task_tracker.cc b/third_party/mojo/src/mojo/public/cpp/environment/lib/default_task_tracker.cc new file mode 100644 index 000000000000..17c814db679d --- /dev/null +++ b/third_party/mojo/src/mojo/public/cpp/environment/lib/default_task_tracker.cc @@ -0,0 +1,38 @@ +// 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/environment/lib/default_task_tracker.h" + +namespace mojo { + +namespace { + +// +// The standalone task tracker does nothing. +// + +TaskTrackingId StartTracking(const char* function_name, + const char* file_name, + int line_number, + const void* program_counter) { + return TaskTrackingId(0); +} + +void EndTracking(const TaskTrackingId id) { +} + +void SetEnabled(bool enabled) { +} + +} // namespace + +namespace internal { + +const TaskTracker kDefaultTaskTracker = {&StartTracking, + &EndTracking, + &SetEnabled}; + +} // namespace internal + +} // namespace mojo diff --git a/third_party/mojo/src/mojo/public/cpp/environment/lib/default_task_tracker.h b/third_party/mojo/src/mojo/public/cpp/environment/lib/default_task_tracker.h new file mode 100644 index 000000000000..83b9ae3c9bf4 --- /dev/null +++ b/third_party/mojo/src/mojo/public/cpp/environment/lib/default_task_tracker.h @@ -0,0 +1,18 @@ +// 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_ENVIRONMENT_LIB_DEFAULT_TASK_TRACKER_H_ +#define MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_TASK_TRACKER_H_ + +#include "mojo/public/cpp/environment/task_tracker.h" + +namespace mojo { +namespace internal { + +extern const TaskTracker kDefaultTaskTracker; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_TASK_TRACKER_H_ diff --git a/third_party/mojo/src/mojo/public/cpp/environment/lib/environment.cc b/third_party/mojo/src/mojo/public/cpp/environment/lib/environment.cc index 6fb7e22a2204..8c7c930671d8 100644 --- a/third_party/mojo/src/mojo/public/cpp/environment/lib/environment.cc +++ b/third_party/mojo/src/mojo/public/cpp/environment/lib/environment.cc @@ -9,6 +9,7 @@ #include "mojo/public/c/environment/logger.h" #include "mojo/public/cpp/environment/lib/default_async_waiter.h" #include "mojo/public/cpp/environment/lib/default_logger.h" +#include "mojo/public/cpp/environment/lib/default_task_tracker.h" #include "mojo/public/cpp/utility/run_loop.h" namespace mojo { @@ -17,27 +18,34 @@ namespace { const MojoAsyncWaiter* g_default_async_waiter = nullptr; const MojoLogger* g_default_logger = nullptr; +const TaskTracker* g_default_task_tracker = nullptr; void Init(const MojoAsyncWaiter* default_async_waiter, - const MojoLogger* default_logger) { + const MojoLogger* default_logger, + const TaskTracker* default_task_tracker) { g_default_async_waiter = default_async_waiter ? default_async_waiter : &internal::kDefaultAsyncWaiter; g_default_logger = default_logger ? default_logger : &internal::kDefaultLogger; + g_default_task_tracker = default_task_tracker + ? default_task_tracker + : &internal::kDefaultTaskTracker; + RunLoop::SetUp(); } } // namespace Environment::Environment() { - Init(nullptr, nullptr); + Init(nullptr, nullptr, nullptr); } Environment::Environment(const MojoAsyncWaiter* default_async_waiter, - const MojoLogger* default_logger) { - Init(default_async_waiter, default_logger); + const MojoLogger* default_logger, + const TaskTracker* default_task_tracker) { + Init(default_async_waiter, default_logger, default_task_tracker); } Environment::~Environment() { @@ -62,6 +70,11 @@ const MojoLogger* Environment::GetDefaultLogger() { } // static +const TaskTracker* Environment::GetDefaultTaskTracker() { + return g_default_task_tracker; +} + +// static void Environment::InstantiateDefaultRunLoop() { assert(!RunLoop::current()); // Not leaked: accessible from |RunLoop::current()|. diff --git a/third_party/mojo/src/mojo/public/cpp/environment/lib/scoped_task_tracking.cc b/third_party/mojo/src/mojo/public/cpp/environment/lib/scoped_task_tracking.cc new file mode 100644 index 000000000000..9e253d5bd80e --- /dev/null +++ b/third_party/mojo/src/mojo/public/cpp/environment/lib/scoped_task_tracking.cc @@ -0,0 +1,37 @@ +// 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/environment/lib/scoped_task_tracking.h" + +#include "mojo/public/cpp/environment/environment.h" + +namespace mojo { +namespace internal { + +ScopedTaskTracking::ScopedTaskTracking(const char* function_name, + const char* file_name, + int line, + const void* program_counter) + : id_(Environment::GetDefaultTaskTracker()->StartTracking( + function_name, + file_name, + line, + program_counter)) { +} + +ScopedTaskTracking::ScopedTaskTracking(const char* function_name, + const char* file_name, + int line) + : id_(Environment::GetDefaultTaskTracker()->StartTracking(function_name, + file_name, + line, + nullptr)) { +} + +ScopedTaskTracking::~ScopedTaskTracking() { + Environment::GetDefaultTaskTracker()->EndTracking(id_); +} + +} // namespace internal +} // namespace mojo diff --git a/third_party/mojo/src/mojo/public/cpp/environment/lib/scoped_task_tracking.h b/third_party/mojo/src/mojo/public/cpp/environment/lib/scoped_task_tracking.h new file mode 100644 index 000000000000..1b0411e805fe --- /dev/null +++ b/third_party/mojo/src/mojo/public/cpp/environment/lib/scoped_task_tracking.h @@ -0,0 +1,34 @@ +// 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_ENVIRONMENT_LIB_SCOPED_TASK_TRACKING_H_ +#define MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_SCOPED_TASK_TRACKING_H_ + +#include "mojo/public/cpp/environment/task_tracker.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +// An RAII wrapper for |TaskTrackingId|. +class ScopedTaskTracking { + public: + ScopedTaskTracking(const char* function_name, + const char* file_name, + int line, + const void* program_counter); + ScopedTaskTracking(const char* function_name, + const char* file_name, + int line); + ~ScopedTaskTracking(); + + private: + TaskTrackingId id_; + MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedTaskTracking); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_ENVIRONMENT_SCOPED_TASK_TRACKING_H_ diff --git a/third_party/mojo/src/mojo/public/cpp/environment/task_tracker.h b/third_party/mojo/src/mojo/public/cpp/environment/task_tracker.h new file mode 100644 index 000000000000..771dc7f63918 --- /dev/null +++ b/third_party/mojo/src/mojo/public/cpp/environment/task_tracker.h @@ -0,0 +1,34 @@ +// 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_ENVIRONMENT_TASK_TRACKER_H_ +#define MOJO_PUBLIC_CPP_ENVIRONMENT_TASK_TRACKER_H_ + +#include + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +typedef intptr_t TaskTrackingId; + +// Interface for wiring task-level profiling, which is implemented through +// tracked_objects system in chrome. +// This API is mainly used from generated interface implementation. +struct TaskTracker { + public: + // Start tracking. The returned id must be reclaimed through |EndTracking()|. + TaskTrackingId (*StartTracking)(const char* function_name, + const char* file_name, + int line_number, + const void* program_counter); + // Finish tracking. The |id| is one that is returned from |StartTracking()|. + void (*EndTracking)(const TaskTrackingId id); + // Enable or disable tracking. It is disabled by default. + void (*SetEnabled)(bool enabled); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_ENVIRONMENT_TASK_TRACKER_H_ diff --git a/third_party/mojo/src/mojo/public/cpp/environment/tests/logging_unittest.cc b/third_party/mojo/src/mojo/public/cpp/environment/tests/logging_unittest.cc index 7ecc8b2080a6..25ebb3403507 100644 --- a/third_party/mojo/src/mojo/public/cpp/environment/tests/logging_unittest.cc +++ b/third_party/mojo/src/mojo/public/cpp/environment/tests/logging_unittest.cc @@ -31,7 +31,7 @@ bool DcheckTestHelper(bool* was_called) { class LoggingTest : public testing::Test { public: - LoggingTest() : environment_(nullptr, &kMockLogger) { + LoggingTest() : environment_(nullptr, &kMockLogger, nullptr) { minimum_log_level_ = MOJO_LOG_LEVEL_INFO; ResetMockLogger(); } diff --git a/third_party/mojo/src/mojo/public/dart/README b/third_party/mojo/src/mojo/public/dart/README deleted file mode 100644 index fd75b8fe36f6..000000000000 --- a/third_party/mojo/src/mojo/public/dart/README +++ /dev/null @@ -1,17 +0,0 @@ -These are interim instructions for building and testing Dart's Mojo bindings. -These instructions currently only work for Linux, and assume you already have a -Mojo checkout. - -1.) Configure Mojo with Dart. - - $ ./mojo/tools/mojob.py gn --release --with-dart - - -2.) Build Mojo with Dart. - - $ ./mojo/tools/mojob.py build --release - - -3.) Run Dart tests. - - $ ./mojo/tools/mojob.py darttest --release diff --git a/third_party/mojo/src/mojo/public/dart/README.md b/third_party/mojo/src/mojo/public/dart/README.md new file mode 100644 index 000000000000..6de696b0426b --- /dev/null +++ b/third_party/mojo/src/mojo/public/dart/README.md @@ -0,0 +1,126 @@ +Dart Mojo Applications +==== + +## Mojo Application API + +*TODO(zra)* + +## Application Packaging + +All Dart sources for a Mojo application are collected in a specially formatted +zip file, which is understood by Dart's content handler in the Mojo shell. +This section describes what the various parts of that package are, and how they +all make it to the right place. + +### GN Template + +Dart Mojo applications are built with the GN template +'dart_packaged_application' defined in `//mojo/public/dart/rules.gni`. +Here is an example: + + +``` +dart_packaged_application("foo") { + output_name = "dart_foo" + uses_pub = true + sources = [ + "main.dart", + "foo.dart", + ] + deps = [ + "//mojo/public/dart", + "//mojo/services/network/public/interfaces", + ] +} +``` + +There are several parts: +* `output_name` is the name of the resulting .mojo file if it should be + different from the name of the target. (In this case we get dart_foo.mojo + instead of foo.mojo.) +* `uses_pub` should be true when the application depends on Dart packages pulled + down from pub. The application should have `pubspec.yaml` and `pubspec.lock` + files adjacent to `main.dart`. More on this below. +* `sources` is the list of Dart sources for the application. Each application + **must** contain a `main.dart` file. `main.dart` must be the library entry + point, and must contain the `main()` function. +* `deps` has the usual meaning. In the example above, + `//mojo/services/network/public/interfaces` indicates that the "foo" + application uses the Dart bindings generated for the network service. + +### pub packages + +Dart Mojo applications may use packages from the pub package repository at +pub.dartlang.org. + +The "foo" example above has `uses_pub` set to true. Suppose its `pubspec.yaml` +is as follows: + +``` +name: foo +version: 0.0.1 +description: Foo +dependencies: + crypto: ">=0.9.0 <0.10.0" +``` + +The script `//mojo/public/tools/git/dart_pub_get.py` should be run before build +time, e.g. as a "runhooks" action during `gclient sync`. The script traverses +a directory tree looking for `pubspec.yaml` files. On finding one, in the +containing directory, it runs `pub get`. This creates a "packages/" directory +in the source tree adjacent to the `pubspec.yaml` file containing the downloaded +Dart packages. `pub get` also creates a `pubspec.lock` file that locks down +pub packages to specific versions. This `pubspec.lock` file must be checked in +in order to have hermetic builds. + +During the build, The `dart_packaged_application` rule looks for a "packages/" +directory, and copies its contents into the zip file. + +### Generated bindings + +The script `//mojo/public/tools/bindings/generators/mojom_dart_generator.py` +and the templates under `//mojo/public/tools/bindings/generators/dart_templates` +govern how `.mojom` files are compiled into Dart code. + +Consider the `network_error.mojom` file from the network services used by our +"foo" example: + +``` +module mojo; + +struct NetworkError { + int32 code; + string? description; +}; +``` + +This contents of this file are in the `mojo` module. The Dart source generated +for this file will end up under, e.g. +`//out/Debug/gen/dart-gen/mojom/mojo/network_error.mojom.dart`, along with the +other Dart sources generated for `.mojom` files in the `mojo` module. + +### Resulting layout + +They layout for our "foo" example will be the following: + +``` +//main.dart +//foo.dart +//crypto/... # Dart's crypto pub package. +//mojo/public/dart/... # Mojo SDK Dart libraries. +//mojom/mojo/... # Generated bindings in the mojo module. +``` + +Where `//mojo/public/dart` contains Dart's Mojo bindings, `//crypto` contains +the `crypto` pub package, and `//mojom/mojo` contains the generated bindings in +the mojom module for the network service. + +Mojo's Dart content handler sets the package root for a Dart application to be +the root directory of the unpacked zip file. Therefore, Dart sources in this +application can use the following imports: + +```dart +import 'package:crypto/crypto.dart'; +import 'package:mojo/public/dart/application.dart'; +import 'package:mojom/mojo/network_error.mojom.dart'; +``` diff --git a/third_party/mojo/src/mojo/public/dart/application.dart b/third_party/mojo/src/mojo/public/dart/application.dart index ba7f49784625..37f923e0b5eb 100644 --- a/third_party/mojo/src/mojo/public/dart/application.dart +++ b/third_party/mojo/src/mojo/public/dart/application.dart @@ -10,9 +10,9 @@ import 'dart:typed_data'; import 'package:mojo/public/dart/bindings.dart' as bindings; import 'package:mojo/public/dart/core.dart' as core; -import 'package:mojo/application.mojom.dart' as application_mojom; -import 'package:mojo/service_provider.mojom.dart'; -import 'package:mojo/shell.mojom.dart' as shell_mojom; +import 'package:mojom/mojo/application.mojom.dart' as application_mojom; +import 'package:mojom/mojo/service_provider.mojom.dart'; +import 'package:mojom/mojo/shell.mojom.dart' as shell_mojom; part 'src/application.dart'; part 'src/application_connection.dart'; diff --git a/third_party/mojo/src/mojo/public/go/bindings/decoder.go b/third_party/mojo/src/mojo/public/go/bindings/decoder.go index 67ebe9e64ee6..2b12ff367fcc 100644 --- a/third_party/mojo/src/mojo/public/go/bindings/decoder.go +++ b/third_party/mojo/src/mojo/public/go/bindings/decoder.go @@ -40,7 +40,7 @@ func NewDecoder(bytes []byte, handles []system.UntypedHandle) *Decoder { // claimData claims a block of |size| bytes for a one-level value. func (d *Decoder) claimData(size int) error { if d.end+size > len(d.buf) { - return fmt.Errorf("data buffer is too small") + return &ValidationError{IllegalMemoryRange, "data buffer is too small"} } d.end += size return nil @@ -48,10 +48,10 @@ func (d *Decoder) claimData(size int) error { func (d *Decoder) claimHandle(index int) (system.UntypedHandle, error) { if index >= len(d.handles) { - return nil, fmt.Errorf("trying to access non present handle") + return nil, &ValidationError{IllegalHandle, "trying to access non present handle"} } if index < d.nextHandle { - return nil, fmt.Errorf("trying to access handle out of order") + return nil, &ValidationError{IllegalHandle, "trying to access handle out of order"} } d.nextHandle = index + 1 return d.handles[index], nil @@ -100,7 +100,9 @@ func (d *Decoder) StartArray(elementBitSize uint32) (uint32, error) { } minSize := bytesForBits(uint64(header.ElementsOrVersion) * uint64(elementBitSize)) if got, want := int(header.Size), dataHeaderSize+minSize; got < want { - return 0, fmt.Errorf("data header size is too small: is %d, but should be at least %d", got, want) + return 0, &ValidationError{UnexpectedArrayHeader, + fmt.Sprintf("data header size(%d) should be at least %d", got, want), + } } if err := d.pushState(header, elementBitSize); err != nil { return 0, err @@ -117,7 +119,9 @@ func (d *Decoder) StartMap() error { return err } if header != mapHeader { - return fmt.Errorf("invalid map header: %v", header) + return &ValidationError{UnexpectedStructHeader, + fmt.Sprintf("invalid map header: %v", header), + } } if err := d.pushState(header, pointerBitSize); err != nil { return err @@ -135,7 +139,9 @@ func (d *Decoder) StartStruct() (DataHeader, error) { return DataHeader{}, err } if header.Size < dataHeaderSize { - return DataHeader{}, fmt.Errorf("data header size(%d) should be at least %d", header.Size, dataHeaderSize) + return DataHeader{}, &ValidationError{UnexpectedStructHeader, + fmt.Sprintf("data header size(%d) should be at least %d", header.Size, dataHeaderSize), + } } if err := d.pushState(header, 0); err != nil { return DataHeader{}, err @@ -299,14 +305,16 @@ func (d *Decoder) ReadPointer() (uint64, error) { } newEnd := uint64(d.state().offset-8) + pointer - if newEnd >= uint64(len(d.buf)) { - return 0, fmt.Errorf("trying to access out of range memory") + if pointer >= uint64(len(d.buf)) || newEnd >= uint64(len(d.buf)) { + return 0, &ValidationError{IllegalPointer, "trying to access out of range memory"} } if newEnd < uint64(d.end) { - return 0, fmt.Errorf("trying to access memory out of order") + return 0, &ValidationError{IllegalMemoryRange, "trying to access memory out of order"} } if newEnd%8 != 0 { - return 0, fmt.Errorf("incorrect pointer data alignment: %d", newEnd) + return 0, &ValidationError{MisalignedObject, + fmt.Sprintf("incorrect pointer data alignment: %d", newEnd), + } } d.claimData(int(newEnd) - d.end) return pointer, nil diff --git a/third_party/mojo/src/mojo/public/go/bindings/message.go b/third_party/mojo/src/mojo/public/go/bindings/message.go index 8455cd4b1e13..f2dce2a59e37 100644 --- a/third_party/mojo/src/mojo/public/go/bindings/message.go +++ b/third_party/mojo/src/mojo/public/go/bindings/message.go @@ -31,6 +31,31 @@ func init() { mapHeader = DataHeader{24, 2} } +const ( + DifferentSizedArraysInMap = "VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP" + IllegalHandle = "VALIDATION_ERROR_ILLEGAL_HANDLE" + IllegalMemoryRange = "VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE" + IllegalPointer = "VALIDATION_ERROR_ILLEGAL_POINTER" + MessageHeaderInvalidFlags = "VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS" + MessageHeaderMissingRequestId = "VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID" + MessageHeaderUnknownMethod = "VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD" + MisalignedObject = "VALIDATION_ERROR_MISALIGNED_OBJECT" + UnexpectedArrayHeader = "VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER" + UnexpectedInvalidHandle = "VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE" + UnexpectedNullPointer = "VALIDATION_ERROR_UNEXPECTED_NULL_POINTER" + UnexpectedStructHeader = "VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER" +) + +// ValidationError is an error that can happen during message validation. +type ValidationError struct { + ErrorCode string + Message string +} + +func (e *ValidationError) Error() string { + return e.Message +} + // Payload is an interface implemented by a mojo struct that can encode/decode // itself into mojo archive format. type Payload interface { @@ -74,8 +99,20 @@ func (h *MessageHeader) Decode(decoder *Decoder) error { } numFields := header.ElementsOrVersion if numFields < 2 || numFields > 3 { - return fmt.Errorf("Invalid message header: it should have 2 or 3 fileds, but has %d", numFields) + return &ValidationError{UnexpectedStructHeader, + fmt.Sprintf("invalid message header: it should have 2 or 3 fileds, but has %d", numFields), + } + } + expectedSize := uint32(dataHeaderSize + 2*4) + if numFields == 3 { + expectedSize += 8 } + if expectedSize != header.Size { + return &ValidationError{UnexpectedStructHeader, + fmt.Sprintf("unexpected struct header size: expected %d, but got %d", expectedSize, header.Size), + } + } + if h.Type, err = decoder.ReadUint32(); err != nil { return err } @@ -84,14 +121,16 @@ func (h *MessageHeader) Decode(decoder *Decoder) error { } if numFields == 3 { if h.Flags != MessageExpectsResponseFlag && h.Flags != MessageIsResponseFlag { - return fmt.Errorf("Message header flags(%v) should be MessageExpectsResponseFlag or MessageIsResponseFlag", h.Flags) + return &ValidationError{MessageHeaderInvalidFlags, + fmt.Sprintf("message header flags(%v) should be MessageExpectsResponseFlag or MessageIsResponseFlag", h.Flags), + } } if h.RequestId, err = decoder.ReadUint64(); err != nil { return err } } else { if h.Flags != MessageNoFlag { - return fmt.Errorf("Message header flags(%v) should be MessageNoFlag", h.Flags) + return &ValidationError{MessageHeaderMissingRequestId, "missing request ID in message header"} } } return decoder.Finish() diff --git a/third_party/mojo/src/mojo/public/go/system/core.go b/third_party/mojo/src/mojo/public/go/system/core.go index 4fc3df5d4d3f..9e29cff783a9 100644 --- a/third_party/mojo/src/mojo/public/go/system/core.go +++ b/third_party/mojo/src/mojo/public/go/system/core.go @@ -117,7 +117,7 @@ func (impl *coreImpl) CreateDataPipe(opts *DataPipeOptions) (MojoResult, Produce if opts == nil { r, p, c = sysImpl.CreateDataPipeWithDefaultOptions() } else { - r, p, c = sysImpl.CreateDataPipe(uint32(opts.flags), uint32(opts.elemSize), uint32(opts.capacity)) + r, p, c = sysImpl.CreateDataPipe(uint32(opts.Flags), uint32(opts.ElemSize), uint32(opts.Capacity)) } impl.mu.Unlock() return MojoResult(r), impl.AcquireNativeHandle(MojoHandle(p)).ToProducerHandle(), impl.AcquireNativeHandle(MojoHandle(c)).ToConsumerHandle() @@ -127,7 +127,7 @@ func (impl *coreImpl) CreateMessagePipe(opts *MessagePipeOptions) (MojoResult, M var flags uint32 if opts != nil { - flags = uint32(opts.flags) + flags = uint32(opts.Flags) } impl.mu.Lock() r, handle0, handle1 := sysImpl.CreateMessagePipe(flags) @@ -138,7 +138,7 @@ func (impl *coreImpl) CreateMessagePipe(opts *MessagePipeOptions) (MojoResult, M func (impl *coreImpl) CreateSharedBuffer(opts *SharedBufferOptions, numBytes uint64) (MojoResult, SharedBufferHandle) { var flags uint32 if opts != nil { - flags = uint32(opts.flags) + flags = uint32(opts.Flags) } impl.mu.Lock() r, handle := sysImpl.CreateSharedBuffer(flags, numBytes) diff --git a/third_party/mojo/src/mojo/public/go/system/mojo_types.go b/third_party/mojo/src/mojo/public/go/system/mojo_types.go index 69051e7ab360..1eb5f7322cd9 100644 --- a/third_party/mojo/src/mojo/public/go/system/mojo_types.go +++ b/third_party/mojo/src/mojo/public/go/system/mojo_types.go @@ -101,27 +101,27 @@ type MojoHandleSignalsState struct { // DataPipeOptions is used to specify creation parameters for a data pipe. type DataPipeOptions struct { - flags MojoCreateDataPipeOptionsFlags + Flags MojoCreateDataPipeOptionsFlags // The size of an element in bytes. All transactions and buffers will // be an integral number of elements. - elemSize uint32 + ElemSize uint32 // The capacity of the data pipe in bytes. Must be a multiple of elemSize. - capacity uint32 + Capacity uint32 } // MessagePipeOptions is used to specify creation parameters for a message pipe. type MessagePipeOptions struct { - flags MojoCreateMessagePipeOptionsFlags + Flags MojoCreateMessagePipeOptionsFlags } // SharedBufferOptions is used to specify creation parameters for a // shared buffer. type SharedBufferOptions struct { - flags MojoCreateSharedBufferOptionsFlags + Flags MojoCreateSharedBufferOptionsFlags } // DuplicateBufferHandleOptions is used to specify parameters in // duplicating access to a shared buffer. type DuplicateBufferHandleOptions struct { - flags MojoDuplicateBufferHandleOptionsFlags + Flags MojoDuplicateBufferHandleOptionsFlags } diff --git a/third_party/mojo/src/mojo/public/go/system/shared_buffer.go b/third_party/mojo/src/mojo/public/go/system/shared_buffer.go index 925ee353d637..f3048f877918 100644 --- a/third_party/mojo/src/mojo/public/go/system/shared_buffer.go +++ b/third_party/mojo/src/mojo/public/go/system/shared_buffer.go @@ -35,7 +35,7 @@ type sharedBuffer struct { func (h *sharedBuffer) DuplicateBufferHandle(opts *DuplicateBufferHandleOptions) (MojoResult, SharedBufferHandle) { var flags uint32 if opts != nil { - flags = uint32(opts.flags) + flags = uint32(opts.Flags) } h.core.mu.Lock() r, dup := sysImpl.DuplicateBufferHandle(uint32(h.mojoHandle), flags) diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_unions.mojom b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_unions.mojom index 7250f6595a9d..cda5be4c48ba 100644 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_unions.mojom +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_unions.mojom @@ -22,6 +22,10 @@ union PodUnion { union ObjectUnion { int8 f_int8; string f_string; + DummyStruct f_dummy; + DummyStruct? f_nullable; + array f_array_int8; + map f_map_int8; }; struct DummyStruct { @@ -33,6 +37,7 @@ struct SmallStruct { PodUnion? pod_union; array? pod_union_array; array? s_array; + map? pod_union_map; }; struct SmallStructNonNullableUnion { diff --git a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java index 94f444570ac7..23a618885cf8 100644 --- a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java +++ b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java @@ -4,6 +4,7 @@ package org.chromium.mojo.bindings; +import org.chromium.mojo.bindings.Interface.AbstractProxy.HandlerImpl; import org.chromium.mojo.bindings.Struct.DataHeader; import org.chromium.mojo.system.Core; import org.chromium.mojo.system.Handle; @@ -261,9 +262,9 @@ public class Encoder { } // If the instance is a proxy, pass the proxy's handle instead of creating a new stub. if (v instanceof Interface.AbstractProxy) { - Interface.AbstractProxy proxy = (Interface.AbstractProxy) v; - if (proxy.getMessageReceiver() instanceof HandleOwner) { - encode(((HandleOwner) proxy.getMessageReceiver()).passHandle(), offset, + HandlerImpl handler = ((Interface.AbstractProxy) v).getProxyHandler(); + if (handler.getMessageReceiver() instanceof HandleOwner) { + encode(((HandleOwner) handler.getMessageReceiver()).passHandle(), offset, nullable); return; } diff --git a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java index c3b26a205dd6..4c828db04c22 100644 --- a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java +++ b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java @@ -30,84 +30,129 @@ public interface Interface extends ConnectionErrorHandler, Closeable { * {@link MessageReceiverWithResponder}, along with the response callback if needed. */ public interface Proxy extends Interface { - /** - * Set the {@link ConnectionErrorHandler} that will be notified of errors. + * Class allowing to interact with the proxy itself. */ - public void setErrorHandler(ConnectionErrorHandler errorHandler); + public interface Handler extends Closeable { + /** + * Sets the {@link ConnectionErrorHandler} that will be notified of errors. + */ + public void setErrorHandler(ConnectionErrorHandler errorHandler); + } + /** + * Returns the {@link Handler} object allowing to interact with the proxy itself. + */ + public Handler getProxyHandler(); } /** * Base implementation of {@link Proxy}. */ abstract class AbstractProxy implements Proxy { - /** - * The {@link Core} implementation to use. + * Implementation of {@link Handler}. */ - private final Core mCore; + protected static class HandlerImpl implements Proxy.Handler, ConnectionErrorHandler { + /** + * The {@link Core} implementation to use. + */ + private final Core mCore; + + /** + * The {@link MessageReceiverWithResponder} that will receive a serialized message for + * each method call. + */ + private final MessageReceiverWithResponder mMessageReceiver; + + /** + * The {@link ConnectionErrorHandler} that will be notified of errors. + */ + private ConnectionErrorHandler mErrorHandler = null; + + /** + * Constructor. + * + * @param core the Core implementation used to create pipes and access the async waiter. + * @param messageReceiver the message receiver to send message to. + */ + protected HandlerImpl(Core core, MessageReceiverWithResponder messageReceiver) { + this.mCore = core; + this.mMessageReceiver = messageReceiver; + } - /** - * The {@link MessageReceiverWithResponder} that will receive a serialized message for each - * method call. - */ - private final MessageReceiverWithResponder mMessageReceiver; + /** + * Returns the message receiver to send message to. + */ + public MessageReceiverWithResponder getMessageReceiver() { + return mMessageReceiver; + } - /** - * The {@link ConnectionErrorHandler} that will be notified of errors. - */ - private ConnectionErrorHandler mErrorHandler = null; + /** + * Returns the Core implementation. + */ + public Core getCore() { + return mCore; + } - /** - * Constructor. - * - * @param core the Core implementation used to create pipes and access the async waiter. - * @param messageReceiver the message receiver to send message to. - */ - protected AbstractProxy(Core core, MessageReceiverWithResponder messageReceiver) { - this.mCore = core; - this.mMessageReceiver = messageReceiver; - } + /** + * Sets the {@link ConnectionErrorHandler} that will be notified of errors. + */ + @Override + public void setErrorHandler(ConnectionErrorHandler errorHandler) { + this.mErrorHandler = errorHandler; + } - /** - * Returns the message receiver to send message to. - */ - protected MessageReceiverWithResponder getMessageReceiver() { - return mMessageReceiver; + /** + * @see ConnectionErrorHandler#onConnectionError(MojoException) + */ + @Override + public void onConnectionError(MojoException e) { + if (mErrorHandler != null) { + mErrorHandler.onConnectionError(e); + } + } + + /** + * @see Closeable#close() + */ + @Override + public void close() { + mMessageReceiver.close(); + } } /** - * Returns the Core implementation. + * The handler associated with this proxy. */ - protected Core getCore() { - return mCore; + private final HandlerImpl mHandler; + + protected AbstractProxy(Core core, MessageReceiverWithResponder messageReceiver) { + mHandler = new HandlerImpl(core, messageReceiver); } /** - * @see Proxy#setErrorHandler(ConnectionErrorHandler) + * @see Interface#close() */ @Override - public void setErrorHandler(ConnectionErrorHandler errorHandler) { - this.mErrorHandler = errorHandler; + public void close() { + mHandler.close(); } /** - * @see ConnectionErrorHandler#onConnectionError(MojoException) + * @see Proxy#getProxyHandler() */ @Override - public void onConnectionError(MojoException e) { - if (mErrorHandler != null) { - mErrorHandler.onConnectionError(e); - } + public HandlerImpl getProxyHandler() { + return mHandler; } /** - * @see Closeable#close() + * @see ConnectionErrorHandler#onConnectionError(org.chromium.mojo.system.MojoException) */ @Override - public void close() { - mMessageReceiver.close(); + public void onConnectionError(MojoException e) { + mHandler.onConnectionError(e); } } diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl index 6e52c392ebdd..3cadeed80881 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl @@ -171,6 +171,7 @@ bool {{class_name}}Stub::Accept(mojo::Message* message) { switch (message->header()->name) { {%- for method in interface.methods %} case internal::k{{class_name}}_{{method.name}}_Name: { + mojo::internal::ScopedTaskTracking task_id("mojo.{{namespace_as_string}}.{{class_name}}.{{method.name}}", __FILE__, __LINE__); {%- if method.response_parameters == None %} internal::{{class_name}}_{{method.name}}_Params_Data* params = reinterpret_cast( @@ -198,6 +199,7 @@ bool {{class_name}}Stub::AcceptWithResponder( switch (message->header()->name) { {%- for method in interface.methods %} case internal::k{{class_name}}_{{method.name}}_Name: { + mojo::internal::ScopedTaskTracking task_id("mojo::{{namespace_as_string}}::{{class_name}}::{{method.name}}", __FILE__, __LINE__); {%- if method.response_parameters != None %} internal::{{class_name}}_{{method.name}}_Params_Data* params = reinterpret_cast( @@ -231,49 +233,32 @@ bool {{class_name}}Stub::AcceptWithResponder( } bool {{class_name}}RequestValidator::Accept(mojo::Message* message) { -{%- if interface.methods %} - if (message->has_flag(mojo::internal::kMessageIsResponse)) { - ReportValidationError( - mojo::internal::VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS); - return false; - } + assert(sink_); switch (message->header()->name) { -{%- for method in interface.methods %} +{%- for method in interface.methods %} case internal::k{{class_name}}_{{method.name}}_Name: { -{%- if method.response_parameters != None %} - if (!message->has_flag(mojo::internal::kMessageExpectsResponse)) { - ReportValidationError( - mojo::internal::VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS); +{%- if method.response_parameters != None %} + if (!mojo::internal::ValidateMessageIsRequestExpectingResponse(message)) return false; - } -{%- else %} - if (message->has_flag(mojo::internal::kMessageExpectsResponse)) { - ReportValidationError( - mojo::internal::VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS); +{%- else %} + if (!mojo::internal::ValidateMessageIsRequestWithoutResponse(message)) return false; - } -{%- endif %} - mojo::internal::BoundsChecker bounds_checker( - message->payload(), message->payload_num_bytes(), - message->handles()->size()); - if (!internal::{{class_name}}_{{method.name}}_Params_Data::Validate( - message->payload(), &bounds_checker)) { +{%- endif %} + if (!mojo::internal::ValidateMessagePayload< + internal::{{class_name}}_{{method.name}}_Params_Data>(message)) { return false; } - break; - } -{%- endfor %} - default: { - // Unrecognized message. - ReportValidationError( - mojo::internal::VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD); - return false; + return sink_->Accept(message); } +{%- endfor %} + default: + break; } -{%- endif %} - assert(sink_); - return sink_->Accept(message); + // Unrecognized message. + ReportValidationError( + mojo::internal::VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD); + return false; } {#--- Response validator definitions #} @@ -283,35 +268,26 @@ bool {{class_name}}RequestValidator::Accept(mojo::Message* message) { } bool {{class_name}}ResponseValidator::Accept(mojo::Message* message) { -{%- if interface.methods %} - if (!message->has_flag(mojo::internal::kMessageIsResponse)) { - ReportValidationError( - mojo::internal::VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS); + assert(sink_); + if (!mojo::internal::ValidateMessageIsResponse(message)) return false; - } switch (message->header()->name) { -{%- for method in interface.methods if method.response_parameters != None %} +{%- for method in interface.methods if method.response_parameters != None %} case internal::k{{class_name}}_{{method.name}}_Name: { - mojo::internal::BoundsChecker bounds_checker( - message->payload(), message->payload_num_bytes(), - message->handles()->size()); - if (!internal::{{class_name}}_{{method.name}}_ResponseParams_Data::Validate( - message->payload(), &bounds_checker)) { + if (!mojo::internal::ValidateMessagePayload< + internal::{{class_name}}_{{method.name}}_ResponseParams_Data>(message)) { return false; } - break; - } -{%- endfor %} - default: { - // Unrecognized message. - ReportValidationError( - mojo::internal::VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD); - return false; + return sink_->Accept(message); } +{%- endfor %} + default: + break; } -{%- endif %} - assert(sink_); - return sink_->Accept(message); + // Unrecognized message. + ReportValidationError( + mojo::internal::VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD); + return false; } {%- endif -%} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl index 3593ff6b301a..210ee2e5f096 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl @@ -25,6 +25,8 @@ #include "mojo/public/cpp/bindings/lib/string_serialization.h" #include "mojo/public/cpp/bindings/lib/validate_params.h" #include "mojo/public/cpp/bindings/lib/validation_errors.h" +#include "mojo/public/cpp/bindings/lib/validation_util.h" +#include "mojo/public/cpp/environment/lib/scoped_task_tracking.h" #include "mojo/public/cpp/environment/logging.h" {%- for namespace in namespaces_as_array %} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl index bc77c112dd0f..f84f60a73015 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl @@ -32,7 +32,7 @@ class {{class_name}} { // a struct." - Section 9.5.2 ISO/IEC 14882:2011 (The C++ Spec) union MOJO_ALIGNAS(8) Union_ { {%- for field in union.fields %} -{%- if field.kind|is_string_kind %} +{%- if field.kind|is_object_kind %} uint64_t f_{{field.name}}; {%- elif field.kind.spec == 'b' %} uint8_t f_{{field.name}} : 1; diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl index 3e6b0ade989a..9ddcc5168db2 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl @@ -57,10 +57,36 @@ void {{class_name}}::set_null() { void {{class_name}}::EncodePointersAndHandles( std::vector* handles) { - // TODO(azani): Implement pointers and handles. + switch (tag) { +{%- for field in union.fields %} + case {{enum_name}}::{{field.name|upper}}: { +{%- if field.kind|is_object_kind and not field.kind|is_union_kind %} + mojo::internal::Encode( + reinterpret_cast<{{field.kind|cpp_field_type}}*>(&data.f_{{field.name}}), + handles); +{%- elif field.kind|is_any_handle_kind %} + mojo::internal::EncodeHandle(&data.f_{{field.name}}, handles); +{%- endif %} + return; + } +{%- endfor %} + } } void {{class_name}}::DecodePointersAndHandles( std::vector* handles) { - // TODO(azani): Implement pointers and handles. + switch (tag) { +{%- for field in union.fields %} + case {{enum_name}}::{{field.name|upper}}: { +{%- if field.kind|is_object_kind and not field.kind|is_union_kind %} + mojo::internal::Decode( + reinterpret_cast<{{field.kind|cpp_field_type}}*>(&data.f_{{field.name}}), + handles); +{%- elif field.kind|is_any_handle_kind %} + mojo::internal::DecodeHandle(&data.f_{{field.name}}, handles); +{%- endif %} + return; + } +{%- endfor %} + } } diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl index f928eba5a9f2..7df17c1fead7 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl @@ -7,11 +7,12 @@ size_t GetSerializedSize_(const {{union.name}}Ptr& input, bool inlined) { if (!input) return size; + mojo::internal::UnionAccessor<{{union.name}}> input_acc(input.get()); switch (input->which()) { {% for field in union.fields %} -{% if field.kind|is_string_kind %} +{% if field.kind|is_object_kind %} case {{union.name}}::Tag::{{field.name|upper}}: - size += GetSerializedSize_(input->get_{{field.name}}()); + size += GetSerializedSize_(*(input_acc.data()->{{field.name}})); break; {%- endif %} {%- endfor %} @@ -35,14 +36,31 @@ void SerializeUnion_({{union.name}}Ptr input, mojo::internal::Buffer* buf, result->tag = input->which(); switch (input->which()) { {% for field in union.fields %} - case {{union.name}}::Tag::{{field.name|upper}}: -{% if field.kind|is_string_kind %} + case {{union.name}}::Tag::{{field.name|upper}}: { +{% if field.kind|is_object_kind %} {{field.kind|cpp_field_type}}* {{field.name}}_ptr = reinterpret_cast<{{field.kind|cpp_field_type}}*>(&result->data.f_{{field.name}}); +{% if field.kind|is_string_kind %} Serialize_(*(input_acc.data()->{{field.name}}), buf, &{{field.name}}_ptr->ptr); +{% elif field.kind|is_struct_kind %} + Serialize_(mojo::internal::Forward(*(input_acc.data()->{{field.name}})), buf, &{{field.name}}_ptr->ptr); +{% elif field.kind|is_array_kind %} + const mojo::internal::ArrayValidateParams {{field.name}}_validate_params = + {{field.kind|get_array_validate_params|indent(16)}}; + SerializeArray_( + mojo::internal::Forward(*(input_acc.data()->{{field.name}})), + buf, &{{field.name}}_ptr->ptr, &{{field.name}}_validate_params); +{% elif field.kind|is_map_kind %} + const mojo::internal::ArrayValidateParams {{field.name}}_validate_params = + {{field.kind.value_kind|get_map_validate_params|indent(16)}}; + SerializeMap_( + mojo::internal::Forward(*(input_acc.data()->{{field.name}})), + buf, &{{field.name}}_ptr->ptr, &{{field.name}}_validate_params); +{%- endif %} {% else %} result->data.f_{{field.name}} = input_acc.data()->{{field.name}}; {%- endif %} break; + } {%- endfor %} } } else if (inlined) { @@ -60,8 +78,8 @@ void Deserialize_(internal::{{union.name}}_Data* input, mojo::internal::UnionAccessor<{{union.name}}> result_acc(result.get()); switch (input->tag) { {% for field in union.fields %} - case {{union.name}}::Tag::{{field.name|upper}}: -{% if field.kind|is_string_kind %} + case {{union.name}}::Tag::{{field.name|upper}}: { +{% if field.kind|is_object_kind %} result_acc.SwitchActive({{union.name}}::Tag::{{field.name|upper}}); {{field.kind|cpp_field_type}}* {{field.name}}_ptr = reinterpret_cast<{{field.kind|cpp_field_type}}*>(&input->data.f_{{field.name}}); Deserialize_({{field.name}}_ptr->ptr, result_acc.data()->{{field.name}}); @@ -69,6 +87,7 @@ void Deserialize_(internal::{{union.name}}_Data* input, result->set_{{field.name}}(input->data.f_{{field.name}}); {%- endif %} break; + } {%- endfor %} } *output = result.Pass(); diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl index 107de09e66b5..2b4a7dded9c1 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl @@ -29,7 +29,7 @@ class {{union.name}} { {% for field in union.fields %} bool is_{{field.name}}() const; - {{field.kind|cpp_result_type}} get_{{field.name}}() const; + {{field.kind|cpp_union_getter_return_type}} get_{{field.name}}() const; void set_{{field.name}}({{field.kind|cpp_const_wrapper_type}} {{field.name}}); {%- endfor %} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl index b5e9c23781a2..4355f41cfd38 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl @@ -21,8 +21,10 @@ switch (tag_) { {% for field in union.fields %} case Tag::{{field.name|upper}}: -{% if field.kind|is_object_kind %} +{% if field.kind|is_string_kind %} rv->set_{{field.name}}(*(data_.{{field.name}})); +{% elif field.kind|is_object_kind %} + rv->set_{{field.name}}(data_.{{field.name}}->Clone()); {%- else %} rv->set_{{field.name}}(data_.{{field.name}}); {%- endif %} @@ -57,7 +59,7 @@ bool {{union.name}}::is_{{field.name}}() const { return tag_ == Tag::{{field.name|upper}}; } -{{field.kind|cpp_result_type}} {{union.name}}::get_{{field.name}}() const { +{{field.kind|cpp_union_getter_return_type}} {{union.name}}::get_{{field.name}}() const { MOJO_DCHECK(tag_ == Tag::{{field.name|upper}}); {% if field.kind|is_object_kind %} return *(data_.{{field.name}}); @@ -70,6 +72,8 @@ void {{union.name}}::set_{{field.name}}({{field.kind|cpp_const_wrapper_type}} {{ SwitchActive(Tag::{{field.name|upper}}); {% if field.kind|is_string_kind %} *(data_.{{field.name}}) = {{field.name}}; +{% elif field.kind|is_object_kind %} + *(data_.{{field.name}}) = {{field.name}}.Pass(); {%- else %} data_.{{field.name}} = {{field.name}}; {%- endif %} @@ -89,8 +93,8 @@ void {{union.name}}::SetActive(Tag new_active) { switch (new_active) { {% for field in union.fields %} case Tag::{{field.name|upper}}: -{% if field.kind|is_string_kind %} - data_.{{field.name}} = new String(); +{% if field.kind|is_object_kind %} + data_.{{field.name}} = new {{field.kind|cpp_wrapper_type}}(); {%- endif %} break; {%- endfor %} @@ -103,7 +107,7 @@ void {{union.name}}::DestroyActive() { switch (tag_) { {% for field in union.fields %} case Tag::{{field.name|upper}}: -{% if field.kind|is_string_kind %} +{% if field.kind|is_object_kind %} delete data_.{{field.name}}; {%- endif %} break; diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/interface.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/interface.tmpl index 4d4ea394f893..9c378735b32c 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/interface.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/interface.tmpl @@ -81,7 +81,7 @@ func CreateMessagePipeFor{{interface|name}}() ({{interface|name}}Request, {{inte } {% for method in interface.methods %} -const {{interface|name(False)}}_{{method|name}}_Name = {{method.ordinal}} +const {{interface|name(False)}}_{{method|name}}_Name uint32 = {{method.ordinal}} {% endfor %} type {{interface|name}}Proxy struct { @@ -130,9 +130,20 @@ func (p *{{interface|name}}Proxy) {{method|name}}{{declare_request_params(method p.Close_proxy() return } + if readResult.Message.Header.Flags != bindings.MessageIsResponseFlag { + err = &bindings.ValidationError{bindings.MessageHeaderInvalidFlags, + fmt.Sprintf("invalid message header flag: %v", readResult.Message.Header.Flags), + } + return + } + if got, want := readResult.Message.Header.Type, {{interface|name(False)}}_{{method|name}}_Name; got != want { + err = &bindings.ValidationError{bindings.MessageHeaderUnknownMethod, + fmt.Sprintf("invalid method in response: expected %v, got %v", want, got), + } + return + } var response {{method.response_param_struct|name(False)}} if err = readResult.Message.DecodePayload(&response); err != nil { - err = fmt.Errorf("can't decode response: %v", err.Error()) p.Close_proxy() return } @@ -163,9 +174,18 @@ func (s *{{interface|name(False)}}Stub) Accept(message *bindings.Message) (err e switch message.Header.Type { {% for method in interface.methods %} case {{interface|name(False)}}_{{method|name}}_Name: +{% if method.response_parameters %} + if message.Header.Flags != bindings.MessageExpectsResponseFlag { +{% else %} + if message.Header.Flags != bindings.MessageNoFlag { +{% endif %} + return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags, + fmt.Sprintf("invalid message header flag: %v", message.Header.Flags), + } + } var request {{method.param_struct|name(False)}} if err := message.DecodePayload(&request); err != nil { - return fmt.Errorf("can't decode request: %v", err.Error()) + return err } {% if method.response_parameters %} var response {{method.response_param_struct|name(False)}} @@ -192,13 +212,16 @@ func (s *{{interface|name(False)}}Stub) Accept(message *bindings.Message) (err e } message, err = bindings.EncodeMessage(header, &response) if err != nil { - return fmt.Errorf("can't encode response: %v", err.Error()) + return err } return s.connector.WriteMessage(message) {% endif %} {% endfor %} default: - return fmt.Errorf("unsupported request type %v", message.Header.Type); + return &bindings.ValidationError{ + bindings.MessageHeaderUnknownMethod, + fmt.Sprintf("unknown method %v", message.Header.Type), + } } return } diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/struct.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/struct.tmpl index 7f687d211256..5e10011c33a2 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/struct.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/struct.tmpl @@ -43,7 +43,9 @@ func (s *{{struct|name(exported)}}) Decode(decoder *bindings.Decoder) error { } expectedSize := {{struct|name(False)}}_Versions[index].Size if expectedSize != header.Size { - return fmt.Errorf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size) + return &bindings.ValidationError{bindings.UnexpectedStructHeader, + fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size), + } } } {% for byte in struct.bytes %} @@ -151,7 +153,7 @@ if pointer{{level}} == 0 { {{decodePointerValue('(*'~value~')', kind, level)|tab_indent()}} } {% else %} - return fmt.Errorf("unexpected null pointer") + return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"} } else { {{decodePointerValue(value, kind, level)|tab_indent()}} } @@ -172,7 +174,7 @@ if handle{{level}}.IsValid() { {% if kind|is_nullable %} {{value}} = nil {% else %} - return fmt.Errorf("unexpected invalid handle") + return &bindings.ValidationError{bindings.UnexpectedInvalidHandle, "unexpected invalid handle"} {% endif %} } {% elif kind|is_enum %} @@ -204,7 +206,9 @@ if err != nil { } {% if kind.length %} if len{{level}} != {{kind.length}} { - return fmt.Errorf("invalid array length: expected %d, got %d", {{kind.length}}, len{{level}}) + return &bindings.ValidationError{bindings.UnexpectedArrayHeader, + fmt.Sprintf("invalid array length: expected %d, got %d", {{kind.length}}, len{{level}}), + } } {% else %} {{value}} = make({{kind|go_type(False)}}, len{{level}}) @@ -228,7 +232,9 @@ var values{{level}} {{kind.value_kind|array|go_type}} {{decode('values'~level, kind.value_kind|array, level+1)|tab_indent()}} } if len(keys{{level}}) != len(values{{level}}) { - return fmt.Errorf("Number of keys %d is different from number of values %d", len(keys{{level}}), len(values{{level}})) + return &bindings.ValidationError{bindings.DifferentSizedArraysInMap, + fmt.Sprintf("Number of keys %d is different from number of values %d", len(keys{{level}}), len(values{{level}})), + } } if err := decoder.Finish(); err != nil { return err diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl index c7aed13398a4..d666e66432ee 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl @@ -168,18 +168,18 @@ class {{interface|name}}_Internal { _message.{{param|name}} = {{param|name}}; {% endfor %} {% if method.response_parameters != None %} - getMessageReceiver().acceptWithResponder( + getProxyHandler().getMessageReceiver().acceptWithResponder( _message.serializeWithHeader( - getCore(), + getProxyHandler().getCore(), new org.chromium.mojo.bindings.MessageHeader( {{method|method_ordinal_name}}, {{flags_for_method(method, True)}}, 0)), new {{method.response_param_struct|name}}ForwardToCallback(callback)); {% else %} - getMessageReceiver().accept( + getProxyHandler().getMessageReceiver().accept( _message.serializeWithHeader( - getCore(), + getProxyHandler().getCore(), new org.chromium.mojo.bindings.MessageHeader({{method|method_ordinal_name}}))); {% endif %} } diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_cpp_generator.py index 10ce58214599..b5bf6a460ee0 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_cpp_generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_cpp_generator.py @@ -227,6 +227,12 @@ def GetCppFieldType(kind): return "mojo::internal::StringPointer" return _kind_to_cpp_type[kind] +def GetUnionGetterReturnType(kind): + if (mojom.IsStructKind(kind) or mojom.IsArrayKind(kind) or + mojom.IsMapKind(kind)): + return "%s&" % GetCppWrapperType(kind) + return GetCppResultWrapperType(kind) + def IsStructWithHandles(struct): for pf in struct.packed.packed_fields: if mojom.IsAnyHandleKind(pf.field.kind): @@ -335,6 +341,7 @@ class Generator(generator.Generator): "cpp_pod_type": GetCppPodType, "cpp_result_type": GetCppResultWrapperType, "cpp_type": GetCppType, + "cpp_union_getter_return_type": GetUnionGetterReturnType, "cpp_wrapper_type": GetCppWrapperType, "default_value": DefaultValue, "expression_to_text": ExpressionToText, @@ -374,7 +381,7 @@ class Generator(generator.Generator): "kinds": self.module.kinds, "enums": self.module.enums, "structs": self.GetStructs(), - "unions": self.module.unions, + "unions": self.GetUnions(), "interfaces": self.GetInterfaces(), } diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py index 9d2fafef9754..ac27fa1d3dde 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py @@ -360,7 +360,7 @@ def IsPointerArrayKind(kind): def GetImportUri(module): elements = module.namespace.split('.') elements.append("%s" % module.name) - return os.path.join(*elements) + return os.path.join("mojom", *elements) class Generator(generator.Generator): @@ -402,17 +402,24 @@ class Generator(generator.Generator): def GenerateFiles(self, args): elements = self.module.namespace.split('.') elements.append("%s.dart" % self.module.name) - path = os.path.join("dart-gen", *elements) + path = os.path.join("dart-gen", "mojom", *elements) self.Write(self.GenerateLibModule(args), path) link = self.MatchMojomFilePath("%s.dart" % self.module.name) if os.path.exists(os.path.join(self.output_dir, link)): os.unlink(os.path.join(self.output_dir, link)) - if sys.platform == "win32": - shutil.copy(os.path.join(self.output_dir, path), - os.path.join(self.output_dir, link)) - else: - os.symlink(os.path.join(self.output_dir, path), - os.path.join(self.output_dir, link)) + try: + if sys.platform == "win32": + shutil.copy(os.path.join(self.output_dir, path), + os.path.join(self.output_dir, link)) + else: + os.symlink(os.path.join(self.output_dir, path), + os.path.join(self.output_dir, link)) + except OSError as e: + # Errno 17 is file already exists. If the link fails because file already + # exists assume another instance of this script tried to create the same + # file and continue on. + if e.errno != 17: + raise e def GetImports(self, args): used_names = set() diff --git a/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni b/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni index 6151ded3ff99..d00f6322e3a5 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni +++ b/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni @@ -4,9 +4,9 @@ import("../../mojo_sdk.gni") -# Generate C++ and JavaScript source files from mojom files. The output files -# will go under the generated file directory tree with the same path as each -# input file. +# Generate C++/JavaScript/Java/Python/Dart/Go source files from mojom files. The +# output files will go under the generated file directory tree with the same +# path as each input file. # # If a mojom target is intended for use in a client repo where the location of # the Mojo SDK will be different than its location in the Mojo repo, @@ -48,6 +48,8 @@ template("mojom") { defined(invoker.mojo_sdk_public_deps), "\"sources\" or \"deps\" must be defined for the $target_name template.") + cpp_sources_suffix = "cpp_sources" + cpp_sources_target_name = "${target_name}_${cpp_sources_suffix}" if (defined(invoker.sources)) { generator_root = rebase_path("mojo/public/tools/bindings", ".", mojo_root) generator_script = "$generator_root/mojom_bindings_generator.py" @@ -78,6 +80,11 @@ template("mojom") { "$generator_root/generators/cpp_templates/wrapper_class_definition.tmpl", "$generator_root/generators/cpp_templates/wrapper_union_class_declaration.tmpl", "$generator_root/generators/cpp_templates/wrapper_union_class_definition.tmpl", + "$generator_root/generators/dart_templates/enum_definition.tmpl", + "$generator_root/generators/dart_templates/interface_definition.tmpl", + "$generator_root/generators/dart_templates/module.lib.tmpl", + "$generator_root/generators/dart_templates/module_definition.tmpl", + "$generator_root/generators/dart_templates/struct_definition.tmpl", "$generator_root/generators/go_templates/enum.tmpl", "$generator_root/generators/go_templates/interface.tmpl", "$generator_root/generators/go_templates/source.tmpl", @@ -100,6 +107,7 @@ template("mojom") { "$generator_root/generators/python_templates/module.py.tmpl", "$generator_root/generators/python_templates/module_macros.tmpl", "$generator_root/generators/mojom_cpp_generator.py", + "$generator_root/generators/mojom_dart_generator.py", "$generator_root/generators/mojom_go_generator.py", "$generator_root/generators/mojom_js_generator.py", "$generator_root/generators/mojom_java_generator.py", @@ -126,12 +134,15 @@ template("mojom") { ] generator_js_outputs = [ "{{source_gen_dir}}/{{source_name_part}}.mojom.js" ] + generator_dart_outputs = + [ "{{source_gen_dir}}/{{source_name_part}}.mojom.dart" ] generator_go_outputs = [ "${root_gen_dir}/go/src/{{source_dir}}/{{source_name_part}}/{{source_name_part}}.mojom.go" ] generator_python_outputs = [ "{{source_gen_dir}}/{{source_name_part}}_mojom.py" ] generator_java_outputs = [ "{{source_gen_dir}}/{{source_name_part}}.mojom.srcjar" ] } + generator_dart_zip_output = "$target_out_dir/$target_name.dartzip" generator_python_zip_output = "$target_out_dir/$target_name.pyzip" rebased_mojo_sdk_public_deps = [] @@ -163,12 +174,13 @@ template("mojom") { generator_target_name = target_name + "__generator" action_foreach(generator_target_name) { if (defined(invoker.visibility)) { - visibility = target_visibility + invoker.visibility + visibility = target_visibility + invoker.visibility + + [ ":${cpp_sources_target_name}" ] } script = generator_script inputs = generator_sources sources = invoker.sources - outputs = generator_cpp_outputs + + outputs = generator_cpp_outputs + generator_dart_outputs + generator_go_outputs + generator_java_outputs + generator_js_outputs + generator_python_outputs args = [ @@ -203,7 +215,6 @@ template("mojom") { testonly = invoker.testonly } if (defined(invoker.sources)) { - sources = process_file_template(invoker.sources, generator_cpp_outputs) data = process_file_template(invoker.sources, generator_js_outputs) } @@ -211,6 +222,9 @@ template("mojom") { rebase_path([ "mojo/public/build/config:mojo_sdk" ], ".", mojo_root) public_deps = rebase_path([ "mojo/public/cpp/bindings" ], ".", mojo_root) + if (defined(invoker.sources)) { + public_deps += [ ":${cpp_sources_target_name}" ] + } public_deps += rebased_mojo_sdk_public_deps if (defined(invoker.public_deps)) { public_deps += invoker.public_deps @@ -226,6 +240,7 @@ template("mojom") { } data_deps = [ ":${target_name}_python", + ":${target_name}_dart", ] if (defined(invoker.mojo_sdk_deps)) { foreach(sdk_dep, invoker.mojo_sdk_deps) { @@ -300,6 +315,79 @@ template("mojom") { } } + action("${target_name}_dart") { + script = rebase_path("mojo/public/tools/gn/zip.py", ".", mojo_root) + + if (defined(invoker.sources)) { + inputs = process_file_template(invoker.sources, generator_dart_outputs) + } + + deps = [] + zip_inputs = [] + + foreach(d, all_deps) { + # Resolve the name, so that a target //mojo/something becomes + # //mojo/something:something and we can append "_dart" to get the dart + # dependency name. + full_name = get_label_info(d, "label_no_toolchain") + dep_name = get_label_info(d, "name") + dep_target_out_dir = get_label_info(d, "target_out_dir") + deps += [ "${full_name}_dart" ] + zip_inputs += [ "$dep_target_out_dir/$dep_name.dartzip" ] + } + + output = generator_dart_zip_output + outputs = [ + output, + ] + + rebase_import_from = + rebase_path("$root_build_dir/gen/dart-gen", root_build_dir) + if (defined(invoker.sources)) { + rebase_inputs = rebase_path(inputs, root_build_dir) + } + rebase_zip_inputs = rebase_path(zip_inputs, root_build_dir) + rebase_output = rebase_path(output, root_build_dir) + args = [ + "--base-dir=$rebase_import_from", + "--zip-inputs=$rebase_zip_inputs", + "--output=$rebase_output", + ] + if (defined(invoker.sources)) { + args += [ "--link-inputs=$rebase_inputs" ] + } + } + + if (defined(invoker.sources)) { + # The generated C++ source files. The main reason to introduce this target + # is so that mojo/public/cpp/bindings can depend on mojom interfaces without + # circular dependencies. It means that the target is missing the dependency + # on mojo/public/cpp/bindings. No external targets should depend directly on + # this target *except* mojo/public/cpp/bindings and other *_cpp_sources + # targets. + source_set(cpp_sources_target_name) { + if (defined(invoker.visibility)) { + visibility = target_visibility + invoker.visibility + } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } + sources = process_file_template(invoker.sources, generator_cpp_outputs) + public_configs = + rebase_path([ "mojo/public/build/config:mojo_sdk" ], ".", mojo_root) + deps = [ + ":$generator_target_name", + ] + foreach(d, all_deps) { + # Resolve the name, so that a target //mojo/something becomes + # //mojo/something:something and we can append cpp_sources_suffix to + # get the cpp dependency name. + full_name = get_label_info(d, "label_no_toolchain") + deps += [ "${full_name}_${cpp_sources_suffix}" ] + } + } + } + if (is_android) { import("//build/config/android/rules.gni") diff --git a/third_party/mojo/src/mojo/public/tools/bindings/mojom_bindings_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/mojom_bindings_generator.py index 64fcc7af83dc..0498838a8659 100755 --- a/third_party/mojo/src/mojo/public/tools/bindings/mojom_bindings_generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/mojom_bindings_generator.py @@ -195,7 +195,7 @@ def main(): help="output directory for generated files") parser.add_argument("-g", "--generators", dest="generators_string", metavar="GENERATORS", - default="c++,go,javascript,java,python", + default="c++,dart,go,javascript,java,python", help="comma-separated list of generators") parser.add_argument("--debug_print_intermediate", action="store_true", help="print the intermediate representation") diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator.py index 9c2763ddd10d..666ef439fa52 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator.py @@ -56,6 +56,9 @@ class Generator(object): def GetStructs(self): return map(partial(self._AddStructComputedData, True), self.module.structs) + def GetUnions(self): + return map(self._AddUnionComputedData, self.module.unions) + def GetInterfaces(self): return map(self._AddInterfaceComputedData, self.module.interfaces) @@ -91,6 +94,17 @@ class Generator(object): struct.exported = exported return struct + def _AddUnionComputedData(self, union): + """Adds computed data to the given union. The data is computed once and + used repeatedly in the generation process.""" + ordinal = 0 + for field in union.fields: + if field.ordinal is not None: + ordinal = field.ordinal + field.ordinal = ordinal + ordinal += 1 + return union + def _AddInterfaceComputedData(self, interface): """Adds computed data to the given interface. The data is computed once and used repeatedly in the generation process.""" diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator_unittest.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator_unittest.py new file mode 100644 index 000000000000..9966b0b7f8f5 --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator_unittest.py @@ -0,0 +1,24 @@ +# 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. + +import unittest + +import module as mojom +import generator + +class TestGenerator(unittest.TestCase): + + def testGetUnionsAddsOrdinals(self): + module = mojom.Module() + union = module.AddUnion('a') + union.AddField('a', mojom.BOOL) + union.AddField('b', mojom.BOOL) + union.AddField('c', mojom.BOOL, ordinal=10) + union.AddField('d', mojom.BOOL) + + gen = generator.Generator(module) + union = gen.GetUnions()[0] + ordinals = [field.ordinal for field in union.fields] + + self.assertEquals([0, 1, 10, 11], ordinals) diff --git a/third_party/mojo/src/mojo/public/tools/dart_analyze.py b/third_party/mojo/src/mojo/public/tools/dart_analyze.py index cb80804bad44..b90cbef558dd 100755 --- a/third_party/mojo/src/mojo/public/tools/dart_analyze.py +++ b/third_party/mojo/src/mojo/public/tools/dart_analyze.py @@ -29,6 +29,8 @@ _IGNORED_PATTERNS = [ # TODO: It seems like this should be re-enabled evenutally. re.compile(r'.*is a part and can not|^Only libraries can be analyzed'), + # TODO: Remove this once dev SDK includes Uri.directory constructor. + re.compile(r'.*The class \'Uri\' does not have a constructor \'directory\''), ] def _success(stamp_file): -- 2.11.4.GIT