summaryrefslogtreecommitdiff
path: root/chromium/mojo
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/mojo
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-c30a6232df03e1efbd9f3b226777b07e087a1122.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/mojo')
-rw-r--r--chromium/mojo/core/BUILD.gn11
-rw-r--r--chromium/mojo/core/atomic_flag.h2
-rw-r--r--chromium/mojo/core/broker_win.cc3
-rw-r--r--chromium/mojo/core/channel.cc3
-rw-r--r--chromium/mojo/core/channel.h2
-rw-r--r--chromium/mojo/core/channel_fuchsia.cc11
-rw-r--r--chromium/mojo/core/channel_posix.cc4
-rw-r--r--chromium/mojo/core/channel_unittest.cc4
-rw-r--r--chromium/mojo/core/channel_win.cc3
-rw-r--r--chromium/mojo/core/core.cc27
-rw-r--r--chromium/mojo/core/core.h6
-rw-r--r--chromium/mojo/core/core_test_base.cc6
-rw-r--r--chromium/mojo/core/data_pipe_consumer_dispatcher.cc2
-rw-r--r--chromium/mojo/core/data_pipe_control_message.cc1
-rw-r--r--chromium/mojo/core/data_pipe_producer_dispatcher.cc2
-rw-r--r--chromium/mojo/core/dispatcher.cc8
-rw-r--r--chromium/mojo/core/embedder/embedder.cc8
-rw-r--r--chromium/mojo/core/embedder/embedder.h16
-rw-r--r--chromium/mojo/core/embedder/scoped_ipc_support.h2
-rw-r--r--chromium/mojo/core/entrypoints.cc9
-rw-r--r--chromium/mojo/core/handle_table.cc8
-rw-r--r--chromium/mojo/core/handle_table_unittest.cc4
-rw-r--r--chromium/mojo/core/message_pipe_dispatcher.cc17
-rw-r--r--chromium/mojo/core/message_unittest.cc2
-rw-r--r--chromium/mojo/core/mojo_core.cc102
-rw-r--r--chromium/mojo/core/mojo_core_unittest.cc37
-rw-r--r--chromium/mojo/core/mojo_core_unittest.h21
-rw-r--r--chromium/mojo/core/node_channel.cc19
-rw-r--r--chromium/mojo/core/node_channel.h20
-rw-r--r--chromium/mojo/core/node_channel_fuzzer.cc57
-rw-r--r--chromium/mojo/core/node_channel_unittest.cc72
-rw-r--r--chromium/mojo/core/node_controller.cc2
-rw-r--r--chromium/mojo/core/node_controller.h2
-rw-r--r--chromium/mojo/core/options_validation.h2
-rw-r--r--chromium/mojo/core/platform_shared_memory_mapping.h1
-rw-r--r--chromium/mojo/core/ports/message_filter.h2
-rw-r--r--chromium/mojo/core/ports/node.cc3
-rw-r--r--chromium/mojo/core/ports/node_delegate.h2
-rw-r--r--chromium/mojo/core/ports/port.cc2
-rw-r--r--chromium/mojo/core/ports/port_ref.cc4
-rw-r--r--chromium/mojo/core/ports/port_ref.h1
-rw-r--r--chromium/mojo/core/ports/ports_unittest.cc4
-rw-r--r--chromium/mojo/core/ports/user_data.h2
-rw-r--r--chromium/mojo/core/request_context.cc2
-rw-r--r--chromium/mojo/core/run_all_core_unittests.cc47
-rw-r--r--chromium/mojo/core/shared_buffer_dispatcher_unittest.cc4
-rw-r--r--chromium/mojo/core/test/BUILD.gn4
-rw-r--r--chromium/mojo/core/test_utils.cc4
-rw-r--r--chromium/mojo/core/trap_unittest.cc8
-rw-r--r--chromium/mojo/core/watch.cc2
-rw-r--r--chromium/mojo/docs/mojolpm.md471
-rw-r--r--chromium/mojo/public/c/system/functions.h18
-rw-r--r--chromium/mojo/public/c/system/invitation.h50
-rw-r--r--chromium/mojo/public/c/system/macros.h13
-rw-r--r--chromium/mojo/public/c/system/thunks.cc92
-rw-r--r--chromium/mojo/public/c/system/thunks.h5
-rw-r--r--chromium/mojo/public/c/system/types.h44
-rw-r--r--chromium/mojo/public/cpp/base/big_buffer.cc4
-rw-r--r--chromium/mojo/public/cpp/bindings/README.md14
-rw-r--r--chromium/mojo/public/cpp/bindings/associated_binding.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/associated_group_controller.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/associated_interface_ptr.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/associated_receiver.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/associated_remote.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/binding.h7
-rw-r--r--chromium/mojo/public/cpp/bindings/connector.h8
-rw-r--r--chromium/mojo/public/cpp/bindings/interface_endpoint_client.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/interface_id.h8
-rw-r--r--chromium/mojo/public/cpp/bindings/interface_ptr.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/interface_request.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/array_internal.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/binding_state.cc8
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/binding_state.h5
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/connector.cc30
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.cc2
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.h4
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/message.cc8
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/message_header_validator.cc2
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/message_quota_checker.h8
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc14
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/multiplex_router.h23
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/native_enum_serialization.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc6
-rw-r--r--chromium/mojo/public/cpp/bindings/map_data_view.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/message.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/pending_remote.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/receiver.h4
-rw-r--r--chromium/mojo/public/cpp/bindings/remote.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/strong_associated_binding.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/strong_associated_binding_set.h25
-rw-r--r--chromium/mojo/public/cpp/bindings/strong_binding.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/struct_ptr.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/sync_call_restrictions.h9
-rw-r--r--chromium/mojo/public/cpp/bindings/sync_handle_watcher.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/tests/BUILD.gn6
-rw-r--r--chromium/mojo/public/cpp/platform/platform_channel.cc6
-rw-r--r--chromium/mojo/public/cpp/platform/platform_channel.h4
-rw-r--r--chromium/mojo/public/cpp/platform/platform_handle.h2
-rw-r--r--chromium/mojo/public/cpp/platform/socket_utils_posix.cc1
-rw-r--r--chromium/mojo/public/cpp/platform/socket_utils_posix.h1
-rw-r--r--chromium/mojo/public/cpp/system/BUILD.gn3
-rw-r--r--chromium/mojo/public/cpp/system/buffer.h2
-rw-r--r--chromium/mojo/public/cpp/system/data_pipe.h2
-rw-r--r--chromium/mojo/public/cpp/system/data_pipe_producer.cc9
-rw-r--r--chromium/mojo/public/cpp/system/dynamic_library_support.cc64
-rw-r--r--chromium/mojo/public/cpp/system/dynamic_library_support.h45
-rw-r--r--chromium/mojo/public/cpp/system/functions.cc36
-rw-r--r--chromium/mojo/public/cpp/system/functions.h15
-rw-r--r--chromium/mojo/public/cpp/system/handle.h2
-rw-r--r--chromium/mojo/public/cpp/system/message_pipe.h2
-rw-r--r--chromium/mojo/public/cpp/system/platform_handle.h1
-rw-r--r--chromium/mojo/public/cpp/test_support/BUILD.gn1
-rw-r--r--chromium/mojo/public/cpp/test_support/lib/test_utils.cc7
-rw-r--r--chromium/mojo/public/interfaces/bindings/pipe_control_messages.mojom2
-rw-r--r--chromium/mojo/public/interfaces/bindings/tests/BUILD.gn4
-rw-r--r--chromium/mojo/public/interfaces/bindings/tests/test_sync_methods.mojom2
-rw-r--r--chromium/mojo/public/js/BUILD.gn2
-rw-r--r--chromium/mojo/public/js/bindings.js6
-rw-r--r--chromium/mojo/public/js/interface_types.js10
-rw-r--r--chromium/mojo/public/js/lib/router.js6
-rw-r--r--chromium/mojo/public/js/lib/validator.js2
-rw-r--r--chromium/mojo/public/js/test/BUILD.gn2
-rw-r--r--chromium/mojo/public/js/ts/bindings/tests/BUILD.gn7
-rw-r--r--chromium/mojo/public/mojom/base/BUILD.gn29
-rw-r--r--chromium/mojo/public/mojom/base/binder.mojom18
-rw-r--r--chromium/mojo/public/mojom/base/generic_pending_receiver.mojom14
-rw-r--r--chromium/mojo/public/mojom/base/string16.mojom5
-rw-r--r--chromium/mojo/public/mojom/base/time.mojom1
-rw-r--r--chromium/mojo/public/tools/bindings/README.md11
-rw-r--r--chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni1
-rw-r--r--chromium/mojo/public/tools/bindings/compile_typescript.py21
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl7
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/module-params-data.h.tmpl1
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl1
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl1
-rw-r--r--chromium/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl12
-rw-r--r--chromium/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl8
-rw-r--r--chromium/mojo/public/tools/bindings/generators/js_templates/lite/enum_definition.tmpl13
-rw-r--r--chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.cc.tmpl841
-rw-r--r--chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.h.tmpl251
-rw-r--r--chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.proto.tmpl406
-rw-r--r--chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_from_proto_macros.tmpl383
-rw-r--r--chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_macros.tmpl82
-rw-r--r--chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_to_proto_macros.tmpl360
-rw-r--r--chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_traits_specialization_macros.tmpl96
-rw-r--r--chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py60
-rw-r--r--chromium/mojo/public/tools/bindings/generators/mojom_mojolpm_generator.py517
-rw-r--r--chromium/mojo/public/tools/bindings/generators/mojom_ts_generator.py78
-rw-r--r--chromium/mojo/public/tools/bindings/generators/ts_templates/module_definition.tmpl21
-rw-r--r--chromium/mojo/public/tools/bindings/generators/ts_templates/mojom.tmpl11
-rw-r--r--chromium/mojo/public/tools/bindings/mojom.gni340
-rwxr-xr-xchromium/mojo/public/tools/bindings/mojom_bindings_generator.py21
-rw-r--r--chromium/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py39
-rw-r--r--chromium/mojo/public/tools/fuzzers/mojolpm.gni144
-rwxr-xr-xchromium/mojo/public/tools/mojom/check_stable_mojom_compatibility.py170
-rwxr-xr-xchromium/mojo/public/tools/mojom/check_stable_mojom_compatibility_unittest.py260
-rw-r--r--chromium/mojo/public/tools/mojom/const_unittest.py90
-rw-r--r--chromium/mojo/public/tools/mojom/enum_unittest.py92
-rw-r--r--chromium/mojo/public/tools/mojom/mojom/generate/generator.py33
-rw-r--r--chromium/mojo/public/tools/mojom/mojom/generate/module.py291
-rw-r--r--chromium/mojo/public/tools/mojom/mojom/generate/translate.py328
-rw-r--r--chromium/mojo/public/tools/mojom/mojom/parse/ast.py36
-rw-r--r--chromium/mojo/public/tools/mojom/mojom/parse/parser.py2
-rwxr-xr-xchromium/mojo/public/tools/mojom/mojom_parser.py3
-rw-r--r--chromium/mojo/public/tools/mojom/mojom_parser_test_case.py73
-rw-r--r--[-rwxr-xr-x]chromium/mojo/public/tools/mojom/mojom_parser_unittest.py56
-rw-r--r--chromium/mojo/public/tools/mojom/stable_attribute_unittest.py127
-rw-r--r--chromium/mojo/public/tools/mojom/version_compatibility_unittest.py397
169 files changed, 6702 insertions, 808 deletions
diff --git a/chromium/mojo/core/BUILD.gn b/chromium/mojo/core/BUILD.gn
index e6fcb96256f..c42daf24d62 100644
--- a/chromium/mojo/core/BUILD.gn
+++ b/chromium/mojo/core/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/compiler/compiler.gni")
import("//build/config/nacl/config.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
@@ -18,6 +19,7 @@ component("embedder_internal") {
":test_sources",
"//mojo:*",
"//mojo/core/embedder",
+ "//mojo/core/test:test_support",
]
}
@@ -57,6 +59,7 @@ template("core_impl_source_set") {
"handle_table.h",
"invitation_dispatcher.h",
"message_pipe_dispatcher.h",
+ "node_channel.h",
"node_controller.h",
"options_validation.h",
"platform_handle_dispatcher.h",
@@ -86,7 +89,6 @@ template("core_impl_source_set") {
"invitation_dispatcher.cc",
"message_pipe_dispatcher.cc",
"node_channel.cc",
- "node_channel.h",
"node_controller.cc",
"platform_handle_dispatcher.cc",
"platform_handle_in_transit.cc",
@@ -160,7 +162,8 @@ template("core_impl_source_set") {
# Use target_os == "chromeos" instead of is_chromeos because we need to
# build NaCl targets (i.e. IRT) for ChromeOS the same as the rest of ChromeOS.
- if (is_android || target_os == "chromeos") {
+ if (is_android || target_os == "chromeos" ||
+ (target_os == "linux" && chromeos_is_browser_only)) {
defines += [ "MOJO_CORE_LEGACY_PROTOCOL" ]
}
@@ -187,6 +190,7 @@ if (is_chromeos || is_linux || is_android || is_win) {
defines = [ "MOJO_CORE_SHARED_LIBRARY" ]
deps = [
":impl_for_shared_library",
+ "//base:base_static",
"//mojo/public/c/system:headers",
]
if (is_win) {
@@ -240,6 +244,7 @@ if (is_chromeos || is_linux || is_android || is_win) {
test("mojo_core_unittests") {
sources = [
"mojo_core_unittest.cc",
+ "mojo_core_unittest.h",
"run_all_core_unittests.cc",
]
@@ -289,6 +294,7 @@ source_set("test_sources") {
"handle_table_unittest.cc",
"message_pipe_unittest.cc",
"message_unittest.cc",
+ "node_channel_unittest.cc",
"options_validation_unittest.cc",
"platform_handle_dispatcher_unittest.cc",
"quota_unittest.cc",
@@ -387,6 +393,7 @@ fuzzer_test("mojo_core_node_channel_fuzzer") {
deps = [
":core_impl_for_fuzzers",
"//base",
+ "//mojo/core/test:test_support",
"//mojo/public/cpp/platform",
]
}
diff --git a/chromium/mojo/core/atomic_flag.h b/chromium/mojo/core/atomic_flag.h
index 075b837ab1b..aec7f4ee65b 100644
--- a/chromium/mojo/core/atomic_flag.h
+++ b/chromium/mojo/core/atomic_flag.h
@@ -33,7 +33,7 @@ namespace core {
class AtomicFlag {
public:
AtomicFlag() : flag_(0) {}
- ~AtomicFlag() {}
+ ~AtomicFlag() = default;
void Set(bool value) { base::subtle::Release_Store(&flag_, value ? 1 : 0); }
diff --git a/chromium/mojo/core/broker_win.cc b/chromium/mojo/core/broker_win.cc
index e81bfd301cd..f734b6b6f55 100644
--- a/chromium/mojo/core/broker_win.cc
+++ b/chromium/mojo/core/broker_win.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/debug/alias.h"
+#include "base/logging.h"
#include "base/memory/platform_shared_memory_region.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_piece.h"
@@ -118,7 +119,7 @@ Broker::Broker(PlatformHandle handle, bool wait_for_channel_handle)
}
}
-Broker::~Broker() {}
+Broker::~Broker() = default;
PlatformChannelEndpoint Broker::GetInviterEndpoint() {
return std::move(inviter_endpoint_);
diff --git a/chromium/mojo/core/channel.cc b/chromium/mojo/core/channel.cc
index 38cbaea5c99..5d855891e2e 100644
--- a/chromium/mojo/core/channel.cc
+++ b/chromium/mojo/core/channel.cc
@@ -11,6 +11,7 @@
#include <limits>
#include <utility>
+#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/aligned_memory.h"
#include "base/memory/ptr_util.h"
@@ -577,7 +578,7 @@ Channel::Channel(Delegate* delegate,
? new ReadBuffer
: nullptr) {}
-Channel::~Channel() {}
+Channel::~Channel() = default;
void Channel::ShutDown() {
ShutDownImpl();
diff --git a/chromium/mojo/core/channel.h b/chromium/mojo/core/channel.h
index 62447f8756d..a639c53c452 100644
--- a/chromium/mojo/core/channel.h
+++ b/chromium/mojo/core/channel.h
@@ -252,7 +252,7 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel
// was created (see Channel::Create).
class Delegate {
public:
- virtual ~Delegate() {}
+ virtual ~Delegate() = default;
// Notify of a received message. |payload| is not owned and must not be
// retained; it will be null if |payload_size| is 0. |handles| are
diff --git a/chromium/mojo/core/channel_fuchsia.cc b/chromium/mojo/core/channel_fuchsia.cc
index 8ca10557d8d..2d818ac6804 100644
--- a/chromium/mojo/core/channel_fuchsia.cc
+++ b/chromium/mojo/core/channel_fuchsia.cc
@@ -99,16 +99,11 @@ class MessageView {
DCHECK_GT(message_->data_num_bytes(), offset_);
}
- MessageView(MessageView&& other) { *this = std::move(other); }
+ MessageView(MessageView&& other) = default;
- MessageView& operator=(MessageView&& other) {
- message_ = std::move(other.message_);
- offset_ = other.offset_;
- handles_ = std::move(other.handles_);
- return *this;
- }
+ MessageView& operator=(MessageView&& other) = default;
- ~MessageView() {}
+ ~MessageView() = default;
const void* data() const {
return static_cast<const char*>(message_->data()) + offset_;
diff --git a/chromium/mojo/core/channel_posix.cc b/chromium/mojo/core/channel_posix.cc
index 7b52b42f230..fb7c190b50a 100644
--- a/chromium/mojo/core/channel_posix.cc
+++ b/chromium/mojo/core/channel_posix.cc
@@ -47,11 +47,11 @@ class MessageView {
DCHECK(!message_->data_num_bytes() || message_->data_num_bytes() > offset_);
}
- MessageView(MessageView&& other) { *this = std::move(other); }
+ MessageView(MessageView&& other) = default;
MessageView& operator=(MessageView&& other) = default;
- ~MessageView() {}
+ ~MessageView() = default;
const void* data() const {
return static_cast<const char*>(message_->data()) + offset_;
diff --git a/chromium/mojo/core/channel_unittest.cc b/chromium/mojo/core/channel_unittest.cc
index a57f2a4924d..6013ce22219 100644
--- a/chromium/mojo/core/channel_unittest.cc
+++ b/chromium/mojo/core/channel_unittest.cc
@@ -56,13 +56,13 @@ class TestChannel : public Channel {
void Write(MessagePtr message) override {}
protected:
- ~TestChannel() override {}
+ ~TestChannel() override = default;
};
// Not using GMock as I don't think it supports movable types.
class MockChannelDelegate : public Channel::Delegate {
public:
- MockChannelDelegate() {}
+ MockChannelDelegate() = default;
size_t GetReceivedPayloadSize() const { return payload_size_; }
diff --git a/chromium/mojo/core/channel_win.cc b/chromium/mojo/core/channel_win.cc
index 4ea0aeb6810..3fee0f2b78c 100644
--- a/chromium/mojo/core/channel_win.cc
+++ b/chromium/mojo/core/channel_win.cc
@@ -15,6 +15,7 @@
#include "base/containers/queue.h"
#include "base/debug/activity_tracker.h"
#include "base/location.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop_current.h"
@@ -186,7 +187,7 @@ class ChannelWin : public Channel,
private:
// May run on any thread.
- ~ChannelWin() override {}
+ ~ChannelWin() override = default;
void StartOnIOThread() {
base::MessageLoopCurrent::Get()->AddDestructionObserver(this);
diff --git a/chromium/mojo/core/core.cc b/chromium/mojo/core/core.cc
index d6092658b75..6d06ab1fdee 100644
--- a/chromium/mojo/core/core.cc
+++ b/chromium/mojo/core/core.cc
@@ -153,10 +153,6 @@ scoped_refptr<Dispatcher> Core::GetAndRemoveDispatcher(MojoHandle handle) {
return dispatcher;
}
-void Core::SetDefaultProcessErrorCallback(ProcessErrorCallback callback) {
- default_process_error_callback_ = std::move(callback);
-}
-
MojoHandle Core::CreatePartialMessagePipe(ports::PortRef* peer) {
RequestContext request_context;
ports::PortRef local_port;
@@ -1477,6 +1473,29 @@ MojoResult Core::QueryQuota(MojoHandle handle,
return dispatcher->QueryQuota(type, limit, usage);
}
+MojoResult Core::SetDefaultProcessErrorHandler(
+ MojoDefaultProcessErrorHandler handler,
+ const MojoSetDefaultProcessErrorHandlerOptions* options) {
+ if (default_process_error_callback_ && handler)
+ return MOJO_RESULT_ALREADY_EXISTS;
+
+ if (!handler) {
+ default_process_error_callback_.Reset();
+ return MOJO_RESULT_OK;
+ }
+
+ default_process_error_callback_ = base::BindRepeating(
+ [](MojoDefaultProcessErrorHandler handler, const std::string& error) {
+ MojoProcessErrorDetails details = {0};
+ details.struct_size = sizeof(details);
+ details.error_message_length = static_cast<uint32_t>(error.size());
+ details.error_message = error.c_str();
+ handler(&details);
+ },
+ handler);
+ return MOJO_RESULT_OK;
+}
+
void Core::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) {
base::AutoLock lock(handles_->GetLock());
handles_->GetActiveHandlesForTest(handles);
diff --git a/chromium/mojo/core/core.h b/chromium/mojo/core/core.h
index eaed40c8650..37c8a229fcf 100644
--- a/chromium/mojo/core/core.h
+++ b/chromium/mojo/core/core.h
@@ -54,8 +54,6 @@ class MOJO_SYSTEM_IMPL_EXPORT Core {
scoped_refptr<Dispatcher> GetDispatcher(MojoHandle handle);
scoped_refptr<Dispatcher> GetAndRemoveDispatcher(MojoHandle handle);
- void SetDefaultProcessErrorCallback(ProcessErrorCallback callback);
-
// Creates a message pipe endpoint with an unbound peer port returned in
// |*peer|. Useful for setting up cross-process bootstrap message pipes. The
// returned message pipe handle is usable immediately by the caller.
@@ -325,6 +323,10 @@ class MOJO_SYSTEM_IMPL_EXPORT Core {
uint64_t* limit,
uint64_t* usage);
+ MojoResult SetDefaultProcessErrorHandler(
+ MojoDefaultProcessErrorHandler handler,
+ const MojoSetDefaultProcessErrorHandlerOptions* options);
+
void GetActiveHandlesForTest(std::vector<MojoHandle>* handles);
private:
diff --git a/chromium/mojo/core/core_test_base.cc b/chromium/mojo/core/core_test_base.cc
index 88645237567..e173d853d1a 100644
--- a/chromium/mojo/core/core_test_base.cc
+++ b/chromium/mojo/core/core_test_base.cc
@@ -105,9 +105,9 @@ class MockDispatcher : public Dispatcher {
// CoreTestBase ----------------------------------------------------------------
-CoreTestBase::CoreTestBase() {}
+CoreTestBase::CoreTestBase() = default;
-CoreTestBase::~CoreTestBase() {}
+CoreTestBase::~CoreTestBase() = default;
MojoHandle CoreTestBase::CreateMockHandle(CoreTestBase::MockHandleInfo* info) {
scoped_refptr<MockDispatcher> dispatcher = MockDispatcher::Create(info);
@@ -133,7 +133,7 @@ CoreTestBase_MockHandleInfo::CoreTestBase_MockHandleInfo()
begin_read_data_call_count_(0),
end_read_data_call_count_(0) {}
-CoreTestBase_MockHandleInfo::~CoreTestBase_MockHandleInfo() {}
+CoreTestBase_MockHandleInfo::~CoreTestBase_MockHandleInfo() = default;
unsigned CoreTestBase_MockHandleInfo::GetCtorCallCount() const {
base::AutoLock locker(lock_);
diff --git a/chromium/mojo/core/data_pipe_consumer_dispatcher.cc b/chromium/mojo/core/data_pipe_consumer_dispatcher.cc
index 979a222c104..4cf36093574 100644
--- a/chromium/mojo/core/data_pipe_consumer_dispatcher.cc
+++ b/chromium/mojo/core/data_pipe_consumer_dispatcher.cc
@@ -59,7 +59,7 @@ class DataPipeConsumerDispatcher::PortObserverThunk
: dispatcher_(dispatcher) {}
private:
- ~PortObserverThunk() override {}
+ ~PortObserverThunk() override = default;
// NodeController::PortObserver:
void OnPortStatusChanged() override { dispatcher_->OnPortStatusChanged(); }
diff --git a/chromium/mojo/core/data_pipe_control_message.cc b/chromium/mojo/core/data_pipe_control_message.cc
index cd782e5bc12..d59676ff0ef 100644
--- a/chromium/mojo/core/data_pipe_control_message.cc
+++ b/chromium/mojo/core/data_pipe_control_message.cc
@@ -4,6 +4,7 @@
#include "mojo/core/data_pipe_control_message.h"
+#include "base/logging.h"
#include "mojo/core/node_controller.h"
#include "mojo/core/ports/event.h"
#include "mojo/core/user_message_impl.h"
diff --git a/chromium/mojo/core/data_pipe_producer_dispatcher.cc b/chromium/mojo/core/data_pipe_producer_dispatcher.cc
index 4c0473d0b2f..cebe8dda57d 100644
--- a/chromium/mojo/core/data_pipe_producer_dispatcher.cc
+++ b/chromium/mojo/core/data_pipe_producer_dispatcher.cc
@@ -58,7 +58,7 @@ class DataPipeProducerDispatcher::PortObserverThunk
: dispatcher_(dispatcher) {}
private:
- ~PortObserverThunk() override {}
+ ~PortObserverThunk() override = default;
// NodeController::PortObserver:
void OnPortStatusChanged() override { dispatcher_->OnPortStatusChanged(); }
diff --git a/chromium/mojo/core/dispatcher.cc b/chromium/mojo/core/dispatcher.cc
index a110dbdc8e4..25959441808 100644
--- a/chromium/mojo/core/dispatcher.cc
+++ b/chromium/mojo/core/dispatcher.cc
@@ -16,12 +16,12 @@
namespace mojo {
namespace core {
-Dispatcher::DispatcherInTransit::DispatcherInTransit() {}
+Dispatcher::DispatcherInTransit::DispatcherInTransit() = default;
Dispatcher::DispatcherInTransit::DispatcherInTransit(
const DispatcherInTransit& other) = default;
-Dispatcher::DispatcherInTransit::~DispatcherInTransit() {}
+Dispatcher::DispatcherInTransit::~DispatcherInTransit() = default;
MojoResult Dispatcher::WatchDispatcher(scoped_refptr<Dispatcher> dispatcher,
MojoHandleSignals signals,
@@ -190,9 +190,9 @@ scoped_refptr<Dispatcher> Dispatcher::Deserialize(
}
}
-Dispatcher::Dispatcher() {}
+Dispatcher::Dispatcher() = default;
-Dispatcher::~Dispatcher() {}
+Dispatcher::~Dispatcher() = default;
} // namespace core
} // namespace mojo
diff --git a/chromium/mojo/core/embedder/embedder.cc b/chromium/mojo/core/embedder/embedder.cc
index 8b9d331ad5b..3a4e3172938 100644
--- a/chromium/mojo/core/embedder/embedder.cc
+++ b/chromium/mojo/core/embedder/embedder.cc
@@ -7,10 +7,8 @@
#include <stdint.h>
#include <utility>
-#include "base/bind.h"
#include "base/memory/ref_counted.h"
#include "base/task_runner.h"
-#include "build/build_config.h"
#include "mojo/core/configuration.h"
#include "mojo/core/core.h"
#include "mojo/core/entrypoints.h"
@@ -30,11 +28,7 @@ void Init() {
Init(Configuration());
}
-void SetDefaultProcessErrorCallback(ProcessErrorCallback callback) {
- Core::Get()->SetDefaultProcessErrorCallback(std::move(callback));
-}
-
-scoped_refptr<base::TaskRunner> GetIOTaskRunner() {
+scoped_refptr<base::SingleThreadTaskRunner> GetIOTaskRunner() {
return Core::Get()->GetNodeController()->io_task_runner();
}
diff --git a/chromium/mojo/core/embedder/embedder.h b/chromium/mojo/core/embedder/embedder.h
index 5d654009877..575b301468d 100644
--- a/chromium/mojo/core/embedder/embedder.h
+++ b/chromium/mojo/core/embedder/embedder.h
@@ -9,20 +9,16 @@
#include <string>
-#include "base/callback.h"
#include "base/component_export.h"
#include "base/memory/ref_counted.h"
#include "base/process/process_handle.h"
-#include "base/task_runner.h"
+#include "base/single_thread_task_runner.h"
#include "build/build_config.h"
#include "mojo/core/embedder/configuration.h"
namespace mojo {
namespace core {
-using ProcessErrorCallback =
- base::RepeatingCallback<void(const std::string& error)>;
-
// Basic configuration/initialization ------------------------------------------
// Must be called first, or just after setting configuration parameters, to
@@ -35,16 +31,12 @@ void Init(const Configuration& configuration);
// Like above but uses a default Configuration.
COMPONENT_EXPORT(MOJO_CORE_EMBEDDER) void Init();
-// Sets a default callback to invoke when an internal error is reported but
-// cannot be associated with a specific child process. Calling this is optional.
-COMPONENT_EXPORT(MOJO_CORE_EMBEDDER)
-void SetDefaultProcessErrorCallback(ProcessErrorCallback callback);
-
// Initialialization/shutdown for interprocess communication (IPC) -------------
-// Retrieves the TaskRunner used for IPC I/O, as set by ScopedIPCSupport.
+// Retrieves the SequencedTaskRunner used for IPC I/O, as set by
+// ScopedIPCSupport.
COMPONENT_EXPORT(MOJO_CORE_EMBEDDER)
-scoped_refptr<base::TaskRunner> GetIOTaskRunner();
+scoped_refptr<base::SingleThreadTaskRunner> GetIOTaskRunner();
} // namespace core
} // namespace mojo
diff --git a/chromium/mojo/core/embedder/scoped_ipc_support.h b/chromium/mojo/core/embedder/scoped_ipc_support.h
index aba6e712ad8..ff603294702 100644
--- a/chromium/mojo/core/embedder/scoped_ipc_support.h
+++ b/chromium/mojo/core/embedder/scoped_ipc_support.h
@@ -86,7 +86,7 @@ class COMPONENT_EXPORT(MOJO_CORE_EMBEDDER) ScopedIPCSupport {
//
// There are other practical scenarios where fast shutdown is safe even if
// the process may have live proxies. For example, content's browser process
- // is treated as a sort of master process in the system, in the sense that if
+ // is treated as a sort of root process in the system, in the sense that if
// the browser is terminated, no other part of the system is expected to
// continue normal operation anyway. In this case the side-effects of fast
// shutdown are irrelevant, so fast shutdown is preferred.
diff --git a/chromium/mojo/core/entrypoints.cc b/chromium/mojo/core/entrypoints.cc
index 466da7e08a5..7b342a516f5 100644
--- a/chromium/mojo/core/entrypoints.cc
+++ b/chromium/mojo/core/entrypoints.cc
@@ -350,6 +350,12 @@ MojoResult MojoShutdownImpl(const MojoShutdownOptions* options) {
return MOJO_RESULT_UNIMPLEMENTED;
}
+MojoResult MojoSetDefaultProcessErrorHandlerImpl(
+ MojoDefaultProcessErrorHandler handler,
+ const MojoSetDefaultProcessErrorHandlerOptions* options) {
+ return g_core->SetDefaultProcessErrorHandler(handler, options);
+}
+
} // extern "C"
MojoSystemThunks g_thunks = {sizeof(MojoSystemThunks),
@@ -396,7 +402,8 @@ MojoSystemThunks g_thunks = {sizeof(MojoSystemThunks),
MojoAcceptInvitationImpl,
MojoSetQuotaImpl,
MojoQueryQuotaImpl,
- MojoShutdownImpl};
+ MojoShutdownImpl,
+ MojoSetDefaultProcessErrorHandlerImpl};
} // namespace
diff --git a/chromium/mojo/core/handle_table.cc b/chromium/mojo/core/handle_table.cc
index 62419a92363..9426281d73f 100644
--- a/chromium/mojo/core/handle_table.cc
+++ b/chromium/mojo/core/handle_table.cc
@@ -40,9 +40,9 @@ const char* GetNameForDispatcherType(Dispatcher::Type type) {
} // namespace
-HandleTable::HandleTable() {}
+HandleTable::HandleTable() = default;
-HandleTable::~HandleTable() {}
+HandleTable::~HandleTable() = default;
base::Lock& HandleTable::GetLock() {
return lock_;
@@ -191,14 +191,14 @@ bool HandleTable::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
return true;
}
-HandleTable::Entry::Entry() {}
+HandleTable::Entry::Entry() = default;
HandleTable::Entry::Entry(scoped_refptr<Dispatcher> dispatcher)
: dispatcher(std::move(dispatcher)) {}
HandleTable::Entry::Entry(const Entry& other) = default;
-HandleTable::Entry::~Entry() {}
+HandleTable::Entry::~Entry() = default;
} // namespace core
} // namespace mojo
diff --git a/chromium/mojo/core/handle_table_unittest.cc b/chromium/mojo/core/handle_table_unittest.cc
index 910b14e76cf..0724fb09474 100644
--- a/chromium/mojo/core/handle_table_unittest.cc
+++ b/chromium/mojo/core/handle_table_unittest.cc
@@ -27,14 +27,14 @@ namespace {
class FakeMessagePipeDispatcher : public Dispatcher {
public:
- FakeMessagePipeDispatcher() {}
+ FakeMessagePipeDispatcher() = default;
Type GetType() const override { return Type::MESSAGE_PIPE; }
MojoResult Close() override { return MOJO_RESULT_OK; }
private:
- ~FakeMessagePipeDispatcher() override {}
+ ~FakeMessagePipeDispatcher() override = default;
DISALLOW_COPY_AND_ASSIGN(FakeMessagePipeDispatcher);
};
diff --git a/chromium/mojo/core/message_pipe_dispatcher.cc b/chromium/mojo/core/message_pipe_dispatcher.cc
index 22ac04acc5f..e17fdabc2d3 100644
--- a/chromium/mojo/core/message_pipe_dispatcher.cc
+++ b/chromium/mojo/core/message_pipe_dispatcher.cc
@@ -47,7 +47,7 @@ class MessagePipeDispatcher::PortObserverThunk
: dispatcher_(dispatcher) {}
private:
- ~PortObserverThunk() override {}
+ ~PortObserverThunk() override = default;
// NodeController::PortObserver:
void OnPortStatusChanged() override { dispatcher_->OnPortStatusChanged(); }
@@ -63,8 +63,8 @@ class MessagePipeDispatcher::PortObserverThunk
// the next available message on a port, for debug logging only.
class PeekSizeMessageFilter : public ports::MessageFilter {
public:
- PeekSizeMessageFilter() {}
- ~PeekSizeMessageFilter() override {}
+ PeekSizeMessageFilter() = default;
+ ~PeekSizeMessageFilter() override = default;
// ports::MessageFilter:
bool Match(const ports::UserMessageEvent& message_event) override {
@@ -380,9 +380,8 @@ MojoResult MessagePipeDispatcher::CloseNoLock() {
base::AutoUnlock unlock(signal_lock_);
node_controller_->ClosePort(port_);
- TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
- "MessagePipe closing", pipe_id_ + endpoint_,
- TRACE_EVENT_FLAG_FLOW_OUT);
+ TRACE_EVENT_WITH_FLOW0("toplevel.flow", "MessagePipe closing",
+ pipe_id_ + endpoint_, TRACE_EVENT_FLAG_FLOW_OUT);
}
return MOJO_RESULT_OK;
@@ -433,9 +432,9 @@ HandleSignalsState MessagePipeDispatcher::GetHandleSignalsStateNoLock() const {
rv.satisfied_signals & MOJO_HANDLE_SIGNAL_PEER_CLOSED;
last_known_satisfied_signals_ = rv.satisfied_signals;
if (is_peer_closed && !was_peer_closed) {
- TRACE_EVENT_WITH_FLOW0(
- TRACE_DISABLED_BY_DEFAULT("toplevel.flow"), "MessagePipe peer closed",
- pipe_id_ + (1 - endpoint_), TRACE_EVENT_FLAG_FLOW_IN);
+ TRACE_EVENT_WITH_FLOW0("toplevel.flow", "MessagePipe peer closed",
+ pipe_id_ + (1 - endpoint_),
+ TRACE_EVENT_FLAG_FLOW_IN);
}
return rv;
diff --git a/chromium/mojo/core/message_unittest.cc b/chromium/mojo/core/message_unittest.cc
index c079e1106c6..cb0747c09ea 100644
--- a/chromium/mojo/core/message_unittest.cc
+++ b/chromium/mojo/core/message_unittest.cc
@@ -30,7 +30,7 @@ using MessageTest = test::MojoTestBase;
// handles.
class TestMessageBase {
public:
- virtual ~TestMessageBase() {}
+ virtual ~TestMessageBase() = default;
static MojoMessageHandle MakeMessageHandle(
std::unique_ptr<TestMessageBase> message) {
diff --git a/chromium/mojo/core/mojo_core.cc b/chromium/mojo/core/mojo_core.cc
index 7d28bcfdddd..2261a8a9adb 100644
--- a/chromium/mojo/core/mojo_core.cc
+++ b/chromium/mojo/core/mojo_core.cc
@@ -5,17 +5,25 @@
#include <stddef.h>
#include "base/at_exit.h"
+#include "base/base_switches.h"
#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/debug/stack_trace.h"
+#include "base/feature_list.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/message_loop/message_pump_type.h"
#include "base/no_destructor.h"
+#include "base/rand_util.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "mojo/core/configuration.h"
#include "mojo/core/core.h"
#include "mojo/core/entrypoints.h"
#include "mojo/public/c/system/core.h"
+#include "mojo/public/c/system/macros.h"
#include "mojo/public/c/system/thunks.h"
namespace {
@@ -56,6 +64,62 @@ std::unique_ptr<IPCSupport>& GetIPCSupport() {
return *state;
}
+// This helper is only called from within the context of a newly loaded Mojo
+// Core shared library, where various bits of static state (e.g. //base globals)
+// will not yet be initialized. Base library initialization steps are thus
+// consolidated here so that base APIs work as expected from within the loaded
+// Mojo Core implementation.
+//
+// NOTE: This is a no-op in component builds, as we expect both the client
+// application and the Mojo Core library to have been linked against the same
+// base component library, and we furthermore expect that the client application
+// has already initialized base globals by this point.
+class GlobalStateInitializer {
+ public:
+ GlobalStateInitializer() = default;
+
+ bool Initialize(int argc, const char* const* argv) {
+ if (initialized_)
+ return false;
+ initialized_ = true;
+#if !defined(COMPONENT_BUILD)
+ base::CommandLine::Init(argc, argv);
+
+ logging::LoggingSettings settings;
+ settings.logging_dest =
+ logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR;
+ logging::InitLogging(settings);
+ logging::SetLogItems(true, // Process ID
+ true, // Thread ID
+ true, // Timestamp
+ true); // Tick count
+
+#if !defined(OFFICIAL_BUILD) && !defined(OS_WIN)
+ // Correct stack dumping behavior requires symbol names in all loaded
+ // libraries to be cached. We do this here in case the calling process will
+ // imminently enter a sandbox.
+ base::debug::EnableInProcessStackDumping();
+#endif
+
+#if defined(OS_POSIX)
+ // Tickle base's PRNG. This lazily opens a static handle to /dev/urandom.
+ // Mojo Core uses the API internally, so it's important to warm the handle
+ // before potentially entering a sandbox.
+ base::RandUint64();
+#endif
+
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ base::FeatureList::InitializeInstance(
+ command_line->GetSwitchValueASCII(switches::kEnableFeatures),
+ command_line->GetSwitchValueASCII(switches::kDisableFeatures));
+#endif // !defined(COMPONENT_BUILD)
+ return true;
+ }
+
+ private:
+ bool initialized_ = false;
+};
+
} // namespace
extern "C" {
@@ -63,13 +127,47 @@ extern "C" {
namespace {
MojoResult InitializeImpl(const struct MojoInitializeOptions* options) {
+ std::unique_ptr<IPCSupport>& ipc_support = GetIPCSupport();
+ if (ipc_support) {
+ // Already fully initialized, so there's nothing to do.
+ return MOJO_RESULT_FAILED_PRECONDITION;
+ }
+
+ // NOTE: |MojoInitialize()| may be called more than once if the caller wishes
+ // to separate basic initialization from IPC support initialization. We only
+ // do basic initialization the first time this is called.
+ const bool should_initialize_ipc_support =
+ !options || ((options->flags & MOJO_INITIALIZE_FLAG_LOAD_ONLY) == 0);
+
+ int argc = 0;
+ const char* const* argv = nullptr;
+ if (options && MOJO_IS_STRUCT_FIELD_PRESENT(options, argv)) {
+ argc = options->argc;
+ argv = options->argv;
+ }
+
+ static base::NoDestructor<GlobalStateInitializer> global_state_initializer;
+ const bool was_global_state_already_initialized =
+ !global_state_initializer->Initialize(argc, argv);
+
+ if (!should_initialize_ipc_support) {
+ if (was_global_state_already_initialized)
+ return MOJO_RESULT_ALREADY_EXISTS;
+ else
+ return MOJO_RESULT_OK;
+ }
+
+ DCHECK(!mojo::core::Core::Get());
mojo::core::Configuration config;
config.is_broker_process =
options && options->flags & MOJO_INITIALIZE_FLAG_AS_BROKER;
+ config.force_direct_shared_memory_allocation =
+ options && options->flags &
+ MOJO_INITIALIZE_FLAG_FORCE_DIRECT_SHARED_MEMORY_ALLOCATION;
mojo::core::internal::g_configuration = config;
-
mojo::core::InitializeCore();
- GetIPCSupport() = std::make_unique<IPCSupport>();
+ ipc_support = std::make_unique<IPCSupport>();
+
return MOJO_RESULT_OK;
}
diff --git a/chromium/mojo/core/mojo_core_unittest.cc b/chromium/mojo/core/mojo_core_unittest.cc
index a6f07022b75..e97172c71f9 100644
--- a/chromium/mojo/core/mojo_core_unittest.cc
+++ b/chromium/mojo/core/mojo_core_unittest.cc
@@ -4,12 +4,14 @@
#include <stdint.h>
+#include <tuple>
#include <vector>
#include "base/command_line.h"
#include "base/process/launch.h"
#include "base/test/multiprocess_test.h"
#include "base/test/test_timeouts.h"
+#include "mojo/core/mojo_core_unittest.h"
#include "mojo/public/c/system/core.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/platform/platform_handle.h"
@@ -19,6 +21,11 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
+namespace switches {
+const char kMojoLoadBeforeInit[] = "mojo-load-before-init";
+const char kMojoUseExplicitLibraryPath[] = "mojo-use-explicit-library-path";
+} // namespace switches
+
namespace {
// TODO(https://crbug.com/902135): Re-enable this on MSAN. Currently hangs
@@ -66,10 +73,27 @@ TEST(MojoCoreTest, SanityCheck) {
EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
}
-TEST(MojoCoreTest, BasicMultiprocess) {
+enum class InitializationMode { kCombinedLoadAndInit, kLoadBeforeInit };
+
+enum class LoadPathSpec { kImplicit, kExplicit };
+
+class MojoCoreMultiprocessTest
+ : public ::testing::TestWithParam<
+ std::tuple<InitializationMode, LoadPathSpec>> {
+ public:
+ void SetChildCommandLineForTestParams(base::CommandLine* command_line) {
+ if (std::get<0>(GetParam()) == InitializationMode::kLoadBeforeInit)
+ command_line->AppendSwitch(switches::kMojoLoadBeforeInit);
+ if (std::get<1>(GetParam()) == LoadPathSpec::kExplicit)
+ command_line->AppendSwitch(switches::kMojoUseExplicitLibraryPath);
+ }
+};
+
+TEST_P(MojoCoreMultiprocessTest, BasicMultiprocess) {
base::CommandLine child_cmd(base::GetMultiProcessTestChildBaseCommandLine());
- base::LaunchOptions options;
+ SetChildCommandLineForTestParams(&child_cmd);
+ base::LaunchOptions options;
mojo::PlatformChannel channel;
channel.PrepareToPassRemoteEndpoint(&options, &child_cmd);
base::Process child_process = base::SpawnMultiProcessTestChild(
@@ -108,6 +132,15 @@ MULTIPROCESS_TEST_MAIN(BasicMultiprocessClientMain) {
return 0;
}
+
+INSTANTIATE_TEST_SUITE_P(
+ ,
+ MojoCoreMultiprocessTest,
+ ::testing::Combine(
+ ::testing::Values(InitializationMode::kCombinedLoadAndInit,
+ InitializationMode::kLoadBeforeInit),
+ ::testing::Values(LoadPathSpec::kImplicit, LoadPathSpec::kExplicit)));
+
#endif // !defined(MEMORY_SANITIZER)
} // namespace
diff --git a/chromium/mojo/core/mojo_core_unittest.h b/chromium/mojo/core/mojo_core_unittest.h
new file mode 100644
index 00000000000..ee25f11da9c
--- /dev/null
+++ b/chromium/mojo/core/mojo_core_unittest.h
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium 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_CORE_MOJO_CORE_UNITTEST_H_
+#define MOJO_CORE_MOJO_CORE_UNITTEST_H_
+
+namespace switches {
+
+// Instructs the test runner to initialize the Mojo Core library in separate
+// phases. Used by a unit test when launching a subprocess, to verify the
+// correctness of phased initialization.
+extern const char kMojoLoadBeforeInit[];
+
+// Instructs the test runner to provide an explicit path to the Mojo Core shared
+// library, rather than assuming it's present in the current working directory.
+extern const char kMojoUseExplicitLibraryPath[];
+
+} // namespace switches
+
+#endif // MOJO_CORE_MOJO_CORE_UNITTEST_H_
diff --git a/chromium/mojo/core/node_channel.cc b/chromium/mojo/core/node_channel.cc
index e898b044286..061ea1026e9 100644
--- a/chromium/mojo/core/node_channel.cc
+++ b/chromium/mojo/core/node_channel.cc
@@ -228,7 +228,7 @@ void NodeChannel::NotifyBadMessage(const std::string& error) {
}
void NodeChannel::SetRemoteProcessHandle(ScopedProcessHandle process_handle) {
- DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
{
base::AutoLock lock(channel_lock_);
if (channel_)
@@ -253,7 +253,7 @@ ScopedProcessHandle NodeChannel::CloneRemoteProcessHandle() {
}
void NodeChannel::SetRemoteNodeName(const ports::NodeName& name) {
- DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
remote_node_name_ = name;
}
@@ -468,15 +468,15 @@ NodeChannel::NodeChannel(
Channel::HandlePolicy channel_handle_policy,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
const ProcessErrorCallback& process_error_callback)
- : delegate_(delegate),
- io_task_runner_(io_task_runner),
+ : base::RefCountedDeleteOnSequence<NodeChannel>(io_task_runner),
+ delegate_(delegate),
process_error_callback_(process_error_callback)
#if !defined(OS_NACL_SFI)
,
channel_(Channel::Create(this,
std::move(connection_params),
channel_handle_policy,
- io_task_runner_))
+ std::move(io_task_runner)))
#endif
{
}
@@ -499,15 +499,10 @@ void NodeChannel::CreateAndBindLocalBrokerHost(
void NodeChannel::OnChannelMessage(const void* payload,
size_t payload_size,
std::vector<PlatformHandle> handles) {
- DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
RequestContext request_context(RequestContext::Source::SYSTEM);
- // Ensure this NodeChannel stays alive through the extent of this method. The
- // delegate may have the only other reference to this object and it may choose
- // to drop it here in response to, e.g., a malformed message.
- scoped_refptr<NodeChannel> keepalive = this;
-
if (payload_size <= sizeof(Header)) {
delegate_->OnChannelError(remote_node_name_, this);
return;
@@ -739,7 +734,7 @@ void NodeChannel::OnChannelMessage(const void* payload,
}
void NodeChannel::OnChannelError(Channel::Error error) {
- DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
RequestContext request_context(RequestContext::Source::SYSTEM);
diff --git a/chromium/mojo/core/node_channel.h b/chromium/mojo/core/node_channel.h
index ea91f927049..58ab42bd01f 100644
--- a/chromium/mojo/core/node_channel.h
+++ b/chromium/mojo/core/node_channel.h
@@ -11,7 +11,7 @@
#include "base/callback.h"
#include "base/containers/queue.h"
#include "base/macros.h"
-#include "base/memory/ref_counted.h"
+#include "base/memory/ref_counted_delete_on_sequence.h"
#include "base/process/process_handle.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
@@ -21,17 +21,19 @@
#include "mojo/core/embedder/process_error_callback.h"
#include "mojo/core/ports/name.h"
#include "mojo/core/scoped_process_handle.h"
+#include "mojo/core/system_impl_export.h"
namespace mojo {
namespace core {
// Wraps a Channel to send and receive Node control messages.
-class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
- public Channel::Delegate {
+class MOJO_SYSTEM_IMPL_EXPORT NodeChannel
+ : public base::RefCountedDeleteOnSequence<NodeChannel>,
+ public Channel::Delegate {
public:
class Delegate {
public:
- virtual ~Delegate() {}
+ virtual ~Delegate() = default;
virtual void OnAcceptInvitee(const ports::NodeName& from_node,
const ports::NodeName& inviter_name,
const ports::NodeName& token) = 0;
@@ -92,8 +94,6 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
void** data,
size_t* num_data_bytes);
- Channel* channel() const { return channel_.get(); }
-
// Start receiving messages.
void Start();
@@ -155,7 +155,8 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
#endif
private:
- friend class base::RefCountedThreadSafe<NodeChannel>;
+ friend class base::RefCountedDeleteOnSequence<NodeChannel>;
+ friend class base::DeleteHelper<NodeChannel>;
using PendingMessageQueue = base::queue<Channel::MessagePtr>;
using PendingRelayMessageQueue =
@@ -181,13 +182,12 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
void WriteChannelMessage(Channel::MessagePtr message);
Delegate* const delegate_;
- const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
const ProcessErrorCallback process_error_callback_;
base::Lock channel_lock_;
- scoped_refptr<Channel> channel_;
+ scoped_refptr<Channel> channel_ GUARDED_BY(channel_lock_);
- // Must only be accessed from |io_task_runner_|'s thread.
+ // Must only be accessed from the owning task runner's thread.
ports::NodeName remote_node_name_;
base::Lock remote_process_handle_lock_;
diff --git a/chromium/mojo/core/node_channel_fuzzer.cc b/chromium/mojo/core/node_channel_fuzzer.cc
index 99047c000db..54fe757e0de 100644
--- a/chromium/mojo/core/node_channel_fuzzer.cc
+++ b/chromium/mojo/core/node_channel_fuzzer.cc
@@ -14,6 +14,7 @@
#include "mojo/core/connection_params.h"
#include "mojo/core/entrypoints.h"
#include "mojo/core/node_channel.h" // nogncheck
+#include "mojo/core/test/mock_node_channel_delegate.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#if defined(OS_WIN)
@@ -24,60 +25,6 @@ using mojo::core::Channel;
using mojo::core::ConnectionParams;
using mojo::core::ports::NodeName;
-// Implementation of NodeChannel::Delegate which does nothing. All of the
-// interesting NodeChannel control message message parsing is done by
-// NodeChannel by the time any of the delegate methods are invoked, so there's
-// no need for this to do any work.
-class FakeNodeChannelDelegate : public mojo::core::NodeChannel::Delegate {
- public:
- FakeNodeChannelDelegate() = default;
- ~FakeNodeChannelDelegate() override = default;
-
- void OnAcceptInvitee(const NodeName& from_node,
- const NodeName& inviter_name,
- const NodeName& token) override {}
- void OnAcceptInvitation(const NodeName& from_node,
- const NodeName& token,
- const NodeName& invitee_name) override {}
- void OnAddBrokerClient(const NodeName& from_node,
- const NodeName& client_name,
- base::ProcessHandle process_handle) override {}
- void OnBrokerClientAdded(const NodeName& from_node,
- const NodeName& client_name,
- mojo::PlatformHandle broker_channel) override {}
- void OnAcceptBrokerClient(const NodeName& from_node,
- const NodeName& broker_name,
- mojo::PlatformHandle broker_channel) override {}
- void OnEventMessage(const NodeName& from_node,
- Channel::MessagePtr message) override {}
- void OnRequestPortMerge(
- const NodeName& from_node,
- const mojo::core::ports::PortName& connector_port_name,
- const std::string& token) override {}
- void OnRequestIntroduction(const NodeName& from_node,
- const NodeName& name) override {}
- void OnIntroduce(const NodeName& from_node,
- const NodeName& name,
- mojo::PlatformHandle channel_handle) override {}
- void OnBroadcast(const NodeName& from_node,
- Channel::MessagePtr message) override {}
-#if defined(OS_WIN)
- void OnRelayEventMessage(const NodeName& from_node,
- base::ProcessHandle from_process,
- const NodeName& destination,
- Channel::MessagePtr message) override {}
- void OnEventMessageFromRelay(const NodeName& from_node,
- const NodeName& source_node,
- Channel::MessagePtr message) override {}
-#endif
- void OnAcceptPeer(const NodeName& from_node,
- const NodeName& token,
- const NodeName& peer_name,
- const mojo::core::ports::PortName& port_name) override {}
- void OnChannelError(const NodeName& node,
- mojo::core::NodeChannel* channel) override {}
-};
-
// A fake delegate for the sending Channel endpoint. The sending Channel is not
// being fuzzed and won't receive any interesting messages, so this doesn't need
// to do anything.
@@ -109,7 +56,7 @@ extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) {
// used to carry messages between processes.
mojo::PlatformChannel channel;
- FakeNodeChannelDelegate receiver_delegate;
+ mojo::core::MockNodeChannelDelegate receiver_delegate;
auto receiver = mojo::core::NodeChannel::Create(
&receiver_delegate, ConnectionParams(channel.TakeLocalEndpoint()),
Channel::HandlePolicy::kRejectHandles,
diff --git a/chromium/mojo/core/node_channel_unittest.cc b/chromium/mojo/core/node_channel_unittest.cc
new file mode 100644
index 00000000000..13c46f13fea
--- /dev/null
+++ b/chromium/mojo/core/node_channel_unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2020 The Chromium 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/core/node_channel.h"
+
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/message_loop/message_pump_type.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread.h"
+#include "mojo/core/embedder/embedder.h"
+#include "mojo/core/test/mock_node_channel_delegate.h"
+#include "mojo/public/cpp/platform/platform_channel.h"
+#include "mojo/public/cpp/platform/platform_channel_endpoint.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace core {
+namespace {
+
+using NodeChannelTest = testing::Test;
+using ports::NodeName;
+
+scoped_refptr<NodeChannel> CreateNodeChannel(NodeChannel::Delegate* delegate,
+ PlatformChannelEndpoint endpoint) {
+ return NodeChannel::Create(delegate, ConnectionParams(std::move(endpoint)),
+ Channel::HandlePolicy::kAcceptHandles,
+ GetIOTaskRunner(), base::NullCallback());
+}
+
+TEST_F(NodeChannelTest, DestructionIsSafe) {
+ // Regression test for https://crbug.com/1081874.
+ base::test::TaskEnvironment task_environment;
+
+ PlatformChannel channel;
+ MockNodeChannelDelegate local_delegate;
+ auto local_channel =
+ CreateNodeChannel(&local_delegate, channel.TakeLocalEndpoint());
+ local_channel->Start();
+ MockNodeChannelDelegate remote_delegate;
+ auto remote_channel =
+ CreateNodeChannel(&remote_delegate, channel.TakeRemoteEndpoint());
+ remote_channel->Start();
+
+ // Verify end-to-end operation
+ const NodeName kRemoteNodeName{123, 456};
+ const NodeName kToken{987, 654};
+ base::RunLoop loop;
+ EXPECT_CALL(local_delegate,
+ OnAcceptInvitee(ports::kInvalidNodeName, kRemoteNodeName, kToken))
+ .WillRepeatedly([&] { loop.Quit(); });
+ remote_channel->AcceptInvitee(kRemoteNodeName, kToken);
+ loop.Run();
+
+ // Now send another message to the local endpoint but tear it down
+ // immediately. This will race with the message being received on the IO
+ // thread, and although the corresponding delegate call may or may not
+ // dispatch as a result, the race should still be memory-safe.
+ remote_channel->AcceptInvitee(kRemoteNodeName, kToken);
+
+ base::RunLoop error_loop;
+ EXPECT_CALL(remote_delegate, OnChannelError).WillOnce([&] {
+ error_loop.Quit();
+ });
+ local_channel.reset();
+ error_loop.Run();
+}
+
+} // namespace
+} // namespace core
+} // namespace mojo
diff --git a/chromium/mojo/core/node_controller.cc b/chromium/mojo/core/node_controller.cc
index 345d22ae06b..ff93f0c3a6b 100644
--- a/chromium/mojo/core/node_controller.cc
+++ b/chromium/mojo/core/node_controller.cc
@@ -144,7 +144,7 @@ class ThreadDestructionObserver
} // namespace
-NodeController::~NodeController() {}
+NodeController::~NodeController() = default;
NodeController::NodeController(Core* core)
: core_(core),
diff --git a/chromium/mojo/core/node_controller.h b/chromium/mojo/core/node_controller.h
index e9645084037..9494de5b809 100644
--- a/chromium/mojo/core/node_controller.h
+++ b/chromium/mojo/core/node_controller.h
@@ -48,7 +48,7 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
virtual void OnPortStatusChanged() = 0;
protected:
- ~PortObserver() override {}
+ ~PortObserver() override = default;
};
// |core| owns and out-lives us.
diff --git a/chromium/mojo/core/options_validation.h b/chromium/mojo/core/options_validation.h
index ae4120800ae..89c12d0c887 100644
--- a/chromium/mojo/core/options_validation.h
+++ b/chromium/mojo/core/options_validation.h
@@ -16,7 +16,7 @@
#include <algorithm>
-#include "base/logging.h"
+#include "base/check.h"
#include "base/macros.h"
#include "mojo/core/system_impl_export.h"
#include "mojo/public/c/system/types.h"
diff --git a/chromium/mojo/core/platform_shared_memory_mapping.h b/chromium/mojo/core/platform_shared_memory_mapping.h
index b7c43ace9e0..305f5e4ef15 100644
--- a/chromium/mojo/core/platform_shared_memory_mapping.h
+++ b/chromium/mojo/core/platform_shared_memory_mapping.h
@@ -9,7 +9,6 @@
#include <memory>
-#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/platform_shared_memory_region.h"
#include "base/memory/shared_memory_mapping.h"
diff --git a/chromium/mojo/core/ports/message_filter.h b/chromium/mojo/core/ports/message_filter.h
index f09903ffca4..21f8c1c8697 100644
--- a/chromium/mojo/core/ports/message_filter.h
+++ b/chromium/mojo/core/ports/message_filter.h
@@ -15,7 +15,7 @@ class UserMessageEvent;
// arbitrary policy.
class MessageFilter {
public:
- virtual ~MessageFilter() {}
+ virtual ~MessageFilter() = default;
// Returns true if |message| should be accepted by whomever is applying this
// filter. See MessageQueue::GetNextMessage(), for example.
diff --git a/chromium/mojo/core/ports/node.cc b/chromium/mojo/core/ports/node.cc
index 476594db0cb..5b2558a0465 100644
--- a/chromium/mojo/core/ports/node.cc
+++ b/chromium/mojo/core/ports/node.cc
@@ -15,6 +15,7 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
+#include "base/notreached.h"
#include "base/optional.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_local.h"
@@ -1726,7 +1727,7 @@ Node::DelegateHolder::DelegateHolder(Node* node, NodeDelegate* delegate)
DCHECK(node_);
}
-Node::DelegateHolder::~DelegateHolder() {}
+Node::DelegateHolder::~DelegateHolder() = default;
#if DCHECK_IS_ON()
void Node::DelegateHolder::EnsureSafeDelegateAccess() const {
diff --git a/chromium/mojo/core/ports/node_delegate.h b/chromium/mojo/core/ports/node_delegate.h
index afe1c4cd975..3172779c06b 100644
--- a/chromium/mojo/core/ports/node_delegate.h
+++ b/chromium/mojo/core/ports/node_delegate.h
@@ -17,7 +17,7 @@ namespace ports {
class NodeDelegate {
public:
- virtual ~NodeDelegate() {}
+ virtual ~NodeDelegate() = default;
// Forward an event (possibly asynchronously) to the specified node.
virtual void ForwardEvent(const NodeName& node, ScopedEvent event) = 0;
diff --git a/chromium/mojo/core/ports/port.cc b/chromium/mojo/core/ports/port.cc
index 0d2aa74650e..c46dc9ed25b 100644
--- a/chromium/mojo/core/ports/port.cc
+++ b/chromium/mojo/core/ports/port.cc
@@ -21,7 +21,7 @@ Port::Port(uint64_t next_sequence_num_to_send,
peer_closed(false),
peer_lost_unexpectedly(false) {}
-Port::~Port() {}
+Port::~Port() = default;
} // namespace ports
} // namespace core
diff --git a/chromium/mojo/core/ports/port_ref.cc b/chromium/mojo/core/ports/port_ref.cc
index a3d312bc399..7cbc53674c7 100644
--- a/chromium/mojo/core/ports/port_ref.cc
+++ b/chromium/mojo/core/ports/port_ref.cc
@@ -10,9 +10,9 @@ namespace mojo {
namespace core {
namespace ports {
-PortRef::~PortRef() {}
+PortRef::~PortRef() = default;
-PortRef::PortRef() {}
+PortRef::PortRef() = default;
PortRef::PortRef(const PortName& name, scoped_refptr<Port> port)
: name_(name), port_(std::move(port)) {}
diff --git a/chromium/mojo/core/ports/port_ref.h b/chromium/mojo/core/ports/port_ref.h
index b63d6cfcd00..afa75e54c17 100644
--- a/chromium/mojo/core/ports/port_ref.h
+++ b/chromium/mojo/core/ports/port_ref.h
@@ -6,7 +6,6 @@
#define MOJO_CORE_PORTS_PORT_REF_H_
#include "base/component_export.h"
-#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "mojo/core/ports/name.h"
diff --git a/chromium/mojo/core/ports/ports_unittest.cc b/chromium/mojo/core/ports/ports_unittest.cc
index 07ee1155fd3..3353aa42e2e 100644
--- a/chromium/mojo/core/ports/ports_unittest.cc
+++ b/chromium/mojo/core/ports/ports_unittest.cc
@@ -44,7 +44,7 @@ class TestMessage : public UserMessage {
TestMessage(const base::StringPiece& payload)
: UserMessage(&kUserMessageTypeInfo), payload_(payload) {}
- ~TestMessage() override {}
+ ~TestMessage() override = default;
const std::string& payload() const { return payload_; }
@@ -69,7 +69,7 @@ class TestNode;
class MessageRouter {
public:
- virtual ~MessageRouter() {}
+ virtual ~MessageRouter() = default;
virtual void ForwardEvent(TestNode* from_node,
const NodeName& node_name,
diff --git a/chromium/mojo/core/ports/user_data.h b/chromium/mojo/core/ports/user_data.h
index e18d9b79d5f..2d2b25fc01b 100644
--- a/chromium/mojo/core/ports/user_data.h
+++ b/chromium/mojo/core/ports/user_data.h
@@ -15,7 +15,7 @@ class UserData : public base::RefCountedThreadSafe<UserData> {
protected:
friend class base::RefCountedThreadSafe<UserData>;
- virtual ~UserData() {}
+ virtual ~UserData() = default;
};
} // namespace ports
diff --git a/chromium/mojo/core/request_context.cc b/chromium/mojo/core/request_context.cc
index 582ff6fdf53..4ede95c4146 100644
--- a/chromium/mojo/core/request_context.cc
+++ b/chromium/mojo/core/request_context.cc
@@ -110,7 +110,7 @@ RequestContext::WatchNotifyFinalizer::WatchNotifyFinalizer(
RequestContext::WatchNotifyFinalizer::WatchNotifyFinalizer(
const WatchNotifyFinalizer& other) = default;
-RequestContext::WatchNotifyFinalizer::~WatchNotifyFinalizer() {}
+RequestContext::WatchNotifyFinalizer::~WatchNotifyFinalizer() = default;
} // namespace core
} // namespace mojo
diff --git a/chromium/mojo/core/run_all_core_unittests.cc b/chromium/mojo/core/run_all_core_unittests.cc
index 18b119ef4af..b8b1f199add 100644
--- a/chromium/mojo/core/run_all_core_unittests.cc
+++ b/chromium/mojo/core/run_all_core_unittests.cc
@@ -4,25 +4,54 @@
#include "base/base_switches.h"
#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/optional.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_suite.h"
#include "build/build_config.h"
+#include "mojo/core/mojo_core_unittest.h"
#include "mojo/public/c/system/core.h"
+#include "mojo/public/cpp/system/dynamic_library_support.h"
+
+base::FilePath GetMojoCoreLibraryPath() {
+#if defined(OS_WIN)
+ const char kLibraryFilename[] = "mojo_core.dll";
+#else
+ const char kLibraryFilename[] = "libmojo_core.so";
+#endif
+ base::FilePath executable_dir =
+ base::CommandLine::ForCurrentProcess()->GetProgram().DirName();
+ if (executable_dir.IsAbsolute())
+ return executable_dir.AppendASCII(kLibraryFilename);
+
+ base::FilePath current_directory;
+ CHECK(base::GetCurrentDirectory(&current_directory));
+ return current_directory.Append(executable_dir).AppendASCII(kLibraryFilename);
+}
int main(int argc, char** argv) {
base::TestSuite test_suite(argc, argv);
- MojoInitializeOptions options;
- options.struct_size = sizeof(options);
- options.flags = MOJO_INITIALIZE_FLAG_NONE;
- options.mojo_core_path = NULL;
- options.mojo_core_path_length = 0;
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kTestChildProcess)) {
- options.flags = MOJO_INITIALIZE_FLAG_AS_BROKER;
+ MojoInitializeFlags flags = MOJO_INITIALIZE_FLAG_NONE;
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ if (!command_line.HasSwitch(switches::kTestChildProcess))
+ flags |= MOJO_INITIALIZE_FLAG_AS_BROKER;
+
+ base::Optional<base::FilePath> library_path;
+ if (command_line.HasSwitch(switches::kMojoUseExplicitLibraryPath))
+ library_path = GetMojoCoreLibraryPath();
+
+ if (command_line.HasSwitch(switches::kMojoLoadBeforeInit)) {
+ CHECK_EQ(MOJO_RESULT_OK, mojo::LoadCoreLibrary(library_path));
+ CHECK_EQ(MOJO_RESULT_OK, mojo::InitializeCoreLibrary(flags));
+ } else {
+ CHECK_EQ(MOJO_RESULT_OK,
+ mojo::LoadAndInitializeCoreLibrary(library_path, flags));
}
- CHECK_EQ(MOJO_RESULT_OK, MojoInitialize(&options));
int result = base::LaunchUnitTests(
argc, argv,
base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite)));
diff --git a/chromium/mojo/core/shared_buffer_dispatcher_unittest.cc b/chromium/mojo/core/shared_buffer_dispatcher_unittest.cc
index b245b78330d..fe206b63146 100644
--- a/chromium/mojo/core/shared_buffer_dispatcher_unittest.cc
+++ b/chromium/mojo/core/shared_buffer_dispatcher_unittest.cc
@@ -45,8 +45,8 @@ void RevalidateCreateOptions(
class SharedBufferDispatcherTest : public testing::Test {
public:
- SharedBufferDispatcherTest() {}
- ~SharedBufferDispatcherTest() override {}
+ SharedBufferDispatcherTest() = default;
+ ~SharedBufferDispatcherTest() override = default;
private:
DISALLOW_COPY_AND_ASSIGN(SharedBufferDispatcherTest);
diff --git a/chromium/mojo/core/test/BUILD.gn b/chromium/mojo/core/test/BUILD.gn
index 1abadfc503d..9429c618530 100644
--- a/chromium/mojo/core/test/BUILD.gn
+++ b/chromium/mojo/core/test/BUILD.gn
@@ -7,6 +7,8 @@ import("//third_party/protobuf/proto_library.gni")
static_library("test_support") {
testonly = true
sources = [
+ "mock_node_channel_delegate.cc",
+ "mock_node_channel_delegate.h",
"mojo_test_base.cc",
"mojo_test_base.h",
"test_utils.h",
@@ -27,8 +29,10 @@ static_library("test_support") {
public_deps = [
"//base",
"//base/test:test_support",
+ "//mojo/core:embedder_internal",
"//mojo/core/embedder",
"//mojo/public/cpp/system",
+ "//testing/gmock",
"//testing/gtest",
]
}
diff --git a/chromium/mojo/core/test_utils.cc b/chromium/mojo/core/test_utils.cc
index eb025b4a3c4..acbfca018af 100644
--- a/chromium/mojo/core/test_utils.cc
+++ b/chromium/mojo/core/test_utils.cc
@@ -54,9 +54,9 @@ void Sleep(MojoDeadline deadline) {
base::TimeDelta::FromMicroseconds(static_cast<int64_t>(deadline)));
}
-Stopwatch::Stopwatch() {}
+Stopwatch::Stopwatch() = default;
-Stopwatch::~Stopwatch() {}
+Stopwatch::~Stopwatch() = default;
void Stopwatch::Start() {
start_time_ = base::TimeTicks::Now();
diff --git a/chromium/mojo/core/trap_unittest.cc b/chromium/mojo/core/trap_unittest.cc
index f543b2f0ec3..8ff1f74a6ad 100644
--- a/chromium/mojo/core/trap_unittest.cc
+++ b/chromium/mojo/core/trap_unittest.cc
@@ -34,8 +34,8 @@ class TriggerHelper {
public:
using ContextCallback = base::RepeatingCallback<void(const MojoTrapEvent&)>;
- TriggerHelper() {}
- ~TriggerHelper() {}
+ TriggerHelper() = default;
+ ~TriggerHelper() = default;
MojoResult CreateTrap(MojoHandle* handle) {
return MojoCreateTrap(&Notify, nullptr, handle);
@@ -65,7 +65,7 @@ class TriggerHelper {
explicit NotificationContext(const ContextCallback& callback)
: callback_(callback) {}
- ~NotificationContext() {}
+ ~NotificationContext() = default;
void SetCancelCallback(base::OnceClosure cancel_callback) {
cancel_callback_ = std::move(cancel_callback);
@@ -97,7 +97,7 @@ class ThreadedRunner : public base::SimpleThread {
public:
explicit ThreadedRunner(base::OnceClosure callback)
: SimpleThread("ThreadedRunner"), callback_(std::move(callback)) {}
- ~ThreadedRunner() override {}
+ ~ThreadedRunner() override = default;
void Run() override { std::move(callback_).Run(); }
diff --git a/chromium/mojo/core/watch.cc b/chromium/mojo/core/watch.cc
index 996f0a7ca24..0d0429da097 100644
--- a/chromium/mojo/core/watch.cc
+++ b/chromium/mojo/core/watch.cc
@@ -78,7 +78,7 @@ void Watch::InvokeCallback(MojoResult result,
watcher_->InvokeWatchCallback(context_, result, state, flags);
}
-Watch::~Watch() {}
+Watch::~Watch() = default;
#if DCHECK_IS_ON()
void Watch::AssertWatcherLockAcquired() const {
diff --git a/chromium/mojo/docs/mojolpm.md b/chromium/mojo/docs/mojolpm.md
new file mode 100644
index 00000000000..a3b1c8e254b
--- /dev/null
+++ b/chromium/mojo/docs/mojolpm.md
@@ -0,0 +1,471 @@
+# Getting started with MojoLPM
+
+*** note
+**Note:** Using MojoLPM to fuzz your Mojo interfaces is intended to be simple,
+but there are edge-cases that may require a very detailed understanding of the
+Mojo implementation to fix. If you run into problems that you can't understand
+readily, send an email to [markbrand@google.com] and cc `fuzzing@chromium.org`
+and we'll try and help.
+
+**Prerequisites:** Knowledge of [libfuzzer] and basic understanding
+of [Protocol Buffers] and [libprotobuf-mutator]. Basic understanding of
+[testing in Chromium].
+***
+
+This document will walk you through:
+* An overview of MojoLPM and what it's used for.
+* Adding a fuzzer to an existing Mojo interface using MojoLPM.
+
+[TOC]
+
+## Overview of MojoLPM
+
+MojoLPM is a toolchain for automatically generating structure-aware fuzzers for
+Mojo interfaces using libprotobuf-mutator as the fuzzing engine.
+
+This tool works by using the existing "grammar" for the interface provided by
+the .mojom files, and translating that into a Protocol Buffer format that can be
+fuzzed by libprotobuf-mutator. These protocol buffers are then interpreted by
+a generated runtime as a sequence of mojo method calls on the targeted
+interface.
+
+The intention is that using these should be as simple as plugging the generated
+code in to the existing unittests for those interfaces - so if you've already
+implemented the necessary mocks to unittest your code, the majority of the work
+needed to get quite effective fuzzing of your interfaces is already complete!
+
+## Choose the Mojo interface(s) to fuzz
+
+If you're a developer looking to add fuzzing support for an interface that
+you're developing, then this should be very easy for you!
+
+If not, then a good starting point is to search for [interfaces] in codesearch.
+The most interesting interfaces from a security perspective are those which are
+implemented in the browser process and exposed to the renderer process, but
+there isn't a very simple way to enumerate these, so you may need to look
+through some of the source code to find an interesting one.
+
+For the rest of this guide, we'll write a new fuzzer for
+`blink.mojom.CodeCacheHost`, which is defined in
+`third_party/blink/public/mojom/loader/code_cache.mojom`.
+
+We then need to find the relevant GN build target for this mojo interface so
+that we know how to refer to it later - in this case that is
+`//third_party/blink/public/mojom:mojom_platform`.
+
+## Find the implementations of the interfaces
+
+If you are developing these interfaces, then you already know where to find the
+implementations.
+
+Otherwise a good starting point is to search for references to
+"public blink::mojom::CodeCacheHost". Usually there is only a single
+implementation of a given Mojo interface (there are a few exceptions where the
+interface abstracts platform specific details, but this is less common). This
+leads us to `content/browser/renderer_host/code_cache_host_impl.h` and
+`CodeCacheHostImpl`.
+
+## Find the unittest for the implementation
+
+Unfortunately, it doesn't look like `CodeCacheHostImpl` has a unittest, so we'll
+have to go through the process of understanding how to create a valid instance
+ourselves in order to fuzz this interface.
+
+Since this interface runs in the Browser process, and is part of `/content`,
+we're going to create our new fuzzer in `/content/test/fuzzer`.
+
+## Add our testcase proto
+
+First we'll add a proto source file, `code_cache_host_mojolpm_fuzzer.proto`,
+which is going to define the structure of our testcases. This is basically
+boilerplate, but it allows creating fuzzers which interact with multiple Mojo
+interfaces to uncover more complex issues. For our case, this will be a simple
+file:
+
+```
+syntax = "proto2";
+
+package content.fuzzing.code_cache_host.proto;
+
+import "third_party/blink/public/mojom/loader/code_cache.mojom.mojolpm.proto";
+
+message NewCodeCacheHost {
+ required uint32 id = 1;
+}
+
+message RunUntilIdle {
+ enum ThreadId {
+ IO = 0;
+ UI = 1;
+ }
+
+ required ThreadId id = 1;
+}
+
+message Action {
+ oneof action {
+ NewCodeCacheHost new_code_cache_host = 1;
+ RunUntilIdle run_until_idle = 2;
+ mojolpm.blink.mojom.CodeCacheHost.RemoteMethodCall code_cache_host_call = 3;
+ }
+}
+
+message Sequence {
+ repeated uint32 action_indexes = 1 [packed=true];
+}
+
+message Testcase {
+ repeated Action actions = 1;
+ repeated Sequence sequences = 2;
+ repeated uint32 sequence_indexes = 3 [packed=true];
+}
+```
+
+This specifies all of the actions that the fuzzer will be able to take - it
+will be able to create a new `CodeCacheHost` instance, perform sequences of
+interface calls on those instances, and wait for various threads to be idle.
+
+In order to build this proto file, we'll need to copy it into the out/ directory
+so that it can reference the proto files generated by MojoLPM - this will be
+handled for us by the `mojolpm_fuzzer_test` build rule.
+
+## Add our fuzzer source
+
+Now we're ready to create the fuzzer c++ source file,
+`code_cache_host_mojolpm_fuzzer.cc` and the fuzzer build target. This
+target is going to depend on both our proto file, and on the c++ source file.
+Most of the necessary dependencies will be handled for us, but we do still need
+to add some directly.
+
+Note especially the dependency on `mojom_platform_mojolpm` in blink, this is an
+autogenerated target where the target containing the generated fuzzer protocol
+buffer descriptions will be the name of the mojom target with `_mojolpm`
+appended.
+
+```
+mojolpm_fuzzer_test("code_cache_host_mojolpm_fuzzer") {
+ sources = [
+ "code_cache_host_mojolpm_fuzzer.cc"
+ ]
+
+ proto_source = "code_cache_host_mojolpm_fuzzer.proto"
+
+ deps = [
+ "//base/test:test_support",
+ "//content/browser:for_content_tests",
+ "//content/public/browser:browser_sources",
+ "//content/test:test_support",
+ "//services/network:test_support",
+ "//storage/browser:test_support",
+ ]
+
+ proto_deps = [
+ "//third_party/blink/public/mojom:mojom_platform_mojolpm",
+ ]
+}
+```
+
+Now, the minimal source code to do load our testcases:
+
+```c++
+// Copyright 2020 The Chromium 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 <stdint.h>
+#include <utility>
+
+#include "code_cache_host_mojolpm_fuzzer.pb.h"
+#include "mojo/core/embedder/embedder.h"
+#include "third_party/blink/public/mojom/loader/code_cache.mojom-mojolpm.h"
+#include "third_party/libprotobuf-mutator/src/src/libfuzzer/libfuzzer_macro.h"
+
+DEFINE_BINARY_PROTO_FUZZER(
+ const content::fuzzing::code_cache_host::proto::Testcase& testcase) {
+}
+```
+
+You should now be able to build and run this fuzzer (it, of course, won't do
+very much) to check that everything is lined up right so far.
+
+## Handle global process setup
+
+Now we need to add some basic setup code so that our process has something that
+mostly resembles a normal Browser process; if you look in the file this is
+`CodeCacheHostFuzzerEnvironment`, which adds a global environment instance that
+will handle setting up this basic environment, which will be reused for all of
+our testcases, since starting threads is expensive and slow.
+
+## Handle per-testcase setup
+
+We next need to handle the necessary setup to instantiate `CodeCacheHostImpl`,
+so that we can actually run the testcases. At this point, we realise that it's
+likely that we want to be able to have multiple `CodeCacheHostImpl`'s with
+different render_process_ids and different backing origins, so we need to modify
+our proto file to reflect this:
+
+```
+message NewCodeCacheHost {
+ enum OriginId {
+ ORIGIN_A = 0;
+ ORIGIN_B = 1;
+ ORIGIN_OPAQUE = 2;
+ ORIGIN_EMPTY = 3;
+ }
+
+ required uint32 id = 1;
+ required uint32 render_process_id = 2;
+ required OriginId origin_id = 3;
+}
+```
+
+Note that we're using an enum to represent the origin, rather than a string;
+it's unlikely that the true value of the origin is going to be important, so
+we've instead chosen a few select values based on the cases mentioned in the
+source.
+
+The first thing that we need to do is set-up the basic Browser process
+environment; this is what `ContentFuzzerEnvironment` is doing - this has a basic
+setup suitable for fuzzing interfaces in `/content`. A few things to be careful
+of are that we need to make sure that `mojo::core::Init()` is called (only once)
+and we probably want as much freedom as possible in terms of scheduling, so we
+want to use slightly different threading options than the average unittest. This
+is a singleton type that will live for the entire duration of the fuzzer process
+so we don't want to be holding any testcase-specific data here.
+
+The next thing that we need to do is to figure out the basic setup needed to
+instantiate the interface we're interested in. Looking at the constructor for
+`CodeCacheHostImpl` we need three things; a valid `render_process_id`, an
+instance of `CacheStorageContextImpl` and an instance of
+`GeneratedCodeCacheContext`. `CodeCacheHostFuzzerContext` is our container for
+these per-testcase instances; and will handle creating and binding the instances
+of the Mojo interfaces that we're going to fuzz. The most important thing to be
+careful of here is that everything happens on the correct thread/sequence. Many
+Browser-process objects have specific expectations, and will end up with very
+different behaviour if they are created or used from the wrong context.
+
+## Integrate with the generated MojoLPM fuzzer code
+
+Finally, we need to do a little bit more plumbing, to rig up this infrastructure
+that we've built together with the autogenerated code that MojoLPM gives us to
+interpret and run our testcases. This is the `CodeCacheHostTestcase`, and the
+part where the magic happens is here:
+
+```c++
+void CodeCacheHostTestcase::NextAction() {
+ if (next_idx_ < testcase_.sequence_indexes_size()) {
+ auto sequence_idx = testcase_.sequence_indexes(next_idx_++);
+ const auto& sequence =
+ testcase_.sequences(sequence_idx % testcase_.sequences_size());
+ for (auto action_idx : sequence.action_indexes()) {
+ if (!testcase_.actions_size() || ++action_count_ > MAX_ACTION_COUNT) {
+ return;
+ }
+ const auto& action =
+ testcase_.actions(action_idx % testcase_.actions_size());
+ switch (action.action_case()) {
+ case content::fuzzing::code_cache_host::proto::Action::kNewCodeCacheHost: {
+ cch_context_.AddCodeCacheHost(
+ action.new_code_cache_host().id(),
+ action.new_code_cache_host().render_process_id(),
+ action.new_code_cache_host().origin_id());
+ } break;
+
+ case content::fuzzing::code_cache_host::proto::Action::kRunUntilIdle: {
+ if (action.run_until_idle().id()) {
+ content::RunUIThreadUntilIdle();
+ } else {
+ content::RunIOThreadUntilIdle();
+ }
+ } break;
+
+ case content::fuzzing::code_cache_host::proto::Action::kCodeCacheHostCall: {
+ mojolpm::HandleRemoteMethodCall(action.code_cache_host_call());
+ } break;
+
+ case content::fuzzing::code_cache_host::proto::Action::ACTION_NOT_SET:
+ break;
+ }
+ }
+ }
+}
+```
+
+The key line here in integration with MojoLPM is the last case,
+`kCodeCacheHostCall`, where we're asking MojoLPM to treat this incoming proto
+entry as a call to a method on the `CodeCacheHost` interface.
+
+There's just a little bit more boilerplate in the bottom of the file to tidy up
+concurrency loose ends, making sure that the fuzzer components are all running
+on the correct threads; those are more-or-less common to any fuzzer using
+MojoLPM.
+
+## Test it!
+
+Make a corpus directory and fire up your shiny new fuzzer!
+
+```
+ ~/chromium/src% out/Default/code_cache_host_mojolpm_fuzzer /dev/shm/corpus
+INFO: Seed: 3273881842
+INFO: Loaded 1 modules (1121912 inline 8-bit counters): 1121912 [0x559151a1aea8, 0x559151b2cd20),
+INFO: Loaded 1 PC tables (1121912 PCs): 1121912 [0x559151b2cd20,0x559152c4b4a0),
+INFO: 146 files found in /dev/shm/corpus
+INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
+INFO: seed corpus: files: 146 min: 2b max: 268b total: 8548b rss: 88Mb
+#147 INITED cov: 4633 ft: 10500 corp: 138/8041b exec/s: 0 rss: 91Mb
+#152 NEW cov: 4633 ft: 10501 corp: 139/8139b lim: 4096 exec/s: 0 rss: 91Mb L: 98/268 MS: 8 Custom-ChangeByte-Custom-EraseBytes-Custom-ShuffleBytes-Custom-Custom-
+#154 NEW cov: 4634 ft: 10510 corp: 140/8262b lim: 4096 exec/s: 0 rss: 91Mb L: 123/268 MS: 3 CustomCrossOver-ChangeBit-Custom-
+#157 NEW cov: 4634 ft: 10512 corp: 141/8384b lim: 4096 exec/s: 0 rss: 91Mb L: 122/268 MS: 3 CustomCrossOver-Custom-CustomCrossOver-
+#158 NEW cov: 4634 ft: 10514 corp: 142/8498b lim: 4096 exec/s: 0 rss: 91Mb L: 114/268 MS: 1 CustomCrossOver-
+#159 NEW cov: 4634 ft: 10517 corp: 143/8601b lim: 4096 exec/s: 0 rss: 91Mb L: 103/268 MS: 1 Custom-
+#160 NEW cov: 4634 ft: 10526 corp: 144/8633b lim: 4096 exec/s: 0 rss: 91Mb L: 32/268 MS: 1 Custom-
+#164 NEW cov: 4634 ft: 10528 corp: 145/8851b lim: 4096 exec/s: 0 rss: 91Mb L: 218/268 MS: 4 CustomCrossOver-Custom-CustomCrossOver-Custom-
+```
+
+## Wait for it...
+
+Let the fuzzer run for a while, and keep periodically checking in in case it's
+fallen over. It's likely you'll have made a few mistakes somewhere along the way
+but hopefully soon you'll have the fuzzer running 'clean' for a few hours.
+
+If your coverage isn't going up at all, then you've probably made a mistake and
+it likely isn't managing to actually interact with the interface you're trying
+to fuzz - try using the code coverage output from the next step to debug what's
+going wrong.
+
+## (Optional) Run coverage
+
+In many cases it's useful to check the code coverage to see if we can benefit
+from adding some manual testcases to get deeper coverage. For this example I
+used the following command:
+
+```
+python tools/code_coverage/coverage.py code_cache_host_mojolpm_fuzzer -b out/Coverage -o ManualReport -c "out/Coverage/code_cache_host_mojolpm_fuzzer -ignore_timeouts=1 -timeout=4 -runs=0 /dev/shm/corpus" -f content
+```
+
+With the CodeCacheHost, looking at the coverage after a few hours we could see
+that there's definitely some room for improvement:
+
+```c++
+/* 55 */ base::Optional<GURL> GetSecondaryKeyForCodeCache(const GURL& resource_url,
+/* 56 53.6k */ int render_process_id) {
+/* 57 53.6k */ if (!resource_url.is_valid() || !resource_url.SchemeIsHTTPOrHTTPS())
+/* 58 53.6k */ return base::nullopt;
+/* 59 0 */
+/* 60 0 */ GURL origin_lock =
+/* 61 0 */ ChildProcessSecurityPolicyImpl::GetInstance()->GetOriginLock(
+/* 62 0 */ render_process_id);
+```
+
+## (Optional) Improve corpus manually
+
+It's fairly easy to improve the corpus manually, since our corpus files are just
+protobuf files that describe the sequence of interface calls to make.
+
+There are a couple of approaches that we can take here - we'll try building a
+small manual seed corpus that we'll use to kick-start our fuzzer. Since it's
+easier to edit text protos, MojoLPM can automatically convert our seed corpus
+from text protos to binary protos during the build, making this slightly less
+painful for us, and letting us store our corpus in-tree in a readable format.
+
+So, we'll create a new folder to hold this seed corpus, and craft our first
+file:
+
+```
+actions {
+ new_code_cache_host {
+ id: 1
+ render_process_id: 0
+ origin_id: ORIGIN_A
+ }
+}
+actions {
+ code_cache_host_call {
+ remote {
+ id: 1
+ }
+ m_did_generate_cacheable_metadata {
+ m_cache_type: CodeCacheType_kJavascript
+ m_url {
+ new {
+ id: 1
+ m_url: "http://aaa.com/test"
+ }
+ }
+ m_data {
+ new {
+ id: 1
+ m_bytes {
+ }
+ }
+ m_expected_response_time {
+ }
+ }
+ }
+}
+sequences {
+ action_indexes: 0
+ action_indexes: 1
+}
+sequence_indexes: 0
+```
+
+We can then add some new entries to our build target to have the corpus
+converted to binary proto directly during build.
+
+```
+ testcase_proto_kind = "content.fuzzing.code_cache_host.proto.Testcase"
+
+ seed_corpus_sources = [
+ "code_cache_host_mojolpm_fuzzer_corpus/did_generate_cacheable_metadata.textproto",
+ ]
+```
+
+If we now run a new coverage report using this single file seed corpus:
+(note that the binary corpus files will be output in your output directory, in
+this case code_cache_host_mojolpm_fuzzer_seed_corpus.zip):
+
+```
+autoninja -C out/Coverage chrome
+rm -rf /tmp/corpus; mkdir /tmp/corpus; unzip out/Coverage/code_cache_host_mojolpm_fuzzer_seed_corpus.zip -d /tmp/corpus
+python tools/code_coverage/coverage.py code_cache_host_mojolpm_fuzzer -b out/Coverage -o ManualReport -c "out/Coverage/code_cache_host_mojolpm_fuzzer -ignore_timeouts=1 -timeout=4 -runs=0 /tmp/corpus" -f content
+```
+
+We can see that we're now getting some more coverage:
+
+```c++
+/* 118 */ void CodeCacheHostImpl::DidGenerateCacheableMetadata(
+/* 119 */ blink::mojom::CodeCacheType cache_type,
+/* 120 */ const GURL& url,
+/* 121 */ base::Time expected_response_time,
+/* 122 2 */ mojo_base::BigBuffer data) {
+/* 123 2 */ if (!url.SchemeIsHTTPOrHTTPS()) {
+/* 124 0 */ mojo::ReportBadMessage("Invalid URL scheme for code cache.");
+/* 125 0 */ return;
+/* 126 0 */ }
+/* 127 2 */
+/* 128 2 */ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+/* 129 2 */
+/* 130 2 */ GeneratedCodeCache* code_cache = GetCodeCache(cache_type);
+/* 131 2 */ if (!code_cache)
+/* 132 0 */ return;
+/* 133 2 */
+/* 134 2 */ base::Optional<GURL> origin_lock =
+/* 135 2 */ GetSecondaryKeyForCodeCache(url, render_process_id_);
+/* 136 2 */ if (!origin_lock)
+/* 137 0 */ return;
+/* 138 2 */
+/* 139 2 */ code_cache->WriteEntry(url, *origin_lock, expected_response_time,
+/* 140 2 */ std::move(data));
+/* 141 2 */ }
+```
+
+Much better!
+
+[markbrand@google.com]: mailto:markbrand@google.com?subject=[MojoLPM%20Help]:%20&cc=fuzzing@chromium.org
+[libfuzzer]: https://source.chromium.org/chromium/chromium/src/+/master:testing/libfuzzer/getting_started.md
+[Protocol Buffers]: https://developers.google.com/protocol-buffers/docs/cpptutorial
+[libprotobuf-mutator]: https://source.chromium.org/chromium/chromium/src/+/master:testing/libfuzzer/libprotobuf-mutator.md
+[testing in Chromium]: https://source.chromium.org/chromium/chromium/src/+/master:docs/testing/testing_in_chromium.md
+[interfaces]: https://source.chromium.org/search?q=interface%5Cs%2B%5Cw%2B%5Cs%2B%7B%20f:%5C.mojom$%20-f:test
+
diff --git a/chromium/mojo/public/c/system/functions.h b/chromium/mojo/public/c/system/functions.h
index 6f47028f480..257b6012c74 100644
--- a/chromium/mojo/public/c/system/functions.h
+++ b/chromium/mojo/public/c/system/functions.h
@@ -12,6 +12,7 @@
#include <stddef.h>
#include <stdint.h>
+#include "mojo/public/c/system/invitation.h"
#include "mojo/public/c/system/system_export.h"
#include "mojo/public/c/system/types.h"
@@ -26,12 +27,23 @@ extern "C" {
//
// |options| may be null.
//
+// If the |MOJO_INITIALIZE_FLAG_LOAD_ONLY| flag is given in |options|, this only
+// partially initializes the library. Other Mojo APIs will remain unavailable
+// until the library is fully initialized by a subsequent call to
+// |MojoInitialize()| WITHOUT the flag. See documentation on
+// |MOJO_INITIALIZE_FLAG_LOAD_ONLY| in types.h for details.
+//
// Returns:
// |MOJO_RESULT_OK| if Mojo initialization was successful.
+// |MOJO_RESULT_NOT_FOUND| if the Mojo Core library could not be loaded or
+// appears to be malformed.
+// |MOJO_RESULT_FAILED_PRECONDITION| if the Mojo Core library AND full IPC
+// support has already been initialized by some prior call(s) to
+// |MojoInitialize()|.
+// |MOJO_RESULT_ALREADY_EXISTS| if |MOJO_INITIALIZE_FLAG_LOAD_ONLY| was
+// specified for this call but the library has already been successfully
+// loaded and partially initialized by a previous call with the same flag.
// |MOJO_RESULT_INVALID_ARGUMENT| if |options| was non-null and invalid.
-// |MOJO_RESULT_FAILED_PRECONDITION| if |MojoInitialize()| was already called
-// once or if the application already explicitly initialized a Mojo Core
-// environment as an embedder.
MOJO_SYSTEM_EXPORT MojoResult
MojoInitialize(const struct MojoInitializeOptions* options);
diff --git a/chromium/mojo/public/c/system/invitation.h b/chromium/mojo/public/c/system/invitation.h
index e63001eb0be..f95bcc4e096 100644
--- a/chromium/mojo/public/c/system/invitation.h
+++ b/chromium/mojo/public/c/system/invitation.h
@@ -251,6 +251,25 @@ struct MOJO_ALIGNAS(8) MojoAcceptInvitationOptions {
MOJO_STATIC_ASSERT(sizeof(struct MojoAcceptInvitationOptions) == 8,
"MojoAcceptInvitationOptions has wrong size");
+// Flags passed to |MojoSetDefaultProcessErrorHandler()| via
+// |MojoSetDefaultProcessErrorHandlerOptions|.
+typedef uint32_t MojoSetDefaultProcessErrorHandlerFlags;
+
+// No flags. Default behavior.
+#define MOJO_SET_DEFAULT_PROCESS_ERROR_HANDLER_FLAG_NONE \
+ ((MojoSetDefaultProcessErrorHandlerFlags)0)
+
+// Options passed to |MojoSetDefaultProcessErrorHandler()|.
+struct MOJO_ALIGNAS(8) MojoSetDefaultProcessErrorHandlerOptions {
+ // The size of this structure, used for versioning.
+ uint32_t struct_size;
+
+ // See |MojoSetDefaultProcessErrorHandlerFlags|.
+ MojoSetDefaultProcessErrorHandlerFlags flags;
+};
+MOJO_STATIC_ASSERT(sizeof(struct MojoSetDefaultProcessErrorHandlerOptions) == 8,
+ "MojoSetDefaultProcessErrorHandlerOptions has wrong size");
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -266,6 +285,12 @@ typedef void (*MojoProcessErrorHandler)(
uintptr_t context,
const struct MojoProcessErrorDetails* details);
+// Similar to above, but registered globally via
+// |MojoSetDefaultProcessErrorHandler()| and invoked only for communication
+// errors regarding processes NOT invited by the calling process.
+typedef void (*MojoDefaultProcessErrorHandler)(
+ const struct MojoProcessErrorDetails* details);
+
// Creates a new invitation to be sent to another process.
//
// An invitation is used to invite another process to join this process's
@@ -474,6 +499,31 @@ MOJO_SYSTEM_EXPORT MojoResult MojoAcceptInvitation(
const struct MojoAcceptInvitationOptions* options,
MojoHandle* invitation_handle);
+// Registers a process-wide handler to be invoked when an error is raised on a
+// connection to a peer process. Such errors can be raised if the peer process
+// sends malformed data to this process.
+//
+// Note that this handler is only invoked for connections to processes NOT
+// explicitly invited by this process. To handle errors concerning processes
+// invited by this process, see the MojoProcessErrorHandler argument to
+// |MojoSendInvitation()|.
+//
+// The general use case for this API is to be able to log or report instances of
+// bad IPCs received by a client process which no real ability or authority to
+// identify the source.
+//
+// Returns:
+// |MOJO_RESULT_OK| if |handler| is successfully registered as the global
+// default process error handler within the calling process. If |handler|
+// is null, any registered default process error handler is removed.
+// |MOJO_RESULT_ALREADY_EXISTS| if |handler| is non-null and there is already
+// a registered error handler. Callers wishing to replace an existing
+// handler must first call |MojoSetDefaultProcessErrorHandler()| with null
+// in order to do so.
+MOJO_SYSTEM_EXPORT MojoResult MojoSetDefaultProcessErrorHandler(
+ MojoDefaultProcessErrorHandler handler,
+ const struct MojoSetDefaultProcessErrorHandlerOptions* options);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/chromium/mojo/public/c/system/macros.h b/chromium/mojo/public/c/system/macros.h
index 1023e1c111a..ebacb7482ac 100644
--- a/chromium/mojo/public/c/system/macros.h
+++ b/chromium/mojo/public/c/system/macros.h
@@ -6,6 +6,7 @@
#define MOJO_PUBLIC_C_SYSTEM_MACROS_H_
#include <stddef.h>
+#include <stdint.h>
#if !defined(__cplusplus)
#include <assert.h> // Defines static_assert() in C11.
@@ -29,6 +30,18 @@
// Like the C++11 |alignof| operator.
#define MOJO_ALIGNOF(type) alignof(type)
+// Provides a convenient test for the presence of a field in a user-provided
+// structure from a potentially older version of the ABI. Presence is determined
+// by comparing the struct's provided |struct_size| value against the known
+// offset and size of the field in this version of the ABI. Because fields are
+// never reordered or removed, this is a sufficient test for the field's
+// presence within whatever version of the ABI the client is programmed against.
+#define MOJO_IS_STRUCT_FIELD_PRESENT(struct_pointer, field) \
+ ((size_t)(uintptr_t)((const char*)&(struct_pointer)->field - \
+ (const char*)(struct_pointer)) + \
+ sizeof((struct_pointer)->field) <= \
+ (struct_pointer)->struct_size)
+
// Specify the alignment of a |struct|, etc.
// Use like:
// struct MOJO_ALIGNAS(8) Foo { ... };
diff --git a/chromium/mojo/public/c/system/thunks.cc b/chromium/mojo/public/c/system/thunks.cc
index 1bf1a2673d7..6a67df5e710 100644
--- a/chromium/mojo/public/c/system/thunks.cc
+++ b/chromium/mojo/public/c/system/thunks.cc
@@ -8,12 +8,17 @@
#include <cstdint>
#include <cstring>
+#include "base/check_op.h"
#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/no_destructor.h"
+#include "base/notreached.h"
+#include "base/strings/string_piece.h"
#include "build/build_config.h"
#include "mojo/public/c/system/core.h"
+#include "mojo/public/c/system/macros.h"
#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
#include "base/environment.h"
@@ -57,17 +62,17 @@ namespace mojo {
// enabled.
class CoreLibraryInitializer {
public:
- CoreLibraryInitializer(const MojoInitializeOptions* options) {
+ CoreLibraryInitializer() = default;
+ CoreLibraryInitializer(const CoreLibraryInitializer&) = delete;
+ CoreLibraryInitializer& operator=(const CoreLibraryInitializer&) = delete;
+ ~CoreLibraryInitializer() = default;
+
+ MojoResult LoadLibrary(base::FilePath library_path) {
#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
- bool application_provided_path = false;
- base::Optional<base::FilePath> library_path;
- if (options && options->struct_size >= sizeof(*options) &&
- options->mojo_core_path) {
- base::StringPiece utf8_path(options->mojo_core_path,
- options->mojo_core_path_length);
- library_path.emplace(base::FilePath::FromUTF8Unsafe(utf8_path));
- application_provided_path = true;
- } else {
+ if (library_ && library_->is_valid())
+ return MOJO_RESULT_OK;
+
+ if (library_path.empty()) {
auto environment = base::Environment::Create();
std::string library_path_value;
const char kLibraryPathEnvironmentVar[] = "MOJO_CORE_LIBRARY_PATH";
@@ -75,7 +80,7 @@ class CoreLibraryInitializer {
library_path = base::FilePath::FromUTF8Unsafe(library_path_value);
}
- if (!library_path) {
+ if (library_path.empty()) {
// Default to looking for the library in the current working directory.
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
const base::FilePath::CharType kDefaultLibraryPathValue[] =
@@ -84,7 +89,7 @@ class CoreLibraryInitializer {
const base::FilePath::CharType kDefaultLibraryPathValue[] =
FILE_PATH_LITERAL("mojo_core.dll");
#endif
- library_path.emplace(kDefaultLibraryPathValue);
+ library_path = base::FilePath(kDefaultLibraryPathValue);
}
// NOTE: |prefer_own_symbols| on POSIX implies that the library is loaded
@@ -100,47 +105,36 @@ class CoreLibraryInitializer {
// allocator shims, so it's unnecessary there.
library_options.prefer_own_symbols = true;
#endif
- library_.emplace(base::LoadNativeLibraryWithOptions(
- *library_path, library_options, nullptr));
- if (!application_provided_path) {
- CHECK(library_->is_valid())
- << "Unable to load the mojo_core library. Make sure the library is "
- << "in the working directory or is correctly pointed to by the "
- << "MOJO_CORE_LIBRARY_PATH environment variable.";
- } else {
- CHECK(library_->is_valid())
- << "Unable to locate mojo_core library. This application expects to "
- << "find it at " << library_path->value();
- }
+ base::ScopedNativeLibrary library(base::LoadNativeLibraryWithOptions(
+ library_path, library_options, nullptr));
+ if (!library.is_valid())
+ return MOJO_RESULT_NOT_FOUND;
const char kGetThunksFunctionName[] = "MojoGetSystemThunks";
MojoGetSystemThunksFunction g_get_thunks =
reinterpret_cast<MojoGetSystemThunksFunction>(
- library_->GetFunctionPointer(kGetThunksFunctionName));
- CHECK(g_get_thunks) << "Invalid mojo_core library: "
- << library_path->value();
+ library.GetFunctionPointer(kGetThunksFunctionName));
+ if (!g_get_thunks)
+ return MOJO_RESULT_NOT_FOUND;
DCHECK_EQ(g_thunks.size, 0u);
g_thunks.size = sizeof(g_thunks);
g_get_thunks(&g_thunks);
+ if (g_thunks.size == 0)
+ return MOJO_RESULT_NOT_FOUND;
- CHECK_GT(g_thunks.size, 0u)
- << "Invalid mojo_core library: " << library_path->value();
-#else // defined(OS_CHROMEOS) || defined(OS_LINUX)
- NOTREACHED()
- << "Dynamic mojo_core loading is not supported on this platform.";
-#endif // defined(OS_CHROMEOS) || defined(OS_LINUX)
+ library_ = std::move(library);
+ return MOJO_RESULT_OK;
+#else // defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
+ return MOJO_RESULT_UNIMPLEMENTED;
+#endif // defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
}
- ~CoreLibraryInitializer() = default;
-
private:
#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
base::Optional<base::ScopedNativeLibrary> library_;
#endif
-
- DISALLOW_COPY_AND_ASSIGN(CoreLibraryInitializer);
};
} // namespace mojo
@@ -148,10 +142,22 @@ class CoreLibraryInitializer {
extern "C" {
MojoResult MojoInitialize(const struct MojoInitializeOptions* options) {
- static base::NoDestructor<mojo::CoreLibraryInitializer> initializer(options);
- ALLOW_UNUSED_LOCAL(initializer);
- DCHECK(g_thunks.Initialize);
+ static base::NoDestructor<mojo::CoreLibraryInitializer> initializer;
+
+ base::StringPiece library_path_utf8;
+ if (options) {
+ if (!MOJO_IS_STRUCT_FIELD_PRESENT(options, mojo_core_path_length))
+ return MOJO_RESULT_INVALID_ARGUMENT;
+ library_path_utf8 = base::StringPiece(options->mojo_core_path,
+ options->mojo_core_path_length);
+ }
+
+ MojoResult load_result = initializer->LoadLibrary(
+ base::FilePath::FromUTF8Unsafe(library_path_utf8));
+ if (load_result != MOJO_RESULT_OK)
+ return load_result;
+ DCHECK(g_thunks.Initialize);
return INVOKE_THUNK(Initialize, options);
}
@@ -476,6 +482,12 @@ MojoResult MojoShutdown(const MojoShutdownOptions* options) {
return INVOKE_THUNK(Shutdown, options);
}
+MojoResult MojoSetDefaultProcessErrorHandler(
+ MojoDefaultProcessErrorHandler handler,
+ const struct MojoSetDefaultProcessErrorHandlerOptions* options) {
+ return INVOKE_THUNK(SetDefaultProcessErrorHandler, handler, options);
+}
+
} // extern "C"
void MojoEmbedderSetSystemThunks(const MojoSystemThunks* thunks) {
diff --git a/chromium/mojo/public/c/system/thunks.h b/chromium/mojo/public/c/system/thunks.h
index f3f9742a8bf..4b41b939e24 100644
--- a/chromium/mojo/public/c/system/thunks.h
+++ b/chromium/mojo/public/c/system/thunks.h
@@ -228,6 +228,11 @@ struct MojoSystemThunks {
// Core ABI version 2 additions begin here.
MojoResult (*Shutdown)(const struct MojoShutdownOptions* options);
+
+ // Core ABI version 3 additions begin here.
+ MojoResult (*SetDefaultProcessErrorHandler)(
+ MojoDefaultProcessErrorHandler handler,
+ const struct MojoSetDefaultProcessErrorHandlerOptions* options);
};
#pragma pack(pop)
diff --git a/chromium/mojo/public/c/system/types.h b/chromium/mojo/public/c/system/types.h
index cee529f1dac..bb6504343a7 100644
--- a/chromium/mojo/public/c/system/types.h
+++ b/chromium/mojo/public/c/system/types.h
@@ -147,8 +147,38 @@ typedef uint32_t MojoInitializeFlags;
// process. That process is always the first member of the network and it should
// set this flag during initialization. Attempts to invite a broker process into
// an existing network will always fail.
+//
+// This flag is ignored when |MOJO_INITIALIZE_FLAG_LOAD_ONLY| is set.
#define MOJO_INITIALIZE_FLAG_AS_BROKER ((MojoInitializeFlags)1)
+// Even if not initialized as the broker process, the calling process will be
+// configured for direct shared memory allocation. This can be used for
+// non-broker processes which are still sufficiently privileged to allocate
+// their own shared memory.
+//
+// This flag is ignored when |MOJO_INITIALIZE_FLAG_LOAD_ONLY| is set.
+#define MOJO_INITIALIZE_FLAG_FORCE_DIRECT_SHARED_MEMORY_ALLOCATION \
+ ((MojoInitializeFlags)2)
+
+// This call to |MojoInitialize()| should NOT fully initialize Mojo's internal
+// IPC support engine. Initialization is essentially a two-phase operation:
+// first the library is loaded and its global state is initialized, and then
+// full IPC support is initialized. The latter phase may spawn a background
+// thread, thus making it hostile to certain scenarios (e.g. prior to a fork()
+// on Linux et al); meanwhile the former phase may still need to be completed
+// early, e.g. prior to some sandbox configuration which may precede a fork().
+//
+// Applications wishing to separate initialization into two phases can set
+// this flag during an initial call to |MojoInitialize()|. To subsequently
+// enable use of all Mojo APIs, |MojoInitialize()| must be called another time,
+// without this flag set.
+//
+// Note that various MojoInitializeOptions may be ignored on the second call
+// to |MojoInitialize()|, while others may actually override options passed to
+// the first call. Documentation on individual option fields and flags clarifies
+// this behavior.
+#define MOJO_INITIALIZE_FLAG_LOAD_ONLY ((MojoInitializeFlags)4)
+
// Options passed to |MojoInitialize()|.
struct MOJO_ALIGNAS(8) MojoInitializeOptions {
// The size of this structure, used for versioning.
@@ -161,10 +191,22 @@ struct MOJO_ALIGNAS(8) MojoInitializeOptions {
// to load. If the |mojo_core_path| is null then |mojo_core_path_length| is
// ignored and Mojo will fall back first onto the |MOJO_CORE_LIBRARY_PATH|
// environment variable, and then onto the current working directory.
+ //
+ // NOTE: These fields are only observed during the first successful call to
+ // |MojoInitialize()| in a process.
MOJO_POINTER_FIELD(const char*, mojo_core_path);
uint32_t mojo_core_path_length;
+
+ // For POSIX and Fuchsia systems only, this is the |argc| and |argv| from
+ // the calling process's main() entry point. These fields are ignored on
+ // Windows, but we define them anyway for the sake of ABI consistency.
+ //
+ // NOTE: These fields are only observed during the first successful call to
+ // |MojoInitialize()| within a process.
+ int32_t argc;
+ MOJO_POINTER_FIELD(const char* const*, argv);
};
-MOJO_STATIC_ASSERT(sizeof(struct MojoInitializeOptions) == 24,
+MOJO_STATIC_ASSERT(sizeof(struct MojoInitializeOptions) == 32,
"MojoInitializeOptions has wrong size");
// Flags passed to |MojoShutdown()| via |MojoShutdownOptions|.
diff --git a/chromium/mojo/public/cpp/base/big_buffer.cc b/chromium/mojo/public/cpp/base/big_buffer.cc
index ecd5c0dfe55..59e3039ec29 100644
--- a/chromium/mojo/public/cpp/base/big_buffer.cc
+++ b/chromium/mojo/public/cpp/base/big_buffer.cc
@@ -67,6 +67,10 @@ void TryCreateSharedMemory(
// instead produce an invalid buffer. This will always fail validation on
// the receiving end.
*storage_type = BigBuffer::StorageType::kInvalidBuffer;
+
+ // TODO(crbug.com/1076341): Remove this temporary CHECK to investigate
+ // some bad IPC reports likely caused by this path.
+ CHECK(false);
return;
}
}
diff --git a/chromium/mojo/public/cpp/bindings/README.md b/chromium/mojo/public/cpp/bindings/README.md
index 2c64ec743d8..db9b37d2a64 100644
--- a/chromium/mojo/public/cpp/bindings/README.md
+++ b/chromium/mojo/public/cpp/bindings/README.md
@@ -1139,23 +1139,23 @@ foo->SetBar(std::move(bar));
### Performance considerations
-When using associated interfaces on different sequences than the master sequence
-(where the master interface lives):
+When using associated interfaces on different sequences than the primary
+sequence (where the primary interface lives):
* Sending messages: send happens directly on the calling sequence. So there
isn't sequence hopping.
* Receiving messages: associated interfaces bound on a different sequence from
- the master interface incur an extra sequence hop during dispatch.
+ the primary interface incur an extra sequence hop during dispatch.
Therefore, performance-wise associated interfaces are better suited for
-scenarios where message receiving happens on the master sequence.
+scenarios where message receiving happens on the primary sequence.
### Testing
-Associated interfaces need to be associated with a master interface before
+Associated interfaces need to be associated with a primary interface before
they can be used. This means one end of the associated interface must be sent
-over one end of the master interface, or over one end of another associated
-interface which itself already has a master interface.
+over one end of the primary interface, or over one end of another associated
+interface which itself already has a primary interface.
If you want to test an associated interface endpoint without first
associating it, you can use `AssociatedRemote::BindNewEndpointAndPassDedicatedReceiverForTesting`.
diff --git a/chromium/mojo/public/cpp/bindings/associated_binding.h b/chromium/mojo/public/cpp/bindings/associated_binding.h
index 2c7f8a3f9f7..a0b6eeadc21 100644
--- a/chromium/mojo/public/cpp/bindings/associated_binding.h
+++ b/chromium/mojo/public/cpp/bindings/associated_binding.h
@@ -11,8 +11,8 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/check.h"
#include "base/component_export.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
diff --git a/chromium/mojo/public/cpp/bindings/associated_group_controller.h b/chromium/mojo/public/cpp/bindings/associated_group_controller.h
index 386ebdf8609..6de041783f5 100644
--- a/chromium/mojo/public/cpp/bindings/associated_group_controller.h
+++ b/chromium/mojo/public/cpp/bindings/associated_group_controller.h
@@ -38,7 +38,7 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) AssociatedGroupController
// Creates an interface endpoint handle from a given interface ID. The handle
// joins this associated group.
// Typically, this method is used to (1) create an endpoint handle for the
- // master interface; or (2) create an endpoint handle on receiving an
+ // primary interface; or (2) create an endpoint handle on receiving an
// interface ID from the message pipe.
//
// On failure, the method returns an invalid handle. Usually that is because
diff --git a/chromium/mojo/public/cpp/bindings/associated_interface_ptr.h b/chromium/mojo/public/cpp/bindings/associated_interface_ptr.h
index f027f9ea2b1..956138c4277 100644
--- a/chromium/mojo/public/cpp/bindings/associated_interface_ptr.h
+++ b/chromium/mojo/public/cpp/bindings/associated_interface_ptr.h
@@ -12,8 +12,8 @@
#include <utility>
#include "base/callback.h"
+#include "base/check.h"
#include "base/component_export.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
diff --git a/chromium/mojo/public/cpp/bindings/associated_receiver.h b/chromium/mojo/public/cpp/bindings/associated_receiver.h
index 2087f4e4cde..f2857dcaa44 100644
--- a/chromium/mojo/public/cpp/bindings/associated_receiver.h
+++ b/chromium/mojo/public/cpp/bindings/associated_receiver.h
@@ -8,8 +8,8 @@
#include <memory>
#include <utility>
+#include "base/check.h"
#include "base/compiler_specific.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequenced_task_runner.h"
diff --git a/chromium/mojo/public/cpp/bindings/associated_remote.h b/chromium/mojo/public/cpp/bindings/associated_remote.h
index 9aa834c11fd..32b010c61c9 100644
--- a/chromium/mojo/public/cpp/bindings/associated_remote.h
+++ b/chromium/mojo/public/cpp/bindings/associated_remote.h
@@ -9,8 +9,8 @@
#include <utility>
#include "base/callback_forward.h"
+#include "base/check.h"
#include "base/compiler_specific.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequenced_task_runner.h"
diff --git a/chromium/mojo/public/cpp/bindings/binding.h b/chromium/mojo/public/cpp/bindings/binding.h
index bd650c79a40..4993de731f6 100644
--- a/chromium/mojo/public/cpp/bindings/binding.h
+++ b/chromium/mojo/public/cpp/bindings/binding.h
@@ -138,11 +138,10 @@ class Binding {
// true if a method was successfully read and dispatched.
//
// This method may only be called if the object has been bound to a message
- // pipe. This returns once a message is received either on the master
+ // pipe. This returns once a message is received either on the primary
// interface or any associated interfaces.
- bool WaitForIncomingMethodCall(
- MojoDeadline deadline = MOJO_DEADLINE_INDEFINITE) {
- return internal_state_.WaitForIncomingMethodCall(deadline);
+ bool WaitForIncomingMethodCall() {
+ return internal_state_.WaitForIncomingMethodCall();
}
// Closes the message pipe that was previously bound. Put this object into a
diff --git a/chromium/mojo/public/cpp/bindings/connector.h b/chromium/mojo/public/cpp/bindings/connector.h
index 91dd4655b6a..16e478c9ebd 100644
--- a/chromium/mojo/public/cpp/bindings/connector.h
+++ b/chromium/mojo/public/cpp/bindings/connector.h
@@ -161,10 +161,10 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) Connector : public MessageReceiver {
// be added to the same group.
void SetConnectionGroup(ConnectionGroup::Ref ref);
- // Waits for the next message on the pipe, blocking until one arrives,
- // |deadline| elapses, or an error happens. Returns |true| if a message has
- // been delivered, |false| otherwise.
- bool WaitForIncomingMessage(MojoDeadline deadline);
+ // Waits for the next message on the pipe, blocking until one arrives or an
+ // error happens. Returns |true| if a message has been delivered, |false|
+ // otherwise.
+ bool WaitForIncomingMessage();
// See Binding for details of pause/resume.
void PauseIncomingMethodCallProcessing();
diff --git a/chromium/mojo/public/cpp/bindings/interface_endpoint_client.h b/chromium/mojo/public/cpp/bindings/interface_endpoint_client.h
index d2e1d0574f5..c8065924b2e 100644
--- a/chromium/mojo/public/cpp/bindings/interface_endpoint_client.h
+++ b/chromium/mojo/public/cpp/bindings/interface_endpoint_client.h
@@ -12,10 +12,10 @@
#include <utility>
#include "base/callback.h"
+#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/component_export.h"
#include "base/location.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
diff --git a/chromium/mojo/public/cpp/bindings/interface_id.h b/chromium/mojo/public/cpp/bindings/interface_id.h
index d6128537d20..8760fea068f 100644
--- a/chromium/mojo/public/cpp/bindings/interface_id.h
+++ b/chromium/mojo/public/cpp/bindings/interface_id.h
@@ -14,16 +14,16 @@ using InterfaceId = uint32_t;
// IDs of associated interface can be generated at both sides of the message
// pipe. In order to avoid collision, the highest bit is used as namespace bit:
-// at the side where the client-side of the master interface lives, IDs are
+// at the side where the client-side of the primary interface lives, IDs are
// generated with the namespace bit set to 1; at the opposite side IDs are
// generated with the namespace bit set to 0.
const uint32_t kInterfaceIdNamespaceMask = 0x80000000;
-const InterfaceId kMasterInterfaceId = 0x00000000;
+const InterfaceId kPrimaryInterfaceId = 0x00000000;
const InterfaceId kInvalidInterfaceId = 0xFFFFFFFF;
-inline bool IsMasterInterfaceId(InterfaceId id) {
- return id == kMasterInterfaceId;
+inline bool IsPrimaryInterfaceId(InterfaceId id) {
+ return id == kPrimaryInterfaceId;
}
inline bool IsValidInterfaceId(InterfaceId id) {
diff --git a/chromium/mojo/public/cpp/bindings/interface_ptr.h b/chromium/mojo/public/cpp/bindings/interface_ptr.h
index 4f10be5acc5..6745a32b530 100644
--- a/chromium/mojo/public/cpp/bindings/interface_ptr.h
+++ b/chromium/mojo/public/cpp/bindings/interface_ptr.h
@@ -12,7 +12,7 @@
#include <utility>
#include "base/callback_forward.h"
-#include "base/logging.h"
+#include "base/check.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
diff --git a/chromium/mojo/public/cpp/bindings/interface_request.h b/chromium/mojo/public/cpp/bindings/interface_request.h
index 0b9fd64b193..3e44bfba2a7 100644
--- a/chromium/mojo/public/cpp/bindings/interface_request.h
+++ b/chromium/mojo/public/cpp/bindings/interface_request.h
@@ -80,7 +80,7 @@ class InterfaceRequest {
Message message =
PipeControlMessageProxy::ConstructPeerEndpointClosedMessage(
- kMasterInterfaceId, DisconnectReason(custom_reason, description));
+ kPrimaryInterfaceId, DisconnectReason(custom_reason, description));
MojoResult result =
WriteMessageNew(state_.pipe.get(), message.TakeMojoMessage(),
MOJO_WRITE_MESSAGE_FLAG_NONE);
diff --git a/chromium/mojo/public/cpp/bindings/lib/array_internal.h b/chromium/mojo/public/cpp/bindings/lib/array_internal.h
index e34349f2a72..cb8c5b30907 100644
--- a/chromium/mojo/public/cpp/bindings/lib/array_internal.h
+++ b/chromium/mojo/public/cpp/bindings/lib/array_internal.h
@@ -11,8 +11,8 @@
#include <limits>
#include <new>
+#include "base/check.h"
#include "base/component_export.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "mojo/public/c/system/macros.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
diff --git a/chromium/mojo/public/cpp/bindings/lib/binding_state.cc b/chromium/mojo/public/cpp/bindings/lib/binding_state.cc
index f0eab656f1e..ecfe41c4652 100644
--- a/chromium/mojo/public/cpp/bindings/lib/binding_state.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/binding_state.cc
@@ -36,9 +36,9 @@ void BindingStateBase::ResumeIncomingMethodCallProcessing() {
router_->ResumeIncomingMethodCallProcessing();
}
-bool BindingStateBase::WaitForIncomingMethodCall(MojoDeadline deadline) {
+bool BindingStateBase::WaitForIncomingMethodCall() {
DCHECK(router_);
- return router_->WaitForIncomingMessage(deadline);
+ return router_->WaitForIncomingMessage();
}
void BindingStateBase::PauseRemoteCallbacksUntilFlushCompletes(
@@ -121,11 +121,11 @@ void BindingStateBase::BindInternal(
: MultiplexRouter::SINGLE_INTERFACE);
router_ = new MultiplexRouter(std::move(receiver_state->pipe), config, false,
sequenced_runner);
- router_->SetMasterInterfaceName(interface_name);
+ router_->SetPrimaryInterfaceName(interface_name);
router_->SetConnectionGroup(std::move(receiver_state->connection_group));
endpoint_client_.reset(new InterfaceEndpointClient(
- router_->CreateLocalEndpointHandle(kMasterInterfaceId), stub,
+ router_->CreateLocalEndpointHandle(kPrimaryInterfaceId), stub,
std::move(request_validator), has_sync_methods,
std::move(sequenced_runner), interface_version, interface_name));
endpoint_client_->SetIdleTrackingEnabledCallback(
diff --git a/chromium/mojo/public/cpp/bindings/lib/binding_state.h b/chromium/mojo/public/cpp/bindings/lib/binding_state.h
index cadb81a7fa6..598668482ff 100644
--- a/chromium/mojo/public/cpp/bindings/lib/binding_state.h
+++ b/chromium/mojo/public/cpp/bindings/lib/binding_state.h
@@ -11,8 +11,8 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/check.h"
#include "base/component_export.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
@@ -48,8 +48,7 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) BindingStateBase {
void PauseIncomingMethodCallProcessing();
void ResumeIncomingMethodCallProcessing();
- bool WaitForIncomingMethodCall(
- MojoDeadline deadline = MOJO_DEADLINE_INDEFINITE);
+ bool WaitForIncomingMethodCall();
void PauseRemoteCallbacksUntilFlushCompletes(PendingFlush flush);
void FlushAsync(AsyncFlusher flusher);
diff --git a/chromium/mojo/public/cpp/bindings/lib/connector.cc b/chromium/mojo/public/cpp/bindings/lib/connector.cc
index 5c92e2d65ba..c342d655d29 100644
--- a/chromium/mojo/public/cpp/bindings/lib/connector.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/connector.cc
@@ -229,7 +229,7 @@ void Connector::SetConnectionGroup(ConnectionGroup::Ref ref) {
connection_group_ = std::move(ref);
}
-bool Connector::WaitForIncomingMessage(MojoDeadline deadline) {
+bool Connector::WaitForIncomingMessage() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (error_)
@@ -237,23 +237,13 @@ bool Connector::WaitForIncomingMessage(MojoDeadline deadline) {
ResumeIncomingMethodCallProcessing();
- // TODO(rockot): Use a timed Wait here. Nobody uses anything but 0 or
- // INDEFINITE deadlines at present, so we only support those.
- DCHECK(deadline == 0 || deadline == MOJO_DEADLINE_INDEFINITE);
-
- MojoResult rv = MOJO_RESULT_UNKNOWN;
- if (deadline == 0 && !message_pipe_->QuerySignalsState().readable())
+ MojoResult rv = Wait(message_pipe_.get(), MOJO_HANDLE_SIGNAL_READABLE);
+ if (rv != MOJO_RESULT_OK) {
+ // Users that call WaitForIncomingMessage() should expect their code to be
+ // re-entered, so we call the error handler synchronously.
+ HandleError(rv != MOJO_RESULT_FAILED_PRECONDITION /* force_pipe_reset */,
+ false /* force_async_handler */);
return false;
-
- if (deadline == MOJO_DEADLINE_INDEFINITE) {
- rv = Wait(message_pipe_.get(), MOJO_HANDLE_SIGNAL_READABLE);
- if (rv != MOJO_RESULT_OK) {
- // Users that call WaitForIncomingMessage() should expect their code to be
- // re-entered, so we call the error handler synchronously.
- HandleError(rv != MOJO_RESULT_FAILED_PRECONDITION /* force_pipe_reset */,
- false /* force_async_handler */);
- return false;
- }
}
Message message;
@@ -505,9 +495,9 @@ bool Connector::DispatchMessage(Message message) {
incoming_serialization_mode_);
}
- TRACE_EVENT_WITH_FLOW0(
- TRACE_DISABLED_BY_DEFAULT("toplevel.flow"), "mojo::Message Receive",
- MANGLE_MESSAGE_ID(message.header()->trace_id), TRACE_EVENT_FLAG_FLOW_IN);
+ TRACE_EVENT_WITH_FLOW0("toplevel.flow", "mojo::Message Receive",
+ MANGLE_MESSAGE_ID(message.header()->trace_id),
+ TRACE_EVENT_FLAG_FLOW_IN);
#if !BUILDFLAG(MOJO_TRACE_ENABLED)
// This emits just full class name, and is inferior to mojo tracing.
TRACE_EVENT0("mojom", heap_profiler_tag_);
diff --git a/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.cc b/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.cc
index 348c63d7c16..bd363911483 100644
--- a/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.cc
@@ -92,7 +92,7 @@ bool InterfacePtrStateBase::InitializeEndpointClient(
DCHECK(runner_->RunsTasksInCurrentSequence());
router_ = new MultiplexRouter(std::move(handle_), config, true, runner_);
endpoint_client_.reset(new InterfaceEndpointClient(
- router_->CreateLocalEndpointHandle(kMasterInterfaceId), nullptr,
+ router_->CreateLocalEndpointHandle(kPrimaryInterfaceId), nullptr,
std::move(payload_validator), false, std::move(runner_),
// The version is only queried from the client so the value passed here
// will not be used.
diff --git a/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.h b/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.h
index 0d259f37a2f..d1e37115f90 100644
--- a/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.h
+++ b/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.h
@@ -14,9 +14,9 @@
#include "base/bind.h"
#include "base/callback_forward.h"
+#include "base/check_op.h"
#include "base/component_export.h"
#include "base/location.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
@@ -260,7 +260,7 @@ class InterfacePtrState : public InterfacePtrStateBase {
Interface::PassesAssociatedKinds_, Interface::HasSyncMethods_,
std::make_unique<typename Interface::ResponseValidator_>(),
Interface::Name_)) {
- router()->SetMasterInterfaceName(Interface::Name_);
+ router()->SetPrimaryInterfaceName(Interface::Name_);
proxy_ = std::make_unique<Proxy>(endpoint_client());
}
}
diff --git a/chromium/mojo/public/cpp/bindings/lib/message.cc b/chromium/mojo/public/cpp/bindings/lib/message.cc
index 7b8e92ecbf7..893ec949fbc 100644
--- a/chromium/mojo/public/cpp/bindings/lib/message.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/message.cc
@@ -102,8 +102,8 @@ void CreateSerializedMessageObject(uint32_t name,
std::vector<ScopedHandle>* handles,
ScopedMessageHandle* out_handle,
internal::Buffer* out_buffer) {
- TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
- "mojo::Message Send", MANGLE_MESSAGE_ID(trace_id),
+ TRACE_EVENT_WITH_FLOW0("toplevel.flow", "mojo::Message Send",
+ MANGLE_MESSAGE_ID(trace_id),
TRACE_EVENT_FLAG_FLOW_OUT);
ScopedMessageHandle handle;
@@ -148,8 +148,8 @@ void SerializeUnserializedContext(MojoMessageHandle message,
reinterpret_cast<internal::UnserializedMessageContext*>(context_value);
uint32_t trace_id = GetTraceId(context);
- TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
- "mojo::Message Send", MANGLE_MESSAGE_ID(trace_id),
+ TRACE_EVENT_WITH_FLOW0("toplevel.flow", "mojo::Message Send",
+ MANGLE_MESSAGE_ID(trace_id),
TRACE_EVENT_FLAG_FLOW_OUT);
void* buffer;
diff --git a/chromium/mojo/public/cpp/bindings/lib/message_header_validator.cc b/chromium/mojo/public/cpp/bindings/lib/message_header_validator.cc
index 25a651e4b45..e4f8a4905cd 100644
--- a/chromium/mojo/public/cpp/bindings/lib/message_header_validator.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/message_header_validator.cc
@@ -90,7 +90,7 @@ bool IsValidMessageHeader(const internal::MessageHeader* header,
size_t num_ids = header_v2->payload_interface_ids.Get()->size();
const uint32_t* ids = header_v2->payload_interface_ids.Get()->storage();
for (size_t i = 0; i < num_ids; ++i) {
- if (!IsValidInterfaceId(ids[i]) || IsMasterInterfaceId(ids[i])) {
+ if (!IsValidInterfaceId(ids[i]) || IsPrimaryInterfaceId(ids[i])) {
internal::ReportValidationError(
validation_context,
internal::VALIDATION_ERROR_ILLEGAL_INTERFACE_ID);
diff --git a/chromium/mojo/public/cpp/bindings/lib/message_quota_checker.h b/chromium/mojo/public/cpp/bindings/lib/message_quota_checker.h
index 071853640a6..37955350905 100644
--- a/chromium/mojo/public/cpp/bindings/lib/message_quota_checker.h
+++ b/chromium/mojo/public/cpp/bindings/lib/message_quota_checker.h
@@ -31,10 +31,10 @@ namespace internal {
// outgoing queue. Additionally, |BeforeWrite()| should be called immediately
// before writing each message to the corresponding message pipe.
//
-// Also note that messages posted to a different sequence with
-// |base::PostTask()| and the like, need to be treated as locally queued. Task
-// queues can grow arbitrarily long, and it's ideal to perform unread quota
-// checks before posting.
+// Also note that messages posted to a different sequence with base::ThreadPool
+// and the like, need to be treated as locally queued. Task queues can grow
+// arbitrarily long, and it's ideal to perform unread quota checks before
+// posting.
//
// Either |BeforeMessagesEnqueued()| or |BeforeWrite()| may cause the quota
// to be exceeded, thus invoking the |maybe_crash_function| set in this
diff --git a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc
index 4a825fd6a71..08da6c26ded 100644
--- a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc
@@ -369,12 +369,12 @@ void MultiplexRouter::SetIncomingMessageFilter(
dispatcher_.SetFilter(std::move(filter));
}
-void MultiplexRouter::SetMasterInterfaceName(const char* name) {
+void MultiplexRouter::SetPrimaryInterfaceName(const char* name) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
header_validator_->SetDescription(std::string(name) +
- " [master] MessageHeaderValidator");
+ " [primary] MessageHeaderValidator");
control_message_handler_.SetDescription(
- std::string(name) + " [master] PipeControlMessageHandler");
+ std::string(name) + " [primary] PipeControlMessageHandler");
connector_.SetWatcherHeapProfilerTag(name);
}
@@ -454,7 +454,7 @@ void MultiplexRouter::CloseEndpointHandle(
DCHECK(!endpoint->closed());
UpdateEndpointStateMayRemove(endpoint, ENDPOINT_CLOSED);
- if (!IsMasterInterfaceId(id) || reason) {
+ if (!IsPrimaryInterfaceId(id) || reason) {
MayAutoUnlock unlocker(&lock_);
control_message_proxy_.NotifyPeerEndpointClosed(id, reason);
}
@@ -575,7 +575,7 @@ bool MultiplexRouter::HasAssociatedEndpoints() const {
if (endpoints_.size() == 0)
return false;
- return !base::Contains(endpoints_, kMasterInterfaceId);
+ return !base::Contains(endpoints_, kPrimaryInterfaceId);
}
void MultiplexRouter::EnableBatchDispatch() {
@@ -674,7 +674,7 @@ bool MultiplexRouter::OnPeerAssociatedEndpointClosed(
bool MultiplexRouter::WaitForFlushToComplete(ScopedMessagePipeHandle pipe) {
// If this MultiplexRouter has an associated interface on some task runner
- // other than the master interface's task runner, it is possible to process
+ // other than the primary interface's task runner, it is possible to process
// incoming control messages on that task runner. We don't support this
// control message on anything but the main interface though.
if (!task_runner_->RunsTasksInCurrentSequence())
@@ -1048,7 +1048,7 @@ bool MultiplexRouter::InsertEndpointsForMessage(const Message& message) {
MayAutoLock locker(&lock_);
for (uint32_t i = 0; i < num_ids; ++i) {
// Message header validation already ensures that the IDs are valid and not
- // the master ID.
+ // the primary ID.
// The IDs are from the remote side and therefore their namespace bit is
// supposed to be different than the value that this router would use.
if (set_interface_id_namespace_bit_ ==
diff --git a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h
index 3063ec49703..16128e880b0 100644
--- a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h
+++ b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h
@@ -11,11 +11,11 @@
#include <memory>
#include <string>
+#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/component_export.h"
#include "base/containers/queue.h"
#include "base/containers/small_map.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
@@ -47,7 +47,7 @@ namespace internal {
// MultiplexRouter supports routing messages for multiple interfaces over a
// single message pipe.
//
-// It is created on the sequence where the master interface of the message pipe
+// It is created on the sequence where the primary interface of the message pipe
// lives.
// Some public methods are only allowed to be called on the creating sequence;
// while the others are safe to call from any sequence. Please see the method
@@ -61,14 +61,14 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) MultiplexRouter
public PipeControlMessageHandlerDelegate {
public:
enum Config {
- // There is only the master interface running on this router. Please note
+ // There is only the primary interface running on this router. Please note
// that because of interface versioning, the other side of the message pipe
- // may use a newer master interface definition which passes associated
+ // may use a newer primary interface definition which passes associated
// interfaces. In that case, this router may still receive pipe control
// messages or messages targetting associated interfaces.
SINGLE_INTERFACE,
- // Similar to the mode above, there is only the master interface running on
- // this router. Besides, the master interface has sync methods.
+ // Similar to the mode above, there is only the primary interface running on
+ // this router. Besides, the primary interface has sync methods.
SINGLE_INTERFACE_WITH_SYNC_METHODS,
// There may be associated interfaces running on this router.
MULTI_INTERFACE
@@ -85,10 +85,10 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) MultiplexRouter
// before dispatch.
void SetIncomingMessageFilter(std::unique_ptr<MessageFilter> filter);
- // Sets the master interface name for this router. Only used when reporting
+ // Sets the primary interface name for this router. Only used when reporting
// message header or control message validation errors.
// |name| must be a string literal.
- void SetMasterInterfaceName(const char* name);
+ void SetPrimaryInterfaceName(const char* name);
// Adds this object to a ConnectionGroup identified by |ref|. All receiving
// pipe endpoints decoded from inbound messages on this MultiplexRouter will
@@ -130,11 +130,10 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) MultiplexRouter
return connector_.PassMessagePipe();
}
- // Blocks the current sequence until the first incoming message, or
- // |deadline|.
- bool WaitForIncomingMessage(MojoDeadline deadline) {
+ // Blocks the current sequence until the first incoming message.
+ bool WaitForIncomingMessage() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return connector_.WaitForIncomingMessage(deadline);
+ return connector_.WaitForIncomingMessage();
}
// See Binding for details of pause/resume.
diff --git a/chromium/mojo/public/cpp/bindings/lib/native_enum_serialization.h b/chromium/mojo/public/cpp/bindings/lib/native_enum_serialization.h
index 4faf957c58e..6cd8c7f90fb 100644
--- a/chromium/mojo/public/cpp/bindings/lib/native_enum_serialization.h
+++ b/chromium/mojo/public/cpp/bindings/lib/native_enum_serialization.h
@@ -10,7 +10,7 @@
#include <type_traits>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/pickle.h"
#include "ipc/ipc_param_traits.h"
#include "mojo/public/cpp/bindings/lib/serialization_forward.h"
diff --git a/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.h b/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.h
index 5e2be21c981..41abb228c4f 100644
--- a/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.h
+++ b/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.h
@@ -10,8 +10,8 @@
#include <limits>
+#include "base/check_op.h"
#include "base/component_export.h"
-#include "base/logging.h"
#include "base/pickle.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_param_traits.h"
diff --git a/chromium/mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc b/chromium/mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc
index c443c65cf55..1d9178799df 100644
--- a/chromium/mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc
@@ -99,6 +99,8 @@ class SequenceLocalSyncEventWatcher::SequenceLocalState {
{
base::AutoLock lock(ready_watchers_lock_);
ready_watchers_.erase(iter->first);
+ if (ready_watchers_.empty())
+ event_.Reset();
}
registered_watchers_.erase(iter);
@@ -206,8 +208,10 @@ void SequenceLocalSyncEventWatcher::SequenceLocalState::OnEventSignaled() {
base::AutoLock lock(ready_watchers_lock_);
std::swap(ready_watchers_, ready_watchers);
}
- if (ready_watchers.empty())
+ if (ready_watchers.empty()) {
+ event_.Reset();
return;
+ }
auto weak_self = weak_ptr_factory_.GetWeakPtr();
for (auto* watcher : ready_watchers) {
diff --git a/chromium/mojo/public/cpp/bindings/map_data_view.h b/chromium/mojo/public/cpp/bindings/map_data_view.h
index a65bb9eca14..5743829eeec 100644
--- a/chromium/mojo/public/cpp/bindings/map_data_view.h
+++ b/chromium/mojo/public/cpp/bindings/map_data_view.h
@@ -5,7 +5,7 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_MAP_DATA_VIEW_H_
#define MOJO_PUBLIC_CPP_BINDINGS_MAP_DATA_VIEW_H_
-#include "base/logging.h"
+#include "base/check_op.h"
#include "mojo/public/cpp/bindings/array_data_view.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
#include "mojo/public/cpp/bindings/lib/map_data_internal.h"
diff --git a/chromium/mojo/public/cpp/bindings/message.h b/chromium/mojo/public/cpp/bindings/message.h
index 8dbb3df8875..8099cd4305b 100644
--- a/chromium/mojo/public/cpp/bindings/message.h
+++ b/chromium/mojo/public/cpp/bindings/message.h
@@ -14,10 +14,10 @@
#include <vector>
#include "base/callback.h"
+#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/component_export.h"
#include "base/containers/span.h"
-#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/lib/buffer.h"
diff --git a/chromium/mojo/public/cpp/bindings/pending_remote.h b/chromium/mojo/public/cpp/bindings/pending_remote.h
index e67dd1a6691..64c9ab90653 100644
--- a/chromium/mojo/public/cpp/bindings/pending_remote.h
+++ b/chromium/mojo/public/cpp/bindings/pending_remote.h
@@ -9,8 +9,8 @@
#include <type_traits>
#include <utility>
+#include "base/check.h"
#include "base/compiler_specific.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/interface_ptr_info.h"
diff --git a/chromium/mojo/public/cpp/bindings/receiver.h b/chromium/mojo/public/cpp/bindings/receiver.h
index 045bd3e5dbc..6f8b9976581 100644
--- a/chromium/mojo/public/cpp/bindings/receiver.h
+++ b/chromium/mojo/public/cpp/bindings/receiver.h
@@ -8,8 +8,8 @@
#include <memory>
#include <utility>
+#include "base/check.h"
#include "base/compiler_specific.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequenced_task_runner.h"
@@ -204,7 +204,7 @@ class Receiver {
// Blocks the calling thread until a new message arrives and is dispatched
// to the bound implementation.
bool WaitForIncomingCall() {
- return internal_state_.WaitForIncomingMethodCall(MOJO_DEADLINE_INDEFINITE);
+ return internal_state_.WaitForIncomingMethodCall();
}
// Pauses the Remote endpoint, stopping dispatch of callbacks on that end. Any
diff --git a/chromium/mojo/public/cpp/bindings/remote.h b/chromium/mojo/public/cpp/bindings/remote.h
index 45615bfb930..d71d2037141 100644
--- a/chromium/mojo/public/cpp/bindings/remote.h
+++ b/chromium/mojo/public/cpp/bindings/remote.h
@@ -9,8 +9,8 @@
#include <utility>
#include "base/callback_forward.h"
+#include "base/check.h"
#include "base/compiler_specific.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequenced_task_runner.h"
diff --git a/chromium/mojo/public/cpp/bindings/strong_associated_binding.h b/chromium/mojo/public/cpp/bindings/strong_associated_binding.h
index 0bb340c7d11..7425e87f2e4 100644
--- a/chromium/mojo/public/cpp/bindings/strong_associated_binding.h
+++ b/chromium/mojo/public/cpp/bindings/strong_associated_binding.h
@@ -11,7 +11,7 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/logging.h"
+#include "base/check.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
diff --git a/chromium/mojo/public/cpp/bindings/strong_associated_binding_set.h b/chromium/mojo/public/cpp/bindings/strong_associated_binding_set.h
deleted file mode 100644
index 8c769698ba3..00000000000
--- a/chromium/mojo/public/cpp/bindings/strong_associated_binding_set.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_STRONG_ASSOCIATED_BINDING_SET_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_STRONG_ASSOCIATED_BINDING_SET_H_
-
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "mojo/public/cpp/bindings/associated_binding_set.h"
-#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
-#include "mojo/public/cpp/bindings/associated_interface_request.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/unique_ptr_impl_ref_traits.h"
-
-namespace mojo {
-
-template <typename Interface, typename ContextType = void>
-using StrongAssociatedBindingSet = BindingSetBase<
- Interface,
- AssociatedBinding<Interface, UniquePtrImplRefTraits<Interface>>,
- ContextType>;
-
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_STRONG_ASSOCIATED_BINDING_SET_H_
diff --git a/chromium/mojo/public/cpp/bindings/strong_binding.h b/chromium/mojo/public/cpp/bindings/strong_binding.h
index b1160453a96..e3940fba4b5 100644
--- a/chromium/mojo/public/cpp/bindings/strong_binding.h
+++ b/chromium/mojo/public/cpp/bindings/strong_binding.h
@@ -11,7 +11,7 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/logging.h"
+#include "base/check.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "mojo/public/cpp/bindings/binding.h"
diff --git a/chromium/mojo/public/cpp/bindings/struct_ptr.h b/chromium/mojo/public/cpp/bindings/struct_ptr.h
index 93431740434..ea2f52ea878 100644
--- a/chromium/mojo/public/cpp/bindings/struct_ptr.h
+++ b/chromium/mojo/public/cpp/bindings/struct_ptr.h
@@ -10,7 +10,7 @@
#include <memory>
#include <new>
-#include "base/logging.h"
+#include "base/check.h"
#include "base/macros.h"
#include "base/optional.h"
#include "mojo/public/cpp/bindings/lib/hash_util.h"
diff --git a/chromium/mojo/public/cpp/bindings/sync_call_restrictions.h b/chromium/mojo/public/cpp/bindings/sync_call_restrictions.h
index 60e11492057..599d24e260a 100644
--- a/chromium/mojo/public/cpp/bindings/sync_call_restrictions.h
+++ b/chromium/mojo/public/cpp/bindings/sync_call_restrictions.h
@@ -15,6 +15,10 @@
#define ENABLE_SYNC_CALL_RESTRICTIONS 0
#endif
+namespace chromecast {
+class CastCdmOriginProvider;
+} // namespace chromecast
+
namespace sync_preferences {
class PrefServiceSyncable;
}
@@ -82,6 +86,11 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) SyncCallRestrictions {
// For preventing frame swaps of wrong size during resize on Windows.
// (https://crbug.com/811945)
friend class ui::Compositor;
+ // For calling sync mojo API to get cdm origin. The service and the client are
+ // running in the same process, so it won't block anything.
+ // TODO(159346933) Remove once the origin isolation logic is moved outside of
+ // cast media service.
+ friend class chromecast::CastCdmOriginProvider;
// END ALLOWED USAGE.
#if ENABLE_SYNC_CALL_RESTRICTIONS
diff --git a/chromium/mojo/public/cpp/bindings/sync_handle_watcher.h b/chromium/mojo/public/cpp/bindings/sync_handle_watcher.h
index f75e1e232af..5ed7e7b827e 100644
--- a/chromium/mojo/public/cpp/bindings/sync_handle_watcher.h
+++ b/chromium/mojo/public/cpp/bindings/sync_handle_watcher.h
@@ -22,7 +22,7 @@ namespace mojo {
// SyncHandleWatcher is used for sync methods. While a sync call is waiting for
// response, we would like to block the sequence. On the other hand, we need
// incoming sync method requests on the same sequence to be able to reenter. We
-// also need master interface endpoints to continue dispatching messages for
+// also need primary interface endpoints to continue dispatching messages for
// associated endpoints on different sequence.
//
// This class is not thread safe.
diff --git a/chromium/mojo/public/cpp/bindings/tests/BUILD.gn b/chromium/mojo/public/cpp/bindings/tests/BUILD.gn
index 6fb6542728a..16674cc3366 100644
--- a/chromium/mojo/public/cpp/bindings/tests/BUILD.gn
+++ b/chromium/mojo/public/cpp/bindings/tests/BUILD.gn
@@ -67,7 +67,6 @@ source_set("tests") {
":test_extra_cpp_template_mojom",
":test_mojom",
"//base/test:test_support",
- "//mojo/core/embedder",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
"//mojo/public/cpp/test_support:test_utils",
@@ -197,7 +196,10 @@ source_set("mojo_public_bindings_test_utils") {
"validation_test_input_parser.h",
]
- deps = [ "//mojo/public/c/system" ]
+ deps = [
+ "//base",
+ "//mojo/public/c/system",
+ ]
}
action("generate_test_mojom") {
diff --git a/chromium/mojo/public/cpp/platform/platform_channel.cc b/chromium/mojo/public/cpp/platform/platform_channel.cc
index 3320bcce7eb..140fb8bf965 100644
--- a/chromium/mojo/public/cpp/platform/platform_channel.cc
+++ b/chromium/mojo/public/cpp/platform/platform_channel.cc
@@ -337,4 +337,10 @@ PlatformChannelEndpoint PlatformChannel::RecoverPassedEndpointFromCommandLine(
command_line.GetSwitchValueASCII(kHandleSwitch));
}
+// static
+bool PlatformChannel::CommandLineHasPassedEndpoint(
+ const base::CommandLine& command_line) {
+ return command_line.HasSwitch(kHandleSwitch);
+}
+
} // namespace mojo
diff --git a/chromium/mojo/public/cpp/platform/platform_channel.h b/chromium/mojo/public/cpp/platform/platform_channel.h
index 01d3ae19390..c7ef7badb8a 100644
--- a/chromium/mojo/public/cpp/platform/platform_channel.h
+++ b/chromium/mojo/public/cpp/platform/platform_channel.h
@@ -107,6 +107,10 @@ class COMPONENT_EXPORT(MOJO_CPP_PLATFORM) PlatformChannel {
static PlatformChannelEndpoint RecoverPassedEndpointFromCommandLine(
const base::CommandLine& command_line) WARN_UNUSED_RESULT;
+ // Indicates whether |RecoverPassedEndpointFromCommandLine()| would succeed.
+ static bool CommandLineHasPassedEndpoint(
+ const base::CommandLine& command_line);
+
private:
PlatformChannelEndpoint local_endpoint_;
PlatformChannelEndpoint remote_endpoint_;
diff --git a/chromium/mojo/public/cpp/platform/platform_handle.h b/chromium/mojo/public/cpp/platform/platform_handle.h
index 0e01be2cfa7..338b992a2d0 100644
--- a/chromium/mojo/public/cpp/platform/platform_handle.h
+++ b/chromium/mojo/public/cpp/platform/platform_handle.h
@@ -5,9 +5,9 @@
#ifndef MOJO_PUBLIC_CPP_PLATFORM_PLATFORM_HANDLE_H_
#define MOJO_PUBLIC_CPP_PLATFORM_PLATFORM_HANDLE_H_
+#include "base/check_op.h"
#include "base/component_export.h"
#include "base/files/platform_file.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "build/build_config.h"
#include "mojo/public/c/system/platform_handle.h"
diff --git a/chromium/mojo/public/cpp/platform/socket_utils_posix.cc b/chromium/mojo/public/cpp/platform/socket_utils_posix.cc
index 6199a36a69e..b135da1a4e8 100644
--- a/chromium/mojo/public/cpp/platform/socket_utils_posix.cc
+++ b/chromium/mojo/public/cpp/platform/socket_utils_posix.cc
@@ -14,6 +14,7 @@
#include "base/files/file_util.h"
#include "base/logging.h"
+#include "base/notreached.h"
#include "base/posix/eintr_wrapper.h"
#include "build/build_config.h"
diff --git a/chromium/mojo/public/cpp/platform/socket_utils_posix.h b/chromium/mojo/public/cpp/platform/socket_utils_posix.h
index 9e53d058127..3da31cc77e7 100644
--- a/chromium/mojo/public/cpp/platform/socket_utils_posix.h
+++ b/chromium/mojo/public/cpp/platform/socket_utils_posix.h
@@ -13,7 +13,6 @@
#include "base/component_export.h"
#include "base/files/platform_file.h"
#include "base/files/scoped_file.h"
-#include "base/logging.h"
#include "base/macros.h"
struct iovec; // Declared in <sys/uio.h>
diff --git a/chromium/mojo/public/cpp/system/BUILD.gn b/chromium/mojo/public/cpp/system/BUILD.gn
index 8608e7b8f0d..7f8eaefbb1f 100644
--- a/chromium/mojo/public/cpp/system/BUILD.gn
+++ b/chromium/mojo/public/cpp/system/BUILD.gn
@@ -17,10 +17,13 @@ component("system") {
"data_pipe_producer.h",
"data_pipe_utils.cc",
"data_pipe_utils.h",
+ "dynamic_library_support.cc",
+ "dynamic_library_support.h",
"file_data_source.cc",
"file_data_source.h",
"filtered_data_source.cc",
"filtered_data_source.h",
+ "functions.cc",
"functions.h",
"handle.h",
"handle_signal_tracker.cc",
diff --git a/chromium/mojo/public/cpp/system/buffer.h b/chromium/mojo/public/cpp/system/buffer.h
index e20a8fe14d9..9b8700badf8 100644
--- a/chromium/mojo/public/cpp/system/buffer.h
+++ b/chromium/mojo/public/cpp/system/buffer.h
@@ -16,8 +16,8 @@
#include <memory>
+#include "base/check_op.h"
#include "base/compiler_specific.h"
-#include "base/logging.h"
#include "mojo/public/c/system/buffer.h"
#include "mojo/public/cpp/system/handle.h"
#include "mojo/public/cpp/system/system_export.h"
diff --git a/chromium/mojo/public/cpp/system/data_pipe.h b/chromium/mojo/public/cpp/system/data_pipe.h
index eb7d6e279ad..6cd2eb35428 100644
--- a/chromium/mojo/public/cpp/system/data_pipe.h
+++ b/chromium/mojo/public/cpp/system/data_pipe.h
@@ -14,8 +14,8 @@
#include <stdint.h>
+#include "base/check.h"
#include "base/compiler_specific.h"
-#include "base/logging.h"
#include "mojo/public/c/system/data_pipe.h"
#include "mojo/public/cpp/system/handle.h"
diff --git a/chromium/mojo/public/cpp/system/data_pipe_producer.cc b/chromium/mojo/public/cpp/system/data_pipe_producer.cc
index 056620a794d..bb474ca29df 100644
--- a/chromium/mojo/public/cpp/system/data_pipe_producer.cc
+++ b/chromium/mojo/public/cpp/system/data_pipe_producer.cc
@@ -53,6 +53,8 @@ class DataPipeProducer::SequenceState
void Cancel() {
base::AutoLock lock(lock_);
is_cancelled_ = true;
+ owning_task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&SequenceState::CancelOnSequence, this));
}
void Start(std::unique_ptr<DataSource> data_source) {
@@ -151,6 +153,13 @@ class DataPipeProducer::SequenceState
std::move(producer_handle_), result));
}
+ void CancelOnSequence() {
+ if (!data_source_)
+ return;
+ data_source_->Abort();
+ Finish(MOJO_RESULT_CANCELLED);
+ }
+
const scoped_refptr<base::SequencedTaskRunner> callback_task_runner_;
// State which is effectively owned and used only on the file sequence.
diff --git a/chromium/mojo/public/cpp/system/dynamic_library_support.cc b/chromium/mojo/public/cpp/system/dynamic_library_support.cc
new file mode 100644
index 00000000000..c106778e69c
--- /dev/null
+++ b/chromium/mojo/public/cpp/system/dynamic_library_support.cc
@@ -0,0 +1,64 @@
+// Copyright 2020 The Chromium 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/system/dynamic_library_support.h"
+
+#include <stdint.h>
+
+#include "base/command_line.h"
+#include "build/build_config.h"
+#include "mojo/public/c/system/functions.h"
+
+namespace mojo {
+
+namespace {
+
+// Helper for temporary storage related to |MojoInitialize()| calls.
+struct InitializationState {
+ InitializationState(const base::Optional<base::FilePath>& path,
+ MojoInitializeFlags flags) {
+ options.flags = flags;
+
+ if (path) {
+ utf8_path = path->AsUTF8Unsafe();
+ options.mojo_core_path = utf8_path.c_str();
+ options.mojo_core_path_length = static_cast<uint32_t>(utf8_path.size());
+ }
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+ // Build a temporary reconstructed argv to pass into the library so it can
+ // inspect the application command line if needed.
+ for (const std::string& s : base::CommandLine::ForCurrentProcess()->argv())
+ argv.push_back(s.c_str());
+ options.argc = static_cast<uint32_t>(argv.size());
+ options.argv = argv.data();
+#endif
+ }
+
+ MojoInitializeOptions options = {sizeof(MojoInitializeOptions)};
+ std::string utf8_path;
+ std::vector<const char*> argv;
+};
+
+} // namespace
+
+MojoResult LoadCoreLibrary(base::Optional<base::FilePath> path) {
+ InitializationState state(path, MOJO_INITIALIZE_FLAG_LOAD_ONLY);
+ return MojoInitialize(&state.options);
+}
+
+MojoResult InitializeCoreLibrary(MojoInitializeFlags flags) {
+ DCHECK_EQ(flags & MOJO_INITIALIZE_FLAG_LOAD_ONLY, 0u);
+ InitializationState state(base::nullopt, flags);
+ return MojoInitialize(&state.options);
+}
+
+MojoResult LoadAndInitializeCoreLibrary(base::Optional<base::FilePath> path,
+ MojoInitializeFlags flags) {
+ DCHECK_EQ(flags & MOJO_INITIALIZE_FLAG_LOAD_ONLY, 0u);
+ InitializationState state(path, flags);
+ return MojoInitialize(&state.options);
+}
+
+} // namespace mojo
diff --git a/chromium/mojo/public/cpp/system/dynamic_library_support.h b/chromium/mojo/public/cpp/system/dynamic_library_support.h
new file mode 100644
index 00000000000..97c30427cb6
--- /dev/null
+++ b/chromium/mojo/public/cpp/system/dynamic_library_support.h
@@ -0,0 +1,45 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_SYSTEM_DYNAMIC_LIBRARY_SUPPORT_H_
+#define MOJO_PUBLIC_CPP_SYSTEM_DYNAMIC_LIBRARY_SUPPORT_H_
+
+#include "base/files/file_path.h"
+#include "base/optional.h"
+#include "mojo/public/c/system/types.h"
+#include "mojo/public/cpp/system/system_export.h"
+
+namespace mojo {
+
+// Helper to load Mojo Core dynamically from a shared library. If |path| is
+// not given, the library path is assumed to be set in the
+// MOJO_CORE_LIBRARY_PATH environment variable, or the library is searched for
+// in the current working directory.
+//
+// This may only be called in a process that hasn't already initialized Mojo.
+// Mojo is still not fully initialized or usable until |InitializeCoreLibrary()|
+// is also called. These two functions are kept distinct to facilitate use
+// cases where the client application must perform some work (e.g. sandbox
+// configuration, forking, etc) between the loading and initialization steps.
+MOJO_CPP_SYSTEM_EXPORT MojoResult
+LoadCoreLibrary(base::Optional<base::FilePath> path);
+
+// Initializes the dynamic Mojo Core library previously loaded by
+// |LoadCoreLibrary()| above.
+//
+// This may only be called in a process that hasn't already initialized Mojo.
+MOJO_CPP_SYSTEM_EXPORT MojoResult
+InitializeCoreLibrary(MojoInitializeFlags flags);
+
+// Loads and initializes Mojo Core from a shared library. This combines
+// |LoadCoreLibrary()| and |InitializeCoreLibrary()| for convenience in cases
+// where they don't need to be performed at different times by the client
+// application.
+MOJO_CPP_SYSTEM_EXPORT MojoResult
+LoadAndInitializeCoreLibrary(base::Optional<base::FilePath> path,
+ MojoInitializeFlags flags);
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_SYSTEM_DYNAMIC_LIBRARY_SUPPORT_H_
diff --git a/chromium/mojo/public/cpp/system/functions.cc b/chromium/mojo/public/cpp/system/functions.cc
new file mode 100644
index 00000000000..74aee1a0973
--- /dev/null
+++ b/chromium/mojo/public/cpp/system/functions.cc
@@ -0,0 +1,36 @@
+// Copyright 2020 The Chromium 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/system/functions.h"
+
+#include "base/callback.h"
+#include "base/no_destructor.h"
+
+namespace mojo {
+
+namespace {
+
+DefaultProcessErrorHandler& GetDefaultProcessErrorHandler() {
+ static base::NoDestructor<DefaultProcessErrorHandler> handler;
+ return *handler;
+}
+
+void HandleError(const MojoProcessErrorDetails* details) {
+ const DefaultProcessErrorHandler& handler = GetDefaultProcessErrorHandler();
+ handler.Run(
+ std::string(details->error_message, details->error_message_length));
+}
+
+} // namespace
+
+void SetDefaultProcessErrorHandler(DefaultProcessErrorHandler handler) {
+ // Ensure any previously set handler is wiped out.
+ MojoSetDefaultProcessErrorHandler(nullptr, nullptr);
+ auto& global_handler = GetDefaultProcessErrorHandler();
+ global_handler = std::move(handler);
+ if (global_handler)
+ MojoSetDefaultProcessErrorHandler(&HandleError, nullptr);
+}
+
+} // namespace mojo
diff --git a/chromium/mojo/public/cpp/system/functions.h b/chromium/mojo/public/cpp/system/functions.h
index 31edf57ab54..4f45ecef20c 100644
--- a/chromium/mojo/public/cpp/system/functions.h
+++ b/chromium/mojo/public/cpp/system/functions.h
@@ -11,7 +11,11 @@
#ifndef MOJO_PUBLIC_CPP_SYSTEM_FUNCTIONS_H_
#define MOJO_PUBLIC_CPP_SYSTEM_FUNCTIONS_H_
+#include <string>
+
+#include "base/callback_forward.h"
#include "mojo/public/c/system/functions.h"
+#include "mojo/public/cpp/system/system_export.h"
namespace mojo {
@@ -21,6 +25,17 @@ inline MojoTimeTicks GetTimeTicksNow() {
return MojoGetTimeTicksNow();
}
+// Sets a callback to handle communication errors regarding peer processes whose
+// identity is not explicitly known by this process, i.e. processes that are
+// part of the same Mojo process network but which were not invited by this
+// process.
+//
+// This can be used to globally listen for reports of bad incoming IPCs.
+using DefaultProcessErrorHandler =
+ base::RepeatingCallback<void(const std::string& error)>;
+void MOJO_CPP_SYSTEM_EXPORT
+SetDefaultProcessErrorHandler(DefaultProcessErrorHandler handler);
+
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_SYSTEM_FUNCTIONS_H_
diff --git a/chromium/mojo/public/cpp/system/handle.h b/chromium/mojo/public/cpp/system/handle.h
index 61e1e570a2b..a0bd46ba2aa 100644
--- a/chromium/mojo/public/cpp/system/handle.h
+++ b/chromium/mojo/public/cpp/system/handle.h
@@ -8,8 +8,8 @@
#include <stdint.h>
#include <limits>
+#include "base/check_op.h"
#include "base/compiler_specific.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "mojo/public/c/system/functions.h"
#include "mojo/public/c/system/types.h"
diff --git a/chromium/mojo/public/cpp/system/message_pipe.h b/chromium/mojo/public/cpp/system/message_pipe.h
index 3803a20dee5..92ac7a5fcba 100644
--- a/chromium/mojo/public/cpp/system/message_pipe.h
+++ b/chromium/mojo/public/cpp/system/message_pipe.h
@@ -16,8 +16,8 @@
#include <vector>
+#include "base/check_op.h"
#include "base/compiler_specific.h"
-#include "base/logging.h"
#include "mojo/public/c/system/message_pipe.h"
#include "mojo/public/cpp/system/handle.h"
#include "mojo/public/cpp/system/message.h"
diff --git a/chromium/mojo/public/cpp/system/platform_handle.h b/chromium/mojo/public/cpp/system/platform_handle.h
index 297be2263e7..eb69b3e661a 100644
--- a/chromium/mojo/public/cpp/system/platform_handle.h
+++ b/chromium/mojo/public/cpp/system/platform_handle.h
@@ -15,7 +15,6 @@
#include "base/compiler_specific.h"
#include "base/files/platform_file.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/unsafe_shared_memory_region.h"
diff --git a/chromium/mojo/public/cpp/test_support/BUILD.gn b/chromium/mojo/public/cpp/test_support/BUILD.gn
index 8bde2beb334..3312a371ba8 100644
--- a/chromium/mojo/public/cpp/test_support/BUILD.gn
+++ b/chromium/mojo/public/cpp/test_support/BUILD.gn
@@ -12,7 +12,6 @@ static_library("test_utils") {
]
deps = [
- "//mojo/core/embedder",
"//mojo/public/c/test_support",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
diff --git a/chromium/mojo/public/cpp/test_support/lib/test_utils.cc b/chromium/mojo/public/cpp/test_support/lib/test_utils.cc
index 99e7f708bf2..062106db864 100644
--- a/chromium/mojo/public/cpp/test_support/lib/test_utils.cc
+++ b/chromium/mojo/public/cpp/test_support/lib/test_utils.cc
@@ -10,7 +10,7 @@
#include <vector>
#include "base/bind.h"
-#include "mojo/core/embedder/embedder.h"
+#include "base/bind_helpers.h"
#include "mojo/public/cpp/system/core.h"
#include "mojo/public/cpp/system/wait.h"
#include "mojo/public/cpp/test_support/test_support.h"
@@ -80,13 +80,12 @@ void IterateAndReportPerf(const char* test_name,
}
BadMessageObserver::BadMessageObserver() : got_bad_message_(false) {
- mojo::core::SetDefaultProcessErrorCallback(base::BindRepeating(
+ mojo::SetDefaultProcessErrorHandler(base::BindRepeating(
&BadMessageObserver::OnReportBadMessage, base::Unretained(this)));
}
BadMessageObserver::~BadMessageObserver() {
- mojo::core::SetDefaultProcessErrorCallback(
- mojo::core::ProcessErrorCallback());
+ mojo::SetDefaultProcessErrorHandler(base::NullCallback());
}
std::string BadMessageObserver::WaitForBadMessage() {
diff --git a/chromium/mojo/public/interfaces/bindings/pipe_control_messages.mojom b/chromium/mojo/public/interfaces/bindings/pipe_control_messages.mojom
index 052e2e6df33..d735567bfc3 100644
--- a/chromium/mojo/public/interfaces/bindings/pipe_control_messages.mojom
+++ b/chromium/mojo/public/interfaces/bindings/pipe_control_messages.mojom
@@ -38,7 +38,7 @@ struct DisconnectReason {
// An event to notify that an interface endpoint set up at the message sender
// side has been closed.
//
-// This event is omitted if the endpoint belongs to the master interface and
+// This event is omitted if the endpoint belongs to the primary interface and
// there is no disconnect reason specified.
struct PeerAssociatedEndpointClosedEvent {
// The interface ID.
diff --git a/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn b/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn
index 1c48f55567d..404d9cf94f4 100644
--- a/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn
+++ b/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn
@@ -21,8 +21,8 @@ copy("validation_test_data") {
"data/validation/associated_conformance_mthd0_good.expected",
"data/validation/associated_conformance_mthd0_illegal_invalid_interface_id.data",
"data/validation/associated_conformance_mthd0_illegal_invalid_interface_id.expected",
- "data/validation/associated_conformance_mthd0_illegal_master_interface_id.data",
- "data/validation/associated_conformance_mthd0_illegal_master_interface_id.expected",
+ "data/validation/associated_conformance_mthd0_illegal_primary_interface_id.data",
+ "data/validation/associated_conformance_mthd0_illegal_primary_interface_id.expected",
"data/validation/associated_conformance_mthd0_interface_id_index_out_of_range.data",
"data/validation/associated_conformance_mthd0_interface_id_index_out_of_range.expected",
"data/validation/associated_conformance_mthd0_unexpected_invalid_associated_interface.data",
diff --git a/chromium/mojo/public/interfaces/bindings/tests/test_sync_methods.mojom b/chromium/mojo/public/interfaces/bindings/tests/test_sync_methods.mojom
index b5a7911fdee..b859b33d3e0 100644
--- a/chromium/mojo/public/interfaces/bindings/tests/test_sync_methods.mojom
+++ b/chromium/mojo/public/interfaces/bindings/tests/test_sync_methods.mojom
@@ -29,7 +29,7 @@ interface TestSync {
};
// Test sync method support with associated interfaces.
-interface TestSyncMaster {
+interface TestSyncPrimary {
[Sync]
Ping() => ();
diff --git a/chromium/mojo/public/js/BUILD.gn b/chromium/mojo/public/js/BUILD.gn
index c842406970e..47ee8536397 100644
--- a/chromium/mojo/public/js/BUILD.gn
+++ b/chromium/mojo/public/js/BUILD.gn
@@ -61,7 +61,7 @@ js_library("bindings_lite_sources") {
deps = [ "//mojo/public/interfaces/bindings:bindings_js_library_for_compile" ]
}
-if (enable_mojom_closure_compile || closure_compile) {
+if (enable_mojom_closure_compile || enable_js_type_check) {
js_binary("bindings_lite") {
outputs = [ bindings_lite_compiled_file ]
deps = [ ":bindings_lite_sources" ]
diff --git a/chromium/mojo/public/js/bindings.js b/chromium/mojo/public/js/bindings.js
index a82f43dddac..30a76104695 100644
--- a/chromium/mojo/public/js/bindings.js
+++ b/chromium/mojo/public/js/bindings.js
@@ -136,7 +136,7 @@
this.handle_ = null;
this.interfaceEndpointClient_ = new internal.InterfaceEndpointClient(
- this.router_.createLocalEndpointHandle(internal.kMasterInterfaceId));
+ this.router_.createLocalEndpointHandle(internal.kPrimaryInterfaceId));
this.interfaceEndpointClient_ .setPayloadValidators([
this.interfaceType_.validateResponse]);
@@ -214,7 +214,7 @@
this.stub_ = new this.interfaceType_.stubClass(this.impl_);
this.interfaceEndpointClient_ = new internal.InterfaceEndpointClient(
- this.router_.createLocalEndpointHandle(internal.kMasterInterfaceId),
+ this.router_.createLocalEndpointHandle(internal.kPrimaryInterfaceId),
this.stub_, this.interfaceType_.kVersion);
this.interfaceEndpointClient_ .setPayloadValidators([
@@ -345,7 +345,7 @@
//
// // A locally-created associated interface pointer can only be used to
// // make calls when the corresponding associated request is sent over
- // // another interface (either the master interface or another
+ // // another interface (either the primary interface or another
// // associated interface).
// var associatedInterfacePtrInfo = new AssociatedInterfacePtrInfo();
// var associatedRequest = makeRequest(interfacePtrInfo);
diff --git a/chromium/mojo/public/js/interface_types.js b/chromium/mojo/public/js/interface_types.js
index b7085e5a90b..83448a450e9 100644
--- a/chromium/mojo/public/js/interface_types.js
+++ b/chromium/mojo/public/js/interface_types.js
@@ -7,7 +7,7 @@
// Constants ----------------------------------------------------------------
var kInterfaceIdNamespaceMask = 0x80000000;
- var kMasterInterfaceId = 0x00000000;
+ var kPrimaryInterfaceId = 0x00000000;
var kInvalidInterfaceId = 0xFFFFFFFF;
// ---------------------------------------------------------------------------
@@ -69,8 +69,8 @@
this.interfaceEndpointHandle.reset(reason);
};
- function isMasterInterfaceId(interfaceId) {
- return interfaceId === kMasterInterfaceId;
+ function isPrimaryInterfaceId(interfaceId) {
+ return interfaceId === kPrimaryInterfaceId;
}
function isValidInterfaceId(interfaceId) {
@@ -88,10 +88,10 @@
mojo.InterfaceRequest = InterfaceRequest;
mojo.AssociatedInterfacePtrInfo = AssociatedInterfacePtrInfo;
mojo.AssociatedInterfaceRequest = AssociatedInterfaceRequest;
- internal.isMasterInterfaceId = isMasterInterfaceId;
+ internal.isPrimaryInterfaceId = isPrimaryInterfaceId;
internal.isValidInterfaceId = isValidInterfaceId;
internal.hasInterfaceIdNamespaceBitSet = hasInterfaceIdNamespaceBitSet;
internal.kInvalidInterfaceId = kInvalidInterfaceId;
- internal.kMasterInterfaceId = kMasterInterfaceId;
+ internal.kPrimaryInterfaceId = kPrimaryInterfaceId;
internal.kInterfaceIdNamespaceMask = kInterfaceIdNamespaceMask;
})();
diff --git a/chromium/mojo/public/js/lib/router.js b/chromium/mojo/public/js/lib/router.js
index 251f3a97fef..1fa309f731c 100644
--- a/chromium/mojo/public/js/lib/router.js
+++ b/chromium/mojo/public/js/lib/router.js
@@ -165,10 +165,10 @@
return new internal.InterfaceEndpointHandle();
}
- // Unless it is the master ID, |interfaceId| is from the remote side and
+ // Unless it is the primary ID, |interfaceId| is from the remote side and
// therefore its namespace bit is supposed to be different than the value
// that this router would use.
- if (!internal.isMasterInterfaceId(interfaceId) &&
+ if (!internal.isPrimaryInterfaceId(interfaceId) &&
this.setInterfaceIdNamespaceBit_ ===
internal.hasInterfaceIdNamespaceBitSet(interfaceId)) {
return new internal.InterfaceEndpointHandle();
@@ -290,7 +290,7 @@
this.updateEndpointStateMayRemove(endpoint,
EndpointStateUpdateType.ENDPOINT_CLOSED);
- if (!internal.isMasterInterfaceId(interfaceId) || reason) {
+ if (!internal.isPrimaryInterfaceId(interfaceId) || reason) {
this.controlMessageProxy_.notifyPeerEndpointClosed(interfaceId, reason);
}
diff --git a/chromium/mojo/public/js/lib/validator.js b/chromium/mojo/public/js/lib/validator.js
index 577dcf00339..f32419e6b5e 100644
--- a/chromium/mojo/public/js/lib/validator.js
+++ b/chromium/mojo/public/js/lib/validator.js
@@ -323,7 +323,7 @@
if (this.payloadInterfaceIds) {
for (var interfaceId of this.payloadInterfaceIds) {
if (!internal.isValidInterfaceId(interfaceId) ||
- internal.isMasterInterfaceId(interfaceId)) {
+ internal.isPrimaryInterfaceId(interfaceId)) {
return validationError.ILLEGAL_INTERFACE_ID;
}
}
diff --git a/chromium/mojo/public/js/test/BUILD.gn b/chromium/mojo/public/js/test/BUILD.gn
index 68397db1435..8c0a853223a 100644
--- a/chromium/mojo/public/js/test/BUILD.gn
+++ b/chromium/mojo/public/js/test/BUILD.gn
@@ -15,7 +15,7 @@ mojom("test_mojom") {
]
}
-if (enable_mojom_closure_compile || closure_compile) {
+if (enable_mojom_closure_compile || enable_js_type_check) {
js_binary("compile_test") {
outputs = [ "$target_gen_dir/compile_test.js" ]
deps = [ ":test_mojom_js_library_for_compile" ]
diff --git a/chromium/mojo/public/js/ts/bindings/tests/BUILD.gn b/chromium/mojo/public/js/ts/bindings/tests/BUILD.gn
index bafb2d6808a..81873c95bb4 100644
--- a/chromium/mojo/public/js/ts/bindings/tests/BUILD.gn
+++ b/chromium/mojo/public/js/ts/bindings/tests/BUILD.gn
@@ -11,7 +11,14 @@ mojom("test_interfaces") {
sources = [
"constants.test-mojom",
"enums.test-mojom",
+ "export1.test-mojom",
+ "export2.test-mojom",
+ "export3.test-mojom",
+ "export4.test-mojom",
+ "import.test-mojom",
"module.test-mojom",
+ "other_dir/other_dir.test-mojom",
+ "structs.test-mojom",
]
use_typescript_sources = true
}
diff --git a/chromium/mojo/public/mojom/base/BUILD.gn b/chromium/mojo/public/mojom/base/BUILD.gn
index 7734ccba97e..1e42e12c612 100644
--- a/chromium/mojo/public/mojom/base/BUILD.gn
+++ b/chromium/mojo/public/mojom/base/BUILD.gn
@@ -10,6 +10,7 @@ mojom_component("base") {
"application_state.mojom",
"big_buffer.mojom",
"big_string.mojom",
+ "binder.mojom",
"file.mojom",
"file_error.mojom",
"file_info.mojom",
@@ -264,6 +265,20 @@ mojom_component("base") {
"//mojo/public/cpp/base:shared_typemap_traits",
]
},
+ {
+ types = [
+ {
+ mojom = "mojo_base.mojom.TextDirection"
+ cpp = "::base::i18n::TextDirection"
+ },
+ ]
+ traits_headers =
+ [ "//mojo/public/cpp/base/text_direction_mojom_traits.h" ]
+ traits_public_deps = [
+ "//base:i18n",
+ "//mojo/public/cpp/base:typemap_traits",
+ ]
+ },
]
cpp_typemaps = common_typemaps
@@ -372,20 +387,6 @@ mojom_component("base") {
{
types = [
{
- mojom = "mojo_base.mojom.TextDirection"
- cpp = "::base::i18n::TextDirection"
- },
- ]
- traits_headers =
- [ "//mojo/public/cpp/base/text_direction_mojom_traits.h" ]
- traits_public_deps = [
- "//base:i18n",
- "//mojo/public/cpp/base:typemap_traits",
- ]
- },
- {
- types = [
- {
mojom = "mojo_base.mojom.ThreadPriority"
cpp = "::base::ThreadPriority"
},
diff --git a/chromium/mojo/public/mojom/base/binder.mojom b/chromium/mojo/public/mojom/base/binder.mojom
new file mode 100644
index 00000000000..a8e90e09ad6
--- /dev/null
+++ b/chromium/mojo/public/mojom/base/binder.mojom
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module mojo_base.mojom;
+
+import "mojo/public/mojom/base/generic_pending_receiver.mojom";
+
+// A generic interface for anything which can bind arbitrary other interface
+// receivers filtered at runtime.
+//
+// NOTE: This interface may be exposed to external binaries, so all changes MUST
+// preserve backward-compatibility.
+[Stable]
+interface Binder {
+ // Requests that |receiver| be bound to an appropriate endpoint.
+ Bind@0(GenericPendingReceiver receiver);
+};
diff --git a/chromium/mojo/public/mojom/base/generic_pending_receiver.mojom b/chromium/mojo/public/mojom/base/generic_pending_receiver.mojom
index 67dda272651..9008b469bcc 100644
--- a/chromium/mojo/public/mojom/base/generic_pending_receiver.mojom
+++ b/chromium/mojo/public/mojom/base/generic_pending_receiver.mojom
@@ -10,7 +10,17 @@ module mojo_base.mojom;
// This should be used sparingly, in cases where APIs need to dynamically pass
// different types of receivers that cannot or should not be known at compile
// time.
+//
+// NOTE: This type may be exposed to external binaries, so all changes MUST
+// preserve backward-compatibility.
+[Stable]
struct GenericPendingReceiver {
- string interface_name;
- handle<message_pipe> receiving_pipe;
+ // The name of the interface which defines the messages to be received by
+ // |receiving_pipe|.
+ string interface_name@0;
+
+ // A message pipe endpoint which is expected to receive messages defined by
+ // the interface named by |interface_name| above. This should be bound to
+ // an implementation of the named interface.
+ handle<message_pipe> receiving_pipe@1;
};
diff --git a/chromium/mojo/public/mojom/base/string16.mojom b/chromium/mojo/public/mojom/base/string16.mojom
index dd672baa169..2a3808436b5 100644
--- a/chromium/mojo/public/mojom/base/string16.mojom
+++ b/chromium/mojo/public/mojom/base/string16.mojom
@@ -9,10 +9,7 @@ import "mojo/public/mojom/base/big_buffer.mojom";
// Corresponds to |base::string16| in base/strings/string16.h
// Corresponds to |WTF::String| in
// third_party/WebKit/Source/platform/wtf/text/WTFString.h.
-// Don't make backwards-incompatible changes to this definition!
-// It's used in PageState serialization, so backwards incompatible changes
-// would cause stored PageState objects to be un-parseable. Please contact the
-// page state serialization owners before making such a change.
+[Stable]
struct String16 {
array<uint16> data;
};
diff --git a/chromium/mojo/public/mojom/base/time.mojom b/chromium/mojo/public/mojom/base/time.mojom
index 78cde1a1671..64777e56754 100644
--- a/chromium/mojo/public/mojom/base/time.mojom
+++ b/chromium/mojo/public/mojom/base/time.mojom
@@ -4,6 +4,7 @@
module mojo_base.mojom;
+[Stable]
struct Time {
// The internal value is expressed in terms of microseconds since a fixed but
// intentionally unspecified epoch.
diff --git a/chromium/mojo/public/tools/bindings/README.md b/chromium/mojo/public/tools/bindings/README.md
index 56ee4cc3b39..39c26c0998d 100644
--- a/chromium/mojo/public/tools/bindings/README.md
+++ b/chromium/mojo/public/tools/bindings/README.md
@@ -407,6 +407,17 @@ interesting attributes supported today.
field, enum value, interface method, or method parameter was introduced.
See [Versioning](#Versioning) for more details.
+**`[Stable]`**
+: The `Stable` attribute specifies that a given mojom type or interface
+ definition can be considered stable over time, meaning it is safe to use for
+ things like persistent storage or communication between independent
+ version-skewed binaries. Stable definitions may only depend on builtin mojom
+ types or other stable definitions, and changes to such definitions MUST
+ preserve backward-compatibility through appropriate use of versioning.
+ Backward-compatibility of changes is enforced in the Chromium tree using a
+ strict presubmit check. See [Versioning](#Versioning) for more details on
+ backward-compatibility constraints.
+
**`[EnableIf=value]`**
: The `EnableIf` attribute is used to conditionally enable definitions when
the mojom is parsed. If the `mojom` target in the GN file does not include
diff --git a/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index d585c48f963..e40fa41f5b9 100644
--- a/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -21,7 +21,6 @@ _typemap_imports = [
"//components/typemaps.gni",
"//content/browser/typemaps.gni",
"//content/public/common/typemaps.gni",
- "//fuchsia/mojom/test_typemaps.gni",
"//media/capture/mojom/typemaps.gni",
"//media/fuchsia/mojom/typemaps.gni",
"//media/learning/mojo/public/cpp/typemaps.gni",
diff --git a/chromium/mojo/public/tools/bindings/compile_typescript.py b/chromium/mojo/public/tools/bindings/compile_typescript.py
index dc41fb4122d..086d5dcfa8e 100644
--- a/chromium/mojo/public/tools/bindings/compile_typescript.py
+++ b/chromium/mojo/public/tools/bindings/compile_typescript.py
@@ -15,26 +15,11 @@ import node_modules
def main(argv):
parser = argparse.ArgumentParser()
- parser.add_argument('--filelist', required=True)
+ parser.add_argument('--tsconfig_path', required=True)
args = parser.parse_args(argv)
- files = []
- with open(args.filelist) as filelist_file:
- for line in filelist_file:
- for f in line.split():
- files.append(os.path.join(os.getcwd(), f))
-
- file_paths = ' '.join(files)
-
- result = node.RunNode(
- [node_modules.PathToTypescript()] +
- [
- "--target 'es6'",
- "--module 'es6'",
- "--lib 'es6, esnext.bigint'",
- "--strict",
- file_paths
- ])
+ result = node.RunNode([node_modules.PathToTypescript()] +
+ ['--project %s' % args.tsconfig_path])
if len(result) != 0:
raise RuntimeError('Failed to compile Typescript: \n%s' % result)
diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl
index 1093c7ff5fe..9ffd65d3460 100644
--- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl
+++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl
@@ -20,13 +20,8 @@ enum class {{enum_name}} : int32_t;
{{ kythe_annotation(full_enum_name) }}
enum class {{enum_name}} : int32_t {
{%- for field in enum.fields %}
-{%- if field.value %}
{{ kythe_annotation("%s.%s"|format(full_enum_name, field.name)) }}
- {{field.name}} = {{field.value|expression_to_text}},
-{%- else %}
- {{ kythe_annotation("%s.%s"|format(full_enum_name, field.name)) }}
- {{field.name}},
-{%- endif %}
+ {{field.name}} = {{field.numeric_value}},
{%- endfor %}
{%- if enum.min_value is not none %}
kMinValue = {{enum.min_value}},
diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-params-data.h.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-params-data.h.tmpl
index b3525b75ef5..5fab70e5aaa 100644
--- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-params-data.h.tmpl
+++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-params-data.h.tmpl
@@ -9,7 +9,6 @@
#ifndef {{header_guard}}
#define {{header_guard}}
-#include "base/logging.h"
#include "base/macros.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
#include "mojo/public/cpp/bindings/lib/buffer.h"
diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl
index f51f9bd81cd..2aeb29fca9b 100644
--- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl
+++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl
@@ -6,7 +6,6 @@
#include <utility>
-#include "base/logging.h"
#include "base/stl_util.h" // for base::size()
#include "mojo/public/cpp/bindings/lib/validate_params.h"
#include "mojo/public/cpp/bindings/lib/validation_context.h"
diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
index 71ad8790ee4..8e65847a9c5 100644
--- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
+++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
@@ -24,7 +24,6 @@
#include <utility>
#include "base/hash/md5_constexpr.h"
-#include "base/logging.h"
#include "base/run_loop.h"
#include "base/task/common/task_annotator.h"
#include "mojo/public/cpp/bindings/lib/generated_code_util.h"
diff --git a/chromium/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl
index 0daf77b3e6d..e09f00aa569 100644
--- a/chromium/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl
+++ b/chromium/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl
@@ -1,18 +1,8 @@
-{%- macro enum_value(enum, field, index) -%}
-{%- if field.value -%}
-{{field.value|expression_to_text('i32')}};
-{%- elif index == 0 -%}
-{{field.numeric_value}};
-{%- else -%}
-{{field.numeric_value}}; // {{enum.fields[index - 1]|name}} + 1
-{%- endif -%}
-{%- endmacro -%}
-
{%- macro enum_def(enum, top_level) -%}
public {{ 'static ' if not top_level }}final class {{enum|name}} {
private static final boolean IS_EXTENSIBLE = {% if enum.extensible %}true{% else %}false{% endif %};
{% for field in enum.fields %}
- public static final int {{field|name}} = {{enum_value(enum, field, loop.index0)}}
+ public static final int {{field|name}} = {{field.numeric_value}};
{%- endfor %}
{%- if enum|covers_continuous_range %}
diff --git a/chromium/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl
index 26961956fe7..50341269275 100644
--- a/chromium/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl
+++ b/chromium/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl
@@ -2,13 +2,7 @@
{{enum_name}} = {};
{%- set prev_enum = 0 %}
{%- for field in enum.fields %}
-{%- if field.value %}
- {{enum_name}}.{{field.name}} = {{field.value|expression_to_text}};
-{%- elif loop.first %}
- {{enum_name}}.{{field.name}} = 0;
-{%- else %}
- {{enum_name}}.{{field.name}} = {{enum_name}}.{{enum.fields[loop.index0 - 1].name}} + 1;
-{%- endif %}
+ {{enum_name}}.{{field.name}} = {{field.numeric_value}};
{%- endfor %}
{%- if enum.min_value is not none %}
{{enum_name}}.MIN_VALUE = {{enum.min_value}},
diff --git a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/enum_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/enum_definition.tmpl
index affa4d09650..d6561f3b7c8 100644
--- a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/enum_definition.tmpl
+++ b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/enum_definition.tmpl
@@ -21,7 +21,7 @@ goog.provide('{{enum_spec_parent}}.{{enum.name}}Spec');
{{enum_name}} = {
{# Set up the enum here, but fill out the values later. #}
{%- for field in enum.fields %}
- {{field.name}}: 0,
+ {{field.name}}: {{field.numeric_value}},
{%- endfor %}
{%- if enum.min_value is not none %}
MIN_VALUE: {{enum.min_value}},
@@ -30,16 +30,5 @@ goog.provide('{{enum_spec_parent}}.{{enum.name}}Spec');
MAX_VALUE: {{enum.max_value}},
{%- endif %}
};
-{%- for field in enum.fields %}
-{# Suppress type checks since we're assigning number into an enum. #}
-/** @suppress {checkTypes} */
-{%- if field.value %}
-{{enum_name}}.{{field.name}} = {{field.value|expression_to_text_lite}};
-{%- elif loop.first %}
-{{enum_name}}.{{field.name}} = 0;
-{%- else %}
-{{enum_name}}.{{field.name}} = {{enum_name}}.{{enum.fields[loop.index0 - 1].name}} + 1;
-{%- endif %}
-{%- endfor %}
{%- endmacro %}
diff --git a/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.cc.tmpl b/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.cc.tmpl
new file mode 100644
index 00000000000..e9462281808
--- /dev/null
+++ b/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.cc.tmpl
@@ -0,0 +1,841 @@
+// Copyright 2019 The Chromium 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 "{{module.path}}-mojolpm.h"
+
+#include <functional>
+
+#include "base/no_destructor.h"
+#include "base/task/post_task.h"
+#include "mojo/public/cpp/bindings/associated_binding_set.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+
+{% for extra_traits_header in all_extra_traits_headers %}
+#include "{{extra_traits_header}}"
+{%- endfor %}
+
+{%- import "mojolpm_macros.tmpl" as util %}
+{%- import "mojolpm_from_proto_macros.tmpl" as from_proto %}
+{%- import "mojolpm_to_proto_macros.tmpl" as to_proto %}
+{%- import "mojolpm_traits_specialization_macros.tmpl" as traits_specialization %}
+
+namespace mojo {
+{%- for struct in structs %}
+{{- traits_specialization.define_struct(struct) }}
+{%- endfor %}
+
+{%- for union in unions %}
+{{ traits_specialization.define_union(union) }}
+{%- endfor %}
+} // namespace mojo
+
+namespace mojolpm {
+{%- for enum in all_enums %}
+{{- from_proto.define_enum(enum) }}
+{{- to_proto.define_enum(enum) }}
+{%- endfor %}
+
+{%- for struct in structs %}
+{%- set proto_type = "::mojolpm" ~ (struct|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+{%- set struct_type = proto_type ~ "_ProtoStruct" %}
+{%- for field in struct.fields %}
+{%- set name = field.name|camel_to_under %}
+{%- set kind = field.kind %}
+{%- if kind|is_array_kind or kind|is_map_kind %}
+{{- from_proto.define(struct_type, kind, name) }}
+{{- to_proto.define(struct_type, kind, name) }}
+{%- endif %}
+{%- endfor %}
+{{- from_proto.define_struct(struct) }}
+{{- to_proto.define_struct(struct) }}
+{%- endfor %}
+
+{%- for union in unions %}
+{%- set proto_type = "::mojolpm" ~ (union|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+{%- set union_type = proto_type ~ "_ProtoUnion" %}
+{%- for field in union.fields %}
+{%- set name = field.name|camel_to_under %}
+{%- set kind = field.kind %}
+{%- if kind|is_array_kind or kind|is_map_kind %}
+{{- from_proto.define(union_type, kind, name)}}
+{{- to_proto.define(union_type, kind, name)}}
+{%- endif %}
+{%- endfor %}
+{{- from_proto.define_union(union) }}
+{{- to_proto.define_union(union) }}
+{%- endfor %}
+
+{%- for interface in interfaces %}
+{%- set mojom_type = interface|get_qualified_name_for_kind(flatten_nested_kind=True) %}
+{%- set proto_type = "::mojolpm" ~ (interface|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+class {{interface.name}}Impl : public {{mojom_type}} {
+ ::mojo::BindingSet<{{mojom_type}}> bindings_;
+ ::mojo::AssociatedBindingSet<{{mojom_type}}> associated_bindings_;
+
+ public:
+ {{interface.name}}Impl() {
+ }
+
+ void Bind({{mojom_type}}Request&& request) {
+ DCHECK(mojolpm::GetContext()->task_runner()->RunsTasksInCurrentSequence());
+ bindings_.AddBinding(this, std::move(request));
+ }
+
+ void Bind({{mojom_type}}AssociatedRequest&& request) {
+ DCHECK(mojolpm::GetContext()->task_runner()->RunsTasksInCurrentSequence());
+ associated_bindings_.AddBinding(this, std::move(request));
+ }
+
+{%- for method in interface.methods -%}{{"\n"}}
+ void {{method.name}}({{ "\n" }}
+{%- for param in method.parameters -%}
+{%- set name = param.name|camel_to_under -%}
+{%- set kind = param.kind -%}
+{%- set param_mojom_type = kind|cpp_wrapper_param_type(add_same_module_namespaces=true) -%}
+{{ ",\n" if not loop.first }} {{param_mojom_type}} {{name}}
+{%- endfor -%}
+{%- if method.response_parameters != None -%}
+{{ ",\n" if method.parameters }} {{mojom_type}}::{{method.name}}Callback callback
+{%- endif -%}
+) override {
+{%- for param in method.parameters -%}
+{%- set name = param.name|camel_to_under -%}
+{%- set kind = param.kind -%}
+{{ util.add_instance(kind, name, False)|indent(2, True) }}
+{%- endfor %}
+ mojolpmdbg("{{interface.name}}Impl.{{method.name}}\n");
+ mojolpm::GetContext()->NextAction();
+{%- if method.response_parameters != None %}
+ auto mojolpm_response = mojolpm::GetContext()->GetInstance<
+ {{proto_type}}::{{interface.name}}_{{method.name}}Response>(
+ mojolpm::GetContext()->NextResponseIndex(
+ mojolpm::type_id<{{mojom_type}}>()));
+
+ if (!mojolpm_response) {
+ return;
+ }
+
+ bool mojolpm_result = true;
+{%- for param in method.response_parameters %}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- set param_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set param_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=True) %}
+ {{param_mojom_type}} local_{{name}};
+{%- if kind|is_nullable_kind %}
+ {{param_maybe_mojom_type}} local_maybe_{{name}};
+{%- endif %}
+{%- endfor %}
+
+{%- for param in method.response_parameters -%}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- if not kind|is_nullable_kind %}
+ mojolpm_result &= FromProto(mojolpm_response->m_{{name}}(), local_{{name}});
+ mojolpmdbg("{{name}} %i\n", mojolpm_result);
+{%- else %}
+ if (FromProto(mojolpm_response->m_{{name}}(), local_maybe_{{name}})) {
+ local_{{name}} = std::move(local_maybe_{{name}});
+ }
+{%- endif %}
+{%- endfor %}
+ if (mojolpm_result) {
+ std::move(callback).Run(
+{%- for param in method.response_parameters -%}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- if kind|is_interface_kind or kind|is_associated_kind %}
+ {{kind|cpp_wrapper_param_type(add_same_module_namespaces=true)}}(std::move(local_{{name}})){{ ',' if not loop.last }}
+{%- else %}
+ std::move(local_{{name}}){{ ',' if not loop.last }}
+{%- endif %}
+{%- endfor -%}
+);
+ }
+{%- endif %}
+ }
+{%- endfor %}
+};
+
+bool FromProto(const {{proto_type}}::Ptr& input,
+ {{mojom_type}}PtrInfo& output) {
+ bool result = false;
+ std::unique_ptr<{{mojom_type}}Ptr> output_ptr = nullptr;
+
+ if (input.id()) {
+ output_ptr = mojolpm::GetContext()->GetAndRemoveInstance<{{mojom_type}}Ptr>(input.id());
+ } else {
+ output_ptr = NewInstance<{{mojom_type}}>();
+ }
+
+ if (output_ptr) {
+ // NB: PassInterface is allowed, since output_ptr is bound on this sequence
+ // (the fuzzer sequence)
+ output = output_ptr.release()->PassInterface();
+ result = true;
+ } else {
+ // we otherwise create a local instance
+ ::mojo::InterfacePtr<{{mojom_type}}> ptr;
+ ::mojo::InterfaceRequest<{{mojom_type}}> request = ::mojo::MakeRequest(&ptr);
+ auto impl = std::make_unique<{{interface.name}}Impl>();
+ impl->Bind(std::move(request));
+ mojolpm::GetContext()->AddInstance(std::move(impl));
+ output = ptr.PassInterface();
+ result = true;
+ }
+
+ return result;
+}
+
+bool FromProto(const {{proto_type}}::AssociatedPtr& input,
+ {{mojom_type}}AssociatedPtrInfo& output) {
+ bool result = false;
+ std::unique_ptr<{{mojom_type}}AssociatedPtr> output_ptr;
+
+ if (input.id()) {
+ output_ptr = mojolpm::GetContext()->GetAndRemoveInstance<{{mojom_type}}AssociatedPtr>(input.id());
+ } else {
+ output_ptr = NewAssociatedInstance<{{mojom_type}}>();
+ }
+
+ if (output_ptr) {
+ // NB: PassInterface is allowed, since output_ptr is bound on this sequence
+ // (the fuzzer sequence)
+ output = output_ptr.release()->PassInterface();
+ result = true;
+ } else {
+ // we otherwise create a local instance
+ ::mojo::AssociatedInterfacePtr<{{mojom_type}}> ptr;
+ ::mojo::AssociatedInterfaceRequest<{{mojom_type}}> request = ::mojo::MakeRequest(&ptr);
+ auto impl = std::make_unique<{{interface.name}}Impl>();
+ impl->Bind(std::move(request));
+ mojolpm::GetContext()->AddInstance(std::move(impl));
+ output = ptr.PassInterface();
+ result = true;
+ }
+
+ return result;
+}
+
+bool FromProto(const {{proto_type}}::Request& input,
+ {{mojom_type}}Request& output) {
+ {{mojom_type}}Ptr ptr;
+
+ output = ::mojo::MakeRequest(&ptr);
+ mojolpm::GetContext()->AddInstance(input.id(), std::move(ptr));
+
+ return true;
+}
+
+bool FromProto(const {{proto_type}}::AssociatedRequest& input,
+ {{mojom_type}}AssociatedRequest& output) {
+ {{mojom_type}}AssociatedPtr ptr;
+
+ output = ::mojo::MakeRequest(&ptr);
+ mojolpm::GetContext()->AddInstance(input.id(), std::move(ptr));
+
+ return true;
+}
+
+bool ToProto({{mojom_type}}PtrInfo&& input,
+ {{proto_type}}::Ptr& output) {
+ bool result = false;
+
+ // NB: Not implementing this at present as it only has limited applicability,
+ // and the corresponding types are being deprecated. If your target needs this
+ // to fuzz effectively, consider porting to the new mojo types.
+ NOTREACHED();
+
+ return result;
+}
+
+bool ToProto({{mojom_type}}Ptr&& input,
+ {{proto_type}}::Ptr& output) {
+ bool result = false;
+
+ // NB: Not implementing this at present as it only has limited applicability,
+ // and the corresponding types are being deprecated. If your target needs this
+ // to fuzz effectively, consider porting to the new mojo types.
+ CHECK(false);
+
+ return result;
+}
+
+bool ToProto({{mojom_type}}AssociatedPtrInfo&& input,
+ {{proto_type}}::AssociatedPtr& output) {
+ bool result = false;
+
+ // NB: Not implementing this at present as it only has limited applicability,
+ // and the corresponding types are being deprecated. If your target needs this
+ // to fuzz effectively, consider porting to the new mojo types.
+ CHECK(false);
+
+ return result;
+}
+
+bool ToProto({{mojom_type}}Request&& input,
+ {{proto_type}}::Request& output) {
+ bool result = false;
+
+ // NB: Not implementing this at present as it only has limited applicability,
+ // and the corresponding types are being deprecated. If your target needs this
+ // to fuzz effectively, consider porting to the new mojo types.
+ CHECK(false);
+
+ return result;
+}
+
+bool ToProto({{mojom_type}}AssociatedRequest&& input,
+ {{proto_type}}::AssociatedRequest& output) {
+ bool result = false;
+
+ // NB: Not implementing this at present as it only has limited applicability,
+ // and the corresponding types are being deprecated. If your target needs this
+ // to fuzz effectively, consider porting to the new mojo types.
+ CHECK(false);
+
+ return result;
+}
+
+bool FromProto(const {{proto_type}}::PendingRemote& input,
+ ::mojo::PendingRemote<{{mojom_type}}>& output) {
+ bool result = false;
+ ::mojo::Remote<{{mojom_type}}>* output_ptr = nullptr;
+
+ if (input.id()) {
+ output_ptr = mojolpm::GetContext()->GetInstance<::mojo::Remote<{{mojom_type}}>>(input.id());
+ if (output_ptr) {
+ // TODO(markbrand): look for a cleaner way to handle this check.
+ if (output_ptr->internal_state()
+ && output_ptr->internal_state()->has_pending_callbacks()) {
+ // not safe to Unbind, so fail instead.
+ output_ptr = nullptr;
+ } else {
+ output = output_ptr->Unbind();
+ result = true;
+ }
+ }
+ } else {
+ auto impl = std::make_unique<{{interface.name}}Impl>();
+ auto receiver_ptr = std::make_unique<::mojo::Receiver<{{mojom_type}}>>(impl.get());
+ output = receiver_ptr->BindNewPipeAndPassRemote();
+ mojolpm::GetContext()->AddInstance(std::move(impl));
+ mojolpm::GetContext()->AddInstance(input.id(), std::move(receiver_ptr));
+ result = true;
+ }
+
+ return result;
+}
+
+bool ToProto(::mojo::PendingRemote<{{mojom_type}}>&& input,
+ {{proto_type}}::PendingRemote& output) {
+ bool result = false;
+
+ ::mojo::Remote<{{mojom_type}}> remote(std::move(input));
+ int next_id = NextId<{{mojom_type}}>();
+ output.set_id(AddRemote<{{mojom_type}}>(next_id, std::move(remote)));
+
+ return result;
+}
+
+bool FromProto(const {{proto_type}}::PendingReceiver& input,
+ ::mojo::PendingReceiver<{{mojom_type}}>& output) {
+ ::mojo::Remote<{{mojom_type}}> remote = ::mojo::Remote<{{mojom_type}}>();
+
+ output = remote.BindNewPipeAndPassReceiver();
+
+ mojolpm::GetContext()->task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ base::IgnoreResult(&AddRemote<{{mojom_type}}>),
+ input.id(),
+ std::move(remote)));
+
+ return true;
+}
+
+bool ToProto(::mojo::PendingReceiver<{{mojom_type}}>&& input,
+ {{proto_type}}::PendingReceiver& output) {
+ bool result = true;
+
+ // This should only get called from callbacks into the fuzzer, ie from one of
+ // the XxxImpls or from a return callback. Since that is the case, we want to
+ // bind the receiver and store it.
+
+ auto impl = std::make_unique<{{interface.name}}Impl>();
+ auto receiver = std::make_unique<::mojo::Receiver<{{mojom_type}}>>(
+ impl.get(), std::move(input));
+ mojolpm::GetContext()->AddInstance(std::move(impl));
+ output.set_id(mojolpm::GetContext()->AddInstance(std::move(receiver)));
+
+ return result;
+}
+
+bool FromProto(const {{proto_type}}::PendingAssociatedRemote& input,
+ ::mojo::PendingAssociatedRemote<{{mojom_type}}>& output) {
+ mojolpmdbg("PendingAssociatedRemote {{interface.name}}\n");
+ bool result = false;
+ ::mojo::AssociatedRemote<{{mojom_type}}>* output_ptr;
+
+ if (input.id()) {
+ output_ptr = mojolpm::GetContext()->GetInstance<::mojo::AssociatedRemote<{{mojom_type}}>>(input.id());
+ if (output_ptr) {
+ // TODO(markbrand): look for a cleaner way to handle this check.
+ if (output_ptr->internal_state()
+ && output_ptr->internal_state()->has_pending_callbacks()) {
+ // not safe to Unbind, so fail instead.
+ output_ptr = nullptr;
+ } else {
+ output = output_ptr->Unbind();
+ result = true;
+ }
+ }
+ } else {
+ auto impl = std::make_unique<{{interface.name}}Impl>();
+ auto receiver = std::make_unique<::mojo::AssociatedReceiver<{{mojom_type}}>>(impl.get());
+ output = receiver->BindNewEndpointAndPassRemote();
+ mojolpm::GetContext()->AddInstance(std::move(impl));
+ mojolpm::GetContext()->AddInstance(input.id(), std::move(receiver));
+ result = true;
+ }
+
+ return result;
+}
+
+bool ToProto(::mojo::PendingAssociatedRemote<{{mojom_type}}>&& input,
+ {{proto_type}}::PendingAssociatedRemote& output) {
+ bool result = true;
+
+ ::mojo::AssociatedRemote<{{mojom_type}}> remote(std::move(input));
+ int next_id = NextId<{{mojom_type}}>();
+ output.set_id(AddAssociatedRemote(next_id, std::move(remote)));
+
+ return result;
+}
+
+bool FromProto(const {{proto_type}}::PendingAssociatedReceiver& input,
+ ::mojo::PendingAssociatedReceiver<{{mojom_type}}>& output) {
+ mojolpmdbg("PendingAssociatedReceiver {{interface.name}}\n");
+ ::mojo::AssociatedRemote<{{mojom_type}}> remote = ::mojo::AssociatedRemote<{{mojom_type}}>();
+ output = remote.BindNewEndpointAndPassReceiver();
+
+ mojolpm::GetContext()->task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ base::IgnoreResult(&AddAssociatedRemote<{{mojom_type}}>),
+ input.id(),
+ std::move(remote)));
+
+ return true;
+}
+
+bool ToProto(::mojo::PendingAssociatedReceiver<{{mojom_type}}>&& input,
+ {{proto_type}}::PendingAssociatedReceiver& output) {
+ bool result = true;
+
+ // This should only get called from callbacks into the fuzzer, ie from one of
+ // the XxxImpls or from a return callback. Since that is the case, we want to
+ // bind the receiver and store it.
+
+ auto impl = std::make_unique<{{interface.name}}Impl>();
+ auto receiver = std::make_unique<::mojo::AssociatedReceiver<{{mojom_type}}>>(
+ impl.get(), std::move(input));
+ mojolpm::GetContext()->AddInstance(std::move(impl));
+ output.set_id(mojolpm::GetContext()->AddInstance(std::move(receiver)));
+
+ return result;
+}{{"\n"-}}
+
+{%- for method in interface.methods %}
+{%- set method_type = proto_type ~ "::" ~ interface.name ~ "_" ~ method.name %}
+{%- for param in method.parameters %}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- if kind|is_array_kind or kind|is_map_kind -%}
+{{ from_proto.define(method_type, kind, name) }}
+{{ to_proto.define(method_type, kind, name) }}
+{%- endif %}
+{%- endfor %}
+{%- endfor %}
+{%- for method in interface.methods %}
+{%- if method.response_parameters != None %}
+{%- set method_type = proto_type ~ "::" ~ interface.name ~ "_" ~ method.name ~ "Response" %}
+{%- for param in method.response_parameters %}
+{%- set name = param.name %}
+{%- set kind = param.kind %}
+{%- if kind|is_array_kind or kind|is_map_kind -%}
+{{- from_proto.define(method_type, kind, name)}}
+{{- to_proto.define(method_type, kind, name)}}
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+{%- endfor %}
+{%- endfor %}
+
+{%- for interface in interfaces %}
+{%- set mojom_type = interface|get_qualified_name_for_kind(flatten_nested_kind=True) %}
+{%- set proto_type = "::mojolpm" ~ (interface|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+{%- if interface.methods %}
+bool HandleMethodCall(const {{proto_type}}::MethodCall& input) {
+ bool result = false;
+
+ //mojolpmdbg("HandleMethodCall({{interface.name}})\n");
+
+ {{mojom_type}}Ptr* instance_ptr;
+ instance_ptr = mojolpm::GetContext()->GetInstance<{{mojom_type}}Ptr>(input.ptr().id());
+
+ if (instance_ptr && *instance_ptr) {
+ result = true;
+ }
+
+ if (result) {
+ switch (input.method_case()) {
+{%- for method in interface.methods %}
+ case {{proto_type}}::MethodCall::k{{("m_" ~ method.name)|under_to_camel(digits_split=True)}}: {
+ result = HandleMethodCall(*instance_ptr, input.{{("m" ~ method.name)|camel_to_under}}());
+ } break;
+{%- endfor %}
+case {{proto_type}}::MethodCall::kReset: {
+ mojolpm::GetContext()->GetAndRemoveInstance<{{mojom_type}}Ptr>(input.ptr().id());
+ } break;
+ default: {
+ result = false;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool HandleMethodCallA(const {{proto_type}}::MethodCallA& input) {
+ bool result = false;
+
+ //mojolpmdbg("HandleMethodCall({{interface.name}})\n");
+
+ {{mojom_type}}AssociatedPtr* instance_ptr;
+ instance_ptr = mojolpm::GetContext()->GetInstance<{{mojom_type}}AssociatedPtr>(input.ptr().id());
+
+ if (instance_ptr && instance_ptr->is_bound() && *instance_ptr) {
+ result = true;
+ }
+
+ if (result) {
+ switch (input.method_case()) {
+{%- for method in interface.methods %}
+ case {{proto_type}}::MethodCallA::k{{("m_" ~ method.name)|under_to_camel(digits_split=True)}}: {
+ result = HandleMethodCallA(*instance_ptr, input.{{("m" ~ method.name)|camel_to_under}}());
+ } break;
+{%- endfor %}
+ case {{proto_type}}::MethodCallA::kReset: {
+ mojolpm::GetContext()->GetAndRemoveInstance<{{mojom_type}}AssociatedPtr>(input.ptr().id());
+ } break;
+
+ default: {
+ result = false;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool HandleRemoteMethodCall(const {{proto_type}}::RemoteMethodCall& input) {
+ bool result = false;
+
+ ::mojo::Remote<{{mojom_type}}>* instance_ptr;
+ instance_ptr = mojolpm::GetContext()->GetInstance<::mojo::Remote<{{mojom_type}}>>(input.remote().id());
+
+ if (instance_ptr && *instance_ptr && instance_ptr->is_bound()) {
+ result = true;
+ }
+
+ if (result) {
+ switch (input.method_case()) {
+{%- for method in interface.methods %}
+ case {{proto_type}}::RemoteMethodCall::k{{("m_" ~ method.name)|under_to_camel(digits_split=True)}}: {
+ result = HandleRemoteMethodCall(*instance_ptr, input.{{("m" ~ method.name)|camel_to_under}}());
+ } break;
+{%- endfor %}
+case {{proto_type}}::RemoteMethodCall::kReset: {
+ mojolpm::GetContext()->GetAndRemoveInstance<::mojo::Remote<{{mojom_type}}>>(input.remote().id());
+ } break;
+ default: {
+ result = false;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool HandleAssociatedRemoteMethodCall(const {{proto_type}}::AssociatedRemoteMethodCall& input) {
+ bool result = false;
+
+ ::mojo::AssociatedRemote<{{mojom_type}}>* instance_ptr;
+ instance_ptr = mojolpm::GetContext()->GetInstance<::mojo::AssociatedRemote<{{mojom_type}}>>(input.remote().id());
+
+ if (instance_ptr && *instance_ptr && instance_ptr->is_bound()) {
+ result = true;
+ }
+
+ if (result) {
+ switch (input.method_case()) {
+{%- for method in interface.methods %}
+ case {{proto_type}}::AssociatedRemoteMethodCall::k{{("m_" ~ method.name)|under_to_camel(digits_split=True)}}: {
+ result = HandleAssociatedRemoteMethodCall(*instance_ptr, input.{{("m" ~ method.name)|camel_to_under}}());
+ } break;
+{%- endfor %}
+ case {{proto_type}}::AssociatedRemoteMethodCall::kReset: {
+ mojolpm::GetContext()->GetAndRemoveInstance<::mojo::AssociatedRemote<{{mojom_type}}>>(input.remote().id());
+ } break;
+
+ default: {
+ result = false;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool AddResponse(
+ const {{proto_type}}::ReceiverResponse& input) {
+ bool result = true;
+ switch (input.response_case()) {
+{%- for method in interface.methods %}
+ case {{proto_type}}::ReceiverResponse::k{{("m_" ~ method.name)|under_to_camel(digits_split=True) ~ "Response"}}: {
+ {{proto_type}}::{{interface.name}}_{{method.name}}Response response_copy;
+ response_copy.CopyFrom(input.m_{{method.name|camel_to_under}}_response());
+ mojolpm::GetContext()->AddInstance<
+ {{proto_type}}::{{interface.name}}_{{method.name}}Response>(
+ std::move(response_copy));
+ } break;
+{%- endfor %}
+
+ default: {
+ result = false;
+ }
+ }
+
+ return result;
+}{{"\n"-}}
+{%- for method in interface.methods %}
+{%- if method.response_parameters != None %}
+static void {{interface.name}}_{{method.name}}Callback(
+{%- for param in method.response_parameters %}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- set param_mojom_type = kind|cpp_wrapper_param_type(add_same_module_namespaces=true) %}{{ ',' if not loop.first }}
+ {{param_mojom_type}} param_{{name}}
+{%- endfor -%}
+) {
+{%- for param in method.response_parameters %}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{{ util.add_instance(kind, 'param_' ~ name, False) }}
+{%- endfor %}
+ mojolpmdbg("{{interface.name}}.{{method.name}}Callback\n");
+ mojolpm::GetContext()->NextAction();
+}{{"\n"-}}
+{%- endif %}
+bool HandleMethodCall({{mojom_type}}Ptr& instance,
+ const {{proto_type}}::{{interface.name}}_{{method.name}}& input) {
+ bool mojolpm_result = true;
+ mojolpmdbg("HandleMethodCall({{interface.name}}::{{method.name}})\n");
+{%- for param in method.parameters %}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- set param_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set param_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=True) %}
+ {{param_mojom_type}} local_{{name}};
+{%- if kind|is_nullable_kind %}
+ {{param_maybe_mojom_type}} local_maybe_{{name}};
+{%- endif %}
+{%- endfor %}
+
+{%- for param in method.parameters -%}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- if not kind|is_nullable_kind %}
+ mojolpm_result &= FromProto(input.m_{{name}}(), local_{{name}});
+ mojolpmdbg("{{name}} %i\n", mojolpm_result);
+{%- else %}
+ if (FromProto(input.m_{{name}}(), local_maybe_{{name}})) {
+ local_{{name}} = std::move(local_maybe_{{name}});
+ }
+{%- endif %}
+{%- endfor %}
+ if (mojolpm_result) {
+ instance->{{method.name}}(
+{%- for param in method.parameters -%}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- if kind|is_interface_kind or kind|is_associated_kind %}
+ {{kind|cpp_wrapper_param_type(add_same_module_namespaces=true)}}(std::move(local_{{name}})){{ ',' if not loop.last }}
+{%- else %}
+ std::move(local_{{name}}){{ ',' if not loop.last }}
+{%- endif %}
+{%- endfor -%}
+{%- if method.response_parameters != None -%}
+{{ ',' if method.parameters }}
+ base::BindOnce(&{{interface.name}}_{{method.name}}Callback));
+ }
+{%- else -%}
+);
+ }
+{%- endif %}
+ return mojolpm_result;
+}
+
+bool HandleMethodCallA({{mojom_type}}AssociatedPtr& instance,
+ const {{proto_type}}::{{interface.name}}_{{method.name}}& input) {
+ bool mojolpm_result = true;
+ mojolpmdbg("HandleMethodCallA({{interface.name}}::{{method.name}})\n");
+{%- for param in method.parameters %}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- set param_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set param_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=True) %}
+ {{param_mojom_type}} local_{{name}};
+{%- if kind|is_nullable_kind %}
+ {{param_maybe_mojom_type}} local_maybe_{{name}};
+{%- endif %}
+{%- endfor %}
+
+{%- for param in method.parameters -%}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- if not kind|is_nullable_kind %}
+ mojolpm_result &= FromProto(input.m_{{name}}(), local_{{name}});
+{%- else %}
+ if (FromProto(input.m_{{name}}(), local_maybe_{{name}})) {
+ local_{{name}} = std::move(local_maybe_{{name}});
+ }
+{%- endif %}
+{%- endfor %}
+ if (mojolpm_result) {
+ instance->{{method.name}}(
+{%- for param in method.parameters -%}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- if kind|is_interface_kind or kind|is_associated_kind %}
+ {{kind|cpp_wrapper_param_type(add_same_module_namespaces=true)}}(std::move(local_{{name}})){{ ',' if not loop.last }}
+{%- else %}
+ std::move(local_{{name}}){{ ',' if not loop.last }}
+{%- endif %}
+{%- endfor -%}
+{%- if method.response_parameters != None -%}
+{{ ',' if method.parameters }}
+ base::BindOnce(&{{interface.name}}_{{method.name}}Callback));
+ }
+{%- else -%}
+);
+ }
+{%- endif %}
+ return mojolpm_result;
+}
+bool HandleRemoteMethodCall(::mojo::Remote<{{mojom_type}}>& instance,
+ const {{proto_type}}::{{interface.name}}_{{method.name}}& input) {
+ bool mojolpm_result = true;
+ mojolpmdbg("HandleRemoteMethodCall({{interface.name}}::{{method.name}})\n");
+{%- for param in method.parameters %}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- set param_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set param_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=True) %}
+ {{param_mojom_type}} local_{{name}};
+{%- if kind|is_nullable_kind %}
+ {{param_maybe_mojom_type}} local_maybe_{{name}};
+{%- endif %}
+{%- endfor %}
+
+{%- for param in method.parameters -%}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- if not kind|is_nullable_kind %}
+ mojolpm_result &= FromProto(input.m_{{name}}(), local_{{name}});
+{%- else %}
+ if (FromProto(input.m_{{name}}(), local_maybe_{{name}})) {
+ local_{{name}} = std::move(local_maybe_{{name}});
+ }
+{%- endif %}
+{%- endfor %}
+ if (mojolpm_result) {
+ instance->{{method.name}}(
+{%- for param in method.parameters -%}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- if kind|is_interface_kind or kind|is_associated_kind %}
+ {{kind|cpp_wrapper_param_type(add_same_module_namespaces=true)}}(std::move(local_{{name}})){{ ',' if not loop.last }}
+{%- else %}
+ std::move(local_{{name}}){{ ',' if not loop.last }}
+{%- endif %}
+{%- endfor -%}
+{%- if method.response_parameters != None -%}
+{{ ',' if method.parameters }}
+ base::BindOnce(&{{interface.name}}_{{method.name}}Callback));
+ } else {
+ mojolpmdbg("call failed\n");
+ }
+{%- else -%}
+);
+ }
+{%- endif %}
+ return mojolpm_result;
+}
+
+bool HandleAssociatedRemoteMethodCall(
+ ::mojo::AssociatedRemote<{{mojom_type}}>& instance,
+ const {{proto_type}}::{{interface.name}}_{{method.name}}& input) {
+ bool mojolpm_result = true;
+ mojolpmdbg("HandleAssociatedRemoteMethodCall({{interface.name}}::{{method.name}})\n");
+{%- for param in method.parameters %}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- set param_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set param_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=True) %}
+ {{param_mojom_type}} local_{{name}};
+{%- if kind|is_nullable_kind %}
+ {{param_maybe_mojom_type}} local_maybe_{{name}};
+{%- endif %}
+{%- endfor %}
+
+{%- for param in method.parameters -%}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- if not kind|is_nullable_kind %}
+ mojolpm_result &= FromProto(input.m_{{name}}(), local_{{name}});
+{%- else %}
+ if (FromProto(input.m_{{name}}(), local_maybe_{{name}})) {
+ local_{{name}} = std::move(local_maybe_{{name}});
+ }
+{%- endif %}
+{%- endfor %}
+ if (mojolpm_result) {
+ instance->{{method.name}}(
+{%- for param in method.parameters -%}
+{%- set name = param.name|camel_to_under %}
+{%- set kind = param.kind %}
+{%- if kind|is_interface_kind or kind|is_associated_kind %}
+ {{kind|cpp_wrapper_param_type(add_same_module_namespaces=true)}}(std::move(local_{{name}})){{ ',' if not loop.last }}
+{%- else %}
+ std::move(local_{{name}}){{ ',' if not loop.last }}
+{%- endif %}
+{%- endfor -%}
+{%- if method.response_parameters != None -%}
+{{ ',' if method.parameters }}
+ base::BindOnce(&{{interface.name}}_{{method.name}}Callback));
+ }
+{%- else -%}
+);
+ } else {
+ mojolpmdbg("call failed\n");
+ }
+{%- endif %}
+ return mojolpm_result;
+}{{"\n"-}}
+{%- endfor %}
+{%- endif %}
+{%- endfor -%}
+} // namespace mojolpm
diff --git a/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.h.tmpl b/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.h.tmpl
new file mode 100644
index 00000000000..16af070194f
--- /dev/null
+++ b/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.h.tmpl
@@ -0,0 +1,251 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+{%- set header_guard = "%s_MOJOLPM_H_"|format(
+ module.path|upper|replace("/","_")|replace(".","_")|
+ replace("-", "_")) %}
+
+{%- macro namespace_begin() %}
+namespace mojolpm {
+{%- for namespace in namespaces_as_array %}
+namespace {{namespace}} {
+{%- endfor %}
+{%- endmacro %}
+
+{%- macro namespace_end() %}
+{%- for namespace in namespaces_as_array|reverse %}
+} // namespace {{namespace}}
+{%- endfor %}
+} // namespace mojolpm
+{%- endmacro %}
+
+#ifndef {{header_guard}}
+#define {{header_guard}}
+
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/tools/fuzzers/mojolpm.h"
+
+{% for extra_public_header in extra_public_headers %}
+#include "{{extra_public_header}}"
+{%- endfor %}
+
+{% for import in imports %}
+#include "{{import.path}}-mojolpm.h"
+#include "{{import.path}}.h"
+{%- endfor %}
+
+#include "{{module.path}}.mojolpm.pb.h"
+#include "{{module.path}}.h"
+
+{%- import "mojolpm_macros.tmpl" as util %}
+{%- import "mojolpm_from_proto_macros.tmpl" as from_proto %}
+{%- import "mojolpm_to_proto_macros.tmpl" as to_proto %}
+
+namespace mojolpm {
+
+{%- for enum in all_enums %}
+{%- set mojom_type = enum|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set proto_type = "::mojolpm" ~ (enum|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+// enum {{enum.name}}
+bool FromProto(
+ const {{proto_type}}& input,
+ {{mojom_type}}& output);
+
+bool ToProto(
+ const {{mojom_type}}& input,
+ {{proto_type}}& output);
+{% endfor %}
+
+{%- for struct in structs %}
+{%- set mojom_in_type = struct|cpp_wrapper_param_type(add_same_module_namespaces=true) %}
+{%- set mojom_out_type = struct|cpp_wrapper_call_type(add_same_module_namespaces=true) %}
+{%- set maybe_const = "const " if not struct|contains_handles_or_interfaces else "" %}
+{%- set proto_type = "::mojolpm" ~ (struct|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+{%- set struct_type = proto_type ~ "_ProtoStruct" %}
+// struct {{struct.name}}
+bool FromProto(
+ const {{proto_type}}& input,
+ {{mojom_out_type}}& output);
+
+bool ToProto(
+ {{mojom_in_type}} input,
+ {{proto_type}}& output);{{"\n"-}}
+{%- for field in struct.fields %}
+{%- set name = field.name %}
+{%- set kind = field.kind %}
+{%- if kind|is_array_kind or kind|is_map_kind %}
+{{- from_proto.declare(struct_type, kind, name) }}
+{{- to_proto.declare(struct_type, kind, name) }}
+{%- endif %}
+{%- endfor %}
+{%- endfor %}
+
+{%- for union in unions %}
+{%- set mojom_in_type = union|cpp_wrapper_param_type(add_same_module_namespaces=true) %}
+{%- set mojom_out_type = union|cpp_wrapper_call_type(add_same_module_namespaces=true) %}
+{%- set maybe_const = "const " if not union|contains_handles_or_interfaces else "" %}
+{%- set proto_type = "::mojolpm" ~ (union|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+{%- set union_type = proto_type ~ "_ProtoUnion" %}
+{%- if union|is_native_only_kind %}
+#error "Mojo native-only union {{union.name}} - don't think this is possible"
+{%- else %}
+// union {{union.name}}
+bool FromProto(
+ const {{proto_type}}& input,
+ {{mojom_out_type}}& output);
+
+bool ToProto(
+ {{mojom_in_type}} input,
+ {{proto_type}}& output);{{"\n"-}}
+{%- endif %}
+{%- for field in union.fields %}
+{%- set name = field.name %}
+{%- set kind = field.kind %}
+{%- if kind|is_array_kind or kind|is_map_kind %}
+{{- from_proto.declare(union_type, kind, name) }}
+{{- to_proto.declare(union_type, kind, name) }}
+{%- endif %}
+{%- endfor %}
+{%- endfor %}
+
+{%- for interface in interfaces %}
+{%- set mojom_type = interface|get_qualified_name_for_kind(flatten_nested_kind=True) %}
+{%- set proto_type = "::mojolpm" ~ (interface|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+// interface {{interface.name}}
+bool FromProto(
+ const {{proto_type}}::Ptr& input,
+ {{mojom_type}}PtrInfo& output);
+
+bool ToProto(
+ {{mojom_type}}Ptr&& input,
+ {{proto_type}}::Ptr& output);
+
+bool ToProto(
+ {{mojom_type}}PtrInfo&& input,
+ {{proto_type}}::Ptr& output);
+
+bool FromProto(
+ const {{proto_type}}::AssociatedPtr& input,
+ {{mojom_type}}AssociatedPtrInfo& output);
+
+bool ToProto(
+ {{mojom_type}}AssociatedPtrInfo&& input,
+ {{proto_type}}::AssociatedPtr& output);
+
+bool FromProto(
+ const {{proto_type}}::Request& input,
+ {{mojom_type}}Request& output);
+
+bool ToProto(
+ {{mojom_type}}Request&& input,
+ {{proto_type}}::Request& output);
+
+bool FromProto(
+ const {{proto_type}}::AssociatedRequest& input,
+ {{mojom_type}}AssociatedRequest& output);
+
+bool ToProto(
+ {{mojom_type}}AssociatedRequest&& input,
+ {{proto_type}}::AssociatedRequest& output);
+
+bool FromProto(
+ const {{proto_type}}::PendingRemote& input,
+ ::mojo::PendingRemote<{{mojom_type}}>& output);
+
+bool ToProto(
+ ::mojo::PendingRemote<{{mojom_type}}>&& input,
+ {{proto_type}}::PendingRemote& output);
+
+bool FromProto(
+ const {{proto_type}}::PendingReceiver& input,
+ ::mojo::PendingReceiver<{{mojom_type}}>& output);
+
+bool ToProto(
+ ::mojo::PendingReceiver<{{mojom_type}}>&& input,
+ {{proto_type}}::PendingReceiver& output);
+
+bool FromProto(
+ const {{proto_type}}::PendingAssociatedRemote& input,
+ ::mojo::PendingAssociatedRemote<{{mojom_type}}>& output);
+
+bool ToProto(
+ ::mojo::PendingAssociatedRemote<{{mojom_type}}>&& input,
+ {{proto_type}}::PendingAssociatedRemote& output);
+
+bool FromProto(
+ const {{proto_type}}::PendingAssociatedReceiver& input,
+ ::mojo::PendingAssociatedReceiver<{{mojom_type}}>& output);
+
+bool ToProto(
+ ::mojo::PendingAssociatedReceiver<{{mojom_type}}>&& input,
+ {{proto_type}}::PendingAssociatedReceiver& output);{{"\n"-}}
+{%- for method in interface.methods %}
+{%- set method_type = proto_type ~ "::" ~ interface.name ~ "_" ~ method.name %}
+{%- for param in method.parameters %}
+{%- set name = param.name %}
+{%- set kind = param.kind %}
+{%- if kind|is_array_kind or kind|is_map_kind -%}
+{{- from_proto.declare(method_type, kind, name)}}
+{{- to_proto.declare(method_type, kind, name)}}
+{%- endif %}
+{%- endfor %}
+{%- endfor %}
+{%- for method in interface.methods %}
+{%- if method.response_parameters != None %}
+{%- set method_type = proto_type ~ "::" ~ interface.name ~ "_" ~ method.name ~ "Response" %}
+{%- for param in method.response_parameters %}
+{%- set name = param.name %}
+{%- set kind = param.kind %}
+{%- if kind|is_array_kind or kind|is_map_kind -%}
+{{- from_proto.declare(method_type, kind, name)}}
+{{- to_proto.declare(method_type, kind, name)}}
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+{%- endfor %}
+{%- endfor %}
+
+{%- for interface in interfaces %}
+{%- set mojom_type = interface|get_qualified_name_for_kind(flatten_nested_kind=True) %}
+{%- set proto_type = "::mojolpm" ~ (interface|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+{%- if interface.methods %}
+bool HandleMethodCall(
+ const {{proto_type}}::MethodCall& input);
+
+bool HandleMethodCallA(
+ const {{proto_type}}::MethodCallA& input);
+
+bool HandleRemoteMethodCall(
+ const {{proto_type}}::RemoteMethodCall& input);
+
+bool HandleAssociatedRemoteMethodCall(
+ const {{proto_type}}::AssociatedRemoteMethodCall& input);
+
+bool AddResponse(
+ const {{proto_type}}::ReceiverResponse& response);{{"\n"-}}
+{%- for method in interface.methods %}
+bool HandleMethodCall(
+ {{mojom_type}}Ptr& instance,
+ const {{proto_type}}::{{interface.name}}_{{method.name}}& input);
+
+bool HandleMethodCallA(
+ {{mojom_type}}AssociatedPtr& instance,
+ const {{proto_type}}::{{interface.name}}_{{method.name}}& input);
+
+bool HandleRemoteMethodCall(
+ ::mojo::Remote<{{mojom_type}}>& instance,
+ const {{proto_type}}::{{interface.name}}_{{method.name}}& input);
+
+bool HandleAssociatedRemoteMethodCall(
+ ::mojo::AssociatedRemote<{{mojom_type}}>& instance,
+ const {{proto_type}}::{{interface.name}}_{{method.name}}& input);{{"\n"-}}
+{%- endfor %}
+{%- endif %}
+{%- endfor -%}
+} // namespace mojolpm
+
+#endif // {{header_guard}}
diff --git a/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.proto.tmpl b/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.proto.tmpl
new file mode 100644
index 00000000000..521cdf4e6e8
--- /dev/null
+++ b/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.proto.tmpl
@@ -0,0 +1,406 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+syntax = "proto2";
+
+package mojolpm.{{module.mojom_namespace|replace("/",".")}};
+
+{% for proto_import in proto_imports %}
+import "{{proto_import}}";
+{%- endfor %}
+
+{%- set module_prefix = "%s"|format(namespaces_as_array|join(".")) %}
+
+{%- macro optional_or_required(kind) %}
+{%- if kind|is_nullable_kind %}optional
+{%- else -%}required
+{%- endif %}
+{%- endmacro -%}
+
+{%- for enum in enums %}
+{%- set enum_name = enum|get_name_for_kind(flatten_nested_kind=True) %}
+{%- if enum|is_native_only_kind %}
+// WARNING Native only enum support {{enum_name}} is very basic.
+enum {{enum.name}} {
+ {{enum.name}}_0 = 0;
+ {{enum.name}}_1 = 1;
+ {{enum.name}}_2 = 2;
+ {{enum.name}}_3 = 3;
+ {{enum.name}}_4 = 4;
+ {{enum.name}}_5 = 5;
+ {{enum.name}}_6 = 6;
+ {{enum.name}}_7 = 7;
+ {{enum.name}}_8 = 8;
+ {{enum.name}}_9 = 9;
+ {{enum.name}}_10 = 10;
+ {{enum.name}}_11 = 11;
+ {{enum.name}}_12 = 12;
+ {{enum.name}}_13 = 13;
+ {{enum.name}}_14 = 14;
+ {{enum.name}}_15 = 15;
+}
+{%- else %}
+
+enum {{enum_name}} {
+{%- if enum|has_duplicate_values %}
+ option allow_alias = true;
+{%- endif %}
+{%- set i = 0 %}
+{%- for field in enum.fields %}
+{%- if field.name != "MAX" %}
+ {{enum.name}}_{{field.name|enum_field_name(enum)}} = {{field.numeric_value}};
+{%- endif %}
+{%- endfor %}
+}
+{%- endif %}
+{%- endfor %}
+
+{%- macro forward_declare_field_types_inner(kind, name) %}
+{%- if kind|is_array_kind %}
+{%- set entry_name = name ~ "Entry" -%}
+{%- if (kind.kind|is_array_kind or kind.kind|is_map_kind) %}
+{{forward_declare_field_types_inner(kind.kind, entry_name)}}
+{%- else %}
+ message {{entry_name}} {
+ {{kind.kind|proto_field_type}} value = 1;
+ }
+{%- endif %}
+
+ message {{name}} {
+ repeated {{entry_name}} values = 1;
+ }
+
+{%- elif kind|is_map_kind %}
+{%- set entry_name = name ~ "Entry" %}
+{%- set key_name = name ~ "Key" %}
+{%- set value_name = name ~ "Value" -%}
+{%- if (kind.key_kind|is_array_kind or kind.key_kind|is_map_kind) -%}
+{{forward_declare_field_types_inner(kind.key_kind, key_name)}}
+{%- else %}
+ message {{key_name}} {
+ {{kind.key_kind|proto_field_type}} value = 1;
+ }
+{% endif %}
+{%- if (kind.value_kind|is_array_kind or kind.value_kind|is_map_kind) -%}
+{{forward_declare_field_types_inner(kind.value_kind, value_name)}}
+{%- else %}
+ message {{value_name}} {
+ {{kind.value_kind|proto_field_type}} value = 1;
+ }
+{% endif %}
+ message {{entry_name}} {
+ required {{key_name}} key = 1;
+ required {{value_name}} value = 2;
+ }
+
+ message {{name}} {
+ repeated {{entry_name}} values = 1;
+ }
+{%- endif %}
+{% endmacro %}
+
+{%- macro forward_declare_field_types(kind, name) %}
+{%- if kind|is_array_kind %}
+{%- set array_name = (name|under_to_camel) ~ "_Array" -%}
+{{ forward_declare_field_types_inner(kind, array_name) }}
+{%- elif kind|is_map_kind %}
+{%- set map_name = (name|under_to_camel) ~ "_Map" %}
+{{ forward_declare_field_types_inner(kind, map_name) }}
+{%- endif %}
+{% endmacro %}
+
+{%- for struct in structs %}
+{%- set struct_name = struct|get_name_for_kind(flatten_nested_kind=True) %}
+{%- if struct|is_native_only_kind %}
+message {{struct_name}}_ProtoStruct {
+ // native-only struct
+ required uint32 id = 1;
+ required bytes native_bytes = 2;
+}
+{%- else %}
+
+message {{struct_name}}_ProtoStruct {
+ required uint32 id = 1;
+{%- for pf in struct.packed.packed_fields_in_ordinal_order -%}
+{%- set name = pf.field.name|camel_to_under %}
+{%- set kind = pf.field.kind %}
+{%- if (kind|is_array_kind or kind|is_map_kind) -%}
+{{forward_declare_field_types(kind, name)}}
+{%- endif %}
+{%- endfor %}
+{%- for pf in struct.packed.packed_fields_in_ordinal_order %}
+{%- set name = pf.field.name|camel_to_under %}
+{%- set kind = pf.field.kind %}
+{%- if kind|is_array_kind %}
+ {{optional_or_required(kind)}} {{name|under_to_camel}}_Array m_{{name}} = {{name|proto_id(kind)}};
+{%- elif kind|is_map_kind %}
+ {{optional_or_required(kind)}} {{name|under_to_camel}}_Map m_{{name}} = {{name|proto_id(kind)}};
+{%- else %}
+ {{kind|proto_field_type}} m_{{name}} = {{name|proto_id(kind)}};
+{%- endif %}
+{%- endfor %}
+}
+{%- endif %}
+
+message {{struct_name}} {
+{%- for enum in struct.enums %}
+{%- set enum_name = enum|get_name_for_kind(flatten_nested_kind=True) %}
+{%- if enum|is_native_only_kind %}
+ // WARNING Native only enum support {{enum_name}} is very basic.
+ enum {{enum.name}} {
+ {{enum.name}}_0 = 0;
+ {{enum.name}}_1 = 1;
+ {{enum.name}}_2 = 2;
+ {{enum.name}}_3 = 3;
+ {{enum.name}}_4 = 4;
+ {{enum.name}}_5 = 5;
+ {{enum.name}}_6 = 6;
+ {{enum.name}}_7 = 7;
+ {{enum.name}}_8 = 8;
+ {{enum.name}}_9 = 9;
+ {{enum.name}}_10 = 10;
+ {{enum.name}}_11 = 11;
+ {{enum.name}}_12 = 12;
+ {{enum.name}}_13 = 13;
+ {{enum.name}}_14 = 14;
+ {{enum.name}}_15 = 15;
+ }
+{%- else %}
+
+ enum {{enum.name}} {
+{%- if enum|has_duplicate_values %}
+ option allow_alias = true;
+{%- endif %}
+{%- set i = 0 %}
+{%- for field in enum.fields %}
+ {{enum_name}}_{{field.name}} = {{field.numeric_value}};
+{%- endfor %}
+ }
+{%- endif %}
+{%- endfor %}
+
+ oneof instance {
+ uint32 old = 1;
+ {{struct_name}}_ProtoStruct new = 2;
+ }
+}
+{%- endfor %}
+
+{%- for union in unions %}
+{%- set union_name = union|get_name_for_kind(flatten_nested_kind=True) %}
+{%- if union|is_native_only_kind %}
+// ERROR native-only union kind
+{%- else %}
+
+message {{union_name}}_ProtoUnion {
+ required uint32 id = 1;
+{%- for field in union.fields %}
+{%- set name = field.name|camel_to_under %}
+{%- set kind = field.kind %}
+{%- if (kind|is_array_kind or kind|is_map_kind) -%}
+{{forward_declare_field_types(kind, name)}}
+{%- endif %}
+{%- endfor %}
+ oneof union_member {
+{%- for field in union.fields %}
+{%- set name = field.name|lower %}
+{%- set kind = field.kind %}
+{%- if kind|is_array_kind %}
+ {{name|under_to_camel}}_Array m_{{name}} = {{name|proto_id(kind)}};
+{%- elif kind|is_map_kind %}
+ {{name|under_to_camel}}_Map m_{{name}} = {{name|proto_id(kind)}};
+{%- else %}
+ {{kind|proto_field_type(quantified=False)}} m_{{name}} = {{name|proto_id(kind)}};
+{%- endif %}
+{%- endfor %}
+ }
+}
+
+message {{union_name}} {
+ oneof instance {
+ uint32 old = 1;
+ {{union_name}}_ProtoUnion new = 2;
+ }
+}
+{%- endif %}
+{%- endfor %}
+
+{%- for interface in interfaces %}
+
+message {{interface.name}} {
+ // TODO(markbrand): remove the old types once crbug/955171 is landed.
+ message Ptr {
+ required uint32 id = 1;
+ }
+
+ message AssociatedPtr {
+ required uint32 id = 1;
+ }
+
+ message Request {
+ required uint32 id = 1;
+ }
+
+ message AssociatedRequest {
+ required uint32 id = 1;
+ }
+
+ message PendingRemote {
+ required uint32 id = 1;
+ }
+
+ message PendingReceiver {
+ required uint32 id = 1;
+ }
+
+ message PendingAssociatedRemote {
+ required uint32 id = 1;
+ }
+
+ message PendingAssociatedReceiver {
+ required uint32 id = 1;
+ }
+
+ message Reset {
+ }
+
+{%- for enum in interface.enums %}
+{%- set enum_name = enum|get_name_for_kind(flatten_nested_kind=True) %}
+{%- if enum|is_native_only_kind %}
+ // WARNING Native only enum support {{enum_name}} is very basic.
+ enum {{enum.name}} {
+ {{enum.name}}_0 = 0;
+ {{enum.name}}_1 = 1;
+ {{enum.name}}_2 = 2;
+ {{enum.name}}_3 = 3;
+ {{enum.name}}_4 = 4;
+ {{enum.name}}_5 = 5;
+ {{enum.name}}_6 = 6;
+ {{enum.name}}_7 = 7;
+ {{enum.name}}_8 = 8;
+ {{enum.name}}_9 = 9;
+ {{enum.name}}_10 = 10;
+ {{enum.name}}_11 = 11;
+ {{enum.name}}_12 = 12;
+ {{enum.name}}_13 = 13;
+ {{enum.name}}_14 = 14;
+ {{enum.name}}_15 = 15;
+ }
+{%- else %}
+
+ enum {{enum.name}} {
+{%- if enum|has_duplicate_values %}
+ option allow_alias = true;
+{%- endif %}
+{%- set i = 0 %}
+{%- for field in enum.fields %}
+ {{enum.name}}_{{field.name}} = {{field.numeric_value}};
+{%- endfor %}
+ }
+{%- endif %}
+{%- endfor %}
+
+{%- for method in interface.methods %}
+
+ message {{interface.name}}_{{method.name}} {
+{%- for parameter in method.parameters %}
+{%- set name = parameter.name|camel_to_under %}
+{%- set kind = parameter.kind %}
+{%- if (kind|is_array_kind or kind|is_map_kind) -%}
+{{forward_declare_field_types(kind, name)|indent(width=2)}}
+{%- endif %}
+{%- endfor %}
+{%- for parameter in method.parameters %}
+{%- set name = parameter.name|camel_to_under %}
+{%- set kind = parameter.kind %}
+{%- if kind|is_array_kind %}
+ {{optional_or_required(kind)}} {{name|under_to_camel}}_Array m_{{name}} = {{name|proto_id(kind)}};
+{%- elif kind|is_map_kind %}
+ {{optional_or_required(kind)}} {{name|under_to_camel}}_Map m_{{name}} = {{name|proto_id(kind)}};
+{%- else %}
+ {{kind|proto_field_type}} m_{{name}} = {{name|proto_id(kind)}};
+{%- endif %}
+{%- endfor %}
+ }
+
+ message {{interface.name}}_{{method.name}}Response {
+{%- if method.response_parameters %}
+{%- for parameter in method.response_parameters %}
+{%- set name = parameter.name|camel_to_under %}
+{%- set kind = parameter.kind %}
+{%- if (kind|is_array_kind or kind|is_map_kind) -%}
+{{forward_declare_field_types(kind, name)|indent(width=2)}}
+{%- endif %}
+{%- endfor %}
+{%- for parameter in method.response_parameters %}
+{%- set name = parameter.name|camel_to_under %}
+{%- set kind = parameter.kind %}
+{%- if kind|is_array_kind %}
+ {{optional_or_required(kind)}} {{name|under_to_camel}}_Array m_{{name}} = {{name|proto_id(kind)}};
+{%- elif kind|is_map_kind %}
+ {{optional_or_required(kind)}} {{name|under_to_camel}}_Map m_{{name}} = {{name|proto_id(kind)}};
+{%- else %}
+ {{kind|proto_field_type}} m_{{name}} = {{name|proto_id(kind)}};
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+ }
+{%- endfor%}
+
+{%- if interface.methods|length %}
+ message MethodCall {
+ required {{interface.name}}.Ptr ptr = 1;
+
+ oneof method {
+ Reset reset = 2;
+{%- for method in interface.methods %}
+ {{interface.name}}_{{method.name}} m_{{method.name|camel_to_under}} = {{loop.index + 2}};
+{%- endfor %}
+ }
+ }
+
+ message MethodCallA {
+ required {{interface.name}}.AssociatedPtr ptr = 1;
+
+ oneof method {
+ Reset reset = 2;
+{%- for method in interface.methods %}
+ {{interface.name}}_{{method.name}} m_{{method.name|camel_to_under}} = {{loop.index + 2}};
+{%- endfor %}
+ }
+ }
+
+ message RemoteMethodCall {
+ required {{interface.name}}.PendingRemote remote = 1;
+
+ oneof method {
+ Reset reset = 2;
+{%- for method in interface.methods %}
+ {{interface.name}}_{{method.name}} m_{{method.name|camel_to_under}} = {{loop.index + 2}};
+{%- endfor %}
+ }
+ }
+
+ message AssociatedRemoteMethodCall {
+ required {{interface.name}}.PendingAssociatedRemote remote = 1;
+
+ oneof method {
+ Reset reset = 2;
+{%- for method in interface.methods %}
+ {{interface.name}}_{{method.name}} m_{{method.name|camel_to_under}} = {{loop.index + 2}};
+{%- endfor %}
+ }
+ }
+
+ message ReceiverResponse {
+ oneof response {
+{%- for method in interface.methods %}
+ {{interface.name}}_{{method.name}}Response m_{{method.name|camel_to_under}}_response = {{loop.index + 2}};
+{%- endfor %}
+ }
+ }
+{%- endif %}
+}
+
+{%- endfor %}
diff --git a/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_from_proto_macros.tmpl b/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_from_proto_macros.tmpl
new file mode 100644
index 00000000000..6a7c3989e3d
--- /dev/null
+++ b/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_from_proto_macros.tmpl
@@ -0,0 +1,383 @@
+{% import "mojolpm_macros.tmpl" as util %}
+
+
+{%- macro declare_array(type, kind) %}
+{%- set mojom_type = kind.kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set mojom_maybe_type = kind.kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=true) %}
+bool FromProto(
+ const {{type}}& input,
+ std::vector<{{mojom_type}}>& output);{{"\n"-}}
+{%- if kind.kind|is_array_kind %}
+{{declare_array(type ~ "Entry", kind.kind)}}
+{%- elif kind.kind|is_map_kind %}
+{{declare_map(type ~ "Entry", kind.kind)}}
+{%- elif kind.kind|is_nullable_kind %}
+bool FromProto(
+ const {{type}}Entry& input,
+ {{mojom_maybe_type}}& output);{{"\n"-}}
+{%- else %}
+bool FromProto(
+ const {{type}}Entry& input,
+ {{mojom_type}}& output);{{"\n"-}}
+{%- endif %}
+{%- endmacro %}
+
+
+{%- macro declare_map(type, kind) %}
+{%- set mojom_key_type = kind.key_kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set mojom_value_type = kind.value_kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set mojom_maybe_value_type = kind.value_kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=true) %}
+bool FromProto(
+ const {{type}}& input,
+ base::flat_map<{{mojom_key_type}},
+ {{mojom_value_type}}>& output);{{"\n"-}}
+{%- if kind.key_kind|is_array_kind %}
+{{- declare_array(type ~ "Key", kind.key_kind)}}
+{%- elif kind.key_kind|is_map_kind %}
+{{- declare_map(type ~ "Key", kind.key_kind)}}
+{%- else %}
+bool FromProto(
+ const {{type}}Key& input,
+ {{mojom_key_type}}& output);{{"\n"-}}
+{%- endif %}
+{%- if kind.value_kind|is_array_kind %}
+{{- declare_array(type ~ "Value", kind.value_kind)}}
+{%- elif kind.value_kind|is_map_kind %}
+{{- declare_map(type ~ "Value", kind.value_kind)}}
+{%- elif kind.value_kind|is_nullable_kind %}
+bool FromProto(
+ const {{type}}Value& input,
+ {{mojom_maybe_value_type}}& output);{{"\n"-}}
+{%- else %}
+bool FromProto(
+ const {{type}}Value& input,
+ {{mojom_value_type}}& output);{{"\n"-}}
+{%- endif %}
+{%- endmacro %}
+
+
+{%- macro declare(parent_name, kind, name) %}
+{%- if kind|is_array_kind %}
+{%- set array_type = parent_name ~ "::" ~ name|under_to_camel ~ "_Array" %}
+{{- declare_array(array_type, kind)}}
+{%- elif kind|is_map_kind %}
+{%- set map_type = parent_name ~ "::" ~ name|under_to_camel ~ "_Map" %}
+{{- declare_map(map_type, kind)}}
+{%- endif %}
+{%- endmacro %}
+
+
+{%- macro define_array(type, kind) %}
+{%- set mojom_type = kind.kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set mojom_maybe_type = kind.kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=true) %}
+bool FromProto(
+ const {{type}}& input,
+ std::vector<{{mojom_type}}>& output) {
+ bool result = true;
+ size_t i = 0;
+
+ output.resize(input.values_size());
+
+ for (const auto& entry : input.values()) {
+{%- if kind.kind|is_nullable_kind %}
+ {{mojom_type}} value;
+ {{mojom_maybe_type}} maybe_value;
+ if (FromProto(entry.value(), maybe_value)) {
+ value = std::move(maybe_value);
+ }
+ output[i++] = std::move(value);
+{%- elif kind.kind|is_map_kind or kind.kind|is_array_kind %}
+ {{mojom_type}} values;
+ result = FromProto(entry, values);
+ if (!result) {
+ break;
+ }
+ output[i++] = std::move(values);
+{%- else %}
+ {{mojom_type}} value;
+ result = FromProto(entry.value(), value);
+ if (!result) {
+ break;
+ }
+ output[i++] = std::move(value);
+{%- endif %}
+ }
+
+ return result;
+}{{"\n"-}}
+{%- if kind.kind|is_array_kind %}
+{{- define_array(type ~ "Entry", kind.kind)}}
+{%- elif kind.kind|is_map_kind %}
+{{- define_map(type ~ "Entry", kind.kind)}}
+{%- elif kind.kind|is_nullable_kind %}
+bool FromProto(
+ const {{type}}Entry& input,
+ {{mojom_maybe_type}}& output) {
+ return FromProto(input.value(), output);
+}{{"\n"-}}
+{%- else %}
+bool FromProto(
+ const {{type}}Entry& input,
+ {{mojom_type}}& output) {
+ return FromProto(input.value(), output);
+}{{"\n"-}}
+{%- endif %}
+{%- endmacro %}
+
+
+{%- macro define_map(type, kind) %}
+{%- set mojom_key_type = kind.key_kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set mojom_value_type = kind.value_kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set mojom_maybe_value_type = kind.value_kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=true) %}
+bool FromProto(
+ const {{type}}& input,
+ base::flat_map<{{mojom_key_type}},
+ {{mojom_value_type}}>& output) {
+ bool result = true;
+ for (const auto& entry : input.values()) {
+{%- if kind.value_kind|is_nullable_kind %}
+ {{mojom_key_type}} key;
+ {{mojom_value_type}} value;
+ {{mojom_maybe_value_type}} maybe_value;
+
+ if (FromProto(entry.key(), key)) {
+ if (FromProto(entry.value(), maybe_value)) {
+ value = std::move(maybe_value);
+ }
+ output.emplace(std::move(key), std::move(value));
+ } else {
+ result = false;
+ break;
+ }
+{%- else %}
+ {{mojom_key_type}} key;
+ {{mojom_value_type}} value;
+
+ if (FromProto(entry.key(), key)
+ && FromProto(entry.value(), value)) {
+ output.emplace(std::move(key), std::move(value));
+ } else {
+ result = false;
+ break;
+ }
+{%- endif %}
+ }
+
+ return result;
+}{{"\n"-}}
+{%- if kind.key_kind|is_array_kind %}
+{{define_array(type ~ "Key", kind.key_kind)}}
+{%- elif kind.key_kind|is_map_kind %}
+{{define_map(type ~ "Key", kind.key_kind)}}
+{%- else %}
+bool FromProto(
+ const {{type}}Key& input,
+ {{mojom_key_type}}& output) {
+ return FromProto(input.value(), output);
+}{{"\n"-}}
+{%- endif %}
+{%- if kind.value_kind|is_array_kind %}
+{{- define_array(type ~ "Value", kind.value_kind)}}
+{%- elif kind.value_kind|is_map_kind %}
+{{- define_map(type ~ "Value", kind.value_kind)}}
+{%- elif kind.value_kind|is_nullable_kind %}
+bool FromProto(
+ const {{type}}Value& input,
+ {{mojom_maybe_value_type}}& output) {
+ return FromProto(input.value(), output);
+}{{"\n"-}}
+{%- else %}
+bool FromProto(
+ const {{type}}Value& input,
+ {{mojom_value_type}}& output) {
+ return FromProto(input.value(), output);
+}{{"\n"-}}
+{%- endif %}
+{%- endmacro %}
+
+
+{%- macro define(parent_name, kind, name) %}
+{%- if kind|is_array_kind %}
+{%- set array_type = parent_name ~ "::" ~ name|under_to_camel ~ "_Array" %}
+{{- define_array(array_type, kind)}}
+{%- elif kind|is_map_kind %}
+{%- set map_type = parent_name ~ "::" ~ name|under_to_camel ~ "_Map" %}
+{{- define_map(map_type, kind)}}
+{%- endif %}
+{%- endmacro %}
+
+
+{%- macro define_enum(enum) -%}
+{%- set mojom_type = enum|cpp_wrapper_call_type(add_same_module_namespaces=true) %}
+{%- set proto_type = "::mojolpm" ~ (enum|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+{%- set enum_type = enum|get_qualified_name_for_kind(flatten_nested_kind=True) %}
+bool FromProto(
+ const {{proto_type}}& input,
+ {{mojom_type}}& output) {
+{%- if enum|is_native_only_kind or not enum|is_typemapped_kind %}
+ // This ignores IPC_PARAM_TRAITS for native IPC enums, but internal to the
+ // fuzzer we don't want the overhead of the serialization layer if we don't
+ // need it. This doesn't change the actual checks on the receiving end.
+ output = static_cast<{{mojom_type}}>(input);
+ return true;
+{%- else %}
+ return mojo::EnumTraits<{{enum_type}}, {{mojom_type}}>::FromMojom(
+ static_cast<{{enum_type}}>(input), &output);
+{%- endif %}
+}
+{%- endmacro %}
+
+
+{%- macro define_struct(struct) -%}
+{%- set mojom_type = struct|cpp_wrapper_call_type(add_same_module_namespaces=true) %}
+{%- set proto_type = "::mojolpm" ~ (struct|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+{%- set struct_type = proto_type ~ "_ProtoStruct" %}
+bool FromProto(
+ const {{struct_type}}& input,
+ {{mojom_type}}& output) {
+{%- if struct|is_native_only_kind %}
+ memset((void*)&output, 0, sizeof(output));
+ if (input.native_bytes().size() < sizeof(output)) {
+ memcpy((void*)&output, input.native_bytes().data(), input.native_bytes().size());
+ } else {
+ memcpy((void*)&output, input.native_bytes().data(), sizeof(output));
+ }
+ return true;
+{%- elif struct|is_typemapped_kind %}
+{%- set dataview_type = (struct|get_qualified_name_for_kind(flatten_nested_kind=True)) ~ "DataView" %}
+{%- set data_type = (struct|get_qualified_name_for_kind(flatten_nested_kind=True, internal=True)) %}
+ ::mojo::internal::SerializationContext mojolpm_serialization_context;
+ auto mojolpm_buffer = mojolpm::GetContext()->message().payload_buffer();
+ {{data_type}}::BufferWriter mojolpm_writer;
+ bool result = false;
+
+ ::mojo::internal::Serializer<{{dataview_type}}, const {{struct_type}}>::Serialize(
+ input, mojolpm_buffer, &mojolpm_writer, &mojolpm_serialization_context);
+ result = ::mojo::internal::Serializer<{{dataview_type}}, {{mojom_type}}>::Deserialize(
+ mojolpm_writer.data(), &output, &mojolpm_serialization_context);
+
+ return result;
+
+{%- elif struct.fields %}
+ bool mojolpm_result = true;
+{%- for field in struct.fields %}
+{%- set name = field.name|camel_to_under %}
+{%- set kind = field.kind %}
+{%- set field_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set field_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=true) %}
+ {{field_mojom_type}} local_{{name}};
+{%- if kind|is_nullable_kind %}
+ {{field_maybe_mojom_type}} local_maybe_{{name}};
+{%- endif %}
+{%- endfor %}
+
+{%- for field in struct.fields -%}
+{%- set name = field.name|camel_to_under %}
+{%- set kind = field.kind %}
+{%- if not kind|is_nullable_kind %}
+ mojolpm_result &= FromProto(input.m_{{name}}(), local_{{name}});
+{%- else %}
+ if (input.has_m_{{name}}() && FromProto(input.m_{{name}}(), local_maybe_{{name}})) {
+ local_{{name}} = std::move(local_maybe_{{name}});
+ }
+{%- endif %}
+{%- endfor %}
+ if (mojolpm_result) {
+ output = {{struct|get_qualified_name_for_kind(flatten_nested_kind=true)}}::New(
+{%- for field in struct.fields -%}
+{%- set name = field.name|camel_to_under %}
+ std::move(local_{{name}}){{ ', ' if not loop.last }}
+{%- endfor -%});
+ }
+
+ return mojolpm_result;
+{%- else %}
+ output = {{struct|get_qualified_name_for_kind(flatten_nested_kind=true)}}::New();
+ return true;
+{%- endif %}
+}
+
+bool FromProto(
+ const {{proto_type}}& input,
+ {{mojom_type}}& output) {
+ if (input.instance_case() == {{proto_type}}::kOld) {
+ {{struct_type}}* old = mojolpm::GetContext()->GetInstance<{{struct_type}}>(input.old());
+ if (old) {
+ return FromProto(*old, output);
+ }
+ } else {
+ return FromProto(input.new_(), output);
+ }
+
+ return false;
+}
+{%- endmacro %}
+
+
+{%- macro define_union(union) -%}
+{%- set mojom_type = union|cpp_wrapper_call_type(add_same_module_namespaces=true) %}
+{%- set proto_type = "::mojolpm" ~ (union|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+{%- set union_type = proto_type ~ "_ProtoUnion" %}
+bool FromProto(
+ const {{union_type}}& input,
+ {{mojom_type}}& output) {
+{%- if union|is_typemapped_kind %}
+{%- set dataview_type = (union|get_qualified_name_for_kind(flatten_nested_kind=True)) ~ "DataView" %}
+{%- set data_type = (union|get_qualified_name_for_kind(flatten_nested_kind=True, internal=True)) %}
+ ::mojo::internal::SerializationContext mojolpm_serialization_context;
+ auto mojolpm_buffer = mojolpm::GetContext()->message().payload_buffer();
+ {{data_type}}::BufferWriter mojolpm_writer;
+
+ ::mojo::internal::Serializer<{{dataview_type}}, const {{union_type}}>::Serialize(
+ input, mojolpm_buffer, &mojolpm_writer, false, &mojolpm_serialization_context);
+ return ::mojo::internal::Serializer<{{dataview_type}}, {{mojom_type}}>::Deserialize(
+ mojolpm_writer.data(), &output, &mojolpm_serialization_context);
+{%- else %}
+ switch (input.union_member_case()) {
+{%- for field in union.fields %}
+{%- set name = field.name|camel_to_under %}
+{%- set kind = field.kind %}
+{%- set field_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+ case {{union_type}}::k{{("m_" ~ name)|under_to_camel}}: {
+{%- if kind|is_nullable_kind %}
+{%- set field_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=true) %}
+ {{field_mojom_type}} local_{{name}};
+ {{field_maybe_mojom_type}} maybe_local_{{name}};
+ if (FromProto(input.m_{{name}}(), maybe_local_{{name}})) {
+ local_{{name}} = std::move(maybe_local_{{name}});
+ }
+ output = {{union|get_qualified_name_for_kind(flatten_nested_kind=true)}}::New{{name|under_to_camel}}(std::move(local_{{name}}));
+ return true;
+{%- else %}
+ {{field_mojom_type}} local_{{name}};
+ if (FromProto(input.m_{{name}}(), local_{{name}})) {
+ output = {{union|get_qualified_name_for_kind(flatten_nested_kind=true)}}::New{{name|under_to_camel}}(std::move(local_{{name}}));
+ return true;
+ }
+{%- endif %}
+ } break;
+{% endfor %}
+ default: {
+ return false;
+ }
+ }
+
+ return false;
+{%- endif %}
+}
+
+bool FromProto(
+ const {{proto_type}}& input,
+ {{mojom_type}}& output) {
+ if (input.instance_case() == {{proto_type}}::kOld) {
+ {{union_type}}* old = mojolpm::GetContext()->GetInstance<{{union_type}}>(input.old());
+ if (old) {
+ return FromProto(*old, output);
+ }
+ } else {
+ return FromProto(input.new_(), output);
+ }
+
+ return false;
+}
+{%- endmacro -%} \ No newline at end of file
diff --git a/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_macros.tmpl b/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_macros.tmpl
new file mode 100644
index 00000000000..c34ddb32dc3
--- /dev/null
+++ b/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_macros.tmpl
@@ -0,0 +1,82 @@
+{%- macro not_null(kind, name) %}
+{%- if kind|is_typemapped_kind and kind|is_struct_kind and kind|nullable_is_same_kind %}
+{%- set data_view = kind|get_qualified_name_for_kind ~ "DataView" %}
+{%- set data_type = kind|cpp_wrapper_type(ignore_nullable=True) %}
+{%- if data_type|truncate(16, true, '', 0) == '::scoped_refptr<' %}
+{{name}}
+{%- else %}
+!::mojo::internal::CallIsNullIfExists<::mojo::StructTraits<{{data_view}}, {{data_type}}>>({{name}})
+{%- endif %}
+{%- elif kind|is_platform_handle_kind -%}{{name}}.is_valid()
+{%- else -%}{{name}}
+{%- endif %}
+{%- endmacro -%}
+
+{%- macro value(kind, name) %}
+{%- if kind|is_nullable_kind and (not kind|nullable_is_same_kind) -%}*{{name}}
+{%- else -%}{{name}}
+{%- endif %}
+{%- endmacro -%}
+
+{%- macro add_instance(kind, name, nested) %}
+{%- if kind|is_array_kind %}
+ for (auto& {{name}}_iter : {{ value(kind, name) }}) {
+{{ add_instance(kind.kind, name ~ '_iter', True)|indent(2, True) }}
+ }
+{%- elif kind|is_map_kind %}
+ for (auto& {{name}}_iter : {{ value(kind, name) }}) {
+ auto& {{name}}_key = {{name}}_iter.first;
+ auto& {{name}}_value = {{name}}_iter.second;
+{{ add_instance(kind.key_kind, name ~ "_key", True)|indent(2, True) }}
+{{ add_instance(kind.value_kind, name ~ "_value", True)|indent(2, True) }}
+ }
+{%- elif kind|is_interface_kind %}
+{%- set mojom_type = kind|get_qualified_name_for_kind(flatten_nested_kind=True) %}
+ if ({{name}}) {
+ {{mojom_type}}Ptr tmp_{{name}}(std::move({{name}}));
+ mojolpm::GetContext()->AddInstance(std::move(tmp_{{name}}));
+ }
+{%- elif kind|is_associated_interface_kind %}
+{%- set mojom_type = kind.kind|get_qualified_name_for_kind(flatten_nested_kind=True) %}
+ if ({{name}}) {
+ {{mojom_type}}AssociatedPtr tmp_{{name}}(std::move({{name}}));
+ mojolpm::GetContext()->AddInstance(std::move(tmp_{{name}}));
+ }
+{%- elif kind|is_pending_remote_kind %}
+{%- set mojom_type = kind.kind|get_qualified_name_for_kind(flatten_nested_kind=True) %}
+ if ({{name}}) {
+ ::mojo::Remote<{{mojom_type}}> tmp_{{name}}(std::move({{name}}));
+ mojolpm::GetContext()->AddInstance(std::move(tmp_{{name}}));
+ }
+{%- elif kind|is_pending_associated_remote_kind %}
+{%- set mojom_type = kind.kind|get_qualified_name_for_kind(flatten_nested_kind=True) %}
+ if ({{name}}) {
+ ::mojo::AssociatedRemote<{{mojom_type}}> tmp_{{name}}(std::move({{name}}));
+ mojolpm::GetContext()->AddInstance(std::move(tmp_{{name}}));
+ }
+{%- else %}
+{%- if kind|is_nullable_kind %}
+{%- set proto_type = kind|cpp_wrapper_proto_type(add_same_module_namespaces=true) %}
+ {{proto_type}} tmp_{{name}};
+ if ({{ not_null(kind, name) }}) {
+{%- if kind|is_move_only_kind %}
+ if (ToProto(std::move({{ value(kind, name) }}), tmp_{{name}})) {
+{%- else %}
+ if (ToProto({{ value(kind, name) }}, tmp_{{name}})) {
+{%- endif %}
+ mojolpm::GetContext()->AddInstance(tmp_{{name}});
+ }
+ }
+{%- else %}
+{%- set proto_type = kind|cpp_wrapper_proto_type(add_same_module_namespaces=true) %}
+ {{proto_type}} tmp_{{name}};
+{%- if kind|is_move_only_kind %}
+ if (ToProto(std::move({{name}}), tmp_{{name}})) {
+{%- else %}
+ if (ToProto({{name}}, tmp_{{name}})) {
+{%- endif %}
+ mojolpm::GetContext()->AddInstance(tmp_{{name}});
+ }
+{%- endif %}
+{%- endif %}
+{%- endmacro %} \ No newline at end of file
diff --git a/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_to_proto_macros.tmpl b/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_to_proto_macros.tmpl
new file mode 100644
index 00000000000..e7fe4f52f13
--- /dev/null
+++ b/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_to_proto_macros.tmpl
@@ -0,0 +1,360 @@
+{% import "mojolpm_macros.tmpl" as util %}
+
+
+{%- macro declare_array(type, kind) %}
+{%- set mojom_type = kind.kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set maybe_mojom_type = kind.kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=true) %}
+bool ToProto(
+{%- if kind.kind|is_move_only_kind %}
+ std::vector<{{mojom_type}}>&& input,
+{%- else %}
+ const std::vector<{{mojom_type}}>& input,
+{%- endif %}
+ {{type}}& output);{{"\n"-}}
+{%- if kind.kind|is_array_kind %}
+{{declare_array(type ~ "Entry", kind.kind)}}
+{%- elif kind.kind|is_map_kind %}
+{{declare_map(type ~ "Entry", kind.kind)}}
+{%- else %}
+bool ToProto(
+ {{maybe_mojom_type}} input,
+ {{type}}Entry& output);{{"\n"-}}
+{%- endif %}
+{%- endmacro %}
+
+{%- macro declare_map(type, kind) %}
+{%- set mojom_key_type = kind.key_kind|cpp_wrapper_call_type(add_same_module_namespaces=true) %}
+{%- set mojom_value_type = kind.value_kind|cpp_wrapper_call_type(add_same_module_namespaces=true) %}
+bool ToProto(
+{%- if kind.key_kind|is_move_only_kind or kind.value_kind|is_move_only_kind %}
+ base::flat_map<{{mojom_key_type}},
+ {{mojom_value_type}}>&& input,
+{%- else %}
+ const base::flat_map<{{mojom_key_type}},
+ {{mojom_value_type}}>& input,
+{%- endif %}
+ {{type}}& output);{{"\n"-}}
+{%- if kind.key_kind|is_array_kind %}
+{{- declare_array(type ~ "Key", kind.key_kind)}}
+{%- elif kind.key_kind|is_map_kind %}
+{{- declare_map(type ~ "Key", kind.key_kind)}}
+{%- else %}
+bool ToProto(
+ {{mojom_key_type}} input,
+ {{type}}Key& output);{{"\n"-}}
+{%- endif %}
+{%- if kind.value_kind|is_array_kind %}
+{{- declare_array(type ~ "Value", kind.value_kind)}}
+{%- elif kind.value_kind|is_map_kind %}
+{{- declare_map(type ~ "Value", kind.value_kind)}}
+{%- elif kind.value_kind|is_nullable_kind %}
+bool ToProto(
+ {{mojom_value_type}} input,
+ {{type}}Value& output);{{"\n"-}}
+{%- else %}
+bool ToProto(
+ {{mojom_value_type}} input,
+ {{type}}Value& output);{{"\n"-}}
+{%- endif %}
+{%- endmacro %}
+
+
+{%- macro declare(parent_name, kind, name) %}
+{%- if kind|is_array_kind %}
+{%- set array_type = parent_name ~ "::" ~ name|under_to_camel ~ "_Array" %}
+{{- declare_array(array_type, kind)}}
+{%- elif kind|is_map_kind %}
+{%- set map_type = parent_name ~ "::" ~ name|under_to_camel ~ "_Map" %}
+{{- declare_map(map_type, kind)}}
+{%- endif %}
+{%- endmacro %}
+
+
+{%- macro define_array(type, kind) %}
+{%- set maybe_const = "const " if not kind.kind|is_move_only_kind else "" %}
+{%- set mojom_type = kind.kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set maybe_mojom_type = kind.kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=true) %}
+bool ToProto(
+{%- if kind.kind|is_move_only_kind %}
+ std::vector<{{mojom_type}}>&& input,
+{%- else %}
+ const std::vector<{{mojom_type}}>& input,
+{%- endif %}
+ {{type}}& output) {
+ bool result = true;
+
+ for ({{maybe_const}}auto& in_value : input) {
+{%- if kind.kind|is_nullable_kind %}
+ {{type}}Entry* out_value = output.mutable_values()->Add();
+ if ({{util.not_null(kind.kind, 'in_value')}}) {
+{%- if kind.kind|is_move_only_kind %}
+ ToProto(std::move({{util.value(kind.kind, 'in_value')}}), *out_value);
+{%- else %}
+ ToProto({{util.value(kind.kind, 'in_value')}}, *out_value);
+{%- endif %}
+ }
+{%- else %}
+ {{type}}Entry* out_value = output.mutable_values()->Add();
+{%- if kind.kind|is_move_only_kind %}
+ ToProto(std::move({{util.value(kind.kind, 'in_value')}}), *out_value);
+{%- else %}
+ ToProto({{util.value(kind.kind, 'in_value')}}, *out_value);
+{%- endif %}
+{%- endif %}
+ }
+
+ return result;
+}{{"\n"-}}
+{%- if kind.kind|is_array_kind %}
+{{- define_array(type ~ "Entry", kind.kind)}}
+{%- elif kind.kind|is_map_kind %}
+{{- define_map(type ~ "Entry", kind.kind)}}
+{%- elif kind.kind|is_nullable_kind %}
+bool ToProto(
+ {{maybe_const}}{{maybe_mojom_type}} input,
+ {{type}}Entry& output) {
+{%- if kind.kind|is_move_only_kind %}
+ return ToProto(std::move(input), *output.mutable_value());
+{%- else %}
+ return ToProto(input, *output.mutable_value());
+{%- endif %}
+}{{"\n"-}}
+{%- else %}
+bool ToProto(
+ {{maybe_const}}{{mojom_type}} input,
+ {{type}}Entry& output) {
+{%- if kind.kind|is_integral_kind or kind.kind|is_enum_kind or kind.kind|is_float_kind or kind.kind|is_double_kind %}
+ bool mojolpm_result;
+ {{kind.kind|cpp_wrapper_proto_type(add_same_module_namespaces=true)}} value;
+ mojolpm_result = ToProto(input, value);
+ output.set_value(value);
+ return mojolpm_result;
+{%- elif kind.kind|is_move_only_kind %}
+ return ToProto(std::move(input), *output.mutable_value());
+{%- else %}
+ return ToProto(input, *output.mutable_value());
+{%- endif %}
+}{{"\n"-}}
+{%- endif %}
+{%- endmacro %}
+
+
+{%- macro define_map(type, kind) %}
+{%- set maybe_const_key = "const " if not kind.key_kind|is_move_only_kind else "" %}
+{%- set mojom_key_type = kind.key_kind|cpp_wrapper_call_type(add_same_module_namespaces=true) %}
+{%- set maybe_const_value = "const " if not kind.key_kind|is_move_only_kind else "" %}
+{%- set mojom_value_type = kind.value_kind|cpp_wrapper_call_type(add_same_module_namespaces=true) %}
+bool ToProto(
+{%- if kind.key_kind|is_move_only_kind or kind.value_kind|is_move_only_kind %}
+ base::flat_map<{{mojom_key_type}},
+ {{mojom_value_type}}>&& input,
+{%- else %}
+ const base::flat_map<{{mojom_key_type}},
+ {{mojom_value_type}}>& input,
+{%- endif %}
+ {{type}}& output) {
+ bool result = true;
+
+ for (auto& in_entry : input) {
+ auto out_entry = output.mutable_values()->Add();
+{%- if kind.key_kind|is_move_only_kind %}
+ result = ToProto(std::move(in_entry.first), *out_entry->mutable_key());
+{%- else %}
+ result = ToProto(in_entry.first, *out_entry->mutable_key());
+{%- endif %}
+ if (!result) {
+ break;
+ }
+{%- if kind.value_kind|is_nullable_kind %}
+ if ({{util.not_null(kind.value_kind, 'in_entry.second')}}) {
+{%- if kind.value_kind|is_move_only_kind %}
+ result = ToProto(std::move(*in_entry.second), *out_entry->mutable_value());
+{%- else %}
+ result = ToProto(*in_entry.second, *out_entry->mutable_value());
+{%- endif %}
+ }
+{%- elif kind.value_kind|is_move_only_kind %}
+ result = ToProto(std::move(in_entry.second), *out_entry->mutable_value());
+{%- else %}
+ result = ToProto(in_entry.second, *out_entry->mutable_value());
+{%- endif %}
+ if (!result) {
+ break;
+ }
+ }
+
+ return result;
+}{{"\n"-}}
+{%- if kind.key_kind|is_array_kind %}
+{{define_array(type ~ "Key", kind.key_kind)}}
+{%- elif kind.key_kind|is_map_kind %}
+{{define_map(type ~ "Key", kind.key_kind)}}
+{%- else %}
+bool ToProto(
+ {{mojom_key_type}} input,
+ {{type}}Key& output) {
+{%- if kind.key_kind|is_integral_kind or kind.key_kind|is_enum_kind or kind.key_kind|is_float_kind or kind.key_kind|is_double_kind %}
+ bool mojolpm_result;
+ {{kind.key_kind|cpp_wrapper_proto_type(add_same_module_namespaces=true)}} value;
+ mojolpm_result = ToProto(input, value);
+ output.set_value(value);
+ return mojolpm_result;
+{%- elif kind.key_kind|is_move_only_kind %}
+ return ToProto(std::move(input), *output.mutable_value());
+{%- else %}
+ return ToProto(input, *output.mutable_value());
+{%- endif %}
+}{{"\n"-}}
+{%- endif %}
+{%- if kind.value_kind|is_array_kind %}
+{{- define_array(type ~ "Value", kind.value_kind)}}
+{%- elif kind.value_kind|is_map_kind %}
+{{- define_map(type ~ "Value", kind.value_kind)}}
+{%- else %}
+bool ToProto(
+ {{mojom_value_type}} input,
+ {{type}}Value& output) {
+{%- if kind.value_kind|is_integral_kind or kind.value_kind|is_enum_kind or kind.value_kind|is_float_kind or kind.value_kind|is_double_kind %}
+ bool mojolpm_result;
+ {{kind.value_kind|cpp_wrapper_proto_type(add_same_module_namespaces=true)}} value;
+ mojolpm_result = ToProto(input, value);
+ output.set_value(value);
+ return mojolpm_result;
+{%- elif kind.value_kind|is_move_only_kind %}
+ return ToProto(std::move(input), *output.mutable_value());
+{%- else %}
+ return ToProto(input, *output.mutable_value());
+{%- endif %}
+}{{"\n"-}}
+{%- endif %}
+{%- endmacro %}
+
+
+{%- macro define(parent_name, kind, name) %}
+{%- if kind|is_array_kind %}
+{%- set array_type = parent_name ~ "::" ~ name|under_to_camel ~ "_Array" %}
+{{- define_array(array_type, kind)}}
+{%- elif kind|is_map_kind %}
+{%- set map_type = parent_name ~ "::" ~ name|under_to_camel ~ "_Map" %}
+{{- define_map(map_type, kind)}}
+{%- endif %}
+{%- endmacro %}
+
+
+{%- macro define_enum(enum) -%}
+{%- set mojom_type = enum|cpp_wrapper_call_type(add_same_module_namespaces=true) %}
+{%- set proto_type = "::mojolpm" ~ (enum|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+{%- set enum_type = enum|get_qualified_name_for_kind(flatten_nested_kind=True) %}
+bool ToProto(
+ const {{mojom_type}}& input,
+ {{proto_type}}& output) {
+{%- if enum|is_native_only_kind or not enum|is_typemapped_kind %}
+ // This ignores IPC_PARAM_TRAITS for native IPC enums, but internal to the
+ // fuzzer we don't want the overhead of the serialization layer if we don't
+ // need it. This doesn't change the actual checks on the receiving end.
+ output = static_cast<{{proto_type}}>(input);
+ return true;
+{%- else %}
+ output = static_cast<{{proto_type}}>(
+ mojo::EnumTraits<{{enum_type}}, {{mojom_type}}>::ToMojom(input));
+ return true;
+{%- endif %}
+}{{"\n"-}}
+{%- endmacro %}
+
+
+{%- macro define_struct(struct) -%}
+{%- set mojom_type = struct|cpp_wrapper_param_type(add_same_module_namespaces=true) %}
+{%- set proto_type = "::mojolpm" ~ (struct|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+{%- set struct_type = proto_type ~ "_ProtoStruct" %}
+bool ToProto(
+ {{mojom_type}} input,
+ {{proto_type}}& output) {
+{%- if struct|is_native_only_kind %}
+ {{struct_type}}* new_instance = output.mutable_new_();
+ new_instance->mutable_native_bytes()->resize(sizeof({{mojom_type}}), 0);
+ memcpy(&new_instance->mutable_native_bytes()[0], (void*)&input, sizeof({{mojom_type}}));
+ return true;
+{%- elif struct|is_typemapped_kind %}
+ // TODO(markbrand): ToProto for typemapped struct kind
+ return false;
+{%- elif struct.fields %}
+ {{struct_type}}* new_instance = output.mutable_new_();
+ bool mojolpm_result = true;
+{%- for field in struct.fields -%}
+{%- set raw_name = field.name %}
+{%- set name = field.name|camel_to_under %}
+{%- set kind = field.kind %}
+{%- if kind|is_integral_kind or kind|is_enum_kind or kind|is_float_kind or kind|is_double_kind %}
+ {{kind|cpp_wrapper_proto_type(add_same_module_namespaces=true)}} tmp_{{name}};
+ mojolpm_result &= ToProto(input->{{raw_name}}, tmp_{{name}});
+ new_instance->set_m_{{name}}(tmp_{{name}});
+{%- elif kind|is_nullable_kind %}
+ if ({{util.not_null(kind, 'input->' ~ raw_name)}}) {
+{%- if kind|is_move_only_kind %}
+ mojolpm_result &= ToProto(std::move({{util.value(kind, 'input->' ~ raw_name)}}), *new_instance->mutable_m_{{name}}());
+{%- else %}
+ mojolpm_result &= ToProto({{util.value(kind, 'input->' ~ raw_name)}}, *new_instance->mutable_m_{{name}}());
+{%- endif %}
+ }
+{%- elif kind|is_move_only_kind %}
+ mojolpm_result &= ToProto(std::move(input->{{raw_name}}), *new_instance->mutable_m_{{name}}());
+{%- else %}
+ mojolpm_result &= ToProto(input->{{raw_name}}, *new_instance->mutable_m_{{name}}());
+{%- endif %}
+{%- endfor %}
+ return mojolpm_result;
+{%- else %}
+ output.new_();
+ return true;
+{%- endif %}
+}{{"\n"-}}
+{%- endmacro %}
+
+
+{%- macro define_union(union) %}
+{%- set mojom_type = union|cpp_wrapper_param_type(add_same_module_namespaces=true) %}
+{%- set proto_type = "::mojolpm" ~ (union|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+{%- set union_type = proto_type ~ "_ProtoUnion" %}
+bool ToProto(
+ {{mojom_type}} input,
+ {{proto_type}}& output) {
+{%- if union|is_typemapped_kind %}
+ // TODO(markbrand): ToProto for typemapped union kind.
+ return false;
+{%- else %}
+{%- set enum_name = (union|get_qualified_name_for_kind(flatten_nested_kind=True, internal=True)) ~ "::" ~ union.name ~ "_Tag" %}
+ {{union_type}}* new_instance = output.mutable_new_();
+ bool mojolpm_result = true;
+ switch (input->which()) {
+{%- for field in union.fields %}
+{%- set raw_name = field.name %}
+{%- set name = field.name|camel_to_under %}
+{%- set kind = field.kind %}
+ case {{enum_name}}::{{field.name|upper}}: {
+{%- if kind|is_move_only_kind and kind|is_nullable_kind %}
+ if ({{util.not_null(kind, 'input->get_' ~ raw_name ~ '()')}}) {
+ mojolpm_result &= ToProto(std::move({{util.value(kind, 'input->get_' ~ raw_name ~ '()')}}), *new_instance->mutable_m_{{name}}());
+ }
+{%- elif kind|is_move_only_kind %}
+ mojolpm_result = ToProto(std::move(input->get_{{raw_name}}()),
+ *(new_instance->mutable_m_{{name}}()));
+{%- elif kind|is_nullable_kind %}
+ if ({{util.not_null(kind, 'input->get_' ~ raw_name ~ '()')}}) {
+ mojolpm_result &= ToProto({{util.value(kind, 'input->get_' ~ raw_name ~ '()')}}, *new_instance->mutable_m_{{name}}());
+ }
+{%- elif kind|is_integral_kind or kind|is_enum_kind or kind|is_float_kind or kind|is_double_kind %}
+ {{kind|cpp_wrapper_proto_type(add_same_module_namespaces=true)}} tmp_{{name}};
+ mojolpm_result &= ToProto(input->get_{{raw_name}}(), tmp_{{name}});
+ new_instance->set_m_{{name}}(tmp_{{name}});
+{%- else %}
+ mojolpm_result = ToProto(input->get_{{name}}(),
+ *(new_instance->mutable_m_{{name}}()));
+{%- endif %}
+ } break;
+{%- endfor %}
+ }
+ return mojolpm_result;
+{%- endif %}
+}{{"\n"-}}
+{%- endmacro %}
diff --git a/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_traits_specialization_macros.tmpl b/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_traits_specialization_macros.tmpl
new file mode 100644
index 00000000000..7eeddd7ada4
--- /dev/null
+++ b/chromium/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_traits_specialization_macros.tmpl
@@ -0,0 +1,96 @@
+{% import "mojolpm_macros.tmpl" as util %}
+
+{%- macro define_struct(struct) %}
+{%- set mojom_type = struct|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set proto_type = "::mojolpm" ~ (struct|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+{%- set struct_type = proto_type ~ "_ProtoStruct" %}
+{%- set dataview_type = (struct|get_qualified_name_for_kind(flatten_nested_kind=True)) ~ "DataView" %}
+template <>
+struct StructTraits<{{dataview_type}}, {{struct_type}}> {
+{%- for field in struct.fields %}
+{%- set name = field.name|camel_to_under %}
+{%- set kind = field.kind %}
+{%- if field.kind|is_nullable_kind and not field.kind|nullable_is_same_kind %}
+{%- set field_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set field_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=true) %}
+ static {{field_mojom_type}} {{field.name}}(
+ const {{struct_type}}& input) {
+ {{field_mojom_type}} maybe_local_{{name}};
+ {{field_maybe_mojom_type}} local_{{name}};
+ if (input.has_m_{{name}}() && mojolpm::FromProto(
+ input.m_{{name}}(),
+ local_{{name}})) {
+ maybe_local_{{name}} = std::move(local_{{name}});
+ }
+ return maybe_local_{{name}};
+ }{{ "\n" }}
+{%- else %}
+{%- set field_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+ static {{field_mojom_type}} {{field.name}}(
+ const {{struct_type}}& input) {
+ {{field_mojom_type}} local_{{name}};
+ (void) mojolpm::FromProto(
+ input.m_{{name}}(),
+ local_{{name}});
+ return local_{{name}};
+ }{{ "\n" }}
+{%- endif %}
+{%- endfor -%}
+};
+{% endmacro -%}
+
+{%- macro define_union(union) -%}
+{%- set mojom_type = union|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set proto_type = "::mojolpm" ~ (union|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
+{%- set union_type = proto_type ~ "_ProtoUnion" %}
+{%- if union|is_typemapped_kind %}
+{%- set dataview_type = (union|get_qualified_name_for_kind(flatten_nested_kind=True)) ~ "DataView" %}
+template<>
+struct UnionTraits<{{dataview_type}}, {{union_type}}> {
+ static {{dataview_type}}::Tag GetTag(
+ const {{union_type}}& input) {
+ switch (input.union_member_case()) {
+{%- for field in union.fields %}
+{%- set name = field.name|camel_to_under %}
+{%- set kind = field.kind %}
+{%- set field_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+ case {{union_type}}::k{{("m_" ~ name)|under_to_camel}}:
+ return {{dataview_type}}::Tag::{{name|upper}};
+{%- endfor %}
+ default:
+ NOTREACHED();
+ return static_cast<{{dataview_type}}::Tag>(0);
+ }
+ }{{"\n"}}
+{%- for field in union.fields %}
+{%- set name = field.name|camel_to_under %}
+{%- set kind = field.kind %}
+{%- if field.kind|is_nullable_kind and not field.kind|nullable_is_same_kind %}
+{%- set field_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+{%- set field_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=true) %}
+ static {{field_mojom_type}} {{field.name}}(
+ const {{union_type}}& input) {
+ {{field_mojom_type}} maybe_local_{{name}};
+ {{field_maybe_mojom_type}} local_{{name}};
+ if (mojolpm::FromProto(
+ input.m_{{name}}(),
+ local_{{name}})) {
+ maybe_local_{{name}} = std::move(local_{{name}});
+ }
+ return maybe_local_{{name}};
+ }{{ "\n" }}
+{%- else %}
+{%- set field_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
+ static {{field_mojom_type}} {{field.name}}(
+ const {{union_type}}& input) {
+ {{field_mojom_type}} local_{{name}};
+ (void) mojolpm::FromProto(
+ input.m_{{name}}(),
+ local_{{name}});
+ return local_{{name}};
+ }{{ "\n" }}
+{%- endif %}
+{%- endfor -%}
+};
+{% endif %}
+{% endmacro -%} \ No newline at end of file
diff --git a/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
index 90e559eba13..a0ce5540841 100644
--- a/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
+++ b/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -33,6 +33,8 @@ _kind_to_cpp_literal_suffix = {
}
+
+
class _NameFormatter(object):
"""A formatter for the names of kinds or values."""
@@ -558,12 +560,20 @@ class Generator(generator.Generator):
for cpp_template_path in self.extra_cpp_template_paths:
path_to_template, filename = os.path.split(cpp_template_path)
filename_without_tmpl_suffix = filename.rstrip(".tmpl")
- self.WriteWithComment(self._GenerateModuleFromImportedTemplate(path_to_template, filename),
- "%s%s-%s" % (self.module.path, suffix, filename_without_tmpl_suffix))
+ self.WriteWithComment(
+ self._GenerateModuleFromImportedTemplate(path_to_template,
+ filename), "%s%s-%s" %
+ (self.module.path, suffix, filename_without_tmpl_suffix))
def _ConstantValue(self, constant):
return self._ExpressionToText(constant.value, kind=constant.kind)
+ def _UnderToCamel(self, value, digits_split=False):
+ # There are some mojom files that don't use snake_cased names, so we try to
+ # fix that to get more consistent output.
+ return generator.ToCamel(generator.ToLowerSnakeCase(value),
+ digits_split=digits_split)
+
def _DefaultValue(self, field):
if not field.default:
return ""
@@ -658,8 +668,13 @@ class Generator(generator.Generator):
GetCppPodType(constant.kind), constant.name,
self._ConstantValue(constant))
- def _GetCppWrapperType(self, kind, add_same_module_namespaces=False):
+ def _GetCppWrapperType(self,
+ kind,
+ add_same_module_namespaces=False,
+ ignore_nullable=False):
def _AddOptional(type_name):
+ if ignore_nullable:
+ return type_name
return "base::Optional<%s>" % type_name
if self._IsTypemappedKind(kind):
@@ -700,16 +715,16 @@ class Generator(generator.Generator):
return "%sRequest" % self._GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsPendingRemoteKind(kind):
- return "mojo::PendingRemote<%s>" % self._GetNameForKind(
+ return "::mojo::PendingRemote<%s>" % self._GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsPendingReceiverKind(kind):
- return "mojo::PendingReceiver<%s>" % self._GetNameForKind(
+ return "::mojo::PendingReceiver<%s>" % self._GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsPendingAssociatedRemoteKind(kind):
- return "mojo::PendingAssociatedRemote<%s>" % self._GetNameForKind(
+ return "::mojo::PendingAssociatedRemote<%s>" % self._GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsPendingAssociatedReceiverKind(kind):
- return "mojo::PendingAssociatedReceiver<%s>" % self._GetNameForKind(
+ return "::mojo::PendingAssociatedReceiver<%s>" % self._GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsAssociatedInterfaceKind(kind):
return "%sAssociatedPtrInfo" % self._GetNameForKind(
@@ -724,17 +739,17 @@ class Generator(generator.Generator):
return (_AddOptional(type_name) if mojom.IsNullableKind(kind)
else type_name)
if mojom.IsGenericHandleKind(kind):
- return "mojo::ScopedHandle"
+ return "::mojo::ScopedHandle"
if mojom.IsDataPipeConsumerKind(kind):
- return "mojo::ScopedDataPipeConsumerHandle"
+ return "::mojo::ScopedDataPipeConsumerHandle"
if mojom.IsDataPipeProducerKind(kind):
- return "mojo::ScopedDataPipeProducerHandle"
+ return "::mojo::ScopedDataPipeProducerHandle"
if mojom.IsMessagePipeKind(kind):
- return "mojo::ScopedMessagePipeHandle"
+ return "::mojo::ScopedMessagePipeHandle"
if mojom.IsSharedBufferKind(kind):
- return "mojo::ScopedSharedBufferHandle"
+ return "::mojo::ScopedSharedBufferHandle"
if mojom.IsPlatformHandleKind(kind):
- return "mojo::PlatformHandle"
+ return "::mojo::PlatformHandle"
if not kind in _kind_to_cpp_type:
raise Exception("Unrecognized kind %s" % kind.spec)
return _kind_to_cpp_type[kind]
@@ -769,19 +784,23 @@ class Generator(generator.Generator):
return ((not mojom.IsReferenceKind(kind)) or self._IsMoveOnlyKind(kind) or
self._IsCopyablePassByValue(kind))
- def _GetCppWrapperCallType(self, kind):
+ def _GetCppWrapperCallType(self, kind, add_same_module_namespaces=False):
# TODO: Remove this once interfaces are always passed as PtrInfo.
if mojom.IsInterfaceKind(kind):
- return "%sPtr" % self._GetNameForKind(kind)
- return self._GetCppWrapperType(kind)
+ return "%sPtr" % self._GetNameForKind(
+ kind, add_same_module_namespaces=add_same_module_namespaces)
+ return self._GetCppWrapperType(
+ kind, add_same_module_namespaces=add_same_module_namespaces)
- def _GetCppWrapperParamType(self, kind):
+ def _GetCppWrapperParamType(self, kind, add_same_module_namespaces=False):
# TODO: Remove all usage of this method in favor of
# _GetCppWrapperParamTypeNew. This requires all generated code which passes
# interface handles to use PtrInfo instead of Ptr.
if mojom.IsInterfaceKind(kind):
- return "%sPtr" % self._GetNameForKind(kind)
- cpp_wrapper_type = self._GetCppWrapperType(kind)
+ return "%sPtr" % self._GetNameForKind(
+ kind, add_same_module_namespaces=add_same_module_namespaces)
+ cpp_wrapper_type = self._GetCppWrapperType(
+ kind, add_same_module_namespaces=add_same_module_namespaces)
return (cpp_wrapper_type if self._ShouldPassParamByValue(kind)
else "const %s&" % cpp_wrapper_type)
@@ -937,8 +956,7 @@ class Generator(generator.Generator):
if param_counts[-1] != version.num_fields:
param_counts.append(version.num_fields)
- ordinal_fields = sorted(
- struct.fields, key=lambda field: field.ordinal or "")
+ ordinal_fields = sorted(struct.fields, key=lambda field: field.ordinal)
return (StructConstructor(struct.fields, ordinal_fields[:param_count])
for param_count in param_counts)
diff --git a/chromium/mojo/public/tools/bindings/generators/mojom_mojolpm_generator.py b/chromium/mojo/public/tools/bindings/generators/mojom_mojolpm_generator.py
new file mode 100644
index 00000000000..6b7271114a4
--- /dev/null
+++ b/chromium/mojo/public/tools/bindings/generators/mojom_mojolpm_generator.py
@@ -0,0 +1,517 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Generates C++ source files from a mojom.Module."""
+import os
+import sys
+from mojom_cpp_generator import _NameFormatter as CppNameFormatter
+from mojom_cpp_generator import Generator as CppGenerator
+from mojom_cpp_generator import IsNativeOnlyKind, NamespaceToArray
+import mojom.generate.generator as generator
+import mojom.generate.module as mojom
+import mojom.generate.pack as pack
+from mojom.generate.template_expander import UseJinja, UseJinjaForImportedTemplate
+
+_kind_to_proto_type = {
+ mojom.BOOL: "bool",
+ mojom.INT8: "int32",
+ mojom.UINT8: "uint32",
+ mojom.INT16: "int32",
+ mojom.UINT16: "uint32",
+ mojom.INT32: "int32",
+ mojom.UINT32: "uint32",
+ mojom.FLOAT: "float",
+ mojom.INT64: "int64",
+ mojom.UINT64: "uint64",
+ mojom.DOUBLE: "double",
+}
+
+_kind_to_cpp_proto_type = {
+ mojom.BOOL: "bool",
+ mojom.INT8: "::google::protobuf::int32",
+ mojom.UINT8: "::google::protobuf::uint32",
+ mojom.INT16: "::google::protobuf::int32",
+ mojom.UINT16: "::google::protobuf::uint32",
+ mojom.INT32: "::google::protobuf::int32",
+ mojom.UINT32: "::google::protobuf::uint32",
+ mojom.FLOAT: "float",
+ mojom.INT64: "::google::protobuf::int64",
+ mojom.UINT64: "::google::protobuf::int64",
+ mojom.DOUBLE: "double",
+}
+
+
+def _IsStrOrUnicode(x):
+ if sys.version_info[0] < 3:
+ return isinstance(x, (unicode, str))
+ return isinstance(x, str)
+
+
+class _NameFormatter(CppNameFormatter):
+ """A formatter for the names of kinds or values."""
+
+ def __init__(self, *args, **kwargs):
+ super(_NameFormatter, self).__init__(*args, **kwargs)
+
+ def FormatForProto(self,
+ omit_namespace_for_module=None,
+ flatten_nested_kind=False):
+ return self.Format(".",
+ prefixed=True,
+ omit_namespace_for_module=omit_namespace_for_module,
+ flatten_nested_kind=flatten_nested_kind)
+
+
+class Generator(CppGenerator):
+ def __init__(self, *args, **kwargs):
+ super(Generator, self).__init__(*args, **kwargs)
+ self.needs_mojolpm_proto = False
+ self.enum_name_cache = dict()
+
+ def _GetAllExtraTraitsHeaders(self):
+ extra_headers = set()
+ for typemap in self._GetAllTypemaps():
+ extra_headers.update(typemap.get("traits_headers", []))
+ extra_headers.update(self._GetExtraTraitsHeaders())
+ return sorted(extra_headers)
+
+ def _GetAllTypemaps(self):
+ """Returns the typemaps for types needed in this module.
+ """
+ all_typemaps = []
+ seen_types = set()
+
+ def AddKind(kind):
+ if (mojom.IsIntegralKind(kind) or mojom.IsStringKind(kind)
+ or mojom.IsDoubleKind(kind) or mojom.IsFloatKind(kind)
+ or mojom.IsAnyHandleKind(kind) or mojom.IsInterfaceKind(kind)
+ or mojom.IsInterfaceRequestKind(kind) or mojom.IsAssociatedKind(kind)
+ or mojom.IsPendingRemoteKind(kind)
+ or mojom.IsPendingReceiverKind(kind)):
+ pass
+ elif mojom.IsArrayKind(kind):
+ AddKind(kind.kind)
+ elif mojom.IsMapKind(kind):
+ AddKind(kind.key_kind)
+ AddKind(kind.value_kind)
+ else:
+ name = self._GetFullMojomNameForKind(kind)
+ if name in seen_types:
+ return
+ seen_types.add(name)
+
+ typemap = self.typemap.get(name, None)
+ if typemap:
+ all_typemaps.append(typemap)
+ if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
+ for field in kind.fields:
+ AddKind(field.kind)
+
+ for kind in self.module.enums + self.module.structs + self.module.unions:
+ AddKind(kind)
+
+ return all_typemaps
+
+ def _ProtoImports(self):
+ """Scans all of the types used in this module to check which of the imports
+ are needed for the generated proto files. This is somewhat different to the
+ general case, since the generated proto files don't reference response
+ parameters.
+ """
+ all_imports = self.module.imports
+ seen_imports = set()
+ seen_types = set()
+
+ def AddKind(kind):
+ if (mojom.IsIntegralKind(kind) or mojom.IsStringKind(kind)
+ or mojom.IsDoubleKind(kind) or mojom.IsFloatKind(kind)):
+ pass
+ elif (mojom.IsAnyHandleKind(kind)):
+ self.needs_mojolpm_proto = True
+ elif mojom.IsArrayKind(kind):
+ AddKind(kind.kind)
+ elif mojom.IsMapKind(kind):
+ AddKind(kind.key_kind)
+ AddKind(kind.value_kind)
+ elif (mojom.IsStructKind(kind) or mojom.IsUnionKind(kind)
+ or mojom.IsEnumKind(kind) or mojom.IsInterfaceKind(kind)):
+ name = self._GetFullMojomNameForKind(kind)
+ if name in seen_types:
+ return
+ seen_types.add(name)
+ if kind.module in all_imports:
+ seen_imports.add(kind.module)
+ elif (mojom.IsInterfaceRequestKind(kind)
+ or mojom.IsAssociatedInterfaceKind(kind)
+ or mojom.IsAssociatedInterfaceRequestKind(kind)
+ or mojom.IsPendingRemoteKind(kind)
+ or mojom.IsPendingReceiverKind(kind)
+ or mojom.IsPendingAssociatedRemoteKind(kind)
+ or mojom.IsPendingAssociatedReceiverKind(kind)):
+ AddKind(kind.kind)
+
+ for kind in self.module.structs + self.module.unions:
+ for field in kind.fields:
+ AddKind(field.kind)
+
+ for interface in self.module.interfaces:
+ for method in interface.methods:
+ for parameter in method.parameters:
+ AddKind(parameter.kind)
+ if method.response_parameters:
+ for parameter in method.response_parameters:
+ AddKind(parameter.kind)
+
+ import_files = list(
+ map(lambda x: '{}.mojolpm.proto'.format(x.path), seen_imports))
+ if self.needs_mojolpm_proto:
+ import_files.append('mojolpm.proto')
+ import_files.sort()
+
+ return import_files
+
+ def _GetJinjaExports(self):
+ all_enums = list(self.module.enums)
+ for struct in self.module.structs:
+ all_enums.extend(struct.enums)
+ for interface in self.module.interfaces:
+ all_enums.extend(interface.enums)
+
+ return {
+ "all_enums": all_enums,
+ "all_extra_traits_headers": self._GetAllExtraTraitsHeaders(),
+ "enums": self.module.enums,
+ "extra_public_headers": self._GetExtraPublicHeaders(),
+ "extra_traits_headers": self._GetExtraTraitsHeaders(),
+ "imports": self.module.imports,
+ "interfaces": self.module.interfaces,
+ "module": self.module,
+ "module_namespace": self.module.namespace,
+ "namespaces_as_array": NamespaceToArray(self.module.namespace),
+ "proto_imports": self._ProtoImports(),
+ "structs": self.module.structs,
+ "unions": self.module.unions,
+ }
+
+ @staticmethod
+ def GetTemplatePrefix():
+ return "mojolpm_templates"
+
+ def GetFilters(self):
+ cpp_filters = {
+ "camel_to_under": generator.ToLowerSnakeCase,
+ "contains_handles_or_interfaces": mojom.ContainsHandlesOrInterfaces,
+ "cpp_wrapper_call_type": self._GetCppWrapperCallType,
+ "cpp_wrapper_param_type": self._GetCppWrapperParamType,
+ "cpp_wrapper_proto_type": self._GetCppWrapperProtoType,
+ "cpp_wrapper_type": self._GetCppWrapperType,
+ "enum_field_name": self._EnumFieldName,
+ "get_name_for_kind": self._GetNameForKind,
+ "get_qualified_name_for_kind": self._GetQualifiedNameForKind,
+ "has_duplicate_values": self._EnumHasDuplicateValues,
+ "nullable_is_same_kind": self._NullableIsSameKind,
+ "proto_field_type": self._GetProtoFieldType,
+ "proto_id": self._GetProtoId,
+ "is_array_kind": mojom.IsArrayKind,
+ "is_enum_kind": mojom.IsEnumKind,
+ "is_double_kind": mojom.IsDoubleKind,
+ "is_float_kind": mojom.IsFloatKind,
+ "is_integral_kind": mojom.IsIntegralKind,
+ "is_interface_kind": mojom.IsInterfaceKind,
+ "is_receiver_kind": self._IsReceiverKind,
+ "is_pending_associated_receiver_kind":
+ mojom.IsPendingAssociatedReceiverKind,
+ "is_pending_receiver_kind": mojom.IsPendingReceiverKind,
+ "is_pending_associated_remote_kind":
+ mojom.IsPendingAssociatedRemoteKind,
+ "is_pending_remote_kind": mojom.IsPendingRemoteKind,
+ "is_platform_handle_kind": mojom.IsPlatformHandleKind,
+ "is_associated_interface_kind": mojom.IsAssociatedInterfaceKind,
+ "is_native_only_kind": IsNativeOnlyKind,
+ "is_any_handle_kind": mojom.IsAnyHandleKind,
+ "is_any_interface_kind": mojom.IsAnyInterfaceKind,
+ "is_any_handle_or_interface_kind": mojom.IsAnyHandleOrInterfaceKind,
+ "is_associated_kind": mojom.IsAssociatedKind,
+ "is_float_kind": mojom.IsFloatKind,
+ "is_hashable": self._IsHashableKind,
+ "is_map_kind": mojom.IsMapKind,
+ "is_move_only_kind": self._IsMoveOnlyKind,
+ "is_nullable_kind": mojom.IsNullableKind,
+ "is_object_kind": mojom.IsObjectKind,
+ "is_reference_kind": mojom.IsReferenceKind,
+ "is_string_kind": mojom.IsStringKind,
+ "is_struct_kind": mojom.IsStructKind,
+ "is_typemapped_kind": self._IsTypemappedKind,
+ "is_union_kind": mojom.IsUnionKind,
+ "under_to_camel": self._UnderToCamel,
+ }
+ return cpp_filters
+
+ @UseJinja("mojolpm.proto.tmpl")
+ def _GenerateMojolpmProto(self):
+ return self._GetJinjaExports()
+
+ @UseJinja("mojolpm.h.tmpl")
+ def _GenerateMojolpmHeader(self):
+ return self._GetJinjaExports()
+
+ @UseJinja("mojolpm.cc.tmpl")
+ def _GenerateMojolpmSource(self):
+ return self._GetJinjaExports()
+
+ def GenerateFiles(self, args):
+ self.module.Stylize(generator.Stylizer())
+
+ if self.generate_non_variant_code:
+ self.WriteWithComment(self._GenerateMojolpmProto(),
+ "%s.mojolpm.proto" % self.module.path)
+ else:
+ self.WriteWithComment(self._GenerateMojolpmHeader(),
+ "%s-mojolpm.h" % self.module.path)
+ self.WriteWithComment(self._GenerateMojolpmSource(),
+ "%s-mojolpm.cc" % self.module.path)
+
+ def _GetCppProtoNameForKind(self,
+ kind,
+ flatten_nested_kind=False,
+ add_same_module_namespaces=False):
+ name = _NameFormatter(kind, self.variant).FormatForCpp(
+ flatten_nested_kind=flatten_nested_kind,
+ omit_namespace_for_module=(None if add_same_module_namespaces else
+ self.module))
+ if name.startswith('::'):
+ name = 'mojolpm' + name
+ return name
+
+ def _GetProtoNameForKind(self,
+ kind,
+ flatten_nested_kind=False,
+ add_same_module_namespaces=False):
+ name = _NameFormatter(kind, self.variant).FormatForProto(
+ flatten_nested_kind=flatten_nested_kind,
+ omit_namespace_for_module=(None if add_same_module_namespaces else
+ self.module))
+ if name.startswith('.'):
+ name = 'mojolpm' + name
+ return name
+
+ def _IsMoveOnlyKind(self, kind):
+ if self._IsTypemappedKind(kind):
+ if mojom.IsEnumKind(kind):
+ return False
+ return self.typemap[self._GetFullMojomNameForKind(kind)]["move_only"]
+ if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
+ return True
+ if mojom.IsArrayKind(kind):
+ return self._IsMoveOnlyKind(kind.kind)
+ if mojom.IsMapKind(kind):
+ return (self._IsMoveOnlyKind(kind.value_kind)
+ or self._IsMoveOnlyKind(kind.key_kind))
+ if mojom.IsAnyHandleOrInterfaceKind(kind):
+ return True
+ return False
+
+ def _GetNativeTypeName(self, typemapped_kind):
+ return self.typemap[self._GetFullMojomNameForKind(
+ typemapped_kind)]["typename"]
+
+ def _FormatConstantDeclaration(self, constant, nested=False):
+ if mojom.IsStringKind(constant.kind):
+ if nested:
+ return "const char %s[]" % constant.name
+ return "%sextern const char %s[]" % \
+ ((self.export_attribute + " ") if self.export_attribute else "",
+ constant.name)
+ return "constexpr %s %s = %s" % (GetCppPodType(
+ constant.kind), constant.name, self._ConstantValue(constant))
+
+ def _IsMoveOnlyKind(self, kind):
+ if self._IsTypemappedKind(kind):
+ if mojom.IsEnumKind(kind):
+ return False
+ return self.typemap[self._GetFullMojomNameForKind(kind)]["move_only"]
+ if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
+ return True
+ if mojom.IsArrayKind(kind):
+ return self._IsMoveOnlyKind(kind.kind)
+ if mojom.IsMapKind(kind):
+ return (self._IsMoveOnlyKind(kind.value_kind)
+ or self._IsMoveOnlyKind(kind.key_kind))
+ if mojom.IsAnyHandleOrInterfaceKind(kind):
+ return True
+ return False
+
+ def _GetCppWrapperProtoType(self, kind, add_same_module_namespaces=False):
+ if (mojom.IsEnumKind(kind) or mojom.IsStructKind(kind)
+ or mojom.IsUnionKind(kind)):
+ return self._GetCppProtoNameForKind(
+ kind, add_same_module_namespaces=add_same_module_namespaces)
+ elif mojom.IsInterfaceKind(kind):
+ return '%s::Ptr' % self._GetCppProtoNameForKind(
+ kind, add_same_module_namespaces=add_same_module_namespaces)
+ elif mojom.IsInterfaceRequestKind(kind):
+ return '%s::Request' % self._GetCppProtoNameForKind(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
+ elif mojom.IsAssociatedInterfaceKind(kind):
+ return '%s::AssociatedPtr' % self._GetCppProtoNameForKind(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
+ elif mojom.IsAssociatedInterfaceRequestKind(kind):
+ return '%s::AssociatedRequest' % self._GetCppProtoNameForKind(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
+ elif mojom.IsPendingRemoteKind(kind):
+ return "%s::PendingRemote" % self._GetCppProtoNameForKind(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
+ elif mojom.IsPendingReceiverKind(kind):
+ return "%s::PendingReceiver" % self._GetCppProtoNameForKind(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
+ elif mojom.IsPendingAssociatedRemoteKind(kind):
+ return "%s::PendingAssociatedRemote" % self._GetCppProtoNameForKind(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
+ elif mojom.IsPendingAssociatedReceiverKind(kind):
+ return "%s::PendingAssociatedReceiver" % self._GetCppProtoNameForKind(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
+ elif mojom.IsStringKind(kind):
+ return "std::string"
+ elif mojom.IsGenericHandleKind(kind):
+ return "mojolpm::Handle"
+ elif mojom.IsDataPipeConsumerKind(kind):
+ return "mojolpm::DataPipeConsumerHandle"
+ elif mojom.IsDataPipeProducerKind(kind):
+ return "mojolpm::DataPipeProducerHandle"
+ elif mojom.IsMessagePipeKind(kind):
+ return "mojolpm::MessagePipeHandle"
+ elif mojom.IsSharedBufferKind(kind):
+ return "mojolpm::SharedBufferHandle"
+ elif mojom.IsPlatformHandleKind(kind):
+ return "mojolpm::PlatformHandle"
+
+ if not kind in _kind_to_cpp_proto_type:
+ raise Exception("Unrecognized kind %s" % kind.spec)
+ return _kind_to_cpp_proto_type[kind]
+
+ def _GetProtoFieldType(self, kind, quantified=True):
+ # TODO(markbrand): This will not handle array<array> or array<map>
+ # TODO(markbrand): This also will not handle array<x, 10>
+ unquantified = ''
+ if (mojom.IsEnumKind(kind) or mojom.IsStructKind(kind)
+ or mojom.IsUnionKind(kind)):
+ unquantified = self._GetProtoNameForKind(kind)
+ elif mojom.IsArrayKind(kind):
+ return "repeated %sEntry" % self._GetProtoFieldType(kind.kind,
+ quantified=False)
+ elif mojom.IsMapKind(kind):
+ return ("map<%sKey, %sValue>" %
+ (self._GetProtoFieldType(kind.key_kind, quantified=False),
+ self._GetProtoFieldType(kind.value_kind, quantified=False)))
+ elif mojom.IsInterfaceKind(kind):
+ unquantified = "%s.Ptr" % self._GetProtoNameForKind(kind)
+ elif mojom.IsInterfaceRequestKind(kind):
+ unquantified = "%s.Request" % self._GetProtoNameForKind(kind.kind)
+ elif mojom.IsAssociatedInterfaceKind(kind):
+ unquantified = "%s.AssociatedPtr" % self._GetProtoNameForKind(kind.kind)
+ elif mojom.IsAssociatedInterfaceRequestKind(kind):
+ unquantified = ("%s.AssociatedRequest" %
+ self._GetProtoNameForKind(kind.kind))
+ elif mojom.IsPendingRemoteKind(kind):
+ unquantified = "%s.PendingRemote" % self._GetProtoNameForKind(kind.kind)
+ elif mojom.IsPendingReceiverKind(kind):
+ unquantified = "%s.PendingReceiver" % self._GetProtoNameForKind(kind.kind)
+ elif mojom.IsPendingAssociatedRemoteKind(kind):
+ unquantified = ("%s.PendingAssociatedRemote" %
+ self._GetProtoNameForKind(kind.kind))
+ elif mojom.IsPendingAssociatedReceiverKind(kind):
+ unquantified = ("%s.PendingAssociatedReceiver" %
+ self._GetProtoNameForKind(kind.kind))
+ elif mojom.IsStringKind(kind):
+ unquantified = "string"
+ elif mojom.IsGenericHandleKind(kind):
+ unquantified = "mojolpm.Handle"
+ elif mojom.IsDataPipeConsumerKind(kind):
+ unquantified = "mojolpm.DataPipeConsumerHandle"
+ elif mojom.IsDataPipeProducerKind(kind):
+ unquantified = "mojolpm.DataPipeProducerHandle"
+ elif mojom.IsMessagePipeKind(kind):
+ unquantified = "mojolpm.MessagePipeHandle"
+ elif mojom.IsSharedBufferKind(kind):
+ unquantified = "mojolpm.SharedBufferHandle"
+ elif mojom.IsPlatformHandleKind(kind):
+ unquantified = "mojolpm.PlatformHandle"
+ else:
+ unquantified = _kind_to_proto_type[kind]
+
+ if quantified and mojom.IsNullableKind(kind):
+ return 'optional %s' % unquantified
+ elif quantified:
+ return 'required %s' % unquantified
+ else:
+ return unquantified
+
+ def _GetProtoId(self, name, kind=''):
+ # We reserve ids [0,15]
+ # Protobuf implementation reserves [19000,19999]
+ # Max proto id is 2^29-1
+ string = '{}@{}'.format(name, self._GetProtoFieldType(kind, False)).lower()
+ # 32-bit fnv-1a
+ fnv = 2166136261
+ for c in string:
+ fnv = fnv ^ ord(c)
+ fnv = (fnv * 16777619) & 0xffffffff
+ # xor-fold to 29-bits
+ fnv = (fnv >> 29) ^ (fnv & 0x1fffffff)
+ # now use a modulo to reduce to [0,2^29-1 - 1016]
+ fnv = fnv % 536869895
+ # now we move out the disallowed ranges
+ fnv = fnv + 15
+ if fnv >= 19000:
+ fnv += 1000
+ return fnv
+
+ def _NullableIsSameKind(self, kind):
+ if self._IsTypemappedKind(kind):
+ if not self.typemap[self._GetFullMojomNameForKind(
+ kind)]["nullable_is_same_type"]:
+ return False
+ if mojom.IsArrayKind(kind):
+ return False
+ if mojom.IsMapKind(kind):
+ return False
+ if mojom.IsStringKind(kind):
+ return False
+ return True
+
+ def _EnumHasDuplicateValues(self, kind):
+ values = set()
+ i = 0
+ for field in kind.fields:
+ if field.name == 'MAX':
+ continue
+ if field.value:
+ if _IsStrOrUnicode(field.value):
+ if field.value in values:
+ return True
+ values.add(field.value)
+ i = int(field.value, 0) + 1
+ else:
+ return True
+ else:
+ if str(i) in values:
+ return True
+ values.add(str(i))
+ i += 1
+ return False
+
+ def _EnumFieldName(self, name, kind):
+ # The WebFeature enum has entries that differ only by the casing of the
+ # names. Protobuf doesn't support this, so we add the value to the end of
+ # the name in these cases to disambiguate.
+ if kind not in self.enum_name_cache:
+ field_names = dict()
+ lower_field_names = set()
+ for field in kind.fields:
+ new_field_name = field.name
+ if new_field_name.lower() in lower_field_names:
+ new_field_name = '{}_{}'.format(new_field_name, field.numeric_value)
+ lower_field_names.add(new_field_name.lower())
+ field_names[field.name] = new_field_name
+ self.enum_name_cache[kind] = field_names
+ return self.enum_name_cache[kind][name]
diff --git a/chromium/mojo/public/tools/bindings/generators/mojom_ts_generator.py b/chromium/mojo/public/tools/bindings/generators/mojom_ts_generator.py
index c9cfd51ee96..2b85a8a0858 100644
--- a/chromium/mojo/public/tools/bindings/generators/mojom_ts_generator.py
+++ b/chromium/mojo/public/tools/bindings/generators/mojom_ts_generator.py
@@ -4,9 +4,13 @@
"""Generates Typescript source files from a mojom.Module."""
+import argparse
import mojom.generate.generator as generator
import mojom.generate.module as mojom
from mojom.generate.template_expander import UseJinja
+import os
+
+GENERATOR_PREFIX = 'ts'
_kind_to_typescript_type = {
mojom.BOOL: "boolean",
@@ -39,16 +43,19 @@ class TypescriptStylizer(generator.Stylizer):
return '.'.join(generator.ToCamel(word, lower_initial=True)
for word in mojom_namespace.split('.'))
+ def StylizeField(self, mojom_name):
+ return generator.ToCamel(mojom_name, lower_initial=True)
+
def StylizeConstant(self, mojom_name):
return generator.ToUpperSnakeCase(mojom_name)
-
class Generator(generator.Generator):
def _GetParameters(self, use_es_modules=False):
return {
- "module": self.module,
- "use_es_modules": use_es_modules,
- "enums": self.module.enums,
+ "module": self.module,
+ "use_es_modules": use_es_modules,
+ "enums": self.module.enums,
+ "structs": self.module.structs,
}
@staticmethod
@@ -57,8 +64,9 @@ class Generator(generator.Generator):
def GetFilters(self):
ts_filters = {
- "typescript_type_with_nullability": self._TypescriptTypeWithNullability,
- "constant_value": self._ConstantValue,
+ "typescript_type_with_nullability": self._TypescriptTypeWithNullability,
+ "constant_value": self._ConstantValue,
+ "relative_path": self._RelativePath,
}
return ts_filters
@@ -70,24 +78,61 @@ class Generator(generator.Generator):
def _GenerateESModulesBindings(self):
return self._GetParameters(use_es_modules=True)
- def GenerateFiles(self, args):
+ def GenerateFiles(self, unparsed_args):
if self.variant:
raise Exception("Variants not supported in JavaScript bindings.")
- self.module.Stylize(TypescriptStylizer())
-
- self.Write(self._GenerateBindings(), "%s-lite.ts" % self.module.path)
- self.Write(self._GenerateESModulesBindings(),
- "%s-lite.m.ts" % self.module.path)
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--ts_use_es_modules',
+ action="store_true",
+ help="Generate bindings that use ES Modules.")
+ args = parser.parse_args(unparsed_args)
+ self.module.Stylize(TypescriptStylizer())
- def _TypescriptType(self, kind):
+ self._SetUniqueAliasesForImports()
+
+ if args.ts_use_es_modules == True:
+ self.Write(self._GenerateESModulesBindings(),
+ "%s-lite.m.ts" % self.module.path)
+ else:
+ self.Write(self._GenerateBindings(), "%s-lite.ts" % self.module.path)
+
+ # Function that sets unique alias names for all imported modules based on
+ # their namespace. For example, for two imported modules with namespace
+ # "mojo.foo", we would generate two aliases "mojoFoo" and "mojoFoo$0".
+ def _SetUniqueAliasesForImports(self):
+ used_aliases = set()
+ for each_import in self.module.imports:
+ # Per the style guide module aliases start with lower case.
+ simple_alias = generator.ToCamel(identifier=each_import.namespace,
+ lower_initial=True,
+ delimiter='.')
+ unique_alias = simple_alias
+ counter = 0
+ while unique_alias in used_aliases:
+ unique_alias = '%s$%d' % (simple_alias, counter)
+ counter += 1
+
+ used_aliases.add(unique_alias)
+ each_import.unique_alias = unique_alias
+
+ def _TypescriptType(self, kind, use_es_modules):
if kind in mojom.PRIMITIVES:
return _kind_to_typescript_type[kind]
+
+ if mojom.IsStructKind(kind):
+ if kind.module and kind.module.path != self.module.path:
+ namespace = (kind.module.unique_alias
+ if use_es_modules else kind.module.namespace)
+ return '.'.join([namespace, kind.name])
+
+ return kind.name
+
raise Exception("Type is not supported yet.")
- def _TypescriptTypeWithNullability(self, kind):
- return (self._TypescriptType(kind) +
+ def _TypescriptTypeWithNullability(self, kind, use_es_modules):
+ return (self._TypescriptType(kind, use_es_modules) +
(" | null" if mojom.IsNullableKind(kind) else ""))
def _ConstantValue(self, constant):
@@ -110,3 +155,6 @@ class Generator(generator.Generator):
return "BigInt('%s')" % value
return value
+
+ def _RelativePath(self, path):
+ return os.path.relpath(path, os.path.dirname(self.module.path))
diff --git a/chromium/mojo/public/tools/bindings/generators/ts_templates/module_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/ts_templates/module_definition.tmpl
index dc6d54dff30..a00f9a03de5 100644
--- a/chromium/mojo/public/tools/bindings/generators/ts_templates/module_definition.tmpl
+++ b/chromium/mojo/public/tools/bindings/generators/ts_templates/module_definition.tmpl
@@ -1,21 +1,17 @@
-{%- if not use_es_modules %}
+{%- if not use_es_modules -%}
namespace {{module.namespace}} {
{% endif %}
{#--- Constants #}
{%- for constant in module.constants %}
-export const {{constant.name}}: {{constant.kind|typescript_type_with_nullability}} =
+export const {{constant.name}}: {{constant.kind|typescript_type_with_nullability(use_es_modules)}} =
{{constant|constant_value}};
{%- endfor %}
{#--- Enums #}
-{% for enum in enums %}
+{%- for enum in enums %}
export enum {{enum.name}} {
{%- for field in enum.fields %}
-{%- if field.value %}
- {{field.name}} = {{field.value}},
-{%- else %}
- {{field.name}},
-{%- endif %}
+ {{field.name}} = {{field.numeric_value}},
{%- endfor %}
{%- if enum.min_value is not none %}
MIN_VALUE = {{enum.min_value}},
@@ -26,6 +22,15 @@ export enum {{enum.name}} {
}
{% endfor %}
+{#--- Structs #}
+{%- for struct in structs %}
+export interface {{struct.name}} {
+{%- for packed_field in struct.packed.packed_fields %}
+ {{packed_field.field.name}}: {{packed_field.field.kind|typescript_type_with_nullability(use_es_modules)}};
+{%- endfor %}
+}
+{% endfor %}
+
{%- if not use_es_modules %}
} // namespace {{module.namespace}}
{% endif %}
diff --git a/chromium/mojo/public/tools/bindings/generators/ts_templates/mojom.tmpl b/chromium/mojo/public/tools/bindings/generators/ts_templates/mojom.tmpl
index 1dd6cf0afae..4d358eb9f08 100644
--- a/chromium/mojo/public/tools/bindings/generators/ts_templates/mojom.tmpl
+++ b/chromium/mojo/public/tools/bindings/generators/ts_templates/mojom.tmpl
@@ -2,4 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+{%- if use_es_modules %}
+{%- for import in module.imports %}
+{#
+ # We add a ".js" file extension because otherwise the compiled JS would import
+ # "-lite.m" which doesn't work on browsers unless served with a
+ # "text/javascript" MIME type.
+ #}
+import * as {{import.unique_alias}} from '{{import.path|relative_path}}-lite.m.js';
+{%- endfor %}
+{% endif %}
+
{% include "module_definition.tmpl" %}
diff --git a/chromium/mojo/public/tools/bindings/mojom.gni b/chromium/mojo/public/tools/bindings/mojom.gni
index f8c595f49f7..0d2080c566e 100644
--- a/chromium/mojo/public/tools/bindings/mojom.gni
+++ b/chromium/mojo/public/tools/bindings/mojom.gni
@@ -5,6 +5,7 @@
import("//build/config/jumbo.gni")
import("//third_party/closure_compiler/closure_args.gni")
import("//third_party/closure_compiler/compile_js.gni")
+import("//third_party/protobuf/proto_library.gni")
import("//ui/webui/webui_features.gni")
# TODO(rockot): Maybe we can factor these dependencies out of //mojo. They're
@@ -14,6 +15,7 @@ import("//ui/webui/webui_features.gni")
# flipped elsewhere though.
import("//build/config/chrome_build.gni")
import("//build/config/chromecast_build.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/nacl/config.gni")
import("//build/toolchain/kythe.gni")
import("//components/nacl/features.gni")
@@ -39,7 +41,7 @@ declare_args() {
# Enables Closure compilation of generated JS lite bindings. In environments
# where compilation is supported, any mojom target "foo" will also have a
# corresponding "foo_js_library_for_compile" target generated.
- enable_mojom_closure_compile = closure_compile && optimize_webui
+ enable_mojom_closure_compile = enable_js_type_check && optimize_webui
# Enables generating Typescript bindings and compiling them to JS bindings.
enable_typescript_bindings = false
@@ -60,8 +62,10 @@ declare_args() {
# check |target_os| explicitly, as it's consistent across all toolchains.
enable_scrambled_message_ids =
enable_mojom_message_id_scrambling &&
- (is_mac || is_win || (is_linux && !is_chromeos && !is_chromecast) ||
- ((enable_nacl || is_nacl || is_nacl_nonsfi) && target_os != "chromeos"))
+ (is_mac || is_win || (is_linux && !is_chromeos && !is_chromecast &&
+ !chromeos_is_browser_only) ||
+ ((enable_nacl || is_nacl || is_nacl_nonsfi) &&
+ (target_os != "chromeos" && !chromeos_is_browser_only)))
_mojom_tools_root = "//mojo/public/tools"
_mojom_library_root = "$_mojom_tools_root/mojom/mojom"
@@ -529,6 +533,12 @@ template("mojom") {
sources_list = invoker.sources
}
+ # Reset sources_assignment_filter for the BUILD.gn file to prevent
+ # regression during the migration of Chromium away from the feature.
+ # See docs/no_sources_assignment_filter.md for more information.
+ # TODO(crbug.com/1018739): remove this when migration is done.
+ set_sources_assignment_filter([])
+
# Listed sources may be relative to the current target dir, or they may be
# absolute paths, including paths to generated mojom files. While those are
# fine as-is for input references, deriving output paths can be more subtle.
@@ -904,6 +914,83 @@ template("mojom") {
}
}
+ if (generate_fuzzing) {
+ # This block generates the proto files used for the MojoLPM fuzzer,
+ # and the corresponding proto targets that will be linked in the fuzzer
+ # targets. These are independent of the typemappings, and can be done
+ # separately here.
+
+ generator_mojolpm_proto_target_name =
+ "${target_name}_mojolpm_proto_generator"
+ action(generator_mojolpm_proto_target_name) {
+ script = mojom_generator_script
+ inputs = mojom_generator_sources + jinja2_sources
+ sources = invoker.sources
+ deps = [
+ ":$parser_target_name",
+ "//mojo/public/tools/bindings:precompile_templates",
+ ]
+
+ outputs = []
+ args = common_generator_args
+ filelist = []
+ foreach(source, invoker.sources) {
+ filelist += [ rebase_path("$source", root_build_dir) ]
+ outputs += [ "$target_gen_dir/$source.mojolpm.proto" ]
+ }
+
+ response_file_contents = filelist
+
+ args += [
+ "--filelist={{response_file_name}}",
+ "--generate_non_variant_code",
+ "-g",
+ "mojolpm",
+ ]
+ }
+
+ mojolpm_proto_target_name = "${target_name}_mojolpm_proto"
+ if (defined(invoker.sources)) {
+ proto_library(mojolpm_proto_target_name) {
+ testonly = true
+ generate_python = false
+ sources = process_file_template(
+ invoker.sources,
+ [ "{{source_gen_dir}}/{{source_file_part}}.mojolpm.proto" ])
+ import_dirs = [ "${root_gen_dir}" ]
+ proto_in_dir = "${root_gen_dir}"
+ proto_out_dir = "."
+ proto_deps = [ "//mojo/public/tools/fuzzers:mojolpm_proto_copy" ]
+ proto_deps += [ ":$generator_mojolpm_proto_target_name" ]
+ link_deps = [ "//mojo/public/tools/fuzzers:mojolpm_proto" ]
+
+ foreach(d, all_deps) {
+ # Resolve the name, so that a target //mojo/something becomes
+ # //mojo/something:something and we can append mojolpm_proto_suffix
+ # to get the proto dependency name.
+ full_name = get_label_info("$d", "label_no_toolchain")
+ proto_deps += [ "${full_name}_mojolpm_proto" ]
+ link_deps += [ "${full_name}_mojolpm_proto" ]
+ }
+ }
+ } else {
+ group(mojolpm_proto_target_name) {
+ testonly = true
+ public_deps = [ "//mojo/public/tools/fuzzers:mojolpm_proto" ]
+ if (defined(generator_shared_target_name)) {
+ public_deps += [ ":$generator_shared_target_name" ]
+ }
+ foreach(d, all_deps) {
+ # Resolve the name, so that a target //mojo/something becomes
+ # //mojo/something:something and we can append #mojolpm_proto_suffix
+ # to get the proto dependency name.
+ full_name = get_label_info("$d", "label_no_toolchain")
+ public_deps += [ "${full_name}_mojolpm_proto" ]
+ }
+ }
+ }
+ }
+
# Generate code for variants.
if (!defined(invoker.disable_variants) || !invoker.disable_variants) {
enabled_configurations = _bindings_configurations
@@ -1021,33 +1108,7 @@ template("mojom") {
}
_typemap_config = typemap.config
if (get_path_info(source, "abspath") == _typemap_config.mojom) {
- enabled = false
- if (!defined(_typemap_config.os_whitelist)) {
- enabled = true
- } else {
- foreach(os, _typemap_config.os_whitelist) {
- if (os == "android" && is_android) {
- enabled = true
- } else if (os == "chromeos" && is_chromeos) {
- enabled = true
- } else if (os == "fuchsia" && is_fuchsia) {
- enabled = true
- } else if (os == "ios" && is_ios) {
- enabled = true
- } else if (os == "linux" && is_linux) {
- enabled = true
- } else if (os == "mac" && is_mac) {
- enabled = true
- } else if (os == "posix" && is_posix) {
- enabled = true
- } else if (os == "win" && is_win) {
- enabled = true
- }
- }
- }
- if (enabled) {
- active_typemaps += [ typemap ]
- }
+ active_typemaps += [ typemap ]
}
}
}
@@ -1081,6 +1142,12 @@ template("mojom") {
"$root_gen_dir/${base_path}${variant_dash_suffix}.cc",
"$root_gen_dir/${base_path}${variant_dash_suffix}.h",
]
+ if (generate_fuzzing && !defined(bindings_configuration.variant)) {
+ outputs += [
+ "$root_gen_dir/${base_path}${variant_dash_suffix}-mojolpm.cc",
+ "$root_gen_dir/${base_path}${variant_dash_suffix}-mojolpm.h",
+ ]
+ }
}
response_file_contents = filelist
@@ -1088,9 +1155,14 @@ template("mojom") {
args += [
"--filelist={{response_file_name}}",
"-g",
- "c++",
]
+ if (generate_fuzzing && !defined(bindings_configuration.variant)) {
+ args += [ "c++,mojolpm" ]
+ } else {
+ args += [ "c++" ]
+ }
+
if (defined(bindings_configuration.variant)) {
args += [
"--variant",
@@ -1141,6 +1213,73 @@ template("mojom") {
}
}
+ if (generate_fuzzing && !defined(variant)) {
+ # This block contains the C++ targets for the MojoLPM fuzzer, we need to
+ # do this here so that we can use the typemap configuration for the
+ # empty-variant Mojo target.
+
+ mojolpm_target_name = "${target_name}_mojolpm"
+ mojolpm_generator_target_name = "${target_name}__generator"
+ source_set(mojolpm_target_name) {
+ # There are still a few missing header dependencies between mojo targets
+ # with typemaps and the dependencies of their typemap headers. It would
+ # be good to enable include checking for these in the future though.
+ check_includes = false
+ testonly = true
+ if (defined(invoker.sources)) {
+ sources = process_file_template(
+ invoker.sources,
+ [
+ "{{source_gen_dir}}/{{source_file_part}}-mojolpm.cc",
+ "{{source_gen_dir}}/{{source_file_part}}-mojolpm.h",
+ ])
+ deps = []
+ } else {
+ sources = []
+ deps = []
+ }
+
+ public_deps = [
+ ":$generator_shared_target_name",
+
+ # NB: hardcoded dependency on the no-variant variant generator, since
+ # mojolpm only uses the no-variant type.
+ ":$mojolpm_generator_target_name",
+ ":$mojolpm_proto_target_name",
+ "//mojo/public/tools/fuzzers:mojolpm",
+ ]
+
+ foreach(d, all_deps) {
+ # Resolve the name, so that a target //mojo/something becomes
+ # //mojo/something:something and we can append variant_suffix to
+ # get the cpp dependency name.
+ full_name = get_label_info("$d", "label_no_toolchain")
+ public_deps += [ "${full_name}_mojolpm" ]
+ }
+
+ foreach(typemap, active_typemaps) {
+ _typemap_config = {
+ }
+ _typemap_config = typemap.config
+
+ if (defined(_typemap_config.deps)) {
+ deps += _typemap_config.deps
+ }
+ if (defined(_typemap_config.public_deps)) {
+ public_deps += _typemap_config.public_deps
+ }
+ }
+ foreach(config, cpp_typemap_configs) {
+ if (defined(config.traits_deps)) {
+ deps += config.traits_deps
+ }
+ if (defined(config.traits_public_deps)) {
+ public_deps += config.traits_public_deps
+ }
+ }
+ }
+ }
+
# Write the typemapping configuration for this target out to a file to be
# validated by a Python script. This helps catch mistakes that can't
# be caught by logic in GN.
@@ -1458,6 +1597,7 @@ template("mojom") {
java_target_name = target_name + "_java"
android_library(java_target_name) {
+ forward_variables_from(invoker, [ "enable_bytecode_checks" ])
deps = [
"//base:base_java",
"//mojo/public/java:bindings_java",
@@ -1630,69 +1770,111 @@ template("mojom") {
}
if ((generate_fuzzing || !defined(invoker.cpp_only) || !invoker.cpp_only) &&
use_typescript_for_target) {
- generator_ts_target_name = "${target_name}_ts__generator"
-
+ generator_js_target_names = []
source_filelist = []
- ts_filelist = []
- ts_outputs = []
- js_outputs = []
foreach(source, sources_list) {
source_filelist += [ rebase_path("$source", root_build_dir) ]
}
- foreach(base_path, output_file_base_paths) {
- ts_outputs += [
- "$root_gen_dir/$base_path-lite.ts",
- "$root_gen_dir/$base_path-lite.m.ts",
- ]
- ts_filelist += [
- rebase_path("$root_gen_dir/$base_path-lite.ts", root_build_dir),
- rebase_path("$root_gen_dir/$base_path-lite.m.ts", root_build_dir),
- ]
- js_outputs += [
- "$root_gen_dir/$base_path-lite.js",
- "$root_gen_dir/$base_path-lite.m.js",
- ]
- }
+ dependency_types = [
+ {
+ name = "regular"
+ ts_extension = ".ts"
+ js_extension = ".js"
+ },
+ {
+ name = "es_modules"
+ ts_extension = ".m.ts"
+ js_extension = ".m.js"
+ },
+ ]
- generator_ts_target_name = "${target_name}_ts__generator"
- action(generator_ts_target_name) {
- script = mojom_generator_script
- inputs = mojom_generator_sources + jinja2_sources
- sources = sources_list
- deps = [
- ":$parser_target_name",
- "//mojo/public/tools/bindings:precompile_templates",
- ]
- outputs = ts_outputs
- args = common_generator_args
- response_file_contents = source_filelist
+ foreach(dependency_type, dependency_types) {
+ ts_outputs = []
+ js_outputs = []
- args += [
- "--filelist={{response_file_name}}",
- "-g",
- "typescript",
- ]
+ foreach(base_path, output_file_base_paths) {
+ ts_outputs +=
+ [ "$root_gen_dir/$base_path-lite${dependency_type.ts_extension}" ]
+ js_outputs +=
+ [ "$root_gen_dir/$base_path-lite${dependency_type.js_extension}" ]
+ }
- # TODO(crbug.com/1007587): Support scramble_message_ids.
- # TODO(crbug.com/1007591): Support generate_fuzzing.
- }
+ # Generate Typescript bindings.
+ generator_ts_target_name =
+ "${target_name}_${dependency_type.name}__ts__generator"
+ action(generator_ts_target_name) {
+ script = mojom_generator_script
+ inputs = mojom_generator_sources + jinja2_sources
+ sources = sources_list
+ deps = [
+ ":$parser_target_name",
+ "//mojo/public/tools/bindings:precompile_templates",
+ ]
+ outputs = ts_outputs
+ args = common_generator_args
+ response_file_contents = source_filelist
- generator_js_target_name = "${target_name}_js__generator"
- action(generator_js_target_name) {
- script = "$mojom_generator_root/compile_typescript.py"
- sources = ts_outputs
- outputs = js_outputs
- public_deps = [ ":$generator_ts_target_name" ]
- response_file_contents = ts_filelist
- args = [ "--filelist={{response_file_name}}" ]
+ args += [
+ "--filelist={{response_file_name}}",
+ "-g",
+ "typescript",
+ ]
+
+ if (dependency_type.name == "es_modules") {
+ args += [ "--ts_use_es_modules" ]
+ }
+
+ # TODO(crbug.com/1007587): Support scramble_message_ids.
+ # TODO(crbug.com/1007591): Support generate_fuzzing.
+ }
+
+ # Create tsconfig.json for the generated Typescript.
+ tsconfig_filename =
+ "$target_gen_dir/$target_name-${dependency_type.name}-tsconfig.json"
+ tsconfig = {
+ }
+ tsconfig.compilerOptions = {
+ target = "es6"
+ module = "es6"
+ lib = [
+ "es6",
+ "esnext.bigint",
+ ]
+ strict = true
+ }
+ tsconfig.files = []
+ foreach(base_path, output_file_base_paths) {
+ tsconfig.files += [ rebase_path(
+ "$root_gen_dir/$base_path-lite${dependency_type.ts_extension}",
+ target_gen_dir,
+ root_gen_dir) ]
+ }
+ write_file(tsconfig_filename, tsconfig, "json")
+
+ # Compile previously generated Typescript to Javascript.
+ generator_js_target_name =
+ "${target_name}_${dependency_type.name}__js__generator"
+ generator_js_target_names += [ generator_js_target_name ]
+
+ action(generator_js_target_name) {
+ script = "$mojom_generator_root/compile_typescript.py"
+ sources = ts_outputs
+ outputs = js_outputs
+ public_deps = [ ":$generator_ts_target_name" ]
+ absolute_tsconfig_path =
+ rebase_path(tsconfig_filename, "", target_gen_dir)
+ args = [ "--tsconfig_path=$absolute_tsconfig_path" ]
+ }
}
js_target_name = target_name + "_js"
group(js_target_name) {
public_deps = []
if (sources_list != []) {
- public_deps += [ ":$generator_js_target_name" ]
+ foreach(generator_js_target_name, generator_js_target_names) {
+ public_deps += [ ":$generator_js_target_name" ]
+ }
}
foreach(d, all_deps) {
diff --git a/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py b/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py
index edcb982957a..da9efc71cef 100755
--- a/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py
+++ b/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py
@@ -42,7 +42,7 @@ import mojom.fileutil as fileutil
from mojom.generate.module import Module
from mojom.generate import template_expander
from mojom.generate import translate
-from mojom.generate.generator import AddComputedData, WriteFile
+from mojom.generate.generator import WriteFile
sys.path.append(
os.path.join(_GetDirAbove("mojo"), "tools", "diagnosis"))
@@ -50,10 +50,11 @@ import crbug_1001171
_BUILTIN_GENERATORS = {
- "c++": "mojom_cpp_generator",
- "javascript": "mojom_js_generator",
- "java": "mojom_java_generator",
- "typescript": "mojom_ts_generator",
+ "c++": "mojom_cpp_generator",
+ "javascript": "mojom_js_generator",
+ "java": "mojom_java_generator",
+ "mojolpm": "mojom_mojolpm_generator",
+ "typescript": "mojom_ts_generator",
}
@@ -108,6 +109,8 @@ def ScrambleMethodOrdinals(interfaces, salt):
i = 0
already_generated.clear()
for method in interface.methods:
+ if method.explicit_ordinal is not None:
+ continue
while True:
i = i + 1
if i == 1000000:
@@ -163,6 +166,8 @@ class MojomProcessor(object):
language_map = self._typemap.get(language, {})
language_map.update(typemap)
self._typemap[language] = language_map
+ if 'c++' in self._typemap:
+ self._typemap['mojolpm'] = self._typemap['c++']
def _GenerateModule(self, args, remaining_args, generator_modules,
rel_filename, imported_filename_stack):
@@ -185,7 +190,6 @@ class MojomProcessor(object):
ScrambleMethodOrdinals(module.interfaces, salt)
if self._should_generate(rel_filename.path):
- AddComputedData(module)
for language, generator_module in generator_modules.items():
generator = generator_module.Generator(
module, args.output_dir, typemap=self._typemap.get(language, {}),
@@ -276,10 +280,11 @@ def main():
generate_parser.add_argument("--filelist", help="mojom input file list")
generate_parser.add_argument("-d", "--depth", dest="depth", default=".",
help="depth from source root")
- generate_parser.add_argument("-g", "--generators",
+ generate_parser.add_argument("-g",
+ "--generators",
dest="generators_string",
metavar="GENERATORS",
- default="c++,javascript,java",
+ default="c++,javascript,java,mojolpm",
help="comma-separated list of generators")
generate_parser.add_argument(
"--gen_dir", dest="gen_directories", action="append", metavar="directory",
diff --git a/chromium/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py b/chromium/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py
index bcffbbb116e..bddbe3f4c58 100644
--- a/chromium/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py
+++ b/chromium/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py
@@ -9,14 +9,15 @@ from mojom_bindings_generator import ScrambleMethodOrdinals
class FakeIface(object):
- def __init__( self ):
- self.name = None
+ def __init__(self):
+ self.mojom_name = None
self.methods = None
class FakeMethod(object):
- def __init__( self ):
- self.ordinal = None
+ def __init__(self, explicit_ordinal=None):
+ self.explicit_ordinal = explicit_ordinal
+ self.ordinal = explicit_ordinal
self.ordinal_comment = None
@@ -25,18 +26,23 @@ class MojoBindingsGeneratorTest(unittest.TestCase):
def testMakeImportStackMessage(self):
"""Tests MakeImportStackMessage()."""
- self.assertEquals(MakeImportStackMessage(["x"]), "")
- self.assertEquals(MakeImportStackMessage(["x", "y"]),
- "\n y was imported by x")
- self.assertEquals(MakeImportStackMessage(["x", "y", "z"]),
- "\n z was imported by y\n y was imported by x")
+ self.assertEqual(MakeImportStackMessage(["x"]), "")
+ self.assertEqual(MakeImportStackMessage(["x", "y"]),
+ "\n y was imported by x")
+ self.assertEqual(MakeImportStackMessage(["x", "y", "z"]),
+ "\n z was imported by y\n y was imported by x")
def testScrambleMethodOrdinals(self):
"""Tests ScrambleMethodOrdinals()."""
interface = FakeIface()
- interface.name = 'RendererConfiguration'
- interface.methods = [FakeMethod(), FakeMethod(), FakeMethod()]
- ScrambleMethodOrdinals([interface], "foo")
+ interface.mojom_name = 'RendererConfiguration'
+ interface.methods = [
+ FakeMethod(),
+ FakeMethod(),
+ FakeMethod(),
+ FakeMethod(explicit_ordinal=42)
+ ]
+ ScrambleMethodOrdinals([interface], "foo".encode('utf-8'))
# These next three values are hard-coded. If the generation algorithm
# changes from being based on sha256(seed + interface.name + str(i)) then
# these numbers will obviously need to change too.
@@ -44,9 +50,12 @@ class MojoBindingsGeneratorTest(unittest.TestCase):
# Note that hashlib.sha256('fooRendererConfiguration1').digest()[:4] is
# '\xa5\xbc\xf9\xca' and that hex(1257880741) = '0x4af9bca5'. The
# difference in 0x4a vs 0xca is because we only take 31 bits.
- self.assertEquals(interface.methods[0].ordinal, 1257880741)
- self.assertEquals(interface.methods[1].ordinal, 631133653)
- self.assertEquals(interface.methods[2].ordinal, 549336076)
+ self.assertEqual(interface.methods[0].ordinal, 1257880741)
+ self.assertEqual(interface.methods[1].ordinal, 631133653)
+ self.assertEqual(interface.methods[2].ordinal, 549336076)
+
+ # Explicit method ordinals should not be scrambled.
+ self.assertEqual(interface.methods[3].ordinal, 42)
if __name__ == "__main__":
diff --git a/chromium/mojo/public/tools/fuzzers/mojolpm.gni b/chromium/mojo/public/tools/fuzzers/mojolpm.gni
new file mode 100644
index 00000000000..82f66c1e3c3
--- /dev/null
+++ b/chromium/mojo/public/tools/fuzzers/mojolpm.gni
@@ -0,0 +1,144 @@
+# Copyright 2020 The Chromium 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("//testing/libfuzzer/fuzzer_test.gni")
+import("//third_party/protobuf/proto_library.gni")
+import("//tools/ipc_fuzzer/ipc_fuzzer.gni")
+
+# Generate a MojoLPM-based fuzzer test.
+#
+# This rule will copy the proto file defining the fuzzer testcases into the
+# output directory so that it can be compiled against the generated MojoLPM
+# protos. It then adds a rule to compile that proto, and finally a fuzzer
+# test target which uses the compiled proto.
+#
+# Optionally it can also handle converting a seed corpus of text protos into
+# a binary corpus as part of the build.
+#
+# Parameters:
+# sources
+# List of source .cc files to compile.
+#
+# deps
+# List of dependencies to compile this target.
+#
+# proto_source
+# Single source .proto file defining the structure of a testcase.
+#
+# proto_deps
+# List of additional dependencies for compiling proto_source.
+#
+# testcase_proto_kind (optional, required if seed_corpus_sources provided)
+# Name of proto message type representing a testcase.
+#
+# seed_corpus_sources (optional)
+# List of source .textproto files used to build a seed corpus.
+#
+# Example:
+# mojolpm_fuzzer_test("foo_mojolpm_fuzzer") {
+# sources = [ "foo_mojolpm_fuzzer.cc" ]
+#
+# deps = [
+# "//content/browser/foo:foo_mojolpm_fuzzer_proto",
+# "//content/browser:for_content_tests",
+# "//content/public/browser:browser_sources",
+# "//content/test:test_support",
+# "//mojo/core/embedder",
+# "//mojo/public/tools/fuzzers:mojolpm",
+# "//third_party/libprotobuf-mutator",
+# ]
+#
+# proto_deps = [
+# "//content/browser/bar/mojom:mojom_mojolpm","
+# ]
+#
+# testcase_proto = "foo_mojolpm_fuzzer.proto"
+# testcase_proto_kind = "foo.mojolpm.proto.Testcase"
+#
+# seed_corpus_sources = [
+# "foo_mojolpm_fuzzer_corpus/seed_one.textproto",
+# "foo_mojolpm_fuzzer_corpus/seed_two.textproto",
+# ]
+# }
+template("mojolpm_fuzzer_test") {
+ assert(defined(invoker.sources) && defined(invoker.proto_source),
+ "\"sources\" and \"proto_source\" must be defined for $target_name")
+
+ assert(
+ !defined(invoker.seed_corpus_sources) ||
+ defined(invoker.testcase_proto_kind),
+ "\"testcase_proto_kind\" must be defined for $target_name since \"seed_corpus_sources\" is defined.")
+
+ if (enable_ipc_fuzzer) {
+ proto_target_name = "${target_name}_proto"
+
+ proto_library(proto_target_name) {
+ sources = [ invoker.proto_source ]
+ generate_python = false
+
+ proto_deps = [ "//mojo/public/tools/fuzzers:mojolpm_proto_copy" ]
+
+ import_dirs = [ root_gen_dir ]
+
+ link_deps = []
+
+ if (defined(invoker.proto_deps)) {
+ proto_deps += invoker.proto_deps
+ link_deps += invoker.proto_deps
+ }
+
+ testonly = true
+ }
+
+ if (defined(invoker.seed_corpus_sources)) {
+ protoc_convert_target_name = "${target_name}_protoc_convert"
+ seed_corpus_path = "${target_gen_dir}/${target_name}_seed_corpus"
+
+ protoc_convert(protoc_convert_target_name) {
+ sources = invoker.seed_corpus_sources
+
+ inputs = [ invoker.proto_source ]
+
+ output_pattern = "${seed_corpus_path}/{{source_name_part}}.binarypb"
+
+ args = [
+ "--encode=${invoker.testcase_proto_kind}",
+ "-I",
+ rebase_path(root_gen_dir),
+ "-I",
+ get_path_info(rebase_path(inputs[0]), "dir"),
+ rebase_path(inputs[0]),
+ ]
+
+ deps = []
+
+ if (defined(invoker.proto_deps)) {
+ deps += invoker.proto_deps
+ }
+
+ testonly = true
+ }
+ }
+
+ fuzzer_test(target_name) {
+ sources = invoker.sources
+ deps = [
+ ":${proto_target_name}",
+ "//mojo/core/embedder",
+ "//mojo/public/tools/fuzzers:mojolpm",
+ "//third_party/libprotobuf-mutator",
+ ]
+ if (defined(invoker.deps)) {
+ deps += invoker.deps
+ }
+
+ if (defined(invoker.seed_corpus_sources)) {
+ seed_corpus = seed_corpus_path
+ seed_corpus_deps = [ ":${protoc_convert_target_name}" ]
+ }
+ }
+ } else {
+ not_needed(invoker, "*")
+ }
+}
diff --git a/chromium/mojo/public/tools/mojom/check_stable_mojom_compatibility.py b/chromium/mojo/public/tools/mojom/check_stable_mojom_compatibility.py
new file mode 100755
index 00000000000..7e746112228
--- /dev/null
+++ b/chromium/mojo/public/tools/mojom/check_stable_mojom_compatibility.py
@@ -0,0 +1,170 @@
+#!/usr/bin/env python
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Verifies backward-compatibility of mojom type changes.
+
+Given a set of pre- and post-diff mojom file contents, and a root directory
+for a project, this tool verifies that any changes to [Stable] mojom types are
+backward-compatible with the previous version.
+
+This can be used e.g. by a presubmit check to prevent developers from making
+breaking changes to stable mojoms."""
+
+import argparse
+import errno
+import io
+import json
+import os
+import os.path
+import shutil
+import six
+import sys
+import tempfile
+
+from mojom.generate import module
+from mojom.generate import translate
+from mojom.parse import parser
+
+
+class ParseError(Exception):
+ pass
+
+
+def _ValidateDelta(root, delta):
+ """Parses all modified mojoms (including all transitive mojom dependencies,
+ even if unmodified) to perform backward-compatibility checks on any types
+ marked with the [Stable] attribute.
+
+ Note that unlike the normal build-time parser in mojom_parser.py, this does
+ not produce or rely on cached module translations, but instead parses the full
+ transitive closure of a mojom's input dependencies all at once.
+ """
+
+ # First build a map of all files covered by the delta
+ affected_files = set()
+ old_files = {}
+ new_files = {}
+ for change in delta:
+ # TODO(crbug.com/953884): Use pathlib once we're migrated fully to Python 3.
+ filename = change['filename'].replace('\\', '/')
+ affected_files.add(filename)
+ if change['old']:
+ old_files[filename] = change['old']
+ if change['new']:
+ new_files[filename] = change['new']
+
+ # Parse and translate all mojoms relevant to the delta, including transitive
+ # imports that weren't modified.
+ unmodified_modules = {}
+
+ def parseMojom(mojom, file_overrides, override_modules):
+ if mojom in unmodified_modules or mojom in override_modules:
+ return
+
+ contents = file_overrides.get(mojom)
+ if contents:
+ modules = override_modules
+ else:
+ modules = unmodified_modules
+ with io.open(os.path.join(root, mojom), encoding='utf-8') as f:
+ contents = f.read()
+
+ try:
+ ast = parser.Parse(contents, mojom)
+ except Exception as e:
+ six.reraise(
+ ParseError,
+ 'encountered exception {0} while parsing {1}'.format(e, mojom),
+ sys.exc_info()[2])
+ for imp in ast.import_list:
+ parseMojom(imp.import_filename, file_overrides, override_modules)
+
+ # Now that the transitive set of dependencies has been imported and parsed
+ # above, translate each mojom AST into a Module so that all types are fully
+ # defined and can be inspected.
+ all_modules = {}
+ all_modules.update(unmodified_modules)
+ all_modules.update(override_modules)
+ modules[mojom] = translate.OrderedModule(ast, mojom, all_modules)
+
+ old_modules = {}
+ for mojom in old_files.keys():
+ parseMojom(mojom, old_files, old_modules)
+ new_modules = {}
+ for mojom in new_files.keys():
+ parseMojom(mojom, new_files, new_modules)
+
+ # At this point we have a complete set of translated Modules from both the
+ # pre- and post-diff mojom contents. Now we can analyze backward-compatibility
+ # of the deltas.
+ #
+ # Note that for backward-compatibility checks we only care about types which
+ # were marked [Stable] before the diff. Types newly marked as [Stable] are not
+ # checked.
+ def collectTypes(modules):
+ types = {}
+ for m in modules.values():
+ for kinds in (m.enums, m.structs, m.unions, m.interfaces):
+ for kind in kinds:
+ types[kind.qualified_name] = kind
+ return types
+
+ old_types = collectTypes(old_modules)
+ new_types = collectTypes(new_modules)
+
+ # Collect any renamed types so they can be compared accordingly.
+ renamed_types = {}
+ for name, kind in new_types.items():
+ old_name = kind.attributes and kind.attributes.get('RenamedFrom')
+ if old_name:
+ renamed_types[old_name] = name
+
+ for qualified_name, kind in old_types.items():
+ if not kind.stable:
+ continue
+
+ new_name = renamed_types.get(qualified_name, qualified_name)
+ if new_name not in new_types:
+ raise Exception(
+ 'Stable type %s appears to be deleted by this change. If it was '
+ 'renamed, please add a [RenamedFrom] attribute to the new type. This '
+ 'can be deleted by a subsequent change.' % qualified_name)
+
+ if not new_types[new_name].IsBackwardCompatible(kind):
+ raise Exception('Stable type %s appears to have changed in a way which '
+ 'breaks backward-compatibility. Please fix!\n\nIf you '
+ 'believe this assessment to be incorrect, please file a '
+ 'Chromium bug against the "Internals>Mojo>Bindings" '
+ 'component.' % qualified_name)
+
+
+def Run(command_line, delta=None):
+ """Runs the tool with the given command_line. Normally this will read the
+ change description from stdin as a JSON-encoded list, but tests may pass a
+ delta directly for convenience."""
+ arg_parser = argparse.ArgumentParser(
+ description='Verifies backward-compatibility of mojom type changes.',
+ epilog="""
+This tool reads a change description from stdin and verifies that all modified
+[Stable] mojom types will retain backward-compatibility. The change description
+must be a JSON-encoded list of objects, each with a "filename" key (path to a
+changed mojom file, relative to ROOT); an "old" key whose value is a string of
+the full file contents before the change, or null if the file is being added;
+and a "new" key whose value is a string of the full file contents after the
+change, or null if the file is being deleted.""")
+ arg_parser.add_argument(
+ '--src-root',
+ required=True,
+ action='store',
+ metavar='ROOT',
+ help='The root of the source tree in which the checked mojoms live.')
+
+ args, _ = arg_parser.parse_known_args(command_line)
+ if not delta:
+ delta = json.load(sys.stdin)
+ _ValidateDelta(args.src_root, delta)
+
+
+if __name__ == '__main__':
+ Run(sys.argv[1:])
diff --git a/chromium/mojo/public/tools/mojom/check_stable_mojom_compatibility_unittest.py b/chromium/mojo/public/tools/mojom/check_stable_mojom_compatibility_unittest.py
new file mode 100755
index 00000000000..9f51ea7751f
--- /dev/null
+++ b/chromium/mojo/public/tools/mojom/check_stable_mojom_compatibility_unittest.py
@@ -0,0 +1,260 @@
+#!/usr/bin/env python
+# Copyright 2020 The Chromium 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 json
+import os
+import os.path
+import shutil
+import tempfile
+import unittest
+
+import check_stable_mojom_compatibility
+
+from mojom.generate import module
+
+
+class Change(object):
+ """Helper to clearly define a mojom file delta to be analyzed."""
+
+ def __init__(self, filename, old=None, new=None):
+ """If old is None, this is a file addition. If new is None, this is a file
+ deletion. Otherwise it's a file change."""
+ self.filename = filename
+ self.old = old
+ self.new = new
+
+
+class UnchangedFile(Change):
+ def __init__(self, filename, contents):
+ super(UnchangedFile, self).__init__(filename, old=contents, new=contents)
+
+
+class CheckStableMojomCompatibilityTest(unittest.TestCase):
+ """Tests covering the behavior of the compatibility checking tool. Note that
+ details of different compatibility checks and relevant failure modes are NOT
+ covered by these tests. Those are instead covered by unittests in
+ version_compatibility_unittest.py. Additionally, the tests which ensure a
+ given set of [Stable] mojom definitions are indeed plausibly stable (i.e. they
+ have no unstable dependencies) are covered by stable_attribute_unittest.py.
+
+ These tests cover higher-level concerns of the compatibility checking tool,
+ like file or symbol, renames, changes spread over multiple files, etc."""
+
+ def verifyBackwardCompatibility(self, changes):
+ """Helper for implementing assertBackwardCompatible and
+ assertNotBackwardCompatible"""
+
+ temp_dir = tempfile.mkdtemp()
+ for change in changes:
+ if change.old:
+ # Populate the old file on disk in our temporary fake source root
+ file_path = os.path.join(temp_dir, change.filename)
+ dir_path = os.path.dirname(file_path)
+ if not os.path.exists(dir_path):
+ os.makedirs(dir_path)
+ with open(file_path, 'w') as f:
+ f.write(change.old)
+
+ delta = []
+ for change in changes:
+ if change.old != change.new:
+ delta.append({
+ 'filename': change.filename,
+ 'old': change.old,
+ 'new': change.new
+ })
+
+ try:
+ check_stable_mojom_compatibility.Run(['--src-root', temp_dir],
+ delta=delta)
+ finally:
+ shutil.rmtree(temp_dir)
+
+ def assertBackwardCompatible(self, changes):
+ self.verifyBackwardCompatibility(changes)
+
+ def assertNotBackwardCompatible(self, changes):
+ try:
+ self.verifyBackwardCompatibility(changes)
+ except Exception:
+ return
+
+ raise Exception('Change unexpectedly passed a backward-compatibility check')
+
+ def testBasicCompatibility(self):
+ """Minimal smoke test to verify acceptance of a simple valid change."""
+ self.assertBackwardCompatible([
+ Change('foo/foo.mojom',
+ old='[Stable] struct S {};',
+ new='[Stable] struct S { [MinVersion=1] int32 x; };')
+ ])
+
+ def testBasicIncompatibility(self):
+ """Minimal smoke test to verify rejection of a simple invalid change."""
+ self.assertNotBackwardCompatible([
+ Change('foo/foo.mojom',
+ old='[Stable] struct S {};',
+ new='[Stable] struct S { int32 x; };')
+ ])
+
+ def testIgnoreIfNotStable(self):
+ """We don't care about types not marked [Stable]"""
+ self.assertBackwardCompatible([
+ Change('foo/foo.mojom',
+ old='struct S {};',
+ new='struct S { int32 x; };')
+ ])
+
+ def testRename(self):
+ """We can do checks for renamed types."""
+ self.assertBackwardCompatible([
+ Change('foo/foo.mojom',
+ old='[Stable] struct S {};',
+ new='[Stable, RenamedFrom="S"] struct T {};')
+ ])
+ self.assertNotBackwardCompatible([
+ Change('foo/foo.mojom',
+ old='[Stable] struct S {};',
+ new='[Stable, RenamedFrom="S"] struct T { int32 x; };')
+ ])
+ self.assertBackwardCompatible([
+ Change('foo/foo.mojom',
+ old='[Stable] struct S {};',
+ new="""\
+ [Stable, RenamedFrom="S"]
+ struct T { [MinVersion=1] int32 x; };
+ """)
+ ])
+
+ def testNewlyStable(self):
+ """We don't care about types newly marked as [Stable]."""
+ self.assertBackwardCompatible([
+ Change('foo/foo.mojom',
+ old='struct S {};',
+ new='[Stable] struct S { int32 x; };')
+ ])
+
+ def testFileRename(self):
+ """Make sure we can still do compatibility checks after a file rename."""
+ self.assertBackwardCompatible([
+ Change('foo/foo.mojom', old='[Stable] struct S {};', new=None),
+ Change('bar/bar.mojom',
+ old=None,
+ new='[Stable] struct S { [MinVersion=1] int32 x; };')
+ ])
+ self.assertNotBackwardCompatible([
+ Change('foo/foo.mojom', old='[Stable] struct S {};', new=None),
+ Change('bar/bar.mojom', old=None, new='[Stable] struct S { int32 x; };')
+ ])
+
+ def testWithImport(self):
+ """Ensure that cross-module dependencies do not break the compatibility
+ checking tool."""
+ self.assertBackwardCompatible([
+ Change('foo/foo.mojom',
+ old="""\
+ module foo;
+ [Stable] struct S {};
+ """,
+ new="""\
+ module foo;
+ [Stable] struct S { [MinVersion=2] int32 x; };
+ """),
+ Change('bar/bar.mojom',
+ old="""\
+ module bar;
+ import "foo/foo.mojom";
+ [Stable] struct T { foo.S s; };
+ """,
+ new="""\
+ module bar;
+ import "foo/foo.mojom";
+ [Stable] struct T { foo.S s; [MinVersion=1] int32 y; };
+ """)
+ ])
+
+ def testWithMovedDefinition(self):
+ """If a definition moves from one file to another, we should still be able
+ to check compatibility accurately."""
+ self.assertBackwardCompatible([
+ Change('foo/foo.mojom',
+ old="""\
+ module foo;
+ [Stable] struct S {};
+ """,
+ new="""\
+ module foo;
+ """),
+ Change('bar/bar.mojom',
+ old="""\
+ module bar;
+ import "foo/foo.mojom";
+ [Stable] struct T { foo.S s; };
+ """,
+ new="""\
+ module bar;
+ import "foo/foo.mojom";
+ [Stable, RenamedFrom="foo.S"] struct S {
+ [MinVersion=2] int32 x;
+ };
+ [Stable] struct T { S s; [MinVersion=1] int32 y; };
+ """)
+ ])
+
+ self.assertNotBackwardCompatible([
+ Change('foo/foo.mojom',
+ old="""\
+ module foo;
+ [Stable] struct S {};
+ """,
+ new="""\
+ module foo;
+ """),
+ Change('bar/bar.mojom',
+ old="""\
+ module bar;
+ import "foo/foo.mojom";
+ [Stable] struct T { foo.S s; };
+ """,
+ new="""\
+ module bar;
+ import "foo/foo.mojom";
+ [Stable, RenamedFrom="foo.S"] struct S { int32 x; };
+ [Stable] struct T { S s; [MinVersion=1] int32 y; };
+ """)
+ ])
+
+ def testWithUnmodifiedImport(self):
+ """Unchanged files in the filesystem are still parsed by the compatibility
+ checking tool if they're imported by a changed file."""
+ self.assertBackwardCompatible([
+ UnchangedFile('foo/foo.mojom', 'module foo; [Stable] struct S {};'),
+ Change('bar/bar.mojom',
+ old="""\
+ module bar;
+ import "foo/foo.mojom";
+ [Stable] struct T { foo.S s; };
+ """,
+ new="""\
+ module bar;
+ import "foo/foo.mojom";
+ [Stable] struct T { foo.S s; [MinVersion=1] int32 x; };
+ """)
+ ])
+
+ self.assertNotBackwardCompatible([
+ UnchangedFile('foo/foo.mojom', 'module foo; [Stable] struct S {};'),
+ Change('bar/bar.mojom',
+ old="""\
+ module bar;
+ import "foo/foo.mojom";
+ [Stable] struct T { foo.S s; };
+ """,
+ new="""\
+ module bar;
+ import "foo/foo.mojom";
+ [Stable] struct T { foo.S s; int32 x; };
+ """)
+ ])
diff --git a/chromium/mojo/public/tools/mojom/const_unittest.py b/chromium/mojo/public/tools/mojom/const_unittest.py
new file mode 100644
index 00000000000..cb42dfac355
--- /dev/null
+++ b/chromium/mojo/public/tools/mojom/const_unittest.py
@@ -0,0 +1,90 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from mojom_parser_test_case import MojomParserTestCase
+from mojom.generate import module as mojom
+
+
+class ConstTest(MojomParserTestCase):
+ """Tests constant parsing behavior."""
+
+ def testLiteralInt(self):
+ a_mojom = 'a.mojom'
+ self.WriteFile(a_mojom, 'const int32 k = 42;')
+ self.ParseMojoms([a_mojom])
+ a = self.LoadModule(a_mojom)
+ self.assertEqual(1, len(a.constants))
+ self.assertEqual('k', a.constants[0].mojom_name)
+ self.assertEqual('42', a.constants[0].value)
+
+ def testLiteralFloat(self):
+ a_mojom = 'a.mojom'
+ self.WriteFile(a_mojom, 'const float k = 42.5;')
+ self.ParseMojoms([a_mojom])
+ a = self.LoadModule(a_mojom)
+ self.assertEqual(1, len(a.constants))
+ self.assertEqual('k', a.constants[0].mojom_name)
+ self.assertEqual('42.5', a.constants[0].value)
+
+ def testLiteralString(self):
+ a_mojom = 'a.mojom'
+ self.WriteFile(a_mojom, 'const string k = "woot";')
+ self.ParseMojoms([a_mojom])
+ a = self.LoadModule(a_mojom)
+ self.assertEqual(1, len(a.constants))
+ self.assertEqual('k', a.constants[0].mojom_name)
+ self.assertEqual('"woot"', a.constants[0].value)
+
+ def testEnumConstant(self):
+ a_mojom = 'a.mojom'
+ self.WriteFile(a_mojom, 'module a; enum E { kA = 41, kB };')
+ b_mojom = 'b.mojom'
+ self.WriteFile(
+ b_mojom, """\
+ import "a.mojom";
+ const a.E kE1 = a.E.kB;
+
+ // We also allow value names to be unqualified, implying scope from the
+ // constant's type.
+ const a.E kE2 = kB;
+ """)
+ self.ParseMojoms([a_mojom, b_mojom])
+ a = self.LoadModule(a_mojom)
+ b = self.LoadModule(b_mojom)
+ self.assertEqual(1, len(a.enums))
+ self.assertEqual('E', a.enums[0].mojom_name)
+ self.assertEqual(2, len(b.constants))
+ self.assertEqual('kE1', b.constants[0].mojom_name)
+ self.assertEqual(a.enums[0], b.constants[0].kind)
+ self.assertEqual(a.enums[0].fields[1], b.constants[0].value.field)
+ self.assertEqual(42, b.constants[0].value.field.numeric_value)
+ self.assertEqual('kE2', b.constants[1].mojom_name)
+ self.assertEqual(a.enums[0].fields[1], b.constants[1].value.field)
+ self.assertEqual(42, b.constants[1].value.field.numeric_value)
+
+ def testConstantReference(self):
+ a_mojom = 'a.mojom'
+ self.WriteFile(a_mojom, 'const int32 kA = 42; const int32 kB = kA;')
+ self.ParseMojoms([a_mojom])
+ a = self.LoadModule(a_mojom)
+ self.assertEqual(2, len(a.constants))
+ self.assertEqual('kA', a.constants[0].mojom_name)
+ self.assertEqual('42', a.constants[0].value)
+ self.assertEqual('kB', a.constants[1].mojom_name)
+ self.assertEqual('42', a.constants[1].value)
+
+ def testImportedConstantReference(self):
+ a_mojom = 'a.mojom'
+ self.WriteFile(a_mojom, 'const int32 kA = 42;')
+ b_mojom = 'b.mojom'
+ self.WriteFile(b_mojom, 'import "a.mojom"; const int32 kB = kA;')
+ self.ParseMojoms([a_mojom, b_mojom])
+ a = self.LoadModule(a_mojom)
+ b = self.LoadModule(b_mojom)
+ self.assertEqual(1, len(a.constants))
+ self.assertEqual(1, len(b.constants))
+ self.assertEqual('kA', a.constants[0].mojom_name)
+ self.assertEqual('42', a.constants[0].value)
+ self.assertEqual('kB', b.constants[0].mojom_name)
+ self.assertEqual('42', b.constants[0].value)
diff --git a/chromium/mojo/public/tools/mojom/enum_unittest.py b/chromium/mojo/public/tools/mojom/enum_unittest.py
new file mode 100644
index 00000000000..d9005078671
--- /dev/null
+++ b/chromium/mojo/public/tools/mojom/enum_unittest.py
@@ -0,0 +1,92 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from mojom_parser_test_case import MojomParserTestCase
+
+
+class EnumTest(MojomParserTestCase):
+ """Tests enum parsing behavior."""
+
+ def testExplicitValues(self):
+ """Verifies basic parsing of assigned integral values."""
+ types = self.ExtractTypes('enum E { kFoo=0, kBar=2, kBaz };')
+ self.assertEqual('kFoo', types['E'].fields[0].mojom_name)
+ self.assertEqual(0, types['E'].fields[0].numeric_value)
+ self.assertEqual('kBar', types['E'].fields[1].mojom_name)
+ self.assertEqual(2, types['E'].fields[1].numeric_value)
+ self.assertEqual('kBaz', types['E'].fields[2].mojom_name)
+ self.assertEqual(3, types['E'].fields[2].numeric_value)
+
+ def testImplicitValues(self):
+ """Verifies basic automatic assignment of integral values at parse time."""
+ types = self.ExtractTypes('enum E { kFoo, kBar, kBaz };')
+ self.assertEqual('kFoo', types['E'].fields[0].mojom_name)
+ self.assertEqual(0, types['E'].fields[0].numeric_value)
+ self.assertEqual('kBar', types['E'].fields[1].mojom_name)
+ self.assertEqual(1, types['E'].fields[1].numeric_value)
+ self.assertEqual('kBaz', types['E'].fields[2].mojom_name)
+ self.assertEqual(2, types['E'].fields[2].numeric_value)
+
+ def testSameEnumReference(self):
+ """Verifies that an enum value can be assigned from the value of another
+ field within the same enum."""
+ types = self.ExtractTypes('enum E { kA, kB, kFirst=kA };')
+ self.assertEqual('kA', types['E'].fields[0].mojom_name)
+ self.assertEqual(0, types['E'].fields[0].numeric_value)
+ self.assertEqual('kB', types['E'].fields[1].mojom_name)
+ self.assertEqual(1, types['E'].fields[1].numeric_value)
+ self.assertEqual('kFirst', types['E'].fields[2].mojom_name)
+ self.assertEqual(0, types['E'].fields[2].numeric_value)
+
+ def testSameModuleOtherEnumReference(self):
+ """Verifies that an enum value can be assigned from the value of a field
+ in another enum within the same module."""
+ types = self.ExtractTypes('enum E { kA, kB }; enum F { kA = E.kB };')
+ self.assertEqual(1, types['F'].fields[0].numeric_value)
+
+ def testImportedEnumReference(self):
+ """Verifies that an enum value can be assigned from the value of a field
+ in another enum within a different module."""
+ a_mojom = 'a.mojom'
+ self.WriteFile(a_mojom, 'module a; enum E { kFoo=42, kBar };')
+ b_mojom = 'b.mojom'
+ self.WriteFile(b_mojom,
+ 'module b; import "a.mojom"; enum F { kFoo = a.E.kBar };')
+ self.ParseMojoms([a_mojom, b_mojom])
+ b = self.LoadModule(b_mojom)
+
+ self.assertEqual('F', b.enums[0].mojom_name)
+ self.assertEqual('kFoo', b.enums[0].fields[0].mojom_name)
+ self.assertEqual(43, b.enums[0].fields[0].numeric_value)
+
+ def testConstantReference(self):
+ """Verifies that an enum value can be assigned from the value of an
+ integral constant within the same module."""
+ types = self.ExtractTypes('const int32 kFoo = 42; enum E { kA = kFoo };')
+ self.assertEqual(42, types['E'].fields[0].numeric_value)
+
+ def testInvalidConstantReference(self):
+ """Verifies that enum values cannot be assigned from the value of
+ non-integral constants."""
+ with self.assertRaisesRegexp(ValueError, 'not an integer'):
+ self.ExtractTypes('const float kFoo = 1.0; enum E { kA = kFoo };')
+ with self.assertRaisesRegexp(ValueError, 'not an integer'):
+ self.ExtractTypes('const double kFoo = 1.0; enum E { kA = kFoo };')
+ with self.assertRaisesRegexp(ValueError, 'not an integer'):
+ self.ExtractTypes('const string kFoo = "lol"; enum E { kA = kFoo };')
+
+ def testImportedConstantReference(self):
+ """Verifies that an enum value can be assigned from the value of an integral
+ constant within an imported module."""
+ a_mojom = 'a.mojom'
+ self.WriteFile(a_mojom, 'module a; const int32 kFoo = 37;')
+ b_mojom = 'b.mojom'
+ self.WriteFile(b_mojom,
+ 'module b; import "a.mojom"; enum F { kFoo = a.kFoo };')
+ self.ParseMojoms([a_mojom, b_mojom])
+ b = self.LoadModule(b_mojom)
+
+ self.assertEqual('F', b.enums[0].mojom_name)
+ self.assertEqual('kFoo', b.enums[0].fields[0].mojom_name)
+ self.assertEqual(37, b.enums[0].fields[0].numeric_value)
diff --git a/chromium/mojo/public/tools/mojom/mojom/generate/generator.py b/chromium/mojo/public/tools/mojom/mojom/generate/generator.py
index 3471e6799a8..de62260a5c9 100644
--- a/chromium/mojo/public/tools/mojom/mojom/generate/generator.py
+++ b/chromium/mojo/public/tools/mojom/mojom/generate/generator.py
@@ -163,33 +163,30 @@ def AddComputedData(module):
struct.versions = pack.GetVersionInfo(struct.packed)
struct.exported = exported
- def _AddUnionComputedData(union):
- ordinal = 0
- for field in union.fields:
- if field.ordinal is not None:
- ordinal = field.ordinal
- field.ordinal = ordinal
- ordinal += 1
-
def _AddInterfaceComputedData(interface):
- next_ordinal = 0
interface.version = 0
for method in interface.methods:
- if method.ordinal is None:
- method.ordinal = next_ordinal
# this field is never scrambled
- method.sequential_ordinal = next_ordinal
- next_ordinal = method.ordinal + 1
+ method.sequential_ordinal = method.ordinal
if method.min_version is not None:
interface.version = max(interface.version, method.min_version)
method.param_struct = _GetStructFromMethod(method)
+ if interface.stable:
+ method.param_struct.attributes[mojom.ATTRIBUTE_STABLE] = True
+ if method.explicit_ordinal is None:
+ raise Exception(
+ 'Stable interfaces must declare explicit method ordinals. The '
+ 'method %s on stable interface %s does not declare an explicit '
+ 'ordinal.' % (method.mojom_name, interface.qualified_name))
interface.version = max(interface.version,
method.param_struct.versions[-1].version)
if method.response_parameters is not None:
method.response_param_struct = _GetResponseStructFromMethod(method)
+ if interface.stable:
+ method.response_param_struct.attributes[mojom.ATTRIBUTE_STABLE] = True
interface.version = max(
interface.version,
method.response_param_struct.versions[-1].version)
@@ -200,7 +197,9 @@ def AddComputedData(module):
"""Converts a method's parameters into the fields of a struct."""
params_class = "%s_%s_Params" % (method.interface.mojom_name,
method.mojom_name)
- struct = mojom.Struct(params_class, module=method.interface.module)
+ struct = mojom.Struct(params_class,
+ module=method.interface.module,
+ attributes={})
for param in method.parameters:
struct.AddField(
param.mojom_name,
@@ -214,7 +213,9 @@ def AddComputedData(module):
"""Converts a method's response_parameters into the fields of a struct."""
params_class = "%s_%s_ResponseParams" % (method.interface.mojom_name,
method.mojom_name)
- struct = mojom.Struct(params_class, module=method.interface.module)
+ struct = mojom.Struct(params_class,
+ module=method.interface.module,
+ attributes={})
for param in method.response_parameters:
struct.AddField(
param.mojom_name,
@@ -226,8 +227,6 @@ def AddComputedData(module):
for struct in module.structs:
_AddStructComputedData(True, struct)
- for union in module.unions:
- _AddUnionComputedData(union)
for interface in module.interfaces:
_AddInterfaceComputedData(interface)
diff --git a/chromium/mojo/public/tools/mojom/mojom/generate/module.py b/chromium/mojo/public/tools/mojom/mojom/generate/module.py
index f77cbe227b9..f8eef7c8fe7 100644
--- a/chromium/mojo/public/tools/mojom/mojom/generate/module.py
+++ b/chromium/mojo/public/tools/mojom/mojom/generate/module.py
@@ -254,6 +254,7 @@ PRIMITIVES = (
ATTRIBUTE_MIN_VERSION = 'MinVersion'
ATTRIBUTE_EXTENSIBLE = 'Extensible'
+ATTRIBUTE_STABLE = 'Stable'
ATTRIBUTE_SYNC = 'Sync'
@@ -264,7 +265,7 @@ class NamedValue(object):
self.mojom_name = mojom_name
def GetSpec(self):
- return (self.module.mojom_namespace + '.' +
+ return (self.module.GetNamespacePrefix() +
(self.parent_kind and
(self.parent_kind.mojom_name + '.') or "") + self.mojom_name)
@@ -299,9 +300,9 @@ class EnumValue(NamedValue):
self.enum = enum
def GetSpec(self):
- return (self.module.mojom_namespace + '.' +
- (self.parent_kind and (self.parent_kind.mojom_name + '.')
- or "") + self.enum.mojom_name + '.' + self.mojom_name)
+ return (self.module.GetNamespacePrefix() +
+ (self.parent_kind and (self.parent_kind.mojom_name + '.') or "") +
+ self.enum.mojom_name + '.' + self.mojom_name)
@property
def name(self):
@@ -371,6 +372,16 @@ class UnionField(Field):
pass
+def _IsFieldBackwardCompatible(new_field, old_field):
+ if (new_field.min_version or 0) != (old_field.min_version or 0):
+ return False
+
+ if isinstance(new_field.kind, (Enum, Struct, Union)):
+ return new_field.kind.IsBackwardCompatible(old_field.kind)
+
+ return new_field.kind == old_field.kind
+
+
class Struct(ReferenceKind):
"""A struct with typed fields.
@@ -443,6 +454,84 @@ class Struct(ReferenceKind):
for constant in self.constants:
constant.Stylize(stylizer)
+ def IsBackwardCompatible(self, older_struct):
+ """This struct is backward-compatible with older_struct if and only if all
+ of the following conditions hold:
+ - Any newly added field is tagged with a [MinVersion] attribute specifying
+ a version number greater than all previously used [MinVersion]
+ attributes within the struct.
+ - All fields present in older_struct remain present in the new struct,
+ with the same ordinal position, same optional or non-optional status,
+ same (or backward-compatible) type and where applicable, the same
+ [MinVersion] attribute value.
+ - All [MinVersion] attributes must be non-decreasing in ordinal order.
+ - All reference-typed (string, array, map, struct, or union) fields tagged
+ with a [MinVersion] greater than zero must be optional.
+ """
+
+ def buildOrdinalFieldMap(struct):
+ fields_by_ordinal = {}
+ for field in struct.fields:
+ if field.ordinal in fields_by_ordinal:
+ raise Exception('Multiple fields with ordinal %s in struct %s.' %
+ (field.ordinal, struct.mojom_name))
+ fields_by_ordinal[field.ordinal] = field
+ return fields_by_ordinal
+
+ new_fields = buildOrdinalFieldMap(self)
+ old_fields = buildOrdinalFieldMap(older_struct)
+ if len(new_fields) < len(old_fields):
+ # At least one field was removed, which is not OK.
+ return False
+
+ # If there are N fields, existing ordinal values must exactly cover the
+ # range from 0 to N-1.
+ num_old_ordinals = len(old_fields)
+ max_old_min_version = 0
+ for ordinal in range(num_old_ordinals):
+ new_field = new_fields[ordinal]
+ old_field = old_fields[ordinal]
+ if (old_field.min_version or 0) > max_old_min_version:
+ max_old_min_version = old_field.min_version
+ if not _IsFieldBackwardCompatible(new_field, old_field):
+ # Type or min-version mismatch between old and new versions of the same
+ # ordinal field.
+ return False
+
+ # At this point we know all old fields are intact in the new struct
+ # definition. Now verify that all new fields have a high enough min version
+ # and are appropriately optional where required.
+ num_new_ordinals = len(new_fields)
+ last_min_version = max_old_min_version
+ for ordinal in range(num_old_ordinals, num_new_ordinals):
+ new_field = new_fields[ordinal]
+ min_version = new_field.min_version or 0
+ if min_version <= max_old_min_version:
+ # A new field is being added to an existing version, which is not OK.
+ return False
+ if min_version < last_min_version:
+ # The [MinVersion] of a field cannot be lower than the [MinVersion] of
+ # a field with lower ordinal value.
+ return False
+ if IsReferenceKind(new_field.kind) and not IsNullableKind(new_field.kind):
+ # New fields whose type can be nullable MUST be nullable.
+ return False
+
+ return True
+
+ @property
+ def stable(self):
+ return self.attributes.get(ATTRIBUTE_STABLE, False) \
+ if self.attributes else False
+
+ @property
+ def qualified_name(self):
+ if self.parent_kind:
+ prefix = self.parent_kind.qualified_name + '.'
+ else:
+ prefix = self.module.GetNamespacePrefix()
+ return '%s%s' % (prefix, self.mojom_name)
+
def __eq__(self, rhs):
return (isinstance(rhs, Struct) and
(self.mojom_name, self.native_only, self.fields, self.constants,
@@ -498,6 +587,67 @@ class Union(ReferenceKind):
for field in self.fields:
field.Stylize(stylizer)
+ def IsBackwardCompatible(self, older_union):
+ """This union is backward-compatible with older_union if and only if all
+ of the following conditions hold:
+ - Any newly added field is tagged with a [MinVersion] attribute specifying
+ a version number greater than all previously used [MinVersion]
+ attributes within the union.
+ - All fields present in older_union remain present in the new union,
+ with the same ordinal value, same optional or non-optional status,
+ same (or backward-compatible) type, and where applicable, the same
+ [MinVersion] attribute value.
+ """
+
+ def buildOrdinalFieldMap(union):
+ fields_by_ordinal = {}
+ for field in union.fields:
+ if field.ordinal in fields_by_ordinal:
+ raise Exception('Multiple fields with ordinal %s in union %s.' %
+ (field.ordinal, union.mojom_name))
+ fields_by_ordinal[field.ordinal] = field
+ return fields_by_ordinal
+
+ new_fields = buildOrdinalFieldMap(self)
+ old_fields = buildOrdinalFieldMap(older_union)
+ if len(new_fields) < len(old_fields):
+ # At least one field was removed, which is not OK.
+ return False
+
+ max_old_min_version = 0
+ for ordinal, old_field in old_fields.items():
+ new_field = new_fields.get(ordinal)
+ if not new_field:
+ # A field was removed, which is not OK.
+ return False
+ if not _IsFieldBackwardCompatible(new_field, old_field):
+ # An field changed its type or MinVersion, which is not OK.
+ return False
+ old_min_version = old_field.min_version or 0
+ if old_min_version > max_old_min_version:
+ max_old_min_version = old_min_version
+
+ new_ordinals = set(new_fields.keys()) - set(old_fields.keys())
+ for ordinal in new_ordinals:
+ if (new_fields[ordinal].min_version or 0) <= max_old_min_version:
+ # New fields must use a MinVersion greater than any old fields.
+ return False
+
+ return True
+
+ @property
+ def stable(self):
+ return self.attributes.get(ATTRIBUTE_STABLE, False) \
+ if self.attributes else False
+
+ @property
+ def qualified_name(self):
+ if self.parent_kind:
+ prefix = self.parent_kind.qualified_name + '.'
+ else:
+ prefix = self.module.GetNamespacePrefix()
+ return '%s%s' % (prefix, self.mojom_name)
+
def __eq__(self, rhs):
return (isinstance(rhs, Union) and
(self.mojom_name, self.fields,
@@ -760,6 +910,7 @@ class Method(object):
self.interface = interface
self.mojom_name = mojom_name
self.name = None
+ self.explicit_ordinal = ordinal
self.ordinal = ordinal
self.parameters = []
self.param_struct = None
@@ -875,6 +1026,91 @@ class Interface(ReferenceKind):
for constant in self.constants:
constant.Stylize(stylizer)
+ def IsBackwardCompatible(self, older_interface):
+ """This interface is backward-compatible with older_interface if and only
+ if all of the following conditions hold:
+ - All defined methods in older_interface (when identified by ordinal) have
+ backward-compatible definitions in this interface. For each method this
+ means:
+ - The parameter list is backward-compatible, according to backward-
+ compatibility rules for structs, where each parameter is essentially
+ a struct field.
+ - If the old method definition does not specify a reply message, the
+ new method definition must not specify a reply message.
+ - If the old method definition specifies a reply message, the new
+ method definition must also specify a reply message with a parameter
+ list that is backward-compatible according to backward-compatibility
+ rules for structs.
+ - All newly introduced methods in this interface have a [MinVersion]
+ attribute specifying a version greater than any method in
+ older_interface.
+ """
+
+ def buildOrdinalMethodMap(interface):
+ methods_by_ordinal = {}
+ for method in interface.methods:
+ if method.ordinal in methods_by_ordinal:
+ raise Exception('Multiple methods with ordinal %s in interface %s.' %
+ (method.ordinal, interface.mojom_name))
+ methods_by_ordinal[method.ordinal] = method
+ return methods_by_ordinal
+
+ new_methods = buildOrdinalMethodMap(self)
+ old_methods = buildOrdinalMethodMap(older_interface)
+ max_old_min_version = 0
+ for ordinal, old_method in old_methods.items():
+ new_method = new_methods.get(ordinal)
+ if not new_method:
+ # A method was removed, which is not OK.
+ return False
+
+ if not new_method.param_struct.IsBackwardCompatible(
+ old_method.param_struct):
+ # The parameter list is not backward-compatible, which is not OK.
+ return False
+
+ if old_method.response_param_struct is None:
+ if new_method.response_param_struct is not None:
+ # A reply was added to a message which didn't have one before, and
+ # this is not OK.
+ return False
+ else:
+ if new_method.response_param_struct is None:
+ # A reply was removed from a message, which is not OK.
+ return False
+ if not new_method.response_param_struct.IsBackwardCompatible(
+ old_method.response_param_struct):
+ # The new message's reply is not backward-compatible with the old
+ # message's reply, which is not OK.
+ return False
+
+ if (old_method.min_version or 0) > max_old_min_version:
+ max_old_min_version = old_method.min_version
+
+ # All the old methods are compatible with their new counterparts. Now verify
+ # that newly added methods are properly versioned.
+ new_ordinals = set(new_methods.keys()) - set(old_methods.keys())
+ for ordinal in new_ordinals:
+ new_method = new_methods[ordinal]
+ if (new_method.min_version or 0) <= max_old_min_version:
+ # A method was added to an existing version, which is not OK.
+ return False
+
+ return True
+
+ @property
+ def stable(self):
+ return self.attributes.get(ATTRIBUTE_STABLE, False) \
+ if self.attributes else False
+
+ @property
+ def qualified_name(self):
+ if self.parent_kind:
+ prefix = self.parent_kind.qualified_name + '.'
+ else:
+ prefix = self.module.GetNamespacePrefix()
+ return '%s%s' % (prefix, self.mojom_name)
+
def __eq__(self, rhs):
return (isinstance(rhs, Interface)
and (self.mojom_name, self.methods, self.enums, self.constants,
@@ -964,6 +1200,50 @@ class Enum(Kind):
return self.attributes.get(ATTRIBUTE_EXTENSIBLE, False) \
if self.attributes else False
+ @property
+ def stable(self):
+ return self.attributes.get(ATTRIBUTE_STABLE, False) \
+ if self.attributes else False
+
+ @property
+ def qualified_name(self):
+ if self.parent_kind:
+ prefix = self.parent_kind.qualified_name + '.'
+ else:
+ prefix = self.module.GetNamespacePrefix()
+ return '%s%s' % (prefix, self.mojom_name)
+
+ def IsBackwardCompatible(self, older_enum):
+ """This enum is backward-compatible with older_enum if and only if one of
+ the following conditions holds:
+ - Neither enum is [Extensible] and both have the exact same set of valid
+ numeric values. Field names and aliases for the same numeric value do
+ not affect compatibility.
+ - older_enum is [Extensible], and for every version defined by
+ older_enum, this enum has the exact same set of valid numeric values.
+ """
+
+ def buildVersionFieldMap(enum):
+ fields_by_min_version = {}
+ for field in enum.fields:
+ if field.min_version not in fields_by_min_version:
+ fields_by_min_version[field.min_version] = set()
+ fields_by_min_version[field.min_version].add(field.numeric_value)
+ return fields_by_min_version
+
+ old_fields = buildVersionFieldMap(older_enum)
+ new_fields = buildVersionFieldMap(self)
+
+ if new_fields.keys() != old_fields.keys() and not older_enum.extensible:
+ return False
+
+ for min_version, valid_values in old_fields.items():
+ if (min_version not in new_fields
+ or new_fields[min_version] != valid_values):
+ return False
+
+ return True
+
def __eq__(self, rhs):
return (isinstance(rhs, Enum) and
(self.mojom_name, self.native_only, self.fields, self.attributes,
@@ -1017,6 +1297,9 @@ class Module(object):
'unions': False
})
+ def GetNamespacePrefix(self):
+ return '%s.' % self.mojom_namespace if self.mojom_namespace else ''
+
def AddInterface(self, mojom_name, attributes=None):
interface = Interface(mojom_name, self, attributes)
self.interfaces.append(interface)
diff --git a/chromium/mojo/public/tools/mojom/mojom/generate/translate.py b/chromium/mojo/public/tools/mojom/mojom/generate/translate.py
index 6854b8bfed9..d6df3ca6da8 100644
--- a/chromium/mojo/public/tools/mojom/mojom/generate/translate.py
+++ b/chromium/mojo/public/tools/mojom/mojom/generate/translate.py
@@ -12,11 +12,19 @@ already been parsed and converted to ASTs before.
import itertools
import os
import re
+import sys
+from mojom.generate import generator
from mojom.generate import module as mojom
from mojom.parse import ast
+def _IsStrOrUnicode(x):
+ if sys.version_info[0] < 3:
+ return isinstance(x, (unicode, str))
+ return isinstance(x, str)
+
+
def _DuplicateName(values):
"""Returns the 'mojom_name' of the first entry in |values| whose 'mojom_name'
has already been encountered. If there are no duplicates, returns None."""
@@ -50,6 +58,23 @@ def _ElemsOfType(elems, elem_type, scope):
return result
+def _ProcessElements(scope, elements, operations_by_type):
+ """Iterates over the given elements, running a function from
+ operations_by_type for any element that matches a key in that dict. The scope
+ is the name of the surrounding scope, such as a filename or struct name, used
+ only in error messages."""
+ names_in_this_scope = set()
+ for element in elements:
+ # pylint: disable=unidiomatic-typecheck
+ element_type = type(element)
+ if element_type in operations_by_type:
+ if element.mojom_name in names_in_this_scope:
+ raise Exception('Names must be unique within a scope. The name "%s" is '
+ 'used more than once within the scope "%s".' %
+ (duplicate_name, scope))
+ operations_by_type[element_type](element)
+
+
def _MapKind(kind):
map_to_kind = {
'bool': 'b',
@@ -153,39 +178,62 @@ def _LookupKind(kinds, spec, scope):
return kinds.get(spec)
-def _LookupValue(values, mojom_name, scope, kind):
- """Like LookupKind, but for constant values."""
- # If the type is an enum, the value can be specified as a qualified name, in
- # which case the form EnumName.ENUM_VALUE must be used. We use the presence
- # of a '.' in the requested name to identify this. Otherwise, we prepend the
- # enum name.
- if isinstance(kind, mojom.Enum) and '.' not in mojom_name:
- mojom_name = '%s.%s' % (kind.spec.split(':', 1)[1], mojom_name)
+def _GetScopeForKind(module, kind):
+ """For a given kind, returns a tuple of progressively more specific names
+ used to qualify the kind. For example if kind is an enum named Bar nested in a
+ struct Foo within module 'foo', this would return ('foo', 'Foo', 'Bar')"""
+ if isinstance(kind, mojom.Enum) and kind.parent_kind:
+ # Enums may be nested in other kinds.
+ return _GetScopeForKind(module, kind.parent_kind) + (kind.mojom_name, )
+
+ module_fragment = (module.mojom_namespace, ) if module.mojom_namespace else ()
+ kind_fragment = (kind.mojom_name, ) if kind else ()
+ return module_fragment + kind_fragment
+
+
+def _LookupValueInScope(module, kind, identifier):
+ """Given a kind and an identifier, this attempts to resolve the given
+ identifier to a concrete NamedValue within the scope of the given kind."""
+ scope = _GetScopeForKind(module, kind)
for i in reversed(range(len(scope) + 1)):
- test_spec = '.'.join(scope[:i])
- if test_spec:
- test_spec += '.'
- test_spec += mojom_name
- value = values.get(test_spec)
+ qualified_name = '.'.join(scope[:i] + (identifier, ))
+ value = module.values.get(qualified_name)
if value:
return value
+ return None
+
+
+def _LookupValue(module, parent_kind, implied_kind, ast_leaf_node):
+ """Resolves a leaf node in the form ('IDENTIFIER', 'x') to a constant value
+ identified by 'x' in some mojom definition. parent_kind is used as context
+ when resolving the identifier. If the given leaf node is not an IDENTIFIER
+ (e.g. already a constant value), it is returned as-is.
+
+ If implied_kind is provided, the parsed identifier may also be resolved within
+ its scope as fallback. This can be useful for more concise value references
+ when assigning enum-typed constants or field values."""
+ if not isinstance(ast_leaf_node, tuple) or ast_leaf_node[0] != 'IDENTIFIER':
+ return ast_leaf_node
- return values.get(mojom_name)
+ # First look for a known user-defined identifier to resolve this within the
+ # enclosing scope.
+ identifier = ast_leaf_node[1]
+ value = _LookupValueInScope(module, parent_kind, identifier)
+ if value:
+ return value
-def _FixupExpression(module, value, scope, kind):
- """Translates an IDENTIFIER into a built-in value or structured NamedValue
- object."""
- if isinstance(value, tuple) and value[0] == 'IDENTIFIER':
- # Allow user defined values to shadow builtins.
- result = _LookupValue(module.values, value[1], scope, kind)
- if result:
- if isinstance(result, tuple):
- raise Exception('Unable to resolve expression: %r' % value[1])
- return result
- if _IsBuiltinValue(value[1]):
- return mojom.BuiltinValue(value[1])
- return value
+ # Next look in the scope of implied_kind, if provided.
+ value = (implied_kind and implied_kind.module and _LookupValueInScope(
+ implied_kind.module, implied_kind, identifier))
+ if value:
+ return value
+
+ # Fall back on defined builtin symbols
+ if _IsBuiltinValue(identifier):
+ return mojom.BuiltinValue(identifier)
+
+ raise ValueError('Unknown identifier %s' % identifier)
def _Kind(kinds, spec, scope):
@@ -280,26 +328,22 @@ def _Struct(module, parsed_struct):
struct = mojom.Struct(module=module)
struct.mojom_name = parsed_struct.mojom_name
struct.native_only = parsed_struct.body is None
- struct.spec = 'x:' + module.mojom_namespace + '.' + struct.mojom_name
+ struct.spec = 'x:' + module.GetNamespacePrefix() + struct.mojom_name
module.kinds[struct.spec] = struct
- if struct.native_only:
- struct.enums = []
- struct.constants = []
- struct.fields_data = []
- else:
- struct.enums = list(
- map(
- lambda enum: _Enum(module, enum, struct),
- _ElemsOfType(parsed_struct.body, ast.Enum,
- parsed_struct.mojom_name)))
- struct.constants = list(
- map(
- lambda constant: _Constant(module, constant, struct),
- _ElemsOfType(parsed_struct.body, ast.Const,
- parsed_struct.mojom_name)))
- # Stash fields parsed_struct here temporarily.
- struct.fields_data = _ElemsOfType(parsed_struct.body, ast.StructField,
- parsed_struct.mojom_name)
+ struct.enums = []
+ struct.constants = []
+ struct.fields_data = []
+ if not struct.native_only:
+ _ProcessElements(
+ parsed_struct.mojom_name, parsed_struct.body, {
+ ast.Enum:
+ lambda enum: struct.enums.append(_Enum(module, enum, struct)),
+ ast.Const:
+ lambda const: struct.constants.append(
+ _Constant(module, const, struct)),
+ ast.StructField:
+ struct.fields_data.append,
+ })
struct.attributes = _AttributeListToDict(parsed_struct.attribute_list)
@@ -327,11 +371,12 @@ def _Union(module, parsed_union):
"""
union = mojom.Union(module=module)
union.mojom_name = parsed_union.mojom_name
- union.spec = 'x:' + module.mojom_namespace + '.' + union.mojom_name
+ union.spec = 'x:' + module.GetNamespacePrefix() + union.mojom_name
module.kinds[union.spec] = union
# Stash fields parsed_union here temporarily.
- union.fields_data = _ElemsOfType(parsed_union.body, ast.UnionField,
- parsed_union.mojom_name)
+ union.fields_data = []
+ _ProcessElements(parsed_union.mojom_name, parsed_union.body,
+ {ast.UnionField: union.fields_data.append})
union.attributes = _AttributeListToDict(parsed_union.attribute_list)
return union
@@ -351,9 +396,8 @@ def _StructField(module, parsed_field, struct):
field.kind = _Kind(module.kinds, _MapKind(parsed_field.typename),
(module.mojom_namespace, struct.mojom_name))
field.ordinal = parsed_field.ordinal.value if parsed_field.ordinal else None
- field.default = _FixupExpression(module, parsed_field.default_value,
- (module.mojom_namespace, struct.mojom_name),
- field.kind)
+ field.default = _LookupValue(module, struct, field.kind,
+ parsed_field.default_value)
field.attributes = _AttributeListToDict(parsed_field.attribute_list)
return field
@@ -373,8 +417,7 @@ def _UnionField(module, parsed_field, union):
field.kind = _Kind(module.kinds, _MapKind(parsed_field.typename),
(module.mojom_namespace, union.mojom_name))
field.ordinal = parsed_field.ordinal.value if parsed_field.ordinal else None
- field.default = _FixupExpression(
- module, None, (module.mojom_namespace, union.mojom_name), field.kind)
+ field.default = None
field.attributes = _AttributeListToDict(parsed_field.attribute_list)
return field
@@ -444,89 +487,85 @@ def _Interface(module, parsed_iface):
"""
interface = mojom.Interface(module=module)
interface.mojom_name = parsed_iface.mojom_name
- interface.spec = 'x:' + module.mojom_namespace + '.' + interface.mojom_name
+ interface.spec = 'x:' + module.GetNamespacePrefix() + interface.mojom_name
module.kinds[interface.spec] = interface
- interface.enums = list(
- map(lambda enum: _Enum(module, enum, interface),
- _ElemsOfType(parsed_iface.body, ast.Enum, parsed_iface.mojom_name)))
- interface.constants = list(
- map(lambda constant: _Constant(module, constant, interface),
- _ElemsOfType(parsed_iface.body, ast.Const, parsed_iface.mojom_name)))
- # Stash methods parsed_iface here temporarily.
- interface.methods_data = _ElemsOfType(parsed_iface.body, ast.Method,
- parsed_iface.mojom_name)
interface.attributes = _AttributeListToDict(parsed_iface.attribute_list)
+ interface.enums = []
+ interface.constants = []
+ interface.methods_data = []
+ _ProcessElements(
+ parsed_iface.mojom_name, parsed_iface.body, {
+ ast.Enum:
+ lambda enum: interface.enums.append(_Enum(module, enum, interface)),
+ ast.Const:
+ lambda const: interface.constants.append(
+ _Constant(module, const, interface)),
+ ast.Method:
+ interface.methods_data.append,
+ })
return interface
-def _EnumField(module, enum, parsed_field, parent_kind):
+def _EnumField(module, enum, parsed_field):
"""
Args:
module: {mojom.Module} Module currently being constructed.
enum: {mojom.Enum} Enum this field belongs to.
parsed_field: {ast.EnumValue} Parsed enum value.
- parent_kind: {mojom.Kind} The enclosing type.
Returns:
{mojom.EnumField} AST enum field.
"""
field = mojom.EnumField()
field.mojom_name = parsed_field.mojom_name
- # TODO(mpcomplete): FixupExpression should be done in the second pass,
- # so constants and enums can refer to each other.
- # TODO(mpcomplete): But then, what if constants are initialized to an enum? Or
- # vice versa?
- if parent_kind:
- field.value = _FixupExpression(
- module, parsed_field.value,
- (module.mojom_namespace, parent_kind.mojom_name), enum)
- else:
- field.value = _FixupExpression(module, parsed_field.value,
- (module.mojom_namespace, ), enum)
+ field.value = _LookupValue(module, enum, None, parsed_field.value)
field.attributes = _AttributeListToDict(parsed_field.attribute_list)
value = mojom.EnumValue(module, enum, field)
module.values[value.GetSpec()] = value
return field
-def _ResolveNumericEnumValues(enum_fields):
+def _ResolveNumericEnumValues(enum):
"""
- Given a reference to a list of mojom.EnumField, resolves and assigns their
- values to EnumField.numeric_value.
-
- Returns:
- A tuple of the lowest and highest assigned enumerator value or None, None
- if no enumerator values were assigned.
+ Given a reference to a mojom.Enum, resolves and assigns the numeric value of
+ each field, and also computes the min_value and max_value of the enum.
"""
# map of <mojom_name> -> integral value
- resolved_enum_values = {}
prev_value = -1
min_value = None
max_value = None
- for field in enum_fields:
+ for field in enum.fields:
# This enum value is +1 the previous enum value (e.g: BEGIN).
if field.value is None:
prev_value += 1
# Integral value (e.g: BEGIN = -0x1).
- elif isinstance(field.value, str):
+ elif _IsStrOrUnicode(field.value):
prev_value = int(field.value, 0)
# Reference to a previous enum value (e.g: INIT = BEGIN).
elif isinstance(field.value, mojom.EnumValue):
- prev_value = resolved_enum_values[field.value.mojom_name]
+ prev_value = field.value.field.numeric_value
+ elif isinstance(field.value, mojom.ConstantValue):
+ constant = field.value.constant
+ kind = constant.kind
+ if not mojom.IsIntegralKind(kind) or mojom.IsBoolKind(kind):
+ raise ValueError('Enum values must be integers. %s is not an integer.' %
+ constant.mojom_name)
+ prev_value = int(constant.value, 0)
else:
- raise Exception("Unresolved enum value.")
+ raise Exception('Unresolved enum value for %s' % field.value.GetSpec())
- resolved_enum_values[field.mojom_name] = prev_value
+ #resolved_enum_values[field.mojom_name] = prev_value
field.numeric_value = prev_value
if min_value is None or prev_value < min_value:
min_value = prev_value
if max_value is None or prev_value > max_value:
max_value = prev_value
- return min_value, max_value
+ enum.min_value = min_value
+ enum.max_value = max_value
def _Enum(module, parsed_enum, parent_kind):
@@ -547,11 +586,12 @@ def _Enum(module, parsed_enum, parent_kind):
enum.spec = 'x:%s.%s' % (module.mojom_namespace, mojom_name)
enum.parent_kind = parent_kind
enum.attributes = _AttributeListToDict(parsed_enum.attribute_list)
+
if not enum.native_only:
enum.fields = list(
- map(lambda field: _EnumField(module, enum, field, parent_kind),
+ map(lambda field: _EnumField(module, enum, field),
parsed_enum.enum_value_list))
- enum.min_value, enum.max_value = _ResolveNumericEnumValues(enum.fields)
+ _ResolveNumericEnumValues(enum)
module.kinds[enum.spec] = enum
@@ -583,7 +623,12 @@ def _Constant(module, parsed_const, parent_kind):
# TODO(mpcomplete): maybe we should only support POD kinds.
constant.kind = _Kind(module.kinds, _MapKind(parsed_const.typename), scope)
constant.parent_kind = parent_kind
- constant.value = _FixupExpression(module, parsed_const.value, scope, None)
+ constant.value = _LookupValue(module, parent_kind, constant.kind,
+ parsed_const.value)
+
+ # Iteratively resolve this constant reference to a concrete value
+ while isinstance(constant.value, mojom.ConstantValue):
+ constant.value = constant.value.constant.value
value = mojom.ConstantValue(module, parent_kind, constant)
module.values[value.GetSpec()] = value
@@ -643,6 +688,47 @@ def _CollectReferencedKinds(module, all_defined_kinds):
return referenced_user_kinds
+def _AssignDefaultOrdinals(items):
+ """Assigns default ordinal values to a sequence of items if necessary."""
+ next_ordinal = 0
+ for item in items:
+ if item.ordinal is not None:
+ next_ordinal = item.ordinal + 1
+ else:
+ item.ordinal = next_ordinal
+ next_ordinal += 1
+
+
+def _AssertTypeIsStable(kind):
+ """Raises an error if a type is not stable, meaning it is composed of at least
+ one type that is not marked [Stable]."""
+
+ def assertDependencyIsStable(dependency):
+ if (mojom.IsEnumKind(dependency) or mojom.IsStructKind(dependency)
+ or mojom.IsUnionKind(dependency) or mojom.IsInterfaceKind(dependency)):
+ if not dependency.stable:
+ raise Exception(
+ '%s is marked [Stable] but cannot be stable because it depends on '
+ '%s, which is not marked [Stable].' %
+ (kind.mojom_name, dependency.mojom_name))
+ elif mojom.IsArrayKind(dependency) or mojom.IsAnyInterfaceKind(dependency):
+ assertDependencyIsStable(dependency.kind)
+ elif mojom.IsMapKind(dependency):
+ assertDependencyIsStable(dependency.key_kind)
+ assertDependencyIsStable(dependency.value_kind)
+
+ if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
+ for field in kind.fields:
+ assertDependencyIsStable(field.kind)
+ elif mojom.IsInterfaceKind(kind):
+ for method in kind.methods:
+ for param in method.param_struct.fields:
+ assertDependencyIsStable(param.kind)
+ if method.response_param_struct:
+ for response_param in method.response_param_struct.fields:
+ assertDependencyIsStable(response_param.kind)
+
+
def _Module(tree, path, imports):
"""
Args:
@@ -675,21 +761,25 @@ def _Module(tree, path, imports):
filename = os.path.basename(path)
# First pass collects kinds.
- module.enums = list(
- map(lambda enum: _Enum(module, enum, None),
- _ElemsOfType(tree.definition_list, ast.Enum, filename)))
- module.structs = list(
- map(lambda struct: _Struct(module, struct),
- _ElemsOfType(tree.definition_list, ast.Struct, filename)))
- module.unions = list(
- map(lambda union: _Union(module, union),
- _ElemsOfType(tree.definition_list, ast.Union, filename)))
- module.interfaces = list(
- map(lambda interface: _Interface(module, interface),
- _ElemsOfType(tree.definition_list, ast.Interface, filename)))
- module.constants = list(
- map(lambda constant: _Constant(module, constant, None),
- _ElemsOfType(tree.definition_list, ast.Const, filename)))
+ module.constants = []
+ module.enums = []
+ module.structs = []
+ module.unions = []
+ module.interfaces = []
+ _ProcessElements(
+ filename, tree.definition_list, {
+ ast.Const:
+ lambda const: module.constants.append(_Constant(module, const, None)),
+ ast.Enum:
+ lambda enum: module.enums.append(_Enum(module, enum, None)),
+ ast.Struct:
+ lambda struct: module.structs.append(_Struct(module, struct)),
+ ast.Union:
+ lambda union: module.unions.append(_Union(module, union)),
+ ast.Interface:
+ lambda interface: module.interfaces.append(
+ _Interface(module, interface)),
+ })
# Second pass expands fields and methods. This allows fields and parameters
# to refer to kinds defined anywhere in the mojom.
@@ -698,19 +788,24 @@ def _Module(tree, path, imports):
struct.fields = list(
map(lambda field: _StructField(module, field, struct),
struct.fields_data))
+ _AssignDefaultOrdinals(struct.fields)
del struct.fields_data
all_defined_kinds[struct.spec] = struct
for enum in struct.enums:
all_defined_kinds[enum.spec] = enum
+
for union in module.unions:
union.fields = list(
map(lambda field: _UnionField(module, field, union), union.fields_data))
+ _AssignDefaultOrdinals(union.fields)
del union.fields_data
all_defined_kinds[union.spec] = union
+
for interface in module.interfaces:
interface.methods = list(
map(lambda method: _Method(module, method, interface),
interface.methods_data))
+ _AssignDefaultOrdinals(interface.methods)
del interface.methods_data
all_defined_kinds[interface.spec] = interface
for enum in interface.enums:
@@ -725,6 +820,21 @@ def _Module(tree, path, imports):
module.imported_kinds = dict(
(spec, all_referenced_kinds[spec]) for spec in imported_kind_specs)
+ generator.AddComputedData(module)
+ for iface in module.interfaces:
+ for method in iface.methods:
+ if method.param_struct:
+ _AssignDefaultOrdinals(method.param_struct.fields)
+ if method.response_param_struct:
+ _AssignDefaultOrdinals(method.response_param_struct.fields)
+
+ # Ensure that all types marked [Stable] are actually stable. Enums are
+ # automatically OK since they don't depend on other definitions.
+ for kinds in (module.structs, module.unions, module.interfaces):
+ for kind in kinds:
+ if kind.stable:
+ _AssertTypeIsStable(kind)
+
return module
diff --git a/chromium/mojo/public/tools/mojom/mojom/parse/ast.py b/chromium/mojo/public/tools/mojom/mojom/parse/ast.py
index c9b6605cf43..1f0db200549 100644
--- a/chromium/mojo/public/tools/mojom/mojom/parse/ast.py
+++ b/chromium/mojo/public/tools/mojom/mojom/parse/ast.py
@@ -9,6 +9,15 @@
# failures, especially for more complex types.
+import sys
+
+
+def _IsStrOrUnicode(x):
+ if sys.version_info[0] < 3:
+ return isinstance(x, (unicode, str))
+ return isinstance(x, str)
+
+
class NodeBase(object):
"""Base class for nodes in the AST."""
@@ -87,7 +96,7 @@ class Definition(NodeBase):
include parameter definitions.) This class is meant to be subclassed."""
def __init__(self, mojom_name, **kwargs):
- assert isinstance(mojom_name, str)
+ assert _IsStrOrUnicode(mojom_name)
NodeBase.__init__(self, **kwargs)
self.mojom_name = mojom_name
@@ -99,7 +108,7 @@ class Attribute(NodeBase):
"""Represents an attribute."""
def __init__(self, key, value, **kwargs):
- assert isinstance(key, str)
+ assert _IsStrOrUnicode(key)
super(Attribute, self).__init__(**kwargs)
self.key = key
self.value = value
@@ -122,10 +131,10 @@ class Const(Definition):
def __init__(self, mojom_name, attribute_list, typename, value, **kwargs):
assert attribute_list is None or isinstance(attribute_list, AttributeList)
# The typename is currently passed through as a string.
- assert isinstance(typename, str)
+ assert _IsStrOrUnicode(typename)
# The value is either a literal (currently passed through as a string) or a
# "wrapped identifier".
- assert isinstance(value, str) or isinstance(value, tuple)
+ assert _IsStrOrUnicode or isinstance(value, tuple)
super(Const, self).__init__(mojom_name, **kwargs)
self.attribute_list = attribute_list
self.typename = typename
@@ -161,7 +170,7 @@ class EnumValue(Definition):
# The optional value is either an int (which is current a string) or a
# "wrapped identifier".
assert attribute_list is None or isinstance(attribute_list, AttributeList)
- assert value is None or isinstance(value, (str, tuple))
+ assert value is None or _IsStrOrUnicode(value) or isinstance(value, tuple)
super(EnumValue, self).__init__(mojom_name, **kwargs)
self.attribute_list = attribute_list
self.value = value
@@ -184,7 +193,7 @@ class Import(NodeBase):
def __init__(self, attribute_list, import_filename, **kwargs):
assert attribute_list is None or isinstance(attribute_list, AttributeList)
- assert isinstance(import_filename, str)
+ assert _IsStrOrUnicode(import_filename)
super(Import, self).__init__(**kwargs)
self.attribute_list = attribute_list
self.import_filename = import_filename
@@ -305,10 +314,10 @@ class Parameter(NodeBase):
"""Represents a method request or response parameter."""
def __init__(self, mojom_name, attribute_list, ordinal, typename, **kwargs):
- assert isinstance(mojom_name, str)
+ assert _IsStrOrUnicode(mojom_name)
assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert ordinal is None or isinstance(ordinal, Ordinal)
- assert isinstance(typename, str)
+ assert _IsStrOrUnicode(typename)
super(Parameter, self).__init__(**kwargs)
self.mojom_name = mojom_name
self.attribute_list = attribute_list
@@ -350,13 +359,14 @@ class StructField(Definition):
def __init__(self, mojom_name, attribute_list, ordinal, typename,
default_value, **kwargs):
- assert isinstance(mojom_name, str)
+ assert _IsStrOrUnicode(mojom_name)
assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert ordinal is None or isinstance(ordinal, Ordinal)
- assert isinstance(typename, str)
+ assert _IsStrOrUnicode(typename)
# The optional default value is currently either a value as a string or a
# "wrapped identifier".
- assert default_value is None or isinstance(default_value, (str, tuple))
+ assert default_value is None or _IsStrOrUnicode(default_value) or \
+ isinstance(default_value, tuple)
super(StructField, self).__init__(mojom_name, **kwargs)
self.attribute_list = attribute_list
self.ordinal = ordinal
@@ -396,10 +406,10 @@ class Union(Definition):
class UnionField(Definition):
def __init__(self, mojom_name, attribute_list, ordinal, typename, **kwargs):
- assert isinstance(mojom_name, str)
+ assert _IsStrOrUnicode(mojom_name)
assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert ordinal is None or isinstance(ordinal, Ordinal)
- assert isinstance(typename, str)
+ assert _IsStrOrUnicode(typename)
super(UnionField, self).__init__(mojom_name, **kwargs)
self.attribute_list = attribute_list
self.ordinal = ordinal
diff --git a/chromium/mojo/public/tools/mojom/mojom/parse/parser.py b/chromium/mojo/public/tools/mojom/mojom/parse/parser.py
index fbde9889df7..b3b803d6f33 100644
--- a/chromium/mojo/public/tools/mojom/mojom/parse/parser.py
+++ b/chromium/mojo/public/tools/mojom/mojom/parse/parser.py
@@ -472,7 +472,7 @@ def Parse(source, filename):
"""Parse source file to AST.
Args:
- source: The source text as a str.
+ source: The source text as a str (Python 2 or 3) or unicode (Python 2).
filename: The filename that |source| originates from.
Returns:
diff --git a/chromium/mojo/public/tools/mojom/mojom_parser.py b/chromium/mojo/public/tools/mojom/mojom_parser.py
index 0d63a4ad933..12adbfb9d3f 100755
--- a/chromium/mojo/public/tools/mojom/mojom_parser.py
+++ b/chromium/mojo/public/tools/mojom/mojom_parser.py
@@ -11,6 +11,7 @@ generate usable language bindings.
"""
import argparse
+import codecs
import errno
import json
import os
@@ -193,7 +194,7 @@ def _ParseMojoms(mojom_files,
abs_paths = dict(
(path, abs_path) for abs_path, path in mojom_files_to_parse.items())
for mojom_abspath, _ in mojom_files_to_parse.items():
- with open(mojom_abspath) as f:
+ with codecs.open(mojom_abspath, encoding='utf-8') as f:
ast = parser.Parse(''.join(f.readlines()), mojom_abspath)
conditional_features.RemoveDisabledDefinitions(ast, enabled_features)
loaded_mojom_asts[mojom_abspath] = ast
diff --git a/chromium/mojo/public/tools/mojom/mojom_parser_test_case.py b/chromium/mojo/public/tools/mojom/mojom_parser_test_case.py
new file mode 100644
index 00000000000..e213fbfa760
--- /dev/null
+++ b/chromium/mojo/public/tools/mojom/mojom_parser_test_case.py
@@ -0,0 +1,73 @@
+# Copyright 2020 The Chromium 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 json
+import os
+import os.path
+import shutil
+import tempfile
+import unittest
+
+import mojom_parser
+
+from mojom.generate import module
+
+
+class MojomParserTestCase(unittest.TestCase):
+ """Tests covering the behavior defined by the main mojom_parser.py script.
+ This includes behavior around input and output path manipulation, dependency
+ resolution, and module serialization and deserialization."""
+
+ def __init__(self, method_name):
+ super(MojomParserTestCase, self).__init__(method_name)
+ self._temp_dir = None
+
+ def setUp(self):
+ self._temp_dir = tempfile.mkdtemp()
+
+ def tearDown(self):
+ shutil.rmtree(self._temp_dir)
+ self._temp_dir = None
+
+ def GetPath(self, path):
+ assert not os.path.isabs(path)
+ return os.path.join(self._temp_dir, path)
+
+ def GetModulePath(self, path):
+ assert not os.path.isabs(path)
+ return os.path.join(self.GetPath('out'), path) + '-module'
+
+ def WriteFile(self, path, contents):
+ full_path = self.GetPath(path)
+ dirname = os.path.dirname(full_path)
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+ with open(full_path, 'w') as f:
+ f.write(contents)
+
+ def LoadModule(self, mojom_path):
+ with open(self.GetModulePath(mojom_path), 'rb') as f:
+ return module.Module.Load(f)
+
+ def ParseMojoms(self, mojoms, metadata=None):
+ """Parse all input mojoms relative the temp dir."""
+ out_dir = self.GetPath('out')
+ args = [
+ '--input-root', self._temp_dir, '--input-root', out_dir,
+ '--output-root', out_dir, '--mojoms'
+ ] + list(map(lambda mojom: os.path.join(self._temp_dir, mojom), mojoms))
+ if metadata:
+ args.extend(['--check-imports', self.GetPath(metadata)])
+ mojom_parser.Run(args)
+
+ def ExtractTypes(self, mojom):
+ filename = 'test.mojom'
+ self.WriteFile(filename, mojom)
+ self.ParseMojoms([filename])
+ m = self.LoadModule(filename)
+ definitions = {}
+ for kinds in (m.enums, m.structs, m.unions, m.interfaces):
+ for kind in kinds:
+ definitions[kind.mojom_name] = kind
+ return definitions
diff --git a/chromium/mojo/public/tools/mojom/mojom_parser_unittest.py b/chromium/mojo/public/tools/mojom/mojom_parser_unittest.py
index 9aa655dbed2..a93f34bacb4 100755..100644
--- a/chromium/mojo/public/tools/mojom/mojom_parser_unittest.py
+++ b/chromium/mojo/public/tools/mojom/mojom_parser_unittest.py
@@ -1,67 +1,15 @@
-#!/usr/bin/env python
# Copyright 2020 The Chromium 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 json
-import os
-import os.path
-import shutil
-import tempfile
-import unittest
+from mojom_parser_test_case import MojomParserTestCase
-import mojom_parser
-from mojom.generate import module
-
-
-class MojomParserTest(unittest.TestCase):
+class MojomParserTest(MojomParserTestCase):
"""Tests covering the behavior defined by the main mojom_parser.py script.
This includes behavior around input and output path manipulation, dependency
resolution, and module serialization and deserialization."""
- def __init__(self, method_name):
- super(MojomParserTest, self).__init__(method_name)
- self._temp_dir = None
-
- def setUp(self):
- self._temp_dir = tempfile.mkdtemp()
-
- def tearDown(self):
- shutil.rmtree(self._temp_dir)
- self._temp_dir = None
-
- def GetPath(self, path):
- assert not os.path.isabs(path)
- return os.path.join(self._temp_dir, path)
-
- def GetModulePath(self, path):
- assert not os.path.isabs(path)
- return os.path.join(self.GetPath('out'), path) + '-module'
-
- def WriteFile(self, path, contents):
- full_path = self.GetPath(path)
- dirname = os.path.dirname(full_path)
- if not os.path.exists(dirname):
- os.makedirs(dirname)
- with open(full_path, 'w') as f:
- f.write(contents)
-
- def LoadModule(self, mojom_path):
- with open(self.GetModulePath(mojom_path), 'rb') as f:
- return module.Module.Load(f)
-
- def ParseMojoms(self, mojoms, metadata=None):
- """Parse all input mojoms relative the temp dir."""
- out_dir = self.GetPath('out')
- args = [
- '--input-root', self._temp_dir, '--input-root', out_dir,
- '--output-root', out_dir, '--mojoms'
- ] + list(map(lambda mojom: os.path.join(self._temp_dir, mojom), mojoms))
- if metadata:
- args.extend(['--check-imports', self.GetPath(metadata)])
- mojom_parser.Run(args)
-
def testBasicParse(self):
"""Basic test to verify that we can parse a mojom file and get a module."""
mojom = 'foo/bar.mojom'
diff --git a/chromium/mojo/public/tools/mojom/stable_attribute_unittest.py b/chromium/mojo/public/tools/mojom/stable_attribute_unittest.py
new file mode 100644
index 00000000000..d45ec586299
--- /dev/null
+++ b/chromium/mojo/public/tools/mojom/stable_attribute_unittest.py
@@ -0,0 +1,127 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from mojom_parser_test_case import MojomParserTestCase
+
+from mojom.generate import module
+
+
+class StableAttributeTest(MojomParserTestCase):
+ """Tests covering usage of the [Stable] attribute."""
+
+ def testStableAttributeTagging(self):
+ """Verify that we recognize the [Stable] attribute on relevant definitions
+ and the resulting parser outputs are tagged accordingly."""
+ mojom = 'test.mojom'
+ self.WriteFile(
+ mojom, """\
+ [Stable] enum TestEnum { kFoo };
+ enum UnstableEnum { kBar };
+ [Stable] struct TestStruct { TestEnum a; };
+ struct UnstableStruct { UnstableEnum a; };
+ [Stable] union TestUnion { TestEnum a; TestStruct b; };
+ union UnstableUnion { UnstableEnum a; UnstableStruct b; };
+ [Stable] interface TestInterface { Foo@0(TestUnion x) => (); };
+ interface UnstableInterface { Foo(UnstableUnion x) => (); };
+ """)
+ self.ParseMojoms([mojom])
+
+ m = self.LoadModule(mojom)
+ self.assertEqual(2, len(m.enums))
+ self.assertTrue(m.enums[0].stable)
+ self.assertFalse(m.enums[1].stable)
+ self.assertEqual(2, len(m.structs))
+ self.assertTrue(m.structs[0].stable)
+ self.assertFalse(m.structs[1].stable)
+ self.assertEqual(2, len(m.unions))
+ self.assertTrue(m.unions[0].stable)
+ self.assertFalse(m.unions[1].stable)
+ self.assertEqual(2, len(m.interfaces))
+ self.assertTrue(m.interfaces[0].stable)
+ self.assertFalse(m.interfaces[1].stable)
+
+ def testStableStruct(self):
+ """A [Stable] struct is valid if all its fields are also stable."""
+ self.ExtractTypes('[Stable] struct S {};')
+ self.ExtractTypes('[Stable] struct S { int32 x; bool b; };')
+ self.ExtractTypes('[Stable] enum E { A }; [Stable] struct S { E e; };')
+ self.ExtractTypes('[Stable] struct S {}; [Stable] struct T { S s; };')
+ self.ExtractTypes(
+ '[Stable] struct S {}; [Stable] struct T { array<S> ss; };')
+ self.ExtractTypes(
+ '[Stable] interface F {}; [Stable] struct T { pending_remote<F> f; };')
+
+ with self.assertRaisesRegexp(Exception, 'because it depends on E'):
+ self.ExtractTypes('enum E { A }; [Stable] struct S { E e; };')
+ with self.assertRaisesRegexp(Exception, 'because it depends on X'):
+ self.ExtractTypes('struct X {}; [Stable] struct S { X x; };')
+ with self.assertRaisesRegexp(Exception, 'because it depends on T'):
+ self.ExtractTypes('struct T {}; [Stable] struct S { array<T> xs; };')
+ with self.assertRaisesRegexp(Exception, 'because it depends on T'):
+ self.ExtractTypes('struct T {}; [Stable] struct S { map<int32, T> xs; };')
+ with self.assertRaisesRegexp(Exception, 'because it depends on T'):
+ self.ExtractTypes('struct T {}; [Stable] struct S { map<T, int32> xs; };')
+ with self.assertRaisesRegexp(Exception, 'because it depends on F'):
+ self.ExtractTypes(
+ 'interface F {}; [Stable] struct S { pending_remote<F> f; };')
+ with self.assertRaisesRegexp(Exception, 'because it depends on F'):
+ self.ExtractTypes(
+ 'interface F {}; [Stable] struct S { pending_receiver<F> f; };')
+
+ def testStableUnion(self):
+ """A [Stable] union is valid if all its fields' types are also stable."""
+ self.ExtractTypes('[Stable] union U {};')
+ self.ExtractTypes('[Stable] union U { int32 x; bool b; };')
+ self.ExtractTypes('[Stable] enum E { A }; [Stable] union U { E e; };')
+ self.ExtractTypes('[Stable] struct S {}; [Stable] union U { S s; };')
+ self.ExtractTypes(
+ '[Stable] struct S {}; [Stable] union U { array<S> ss; };')
+ self.ExtractTypes(
+ '[Stable] interface F {}; [Stable] union U { pending_remote<F> f; };')
+
+ with self.assertRaisesRegexp(Exception, 'because it depends on E'):
+ self.ExtractTypes('enum E { A }; [Stable] union U { E e; };')
+ with self.assertRaisesRegexp(Exception, 'because it depends on X'):
+ self.ExtractTypes('struct X {}; [Stable] union U { X x; };')
+ with self.assertRaisesRegexp(Exception, 'because it depends on T'):
+ self.ExtractTypes('struct T {}; [Stable] union U { array<T> xs; };')
+ with self.assertRaisesRegexp(Exception, 'because it depends on T'):
+ self.ExtractTypes('struct T {}; [Stable] union U { map<int32, T> xs; };')
+ with self.assertRaisesRegexp(Exception, 'because it depends on T'):
+ self.ExtractTypes('struct T {}; [Stable] union U { map<T, int32> xs; };')
+ with self.assertRaisesRegexp(Exception, 'because it depends on F'):
+ self.ExtractTypes(
+ 'interface F {}; [Stable] union U { pending_remote<F> f; };')
+ with self.assertRaisesRegexp(Exception, 'because it depends on F'):
+ self.ExtractTypes(
+ 'interface F {}; [Stable] union U { pending_receiver<F> f; };')
+
+ def testStableInterface(self):
+ """A [Stable] interface is valid if all its methods' parameter types are
+ stable, including response parameters where applicable."""
+ self.ExtractTypes('[Stable] interface F {};')
+ self.ExtractTypes('[Stable] interface F { A@0(int32 x); };')
+ self.ExtractTypes('[Stable] interface F { A@0(int32 x) => (bool b); };')
+ self.ExtractTypes("""\
+ [Stable] enum E { A, B, C };
+ [Stable] struct S {};
+ [Stable] interface F { A@0(E e, S s) => (bool b, array<S> s); };
+ """)
+
+ with self.assertRaisesRegexp(Exception, 'because it depends on E'):
+ self.ExtractTypes(
+ 'enum E { A, B, C }; [Stable] interface F { A@0(E e); };')
+ with self.assertRaisesRegexp(Exception, 'because it depends on E'):
+ self.ExtractTypes(
+ 'enum E { A, B, C }; [Stable] interface F { A@0(int32 x) => (E e); };'
+ )
+ with self.assertRaisesRegexp(Exception, 'because it depends on S'):
+ self.ExtractTypes(
+ 'struct S {}; [Stable] interface F { A@0(int32 x) => (S s); };')
+ with self.assertRaisesRegexp(Exception, 'because it depends on S'):
+ self.ExtractTypes(
+ 'struct S {}; [Stable] interface F { A@0(S s) => (bool b); };')
+
+ with self.assertRaisesRegexp(Exception, 'explicit method ordinals'):
+ self.ExtractTypes('[Stable] interface F { A() => (); };')
diff --git a/chromium/mojo/public/tools/mojom/version_compatibility_unittest.py b/chromium/mojo/public/tools/mojom/version_compatibility_unittest.py
new file mode 100644
index 00000000000..a0ee150ec10
--- /dev/null
+++ b/chromium/mojo/public/tools/mojom/version_compatibility_unittest.py
@@ -0,0 +1,397 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from mojom_parser_test_case import MojomParserTestCase
+
+
+class VersionCompatibilityTest(MojomParserTestCase):
+ """Tests covering compatibility between two versions of the same mojom type
+ definition. This coverage ensures that we can reliably detect unsafe changes
+ to definitions that are expected to tolerate version skew in production
+ environments."""
+
+ def _GetTypeCompatibilityMap(self, old_mojom, new_mojom):
+ """Helper to support the implementation of assertBackwardCompatible and
+ assertNotBackwardCompatible."""
+
+ old = self.ExtractTypes(old_mojom)
+ new = self.ExtractTypes(new_mojom)
+ self.assertEqual(set(old.keys()), set(new.keys()),
+ 'Old and new test mojoms should use the same type names.')
+
+ compatibility_map = {}
+ for name in old.keys():
+ compatibility_map[name] = new[name].IsBackwardCompatible(old[name])
+ return compatibility_map
+
+ def assertBackwardCompatible(self, old_mojom, new_mojom):
+ compatibility_map = self._GetTypeCompatibilityMap(old_mojom, new_mojom)
+ for name, compatible in compatibility_map.items():
+ if not compatible:
+ raise AssertionError(
+ 'Given the old mojom:\n\n %s\n\nand the new mojom:\n\n %s\n\n'
+ 'The new definition of %s should pass a backward-compatibiity '
+ 'check, but it does not.' % (old_mojom, new_mojom, name))
+
+ def assertNotBackwardCompatible(self, old_mojom, new_mojom):
+ compatibility_map = self._GetTypeCompatibilityMap(old_mojom, new_mojom)
+ if all(compatibility_map.values()):
+ raise AssertionError(
+ 'Given the old mojom:\n\n %s\n\nand the new mojom:\n\n %s\n\n'
+ 'The new mojom should fail a backward-compatibility check, but it '
+ 'does not.' % (old_mojom, new_mojom))
+
+ def testNewNonExtensibleEnumValue(self):
+ """Adding a value to a non-extensible enum breaks backward-compatibility."""
+ self.assertNotBackwardCompatible('enum E { kFoo, kBar };',
+ 'enum E { kFoo, kBar, kBaz };')
+
+ def testNewNonExtensibleEnumValueWithMinVersion(self):
+ """Adding a value to a non-extensible enum breaks backward-compatibility,
+ even with a new [MinVersion] specified for the value."""
+ self.assertNotBackwardCompatible(
+ 'enum E { kFoo, kBar };', 'enum E { kFoo, kBar, [MinVersion=1] kBaz };')
+
+ def testNewValueInExistingVersion(self):
+ """Adding a value to an existing version is not allowed, even if the old
+ enum was marked [Extensible]. Note that it is irrelevant whether or not the
+ new enum is marked [Extensible]."""
+ self.assertNotBackwardCompatible('[Extensible] enum E { kFoo, kBar };',
+ 'enum E { kFoo, kBar, kBaz };')
+ self.assertNotBackwardCompatible(
+ '[Extensible] enum E { kFoo, kBar };',
+ '[Extensible] enum E { kFoo, kBar, kBaz };')
+ self.assertNotBackwardCompatible(
+ '[Extensible] enum E { kFoo, [MinVersion=1] kBar };',
+ 'enum E { kFoo, [MinVersion=1] kBar, [MinVersion=1] kBaz };')
+
+ def testEnumValueRemoval(self):
+ """Removal of an enum value is never valid even for [Extensible] enums."""
+ self.assertNotBackwardCompatible('enum E { kFoo, kBar };',
+ 'enum E { kFoo };')
+ self.assertNotBackwardCompatible('[Extensible] enum E { kFoo, kBar };',
+ '[Extensible] enum E { kFoo };')
+ self.assertNotBackwardCompatible(
+ '[Extensible] enum E { kA, [MinVersion=1] kB };',
+ '[Extensible] enum E { kA, };')
+ self.assertNotBackwardCompatible(
+ '[Extensible] enum E { kA, [MinVersion=1] kB, [MinVersion=1] kZ };',
+ '[Extensible] enum E { kA, [MinVersion=1] kB };')
+
+ def testNewExtensibleEnumValueWithMinVersion(self):
+ """Adding a new and properly [MinVersion]'d value to an [Extensible] enum
+ is a backward-compatible change. Note that it is irrelevant whether or not
+ the new enum is marked [Extensible]."""
+ self.assertBackwardCompatible('[Extensible] enum E { kA, kB };',
+ 'enum E { kA, kB, [MinVersion=1] kC };')
+ self.assertBackwardCompatible(
+ '[Extensible] enum E { kA, kB };',
+ '[Extensible] enum E { kA, kB, [MinVersion=1] kC };')
+ self.assertBackwardCompatible(
+ '[Extensible] enum E { kA, [MinVersion=1] kB };',
+ '[Extensible] enum E { kA, [MinVersion=1] kB, [MinVersion=2] kC };')
+
+ def testRenameEnumValue(self):
+ """Renaming an enum value does not affect backward-compatibility. Only
+ numeric value is relevant."""
+ self.assertBackwardCompatible('enum E { kA, kB };', 'enum E { kX, kY };')
+
+ def testAddEnumValueAlias(self):
+ """Adding new enum fields does not affect backward-compatibility if it does
+ not introduce any new numeric values."""
+ self.assertBackwardCompatible(
+ 'enum E { kA, kB };', 'enum E { kA, kB, kC = kA, kD = 1, kE = kD };')
+
+ def testEnumIdentity(self):
+ """An unchanged enum is obviously backward-compatible."""
+ self.assertBackwardCompatible('enum E { kA, kB, kC };',
+ 'enum E { kA, kB, kC };')
+
+ def testNewStructFieldUnversioned(self):
+ """Adding a new field to a struct without a new (i.e. higher than any
+ existing version) [MinVersion] tag breaks backward-compatibility."""
+ self.assertNotBackwardCompatible('struct S { string a; };',
+ 'struct S { string a; string b; };')
+
+ def testStructFieldRemoval(self):
+ """Removing a field from a struct breaks backward-compatibility."""
+ self.assertNotBackwardCompatible('struct S { string a; string b; };',
+ 'struct S { string a; };')
+
+ def testStructFieldTypeChange(self):
+ """Changing the type of an existing field always breaks
+ backward-compatibility."""
+ self.assertNotBackwardCompatible('struct S { string a; };',
+ 'struct S { array<int32> a; };')
+
+ def testStructFieldBecomingOptional(self):
+ """Changing a field from non-optional to optional breaks
+ backward-compatibility."""
+ self.assertNotBackwardCompatible('struct S { string a; };',
+ 'struct S { string? a; };')
+
+ def testStructFieldBecomingNonOptional(self):
+ """Changing a field from optional to non-optional breaks
+ backward-compatibility."""
+ self.assertNotBackwardCompatible('struct S { string? a; };',
+ 'struct S { string a; };')
+
+ def testStructFieldOrderChange(self):
+ """Changing the order of fields breaks backward-compatibility."""
+ self.assertNotBackwardCompatible('struct S { string a; bool b; };',
+ 'struct S { bool b; string a; };')
+ self.assertNotBackwardCompatible('struct S { string a@0; bool b@1; };',
+ 'struct S { string a@1; bool b@0; };')
+
+ def testStructFieldMinVersionChange(self):
+ """Changing the MinVersion of a field breaks backward-compatibility."""
+ self.assertNotBackwardCompatible(
+ 'struct S { string a; [MinVersion=1] string? b; };',
+ 'struct S { string a; [MinVersion=2] string? b; };')
+
+ def testStructFieldTypeChange(self):
+ """If a struct field's own type definition changes, the containing struct
+ is backward-compatible if and only if the field type's change is
+ backward-compatible."""
+ self.assertBackwardCompatible(
+ 'struct S {}; struct T { S s; };',
+ 'struct S { [MinVersion=1] int32 x; }; struct T { S s; };')
+ self.assertBackwardCompatible(
+ '[Extensible] enum E { kA }; struct S { E e; };',
+ '[Extensible] enum E { kA, [MinVersion=1] kB }; struct S { E e; };')
+ self.assertNotBackwardCompatible(
+ 'struct S {}; struct T { S s; };',
+ 'struct S { int32 x; }; struct T { S s; };')
+ self.assertNotBackwardCompatible(
+ '[Extensible] enum E { kA }; struct S { E e; };',
+ '[Extensible] enum E { kA, kB }; struct S { E e; };')
+
+ def testNewStructFieldWithInvalidMinVersion(self):
+ """Adding a new field using an existing MinVersion breaks backward-
+ compatibility."""
+ self.assertNotBackwardCompatible(
+ """\
+ struct S {
+ string a;
+ [MinVersion=1] string? b;
+ };
+ """, """\
+ struct S {
+ string a;
+ [MinVersion=1] string? b;
+ [MinVersion=1] string? c;
+ };""")
+
+ def testNewStructFieldWithValidMinVersion(self):
+ """Adding a new field is safe if tagged with a MinVersion greater than any
+ previously used MinVersion in the struct."""
+ self.assertBackwardCompatible(
+ 'struct S { int32 a; };',
+ 'struct S { int32 a; [MinVersion=1] int32 b; };')
+ self.assertBackwardCompatible(
+ 'struct S { int32 a; [MinVersion=1] int32 b; };',
+ 'struct S { int32 a; [MinVersion=1] int32 b; [MinVersion=2] bool c; };')
+
+ def testNewStructFieldNullableReference(self):
+ """Adding a new nullable reference-typed field is fine if versioned
+ properly."""
+ self.assertBackwardCompatible(
+ 'struct S { int32 a; };',
+ 'struct S { int32 a; [MinVersion=1] string? b; };')
+
+ def testStructFieldRename(self):
+ """Renaming a field has no effect on backward-compatibility."""
+ self.assertBackwardCompatible('struct S { int32 x; bool b; };',
+ 'struct S { int32 a; bool b; };')
+
+ def testStructFieldReorderWithExplicitOrdinals(self):
+ """Reordering fields has no effect on backward-compatibility when field
+ ordinals are explicitly labeled and remain unchanged."""
+ self.assertBackwardCompatible('struct S { bool b@1; int32 a@0; };',
+ 'struct S { int32 a@0; bool b@1; };')
+
+ def testNewUnionFieldUnversioned(self):
+ """Adding a new field to a union without a new (i.e. higher than any
+ existing version) [MinVersion] tag breaks backward-compatibility."""
+ self.assertNotBackwardCompatible('union U { string a; };',
+ 'union U { string a; string b; };')
+
+ def testUnionFieldRemoval(self):
+ """Removing a field from a union breaks backward-compatibility."""
+ self.assertNotBackwardCompatible('union U { string a; string b; };',
+ 'union U { string a; };')
+
+ def testUnionFieldTypeChange(self):
+ """Changing the type of an existing field always breaks
+ backward-compatibility."""
+ self.assertNotBackwardCompatible('union U { string a; };',
+ 'union U { array<int32> a; };')
+
+ def testUnionFieldBecomingOptional(self):
+ """Changing a field from non-optional to optional breaks
+ backward-compatibility."""
+ self.assertNotBackwardCompatible('union U { string a; };',
+ 'union U { string? a; };')
+
+ def testUnionFieldBecomingNonOptional(self):
+ """Changing a field from optional to non-optional breaks
+ backward-compatibility."""
+ self.assertNotBackwardCompatible('union U { string? a; };',
+ 'union U { string a; };')
+
+ def testUnionFieldOrderChange(self):
+ """Changing the order of fields breaks backward-compatibility."""
+ self.assertNotBackwardCompatible('union U { string a; bool b; };',
+ 'union U { bool b; string a; };')
+ self.assertNotBackwardCompatible('union U { string a@0; bool b@1; };',
+ 'union U { string a@1; bool b@0; };')
+
+ def testUnionFieldMinVersionChange(self):
+ """Changing the MinVersion of a field breaks backward-compatibility."""
+ self.assertNotBackwardCompatible(
+ 'union U { string a; [MinVersion=1] string b; };',
+ 'union U { string a; [MinVersion=2] string b; };')
+
+ def testUnionFieldTypeChange(self):
+ """If a union field's own type definition changes, the containing union
+ is backward-compatible if and only if the field type's change is
+ backward-compatible."""
+ self.assertBackwardCompatible(
+ 'struct S {}; union U { S s; };',
+ 'struct S { [MinVersion=1] int32 x; }; union U { S s; };')
+ self.assertBackwardCompatible(
+ '[Extensible] enum E { kA }; union U { E e; };',
+ '[Extensible] enum E { kA, [MinVersion=1] kB }; union U { E e; };')
+ self.assertNotBackwardCompatible(
+ 'struct S {}; union U { S s; };',
+ 'struct S { int32 x; }; union U { S s; };')
+ self.assertNotBackwardCompatible(
+ '[Extensible] enum E { kA }; union U { E e; };',
+ '[Extensible] enum E { kA, kB }; union U { E e; };')
+
+ def testNewUnionFieldWithInvalidMinVersion(self):
+ """Adding a new field using an existing MinVersion breaks backward-
+ compatibility."""
+ self.assertNotBackwardCompatible(
+ """\
+ union U {
+ string a;
+ [MinVersion=1] string b;
+ };
+ """, """\
+ union U {
+ string a;
+ [MinVersion=1] string b;
+ [MinVersion=1] string c;
+ };""")
+
+ def testNewUnionFieldWithValidMinVersion(self):
+ """Adding a new field is safe if tagged with a MinVersion greater than any
+ previously used MinVersion in the union."""
+ self.assertBackwardCompatible(
+ 'union U { int32 a; };',
+ 'union U { int32 a; [MinVersion=1] int32 b; };')
+ self.assertBackwardCompatible(
+ 'union U { int32 a; [MinVersion=1] int32 b; };',
+ 'union U { int32 a; [MinVersion=1] int32 b; [MinVersion=2] bool c; };')
+
+ def testUnionFieldRename(self):
+ """Renaming a field has no effect on backward-compatibility."""
+ self.assertBackwardCompatible('union U { int32 x; bool b; };',
+ 'union U { int32 a; bool b; };')
+
+ def testUnionFieldReorderWithExplicitOrdinals(self):
+ """Reordering fields has no effect on backward-compatibility when field
+ ordinals are explicitly labeled and remain unchanged."""
+ self.assertBackwardCompatible('union U { bool b@1; int32 a@0; };',
+ 'union U { int32 a@0; bool b@1; };')
+
+ def testNewInterfaceMethodUnversioned(self):
+ """Adding a new method to an interface without a new (i.e. higher than any
+ existing version) [MinVersion] tag breaks backward-compatibility."""
+ self.assertNotBackwardCompatible('interface F { A(); };',
+ 'interface F { A(); B(); };')
+
+ def testInterfaceMethodRemoval(self):
+ """Removing a method from an interface breaks backward-compatibility."""
+ self.assertNotBackwardCompatible('interface F { A(); B(); };',
+ 'interface F { A(); };')
+
+ def testInterfaceMethodParamsChanged(self):
+ """Changes to the parameter list are only backward-compatible if they meet
+ backward-compatibility requirements of an equivalent struct definition."""
+ self.assertNotBackwardCompatible('interface F { A(); };',
+ 'interface F { A(int32 x); };')
+ self.assertNotBackwardCompatible('interface F { A(int32 x); };',
+ 'interface F { A(bool x); };')
+ self.assertNotBackwardCompatible(
+ 'interface F { A(int32 x, [MinVersion=1] string? s); };', """\
+ interface F {
+ A(int32 x, [MinVersion=1] string? s, [MinVersion=1] int32 y);
+ };""")
+
+ self.assertBackwardCompatible('interface F { A(int32 x); };',
+ 'interface F { A(int32 a); };')
+ self.assertBackwardCompatible(
+ 'interface F { A(int32 x); };',
+ 'interface F { A(int32 x, [MinVersion=1] string? s); };')
+
+ self.assertBackwardCompatible(
+ 'struct S {}; interface F { A(S s); };',
+ 'struct S { [MinVersion=1] int32 x; }; interface F { A(S s); };')
+ self.assertBackwardCompatible(
+ 'struct S {}; struct T {}; interface F { A(S s); };',
+ 'struct S {}; struct T {}; interface F { A(T s); };')
+ self.assertNotBackwardCompatible(
+ 'struct S {}; struct T { int32 x; }; interface F { A(S s); };',
+ 'struct S {}; struct T { int32 x; }; interface F { A(T t); };')
+
+ def testInterfaceMethodReplyAdded(self):
+ """Adding a reply to a message breaks backward-compatibilty."""
+ self.assertNotBackwardCompatible('interface F { A(); };',
+ 'interface F { A() => (); };')
+
+ def testInterfaceMethodReplyRemoved(self):
+ """Removing a reply from a message breaks backward-compatibility."""
+ self.assertNotBackwardCompatible('interface F { A() => (); };',
+ 'interface F { A(); };')
+
+ def testInterfaceMethodReplyParamsChanged(self):
+ """Similar to request parameters, a change to reply parameters is considered
+ backward-compatible if it meets the same backward-compatibility
+ requirements imposed on equivalent struct changes."""
+ self.assertNotBackwardCompatible('interface F { A() => (); };',
+ 'interface F { A() => (int32 x); };')
+ self.assertNotBackwardCompatible('interface F { A() => (int32 x); };',
+ 'interface F { A() => (); };')
+ self.assertNotBackwardCompatible('interface F { A() => (bool x); };',
+ 'interface F { A() => (int32 x); };')
+
+ self.assertBackwardCompatible('interface F { A() => (int32 a); };',
+ 'interface F { A() => (int32 x); };')
+ self.assertBackwardCompatible(
+ 'interface F { A() => (int32 x); };',
+ 'interface F { A() => (int32 x, [MinVersion] string? s); };')
+
+ def testNewInterfaceMethodWithInvalidMinVersion(self):
+ """Adding a new method to an existing version is not backward-compatible."""
+ self.assertNotBackwardCompatible(
+ """\
+ interface F {
+ A();
+ [MinVersion=1] B();
+ };
+ """, """\
+ interface F {
+ A();
+ [MinVersion=1] B();
+ [MinVersion=1] C();
+ };
+ """)
+
+ def testNewInterfaceMethodWithValidMinVersion(self):
+ """Adding a new method is fine as long as its MinVersion exceeds that of any
+ method on the old interface definition."""
+ self.assertBackwardCompatible('interface F { A(); };',
+ 'interface F { A(); [MinVersion=1] B(); };')