aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHidehiko Abe <hidehiko@google.com>2017-12-13 19:00:02 +0900
committerHidehiko Abe <hidehiko@google.com>2017-12-13 23:42:13 +0900
commit0411add1e14cc2dc041f5f1776f05a8c4b787d73 (patch)
tree19a081baf4afcba8d442b5e839cb1ff247f31b7f
parentc96e5aa6f5f1f6df03ef539b4b85c78bf7c292e5 (diff)
downloadlibmojo-0411add1e14cc2dc041f5f1776f05a8c4b787d73.tar.gz
Revert "Revert "libmojo: Uprev the library to r456626 from Chromium""
This reverts commit 21a249e4d9cb0b2ec6f0ff84ed5f7939ea67ac52. Test: Build. Change-Id: Id31199817067e933eb08889b21b83c787b0d4c0d Merged-In: I2f77e0bb4541d6520dac974cd499b30561c6658f
-rw-r--r--Android.mk27
-rw-r--r--Makefile181
-rw-r--r--base/android/animation_frame_time_histogram.cc2
-rw-r--r--base/android/apk_assets.cc29
-rw-r--r--base/android/apk_assets.h13
-rw-r--r--base/android/base_jni_onload.cc33
-rw-r--r--base/android/base_jni_onload.h15
-rw-r--r--base/android/base_jni_registrar.cc31
-rw-r--r--base/android/build_info.cc7
-rw-r--r--base/android/build_info.h5
-rw-r--r--base/android/command_line_android.cc2
-rw-r--r--base/android/content_uri_utils.cc14
-rw-r--r--base/android/content_uri_utils.h2
-rw-r--r--base/android/context_utils.cc4
-rw-r--r--base/android/context_utils.h2
-rw-r--r--base/android/event_log.cc4
-rw-r--r--base/android/event_log.h2
-rw-r--r--base/android/field_trial_list.cc2
-rw-r--r--base/android/fifo_utils.cc25
-rw-r--r--base/android/fifo_utils.h31
-rw-r--r--base/android/java/src/org/chromium/base/ActivityState.java10
-rw-r--r--base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java107
-rw-r--r--base/android/java/src/org/chromium/base/ApplicationStatus.java46
-rw-r--r--base/android/java/src/org/chromium/base/BaseChromiumApplication.java32
-rw-r--r--base/android/java/src/org/chromium/base/BuildInfo.java27
-rw-r--r--base/android/java/src/org/chromium/base/CommandLine.java15
-rw-r--r--base/android/java/src/org/chromium/base/CommandLineInitUtil.java14
-rw-r--r--base/android/java/src/org/chromium/base/ContentUriUtils.java143
-rw-r--r--base/android/java/src/org/chromium/base/ContextUtils.java2
-rw-r--r--base/android/java/src/org/chromium/base/FileUtils.java13
-rw-r--r--base/android/java/src/org/chromium/base/JNIUtils.java22
-rw-r--r--base/android/java/src/org/chromium/base/LocaleUtils.java188
-rw-r--r--base/android/java/src/org/chromium/base/Log.java5
-rw-r--r--base/android/java/src/org/chromium/base/ObserverList.java12
-rw-r--r--base/android/java/src/org/chromium/base/PathUtils.java42
-rw-r--r--base/android/java/src/org/chromium/base/PerfTraceEvent.java10
-rw-r--r--base/android/java/src/org/chromium/base/PowerMonitor.java83
-rw-r--r--base/android/java/src/org/chromium/base/PowerStatusReceiver.java23
-rw-r--r--base/android/java/src/org/chromium/base/ResourceExtractor.java124
-rw-r--r--base/android/java/src/org/chromium/base/SecureRandomInitializer.java19
-rw-r--r--base/android/java/src/org/chromium/base/SysUtils.java21
-rw-r--r--base/android/java/src/org/chromium/base/SystemMessageHandler.java14
-rw-r--r--base/android/java/src/org/chromium/base/ThreadUtils.java9
-rw-r--r--base/android/java/src/org/chromium/base/TraceEvent.java54
-rw-r--r--base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java113
-rw-r--r--base/android/java/src/org/chromium/base/library_loader/Linker.java14
-rw-r--r--base/android/java/src/org/chromium/base/library_loader/ModernLinker.java4
-rw-r--r--base/android/java/src/org/chromium/base/metrics/RecordHistogram.java46
-rw-r--r--base/android/java_handler_thread.cc22
-rw-r--r--base/android/java_handler_thread.h8
-rw-r--r--base/android/java_message_handler_factory.h33
-rw-r--r--base/android/java_runtime.cc8
-rw-r--r--base/android/java_runtime.h3
-rw-r--r--base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java29
-rw-r--r--base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java69
-rw-r--r--base/android/javatests/src/org/chromium/base/CommandLineTest.java69
-rw-r--r--base/android/javatests/src/org/chromium/base/ObserverListTest.java186
-rw-r--r--base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java161
-rw-r--r--base/android/jni_android.cc48
-rw-r--r--base/android/jni_android.h74
-rw-r--r--base/android/jni_generator/golden_sample_for_tests_jni.h481
-rw-r--r--base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java14
-rw-r--r--base/android/jni_generator/jni_generator.gyp72
-rwxr-xr-xbase/android/jni_generator/jni_generator.py158
-rw-r--r--base/android/jni_generator/jni_generator_helper.h50
-rwxr-xr-xbase/android/jni_generator/jni_generator_tests.py65
-rw-r--r--base/android/jni_generator/sample_for_tests.cc18
-rw-r--r--base/android/jni_generator/testCalledByNatives.golden283
-rw-r--r--base/android/jni_generator/testConstantsFromJavaP.golden1167
-rw-r--r--base/android/jni_generator/testFromJavaP.golden144
-rw-r--r--base/android/jni_generator/testFromJavaPGenerics.golden25
-rw-r--r--base/android/jni_generator/testInnerClassNatives.golden22
-rw-r--r--base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden30
-rw-r--r--base/android/jni_generator/testInnerClassNativesMultiple.golden35
-rw-r--r--base/android/jni_generator/testMultipleJNIAdditionalImport.golden36
-rw-r--r--base/android/jni_generator/testNativeExportsOption.golden203
-rw-r--r--base/android/jni_generator/testNativeExportsOptionalOption.golden272
-rw-r--r--base/android/jni_generator/testNatives.golden181
-rw-r--r--base/android/jni_generator/testNativesLong.golden14
-rw-r--r--base/android/jni_generator/testSingleJNIAdditionalImport.golden30
-rw-r--r--base/android/jni_utils.cc5
-rw-r--r--base/android/jni_utils.h3
-rw-r--r--base/android/jni_weak_ref.cc30
-rw-r--r--base/android/jni_weak_ref.h10
-rw-r--r--base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java11
-rw-r--r--base/android/library_loader/library_loader_hooks.cc11
-rw-r--r--base/android/library_loader/library_loader_hooks.h6
-rw-r--r--base/android/library_loader/library_prefetcher.cc8
-rw-r--r--base/android/linker/BUILD.gn1
-rw-r--r--base/android/linker/config.gni3
-rw-r--r--base/android/locale_utils.cc10
-rw-r--r--base/android/locale_utils.h6
-rw-r--r--base/android/memory_pressure_listener_android.cc2
-rw-r--r--base/android/path_utils.cc20
-rw-r--r--base/android/path_utils.h2
-rw-r--r--base/android/record_histogram.cc12
-rw-r--r--base/android/scoped_java_ref.cc8
-rw-r--r--base/android/scoped_java_ref.h99
-rw-r--r--base/android/scoped_java_ref_unittest.cc11
-rw-r--r--base/android/sys_utils.cc6
-rw-r--r--base/android/sys_utils.h2
-rw-r--r--base/android/thread_utils.h16
-rw-r--r--base/debug/stack_trace_android.cc8
-rw-r--r--base/i18n/base_i18n_export.h29
-rw-r--r--base/i18n/rtl.h155
-rw-r--r--base/message_loop/message_pump_android.cc56
-rw-r--r--base/message_loop/message_pump_android.h18
-rw-r--r--base/path_service.cc6
-rw-r--r--base/threading/thread_local_android.cc31
-rw-r--r--base/trace_event/trace_event_android.cc1
-rw-r--r--base/unguessable_token.cc41
-rw-r--r--base/unguessable_token.h103
-rw-r--r--build/android/gyp/util/build_utils.py136
-rw-r--r--build/android/pylib/__init__.py24
-rw-r--r--build/android/pylib/constants/__init__.py16
-rw-r--r--build/build_config.h36
-rw-r--r--build/gn_helpers.py351
-rw-r--r--build_mojom.mk28
-rw-r--r--common.mk934
-rw-r--r--gen/mojo/common/common_custom_types__type_mappings198
-rw-r--r--ipc/attachment_broker.h176
-rw-r--r--ipc/brokerable_attachment.cc72
-rw-r--r--ipc/brokerable_attachment.h91
-rw-r--r--ipc/ipc.mojom40
-rw-r--r--ipc/ipc_channel_handle.h59
-rw-r--r--ipc/ipc_listener.h9
-rw-r--r--ipc/ipc_message.cc104
-rw-r--r--ipc/ipc_message.h41
-rw-r--r--ipc/ipc_message_attachment.h11
-rw-r--r--ipc/ipc_message_attachment_set.cc148
-rw-r--r--ipc/ipc_message_attachment_set.h97
-rw-r--r--ipc/ipc_message_start.h5
-rw-r--r--ipc/ipc_message_utils.cc188
-rw-r--r--ipc/ipc_message_utils.h64
-rw-r--r--ipc/ipc_mojo_handle_attachment.cc9
-rw-r--r--ipc/ipc_mojo_handle_attachment.h5
-rw-r--r--ipc/ipc_mojo_message_helper.cc2
-rw-r--r--ipc/ipc_platform_file_attachment_posix.cc4
-rw-r--r--ipc/ipc_platform_file_attachment_posix.h2
-rw-r--r--ipc/placeholder_brokerable_attachment.cc14
-rw-r--r--ipc/placeholder_brokerable_attachment.h29
-rw-r--r--libmojo.pc.in13
-rw-r--r--mojo/BUILD.gn14
-rw-r--r--mojo/DEPS2
-rw-r--r--mojo/android/BUILD.gn26
-rw-r--r--mojo/android/javatests/init_library.cc30
-rw-r--r--mojo/android/javatests/mojo_test_case.cc5
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java7
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsHelperTest.java6
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsTest.java31
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsVersioningTest.java2
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/bindings/CallbacksTest.java2
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/bindings/ConnectorTest.java2
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/bindings/ExecutorFactoryTest.java2
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/bindings/InterfaceControlMessageTest.java2
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/bindings/InterfacesTest.java2
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/bindings/MessageHeaderTest.java2
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/bindings/ReadAndDispatchMessageTest.java2
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/bindings/RouterTest.java2
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/bindings/SerializationTest.java46
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTest.java9
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTestUtilTest.java2
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java265
-rw-r--r--mojo/android/javatests/validation_test_util.cc9
-rw-r--r--mojo/android/system/base_run_loop.cc29
-rw-r--r--mojo/android/system/core_impl.cc87
-rw-r--r--mojo/android/system/src/org/chromium/mojo/system/impl/BaseRunLoop.java8
-rw-r--r--mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java77
-rw-r--r--mojo/android/system/src/org/chromium/mojo/system/impl/WatcherImpl.java63
-rw-r--r--mojo/android/system/watcher_impl.cc109
-rw-r--r--mojo/android/system/watcher_impl.h20
-rw-r--r--mojo/common/BUILD.gn37
-rw-r--r--mojo/common/DEPS10
-rw-r--r--mojo/common/common_custom_types.typemap24
-rw-r--r--mojo/common/common_custom_types_struct_traits.cc102
-rw-r--r--mojo/common/common_custom_types_struct_traits.h94
-rw-r--r--mojo/common/common_custom_types_unittest.cc315
-rw-r--r--mojo/common/common_type_converters.cc84
-rw-r--r--mojo/common/common_type_converters.h66
-rw-r--r--mojo/common/common_type_converters_unittest.cc130
-rw-r--r--mojo/common/data_pipe_drainer.cc5
-rw-r--r--mojo/common/data_pipe_file_utils.cc81
-rw-r--r--mojo/common/data_pipe_utils.cc36
-rw-r--r--mojo/common/data_pipe_utils.h36
-rw-r--r--mojo/common/file.mojom (renamed from mojo/common/common_custom_types.mojom)12
-rw-r--r--mojo/common/file.typemap13
-rw-r--r--mojo/common/string16.mojom1
-rw-r--r--mojo/common/string16.typemap12
-rw-r--r--mojo/common/test_common_custom_types.mojom36
-rw-r--r--mojo/common/text_direction.mojom12
-rw-r--r--mojo/common/text_direction.typemap12
-rw-r--r--mojo/common/time.mojom14
-rw-r--r--mojo/common/time.typemap7
-rw-r--r--mojo/common/unguessable_token.mojom11
-rw-r--r--mojo/common/unguessable_token.typemap12
-rw-r--r--mojo/common/user_agent.cc25
-rw-r--r--mojo/common/user_agent.h20
-rw-r--r--mojo/common/version.mojom10
-rw-r--r--mojo/common/version.typemap12
-rw-r--r--mojo/converters/blink/BUILD.gn44
-rw-r--r--mojo/converters/blink/DEPS5
-rw-r--r--mojo/converters/blink/blink_input_events_type_converters.cc246
-rw-r--r--mojo/converters/blink/blink_input_events_type_converters.h31
-rw-r--r--mojo/converters/blink/mojo_blink_export.h32
-rw-r--r--mojo/edk/embedder/BUILD.gn34
-rw-r--r--mojo/edk/embedder/README.md340
-rw-r--r--mojo/edk/embedder/connection_params.cc28
-rw-r--r--mojo/edk/embedder/connection_params.h34
-rw-r--r--mojo/edk/embedder/embedder.cc68
-rw-r--r--mojo/edk/embedder/embedder.h97
-rw-r--r--mojo/edk/embedder/embedder_unittest.cc138
-rw-r--r--mojo/edk/embedder/named_platform_channel_pair.h73
-rw-r--r--mojo/edk/embedder/named_platform_handle.h51
-rw-r--r--mojo/edk/embedder/pending_process_connection.cc50
-rw-r--r--mojo/edk/embedder/pending_process_connection.h124
-rw-r--r--mojo/edk/embedder/platform_channel_pair.h1
-rw-r--r--mojo/edk/embedder/platform_channel_pair_posix.cc27
-rw-r--r--mojo/edk/embedder/platform_channel_pair_posix_unittest.cc4
-rw-r--r--mojo/edk/embedder/platform_channel_utils_posix.cc85
-rw-r--r--mojo/edk/embedder/platform_channel_utils_posix.h11
-rw-r--r--mojo/edk/embedder/platform_handle.h3
-rw-r--r--mojo/edk/embedder/platform_handle_utils_posix.cc4
-rw-r--r--mojo/edk/embedder/platform_shared_buffer.cc21
-rw-r--r--mojo/edk/embedder/process_delegate.h31
-rw-r--r--mojo/edk/js/test/BUILD.gn46
-rw-r--r--mojo/edk/js/test/hexdump.js34
-rw-r--r--mojo/edk/js/test/run_js_integration_tests.cc59
-rw-r--r--mojo/edk/js/test/run_js_tests.cc68
-rw-r--r--mojo/edk/js/tests/BUILD.gn44
-rw-r--r--mojo/edk/js/tests/connection_tests.js157
-rw-r--r--mojo/edk/js/tests/js_to_cpp_tests.cc55
-rw-r--r--mojo/edk/js/tests/js_to_cpp_tests.js11
-rw-r--r--mojo/edk/js/tests/sample_service_tests.js176
-rw-r--r--mojo/edk/system/BUILD.gn8
-rw-r--r--mojo/edk/system/broker_host.cc (renamed from mojo/edk/system/broker_host_posix.cc)104
-rw-r--r--mojo/edk/system/broker_host.h22
-rw-r--r--mojo/edk/system/broker_messages.h25
-rw-r--r--mojo/edk/system/broker_posix.cc4
-rw-r--r--mojo/edk/system/channel.cc340
-rw-r--r--mojo/edk/system/channel.h105
-rw-r--r--mojo/edk/system/channel_posix.cc82
-rw-r--r--mojo/edk/system/channel_win.cc10
-rw-r--r--mojo/edk/system/core.cc54
-rw-r--r--mojo/edk/system/core.h23
-rw-r--r--mojo/edk/system/core_unittest.cc35
-rw-r--r--mojo/edk/system/data_pipe_consumer_dispatcher.cc27
-rw-r--r--mojo/edk/system/data_pipe_consumer_dispatcher.h4
-rw-r--r--mojo/edk/system/data_pipe_control_message.h1
-rw-r--r--mojo/edk/system/data_pipe_producer_dispatcher.cc10
-rw-r--r--mojo/edk/system/data_pipe_unittest.cc315
-rw-r--r--mojo/edk/system/handle_table.cc7
-rw-r--r--mojo/edk/system/message_pipe_dispatcher.cc163
-rw-r--r--mojo/edk/system/message_pipe_dispatcher.h1
-rw-r--r--mojo/edk/system/message_pipe_unittest.cc11
-rw-r--r--mojo/edk/system/multiprocess_message_pipe_unittest.cc157
-rw-r--r--mojo/edk/system/node_channel.cc47
-rw-r--r--mojo/edk/system/node_channel.h13
-rw-r--r--mojo/edk/system/node_controller.cc305
-rw-r--r--mojo/edk/system/node_controller.h65
-rw-r--r--mojo/edk/system/platform_handle_dispatcher_unittest.cc4
-rw-r--r--mojo/edk/system/ports/BUILD.gn1
-rw-r--r--mojo/edk/system/ports/message_filter.h29
-rw-r--r--mojo/edk/system/ports/message_queue.cc8
-rw-r--r--mojo/edk/system/ports/message_queue.h8
-rw-r--r--mojo/edk/system/ports/name.cc4
-rw-r--r--mojo/edk/system/ports/name.h4
-rw-r--r--mojo/edk/system/ports/node.cc63
-rw-r--r--mojo/edk/system/ports/node.h38
-rw-r--r--mojo/edk/system/ports/port_ref.cc5
-rw-r--r--mojo/edk/system/ports/port_ref.h2
-rw-r--r--mojo/edk/system/ports/ports_unittest.cc1669
-rw-r--r--mojo/edk/system/request_context.cc7
-rw-r--r--mojo/edk/system/shared_buffer_dispatcher.h1
-rw-r--r--mojo/edk/test/BUILD.gn2
-rw-r--r--mojo/edk/test/mojo_test_base.cc13
-rw-r--r--mojo/edk/test/mojo_test_base.h10
-rw-r--r--mojo/edk/test/multiprocess_test_helper.cc138
-rw-r--r--mojo/edk/test/multiprocess_test_helper.h30
-rw-r--r--mojo/edk/test/run_all_perftests.cc13
-rw-r--r--mojo/edk/test/run_all_unittests.cc13
-rw-r--r--mojo/edk/test/scoped_ipc_support.cc62
-rw-r--r--mojo/edk/test/scoped_ipc_support.h65
-rw-r--r--mojo/gpu/BUILD.gn18
-rw-r--r--mojo/gpu/DEPS4
-rw-r--r--mojo/gpu/mojo_gles2_impl_autogen.cc1899
-rw-r--r--mojo/gpu/mojo_gles2_impl_autogen.h890
-rw-r--r--mojo/message_pump/BUILD.gn24
-rw-r--r--mojo/message_pump/handle_watcher.cc480
-rw-r--r--mojo/message_pump/handle_watcher.h65
-rw-r--r--mojo/message_pump/handle_watcher_perftest.cc207
-rw-r--r--mojo/message_pump/handle_watcher_unittest.cc493
-rw-r--r--mojo/message_pump/message_pump_mojo.cc448
-rw-r--r--mojo/message_pump/message_pump_mojo.h178
-rw-r--r--mojo/message_pump/message_pump_mojo_handler.h29
-rw-r--r--mojo/message_pump/message_pump_mojo_unittest.cc193
-rw-r--r--mojo/message_pump/mojo_message_pump_export.h32
-rw-r--r--mojo/message_pump/time_helper.cc33
-rw-r--r--mojo/message_pump/time_helper.h34
-rw-r--r--mojo/mojo.gyp18
-rw-r--r--mojo/mojo_base.gyp192
-rw-r--r--mojo/mojo_common_unittests.isolate23
-rw-r--r--mojo/mojo_edk.gyp233
-rw-r--r--mojo/mojo_edk_tests.gyp397
-rw-r--r--mojo/mojo_js_unittests.isolate46
-rw-r--r--mojo/mojo_public.gyp310
-rw-r--r--mojo/mojo_public_bindings_unittests.isolate24
-rw-r--r--mojo/mojo_public_system_unittests.isolate23
-rw-r--r--mojo/mojom_bindings_generator.gypi178
-rw-r--r--mojo/mojom_bindings_generator_explicit.gypi195
-rw-r--r--mojo/mojom_bindings_generator_variables.gypi29
-rw-r--r--mojo/public/BUILD.gn5
-rw-r--r--mojo/public/README.md2
-rw-r--r--mojo/public/c/system/BUILD.gn2
-rw-r--r--mojo/public/c/system/core.h1
-rw-r--r--mojo/public/c/system/main.h35
-rw-r--r--mojo/public/c/system/tests/core_unittest.cc9
-rw-r--r--mojo/public/c/system/tests/core_unittest_pure_c.c2
-rw-r--r--mojo/public/c/system/types.h7
-rw-r--r--mojo/public/c/test_support/BUILD.gn1
-rw-r--r--mojo/public/cpp/bindings/BUILD.gn68
-rw-r--r--mojo/public/cpp/bindings/array.h279
-rw-r--r--mojo/public/cpp/bindings/array_data_view.h244
-rw-r--r--mojo/public/cpp/bindings/array_traits.h4
-rw-r--r--mojo/public/cpp/bindings/array_traits_carray.h23
-rw-r--r--mojo/public/cpp/bindings/array_traits_standard.h43
-rw-r--r--mojo/public/cpp/bindings/array_traits_stl.h77
-rw-r--r--mojo/public/cpp/bindings/array_traits_wtf.h40
-rw-r--r--mojo/public/cpp/bindings/associated_binding.h162
-rw-r--r--mojo/public/cpp/bindings/associated_group.h77
-rw-r--r--mojo/public/cpp/bindings/associated_group_controller.h60
-rw-r--r--mojo/public/cpp/bindings/associated_interface_ptr.h143
-rw-r--r--mojo/public/cpp/bindings/associated_interface_ptr_info.h1
-rw-r--r--mojo/public/cpp/bindings/associated_interface_request.h5
-rw-r--r--mojo/public/cpp/bindings/binding.h58
-rw-r--r--mojo/public/cpp/bindings/binding_set.h272
-rw-r--r--mojo/public/cpp/bindings/bindings_export.h34
-rw-r--r--mojo/public/cpp/bindings/clone_traits.h86
-rw-r--r--mojo/public/cpp/bindings/connection_error_callback.h21
-rw-r--r--mojo/public/cpp/bindings/connector.h41
-rw-r--r--mojo/public/cpp/bindings/disconnect_reason.h25
-rw-r--r--mojo/public/cpp/bindings/filter_chain.h (renamed from mojo/public/cpp/bindings/lib/filter_chain.h)35
-rw-r--r--mojo/public/cpp/bindings/interface_data_view.h25
-rw-r--r--mojo/public/cpp/bindings/interface_endpoint_client.h70
-rw-r--r--mojo/public/cpp/bindings/interface_ptr.h44
-rw-r--r--mojo/public/cpp/bindings/interface_ptr_set.h12
-rw-r--r--mojo/public/cpp/bindings/interface_request.h45
-rw-r--r--mojo/public/cpp/bindings/lib/array_internal.h19
-rw-r--r--mojo/public/cpp/bindings/lib/array_serialization.h49
-rw-r--r--mojo/public/cpp/bindings/lib/associated_group.cc31
-rw-r--r--mojo/public/cpp/bindings/lib/associated_group_controller.cc22
-rw-r--r--mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h49
-rw-r--r--mojo/public/cpp/bindings/lib/binding_state.cc90
-rw-r--r--mojo/public/cpp/bindings/lib/binding_state.h213
-rw-r--r--mojo/public/cpp/bindings/lib/bindings_internal.cc47
-rw-r--r--mojo/public/cpp/bindings/lib/bindings_internal.h114
-rw-r--r--mojo/public/cpp/bindings/lib/buffer.h54
-rw-r--r--mojo/public/cpp/bindings/lib/connector.cc102
-rw-r--r--mojo/public/cpp/bindings/lib/control_message_handler.cc112
-rw-r--r--mojo/public/cpp/bindings/lib/control_message_handler.h5
-rw-r--r--mojo/public/cpp/bindings/lib/control_message_proxy.cc165
-rw-r--r--mojo/public/cpp/bindings/lib/control_message_proxy.h17
-rw-r--r--mojo/public/cpp/bindings/lib/equals_traits.h (renamed from mojo/public/cpp/bindings/lib/clone_equals_util.h)73
-rw-r--r--mojo/public/cpp/bindings/lib/filter_chain.cc22
-rw-r--r--mojo/public/cpp/bindings/lib/fixed_buffer.cc43
-rw-r--r--mojo/public/cpp/bindings/lib/fixed_buffer.h55
-rw-r--r--mojo/public/cpp/bindings/lib/handle_interface_serialization.h105
-rw-r--r--mojo/public/cpp/bindings/lib/hash_util.h84
-rw-r--r--mojo/public/cpp/bindings/lib/interface_endpoint_client.cc189
-rw-r--r--mojo/public/cpp/bindings/lib/interface_ptr_state.h220
-rw-r--r--mojo/public/cpp/bindings/lib/map_serialization.h27
-rw-r--r--mojo/public/cpp/bindings/lib/may_auto_lock.h62
-rw-r--r--mojo/public/cpp/bindings/lib/message.cc223
-rw-r--r--mojo/public/cpp/bindings/lib/message_buffer.cc37
-rw-r--r--mojo/public/cpp/bindings/lib/message_buffer.h15
-rw-r--r--mojo/public/cpp/bindings/lib/message_builder.cc67
-rw-r--r--mojo/public/cpp/bindings/lib/message_builder.h61
-rw-r--r--mojo/public/cpp/bindings/lib/message_filter.cc23
-rw-r--r--mojo/public/cpp/bindings/lib/message_header_validator.cc105
-rw-r--r--mojo/public/cpp/bindings/lib/message_internal.h45
-rw-r--r--mojo/public/cpp/bindings/lib/multiplex_router.cc543
-rw-r--r--mojo/public/cpp/bindings/lib/multiplex_router.h83
-rw-r--r--mojo/public/cpp/bindings/lib/native_struct.cc16
-rw-r--r--mojo/public/cpp/bindings/lib/native_struct_data.h4
-rw-r--r--mojo/public/cpp/bindings/lib/native_struct_serialization.cc10
-rw-r--r--mojo/public/cpp/bindings/lib/native_struct_serialization.h6
-rw-r--r--mojo/public/cpp/bindings/lib/no_interface.cc20
-rw-r--r--mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc28
-rw-r--r--mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc69
-rw-r--r--mojo/public/cpp/bindings/lib/router.cc323
-rw-r--r--mojo/public/cpp/bindings/lib/router.h177
-rw-r--r--mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc370
-rw-r--r--mojo/public/cpp/bindings/lib/serialization.h21
-rw-r--r--mojo/public/cpp/bindings/lib/serialization_context.cc5
-rw-r--r--mojo/public/cpp/bindings/lib/serialization_context.h22
-rw-r--r--mojo/public/cpp/bindings/lib/serialization_forward.h1
-rw-r--r--mojo/public/cpp/bindings/lib/string_serialization.h6
-rw-r--r--mojo/public/cpp/bindings/lib/string_traits_wtf.cc5
-rw-r--r--mojo/public/cpp/bindings/lib/sync_call_restrictions.cc4
-rw-r--r--mojo/public/cpp/bindings/lib/sync_handle_registry.cc19
-rw-r--r--mojo/public/cpp/bindings/lib/sync_handle_registry.h67
-rw-r--r--mojo/public/cpp/bindings/lib/validation_context.cc66
-rw-r--r--mojo/public/cpp/bindings/lib/validation_context.h101
-rw-r--r--mojo/public/cpp/bindings/lib/validation_errors.cc31
-rw-r--r--mojo/public/cpp/bindings/lib/validation_errors.h42
-rw-r--r--mojo/public/cpp/bindings/lib/validation_util.cc66
-rw-r--r--mojo/public/cpp/bindings/lib/validation_util.h110
-rw-r--r--mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h10
-rw-r--r--mojo/public/cpp/bindings/lib/wtf_serialization.h2
-rw-r--r--mojo/public/cpp/bindings/map.h312
-rw-r--r--mojo/public/cpp/bindings/map_data_view.h63
-rw-r--r--mojo/public/cpp/bindings/map_traits.h12
-rw-r--r--mojo/public/cpp/bindings/map_traits_standard.h53
-rw-r--r--mojo/public/cpp/bindings/map_traits_stl.h12
-rw-r--r--mojo/public/cpp/bindings/map_traits_wtf.h62
-rw-r--r--mojo/public/cpp/bindings/map_traits_wtf_hash_map.h15
-rw-r--r--mojo/public/cpp/bindings/message.h163
-rw-r--r--mojo/public/cpp/bindings/message_filter.h38
-rw-r--r--mojo/public/cpp/bindings/message_header_validator.h11
-rw-r--r--mojo/public/cpp/bindings/native_struct.h10
-rw-r--r--mojo/public/cpp/bindings/native_struct_data_view.h36
-rw-r--r--mojo/public/cpp/bindings/no_interface.h52
-rw-r--r--mojo/public/cpp/bindings/pipe_control_message_handler.h10
-rw-r--r--mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h7
-rw-r--r--mojo/public/cpp/bindings/pipe_control_message_proxy.h20
-rw-r--r--mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h22
-rw-r--r--mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h94
-rw-r--r--mojo/public/cpp/bindings/stl_converters.h245
-rw-r--r--mojo/public/cpp/bindings/string.h196
-rw-r--r--mojo/public/cpp/bindings/string_data_view.h34
-rw-r--r--mojo/public/cpp/bindings/string_traits.h19
-rw-r--r--mojo/public/cpp/bindings/string_traits_standard.h31
-rw-r--r--mojo/public/cpp/bindings/string_traits_string16.h3
-rw-r--r--mojo/public/cpp/bindings/strong_binding.h143
-rw-r--r--mojo/public/cpp/bindings/struct_ptr.h203
-rw-r--r--mojo/public/cpp/bindings/struct_traits.h45
-rw-r--r--mojo/public/cpp/bindings/sync_call_restrictions.h13
-rw-r--r--mojo/public/cpp/bindings/sync_handle_registry.h4
-rw-r--r--mojo/public/cpp/bindings/sync_handle_watcher.h3
-rw-r--r--mojo/public/cpp/bindings/thread_safe_interface_ptr.h278
-rw-r--r--mojo/public/cpp/bindings/type_converter.h22
-rw-r--r--mojo/public/cpp/bindings/union_traits.h39
-rw-r--r--mojo/public/cpp/bindings/wtf_array.h197
-rw-r--r--mojo/public/cpp/bindings/wtf_map.h200
-rw-r--r--mojo/public/cpp/system/BUILD.gn27
-rw-r--r--mojo/public/cpp/system/buffer.h4
-rw-r--r--mojo/public/cpp/system/platform_handle.cc49
-rw-r--r--mojo/public/cpp/system/platform_handle.h24
-rw-r--r--mojo/public/cpp/system/system_export.h34
-rw-r--r--mojo/public/cpp/system/watcher.cc49
-rw-r--r--mojo/public/cpp/system/watcher.h30
-rw-r--r--mojo/public/cpp/test_support/BUILD.gn1
-rw-r--r--mojo/public/interfaces/BUILD.gn2
-rw-r--r--mojo/public/interfaces/bindings/BUILD.gn5
-rw-r--r--mojo/public/interfaces/bindings/interface_control_messages.mojom62
-rw-r--r--mojo/public/interfaces/bindings/pipe_control_messages.mojom25
-rw-r--r--mojo/public/interfaces/bindings/tests/BUILD.gn67
-rw-r--r--mojo/public/interfaces/bindings/tests/data/message_data25
-rw-r--r--mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd0_good.data17
-rw-r--r--mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd0_unexpected_invalid_associated_interface.data17
-rw-r--r--mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd1_good.data17
-rw-r--r--mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd1_unexpected_invalid_associated_request.data19
-rw-r--r--mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd2_master_interface_id.data15
-rw-r--r--mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd2_master_interface_id.expected1
-rw-r--r--mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd3_good.data20
-rw-r--r--mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd3_unexpected_invalid_associated_interface_in_array.data21
-rw-r--r--mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd15_uknown_non_extensible_enum_array_value.data2
-rw-r--r--mojo/public/interfaces/bindings/tests/rect.mojom13
-rw-r--r--mojo/public/interfaces/bindings/tests/struct_with_traits.mojom41
-rw-r--r--mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom10
-rw-r--r--mojo/public/interfaces/bindings/tests/test_constants.mojom4
-rw-r--r--mojo/public/interfaces/bindings/tests/test_native_types.mojom1
-rw-r--r--mojo/public/interfaces/bindings/tests/test_structs.mojom32
-rw-r--r--mojo/public/interfaces/bindings/tests/test_wtf_types.mojom13
-rw-r--r--mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom22
-rw-r--r--mojo/public/java/BUILD.gn8
-rw-r--r--mojo/public/java/bindings/src/org/chromium/mojo/bindings/BindingsHelper.java6
-rw-r--r--mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java68
-rw-r--r--mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java33
-rw-r--r--mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java34
-rw-r--r--mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java32
-rw-r--r--mojo/public/java/bindings/src/org/chromium/mojo/bindings/InterfaceControlMessagesHelper.java26
-rw-r--r--mojo/public/java/bindings/src/org/chromium/mojo/bindings/Message.java2
-rw-r--r--mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java55
-rw-r--r--mojo/public/java/bindings/src/org/chromium/mojo/bindings/Struct.java19
-rw-r--r--mojo/public/java/system/src/org/chromium/mojo/system/AsyncWaiter.java53
-rw-r--r--mojo/public/java/system/src/org/chromium/mojo/system/Core.java4
-rw-r--r--mojo/public/java/system/src/org/chromium/mojo/system/Watcher.java38
-rw-r--r--mojo/public/js/BUILD.gn29
-rw-r--r--mojo/public/js/bindings.js336
-rw-r--r--mojo/public/js/codec.js81
-rw-r--r--mojo/public/js/codec_unittests.js296
-rw-r--r--mojo/public/js/connection.js176
-rw-r--r--mojo/public/js/connector.js27
-rw-r--r--mojo/public/js/constants.cc11
-rw-r--r--mojo/public/js/constants.h7
-rw-r--r--mojo/public/js/core.js75
-rw-r--r--mojo/public/js/core_unittests.js198
-rw-r--r--mojo/public/js/router.js91
-rw-r--r--mojo/public/js/struct_unittests.js279
-rw-r--r--mojo/public/js/test/validation_test_input_parser.js299
-rw-r--r--mojo/public/js/threading.js2
-rw-r--r--mojo/public/js/union_unittests.js184
-rw-r--r--mojo/public/js/validation_unittests.js349
-rw-r--r--mojo/public/js/validator.js153
-rw-r--r--mojo/public/mojo_application.gni270
-rw-r--r--mojo/public/mojo_application_manifest.gni139
-rw-r--r--mojo/public/mojo_application_manifest.gypi56
-rw-r--r--mojo/public/mojo_constants.gni8
-rw-r--r--mojo/public/tools/bindings/BUILD.gn12
-rw-r--r--mojo/public/tools/bindings/bindings.gyp83
-rw-r--r--mojo/public/tools/bindings/blink_bindings_configuration.gni16
-rw-r--r--mojo/public/tools/bindings/chromium_bindings_configuration.gni56
-rwxr-xr-xmojo/public/tools/bindings/generate_type_mappings.py11
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl130
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/enum_serialization_declaration.tmpl3
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl39
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl258
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl28
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl13
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl4
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl4
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl47
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl126
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl96
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl64
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl212
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl75
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl149
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl111
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_definition.tmpl64
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl17
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl11
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl8
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl34
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/struct_traits_declaration.tmpl32
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/struct_traits_definition.tmpl (renamed from mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl)4
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/union_data_view_declaration.tmpl91
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/union_data_view_definition.tmpl12
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl21
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl31
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl146
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl164
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/union_traits_declaration.tmpl24
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/union_traits_definition.tmpl47
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/validation_macros.tmpl2
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl50
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl44
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl9
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl21
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl38
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_template_definition.tmpl4
-rw-r--r--mojo/public/tools/bindings/generators/java_templates/data_types_definition.tmpl221
-rw-r--r--mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl11
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl32
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl23
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl8
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl1
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl34
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl8
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl14
-rw-r--r--mojo/public/tools/bindings/generators/mojom_cpp_generator.py553
-rw-r--r--mojo/public/tools/bindings/generators/mojom_java_generator.py22
-rw-r--r--mojo/public/tools/bindings/generators/mojom_js_generator.py118
-rwxr-xr-xmojo/public/tools/bindings/generators/run_cpp_generator.py28
-rw-r--r--mojo/public/tools/bindings/mojom.gni438
-rwxr-xr-xmojo/public/tools/bindings/mojom_bindings_generator.py59
-rwxr-xr-xmojo/public/tools/bindings/mojom_list_outputs.py44
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/generate/data.py530
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/generate/data_tests.py86
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/generate/generator.py10
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/generate/module.py75
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py3
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/generate/translate.py639
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/parse/parser.py10
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/parse/translate.py236
-rwxr-xr-xmojo/public/tools/gn/zip.py13
-rwxr-xr-xmojo/public/tools/manifest/manifest_collator.py104
-rwxr-xr-xmojo/public/tools/prepend.py37
-rw-r--r--third_party/catapult/devil/devil/android/perf/cache_control.py1
-rw-r--r--third_party/catapult/devil/devil/android/perf/thermal_throttle.py1
580 files changed, 19024 insertions, 24791 deletions
diff --git a/Android.mk b/Android.mk
index 36c6207..80bf5a9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -14,9 +14,13 @@ LOCAL_MODULE_TAGS := optional
LOCAL_CPP_EXTENSION := .cc
LOCAL_MOJOM_FILES := \
- mojo/common/common_custom_types.mojom \
+ ipc/ipc.mojom \
+ mojo/common/file.mojom \
mojo/common/string16.mojom \
+ mojo/common/text_direction.mojom \
mojo/common/time.mojom \
+ mojo/common/unguessable_token.mojom \
+ mojo/common/version.mojom \
mojo/public/interfaces/bindings/interface_control_messages.mojom \
mojo/public/interfaces/bindings/pipe_control_messages.mojom \
@@ -44,6 +48,7 @@ LOCAL_JAVA_JNI_FILES := \
jni/java/lang/Runtime.class \
mojo/android/system/src/org/chromium/mojo/system/impl/BaseRunLoop.java \
mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java \
+ mojo/android/system/src/org/chromium/mojo/system/impl/WatcherImpl.java \
# Generate all JNI header files.
include $(LOCAL_PATH)/build_generated_jni.mk
@@ -64,10 +69,9 @@ LOCAL_SRC_FILES := \
base/files/file_util_android.cc \
base/message_loop/message_pump_android.cc \
base/path_service.cc \
- base/threading/thread_local_android.cc \
base/trace_event/java_heap_dump_provider_android.cc \
base/trace_event/trace_event_android.cc \
- ipc/brokerable_attachment.cc \
+ base/unguessable_token.cc \
ipc/ipc_message.cc \
ipc/ipc_message_attachment.cc \
ipc/ipc_message_attachment_set.cc \
@@ -76,11 +80,12 @@ LOCAL_SRC_FILES := \
ipc/ipc_mojo_message_helper.cc \
ipc/ipc_mojo_param_traits.cc \
ipc/ipc_platform_file_attachment_posix.cc \
- ipc/placeholder_brokerable_attachment.cc \
mojo/android/system/base_run_loop.cc \
mojo/android/system/core_impl.cc \
- mojo/edk/embedder/embedder.cc \
+ mojo/android/system/watcher_impl.cc \
mojo/common/common_custom_types_struct_traits.cc \
+ mojo/edk/embedder/connection_params.cc \
+ mojo/edk/embedder/embedder.cc \
mojo/edk/embedder/entrypoints.cc \
mojo/edk/embedder/platform_channel_pair.cc \
mojo/edk/embedder/platform_channel_pair_posix.cc \
@@ -88,9 +93,10 @@ LOCAL_SRC_FILES := \
mojo/edk/embedder/platform_handle.cc \
mojo/edk/embedder/platform_handle_utils_posix.cc \
mojo/edk/embedder/platform_shared_buffer.cc \
+ mojo/edk/embedder/pending_process_connection.cc \
mojo/edk/embedder/test_embedder.cc \
mojo/edk/system/awakable_list.cc \
- mojo/edk/system/broker_host_posix.cc \
+ mojo/edk/system/broker_host.cc \
mojo/edk/system/broker_posix.cc \
mojo/edk/system/channel.cc \
mojo/edk/system/channel_posix.cc \
@@ -121,14 +127,11 @@ LOCAL_SRC_FILES := \
mojo/edk/system/waiter.cc \
mojo/edk/system/watcher.cc \
mojo/edk/system/watcher_set.cc \
- mojo/message_pump/handle_watcher.cc \
- mojo/message_pump/message_pump_mojo.cc \
- mojo/message_pump/time_helper.cc \
mojo/public/c/system/thunks.cc \
mojo/public/cpp/bindings/lib/array_internal.cc \
mojo/public/cpp/bindings/lib/associated_group.cc \
mojo/public/cpp/bindings/lib/associated_group_controller.cc \
- mojo/public/cpp/bindings/lib/bindings_internal.cc \
+ mojo/public/cpp/bindings/lib/binding_state.cc \
mojo/public/cpp/bindings/lib/connector.cc \
mojo/public/cpp/bindings/lib/control_message_handler.cc \
mojo/public/cpp/bindings/lib/control_message_proxy.cc \
@@ -138,16 +141,13 @@ LOCAL_SRC_FILES := \
mojo/public/cpp/bindings/lib/message.cc \
mojo/public/cpp/bindings/lib/message_buffer.cc \
mojo/public/cpp/bindings/lib/message_builder.cc \
- mojo/public/cpp/bindings/lib/message_filter.cc \
mojo/public/cpp/bindings/lib/message_header_validator.cc \
mojo/public/cpp/bindings/lib/multiplex_router.cc \
mojo/public/cpp/bindings/lib/native_struct.cc \
mojo/public/cpp/bindings/lib/native_struct_data.cc \
mojo/public/cpp/bindings/lib/native_struct_serialization.cc \
- mojo/public/cpp/bindings/lib/no_interface.cc \
mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc \
mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc \
- mojo/public/cpp/bindings/lib/router.cc \
mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc \
mojo/public/cpp/bindings/lib/serialization_context.cc \
mojo/public/cpp/bindings/lib/sync_handle_registry.cc \
@@ -202,6 +202,7 @@ LOCAL_SRC_FILES := \
base/android/java/src/org/chromium/base/BuildInfo.java \
base/android/java/src/org/chromium/base/ContextUtils.java \
base/android/java/src/org/chromium/base/PackageUtils.java \
+ base/android/java/src/org/chromium/base/Log.java \
base/android/java/src/org/chromium/base/VisibleForTesting.java \
$(call all-java-files-under, mojo/android/system/src) \
$(call all-java-files-under, mojo/public/java/system/src) \
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..cd08c43
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,181 @@
+# Copyright 2016 The Chromium OS 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 common.mk
+
+PC_DEPS = libchrome-$(BASE_VER)
+PC_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(PC_DEPS))
+PC_LIBS := $(shell $(PKG_CONFIG) --libs $(PC_DEPS))
+
+CPPFLAGS += -Wno-unused-parameter -Wno-missing-field-initializers $(PC_CFLAGS) -I$(OUT)
+
+CXXFLAGS += -std=c++11 \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor \
+ -Wno-ignored-qualifiers \
+ -Wno-format-nonliteral \
+ -Wno-extra \
+ -Wno-deprecated-register \
+ -Wno-char-subscripts \
+ -DOS_POSIX \
+ -DNO_TCMALLOC \
+
+LDLIBS += $(PC_LIBS)
+
+CXX_OBJECTS := \
+ base/base_paths.o \
+ base/debug/proc_maps_linux.o \
+ base/path_service.o \
+ base/unguessable_token.o \
+ ipc/ipc_message.o \
+ ipc/ipc_message_attachment.o \
+ ipc/ipc_message_attachment_set.o \
+ ipc/ipc_message_utils.o \
+ ipc/ipc_mojo_handle_attachment.o \
+ ipc/ipc_mojo_message_helper.o \
+ ipc/ipc_mojo_param_traits.o \
+ ipc/ipc_platform_file_attachment_posix.o \
+ mojo/common/common_custom_types_struct_traits.o \
+ mojo/edk/embedder/connection_params.o \
+ mojo/edk/embedder/embedder.o \
+ mojo/edk/embedder/entrypoints.o \
+ mojo/edk/embedder/platform_channel_pair.o \
+ mojo/edk/embedder/platform_channel_pair_posix.o \
+ mojo/edk/embedder/platform_channel_utils_posix.o \
+ mojo/edk/embedder/platform_handle.o \
+ mojo/edk/embedder/platform_handle_utils_posix.o \
+ mojo/edk/embedder/platform_shared_buffer.o \
+ mojo/edk/system/awakable_list.o \
+ mojo/edk/system/broker_host.o \
+ mojo/edk/system/broker_posix.o \
+ mojo/edk/system/channel.o \
+ mojo/edk/system/channel_posix.o \
+ mojo/edk/system/configuration.o \
+ mojo/edk/system/core.o \
+ mojo/edk/system/data_pipe_consumer_dispatcher.o \
+ mojo/edk/system/data_pipe_control_message.o \
+ mojo/edk/system/data_pipe_producer_dispatcher.o \
+ mojo/edk/system/dispatcher.o \
+ mojo/edk/system/handle_table.o \
+ mojo/edk/system/mapping_table.o \
+ mojo/edk/system/message_for_transit.o \
+ mojo/edk/system/message_pipe_dispatcher.o \
+ mojo/edk/system/node_channel.o \
+ mojo/edk/system/node_controller.o \
+ mojo/edk/system/platform_handle_dispatcher.o \
+ mojo/edk/system/ports/event.o \
+ mojo/edk/system/ports/message.o \
+ mojo/edk/system/ports/message_queue.o \
+ mojo/edk/system/ports/name.o \
+ mojo/edk/system/ports/node.o \
+ mojo/edk/system/ports/port.o \
+ mojo/edk/system/ports/port_ref.o \
+ mojo/edk/system/ports_message.o \
+ mojo/edk/system/request_context.o \
+ mojo/edk/system/shared_buffer_dispatcher.o \
+ mojo/edk/system/wait_set_dispatcher.o \
+ mojo/edk/system/waiter.o \
+ mojo/edk/system/watcher.o \
+ mojo/edk/system/watcher_set.o \
+ mojo/public/c/system/thunks.o \
+ mojo/public/cpp/bindings/lib/array_internal.o \
+ mojo/public/cpp/bindings/lib/associated_group.o \
+ mojo/public/cpp/bindings/lib/associated_group_controller.o \
+ mojo/public/cpp/bindings/lib/connector.o \
+ mojo/public/cpp/bindings/lib/control_message_handler.o \
+ mojo/public/cpp/bindings/lib/control_message_proxy.o \
+ mojo/public/cpp/bindings/lib/filter_chain.o \
+ mojo/public/cpp/bindings/lib/fixed_buffer.o \
+ mojo/public/cpp/bindings/lib/interface_endpoint_client.o \
+ mojo/public/cpp/bindings/lib/message.o \
+ mojo/public/cpp/bindings/lib/message_buffer.o \
+ mojo/public/cpp/bindings/lib/message_builder.o \
+ mojo/public/cpp/bindings/lib/message_header_validator.o \
+ mojo/public/cpp/bindings/lib/multiplex_router.o \
+ mojo/public/cpp/bindings/lib/native_struct.o \
+ mojo/public/cpp/bindings/lib/native_struct_data.o \
+ mojo/public/cpp/bindings/lib/native_struct_serialization.o \
+ mojo/public/cpp/bindings/lib/pipe_control_message_handler.o \
+ mojo/public/cpp/bindings/lib/pipe_control_message_proxy.o \
+ mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.o \
+ mojo/public/cpp/bindings/lib/serialization_context.o \
+ mojo/public/cpp/bindings/lib/sync_handle_registry.o \
+ mojo/public/cpp/bindings/lib/sync_handle_watcher.o \
+ mojo/public/cpp/bindings/lib/validation_context.o \
+ mojo/public/cpp/bindings/lib/validation_errors.o \
+ mojo/public/cpp/bindings/lib/validation_util.o \
+ mojo/public/cpp/system/platform_handle.o \
+ mojo/public/cpp/system/watcher.o
+
+MOJOM_FILES := ipc/ipc.mojom \
+ mojo/common/file.mojom \
+ mojo/common/string16.mojom \
+ mojo/common/text_direction.mojom \
+ mojo/common/time.mojom \
+ mojo/common/unguessable_token.mojom \
+ mojo/common/version.mojom \
+ mojo/public/interfaces/bindings/pipe_control_messages.mojom \
+ mojo/public/interfaces/bindings/interface_control_messages.mojom \
+
+MOJOM_BINDINGS_GENERATOR := \
+ $(S)/mojo/public/tools/bindings/mojom_bindings_generator.py
+
+GEN_TEMPLATES_DIR := $(S)/templates
+
+gen_templates:
+ @echo generate_mojo_templates: $(GEN_TEMPLATES_DIR)
+ @rm -rf $(GEN_TEMPLATES_DIR)
+ @mkdir -p $(GEN_TEMPLATES_DIR)
+ @python $(MOJOM_BINDINGS_GENERATOR) --use_bundled_pylibs precompile \
+ -o $(GEN_TEMPLATES_DIR)
+
+templates: gen_templates
+ cd $(S) && \
+ python $(abspath $(MOJOM_BINDINGS_GENERATOR)) \
+ --use_bundled_pylibs generate \
+ $(MOJOM_FILES) \
+ -o $(abspath $(S)) \
+ --bytecode_path $(abspath $(GEN_TEMPLATES_DIR)) \
+ -g c++
+ cd $(S) && \
+ python $(abspath $(MOJOM_BINDINGS_GENERATOR)) \
+ --use_bundled_pylibs generate \
+ $(MOJOM_FILES) \
+ -o $(abspath $(S)) \
+ --bytecode_path $(abspath $(GEN_TEMPLATES_DIR)) \
+ --generate_non_variant_code \
+ -g c++
+
+GENERATED_OBJECTS := $(patsubst %.mojom,%.mojom.o,$(MOJOM_FILES))
+GENERATED_SHARED_OBJECTS := $(patsubst %.mojom,%.mojom-shared.o,$(MOJOM_FILES))
+
+$(eval $(call add_object_rules,$(GENERATED_OBJECTS),CXX,cc,CXXFLAGS,$(SRC)/))
+$(eval $(call add_object_rules,$(GENERATED_SHARED_OBJECTS),CXX,cc,CXXFLAGS,$(SRC)/))
+# Note: I don't know why we need the line below (it's in commmon.mk), but without it,
+# .o files from CXX_OBJECTS won't be built.
+$(eval $(call add_object_rules,$(CXX_OBJECTS),CXX,cc,CXXFLAGS,$(SRC)/))
+
+LIB ?= lib
+LIB_PIE_NAME = libmojo-$(BASE_VER).pie.a
+LIB_PIC_NAME = libmojo-$(BASE_VER).pic.a
+
+CXX_STATIC_LIBRARY($(LIB_PIE_NAME)): $(GENERATED_SHARED_OBJECTS) $(GENERATED_OBJECTS) $(CXX_OBJECTS)
+CXX_STATIC_LIBRARY($(LIB_PIC_NAME)): $(GENERATED_SHARED_OBJECTS) $(GENERATED_OBJECTS) $(CXX_OBJECTS)
+
+all: CXX_STATIC_LIBRARY($(LIB_PIE_NAME)) CXX_STATIC_LIBRARY($(LIB_PIC_NAME))
+
+clean: CLEAN($(LIB_PIE_NAME)) CLEAN($(LIB_PIC_NAME))
+
+install_lib: all
+ install -D -m 755 $(OUT)/$(LIB_PIE_NAME) $(DESTDIR)/usr/$(LIB)/$(LIB_PIE_NAME)
+ install -D -m 755 $(OUT)/$(LIB_PIC_NAME) $(DESTDIR)/usr/$(LIB)/$(LIB_PIC_NAME)
+ sed -e "s:@LIB@:$(LIB):g" -e "s:@BSLOT@:$(BASE_VER):g" $(S)/libmojo.pc.in > $(S)/libmojo-$(BASE_VER).pc
+
+install_tool:
+ install -d $(DESTDIR)/usr/src/libmojo-$(BASE_VER)/mojo/
+ cp -r --preserve=mode $(SRC)/third_party $(DESTDIR)/usr/src/libmojo-$(BASE_VER)/
+ cp -r --preserve=mode $(SRC)/mojo/public/tools/bindings/* \
+ $(DESTDIR)/usr/src/libmojo-$(BASE_VER)/mojo/
+
+install: install_lib install_tool
diff --git a/base/android/animation_frame_time_histogram.cc b/base/android/animation_frame_time_histogram.cc
index 2cf7516..c2b48d3 100644
--- a/base/android/animation_frame_time_histogram.cc
+++ b/base/android/animation_frame_time_histogram.cc
@@ -8,6 +8,8 @@
#include "base/metrics/histogram_macros.h"
#include "jni/AnimationFrameTimeHistogram_jni.h"
+using base::android::JavaParamRef;
+
// static
void SaveHistogram(JNIEnv* env,
const JavaParamRef<jobject>& jcaller,
diff --git a/base/android/apk_assets.cc b/base/android/apk_assets.cc
index 5319e73..19a202c 100644
--- a/base/android/apk_assets.cc
+++ b/base/android/apk_assets.cc
@@ -10,24 +10,20 @@
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
+#include "base/file_descriptor_store.h"
#include "jni/ApkAssets_jni.h"
namespace base {
namespace android {
-bool RegisterApkAssets(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
int OpenApkAsset(const std::string& file_path,
base::MemoryMappedFile::Region* region) {
- // The AAssetManager API of the NDK is does not expose a method for accessing
- // raw resources :(.
+ // The AssetManager API of the NDK does not expose a method for accessing raw
+ // resources :(
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jlongArray> jarr = Java_ApkAssets_open(
- env,
- base::android::GetApplicationContext(),
- base::android::ConvertUTF8ToJavaString(env, file_path).obj());
+ env, base::android::GetApplicationContext(),
+ base::android::ConvertUTF8ToJavaString(env, file_path));
std::vector<jlong> results;
base::android::JavaLongArrayToLongVector(env, jarr.obj(), &results);
CHECK_EQ(3U, results.size());
@@ -37,15 +33,16 @@ int OpenApkAsset(const std::string& file_path,
return fd;
}
-bool RegisterApkAssetWithGlobalDescriptors(base::GlobalDescriptors::Key key,
- const std::string& file_path) {
+bool RegisterApkAssetWithFileDescriptorStore(const std::string& key,
+ const base::FilePath& file_path) {
base::MemoryMappedFile::Region region =
base::MemoryMappedFile::Region::kWholeFile;
- int asset_fd = OpenApkAsset(file_path, &region);
- if (asset_fd != -1) {
- base::GlobalDescriptors::GetInstance()->Set(key, asset_fd, region);
- }
- return asset_fd != -1;
+ int asset_fd = OpenApkAsset(file_path.value(), &region);
+ if (asset_fd == -1)
+ return false;
+ base::FileDescriptorStore::GetInstance().Set(key, base::ScopedFD(asset_fd),
+ region);
+ return true;
}
} // namespace android
diff --git a/base/android/apk_assets.h b/base/android/apk_assets.h
index 6eb5da3..cdac000 100644
--- a/base/android/apk_assets.h
+++ b/base/android/apk_assets.h
@@ -8,14 +8,12 @@
#include <string>
#include "base/android/jni_android.h"
+#include "base/files/file_path.h"
#include "base/files/memory_mapped_file.h"
-#include "base/posix/global_descriptors.h"
namespace base {
namespace android {
-bool RegisterApkAssets(JNIEnv* env);
-
// Opens an asset (e.g. a .pak file) from the apk.
// Can be used from renderer process.
// Fails if the asset is not stored uncompressed within the .apk.
@@ -28,11 +26,12 @@ BASE_EXPORT int OpenApkAsset(
const std::string& file_path,
base::MemoryMappedFile::Region* region);
-// Registers an uncompressed asset from within the apk with GlobalDescriptors.
+// Registers an uncompressed asset from within the apk in the
+// FileDescriptorStore.
// Returns: true in case of success, false otherwise.
-BASE_EXPORT bool RegisterApkAssetWithGlobalDescriptors(
- base::GlobalDescriptors::Key key,
- const std::string& file_path);
+BASE_EXPORT bool RegisterApkAssetWithFileDescriptorStore(
+ const std::string& key,
+ const base::FilePath& file_path);
} // namespace android
} // namespace base
diff --git a/base/android/base_jni_onload.cc b/base/android/base_jni_onload.cc
index 7ab4982..0a82db4 100644
--- a/base/android/base_jni_onload.cc
+++ b/base/android/base_jni_onload.cc
@@ -12,13 +12,11 @@
namespace base {
namespace android {
-namespace {
-
-bool RegisterJNI(JNIEnv* env) {
+bool OnJNIOnLoadRegisterJNI(JNIEnv* env) {
return RegisterLibraryLoaderEntryHook(env);
}
-bool Init() {
+bool OnJNIOnLoadInit() {
InitAtExitManager();
JNIEnv* env = base::android::AttachCurrentThread();
base::android::InitReplacementClassLoader(env,
@@ -26,32 +24,5 @@ bool Init() {
return true;
}
-} // namespace
-
-
-bool OnJNIOnLoadRegisterJNI(JavaVM* vm,
- std::vector<RegisterCallback> callbacks) {
- base::android::InitVM(vm);
- JNIEnv* env = base::android::AttachCurrentThread();
-
- callbacks.push_back(base::Bind(&RegisterJNI));
- for (std::vector<RegisterCallback>::reverse_iterator i =
- callbacks.rbegin(); i != callbacks.rend(); ++i) {
- if (!i->Run(env))
- return false;
- }
- return true;
-}
-
-bool OnJNIOnLoadInit(std::vector<InitCallback> callbacks) {
- callbacks.push_back(base::Bind(&Init));
- for (std::vector<InitCallback>::reverse_iterator i =
- callbacks.rbegin(); i != callbacks.rend(); ++i) {
- if (!i->Run())
- return false;
- }
- return true;
-}
-
} // namespace android
} // namespace base
diff --git a/base/android/base_jni_onload.h b/base/android/base_jni_onload.h
index dcc7756..be637d5 100644
--- a/base/android/base_jni_onload.h
+++ b/base/android/base_jni_onload.h
@@ -14,17 +14,12 @@
namespace base {
namespace android {
-// Returns whether JNI registration succeeded. Caller shall put the
-// RegisterCallback into |callbacks| in reverse order.
+// Returns whether JNI registration succeeded.
typedef base::Callback<bool(JNIEnv*)> RegisterCallback;
-BASE_EXPORT bool OnJNIOnLoadRegisterJNI(
- JavaVM* vm,
- std::vector<RegisterCallback> callbacks);
-
-// Returns whether initialization succeeded. Caller shall put the
-// InitCallback into |callbacks| in reverse order.
-typedef base::Callback<bool(void)> InitCallback;
-BASE_EXPORT bool OnJNIOnLoadInit(std::vector<InitCallback> callbacks);
+BASE_EXPORT bool OnJNIOnLoadRegisterJNI(JNIEnv* env);
+
+// Returns whether initialization succeeded.
+BASE_EXPORT bool OnJNIOnLoadInit();
} // namespace android
} // namespace base
diff --git a/base/android/base_jni_registrar.cc b/base/android/base_jni_registrar.cc
index bc34979..972c333 100644
--- a/base/android/base_jni_registrar.cc
+++ b/base/android/base_jni_registrar.cc
@@ -5,30 +5,23 @@
#include "base/android/base_jni_registrar.h"
#include "base/android/animation_frame_time_histogram.h"
-#include "base/android/apk_assets.h"
#include "base/android/application_status_listener.h"
-#include "base/android/build_info.h"
-#include "base/android/callback_android.h"
#include "base/android/command_line_android.h"
-#include "base/android/content_uri_utils.h"
#include "base/android/context_utils.h"
#include "base/android/cpu_features.h"
-#include "base/android/event_log.h"
+#include "base/android/early_trace_event_binding.h"
#include "base/android/field_trial_list.h"
#include "base/android/important_file_writer_android.h"
+#include "base/android/java_exception_reporter.h"
#include "base/android/java_handler_thread.h"
-#include "base/android/java_runtime.h"
#include "base/android/jni_android.h"
#include "base/android/jni_registrar.h"
-#include "base/android/jni_utils.h"
-#include "base/android/locale_utils.h"
#include "base/android/memory_pressure_listener_android.h"
#include "base/android/path_service_android.h"
-#include "base/android/path_utils.h"
#include "base/android/record_histogram.h"
#include "base/android/record_user_action.h"
-#include "base/android/sys_utils.h"
-#include "base/android/thread_utils.h"
+#include "base/android/statistics_recorder_android.h"
+#include "base/android/time_utils.h"
#include "base/android/trace_event_binding.h"
#include "base/macros.h"
#include "base/message_loop/message_pump_android.h"
@@ -41,33 +34,27 @@ namespace android {
static RegistrationMethod kBaseRegisteredMethods[] = {
{"AnimationFrameTimeHistogram",
base::android::RegisterAnimationFrameTimeHistogram},
- {"ApkAssets", base::android::RegisterApkAssets},
{"ApplicationStatusListener",
base::android::ApplicationStatusListener::RegisterBindings},
- {"BuildInfo", base::android::BuildInfo::RegisterBindings},
- {"CallbackAndroid", base::android::RegisterCallbackAndroid},
{"CommandLine", base::android::RegisterCommandLine},
- {"ContentUriUtils", base::RegisterContentUriUtils},
{"ContextUtils", base::android::RegisterContextUtils},
{"CpuFeatures", base::android::RegisterCpuFeatures},
- {"EventLog", base::android::RegisterEventLog},
+ {"EarlyTraceEvent", base::android::RegisterEarlyTraceEvent},
{"FieldTrialList", base::android::RegisterFieldTrialList},
{"ImportantFileWriterAndroid",
base::android::RegisterImportantFileWriterAndroid},
- {"JNIUtils", base::android::RegisterJNIUtils},
- {"LocaleUtils", base::android::RegisterLocaleUtils},
{"MemoryPressureListenerAndroid",
base::android::MemoryPressureListenerAndroid::Register},
+ {"JavaExceptionReporter", base::android::RegisterJavaExceptionReporterJni},
{"JavaHandlerThread", base::android::JavaHandlerThread::RegisterBindings},
{"PathService", base::android::RegisterPathService},
- {"PathUtils", base::android::RegisterPathUtils},
{"PowerMonitor", base::RegisterPowerMonitor},
{"RecordHistogram", base::android::RegisterRecordHistogram},
{"RecordUserAction", base::android::RegisterRecordUserAction},
- {"Runtime", base::android::JavaRuntime::Register},
+ {"StatisticsRecorderAndroid",
+ base::android::RegisterStatisticsRecorderAndroid},
{"SystemMessageHandler", base::MessagePumpForUI::RegisterBindings},
- {"SysUtils", base::android::SysUtils::Register},
- {"ThreadUtils", base::RegisterThreadUtils},
+ {"TimeUtils", base::android::RegisterTimeUtils},
{"TraceEvent", base::android::RegisterTraceEvent},
};
diff --git a/base/android/build_info.cc b/base/android/build_info.cc
index ef8f572..80b9e0a 100644
--- a/base/android/build_info.cc
+++ b/base/android/build_info.cc
@@ -38,7 +38,7 @@ struct BuildInfoSingletonTraits {
}
static const bool kRegisterAtExit = false;
-#ifndef NDEBUG
+#if DCHECK_IS_ON()
static const bool kAllowedToAccessOnNonjoinableThread = true;
#endif
};
@@ -81,10 +81,5 @@ void BuildInfo::ClearJavaExceptionInfo() {
java_exception_info_ = nullptr;
}
-// static
-bool BuildInfo::RegisterBindings(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace android
} // namespace base
diff --git a/base/android/build_info.h b/base/android/build_info.h
index 838d6f8..cce74f4 100644
--- a/base/android/build_info.h
+++ b/base/android/build_info.h
@@ -26,7 +26,8 @@ enum SdkVersion {
SDK_VERSION_KITKAT_WEAR = 20,
SDK_VERSION_LOLLIPOP = 21,
SDK_VERSION_LOLLIPOP_MR1 = 22,
- SDK_VERSION_MARSHMALLOW = 23
+ SDK_VERSION_MARSHMALLOW = 23,
+ SDK_VERSION_NOUGAT = 24
};
// BuildInfo is a singleton class that stores android build and device
@@ -110,8 +111,6 @@ class BASE_EXPORT BuildInfo {
void ClearJavaExceptionInfo();
- static bool RegisterBindings(JNIEnv* env);
-
private:
friend struct BuildInfoSingletonTraits;
diff --git a/base/android/command_line_android.cc b/base/android/command_line_android.cc
index e196aed..21ae182 100644
--- a/base/android/command_line_android.cc
+++ b/base/android/command_line_android.cc
@@ -12,6 +12,8 @@
using base::android::ConvertUTF8ToJavaString;
using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
using base::CommandLine;
namespace {
diff --git a/base/android/content_uri_utils.cc b/base/android/content_uri_utils.cc
index 31f7b4f..f7484cf 100644
--- a/base/android/content_uri_utils.cc
+++ b/base/android/content_uri_utils.cc
@@ -10,19 +10,16 @@
#include "jni/ContentUriUtils_jni.h"
using base::android::ConvertUTF8ToJavaString;
+using base::android::ScopedJavaLocalRef;
namespace base {
-bool RegisterContentUriUtils(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
bool ContentUriExists(const FilePath& content_uri) {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jstring> j_uri =
ConvertUTF8ToJavaString(env, content_uri.value());
return Java_ContentUriUtils_contentUriExists(
- env, base::android::GetApplicationContext(), j_uri.obj());
+ env, base::android::GetApplicationContext(), j_uri);
}
File OpenContentUriForRead(const FilePath& content_uri) {
@@ -30,7 +27,7 @@ File OpenContentUriForRead(const FilePath& content_uri) {
ScopedJavaLocalRef<jstring> j_uri =
ConvertUTF8ToJavaString(env, content_uri.value());
jint fd = Java_ContentUriUtils_openContentUriForRead(
- env, base::android::GetApplicationContext(), j_uri.obj());
+ env, base::android::GetApplicationContext(), j_uri);
if (fd < 0)
return File();
return File(fd);
@@ -40,9 +37,8 @@ std::string GetContentUriMimeType(const FilePath& content_uri) {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jstring> j_uri =
ConvertUTF8ToJavaString(env, content_uri.value());
- ScopedJavaLocalRef<jstring> j_mime =
- Java_ContentUriUtils_getMimeType(
- env, base::android::GetApplicationContext(), j_uri.obj());
+ ScopedJavaLocalRef<jstring> j_mime = Java_ContentUriUtils_getMimeType(
+ env, base::android::GetApplicationContext(), j_uri);
if (j_mime.is_null())
return std::string();
diff --git a/base/android/content_uri_utils.h b/base/android/content_uri_utils.h
index 59fa1e6..6d817c0 100644
--- a/base/android/content_uri_utils.h
+++ b/base/android/content_uri_utils.h
@@ -13,8 +13,6 @@
namespace base {
-bool RegisterContentUriUtils(JNIEnv* env);
-
// Opens a content URI for read and returns the file descriptor to the caller.
// Returns -1 if the URI is invalid.
BASE_EXPORT File OpenContentUriForRead(const FilePath& content_uri);
diff --git a/base/android/context_utils.cc b/base/android/context_utils.cc
index e9ab723..e2c4ed0 100644
--- a/base/android/context_utils.cc
+++ b/base/android/context_utils.cc
@@ -33,9 +33,9 @@ void SetNativeApplicationContext(JNIEnv* env, const JavaRef<jobject>& context) {
} // namespace
-jobject GetApplicationContext() {
+const JavaRef<jobject>& GetApplicationContext() {
DCHECK(!g_application_context.Get().is_null());
- return g_application_context.Get().obj();
+ return g_application_context.Get();
}
static void InitNativeSideApplicationContext(
diff --git a/base/android/context_utils.h b/base/android/context_utils.h
index f172d93..c5289f1 100644
--- a/base/android/context_utils.h
+++ b/base/android/context_utils.h
@@ -16,7 +16,7 @@ namespace android {
// Gets a global ref to the application context set with
// InitApplicationContext(). Ownership is retained by the function - the caller
// must NOT release it.
-BASE_EXPORT jobject GetApplicationContext();
+BASE_EXPORT const JavaRef<jobject>& GetApplicationContext();
bool RegisterContextUtils(JNIEnv* env);
diff --git a/base/android/event_log.cc b/base/android/event_log.cc
index a4b1dd1..3eb5926 100644
--- a/base/android/event_log.cc
+++ b/base/android/event_log.cc
@@ -12,9 +12,5 @@ void EventLogWriteInt(int tag, int value) {
Java_EventLog_writeEvent(AttachCurrentThread(), tag, value);
}
-bool RegisterEventLog(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace android
} // namespace base
diff --git a/base/android/event_log.h b/base/android/event_log.h
index dad4e4c..ebd5919 100644
--- a/base/android/event_log.h
+++ b/base/android/event_log.h
@@ -14,8 +14,6 @@ namespace android {
void BASE_EXPORT EventLogWriteInt(int tag, int value);
-bool RegisterEventLog(JNIEnv* env);
-
} // namespace android
} // namespace base
diff --git a/base/android/field_trial_list.cc b/base/android/field_trial_list.cc
index 9731a48..5150b81 100644
--- a/base/android/field_trial_list.cc
+++ b/base/android/field_trial_list.cc
@@ -12,6 +12,8 @@
using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
static ScopedJavaLocalRef<jstring> FindFullName(
JNIEnv* env,
diff --git a/base/android/fifo_utils.cc b/base/android/fifo_utils.cc
deleted file mode 100644
index 8f3e95f..0000000
--- a/base/android/fifo_utils.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/android/fifo_utils.h"
-
-#include <sys/stat.h>
-
-#include "base/files/file_path.h"
-
-namespace base {
-namespace android {
-
-bool CreateFIFO(const FilePath& path, int mode) {
- // Default permissions for mkfifo() is ignored, chmod() is required.
- return mkfifo(path.value().c_str(), mode) == 0 &&
- chmod(path.value().c_str(), mode) == 0;
-}
-
-bool RedirectStream(FILE* stream, const FilePath& path, const char* mode) {
- return freopen(path.value().c_str(), mode, stream) != NULL;
-}
-
-} // namespace android
-} // namespace base
diff --git a/base/android/fifo_utils.h b/base/android/fifo_utils.h
deleted file mode 100644
index 0bad8e2..0000000
--- a/base/android/fifo_utils.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_ANDROID_FIFO_UTILS_H_
-#define BASE_ANDROID_FIFO_UTILS_H_
-
-#include <stdio.h>
-
-#include "base/base_export.h"
-
-namespace base {
-
-class FilePath;
-
-namespace android {
-
-// Creates a fifo at the given |path| with POSIX permissions set to |mode|,
-// returning true if it was successfully created and permissions were set.
-BASE_EXPORT bool CreateFIFO(const FilePath& path, int mode);
-
-// Redirects the |stream| to the file provided by |path| with |mode|
-// permissions, returning true if successful.
-BASE_EXPORT bool RedirectStream(FILE* stream,
- const FilePath& path,
- const char* mode);
-
-} // namespace android
-} // namespace base
-
-#endif // BASE_ANDROID_FIFO_UTILS_H_
diff --git a/base/android/java/src/org/chromium/base/ActivityState.java b/base/android/java/src/org/chromium/base/ActivityState.java
index 98aff62..f4e6413 100644
--- a/base/android/java/src/org/chromium/base/ActivityState.java
+++ b/base/android/java/src/org/chromium/base/ActivityState.java
@@ -4,10 +4,20 @@
package org.chromium.base;
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* A set of states that represent the last state change of an Activity.
*/
public interface ActivityState {
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({CREATED, STARTED, RESUMED, PAUSED, STOPPED, DESTROYED})
+ public @interface ActivityStateEnum {}
+
/**
* Represents Activity#onCreate().
*/
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
index 9c9c16b..f773859 100644
--- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
+++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -21,6 +21,7 @@ import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.os.Build;
import android.os.PowerManager;
import android.os.Process;
@@ -31,8 +32,10 @@ import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.Window;
import android.view.WindowManager;
+import android.view.inputmethod.InputMethodSubtype;
import android.widget.TextView;
+import java.io.File;
import java.lang.reflect.Method;
/**
@@ -44,6 +47,22 @@ public class ApiCompatibilityUtils {
}
/**
+ * Compares two long values numerically. The value returned is identical to what would be
+ * returned by {@link Long#compare(long, long)} which is available since API level 19.
+ */
+ public static int compareLong(long lhs, long rhs) {
+ return lhs < rhs ? -1 : (lhs == rhs ? 0 : 1);
+ }
+
+ /**
+ * Compares two boolean values. The value returned is identical to what would be returned by
+ * {@link Boolean#compare(boolean, boolean)} which is available since API level 19.
+ */
+ public static int compareBoolean(boolean lhs, boolean rhs) {
+ return lhs == rhs ? 0 : lhs ? 1 : -1;
+ }
+
+ /**
* Returns true if view's layout direction is right-to-left.
*
* @param view the View whose layout is being considered
@@ -394,13 +413,7 @@ public class ApiCompatibilityUtils {
*/
public static void setStatusBarColor(Window window, int statusBarColor) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- // If both system bars are black, we can remove these from our layout,
- // removing or shrinking the SurfaceFlinger overlay required for our views.
- if (statusBarColor == Color.BLACK && window.getNavigationBarColor() == Color.BLACK) {
- window.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- } else {
- window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- }
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(statusBarColor);
}
}
@@ -515,7 +528,19 @@ public class ApiCompatibilityUtils {
}
/**
- * See {@link android.os.StatFs#getBlockCount()}.
+ * See {@link android.os.StatFs#getAvailableBlocksLong}.
+ */
+ @SuppressWarnings("deprecation")
+ public static long getAvailableBlocks(StatFs statFs) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ return statFs.getAvailableBlocksLong();
+ } else {
+ return statFs.getAvailableBlocks();
+ }
+ }
+
+ /**
+ * See {@link android.os.StatFs#getBlockCount}.
*/
@SuppressWarnings("deprecation")
public static long getBlockCount(StatFs statFs) {
@@ -527,7 +552,7 @@ public class ApiCompatibilityUtils {
}
/**
- * See {@link android.os.StatFs#getBlockSize()}.
+ * See {@link android.os.StatFs#getBlockSize}.
*/
@SuppressWarnings("deprecation")
public static long getBlockSize(StatFs statFs) {
@@ -559,4 +584,68 @@ public class ApiCompatibilityUtils {
return false;
}
+
+ /**
+ * @see Context#checkPermission(String, int, int)
+ */
+ public static int checkPermission(Context context, String permission, int pid, int uid) {
+ try {
+ return context.checkPermission(permission, pid, uid);
+ } catch (RuntimeException e) {
+ // Some older versions of Android throw odd errors when checking for permissions, so
+ // just swallow the exception and treat it as the permission is denied.
+ // crbug.com/639099
+ return PackageManager.PERMISSION_DENIED;
+ }
+ }
+
+ /**
+ * @see android.view.inputmethod.InputMethodSubType#getLocate()
+ */
+ @SuppressWarnings("deprecation")
+ public static String getLocale(InputMethodSubtype inputMethodSubType) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ return inputMethodSubType.getLanguageTag();
+ } else {
+ return inputMethodSubType.getLocale();
+ }
+ }
+
+ /**
+ * Get a URI for |file| which has the image capture. This function assumes that path of |file|
+ * is based on the result of UiUtils.getDirectoryForImageCapture().
+ *
+ * @param context The application context.
+ * @param file image capture file.
+ * @return URI for |file|.
+ */
+ public static Uri getUriForImageCaptureFile(Context context, File file) {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2
+ ? ContentUriUtils.getContentUriFromFile(context, file)
+ : Uri.fromFile(file);
+ }
+
+ /**
+ * @see android.view.Window#FEATURE_INDETERMINATE_PROGRESS
+ */
+ public static void setWindowIndeterminateProgress(Window window) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ @SuppressWarnings("deprecation")
+ int featureNumber = Window.FEATURE_INDETERMINATE_PROGRESS;
+
+ @SuppressWarnings("deprecation")
+ int featureValue = Window.PROGRESS_VISIBILITY_OFF;
+
+ window.setFeatureInt(featureNumber, featureValue);
+ }
+ }
+
+ /**
+ * Null-safe equivalent of {@code a.equals(b)}.
+ *
+ * @see Objects#equals(Object, Object)
+ */
+ public static boolean objectEquals(Object a, Object b) {
+ return (a == null) ? (b == null) : a.equals(b);
+ }
}
diff --git a/base/android/java/src/org/chromium/base/ApplicationStatus.java b/base/android/java/src/org/chromium/base/ApplicationStatus.java
index 37af12d..8d82ed7 100644
--- a/base/android/java/src/org/chromium/base/ApplicationStatus.java
+++ b/base/android/java/src/org/chromium/base/ApplicationStatus.java
@@ -4,11 +4,14 @@
package org.chromium.base;
+import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;
+import org.chromium.base.ActivityState.ActivityStateEnum;
+import org.chromium.base.ApplicationState.ApplicationStateEnum;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.MainDex;
@@ -34,6 +37,7 @@ public class ApplicationStatus {
/**
* @return The current {@link ActivityState} of the activity.
*/
+ @ActivityStateEnum
public int getStatus() {
return mStatus;
}
@@ -41,7 +45,7 @@ public class ApplicationStatus {
/**
* @param status The new {@link ActivityState} of the activity.
*/
- public void setStatus(int status) {
+ public void setStatus(@ActivityStateEnum int status) {
mStatus = status;
}
@@ -54,6 +58,7 @@ public class ApplicationStatus {
}
private static Object sCachedApplicationStateLock = new Object();
+ @ApplicationStateEnum
private static Integer sCachedApplicationState;
/** Last activity that was shown (or null if none or it was destroyed). */
@@ -89,7 +94,7 @@ public class ApplicationStatus {
* Called when the application's state changes.
* @param newState The application state.
*/
- public void onApplicationStateChange(int newState);
+ public void onApplicationStateChange(@ApplicationStateEnum int newState);
}
/**
@@ -101,7 +106,7 @@ public class ApplicationStatus {
* @param activity The activity that had a state change.
* @param newState New activity state.
*/
- public void onActivityStateChange(Activity activity, int newState);
+ public void onActivityStateChange(Activity activity, @ActivityStateEnum int newState);
}
private ApplicationStatus() {}
@@ -170,7 +175,7 @@ public class ApplicationStatus {
* @param activity Current activity.
* @param newState New state value.
*/
- private static void onStateChange(Activity activity, int newState) {
+ private static void onStateChange(Activity activity, @ActivityStateEnum int newState) {
if (activity == null) throw new IllegalArgumentException("null activity is not supported");
if (sActivity == null
@@ -183,7 +188,13 @@ public class ApplicationStatus {
int oldApplicationState = getStateForApplication();
if (newState == ActivityState.CREATED) {
- assert !sActivityInfo.containsKey(activity);
+ // TODO(tedchoc): crbug/691100. The timing of application callback lifecycles were
+ // changed in O and the activity info may have been lazily created
+ // on first access to avoid a crash on startup. This should be removed
+ // once the new lifecycle APIs are available.
+ if (!BuildInfo.isAtLeastO()) {
+ assert !sActivityInfo.containsKey(activity);
+ }
sActivityInfo.put(activity, new ActivityInfo());
}
@@ -195,6 +206,13 @@ public class ApplicationStatus {
ActivityInfo info = sActivityInfo.get(activity);
info.setStatus(newState);
+ // Remove before calling listeners so that isEveryActivityDestroyed() returns false when
+ // this was the last activity.
+ if (newState == ActivityState.DESTROYED) {
+ sActivityInfo.remove(activity);
+ if (activity == sActivity) sActivity = null;
+ }
+
// Notify all state observers that are specifically listening to this activity.
for (ActivityStateListener listener : info.getListeners()) {
listener.onActivityStateChange(activity, newState);
@@ -212,11 +230,6 @@ public class ApplicationStatus {
listener.onApplicationStateChange(applicationState);
}
}
-
- if (newState == ActivityState.DESTROYED) {
- sActivityInfo.remove(activity);
- if (activity == sActivity) sActivity = null;
- }
}
/**
@@ -289,6 +302,7 @@ public class ApplicationStatus {
* @param activity The activity whose state is to be returned.
* @return The state of the specified activity (see {@link ActivityState}).
*/
+ @ActivityStateEnum
public static int getStateForActivity(Activity activity) {
ActivityInfo info = sActivityInfo.get(activity);
return info != null ? info.getStatus() : ActivityState.DESTROYED;
@@ -297,6 +311,7 @@ public class ApplicationStatus {
/**
* @return The state of the application (see {@link ApplicationState}).
*/
+ @ApplicationStateEnum
@CalledByNative
public static int getStateForApplication() {
synchronized (sCachedApplicationStateLock) {
@@ -343,11 +358,19 @@ public class ApplicationStatus {
* @param listener Listener to receive state changes.
* @param activity Activity to track or {@code null} to track all activities.
*/
+ @SuppressLint("NewApi")
public static void registerStateListenerForActivity(ActivityStateListener listener,
Activity activity) {
assert activity != null;
ActivityInfo info = sActivityInfo.get(activity);
+ // TODO(tedchoc): crbug/691100. The timing of application callback lifecycles were changed
+ // in O and the activity info may need to be lazily created if the onCreate
+ // event has not yet been received.
+ if (BuildInfo.isAtLeastO() && info == null && !activity.isDestroyed()) {
+ info = new ActivityInfo();
+ sActivityInfo.put(activity, info);
+ }
assert info != null && info.getStatus() != ActivityState.DESTROYED;
info.getListeners().addObserver(listener);
}
@@ -430,6 +453,7 @@ public class ApplicationStatus {
* HAS_STOPPED_ACTIVITIES if none are running/paused and one is stopped.
* HAS_DESTROYED_ACTIVITIES if none are running/paused/stopped.
*/
+ @ApplicationStateEnum
private static int determineApplicationState() {
boolean hasPausedActivity = false;
boolean hasStoppedActivity = false;
@@ -454,5 +478,5 @@ public class ApplicationStatus {
// Called to notify the native side of state changes.
// IMPORTANT: This is always called on the main thread!
- private static native void nativeOnApplicationStateChange(int newState);
+ private static native void nativeOnApplicationStateChange(@ApplicationStateEnum int newState);
}
diff --git a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
index 44c69dc..6b97bdd 100644
--- a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
+++ b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
@@ -10,6 +10,7 @@ import android.content.Context;
import android.os.Bundle;
import android.view.Window;
+import org.chromium.base.annotations.SuppressFBWarnings;
import org.chromium.base.multidex.ChromiumMultiDexInstaller;
import java.lang.reflect.InvocationHandler;
@@ -21,8 +22,7 @@ import java.lang.reflect.Proxy;
* Basic application functionality that should be shared among all browser applications.
*/
public class BaseChromiumApplication extends Application {
-
- private static final String TAG = "cr.base";
+ private static final String TAG = "base";
private static final String TOOLBAR_CALLBACK_INTERNAL_WRAPPER_CLASS =
"android.support.v7.internal.app.ToolbarActionBar$ToolbarCallbackWrapper";
// In builds using the --use_unpublished_apis flag, the ToolbarActionBar class name does not
@@ -42,6 +42,8 @@ public class BaseChromiumApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
+ assert getBaseContext() != null;
+ checkAppBeingReplaced();
ChromiumMultiDexInstaller.install(this);
}
@@ -58,7 +60,7 @@ public class BaseChromiumApplication extends Application {
}
private ObserverList<WindowFocusChangedListener> mWindowFocusListeners =
- new ObserverList<WindowFocusChangedListener>();
+ new ObserverList<>();
/**
* Intercepts calls to an existing Window.Callback. Most invocations are passed on directly
@@ -144,6 +146,18 @@ public class BaseChromiumApplication extends Application {
((BaseChromiumApplication) context.getApplicationContext()).initCommandLine();
}
+ /** Ensure this application object is not out-of-date. */
+ @SuppressFBWarnings("DM_EXIT")
+ private void checkAppBeingReplaced() {
+ // During app update the old apk can still be triggered by broadcasts and spin up an
+ // out-of-date application. Kill old applications in this bad state. See
+ // http://crbug.com/658130 for more context and http://b.android.com/56296 for the bug.
+ if (getResources() == null) {
+ Log.e(TAG, "getResources() null, closing app.");
+ System.exit(0);
+ }
+ }
+
/** Register hooks and listeners to start tracking the application status. */
private void startTrackingApplicationStatus() {
ApplicationStatus.initialize(this);
@@ -158,7 +172,7 @@ public class BaseChromiumApplication extends Application {
@Override
public void onActivityDestroyed(Activity activity) {
- if (BuildConfig.IS_DEBUG) {
+ if (BuildConfig.DCHECK_IS_ON) {
assert (Proxy.isProxyClass(activity.getWindow().getCallback().getClass())
|| activity.getWindow().getCallback().getClass().getName().equals(
TOOLBAR_CALLBACK_WRAPPER_CLASS)
@@ -169,7 +183,7 @@ public class BaseChromiumApplication extends Application {
@Override
public void onActivityPaused(Activity activity) {
- if (BuildConfig.IS_DEBUG) {
+ if (BuildConfig.DCHECK_IS_ON) {
assert (Proxy.isProxyClass(activity.getWindow().getCallback().getClass())
|| activity.getWindow().getCallback().getClass().getName().equals(
TOOLBAR_CALLBACK_WRAPPER_CLASS)
@@ -180,7 +194,7 @@ public class BaseChromiumApplication extends Application {
@Override
public void onActivityResumed(Activity activity) {
- if (BuildConfig.IS_DEBUG) {
+ if (BuildConfig.DCHECK_IS_ON) {
assert (Proxy.isProxyClass(activity.getWindow().getCallback().getClass())
|| activity.getWindow().getCallback().getClass().getName().equals(
TOOLBAR_CALLBACK_WRAPPER_CLASS)
@@ -191,7 +205,7 @@ public class BaseChromiumApplication extends Application {
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
- if (BuildConfig.IS_DEBUG) {
+ if (BuildConfig.DCHECK_IS_ON) {
assert (Proxy.isProxyClass(activity.getWindow().getCallback().getClass())
|| activity.getWindow().getCallback().getClass().getName().equals(
TOOLBAR_CALLBACK_WRAPPER_CLASS)
@@ -202,7 +216,7 @@ public class BaseChromiumApplication extends Application {
@Override
public void onActivityStarted(Activity activity) {
- if (BuildConfig.IS_DEBUG) {
+ if (BuildConfig.DCHECK_IS_ON) {
assert (Proxy.isProxyClass(activity.getWindow().getCallback().getClass())
|| activity.getWindow().getCallback().getClass().getName().equals(
TOOLBAR_CALLBACK_WRAPPER_CLASS)
@@ -213,7 +227,7 @@ public class BaseChromiumApplication extends Application {
@Override
public void onActivityStopped(Activity activity) {
- if (BuildConfig.IS_DEBUG) {
+ if (BuildConfig.DCHECK_IS_ON) {
assert (Proxy.isProxyClass(activity.getWindow().getCallback().getClass())
|| activity.getWindow().getCallback().getClass().getName().equals(
TOOLBAR_CALLBACK_WRAPPER_CLASS)
diff --git a/base/android/java/src/org/chromium/base/BuildInfo.java b/base/android/java/src/org/chromium/base/BuildInfo.java
index ea6a019..141b62b 100644
--- a/base/android/java/src/org/chromium/base/BuildInfo.java
+++ b/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -11,7 +11,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.StrictMode;
-import android.util.Log;
import org.chromium.base.annotations.CalledByNative;
@@ -72,7 +71,7 @@ public class BuildInfo {
PackageInfo packageInfo = packageManager.getPackageInfo("com.google.android.gms", 0);
msg = Integer.toString(packageInfo.versionCode);
} catch (NameNotFoundException e) {
- Log.d(TAG, "GMS package is not found: %s", e);
+ Log.d(TAG, "GMS package is not found.", e);
}
return msg;
}
@@ -137,6 +136,13 @@ public class BuildInfo {
return Build.TYPE;
}
+ /**
+ * Check if this is a debuggable build of Android. Use this to enable developer-only features.
+ */
+ public static boolean isDebugAndroid() {
+ return "eng".equals(Build.TYPE) || "userdebug".equals(Build.TYPE);
+ }
+
@CalledByNative
public static int getSdkInt() {
return Build.VERSION.SDK_INT;
@@ -148,4 +154,21 @@ public class BuildInfo {
public static boolean isGreaterThanN() {
return Build.VERSION.SDK_INT > 24 || Build.VERSION.CODENAME.equals("NMR1");
}
+
+ /**
+ * @return Whether the current device is running Android O release or newer.
+ */
+ public static boolean isAtLeastO() {
+ return !"REL".equals(Build.VERSION.CODENAME)
+ && ("O".equals(Build.VERSION.CODENAME) || Build.VERSION.CODENAME.startsWith("OMR"));
+ }
+
+ /**
+ * @return Whether the current app targets the SDK for at least O
+ */
+ public static boolean targetsAtLeastO(Context appContext) {
+ return isAtLeastO()
+ && appContext.getApplicationInfo().targetSdkVersion
+ == Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
}
diff --git a/base/android/java/src/org/chromium/base/CommandLine.java b/base/android/java/src/org/chromium/base/CommandLine.java
index efef22a..b6246f3 100644
--- a/base/android/java/src/org/chromium/base/CommandLine.java
+++ b/base/android/java/src/org/chromium/base/CommandLine.java
@@ -134,8 +134,8 @@ public abstract class CommandLine {
* @param file The fully qualified command line file.
*/
public static void initFromFile(String file) {
- // Arbitrary clamp of 8k on the amount of file we read in.
- char[] buffer = readUtf8FileFully(file, 8 * 1024);
+ // Arbitrary clamp of 16k on the amount of file we read in.
+ char[] buffer = readUtf8FileFullyCrashIfTooBig(file, 16 * 1024);
init(buffer == null ? null : tokenizeQuotedAruments(buffer));
}
@@ -238,10 +238,10 @@ public abstract class CommandLine {
/**
* @param fileName the file to read in.
* @param sizeLimit cap on the file size.
- * @return Array of chars read from the file, or null if the file cannot be read
- * or if its length exceeds |sizeLimit|.
+ * @return Array of chars read from the file, or null if the file cannot be read.
+ * @throws RuntimeException if the file size exceeds |sizeLimit|.
*/
- private static char[] readUtf8FileFully(String fileName, int sizeLimit) {
+ private static char[] readUtf8FileFullyCrashIfTooBig(String fileName, int sizeLimit) {
Reader reader = null;
File f = new File(fileName);
long fileLength = f.length();
@@ -251,9 +251,8 @@ public abstract class CommandLine {
}
if (fileLength > sizeLimit) {
- Log.w(TAG, "File " + fileName + " length " + fileLength + " exceeds limit "
- + sizeLimit);
- return null;
+ throw new RuntimeException(
+ "File " + fileName + " length " + fileLength + " exceeds limit " + sizeLimit);
}
try {
diff --git a/base/android/java/src/org/chromium/base/CommandLineInitUtil.java b/base/android/java/src/org/chromium/base/CommandLineInitUtil.java
index 6aa227c..bec9b40 100644
--- a/base/android/java/src/org/chromium/base/CommandLineInitUtil.java
+++ b/base/android/java/src/org/chromium/base/CommandLineInitUtil.java
@@ -51,7 +51,9 @@ public final class CommandLineInitUtil {
public static void initCommandLine(Context context, String fileName) {
if (!CommandLine.isInitialized()) {
File commandLineFile = getAlternativeCommandLinePath(context, fileName);
- if (commandLineFile == null) {
+ if (commandLineFile != null) {
+ Log.i(TAG, "Using alternative command line file in " + commandLineFile.getPath());
+ } else {
commandLineFile = new File(COMMAND_LINE_FILE_PATH, fileName);
}
CommandLine.initFromFile(commandLineFile.getPath());
@@ -59,7 +61,9 @@ public final class CommandLineInitUtil {
}
/**
- * Use an alternative path if adb is enabled and this is the debug app.
+ * Use an alternative path if:
+ * - The current build is "eng" or "userdebug", OR
+ * - adb is enabled and this is the debug app.
*/
@SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME")
private static File getAlternativeCommandLinePath(Context context, String fileName) {
@@ -67,13 +71,15 @@ public final class CommandLineInitUtil {
new File(COMMAND_LINE_FILE_PATH_DEBUG_APP, fileName);
if (!alternativeCommandLineFile.exists()) return null;
try {
+ if (BuildInfo.isDebugAndroid()) {
+ return alternativeCommandLineFile;
+ }
+
String debugApp = Build.VERSION.SDK_INT < 17
? getDebugAppPreJBMR1(context) : getDebugAppJBMR1(context);
if (debugApp != null
&& debugApp.equals(context.getApplicationContext().getPackageName())) {
- Log.i(TAG, "Using alternative command line file in "
- + alternativeCommandLineFile.getPath());
return alternativeCommandLineFile;
}
} catch (RuntimeException e) {
diff --git a/base/android/java/src/org/chromium/base/ContentUriUtils.java b/base/android/java/src/org/chromium/base/ContentUriUtils.java
index 5448aa0..9253f28 100644
--- a/base/android/java/src/org/chromium/base/ContentUriUtils.java
+++ b/base/android/java/src/org/chromium/base/ContentUriUtils.java
@@ -6,15 +6,20 @@ package org.chromium.base;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract;
import android.util.Log;
+import android.webkit.MimeTypeMap;
import org.chromium.base.annotations.CalledByNative;
import java.io.File;
import java.io.FileNotFoundException;
+import java.io.IOException;
/**
* This class provides methods to access content URI schemes.
@@ -67,9 +72,9 @@ public abstract class ContentUriUtils {
*/
@CalledByNative
public static int openContentUriForRead(Context context, String uriString) {
- ParcelFileDescriptor pfd = getParcelFileDescriptor(context, uriString);
- if (pfd != null) {
- return pfd.detachFd();
+ AssetFileDescriptor afd = getAssetFileDescriptor(context, uriString);
+ if (afd != null) {
+ return afd.getParcelFileDescriptor().detachFd();
}
return -1;
}
@@ -83,7 +88,21 @@ public abstract class ContentUriUtils {
*/
@CalledByNative
public static boolean contentUriExists(Context context, String uriString) {
- return getParcelFileDescriptor(context, uriString) != null;
+ AssetFileDescriptor asf = null;
+ try {
+ asf = getAssetFileDescriptor(context, uriString);
+ return asf != null;
+ } finally {
+ // Do not use StreamUtil.closeQuietly here, as AssetFileDescriptor
+ // does not implement Closeable until KitKat.
+ if (asf != null) {
+ try {
+ asf.close();
+ } catch (IOException e) {
+ // Closing quietly.
+ }
+ }
+ }
}
/**
@@ -96,8 +115,11 @@ public abstract class ContentUriUtils {
@CalledByNative
public static String getMimeType(Context context, String uriString) {
ContentResolver resolver = context.getContentResolver();
- if (resolver == null) return null;
Uri uri = Uri.parse(uriString);
+ if (isVirtualDocument(uri, context)) {
+ String[] streamTypes = resolver.getStreamTypes(uri, "*/*");
+ return (streamTypes != null && streamTypes.length > 0) ? streamTypes[0] : null;
+ }
return resolver.getType(uri);
}
@@ -106,15 +128,36 @@ public abstract class ContentUriUtils {
*
* @param context {@link Context} in interest.
* @param uriString the content URI to open.
- * @return ParcelFileDescriptor of the content URI, or NULL if the file does not exist.
+ * @return AssetFileDescriptor of the content URI, or NULL if the file does not exist.
*/
- private static ParcelFileDescriptor getParcelFileDescriptor(Context context, String uriString) {
+ private static AssetFileDescriptor getAssetFileDescriptor(Context context, String uriString) {
ContentResolver resolver = context.getContentResolver();
Uri uri = Uri.parse(uriString);
- ParcelFileDescriptor pfd = null;
try {
- pfd = resolver.openFileDescriptor(uri, "r");
+ if (isVirtualDocument(uri, context)) {
+ String[] streamTypes = resolver.getStreamTypes(uri, "*/*");
+ if (streamTypes != null && streamTypes.length > 0) {
+ AssetFileDescriptor afd =
+ resolver.openTypedAssetFileDescriptor(uri, streamTypes[0], null);
+ if (afd.getStartOffset() != 0) {
+ // Do not use StreamUtil.closeQuietly here, as AssetFileDescriptor
+ // does not implement Closeable until KitKat.
+ try {
+ afd.close();
+ } catch (IOException e) {
+ // Closing quietly.
+ }
+ throw new SecurityException("Cannot open files with non-zero offset type.");
+ }
+ return afd;
+ }
+ } else {
+ ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r");
+ if (pfd != null) {
+ return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH);
+ }
+ }
} catch (FileNotFoundException e) {
Log.w(TAG, "Cannot find content uri: " + uriString, e);
} catch (SecurityException e) {
@@ -124,37 +167,103 @@ public abstract class ContentUriUtils {
} catch (IllegalStateException e) {
Log.w(TAG, "Unknown content uri: " + uriString, e);
}
- return pfd;
+
+ return null;
}
/**
* Method to resolve the display name of a content URI.
*
* @param uri the content URI to be resolved.
- * @param contentResolver the content resolver to query.
+ * @param context {@link Context} in interest.
* @param columnField the column field to query.
* @return the display name of the @code uri if present in the database
* or an empty string otherwise.
*/
- public static String getDisplayName(
- Uri uri, ContentResolver contentResolver, String columnField) {
- if (contentResolver == null || uri == null) return "";
+ public static String getDisplayName(Uri uri, Context context, String columnField) {
+ if (uri == null) return "";
+ ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = null;
try {
cursor = contentResolver.query(uri, null, null, null, null);
if (cursor != null && cursor.getCount() >= 1) {
cursor.moveToFirst();
- int index = cursor.getColumnIndex(columnField);
- if (index > -1) return cursor.getString(index);
+ int displayNameIndex = cursor.getColumnIndex(columnField);
+ if (displayNameIndex == -1) {
+ return "";
+ }
+ String displayName = cursor.getString(displayNameIndex);
+ // For Virtual documents, try to modify the file extension so it's compatible
+ // with the alternative MIME type.
+ if (hasVirtualFlag(cursor)) {
+ String[] mimeTypes = contentResolver.getStreamTypes(uri, "*/*");
+ if (mimeTypes != null && mimeTypes.length > 0) {
+ String ext =
+ MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeTypes[0]);
+ if (ext != null) {
+ // Just append, it's simpler and more secure than altering an
+ // existing extension.
+ displayName += "." + ext;
+ }
+ }
+ }
+ return displayName;
}
} catch (NullPointerException e) {
// Some android models don't handle the provider call correctly.
// see crbug.com/345393
return "";
} finally {
- if (cursor != null) cursor.close();
+ StreamUtil.closeQuietly(cursor);
}
return "";
}
+
+ /**
+ * Checks whether the passed Uri represents a virtual document.
+ *
+ * @param uri the content URI to be resolved.
+ * @param contentResolver the content resolver to query.
+ * @return True for virtual file, false for any other file.
+ */
+ private static boolean isVirtualDocument(Uri uri, Context context) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return false;
+ if (uri == null) return false;
+ if (!DocumentsContract.isDocumentUri(context, uri)) return false;
+ ContentResolver contentResolver = context.getContentResolver();
+ Cursor cursor = null;
+ try {
+ cursor = contentResolver.query(uri, null, null, null, null);
+
+ if (cursor != null && cursor.getCount() >= 1) {
+ cursor.moveToFirst();
+ return hasVirtualFlag(cursor);
+ }
+ } catch (NullPointerException e) {
+ // Some android models don't handle the provider call correctly.
+ // see crbug.com/345393
+ return false;
+ } finally {
+ StreamUtil.closeQuietly(cursor);
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether the passed cursor for a document has a virtual document flag.
+ *
+ * The called must close the passed cursor.
+ *
+ * @param cursor Cursor with COLUMN_FLAGS.
+ * @return True for virtual file, false for any other file.
+ */
+ private static boolean hasVirtualFlag(Cursor cursor) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return false;
+ int index = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_FLAGS);
+ if (index > -1) {
+ return (cursor.getLong(index) & DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT) != 0;
+ }
+ return false;
+ }
}
diff --git a/base/android/java/src/org/chromium/base/ContextUtils.java b/base/android/java/src/org/chromium/base/ContextUtils.java
index 4b615cb..448eff9 100644
--- a/base/android/java/src/org/chromium/base/ContextUtils.java
+++ b/base/android/java/src/org/chromium/base/ContextUtils.java
@@ -9,11 +9,13 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.MainDex;
/**
* This class provides Android application context related utility methods.
*/
@JNINamespace("base::android")
+@MainDex
public class ContextUtils {
private static final String TAG = "ContextUtils";
private static Context sApplicationContext;
diff --git a/base/android/java/src/org/chromium/base/FileUtils.java b/base/android/java/src/org/chromium/base/FileUtils.java
index 2c0d8f5..2ad70dd 100644
--- a/base/android/java/src/org/chromium/base/FileUtils.java
+++ b/base/android/java/src/org/chromium/base/FileUtils.java
@@ -12,6 +12,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.List;
/**
* Helper methods for dealing with Files.
@@ -37,6 +38,18 @@ public class FileUtils {
}
/**
+ * Delete the given files or directories by calling {@link #recursivelyDeleteFile(File)}.
+ * @param files The files to delete.
+ */
+ public static void batchDeleteFiles(List<File> files) {
+ assert !ThreadUtils.runningOnUiThread();
+
+ for (File file : files) {
+ if (file.exists()) recursivelyDeleteFile(file);
+ }
+ }
+
+ /**
* Extracts an asset from the app's APK to a file.
* @param context
* @param assetName Name of the asset to extract.
diff --git a/base/android/java/src/org/chromium/base/JNIUtils.java b/base/android/java/src/org/chromium/base/JNIUtils.java
index f971b5e..3fcec91 100644
--- a/base/android/java/src/org/chromium/base/JNIUtils.java
+++ b/base/android/java/src/org/chromium/base/JNIUtils.java
@@ -12,6 +12,8 @@ import org.chromium.base.annotations.MainDex;
*/
@MainDex
public class JNIUtils {
+ private static Boolean sSelectiveJniRegistrationEnabled;
+
/**
* This returns a ClassLoader that is capable of loading Chromium Java code. Such a ClassLoader
* is needed for the few cases where the JNI mechanism is unable to automatically determine the
@@ -21,4 +23,24 @@ public class JNIUtils {
public static Object getClassLoader() {
return JNIUtils.class.getClassLoader();
}
+
+ /**
+ * @return whether or not the current process supports selective JNI registration.
+ */
+ @CalledByNative
+ public static boolean isSelectiveJniRegistrationEnabled() {
+ if (sSelectiveJniRegistrationEnabled == null) {
+ sSelectiveJniRegistrationEnabled = false;
+ }
+ return sSelectiveJniRegistrationEnabled;
+ }
+
+ /**
+ * Allow this process to selectively perform JNI registration. This must be called before
+ * loading native libraries or it will have no effect.
+ */
+ public static void enableSelectiveJniRegistration() {
+ assert sSelectiveJniRegistrationEnabled == null;
+ sSelectiveJniRegistrationEnabled = true;
+ }
}
diff --git a/base/android/java/src/org/chromium/base/LocaleUtils.java b/base/android/java/src/org/chromium/base/LocaleUtils.java
index 5c26e7a..2f51455 100644
--- a/base/android/java/src/org/chromium/base/LocaleUtils.java
+++ b/base/android/java/src/org/chromium/base/LocaleUtils.java
@@ -4,9 +4,18 @@
package org.chromium.base;
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.os.LocaleList;
+import android.text.TextUtils;
+
import org.chromium.base.annotations.CalledByNative;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Locale;
+import java.util.Map;
/**
* This class provides the locale related methods.
@@ -18,41 +27,176 @@ public class LocaleUtils {
private LocaleUtils() {
}
+ private static final Map<String, String> LANGUAGE_MAP_FOR_CHROMIUM;
+ private static final Map<String, String> LANGUAGE_MAP_FOR_ANDROID;
+
+ static {
+ // A variation of this mapping also exists in:
+ // build/android/gyp/package_resources.py
+ HashMap<String, String> mapForChromium = new HashMap<>();
+ mapForChromium.put("iw", "he"); // Hebrew
+ mapForChromium.put("ji", "yi"); // Yiddish
+ mapForChromium.put("in", "id"); // Indonesian
+ mapForChromium.put("tl", "fil"); // Filipino
+ LANGUAGE_MAP_FOR_CHROMIUM = Collections.unmodifiableMap(mapForChromium);
+ }
+
+ static {
+ HashMap<String, String> mapForAndroid = new HashMap<>();
+ mapForAndroid.put("und", ""); // Undefined
+ mapForAndroid.put("fil", "tl"); // Filipino
+ LANGUAGE_MAP_FOR_ANDROID = Collections.unmodifiableMap(mapForAndroid);
+ }
+
/**
- * @return the string for the given locale, translating
- * Android deprecated language codes into the modern ones
- * used by Chromium.
+ * Java keeps deprecated language codes for Hebrew, Yiddish and Indonesian but Chromium uses
+ * updated ones. Similarly, Android uses "tl" while Chromium uses "fil" for Tagalog/Filipino.
+ * So apply a mapping here.
+ * See http://developer.android.com/reference/java/util/Locale.html
+ * @return a updated language code for Chromium with given language string.
*/
- public static String getLocale(Locale locale) {
- String language = locale.getLanguage();
- String country = locale.getCountry();
+ public static String getUpdatedLanguageForChromium(String language) {
+ String updatedLanguageCode = LANGUAGE_MAP_FOR_CHROMIUM.get(language);
+ return updatedLanguageCode == null ? language : updatedLanguageCode;
+ }
+
+ /**
+ * @return a locale with updated language codes for Chromium, with translated modern language
+ * codes used by Chromium.
+ */
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ @VisibleForTesting
+ public static Locale getUpdatedLocaleForChromium(Locale locale) {
+ String languageForChrome = LANGUAGE_MAP_FOR_CHROMIUM.get(locale.getLanguage());
+ if (languageForChrome == null) {
+ return locale;
+ }
+ return new Locale.Builder().setLocale(locale).setLanguage(languageForChrome).build();
+ }
+
+ /**
+ * Android uses "tl" while Chromium uses "fil" for Tagalog/Filipino.
+ * So apply a mapping here.
+ * See http://developer.android.com/reference/java/util/Locale.html
+ * @return a updated language code for Android with given language string.
+ */
+ public static String getUpdatedLanguageForAndroid(String language) {
+ String updatedLanguageCode = LANGUAGE_MAP_FOR_ANDROID.get(language);
+ return updatedLanguageCode == null ? language : updatedLanguageCode;
+ }
+
+ /**
+ * @return a locale with updated language codes for Android, from translated modern language
+ * codes used by Chromium.
+ */
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ @VisibleForTesting
+ public static Locale getUpdatedLocaleForAndroid(Locale locale) {
+ String languageForAndroid = LANGUAGE_MAP_FOR_ANDROID.get(locale.getLanguage());
+ if (languageForAndroid == null) {
+ return locale;
+ }
+ return new Locale.Builder().setLocale(locale).setLanguage(languageForAndroid).build();
+ }
+
+ /**
+ * This function creates a Locale object from xx-XX style string where xx is language code
+ * and XX is a country code. This works for API level lower than 21.
+ * @return the locale that best represents the language tag.
+ */
+ public static Locale forLanguageTagCompat(String languageTag) {
+ String[] tag = languageTag.split("-");
+ if (tag.length == 0) {
+ return new Locale("");
+ }
+ String language = getUpdatedLanguageForAndroid(tag[0]);
+ if ((language.length() != 2 && language.length() != 3) || language.equals("und")) {
+ return new Locale("");
+ }
+ if (tag.length == 1) {
+ return new Locale(language);
+ }
+ String country = tag[1];
+ if (country.length() != 2 && country.length() != 3) {
+ return new Locale(language);
+ }
+ return new Locale(language, country);
+ }
- // Android uses deprecated lanuages codes for Hebrew and Indonesian but Chromium uses the
- // updated codes. Also, Android uses "tl" while Chromium uses "fil" for Tagalog/Filipino.
- // So apply a mapping.
- // See http://developer.android.com/reference/java/util/Locale.html
- if ("iw".equals(language)) {
- language = "he";
- } else if ("in".equals(language)) {
- language = "id";
- } else if ("tl".equals(language)) {
- language = "fil";
+ /**
+ * This function creates a Locale object from xx-XX style string where xx is language code
+ * and XX is a country code.
+ * @return the locale that best represents the language tag.
+ */
+ public static Locale forLanguageTag(String languageTag) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ Locale locale = Locale.forLanguageTag(languageTag);
+ return getUpdatedLocaleForAndroid(locale);
+ }
+ return forLanguageTagCompat(languageTag);
+ }
+
+ /**
+ * Converts Locale object to the BCP 47 compliant string format.
+ * This works for API level lower than 24.
+ *
+ * Note that for Android M or before, we cannot use Locale.getLanguage() and
+ * Locale.toLanguageTag() for this purpose. Since Locale.getLanguage() returns deprecated
+ * language code even if the Locale object is constructed with updated language code. As for
+ * Locale.toLanguageTag(), it does a special conversion from deprecated language code to updated
+ * one, but it is only usable for Android N or after.
+ * @return a well-formed IETF BCP 47 language tag with language and country code that
+ * represents this locale.
+ */
+ public static String toLanguageTag(Locale locale) {
+ String language = getUpdatedLanguageForChromium(locale.getLanguage());
+ String country = locale.getCountry();
+ if (language.equals("no") && country.equals("NO") && locale.getVariant().equals("NY")) {
+ return "nn-NO";
}
return country.isEmpty() ? language : language + "-" + country;
}
/**
- * @return the default locale, translating Android deprecated
- * language codes into the modern ones used by Chromium.
+ * Converts LocaleList object to the comma separated BCP 47 compliant string format.
+ *
+ * @return a well-formed IETF BCP 47 language tag with language and country code that
+ * represents this locale list.
+ */
+ @TargetApi(Build.VERSION_CODES.N)
+ public static String toLanguageTags(LocaleList localeList) {
+ ArrayList<String> newLocaleList = new ArrayList<>();
+ for (int i = 0; i < localeList.size(); i++) {
+ Locale locale = getUpdatedLocaleForChromium(localeList.get(i));
+ newLocaleList.add(toLanguageTag(locale));
+ }
+ return TextUtils.join(",", newLocaleList);
+ }
+
+ /**
+ * @return a comma separated language tags string that represents a default locale.
+ * Each language tag is well-formed IETF BCP 47 language tag with language and country
+ * code.
*/
@CalledByNative
- public static String getDefaultLocale() {
- return getLocale(Locale.getDefault());
+ public static String getDefaultLocaleString() {
+ return toLanguageTag(Locale.getDefault());
+ }
+
+ /**
+ * @return a comma separated language tags string that represents a default locale or locales.
+ * Each language tag is well-formed IETF BCP 47 language tag with language and country
+ * code.
+ */
+ public static String getDefaultLocaleListString() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ return toLanguageTags(LocaleList.getDefault());
+ }
+ return getDefaultLocaleString();
}
/**
- * Get the default country code set during install.
- * @return country code.
+ * @return The default country code set during install.
*/
@CalledByNative
private static String getDefaultCountryCode() {
diff --git a/base/android/java/src/org/chromium/base/Log.java b/base/android/java/src/org/chromium/base/Log.java
index 8815e63..399f16d 100644
--- a/base/android/java/src/org/chromium/base/Log.java
+++ b/base/android/java/src/org/chromium/base/Log.java
@@ -347,6 +347,11 @@ public class Log {
}
}
+ /** Handy function to get a loggable stack trace from a Throwable. */
+ public static String getStackTraceString(Throwable tr) {
+ return android.util.Log.getStackTraceString(tr);
+ }
+
private static Throwable getThrowableToLog(Object[] args) {
if (args == null || args.length == 0) return null;
diff --git a/base/android/java/src/org/chromium/base/ObserverList.java b/base/android/java/src/org/chromium/base/ObserverList.java
index 7a2ab98..59276c6 100644
--- a/base/android/java/src/org/chromium/base/ObserverList.java
+++ b/base/android/java/src/org/chromium/base/ObserverList.java
@@ -21,7 +21,7 @@ import javax.annotation.concurrent.NotThreadSafe;
* The implementation (and the interface) is heavily influenced by the C++ ObserverList.
* Notable differences:
* - The iterator implements NOTIFY_EXISTING_ONLY.
- * - The FOR_EACH_OBSERVER closure is left to the clients to implement in terms of iterator().
+ * - The range-based for loop is left to the clients to implement in terms of iterator().
* <p/>
* This class is not threadsafe. Observers MUST be added, removed and will be notified on the same
* thread this is created.
@@ -44,9 +44,9 @@ public class ObserverList<E> implements Iterable<E> {
}
public final List<E> mObservers = new ArrayList<E>();
- private int mIterationDepth = 0;
- private int mCount = 0;
- private boolean mNeedsCompact = false;
+ private int mIterationDepth;
+ private int mCount;
+ private boolean mNeedsCompact;
public ObserverList() {}
@@ -190,8 +190,8 @@ public class ObserverList<E> implements Iterable<E> {
private class ObserverListIterator implements RewindableIterator<E> {
private int mListEndMarker;
- private int mIndex = 0;
- private boolean mIsExhausted = false;
+ private int mIndex;
+ private boolean mIsExhausted;
private ObserverListIterator() {
ObserverList.this.incrementIterationDepth();
diff --git a/base/android/java/src/org/chromium/base/PathUtils.java b/base/android/java/src/org/chromium/base/PathUtils.java
index c3d3e7e..00977d5 100644
--- a/base/android/java/src/org/chromium/base/PathUtils.java
+++ b/base/android/java/src/org/chromium/base/PathUtils.java
@@ -34,13 +34,9 @@ public abstract class PathUtils {
private static final AtomicBoolean sInitializationStarted = new AtomicBoolean();
private static AsyncTask<Void, Void, String[]> sDirPathFetchTask;
- // In setPrivateDataDirectorySuffix(), we store the app's context. If the AsyncTask started in
- // setPrivateDataDirectorySuffix() fails to complete by the time we need the values, we will
- // need the context so that we can restart the task synchronously on the UI thread.
- private static Context sDataDirectoryAppContext;
-
- // We also store the directory path suffix from setPrivateDataDirectorySuffix() for the same
- // reason as above.
+ // If the AsyncTask started in setPrivateDataDirectorySuffix() fails to complete by the time we
+ // need the values, we will need the suffix so that we can restart the task synchronously on
+ // the UI thread.
private static String sDataDirectorySuffix;
// Prevent instantiation.
@@ -101,13 +97,14 @@ public abstract class PathUtils {
*/
private static String[] setPrivateDataDirectorySuffixInternal() {
String[] paths = new String[NUM_DIRECTORIES];
- paths[DATA_DIRECTORY] = sDataDirectoryAppContext.getDir(sDataDirectorySuffix,
- Context.MODE_PRIVATE).getPath();
- paths[THUMBNAIL_DIRECTORY] = sDataDirectoryAppContext.getDir(
+ Context appContext = ContextUtils.getApplicationContext();
+ paths[DATA_DIRECTORY] = appContext.getDir(
+ sDataDirectorySuffix, Context.MODE_PRIVATE).getPath();
+ paths[THUMBNAIL_DIRECTORY] = appContext.getDir(
THUMBNAIL_DIRECTORY_NAME, Context.MODE_PRIVATE).getPath();
- paths[DATABASE_DIRECTORY] = sDataDirectoryAppContext.getDatabasePath("foo").getParent();
- if (sDataDirectoryAppContext.getCacheDir() != null) {
- paths[CACHE_DIRECTORY] = sDataDirectoryAppContext.getCacheDir().getPath();
+ paths[DATABASE_DIRECTORY] = appContext.getDatabasePath("foo").getParent();
+ if (appContext.getCacheDir() != null) {
+ paths[CACHE_DIRECTORY] = appContext.getCacheDir().getPath();
}
return paths;
}
@@ -124,12 +121,12 @@ public abstract class PathUtils {
* @param suffix The private data directory suffix.
* @see Context#getDir(String, int)
*/
- public static void setPrivateDataDirectorySuffix(String suffix, Context context) {
+ public static void setPrivateDataDirectorySuffix(String suffix) {
// This method should only be called once, but many tests end up calling it multiple times,
// so adding a guard here.
if (!sInitializationStarted.getAndSet(true)) {
+ assert ContextUtils.getApplicationContext() != null;
sDataDirectorySuffix = suffix;
- sDataDirectoryAppContext = context.getApplicationContext();
sDirPathFetchTask = new AsyncTask<Void, Void, String[]>() {
@Override
protected String[] doInBackground(Void... unused) {
@@ -151,7 +148,7 @@ public abstract class PathUtils {
* @return the private directory that is used to store application data.
*/
@CalledByNative
- public static String getDataDirectory(Context appContext) {
+ public static String getDataDirectory() {
assert sDirPathFetchTask != null : "setDataDirectorySuffix must be called first.";
return getDirectoryPath(DATA_DIRECTORY);
}
@@ -160,7 +157,7 @@ public abstract class PathUtils {
* @return the private directory that is used to store application database.
*/
@CalledByNative
- public static String getDatabaseDirectory(Context appContext) {
+ public static String getDatabaseDirectory() {
assert sDirPathFetchTask != null : "setDataDirectorySuffix must be called first.";
return getDirectoryPath(DATABASE_DIRECTORY);
}
@@ -168,15 +165,14 @@ public abstract class PathUtils {
/**
* @return the cache directory.
*/
- @SuppressWarnings("unused")
@CalledByNative
- public static String getCacheDirectory(Context appContext) {
+ public static String getCacheDirectory() {
assert sDirPathFetchTask != null : "setDataDirectorySuffix must be called first.";
return getDirectoryPath(CACHE_DIRECTORY);
}
@CalledByNative
- public static String getThumbnailCacheDirectory(Context appContext) {
+ public static String getThumbnailCacheDirectory() {
assert sDirPathFetchTask != null : "setDataDirectorySuffix must be called first.";
return getDirectoryPath(THUMBNAIL_DIRECTORY);
}
@@ -186,7 +182,7 @@ public abstract class PathUtils {
*/
@SuppressWarnings("unused")
@CalledByNative
- private static String getDownloadsDirectory(Context appContext) {
+ private static String getDownloadsDirectory() {
// Temporarily allowing disk access while fixing. TODO: http://crbug.com/508615
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
String downloadsPath;
@@ -207,8 +203,8 @@ public abstract class PathUtils {
*/
@SuppressWarnings("unused")
@CalledByNative
- private static String getNativeLibraryDirectory(Context appContext) {
- ApplicationInfo ai = appContext.getApplicationInfo();
+ private static String getNativeLibraryDirectory() {
+ ApplicationInfo ai = ContextUtils.getApplicationContext().getApplicationInfo();
if ((ai.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0
|| (ai.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
return ai.nativeLibraryDir;
diff --git a/base/android/java/src/org/chromium/base/PerfTraceEvent.java b/base/android/java/src/org/chromium/base/PerfTraceEvent.java
index c0e4b21..8a87773 100644
--- a/base/android/java/src/org/chromium/base/PerfTraceEvent.java
+++ b/base/android/java/src/org/chromium/base/PerfTraceEvent.java
@@ -8,12 +8,12 @@ import android.os.Debug;
import android.os.Debug.MemoryInfo;
import android.util.Log;
-import org.chromium.base.annotations.SuppressFBWarnings;
-
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import org.chromium.base.annotations.SuppressFBWarnings;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -42,7 +42,7 @@ import java.util.List;
public class PerfTraceEvent {
private static final int MAX_NAME_LENGTH = 40;
private static final String MEMORY_TRACE_NAME_SUFFIX = "_BZR_PSS";
- private static File sOutputFile = null;
+ private static File sOutputFile;
/** The event types understood by the perf trace scripts. */
private enum EventType {
@@ -63,9 +63,9 @@ public class PerfTraceEvent {
}
}
- private static boolean sEnabled = false;
+ private static boolean sEnabled;
private static boolean sTrackTiming = true;
- private static boolean sTrackMemory = false;
+ private static boolean sTrackMemory;
// A list of performance trace event strings.
// Events are stored as a JSON dict much like TraceEvent.
diff --git a/base/android/java/src/org/chromium/base/PowerMonitor.java b/base/android/java/src/org/chromium/base/PowerMonitor.java
index 5d8fa0c..ae36a75 100644
--- a/base/android/java/src/org/chromium/base/PowerMonitor.java
+++ b/base/android/java/src/org/chromium/base/PowerMonitor.java
@@ -4,74 +4,61 @@
package org.chromium.base;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
-import android.os.Handler;
-import android.os.Looper;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
-
/**
* Integrates native PowerMonitor with the java side.
*/
@JNINamespace("base::android")
-public class PowerMonitor implements ApplicationStatus.ApplicationStateListener {
- private static final long SUSPEND_DELAY_MS = 1 * 60 * 1000; // 1 minute.
- private static class LazyHolder {
- private static final PowerMonitor INSTANCE = new PowerMonitor();
- }
+public class PowerMonitor {
private static PowerMonitor sInstance;
private boolean mIsBatteryPower;
- private final Handler mHandler = new Handler(Looper.getMainLooper());
-
- // Asynchronous task used to fire the "paused" event to the native side 1 minute after the main
- // activity transitioned to the "paused" state. This event is not sent immediately because it
- // would be too aggressive. An Android activity can be in the "paused" state quite often. This
- // can happen when a dialog window shows up for instance.
- private static final Runnable sSuspendTask = new Runnable() {
- @Override
- public void run() {
- nativeOnMainActivitySuspended();
- }
- };
- public static void createForTests(Context context) {
+ public static void createForTests() {
// Applications will create this once the JNI side has been fully wired up both sides. For
// tests, we just need native -> java, that is, we don't need to notify java -> native on
// creation.
- sInstance = LazyHolder.INSTANCE;
+ sInstance = new PowerMonitor();
}
/**
* Create a PowerMonitor instance if none exists.
- * @param context The context to register broadcast receivers for. The application context
- * will be used from this parameter.
*/
- public static void create(Context context) {
- context = context.getApplicationContext();
- if (sInstance == null) {
- sInstance = LazyHolder.INSTANCE;
- ApplicationStatus.registerApplicationStateListener(sInstance);
- IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
- Intent batteryStatusIntent = context.registerReceiver(null, ifilter);
- if (batteryStatusIntent != null) onBatteryChargingChanged(batteryStatusIntent);
- }
+ public static void create() {
+ ThreadUtils.assertOnUiThread();
+
+ if (sInstance != null) return;
+
+ Context context = ContextUtils.getApplicationContext();
+ sInstance = new PowerMonitor();
+ IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+ Intent batteryStatusIntent = context.registerReceiver(null, ifilter);
+ if (batteryStatusIntent != null) onBatteryChargingChanged(batteryStatusIntent);
+
+ IntentFilter powerConnectedFilter = new IntentFilter();
+ powerConnectedFilter.addAction(Intent.ACTION_POWER_CONNECTED);
+ powerConnectedFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
+ context.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ PowerMonitor.onBatteryChargingChanged(intent);
+ }
+ }, powerConnectedFilter);
}
private PowerMonitor() {
}
- public static void onBatteryChargingChanged(Intent intent) {
- if (sInstance == null) {
- // We may be called by the framework intent-filter before being fully initialized. This
- // is not a problem, since our constructor will check for the state later on.
- return;
- }
+ private static void onBatteryChargingChanged(Intent intent) {
+ assert sInstance != null;
int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
// If we're not plugged, assume we're running on battery power.
sInstance.mIsBatteryPower = chargePlug != BatteryManager.BATTERY_PLUGGED_USB
@@ -79,23 +66,15 @@ public class PowerMonitor implements ApplicationStatus.ApplicationStateListener
nativeOnBatteryChargingChanged();
}
- @Override
- public void onApplicationStateChange(int newState) {
- if (newState == ApplicationState.HAS_RUNNING_ACTIVITIES) {
- // Remove the callback from the message loop in case it hasn't been executed yet.
- mHandler.removeCallbacks(sSuspendTask);
- nativeOnMainActivityResumed();
- } else if (newState == ApplicationState.HAS_PAUSED_ACTIVITIES) {
- mHandler.postDelayed(sSuspendTask, SUSPEND_DELAY_MS);
- }
- }
-
@CalledByNative
private static boolean isBatteryPower() {
+ // Creation of the PowerMonitor can be deferred based on the browser startup path. If the
+ // battery power is requested prior to the browser triggering the creation, force it to be
+ // created now.
+ if (sInstance == null) create();
+
return sInstance.mIsBatteryPower;
}
private static native void nativeOnBatteryChargingChanged();
- private static native void nativeOnMainActivitySuspended();
- private static native void nativeOnMainActivityResumed();
}
diff --git a/base/android/java/src/org/chromium/base/PowerStatusReceiver.java b/base/android/java/src/org/chromium/base/PowerStatusReceiver.java
deleted file mode 100644
index 904a740..0000000
--- a/base/android/java/src/org/chromium/base/PowerStatusReceiver.java
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2012 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.
-
-package org.chromium.base;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-
-/**
- * A BroadcastReceiver that listens to changes in power status and notifies
- * PowerMonitor.
- * It's instantiated by the framework via the application intent-filter
- * declared in its manifest.
- */
-public class PowerStatusReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- PowerMonitor.onBatteryChargingChanged(intent);
- }
-}
diff --git a/base/android/java/src/org/chromium/base/ResourceExtractor.java b/base/android/java/src/org/chromium/base/ResourceExtractor.java
index 2854b02..c1d1856 100644
--- a/base/android/java/src/org/chromium/base/ResourceExtractor.java
+++ b/base/android/java/src/org/chromium/base/ResourceExtractor.java
@@ -4,18 +4,12 @@
package org.chromium.base;
-import android.annotation.TargetApi;
-import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.Handler;
import android.os.Looper;
-import android.os.Trace;
-
-import org.chromium.base.annotations.SuppressFBWarnings;
import java.io.File;
import java.io.FileOutputStream;
@@ -23,7 +17,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.Locale;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
@@ -38,23 +34,7 @@ public class ResourceExtractor {
private static final String V8_NATIVES_DATA_FILENAME = "natives_blob.bin";
private static final String V8_SNAPSHOT_DATA_FILENAME = "snapshot_blob.bin";
private static final String APP_VERSION_PREF = "org.chromium.base.ResourceExtractor.Version";
-
- private static ResourceEntry[] sResourcesToExtract = new ResourceEntry[0];
-
- /**
- * Holds information about a res/raw file (e.g. locale .pak files).
- */
- public static final class ResourceEntry {
- public final int resourceId;
- public final String pathWithinApk;
- public final String extractedFileName;
-
- public ResourceEntry(int resourceId, String pathWithinApk, String extractedFileName) {
- this.resourceId = resourceId;
- this.pathWithinApk = pathWithinApk;
- this.extractedFileName = extractedFileName;
- }
- }
+ private static final String FALLBACK_LOCALE = "en-US";
private class ExtractTask extends AsyncTask<Void, Void, Void> {
private static final int BUFFER_SIZE = 16 * 1024;
@@ -92,12 +72,12 @@ public class ResourceExtractor {
return;
}
- beginTraceSection("checkPakTimeStamp");
+ TraceEvent.begin("checkPakTimeStamp");
long curAppVersion = getApkVersion();
SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
long prevAppVersion = sharedPrefs.getLong(APP_VERSION_PREF, 0);
boolean versionChanged = curAppVersion != prevAppVersion;
- endTraceSection();
+ TraceEvent.end("checkPakTimeStamp");
if (versionChanged) {
deleteFiles();
@@ -107,23 +87,23 @@ public class ResourceExtractor {
sharedPrefs.edit().putLong(APP_VERSION_PREF, curAppVersion).apply();
}
- beginTraceSection("WalkAssets");
+ TraceEvent.begin("WalkAssets");
byte[] buffer = new byte[BUFFER_SIZE];
try {
- for (ResourceEntry entry : sResourcesToExtract) {
- File output = new File(outputDir, entry.extractedFileName);
+ for (String assetName : mAssetsToExtract) {
+ File output = new File(outputDir, assetName);
// TODO(agrieve): It would be better to check that .length == expectedLength.
// http://crbug.com/606413
if (output.length() != 0) {
continue;
}
- beginTraceSection("ExtractResource");
- InputStream inputStream = mContext.getResources().openRawResource(
- entry.resourceId);
+ TraceEvent.begin("ExtractResource");
+ InputStream inputStream =
+ ContextUtils.getApplicationContext().getAssets().open(assetName);
try {
extractResourceHelper(inputStream, output, buffer);
} finally {
- endTraceSection(); // ExtractResource
+ TraceEvent.end("ExtractResource");
}
}
} catch (IOException e) {
@@ -131,25 +111,21 @@ public class ResourceExtractor {
// Try to recover here, can we try again after deleting files instead of
// returning null? It might be useful to gather UMA here too to track if
// this happens with regularity.
- Log.w(TAG, "Exception unpacking required pak resources: %s", e.getMessage());
+ Log.w(TAG, "Exception unpacking required pak asset: %s", e.getMessage());
deleteFiles();
return;
} finally {
- endTraceSection(); // WalkAssets
+ TraceEvent.end("WalkAssets");
}
}
@Override
protected Void doInBackground(Void... unused) {
- // TODO(lizeb): Use chrome tracing here (and above in
- // doInBackgroundImpl) when it will be possible. This is currently
- // not doable since the native library is not loaded yet, and the
- // TraceEvent calls are dropped before this point.
- beginTraceSection("ResourceExtractor.ExtractTask.doInBackground");
+ TraceEvent.begin("ResourceExtractor.ExtractTask.doInBackground");
try {
doInBackgroundImpl();
} finally {
- endTraceSection();
+ TraceEvent.end("ResourceExtractor.ExtractTask.doInBackground");
}
return null;
}
@@ -163,64 +139,60 @@ public class ResourceExtractor {
@Override
protected void onPostExecute(Void result) {
- beginTraceSection("ResourceExtractor.ExtractTask.onPostExecute");
+ TraceEvent.begin("ResourceExtractor.ExtractTask.onPostExecute");
try {
onPostExecuteImpl();
} finally {
- endTraceSection();
+ TraceEvent.end("ResourceExtractor.ExtractTask.onPostExecute");
}
}
/** Returns a number that is different each time the apk changes. */
private long getApkVersion() {
- PackageManager pm = mContext.getPackageManager();
+ PackageManager pm = ContextUtils.getApplicationContext().getPackageManager();
try {
- // More appropriate would be versionCode, but it doesn't change while developing.
- PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), 0);
- return pi.lastUpdateTime;
+ // Use lastUpdateTime since versionCode does not change when developing locally,
+ // but also use versionCode since it is possible for Chrome to be updated without
+ // the lastUpdateTime being changed (http://crbug.org/673458).
+ PackageInfo pi =
+ pm.getPackageInfo(ContextUtils.getApplicationContext().getPackageName(), 0);
+ // Xor'ing versionCode into upper half of the long to ensure it doesn't somehow
+ // exactly offset an increase in time.
+ return pi.lastUpdateTime ^ (((long) pi.versionCode) << 32);
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(e);
}
}
-
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
- private void beginTraceSection(String section) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return;
- Trace.beginSection(section);
- }
-
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
- private void endTraceSection() {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return;
- Trace.endSection();
- }
}
- private final Context mContext;
private ExtractTask mExtractTask;
+ private final String[] mAssetsToExtract = detectFilesToExtract();
private static ResourceExtractor sInstance;
- public static ResourceExtractor get(Context context) {
+ public static ResourceExtractor get() {
if (sInstance == null) {
- sInstance = new ResourceExtractor(context);
+ sInstance = new ResourceExtractor();
}
return sInstance;
}
- /**
- * Specifies the files that should be extracted from the APK.
- * and moved to {@link #getOutputDir()}.
- */
- @SuppressFBWarnings("EI_EXPOSE_STATIC_REP2")
- public static void setResourcesToExtract(ResourceEntry[] entries) {
- assert (sInstance == null || sInstance.mExtractTask == null)
- : "Must be called before startExtractingResources is called";
- sResourcesToExtract = entries;
- }
-
- private ResourceExtractor(Context context) {
- mContext = context.getApplicationContext();
+ private static String[] detectFilesToExtract() {
+ Locale defaultLocale = Locale.getDefault();
+ String language = LocaleUtils.getUpdatedLanguageForChromium(defaultLocale.getLanguage());
+ // Currenty (Oct 2016), this array can be as big as 4 entries, so using a capacity
+ // that allows a bit of growth, but is still in the right ballpark..
+ ArrayList<String> activeLocalePakFiles = new ArrayList<String>(6);
+ for (String locale : BuildConfig.COMPRESSED_LOCALES) {
+ if (locale.startsWith(language)) {
+ activeLocalePakFiles.add(locale + ".pak");
+ }
+ }
+ if (activeLocalePakFiles.isEmpty() && BuildConfig.COMPRESSED_LOCALES.length > 0) {
+ assert Arrays.asList(BuildConfig.COMPRESSED_LOCALES).contains(FALLBACK_LOCALE);
+ activeLocalePakFiles.add(FALLBACK_LOCALE + ".pak");
+ }
+ return activeLocalePakFiles.toArray(new String[activeLocalePakFiles.size()]);
}
/**
@@ -301,7 +273,7 @@ public class ResourceExtractor {
}
private File getAppDataDir() {
- return new File(PathUtils.getDataDirectory(mContext));
+ return new File(PathUtils.getDataDirectory());
}
private File getOutputDir() {
@@ -348,6 +320,6 @@ public class ResourceExtractor {
* Pak extraction not necessarily required by the embedder.
*/
private static boolean shouldSkipPakExtraction() {
- return sResourcesToExtract.length == 0;
+ return get().mAssetsToExtract.length == 0;
}
}
diff --git a/base/android/java/src/org/chromium/base/SecureRandomInitializer.java b/base/android/java/src/org/chromium/base/SecureRandomInitializer.java
index 457e2ef..294b1e6 100644
--- a/base/android/java/src/org/chromium/base/SecureRandomInitializer.java
+++ b/base/android/java/src/org/chromium/base/SecureRandomInitializer.java
@@ -4,6 +4,8 @@
package org.chromium.base;
+import android.annotation.SuppressLint;
+
import java.io.FileInputStream;
import java.io.IOException;
import java.security.SecureRandom;
@@ -13,30 +15,25 @@ import java.security.SecureRandom;
* <= 4.3. See
* {@link http://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html}.
*/
+// TODO(crbug.com/635567): Fix this properly.
+@SuppressLint("SecureRandom")
public class SecureRandomInitializer {
private static final int NUM_RANDOM_BYTES = 16;
- private static byte[] sSeedBytes = new byte[NUM_RANDOM_BYTES];
-
/**
* Safely initializes the random number generator, by seeding it with data from /dev/urandom.
*/
public static void initialize(SecureRandom generator) throws IOException {
FileInputStream fis = null;
try {
+ byte[] seedBytes = new byte[NUM_RANDOM_BYTES];
fis = new FileInputStream("/dev/urandom");
- if (fis.read(sSeedBytes) != sSeedBytes.length) {
+ if (fis.read(seedBytes) != seedBytes.length) {
throw new IOException("Failed to get enough random data.");
}
- generator.setSeed(sSeedBytes);
+ generator.setSeed(seedBytes);
} finally {
- try {
- if (fis != null) {
- fis.close();
- }
- } catch (IOException e) {
- // Ignore exception closing the device.
- }
+ StreamUtil.closeQuietly(fis);
}
}
}
diff --git a/base/android/java/src/org/chromium/base/SysUtils.java b/base/android/java/src/org/chromium/base/SysUtils.java
index 04a8332..5ab77df 100644
--- a/base/android/java/src/org/chromium/base/SysUtils.java
+++ b/base/android/java/src/org/chromium/base/SysUtils.java
@@ -4,6 +4,9 @@
package org.chromium.base;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
import android.os.StrictMode;
import android.util.Log;
@@ -99,6 +102,24 @@ public class SysUtils {
return sLowEndDevice.booleanValue();
}
+ /**
+ * Resets the cached value, if any.
+ */
+ @VisibleForTesting
+ public static void reset() {
+ sLowEndDevice = null;
+ }
+
+ public static boolean hasCamera(final Context context) {
+ final PackageManager pm = context.getPackageManager();
+ // JellyBean support.
+ boolean hasCamera = pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ hasCamera |= pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
+ }
+ return hasCamera;
+ }
+
private static boolean detectLowEndDevice() {
assert CommandLine.isInitialized();
if (CommandLine.getInstance().hasSwitch(BaseSwitches.ENABLE_LOW_END_DEVICE_MODE)) {
diff --git a/base/android/java/src/org/chromium/base/SystemMessageHandler.java b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
index ebcc0d9..abfa2d8 100644
--- a/base/android/java/src/org/chromium/base/SystemMessageHandler.java
+++ b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
@@ -25,10 +25,12 @@ class SystemMessageHandler extends Handler {
// Native class pointer set by the constructor of the SharedClient native class.
private long mMessagePumpDelegateNative = 0;
+ private long mMessagePumpNative = 0;
private long mDelayedScheduledTimeTicks = 0;
- private SystemMessageHandler(long messagePumpDelegateNative) {
+ protected SystemMessageHandler(long messagePumpDelegateNative, long messagePumpNative) {
mMessagePumpDelegateNative = messagePumpDelegateNative;
+ mMessagePumpNative = messagePumpNative;
}
@Override
@@ -36,7 +38,8 @@ class SystemMessageHandler extends Handler {
if (msg.what == DELAYED_SCHEDULED_WORK) {
mDelayedScheduledTimeTicks = 0;
}
- nativeDoRunLoopOnce(mMessagePumpDelegateNative, mDelayedScheduledTimeTicks);
+ nativeDoRunLoopOnce(
+ mMessagePumpDelegateNative, mMessagePumpNative, mDelayedScheduledTimeTicks);
}
@SuppressWarnings("unused")
@@ -153,10 +156,11 @@ class SystemMessageHandler extends Handler {
}
@CalledByNative
- private static SystemMessageHandler create(long messagePumpDelegateNative) {
- return new SystemMessageHandler(messagePumpDelegateNative);
+ private static SystemMessageHandler create(
+ long messagePumpDelegateNative, long messagePumpNative) {
+ return new SystemMessageHandler(messagePumpDelegateNative, messagePumpNative);
}
private native void nativeDoRunLoopOnce(
- long messagePumpDelegateNative, long delayedScheduledTimeTicks);
+ long messagePumpDelegateNative, long messagePumpNative, long delayedScheduledTimeTicks);
}
diff --git a/base/android/java/src/org/chromium/base/ThreadUtils.java b/base/android/java/src/org/chromium/base/ThreadUtils.java
index ef2887a..737d7f6 100644
--- a/base/android/java/src/org/chromium/base/ThreadUtils.java
+++ b/base/android/java/src/org/chromium/base/ThreadUtils.java
@@ -34,6 +34,11 @@ public class ThreadUtils {
@VisibleForTesting
public static void setUiThread(Looper looper) {
synchronized (sLock) {
+ if (looper == null) {
+ // Used to reset the looper after tests.
+ sUiThreadHandler = null;
+ return;
+ }
if (sUiThreadHandler != null && sUiThreadHandler.getLooper() != looper) {
throw new RuntimeException("UI thread looper is already set to "
+ sUiThreadHandler.getLooper() + " (Main thread looper is "
@@ -189,7 +194,9 @@ public class ThreadUtils {
* Asserts that the current thread is running on the main thread.
*/
public static void assertOnUiThread() {
- assert runningOnUiThread();
+ if (BuildConfig.DCHECK_IS_ON && !runningOnUiThread()) {
+ throw new IllegalStateException("Must be called on the Ui thread.");
+ }
}
/**
diff --git a/base/android/java/src/org/chromium/base/TraceEvent.java b/base/android/java/src/org/chromium/base/TraceEvent.java
index 878275c..71bfac1 100644
--- a/base/android/java/src/org/chromium/base/TraceEvent.java
+++ b/base/android/java/src/org/chromium/base/TraceEvent.java
@@ -12,18 +12,19 @@ import android.util.Printer;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.MainDex;
/**
* Java mirror of Chrome trace event API. See base/trace_event/trace_event.h. Unlike the native
* version, Java does not have stack objects, so a TRACE_EVENT() which does both TRACE_EVENT_BEGIN()
* and TRACE_EVENT_END() in ctor/dtor is not possible.
- * It is OK to use tracing before the native library has loaded, but such traces will
- * be ignored. (Perhaps we could devise to buffer them up in future?).
+ * It is OK to use tracing before the native library has loaded, in a slightly restricted fashion.
+ * @see EarlyTraceEvent for details.
*/
@JNINamespace("base::android")
+@MainDex
public class TraceEvent {
-
- private static volatile boolean sEnabled = false;
- private static volatile boolean sATraceEnabled = false; // True when taking an Android systrace.
+ private static volatile boolean sEnabled;
+ private static volatile boolean sATraceEnabled; // True when taking an Android systrace.
private static class BasicLooperMonitor implements Printer {
@Override
@@ -82,14 +83,14 @@ public class TraceEvent {
MIN_INTERESTING_DURATION_MILLIS * 3;
// Stats tracking
- private long mLastIdleStartedAt = 0L;
- private long mLastWorkStartedAt = 0L;
- private int mNumTasksSeen = 0;
- private int mNumIdlesSeen = 0;
- private int mNumTasksSinceLastIdle = 0;
+ private long mLastIdleStartedAt;
+ private long mLastWorkStartedAt;
+ private int mNumTasksSeen;
+ private int mNumIdlesSeen;
+ private int mNumTasksSinceLastIdle;
// State
- private boolean mIdleMonitorAttached = false;
+ private boolean mIdleMonitorAttached;
// Called from within the begin/end methods only.
// This method can only execute on the looper thread, because that is
@@ -179,11 +180,26 @@ public class TraceEvent {
*/
@CalledByNative
public static void setEnabled(boolean enabled) {
- sEnabled = enabled;
- // Android M+ systrace logs this on its own. Only log it if not writing to Android systrace.
- if (sATraceEnabled) return;
- ThreadUtils.getUiThreadLooper().setMessageLogging(
- enabled ? LooperMonitorHolder.sInstance : null);
+ if (enabled) EarlyTraceEvent.disable();
+ // Only disable logging if Chromium enabled it originally, so as to not disrupt logging done
+ // by other applications
+ if (sEnabled != enabled) {
+ sEnabled = enabled;
+ // Android M+ systrace logs this on its own. Only log it if not writing to Android
+ // systrace.
+ if (sATraceEnabled) return;
+ ThreadUtils.getUiThreadLooper().setMessageLogging(
+ enabled ? LooperMonitorHolder.sInstance : null);
+ }
+ }
+
+ /**
+ * May enable early tracing depending on the environment.
+ *
+ * Must be called after the command-line has been read.
+ */
+ public static void maybeEnableEarlyTracing() {
+ EarlyTraceEvent.maybeEnable();
}
/**
@@ -254,7 +270,7 @@ public class TraceEvent {
* @param name The name of the event.
*/
public static void begin(String name) {
- if (sEnabled) nativeBegin(name, null);
+ begin(name, null);
}
/**
@@ -263,6 +279,7 @@ public class TraceEvent {
* @param arg The arguments of the event.
*/
public static void begin(String name, String arg) {
+ EarlyTraceEvent.begin(name);
if (sEnabled) nativeBegin(name, arg);
}
@@ -271,7 +288,7 @@ public class TraceEvent {
* @param name The name of the event.
*/
public static void end(String name) {
- if (sEnabled) nativeEnd(name, null);
+ end(name, null);
}
/**
@@ -280,6 +297,7 @@ public class TraceEvent {
* @param arg The arguments of the event.
*/
public static void end(String name, String arg) {
+ EarlyTraceEvent.end(name);
if (sEnabled) nativeEnd(name, arg);
}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
index f6bf867..d3e0fb9 100644
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
@@ -4,6 +4,7 @@
package org.chromium.base.library_loader;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.os.AsyncTask;
import android.os.SystemClock;
@@ -12,8 +13,10 @@ import org.chromium.base.CommandLine;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.base.TraceEvent;
+import org.chromium.base.VisibleForTesting;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.MainDex;
import org.chromium.base.metrics.RecordHistogram;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -35,6 +38,7 @@ import javax.annotation.Nullable;
* the native counterpart to this class.
*/
@JNINamespace("base::android")
+@MainDex
public class LibraryLoader {
private static final String TAG = "LibraryLoader";
@@ -129,18 +133,14 @@ public class LibraryLoader {
/**
* This method blocks until the library is fully loaded and initialized.
- *
- * @param context The context in which the method is called.
*/
- public void ensureInitialized(Context context) throws ProcessInitException {
- // TODO(wnwen): Move this call appropriately down to the tests that need it.
- ContextUtils.initApplicationContext(context.getApplicationContext());
+ public void ensureInitialized() throws ProcessInitException {
synchronized (sLock) {
if (mInitialized) {
// Already initialized, nothing to do.
return;
}
- loadAlreadyLocked(context);
+ loadAlreadyLocked(ContextUtils.getApplicationContext());
initializeAlreadyLocked();
}
}
@@ -159,13 +159,26 @@ public class LibraryLoader {
* this is called on will be the thread that runs the native code's static initializers.
* See the comment in doInBackground() for more considerations on this.
*
- * @param context The context the code is running.
- *
* @throws ProcessInitException if the native library failed to load.
*/
- public void loadNow(Context context) throws ProcessInitException {
+ public void loadNow() throws ProcessInitException {
+ loadNowOverrideApplicationContext(ContextUtils.getApplicationContext());
+ }
+
+ /**
+ * Override kept for callers that need to load from a different app context. Do not use unless
+ * specifically required to load from another context that is not the current process's app
+ * context.
+ *
+ * @param appContext The overriding app context to be used to load libraries.
+ * @throws ProcessInitException if the native library failed to load with this context.
+ */
+ public void loadNowOverrideApplicationContext(Context appContext) throws ProcessInitException {
synchronized (sLock) {
- loadAlreadyLocked(context);
+ if (mLoaded && appContext != ContextUtils.getApplicationContext()) {
+ throw new IllegalStateException("Attempt to load again from alternate context.");
+ }
+ loadAlreadyLocked(appContext);
}
}
@@ -197,7 +210,10 @@ public class LibraryLoader {
TraceEvent.begin("LibraryLoader.asyncPrefetchLibrariesToMemory");
int percentage = nativePercentageOfResidentNativeLibraryCode();
boolean success = false;
- if (coldStart) {
+ // Arbitrary percentage threshold. If most of the native library is already
+ // resident (likely with monochrome), don't bother creating a prefetch process.
+ boolean prefetch = coldStart && percentage < 90;
+ if (prefetch) {
success = nativeForkAndPrefetchNativeLibrary();
if (!success) {
Log.w(TAG, "Forking a process to prefetch the native library failed.");
@@ -206,7 +222,7 @@ public class LibraryLoader {
// As this runs in a background thread, it can be called before histograms are
// initialized. In this instance, histograms are dropped.
RecordHistogram.initialize();
- if (coldStart) {
+ if (prefetch) {
RecordHistogram.recordBooleanHistogram("LibraryLoader.PrefetchStatus", success);
}
if (percentage != -1) {
@@ -247,7 +263,9 @@ public class LibraryLoader {
// Invoke either Linker.loadLibrary(...) or System.loadLibrary(...), triggering
// JNI_OnLoad in native code
- private void loadAlreadyLocked(Context context) throws ProcessInitException {
+ // TODO(crbug.com/635567): Fix this properly.
+ @SuppressLint("DefaultLocale")
+ private void loadAlreadyLocked(Context appContext) throws ProcessInitException {
try {
if (!mLoaded) {
assert !mInitialized;
@@ -273,25 +291,35 @@ public class LibraryLoader {
String libFilePath = System.mapLibraryName(library);
if (Linker.isInZipFile()) {
// Load directly from the APK.
- zipFilePath = context.getApplicationInfo().sourceDir;
+ zipFilePath = appContext.getApplicationInfo().sourceDir;
Log.i(TAG, "Loading " + library + " from within " + zipFilePath);
} else {
// The library is in its own file.
Log.i(TAG, "Loading " + library);
}
- // Load the library using this Linker. May throw UnsatisfiedLinkError.
- loadLibrary(linker, zipFilePath, libFilePath);
+ try {
+ // Load the library using this Linker. May throw UnsatisfiedLinkError.
+ loadLibrary(linker, zipFilePath, libFilePath);
+ } catch (UnsatisfiedLinkError e) {
+ Log.e(TAG, "Unable to load library: " + library);
+ throw(e);
+ }
}
linker.finishLibraryLoad();
} else {
if (sLibraryPreloader != null) {
- mLibraryPreloaderStatus = sLibraryPreloader.loadLibrary(context);
+ mLibraryPreloaderStatus = sLibraryPreloader.loadLibrary(appContext);
}
// Load libraries using the system linker.
for (String library : NativeLibraries.LIBRARIES) {
- System.loadLibrary(library);
+ try {
+ System.loadLibrary(library);
+ } catch (UnsatisfiedLinkError e) {
+ Log.e(TAG, "Unable to load library: " + library);
+ throw(e);
+ }
}
}
@@ -307,21 +335,6 @@ public class LibraryLoader {
} catch (UnsatisfiedLinkError e) {
throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED, e);
}
- // Check that the version of the library we have loaded matches the version we expect
- Log.i(TAG, String.format(
- "Expected native library version number \"%s\", "
- + "actual native library version number \"%s\"",
- NativeLibraries.sVersionNumber,
- nativeGetVersionNumber()));
- if (!NativeLibraries.sVersionNumber.equals(nativeGetVersionNumber())) {
- throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_WRONG_VERSION);
- }
- }
-
- // Returns whether the given split name is that of the ABI split.
- private static boolean isAbiSplit(String splitName) {
- // The split name for the ABI split is manually set in the build rules.
- return splitName.startsWith("abi_");
}
// The WebView requires the Command Line to be switched over before
@@ -363,6 +376,14 @@ public class LibraryLoader {
throw new ProcessInitException(LoaderErrors.LOADER_ERROR_FAILED_TO_REGISTER_JNI);
}
+ // Check that the version of the library we have loaded matches the version we expect
+ Log.i(TAG, String.format("Expected native library version number \"%s\", "
+ + "actual native library version number \"%s\"",
+ NativeLibraries.sVersionNumber, nativeGetVersionNumber()));
+ if (!NativeLibraries.sVersionNumber.equals(nativeGetVersionNumber())) {
+ throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_WRONG_VERSION);
+ }
+
// From now on, keep tracing in sync with native.
TraceEvent.registerNativeEnabledObserver();
@@ -375,18 +396,19 @@ public class LibraryLoader {
}
// Called after all native initializations are complete.
- public void onNativeInitializationComplete(Context context) {
- recordBrowserProcessHistogram(context);
+ public void onNativeInitializationComplete() {
+ recordBrowserProcessHistogram();
}
// Record Chromium linker histogram state for the main browser process. Called from
// onNativeInitializationComplete().
- private void recordBrowserProcessHistogram(Context context) {
+ private void recordBrowserProcessHistogram() {
if (Linker.getInstance().isUsed()) {
- nativeRecordChromiumAndroidLinkerBrowserHistogram(mIsUsingBrowserSharedRelros,
- mLoadAtFixedAddressFailed,
- getLibraryLoadFromApkStatus(context),
- mLibraryLoadTimeMs);
+ nativeRecordChromiumAndroidLinkerBrowserHistogram(
+ mIsUsingBrowserSharedRelros,
+ mLoadAtFixedAddressFailed,
+ getLibraryLoadFromApkStatus(),
+ mLibraryLoadTimeMs);
}
if (sLibraryPreloader != null) {
nativeRecordLibraryPreloaderBrowserHistogram(mLibraryPreloaderStatus);
@@ -395,7 +417,7 @@ public class LibraryLoader {
// Returns the device's status for loading a library directly from the APK file.
// This method can only be called when the Chromium linker is used.
- private int getLibraryLoadFromApkStatus(Context context) {
+ private int getLibraryLoadFromApkStatus() {
assert Linker.getInstance().isUsed();
if (mLibraryWasLoadedFromApk) {
@@ -432,6 +454,15 @@ public class LibraryLoader {
return sInstance.mLibraryProcessType;
}
+ /**
+ * Override the library loader (normally with a mock) for testing.
+ * @param loader the mock library loader.
+ */
+ @VisibleForTesting
+ public static void setLibraryLoaderForTesting(LibraryLoader loader) {
+ sInstance = loader;
+ }
+
private native void nativeInitCommandLine(String[] initCommandLine);
// Only methods needed before or during normal JNI registration are during System.OnLoad.
diff --git a/base/android/java/src/org/chromium/base/library_loader/Linker.java b/base/android/java/src/org/chromium/base/library_loader/Linker.java
index 271e6cb..7d19995 100644
--- a/base/android/java/src/org/chromium/base/library_loader/Linker.java
+++ b/base/android/java/src/org/chromium/base/library_loader/Linker.java
@@ -503,32 +503,24 @@ public abstract class Linker {
}
/**
- * Determine whether a library is the linker library. Also deal with the
- * component build that adds a .cr suffix to the name.
+ * Determine whether a library is the linker library.
*
* @param library the name of the library.
* @return true is the library is the Linker's own JNI library.
*/
public boolean isChromiumLinkerLibrary(String library) {
- return library.equals(LINKER_JNI_LIBRARY) || library.equals(LINKER_JNI_LIBRARY + ".cr");
+ return library.equals(LINKER_JNI_LIBRARY);
}
/**
* Load the Linker JNI library. Throws UnsatisfiedLinkError on error.
- * In a component build, the suffix ".cr" is added to each library name, so
- * if the initial load fails we retry with a suffix.
*/
protected static void loadLinkerJniLibrary() {
String libName = "lib" + LINKER_JNI_LIBRARY + ".so";
if (DEBUG) {
Log.i(TAG, "Loading " + libName);
}
- try {
- System.loadLibrary(LINKER_JNI_LIBRARY);
- } catch (UnsatisfiedLinkError e) {
- Log.w(TAG, "Couldn't load " + libName + ", trying " + libName + ".cr");
- System.loadLibrary(LINKER_JNI_LIBRARY + ".cr");
- }
+ System.loadLibrary(LINKER_JNI_LIBRARY);
}
/**
diff --git a/base/android/java/src/org/chromium/base/library_loader/ModernLinker.java b/base/android/java/src/org/chromium/base/library_loader/ModernLinker.java
index 7716a8d..15021c7 100644
--- a/base/android/java/src/org/chromium/base/library_loader/ModernLinker.java
+++ b/base/android/java/src/org/chromium/base/library_loader/ModernLinker.java
@@ -251,8 +251,6 @@ class ModernLinker extends Linker {
Log.i(TAG, "disableSharedRelros() called");
}
synchronized (mLock) {
- assert !mPrepareLibraryLoadCalled;
-
// Mark this as a service process, and disable wait for shared RELRO.
mInBrowserProcess = false;
mWaitForSharedRelros = false;
@@ -388,7 +386,7 @@ class ModernLinker extends Linker {
// We are in the browser, and with a current load address that indicates that
// there is enough address space for shared RELRO to operate. Create the
// shared RELRO, and store it in the map.
- String relroPath = PathUtils.getDataDirectory(null) + "/RELRO:" + libFilePath;
+ String relroPath = PathUtils.getDataDirectory() + "/RELRO:" + libFilePath;
if (nativeCreateSharedRelro(dlopenExtPath,
mCurrentLoadAddress, relroPath, libInfo)) {
mSharedRelros.put(dlopenExtPath, libInfo);
diff --git a/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java b/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
index 56a5803..eaf57b7 100644
--- a/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
+++ b/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
@@ -25,16 +25,23 @@ import java.util.concurrent.TimeUnit;
*/
@JNINamespace("base::android")
public class RecordHistogram {
- private static boolean sIsDisabledForTests = false;
+ private static Throwable sDisabledBy;
private static Map<String, Long> sCache =
Collections.synchronizedMap(new HashMap<String, Long>());
/**
- * Tests may not have native initialized, so they may need to disable metrics.
+ * Tests may not have native initialized, so they may need to disable metrics. The value should
+ * be reset after the test done, to avoid carrying over state to unrelated tests.
+ *
+ * In JUnit tests this can be done automatically using
+ * {@link org.chromium.chrome.browser.DisableHistogramsRule}
*/
@VisibleForTesting
- public static void disableForTests() {
- sIsDisabledForTests = true;
+ public static void setDisabledForTests(boolean disabled) {
+ if (disabled && sDisabledBy != null) {
+ throw new IllegalStateException("Histograms are already disabled.", sDisabledBy);
+ }
+ sDisabledBy = disabled ? new Throwable() : null;
}
private static long getCachedHistogramKey(String name) {
@@ -54,7 +61,7 @@ public class RecordHistogram {
* @param sample sample to be recorded, either true or false
*/
public static void recordBooleanHistogram(String name, boolean sample) {
- if (sIsDisabledForTests) return;
+ if (sDisabledBy != null) return;
long key = getCachedHistogramKey(name);
long result = nativeRecordBooleanHistogram(name, key, sample);
if (result != key) sCache.put(name, result);
@@ -70,7 +77,7 @@ public class RecordHistogram {
* lower than |boundary|
*/
public static void recordEnumeratedHistogram(String name, int sample, int boundary) {
- if (sIsDisabledForTests) return;
+ if (sDisabledBy != null) return;
long key = getCachedHistogramKey(name);
long result = nativeRecordEnumeratedHistogram(name, key, sample, boundary);
if (result != key) sCache.put(name, result);
@@ -111,13 +118,13 @@ public class RecordHistogram {
* UMA_HISTOGRAM_CUSTOM_COUNTS C++ macro.
* @param name name of the histogram
* @param sample sample to be recorded, at least |min| and at most |max| - 1
- * @param min lower bound for expected sample values
+ * @param min lower bound for expected sample values. It must be >= 1
* @param max upper bounds for expected sample values
* @param numBuckets the number of buckets
*/
public static void recordCustomCountHistogram(
String name, int sample, int min, int max, int numBuckets) {
- if (sIsDisabledForTests) return;
+ if (sDisabledBy != null) return;
long key = getCachedHistogramKey(name);
long result = nativeRecordCustomCountHistogram(name, key, sample, min, max, numBuckets);
if (result != key) sCache.put(name, result);
@@ -134,7 +141,7 @@ public class RecordHistogram {
*/
public static void recordLinearCountHistogram(
String name, int sample, int min, int max, int numBuckets) {
- if (sIsDisabledForTests) return;
+ if (sDisabledBy != null) return;
long key = getCachedHistogramKey(name);
long result = nativeRecordLinearCountHistogram(name, key, sample, min, max, numBuckets);
if (result != key) sCache.put(name, result);
@@ -147,7 +154,7 @@ public class RecordHistogram {
* @param sample sample to be recorded, at least 0 and at most 100.
*/
public static void recordPercentageHistogram(String name, int sample) {
- if (sIsDisabledForTests) return;
+ if (sDisabledBy != null) return;
long key = getCachedHistogramKey(name);
long result = nativeRecordEnumeratedHistogram(name, key, sample, 101);
if (result != key) sCache.put(name, result);
@@ -160,7 +167,7 @@ public class RecordHistogram {
* values.
*/
public static void recordSparseSlowlyHistogram(String name, int sample) {
- if (sIsDisabledForTests) return;
+ if (sDisabledBy != null) return;
long key = getCachedHistogramKey(name);
long result = nativeRecordSparseHistogram(name, key, sample);
if (result != key) sCache.put(name, result);
@@ -218,6 +225,19 @@ public class RecordHistogram {
timeUnit.toMillis(min), timeUnit.toMillis(max), numBuckets);
}
+ /**
+ * Records a sample in a histogram of sizes in KB. This is the Java equivalent of the
+ * UMA_HISTOGRAM_MEMORY_KB C++ macro.
+ *
+ * Good for sizes up to about 500MB.
+ *
+ * @param name name of the histogram.
+ * @param sizeInkB Sample to record in KB.
+ */
+ public static void recordMemoryKBHistogram(String name, int sizeInKB) {
+ recordCustomCountHistogram(name, sizeInKB, 1000, 500000, 50);
+ }
+
private static int clampToInt(long value) {
if (value > Integer.MAX_VALUE) return Integer.MAX_VALUE;
// Note: Clamping to MIN_VALUE rather than 0, to let base/ histograms code
@@ -228,7 +248,7 @@ public class RecordHistogram {
private static void recordCustomTimesHistogramMilliseconds(
String name, long duration, long min, long max, int numBuckets) {
- if (sIsDisabledForTests) return;
+ if (sDisabledBy != null) return;
long key = getCachedHistogramKey(name);
// Note: Duration, min and max are clamped to int here because that's what's expected by
// the native histograms API. Callers of these functions still pass longs because that's
@@ -253,7 +273,7 @@ public class RecordHistogram {
* Initializes the metrics system.
*/
public static void initialize() {
- if (sIsDisabledForTests) return;
+ if (sDisabledBy != null) return;
nativeInitialize();
}
diff --git a/base/android/java_handler_thread.cc b/base/android/java_handler_thread.cc
index 7527034..76ee301 100644
--- a/base/android/java_handler_thread.cc
+++ b/base/android/java_handler_thread.cc
@@ -20,8 +20,8 @@ namespace android {
JavaHandlerThread::JavaHandlerThread(const char* name) {
JNIEnv* env = base::android::AttachCurrentThread();
- java_thread_.Reset(Java_JavaHandlerThread_create(
- env, ConvertUTF8ToJavaString(env, name).obj()));
+ java_thread_.Reset(
+ Java_JavaHandlerThread_create(env, ConvertUTF8ToJavaString(env, name)));
}
JavaHandlerThread::~JavaHandlerThread() {
@@ -35,8 +35,7 @@ void JavaHandlerThread::Start() {
base::WaitableEvent initialize_event(
WaitableEvent::ResetPolicy::AUTOMATIC,
WaitableEvent::InitialState::NOT_SIGNALED);
- Java_JavaHandlerThread_start(env,
- java_thread_.obj(),
+ Java_JavaHandlerThread_start(env, java_thread_,
reinterpret_cast<intptr_t>(this),
reinterpret_cast<intptr_t>(&initialize_event));
// Wait for thread to be initialized so it is ready to be used when Start
@@ -49,8 +48,7 @@ void JavaHandlerThread::Stop() {
JNIEnv* env = base::android::AttachCurrentThread();
base::WaitableEvent shutdown_event(WaitableEvent::ResetPolicy::AUTOMATIC,
WaitableEvent::InitialState::NOT_SIGNALED);
- Java_JavaHandlerThread_stop(env,
- java_thread_.obj(),
+ Java_JavaHandlerThread_stop(env, java_thread_,
reinterpret_cast<intptr_t>(this),
reinterpret_cast<intptr_t>(&shutdown_event));
// Wait for thread to shut down before returning.
@@ -63,17 +61,25 @@ void JavaHandlerThread::InitializeThread(JNIEnv* env,
jlong event) {
// TYPE_JAVA to get the Android java style message loop.
message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_JAVA));
- static_cast<MessageLoopForUI*>(message_loop_.get())->Start();
+ StartMessageLoop();
reinterpret_cast<base::WaitableEvent*>(event)->Signal();
}
void JavaHandlerThread::StopThread(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong event) {
- static_cast<MessageLoopForUI*>(message_loop_.get())->QuitWhenIdle();
+ StopMessageLoop();
reinterpret_cast<base::WaitableEvent*>(event)->Signal();
}
+void JavaHandlerThread::StartMessageLoop() {
+ static_cast<MessageLoopForUI*>(message_loop_.get())->Start();
+}
+
+void JavaHandlerThread::StopMessageLoop() {
+ static_cast<MessageLoopForUI*>(message_loop_.get())->QuitWhenIdle();
+}
+
// static
bool JavaHandlerThread::RegisterBindings(JNIEnv* env) {
return RegisterNativesImpl(env);
diff --git a/base/android/java_handler_thread.h b/base/android/java_handler_thread.h
index 1709ff4..96f2f0a 100644
--- a/base/android/java_handler_thread.h
+++ b/base/android/java_handler_thread.h
@@ -14,7 +14,6 @@
namespace base {
class MessageLoop;
-class WaitableEvent;
namespace android {
@@ -41,10 +40,15 @@ class BASE_EXPORT JavaHandlerThread {
const JavaParamRef<jobject>& obj,
jlong event);
+ virtual void StartMessageLoop();
+ virtual void StopMessageLoop();
+
static bool RegisterBindings(JNIEnv* env);
- private:
+ protected:
std::unique_ptr<base::MessageLoop> message_loop_;
+
+ private:
ScopedJavaGlobalRef<jobject> java_thread_;
};
diff --git a/base/android/java_message_handler_factory.h b/base/android/java_message_handler_factory.h
new file mode 100644
index 0000000..801617d
--- /dev/null
+++ b/base/android/java_message_handler_factory.h
@@ -0,0 +1,33 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JAVA_MESSAGE_HANDLER_FACTORY_H_
+#define BASE_ANDROID_JAVA_MESSAGE_HANDLER_FACTORY_H_
+
+#include "base/android/scoped_java_ref.h"
+#include "base/message_loop/message_pump.h"
+
+namespace base {
+
+class MessagePumpForUI;
+class WaitableEvent;
+
+namespace android {
+
+// Factory for creating the Java-side system message handler - only used for
+// testing.
+class JavaMessageHandlerFactory {
+ public:
+ virtual ~JavaMessageHandlerFactory() {}
+ virtual base::android::ScopedJavaLocalRef<jobject> CreateMessageHandler(
+ JNIEnv* env,
+ base::MessagePump::Delegate* delegate,
+ MessagePumpForUI* message_pump,
+ WaitableEvent* test_done_event) = 0;
+};
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_JAVA_MESSAGE_HANDLER_FACTORY_H_
diff --git a/base/android/java_runtime.cc b/base/android/java_runtime.cc
index 5be9adf..5fae49a 100644
--- a/base/android/java_runtime.cc
+++ b/base/android/java_runtime.cc
@@ -9,16 +9,12 @@
namespace base {
namespace android {
-bool JavaRuntime::Register(JNIEnv* env) {
- return JNI_Runtime::RegisterNativesImpl(env);
-}
-
void JavaRuntime::GetMemoryUsage(long* total_memory, long* free_memory) {
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jobject> runtime =
JNI_Runtime::Java_Runtime_getRuntime(env);
- *total_memory = JNI_Runtime::Java_Runtime_totalMemory(env, runtime.obj());
- *free_memory = JNI_Runtime::Java_Runtime_freeMemory(env, runtime.obj());
+ *total_memory = JNI_Runtime::Java_Runtime_totalMemory(env, runtime);
+ *free_memory = JNI_Runtime::Java_Runtime_freeMemory(env, runtime);
}
} // namespace android
diff --git a/base/android/java_runtime.h b/base/android/java_runtime.h
index 4ca889e..2034fb9 100644
--- a/base/android/java_runtime.h
+++ b/base/android/java_runtime.h
@@ -14,9 +14,6 @@ namespace android {
// Wrapper class for using the java.lang.Runtime object from jni.
class BASE_EXPORT JavaRuntime {
public:
- // Registers the jni class (once per process).
- static bool Register(JNIEnv* env);
-
// Fills the total memory used and memory allocated for objects by the java
// heap in the current process. Returns true on success.
static void GetMemoryUsage(long* total_memory, long* free_memory);
diff --git a/base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java b/base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java
index 02dbeb1..20c626d 100644
--- a/base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java
+++ b/base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// 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.
@@ -9,15 +9,21 @@ import android.content.ComponentCallbacks;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.res.Configuration;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.AdvancedMockContext;
/**
* Tests for {@link org.chromium.base.test.util.AdvancedMockContext}.
*/
-public class AdvancedMockContextTest extends InstrumentationTestCase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class AdvancedMockContextTest {
private static class Callback1 implements ComponentCallbacks {
protected Configuration mConfiguration;
protected boolean mOnLowMemoryCalled;
@@ -42,9 +48,10 @@ public class AdvancedMockContextTest extends InstrumentationTestCase {
}
}
+ @Test
@SmallTest
public void testComponentCallbacksForTargetContext() {
- Context targetContext = getInstrumentation().getTargetContext();
+ Context targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
Application targetApplication = (Application) targetContext.getApplicationContext();
AdvancedMockContext context = new AdvancedMockContext(targetContext);
Callback1 callback1 = new Callback1();
@@ -53,18 +60,18 @@ public class AdvancedMockContextTest extends InstrumentationTestCase {
context.registerComponentCallbacks(callback2);
targetApplication.onLowMemory();
- assertTrue("onLowMemory should have been called.", callback1.mOnLowMemoryCalled);
- assertTrue("onLowMemory should have been called.", callback2.mOnLowMemoryCalled);
+ Assert.assertTrue("onLowMemory should have been called.", callback1.mOnLowMemoryCalled);
+ Assert.assertTrue("onLowMemory should have been called.", callback2.mOnLowMemoryCalled);
Configuration configuration = new Configuration();
targetApplication.onConfigurationChanged(configuration);
- assertEquals("onConfigurationChanged should have been called.", configuration,
+ Assert.assertEquals("onConfigurationChanged should have been called.", configuration,
callback1.mConfiguration);
- assertEquals("onConfigurationChanged should have been called.", configuration,
+ Assert.assertEquals("onConfigurationChanged should have been called.", configuration,
callback2.mConfiguration);
targetApplication.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
- assertEquals("onTrimMemory should have been called.", ComponentCallbacks2
- .TRIM_MEMORY_MODERATE, callback2.mLevel);
+ Assert.assertEquals("onTrimMemory should have been called.",
+ ComponentCallbacks2.TRIM_MEMORY_MODERATE, callback2.mLevel);
}
}
diff --git a/base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java b/base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java
index 45b3e21..de0858a 100644
--- a/base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java
+++ b/base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// 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.
@@ -8,13 +8,20 @@ import android.annotation.TargetApi;
import android.app.Activity;
import android.os.Build;
import android.os.SystemClock;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
/**
* Test of ApiCompatibilityUtils
*/
-public class ApiCompatibilityUtilsTest extends InstrumentationTestCase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class ApiCompatibilityUtilsTest {
private static final long WAIT_TIMEOUT_IN_MS = 5000;
private static final long SLEEP_INTERVAL_IN_MS = 50;
@@ -42,30 +49,40 @@ public class ApiCompatibilityUtilsTest extends InstrumentationTestCase {
}
}
+ @Test
@SmallTest
- public void testFinishAndRemoveTask() throws InterruptedException {
- MockActivity activity = new MockActivity();
- ApiCompatibilityUtils.finishAndRemoveTask(activity);
+ public void testFinishAndRemoveTask() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ MockActivity activity = new MockActivity();
+ ApiCompatibilityUtils.finishAndRemoveTask(activity);
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
- assertEquals(1, activity.mFinishAndRemoveTaskCallbackCount);
- assertEquals(0, activity.mFinishCallbackCount);
- } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
- long startTime = SystemClock.uptimeMillis();
- while (activity.mFinishCallbackCount == 0
- && SystemClock.uptimeMillis() - startTime < WAIT_TIMEOUT_IN_MS) {
- Thread.sleep(SLEEP_INTERVAL_IN_MS);
- }
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
+ Assert.assertEquals(1, activity.mFinishAndRemoveTaskCallbackCount);
+ Assert.assertEquals(0, activity.mFinishCallbackCount);
+ } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
+ long startTime = SystemClock.uptimeMillis();
+ while (activity.mFinishCallbackCount == 0
+ && SystemClock.uptimeMillis() - startTime < WAIT_TIMEOUT_IN_MS) {
+ try {
+ Thread.sleep(SLEEP_INTERVAL_IN_MS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted thread sleep", e);
+ }
+ }
- // MockActivity#finishAndRemoveTask() never sets isFinishing() to true for LOLLIPOP to
- // simulate an exceptional case. In that case, MockActivity#finish() should be called
- // after 3 tries.
- assertEquals(3, activity.mFinishAndRemoveTaskCallbackCount);
- assertEquals(1, activity.mFinishCallbackCount);
- } else {
- assertEquals(0, activity.mFinishAndRemoveTaskCallbackCount);
- assertEquals(1, activity.mFinishCallbackCount);
- }
- assertTrue(activity.mIsFinishing);
+ // MockActivity#finishAndRemoveTask() never sets isFinishing() to true for
+ // LOLLIPOP to simulate an exceptional case. In that case, MockActivity#finish()
+ // should be called after 3 tries.
+ Assert.assertEquals(3, activity.mFinishAndRemoveTaskCallbackCount);
+ Assert.assertEquals(1, activity.mFinishCallbackCount);
+ } else {
+ Assert.assertEquals(0, activity.mFinishAndRemoveTaskCallbackCount);
+ Assert.assertEquals(1, activity.mFinishCallbackCount);
+ }
+ Assert.assertTrue(activity.mIsFinishing);
+ }
+ });
}
}
diff --git a/base/android/javatests/src/org/chromium/base/CommandLineTest.java b/base/android/javatests/src/org/chromium/base/CommandLineTest.java
index 2b1a967..47749fb 100644
--- a/base/android/javatests/src/org/chromium/base/CommandLineTest.java
+++ b/base/android/javatests/src/org/chromium/base/CommandLineTest.java
@@ -1,15 +1,21 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// 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.
package org.chromium.base;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.Feature;
-public class CommandLineTest extends InstrumentationTestCase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class CommandLineTest {
// A reference command line. Note that switch2 is [brea\d], switch3 is [and "butter"],
// and switch4 is [a "quoted" 'food'!]
static final String INIT_SWITCHES[] = { "init_command", "--SWITCH", "Arg",
@@ -27,60 +33,61 @@ public class CommandLineTest extends InstrumentationTestCase {
static final String CL_ADDED_SWITCH_2 = "username";
static final String CL_ADDED_VALUE_2 = "bozo";
- @Override
+ @Before
public void setUp() throws Exception {
CommandLine.reset();
}
void checkInitSwitches() {
CommandLine cl = CommandLine.getInstance();
- assertFalse(cl.hasSwitch("init_command"));
- assertFalse(cl.hasSwitch("switch"));
- assertTrue(cl.hasSwitch("SWITCH"));
- assertFalse(cl.hasSwitch("--SWITCH"));
- assertFalse(cl.hasSwitch("Arg"));
- assertFalse(cl.hasSwitch("actually_an_arg"));
- assertEquals("brea\\d", cl.getSwitchValue("switch2"));
- assertEquals("and \"butter\"", cl.getSwitchValue("switch3"));
- assertEquals("a \"quoted\" 'food'!", cl.getSwitchValue("switch4"));
- assertNull(cl.getSwitchValue("SWITCH"));
- assertNull(cl.getSwitchValue("non-existant"));
+ Assert.assertFalse(cl.hasSwitch("init_command"));
+ Assert.assertFalse(cl.hasSwitch("switch"));
+ Assert.assertTrue(cl.hasSwitch("SWITCH"));
+ Assert.assertFalse(cl.hasSwitch("--SWITCH"));
+ Assert.assertFalse(cl.hasSwitch("Arg"));
+ Assert.assertFalse(cl.hasSwitch("actually_an_arg"));
+ Assert.assertEquals("brea\\d", cl.getSwitchValue("switch2"));
+ Assert.assertEquals("and \"butter\"", cl.getSwitchValue("switch3"));
+ Assert.assertEquals("a \"quoted\" 'food'!", cl.getSwitchValue("switch4"));
+ Assert.assertNull(cl.getSwitchValue("SWITCH"));
+ Assert.assertNull(cl.getSwitchValue("non-existant"));
}
void checkSettingThenGetting() {
CommandLine cl = CommandLine.getInstance();
// Add a plain switch.
- assertFalse(cl.hasSwitch(CL_ADDED_SWITCH));
+ Assert.assertFalse(cl.hasSwitch(CL_ADDED_SWITCH));
cl.appendSwitch(CL_ADDED_SWITCH);
- assertTrue(cl.hasSwitch(CL_ADDED_SWITCH));
+ Assert.assertTrue(cl.hasSwitch(CL_ADDED_SWITCH));
// Add a switch paired with a value.
- assertFalse(cl.hasSwitch(CL_ADDED_SWITCH_2));
- assertNull(cl.getSwitchValue(CL_ADDED_SWITCH_2));
+ Assert.assertFalse(cl.hasSwitch(CL_ADDED_SWITCH_2));
+ Assert.assertNull(cl.getSwitchValue(CL_ADDED_SWITCH_2));
cl.appendSwitchWithValue(CL_ADDED_SWITCH_2, CL_ADDED_VALUE_2);
- assertTrue(CL_ADDED_VALUE_2.equals(cl.getSwitchValue(CL_ADDED_SWITCH_2)));
+ Assert.assertTrue(CL_ADDED_VALUE_2.equals(cl.getSwitchValue(CL_ADDED_SWITCH_2)));
// Append a few new things.
final String switchesAndArgs[] = { "dummy", "--superfast", "--speed=turbo" };
- assertFalse(cl.hasSwitch("dummy"));
- assertFalse(cl.hasSwitch("superfast"));
- assertNull(cl.getSwitchValue("speed"));
+ Assert.assertFalse(cl.hasSwitch("dummy"));
+ Assert.assertFalse(cl.hasSwitch("superfast"));
+ Assert.assertNull(cl.getSwitchValue("speed"));
cl.appendSwitchesAndArguments(switchesAndArgs);
- assertFalse(cl.hasSwitch("dummy"));
- assertFalse(cl.hasSwitch("command"));
- assertTrue(cl.hasSwitch("superfast"));
- assertTrue("turbo".equals(cl.getSwitchValue("speed")));
+ Assert.assertFalse(cl.hasSwitch("dummy"));
+ Assert.assertFalse(cl.hasSwitch("command"));
+ Assert.assertTrue(cl.hasSwitch("superfast"));
+ Assert.assertTrue("turbo".equals(cl.getSwitchValue("speed")));
}
void checkTokenizer(String[] expected, String toParse) {
String[] actual = CommandLine.tokenizeQuotedAruments(toParse.toCharArray());
- assertEquals(expected.length, actual.length);
+ Assert.assertEquals(expected.length, actual.length);
for (int i = 0; i < expected.length; ++i) {
- assertEquals("comparing element " + i, expected[i], actual[i]);
+ Assert.assertEquals("comparing element " + i, expected[i], actual[i]);
}
}
+ @Test
@SmallTest
@Feature({"Android-AppBase"})
public void testJavaInitialization() {
@@ -89,6 +96,7 @@ public class CommandLineTest extends InstrumentationTestCase {
checkSettingThenGetting();
}
+ @Test
@SmallTest
@Feature({"Android-AppBase"})
public void testBufferInitialization() {
@@ -97,6 +105,7 @@ public class CommandLineTest extends InstrumentationTestCase {
checkSettingThenGetting();
}
+ @Test
@SmallTest
@Feature({"Android-AppBase"})
public void testArgumentTokenizer() {
diff --git a/base/android/javatests/src/org/chromium/base/ObserverListTest.java b/base/android/javatests/src/org/chromium/base/ObserverListTest.java
index 94a9c71..1899f45 100644
--- a/base/android/javatests/src/org/chromium/base/ObserverListTest.java
+++ b/base/android/javatests/src/org/chromium/base/ObserverListTest.java
@@ -1,12 +1,16 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// 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.
package org.chromium.base;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.Feature;
import java.util.Collection;
@@ -16,7 +20,8 @@ import java.util.NoSuchElementException;
/**
* Tests for (@link ObserverList}.
*/
-public class ObserverListTest extends InstrumentationTestCase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class ObserverListTest {
interface Observer {
void observe(int x);
}
@@ -79,6 +84,7 @@ public class ObserverListTest extends InstrumentationTestCase {
return num;
}
+ @Test
@SmallTest
@Feature({"Android-AppBase"})
public void testRemoveWhileIteration() {
@@ -105,17 +111,18 @@ public class ObserverListTest extends InstrumentationTestCase {
for (Observer obs : observerList) obs.observe(10);
// observe should be called twice on a.
- assertEquals(20, a.mTotal);
+ Assert.assertEquals(20, a.mTotal);
// observe should be called twice on b.
- assertEquals(-20, b.mTotal);
+ Assert.assertEquals(-20, b.mTotal);
// evil removed c from the observerList before it got any callbacks.
- assertEquals(0, c.mTotal);
+ Assert.assertEquals(0, c.mTotal);
// observe should be called once on d.
- assertEquals(-10, d.mTotal);
+ Assert.assertEquals(-10, d.mTotal);
// e was never added to the list, observe should not be called.
- assertEquals(0, e.mTotal);
+ Assert.assertEquals(0, e.mTotal);
}
+ @Test
@SmallTest
@Feature({"Android-AppBase"})
public void testAddWhileIteration() {
@@ -131,12 +138,13 @@ public class ObserverListTest extends InstrumentationTestCase {
for (Observer obs : observerList) obs.observe(10);
- assertTrue(observerList.hasObserver(c));
- assertEquals(10, a.mTotal);
- assertEquals(-10, b.mTotal);
- assertEquals(0, c.mTotal);
+ Assert.assertTrue(observerList.hasObserver(c));
+ Assert.assertEquals(10, a.mTotal);
+ Assert.assertEquals(-10, b.mTotal);
+ Assert.assertEquals(0, c.mTotal);
}
+ @Test
@SmallTest
@Feature({"Android-AppBase"})
public void testIterator() {
@@ -144,38 +152,39 @@ public class ObserverListTest extends InstrumentationTestCase {
observerList.addObserver(5);
observerList.addObserver(10);
observerList.addObserver(15);
- assertEquals(3, getSizeOfIterable(observerList));
+ Assert.assertEquals(3, getSizeOfIterable(observerList));
observerList.removeObserver(10);
- assertEquals(2, getSizeOfIterable(observerList));
+ Assert.assertEquals(2, getSizeOfIterable(observerList));
Iterator<Integer> it = observerList.iterator();
- assertTrue(it.hasNext());
- assertTrue(5 == it.next());
- assertTrue(it.hasNext());
- assertTrue(15 == it.next());
- assertFalse(it.hasNext());
+ Assert.assertTrue(it.hasNext());
+ Assert.assertTrue(5 == it.next());
+ Assert.assertTrue(it.hasNext());
+ Assert.assertTrue(15 == it.next());
+ Assert.assertFalse(it.hasNext());
boolean removeExceptionThrown = false;
try {
it.remove();
- fail("Expecting UnsupportedOperationException to be thrown here.");
+ Assert.fail("Expecting UnsupportedOperationException to be thrown here.");
} catch (UnsupportedOperationException e) {
removeExceptionThrown = true;
}
- assertTrue(removeExceptionThrown);
- assertEquals(2, getSizeOfIterable(observerList));
+ Assert.assertTrue(removeExceptionThrown);
+ Assert.assertEquals(2, getSizeOfIterable(observerList));
boolean noElementExceptionThrown = false;
try {
it.next();
- fail("Expecting NoSuchElementException to be thrown here.");
+ Assert.fail("Expecting NoSuchElementException to be thrown here.");
} catch (NoSuchElementException e) {
noElementExceptionThrown = true;
}
- assertTrue(noElementExceptionThrown);
+ Assert.assertTrue(noElementExceptionThrown);
}
+ @Test
@SmallTest
@Feature({"Android-AppBase"})
public void testRewindableIterator() {
@@ -183,52 +192,54 @@ public class ObserverListTest extends InstrumentationTestCase {
observerList.addObserver(5);
observerList.addObserver(10);
observerList.addObserver(15);
- assertEquals(3, getSizeOfIterable(observerList));
+ Assert.assertEquals(3, getSizeOfIterable(observerList));
ObserverList.RewindableIterator<Integer> it = observerList.rewindableIterator();
- assertTrue(it.hasNext());
- assertTrue(5 == it.next());
- assertTrue(it.hasNext());
- assertTrue(10 == it.next());
- assertTrue(it.hasNext());
- assertTrue(15 == it.next());
- assertFalse(it.hasNext());
+ Assert.assertTrue(it.hasNext());
+ Assert.assertTrue(5 == it.next());
+ Assert.assertTrue(it.hasNext());
+ Assert.assertTrue(10 == it.next());
+ Assert.assertTrue(it.hasNext());
+ Assert.assertTrue(15 == it.next());
+ Assert.assertFalse(it.hasNext());
it.rewind();
- assertTrue(it.hasNext());
- assertTrue(5 == it.next());
- assertTrue(it.hasNext());
- assertTrue(10 == it.next());
- assertTrue(it.hasNext());
- assertTrue(15 == it.next());
- assertEquals(5, (int) observerList.mObservers.get(0));
+ Assert.assertTrue(it.hasNext());
+ Assert.assertTrue(5 == it.next());
+ Assert.assertTrue(it.hasNext());
+ Assert.assertTrue(10 == it.next());
+ Assert.assertTrue(it.hasNext());
+ Assert.assertTrue(15 == it.next());
+ Assert.assertEquals(5, (int) observerList.mObservers.get(0));
observerList.removeObserver(5);
- assertEquals(null, observerList.mObservers.get(0));
+ Assert.assertEquals(null, observerList.mObservers.get(0));
it.rewind();
- assertEquals(10, (int) observerList.mObservers.get(0));
- assertTrue(it.hasNext());
- assertTrue(10 == it.next());
- assertTrue(it.hasNext());
- assertTrue(15 == it.next());
+ Assert.assertEquals(10, (int) observerList.mObservers.get(0));
+ Assert.assertTrue(it.hasNext());
+ Assert.assertTrue(10 == it.next());
+ Assert.assertTrue(it.hasNext());
+ Assert.assertTrue(15 == it.next());
}
+ @Test
@SmallTest
@Feature({"Android-AppBase"})
public void testAddObserverReturnValue() {
ObserverList<Object> observerList = new ObserverList<Object>();
Object a = new Object();
- assertTrue(observerList.addObserver(a));
- assertFalse(observerList.addObserver(a));
+ Assert.assertTrue(observerList.addObserver(a));
+ Assert.assertFalse(observerList.addObserver(a));
Object b = new Object();
- assertTrue(observerList.addObserver(b));
- assertFalse(observerList.addObserver(null));
+ Assert.assertTrue(observerList.addObserver(b));
+ Assert.assertFalse(observerList.addObserver(null));
}
+ @Test
@SmallTest
@Feature({"Android-AppBase"})
public void testRemoveObserverReturnValue() {
@@ -239,91 +250,92 @@ public class ObserverListTest extends InstrumentationTestCase {
observerList.addObserver(a);
observerList.addObserver(b);
- assertTrue(observerList.removeObserver(a));
- assertFalse(observerList.removeObserver(a));
- assertFalse(observerList.removeObserver(new Object()));
- assertTrue(observerList.removeObserver(b));
- assertFalse(observerList.removeObserver(null));
+ Assert.assertTrue(observerList.removeObserver(a));
+ Assert.assertFalse(observerList.removeObserver(a));
+ Assert.assertFalse(observerList.removeObserver(new Object()));
+ Assert.assertTrue(observerList.removeObserver(b));
+ Assert.assertFalse(observerList.removeObserver(null));
// If we remove an object while iterating, it will be replaced by 'null'.
observerList.addObserver(a);
- assertTrue(observerList.removeObserver(a));
- assertFalse(observerList.removeObserver(null));
+ Assert.assertTrue(observerList.removeObserver(a));
+ Assert.assertFalse(observerList.removeObserver(null));
}
+ @Test
@SmallTest
@Feature({"Android-AppBase"})
public void testSize() {
ObserverList<Object> observerList = new ObserverList<Object>();
- assertEquals(0, observerList.size());
- assertTrue(observerList.isEmpty());
+ Assert.assertEquals(0, observerList.size());
+ Assert.assertTrue(observerList.isEmpty());
observerList.addObserver(null);
- assertEquals(0, observerList.size());
- assertTrue(observerList.isEmpty());
+ Assert.assertEquals(0, observerList.size());
+ Assert.assertTrue(observerList.isEmpty());
Object a = new Object();
observerList.addObserver(a);
- assertEquals(1, observerList.size());
- assertFalse(observerList.isEmpty());
+ Assert.assertEquals(1, observerList.size());
+ Assert.assertFalse(observerList.isEmpty());
observerList.addObserver(a);
- assertEquals(1, observerList.size());
- assertFalse(observerList.isEmpty());
+ Assert.assertEquals(1, observerList.size());
+ Assert.assertFalse(observerList.isEmpty());
observerList.addObserver(null);
- assertEquals(1, observerList.size());
- assertFalse(observerList.isEmpty());
+ Assert.assertEquals(1, observerList.size());
+ Assert.assertFalse(observerList.isEmpty());
Object b = new Object();
observerList.addObserver(b);
- assertEquals(2, observerList.size());
- assertFalse(observerList.isEmpty());
+ Assert.assertEquals(2, observerList.size());
+ Assert.assertFalse(observerList.isEmpty());
observerList.removeObserver(null);
- assertEquals(2, observerList.size());
- assertFalse(observerList.isEmpty());
+ Assert.assertEquals(2, observerList.size());
+ Assert.assertFalse(observerList.isEmpty());
observerList.removeObserver(new Object());
- assertEquals(2, observerList.size());
- assertFalse(observerList.isEmpty());
+ Assert.assertEquals(2, observerList.size());
+ Assert.assertFalse(observerList.isEmpty());
observerList.removeObserver(b);
- assertEquals(1, observerList.size());
- assertFalse(observerList.isEmpty());
+ Assert.assertEquals(1, observerList.size());
+ Assert.assertFalse(observerList.isEmpty());
observerList.removeObserver(b);
- assertEquals(1, observerList.size());
- assertFalse(observerList.isEmpty());
+ Assert.assertEquals(1, observerList.size());
+ Assert.assertFalse(observerList.isEmpty());
observerList.removeObserver(a);
- assertEquals(0, observerList.size());
- assertTrue(observerList.isEmpty());
+ Assert.assertEquals(0, observerList.size());
+ Assert.assertTrue(observerList.isEmpty());
observerList.removeObserver(a);
observerList.removeObserver(b);
observerList.removeObserver(null);
observerList.removeObserver(new Object());
- assertEquals(0, observerList.size());
- assertTrue(observerList.isEmpty());
+ Assert.assertEquals(0, observerList.size());
+ Assert.assertTrue(observerList.isEmpty());
observerList.addObserver(new Object());
observerList.addObserver(new Object());
observerList.addObserver(new Object());
observerList.addObserver(a);
- assertEquals(4, observerList.size());
- assertFalse(observerList.isEmpty());
+ Assert.assertEquals(4, observerList.size());
+ Assert.assertFalse(observerList.isEmpty());
observerList.clear();
- assertEquals(0, observerList.size());
- assertTrue(observerList.isEmpty());
+ Assert.assertEquals(0, observerList.size());
+ Assert.assertTrue(observerList.isEmpty());
observerList.removeObserver(a);
observerList.removeObserver(b);
observerList.removeObserver(null);
observerList.removeObserver(new Object());
- assertEquals(0, observerList.size());
- assertTrue(observerList.isEmpty());
+ Assert.assertEquals(0, observerList.size());
+ Assert.assertTrue(observerList.isEmpty());
}
}
diff --git a/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java b/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
index 6b1888c..daf639b 100644
--- a/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
+++ b/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
@@ -1,14 +1,19 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// 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.
package org.chromium.base.metrics;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.library_loader.LibraryProcessType;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.MetricsUtils.HistogramDelta;
import java.util.concurrent.TimeUnit;
@@ -16,42 +21,43 @@ import java.util.concurrent.TimeUnit;
/**
* Tests for the Java API for recording UMA histograms.
*/
-public class RecordHistogramTest extends InstrumentationTestCase {
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER)
- .ensureInitialized(getInstrumentation().getTargetContext());
+@RunWith(BaseJUnit4ClassRunner.class)
+public class RecordHistogramTest {
+ @Before
+ public void setUp() throws Exception {
+ LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized();
RecordHistogram.initialize();
}
/**
* Tests recording of boolean histograms.
*/
+ @Test
@SmallTest
public void testRecordBooleanHistogram() {
String histogram = "HelloWorld.BooleanMetric";
HistogramDelta falseCount = new HistogramDelta(histogram, 0);
HistogramDelta trueCount = new HistogramDelta(histogram, 1);
- assertEquals(0, trueCount.getDelta());
- assertEquals(0, falseCount.getDelta());
+ Assert.assertEquals(0, trueCount.getDelta());
+ Assert.assertEquals(0, falseCount.getDelta());
RecordHistogram.recordBooleanHistogram(histogram, true);
- assertEquals(1, trueCount.getDelta());
- assertEquals(0, falseCount.getDelta());
+ Assert.assertEquals(1, trueCount.getDelta());
+ Assert.assertEquals(0, falseCount.getDelta());
RecordHistogram.recordBooleanHistogram(histogram, true);
- assertEquals(2, trueCount.getDelta());
- assertEquals(0, falseCount.getDelta());
+ Assert.assertEquals(2, trueCount.getDelta());
+ Assert.assertEquals(0, falseCount.getDelta());
RecordHistogram.recordBooleanHistogram(histogram, false);
- assertEquals(2, trueCount.getDelta());
- assertEquals(1, falseCount.getDelta());
+ Assert.assertEquals(2, trueCount.getDelta());
+ Assert.assertEquals(1, falseCount.getDelta());
}
/**
* Tests recording of enumerated histograms.
*/
+ @Test
@SmallTest
public void testRecordEnumeratedHistogram() {
String histogram = "HelloWorld.EnumeratedMetric";
@@ -60,29 +66,30 @@ public class RecordHistogramTest extends InstrumentationTestCase {
HistogramDelta twoCount = new HistogramDelta(histogram, 2);
final int boundary = 3;
- assertEquals(0, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
+ Assert.assertEquals(0, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(0, twoCount.getDelta());
RecordHistogram.recordEnumeratedHistogram(histogram, 0, boundary);
- assertEquals(1, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
+ Assert.assertEquals(1, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(0, twoCount.getDelta());
RecordHistogram.recordEnumeratedHistogram(histogram, 0, boundary);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
+ Assert.assertEquals(2, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(0, twoCount.getDelta());
RecordHistogram.recordEnumeratedHistogram(histogram, 2, boundary);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(1, twoCount.getDelta());
+ Assert.assertEquals(2, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(1, twoCount.getDelta());
}
/**
* Tests recording of count histograms.
*/
+ @Test
@SmallTest
public void testRecordCountHistogram() {
String histogram = "HelloWorld.CountMetric";
@@ -91,39 +98,40 @@ public class RecordHistogramTest extends InstrumentationTestCase {
HistogramDelta twoCount = new HistogramDelta(histogram, 2);
HistogramDelta eightThousandCount = new HistogramDelta(histogram, 8000);
- assertEquals(0, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
- assertEquals(0, eightThousandCount.getDelta());
+ Assert.assertEquals(0, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(0, twoCount.getDelta());
+ Assert.assertEquals(0, eightThousandCount.getDelta());
RecordHistogram.recordCountHistogram(histogram, 0);
- assertEquals(1, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
- assertEquals(0, eightThousandCount.getDelta());
+ Assert.assertEquals(1, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(0, twoCount.getDelta());
+ Assert.assertEquals(0, eightThousandCount.getDelta());
RecordHistogram.recordCountHistogram(histogram, 0);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
- assertEquals(0, eightThousandCount.getDelta());
+ Assert.assertEquals(2, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(0, twoCount.getDelta());
+ Assert.assertEquals(0, eightThousandCount.getDelta());
RecordHistogram.recordCountHistogram(histogram, 2);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(1, twoCount.getDelta());
- assertEquals(0, eightThousandCount.getDelta());
+ Assert.assertEquals(2, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(1, twoCount.getDelta());
+ Assert.assertEquals(0, eightThousandCount.getDelta());
RecordHistogram.recordCountHistogram(histogram, 8000);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(1, twoCount.getDelta());
- assertEquals(1, eightThousandCount.getDelta());
+ Assert.assertEquals(2, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(1, twoCount.getDelta());
+ Assert.assertEquals(1, eightThousandCount.getDelta());
}
/**
* Tests recording of custom times histograms.
*/
+ @Test
@SmallTest
public void testRecordCustomTimesHistogram() {
String histogram = "HelloWorld.CustomTimesMetric";
@@ -131,36 +139,37 @@ public class RecordHistogramTest extends InstrumentationTestCase {
HistogramDelta oneCount = new HistogramDelta(histogram, 1);
HistogramDelta twoCount = new HistogramDelta(histogram, 100);
- assertEquals(0, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
+ Assert.assertEquals(0, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(0, twoCount.getDelta());
TimeUnit milli = TimeUnit.MILLISECONDS;
RecordHistogram.recordCustomTimesHistogram(histogram, 0, 1, 100, milli, 3);
- assertEquals(1, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
+ Assert.assertEquals(1, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(0, twoCount.getDelta());
RecordHistogram.recordCustomTimesHistogram(histogram, 0, 1, 100, milli, 3);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
+ Assert.assertEquals(2, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(0, twoCount.getDelta());
RecordHistogram.recordCustomTimesHistogram(histogram, 95, 1, 100, milli, 3);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(1, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
+ Assert.assertEquals(2, zeroCount.getDelta());
+ Assert.assertEquals(1, oneCount.getDelta());
+ Assert.assertEquals(0, twoCount.getDelta());
RecordHistogram.recordCustomTimesHistogram(histogram, 200, 1, 100, milli, 3);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(1, oneCount.getDelta());
- assertEquals(1, twoCount.getDelta());
+ Assert.assertEquals(2, zeroCount.getDelta());
+ Assert.assertEquals(1, oneCount.getDelta());
+ Assert.assertEquals(1, twoCount.getDelta());
}
/**
* Tests recording of linear count histograms.
*/
+ @Test
@SmallTest
public void testRecordLinearCountHistogram() {
String histogram = "HelloWorld.LinearCountMetric";
@@ -171,23 +180,23 @@ public class RecordHistogramTest extends InstrumentationTestCase {
final int max = 3;
final int numBuckets = 4;
- assertEquals(0, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
+ Assert.assertEquals(0, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(0, twoCount.getDelta());
RecordHistogram.recordLinearCountHistogram(histogram, 0, min, max, numBuckets);
- assertEquals(1, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
+ Assert.assertEquals(1, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(0, twoCount.getDelta());
RecordHistogram.recordLinearCountHistogram(histogram, 0, min, max, numBuckets);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
+ Assert.assertEquals(2, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(0, twoCount.getDelta());
RecordHistogram.recordLinearCountHistogram(histogram, 2, min, max, numBuckets);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(1, twoCount.getDelta());
+ Assert.assertEquals(2, zeroCount.getDelta());
+ Assert.assertEquals(0, oneCount.getDelta());
+ Assert.assertEquals(1, twoCount.getDelta());
}
}
diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc
index 3b53624..56dc5c2 100644
--- a/base/android/jni_android.cc
+++ b/base/android/jni_android.cc
@@ -11,33 +11,40 @@
#include "base/android/build_info.h"
#include "base/android/jni_string.h"
#include "base/android/jni_utils.h"
+#include "base/debug/debugging_flags.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/threading/thread_local.h"
namespace {
using base::android::GetClass;
using base::android::MethodID;
using base::android::ScopedJavaLocalRef;
-bool g_disable_manual_jni_registration = false;
+base::android::JniRegistrationType g_jni_registration_type =
+ base::android::ALL_JNI_REGISTRATION;
JavaVM* g_jvm = NULL;
-base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky
+base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject>>::Leaky
g_class_loader = LAZY_INSTANCE_INITIALIZER;
jmethodID g_class_loader_load_class_method_id = 0;
+#if BUILDFLAG(ENABLE_PROFILING) && HAVE_TRACE_STACK_FRAME_POINTERS
+base::LazyInstance<base::ThreadLocalPointer<void>>::Leaky
+ g_stack_frame_pointer = LAZY_INSTANCE_INITIALIZER;
+#endif
+
} // namespace
namespace base {
namespace android {
-bool IsManualJniRegistrationDisabled() {
- return g_disable_manual_jni_registration;
+JniRegistrationType GetJniRegistrationType() {
+ return g_jni_registration_type;
}
-void DisableManualJniRegistration() {
- DCHECK(!g_disable_manual_jni_registration);
- g_disable_manual_jni_registration = true;
+void SetJniRegistrationType(JniRegistrationType jni_registration_type) {
+ g_jni_registration_type = jni_registration_type;
}
JNIEnv* AttachCurrentThread() {
@@ -233,16 +240,7 @@ void CheckException(JNIEnv* env) {
}
// Now, feel good about it and die.
- // TODO(lhchavez): Remove this hack. See b/28814913 for details.
- // We're using BuildInfo's java_exception_info() instead of storing the
- // exception info a few lines above to avoid extra copies. It will be
- // truncated to 1024 bytes anyways.
- const char* exception_string =
- base::android::BuildInfo::GetInstance()->java_exception_info();
- if (exception_string)
- LOG(FATAL) << exception_string;
- else
- LOG(FATAL) << "Unhandled exception";
+ LOG(FATAL) << "Please include Java exception stack in crash report";
}
std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
@@ -291,6 +289,22 @@ std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
return ConvertJavaStringToUTF8(exception_string);
}
+#if BUILDFLAG(ENABLE_PROFILING) && HAVE_TRACE_STACK_FRAME_POINTERS
+
+JNIStackFrameSaver::JNIStackFrameSaver(void* current_fp) {
+ previous_fp_ = g_stack_frame_pointer.Pointer()->Get();
+ g_stack_frame_pointer.Pointer()->Set(current_fp);
+}
+
+JNIStackFrameSaver::~JNIStackFrameSaver() {
+ g_stack_frame_pointer.Pointer()->Set(previous_fp_);
+}
+
+void* JNIStackFrameSaver::SavedFrame() {
+ return g_stack_frame_pointer.Pointer()->Get();
+}
+
+#endif // ENABLE_PROFILING && HAVE_TRACE_STACK_FRAME_POINTERS
} // namespace android
} // namespace base
diff --git a/base/android/jni_android.h b/base/android/jni_android.h
index 909e3da..de53c10 100644
--- a/base/android/jni_android.h
+++ b/base/android/jni_android.h
@@ -14,6 +14,39 @@
#include "base/atomicops.h"
#include "base/base_export.h"
#include "base/compiler_specific.h"
+#include "base/debug/stack_trace.h"
+#include "base/macros.h"
+
+#if HAVE_TRACE_STACK_FRAME_POINTERS
+
+// When profiling is enabled (enable_profiling=true) this macro is added to
+// all generated JNI stubs so that it becomes the last thing that runs before
+// control goes into Java.
+//
+// This macro saves stack frame pointer of the current function. Saved value
+// used later by JNI_LINK_SAVED_FRAME_POINTER.
+#define JNI_SAVE_FRAME_POINTER \
+ base::android::JNIStackFrameSaver jni_frame_saver(__builtin_frame_address(0))
+
+// When profiling is enabled (enable_profiling=true) this macro is added to
+// all generated JNI callbacks so that it becomes the first thing that runs
+// after control returns from Java.
+//
+// This macro links stack frame of the current function to the stack frame
+// saved by JNI_SAVE_FRAME_POINTER, allowing frame-based unwinding
+// (used by the heap profiler) to produce complete traces.
+#define JNI_LINK_SAVED_FRAME_POINTER \
+ base::debug::ScopedStackFrameLinker jni_frame_linker( \
+ __builtin_frame_address(0), \
+ base::android::JNIStackFrameSaver::SavedFrame())
+
+#else
+
+// Frame-based stack unwinding is not supported, do nothing.
+#define JNI_SAVE_FRAME_POINTER
+#define JNI_LINK_SAVED_FRAME_POINTER
+
+#endif // HAVE_TRACE_STACK_FRAME_POINTERS
namespace base {
namespace android {
@@ -21,12 +54,23 @@ namespace android {
// Used to mark symbols to be exported in a shared library's symbol table.
#define JNI_EXPORT __attribute__ ((visibility("default")))
-// Used to disable manual JNI registration in binaries that prefer to use native
-// JNI exports for startup performance. This is not compatible with the crazy
-// linker and so defaults to off. Call DisableManualJniRegistration at the very
-// beginning of JNI_OnLoad to use this.
-BASE_EXPORT bool IsManualJniRegistrationDisabled();
-BASE_EXPORT void DisableManualJniRegistration();
+// The level of JNI registration required for the current process.
+enum JniRegistrationType {
+ // Register all native methods.
+ ALL_JNI_REGISTRATION,
+ // Register some native methods, as controlled by the jni_generator.
+ SELECTIVE_JNI_REGISTRATION,
+ // Do not register any native methods.
+ NO_JNI_REGISTRATION,
+};
+
+BASE_EXPORT JniRegistrationType GetJniRegistrationType();
+
+// Set the JniRegistrationType for this process (defaults to
+// ALL_JNI_REGISTRATION). This should be called in the JNI_OnLoad function
+// which is called when the native library is first loaded.
+BASE_EXPORT void SetJniRegistrationType(
+ JniRegistrationType jni_registration_type);
// Contains the registration method information for initializing JNI bindings.
struct RegistrationMethod {
@@ -122,6 +166,24 @@ BASE_EXPORT void CheckException(JNIEnv* env);
BASE_EXPORT std::string GetJavaExceptionInfo(JNIEnv* env,
jthrowable java_throwable);
+#if HAVE_TRACE_STACK_FRAME_POINTERS
+
+// Saves caller's PC and stack frame in a thread-local variable.
+// Implemented only when profiling is enabled (enable_profiling=true).
+class BASE_EXPORT JNIStackFrameSaver {
+ public:
+ JNIStackFrameSaver(void* current_fp);
+ ~JNIStackFrameSaver();
+ static void* SavedFrame();
+
+ private:
+ void* previous_fp_;
+
+ DISALLOW_COPY_AND_ASSIGN(JNIStackFrameSaver);
+};
+
+#endif // HAVE_TRACE_STACK_FRAME_POINTERS
+
} // namespace android
} // namespace base
diff --git a/base/android/jni_generator/golden_sample_for_tests_jni.h b/base/android/jni_generator/golden_sample_for_tests_jni.h
deleted file mode 100644
index e982609..0000000
--- a/base/android/jni_generator/golden_sample_for_tests_jni.h
+++ /dev/null
@@ -1,481 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file is autogenerated by
-// base/android/jni_generator/jni_generator.py
-// For
-// org/chromium/example/jni_generator/SampleForTests
-
-#ifndef org_chromium_example_jni_generator_SampleForTests_JNI
-#define org_chromium_example_jni_generator_SampleForTests_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// Step 1: forward declarations.
-namespace {
-const char kInnerStructAClassPath[] =
- "org/chromium/example/jni_generator/SampleForTests$InnerStructA";
-const char kSampleForTestsClassPath[] =
- "org/chromium/example/jni_generator/SampleForTests";
-const char kInnerStructBClassPath[] =
- "org/chromium/example/jni_generator/SampleForTests$InnerStructB";
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_InnerStructA_clazz = NULL;
-#define InnerStructA_clazz(env) g_InnerStructA_clazz
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_SampleForTests_clazz = NULL;
-#define SampleForTests_clazz(env) g_SampleForTests_clazz
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_InnerStructB_clazz = NULL;
-#define InnerStructB_clazz(env) g_InnerStructB_clazz
-
-} // namespace
-
-namespace base {
-namespace android {
-
-// Step 2: method stubs.
-
-static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller,
- const JavaParamRef<jstring>& param);
-
-static jlong
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeInit(JNIEnv*
- env, jobject jcaller,
- jstring param) {
- return Init(env, JavaParamRef<jobject>(env, jcaller),
- JavaParamRef<jstring>(env, param));
-}
-
-static void
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeDestroy(JNIEnv*
- env,
- jobject jcaller,
- jlong nativeCPPClass) {
- CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
- CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
- return native->Destroy(env, JavaParamRef<jobject>(env, jcaller));
-}
-
-static jdouble GetDoubleFunction(JNIEnv* env, const JavaParamRef<jobject>&
- jcaller);
-
-static jdouble
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetDoubleFunction(JNIEnv*
- env, jobject jcaller) {
- return GetDoubleFunction(env, JavaParamRef<jobject>(env, jcaller));
-}
-
-static jfloat GetFloatFunction(JNIEnv* env, const JavaParamRef<jclass>&
- jcaller);
-
-static jfloat
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetFloatFunction(JNIEnv*
- env, jclass jcaller) {
- return GetFloatFunction(env, JavaParamRef<jclass>(env, jcaller));
-}
-
-static void SetNonPODDatatype(JNIEnv* env, const JavaParamRef<jobject>& jcaller,
- const JavaParamRef<jobject>& rect);
-
-static void
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeSetNonPODDatatype(JNIEnv*
- env, jobject jcaller,
- jobject rect) {
- return SetNonPODDatatype(env, JavaParamRef<jobject>(env, jcaller),
- JavaParamRef<jobject>(env, rect));
-}
-
-static ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env, const
- JavaParamRef<jobject>& jcaller);
-
-static jobject
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetNonPODDatatype(JNIEnv*
- env, jobject jcaller) {
- return GetNonPODDatatype(env, JavaParamRef<jobject>(env, jcaller)).Release();
-}
-
-static jint
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(JNIEnv*
- env,
- jobject jcaller,
- jlong nativeCPPClass) {
- CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
- CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
- return native->Method(env, JavaParamRef<jobject>(env, jcaller));
-}
-
-static jdouble
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethodOtherP0(JNIEnv*
- env,
- jobject jcaller,
- jlong nativePtr) {
- CPPClass::InnerClass* native =
- reinterpret_cast<CPPClass::InnerClass*>(nativePtr);
- CHECK_NATIVE_PTR(env, jcaller, native, "MethodOtherP0", 0);
- return native->MethodOtherP0(env, JavaParamRef<jobject>(env, jcaller));
-}
-
-static void
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeAddStructB(JNIEnv*
- env,
- jobject jcaller,
- jlong nativeCPPClass,
- jobject b) {
- CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
- CHECK_NATIVE_PTR(env, jcaller, native, "AddStructB");
- return native->AddStructB(env, JavaParamRef<jobject>(env, jcaller),
- JavaParamRef<jobject>(env, b));
-}
-
-static void
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeIterateAndDoSomethingWithStructB(JNIEnv*
- env,
- jobject jcaller,
- jlong nativeCPPClass) {
- CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
- CHECK_NATIVE_PTR(env, jcaller, native, "IterateAndDoSomethingWithStructB");
- return native->IterateAndDoSomethingWithStructB(env,
- JavaParamRef<jobject>(env, jcaller));
-}
-
-static jstring
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeReturnAString(JNIEnv*
- env,
- jobject jcaller,
- jlong nativeCPPClass) {
- CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
- CHECK_NATIVE_PTR(env, jcaller, native, "ReturnAString", NULL);
- return native->ReturnAString(env, JavaParamRef<jobject>(env,
- jcaller)).Release();
-}
-
-static base::subtle::AtomicWord g_SampleForTests_javaMethod = 0;
-static jint Java_SampleForTests_javaMethod(JNIEnv* env, jobject obj,
- JniIntWrapper foo,
- JniIntWrapper bar) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "javaMethod",
-
-"("
-"I"
-"I"
-")"
-"I",
- &g_SampleForTests_javaMethod);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id, as_jint(foo), as_jint(bar));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_SampleForTests_staticJavaMethod = 0;
-static jboolean Java_SampleForTests_staticJavaMethod(JNIEnv* env) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, SampleForTests_clazz(env),
- SampleForTests_clazz(env), false);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, SampleForTests_clazz(env),
- "staticJavaMethod",
-
-"("
-")"
-"Z",
- &g_SampleForTests_staticJavaMethod);
-
- jboolean ret =
- env->CallStaticBooleanMethod(SampleForTests_clazz(env),
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_SampleForTests_packagePrivateJavaMethod = 0;
-static void Java_SampleForTests_packagePrivateJavaMethod(JNIEnv* env, jobject
- obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "packagePrivateJavaMethod",
-
-"("
-")"
-"V",
- &g_SampleForTests_packagePrivateJavaMethod);
-
- env->CallVoidMethod(obj,
- method_id);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_SampleForTests_methodThatThrowsException = 0;
-static void Java_SampleForTests_methodThatThrowsException(JNIEnv* env, jobject
- obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "methodThatThrowsException",
-
-"("
-")"
-"V",
- &g_SampleForTests_methodThatThrowsException);
-
- env->CallVoidMethod(obj,
- method_id);
-
-}
-
-static base::subtle::AtomicWord g_InnerStructA_create = 0;
-static ScopedJavaLocalRef<jobject> Java_InnerStructA_create(JNIEnv* env, jlong
- l,
- JniIntWrapper i,
- jstring s) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, InnerStructA_clazz(env),
- InnerStructA_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, InnerStructA_clazz(env),
- "create",
-
-"("
-"J"
-"I"
-"Ljava/lang/String;"
-")"
-"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructA;",
- &g_InnerStructA_create);
-
- jobject ret =
- env->CallStaticObjectMethod(InnerStructA_clazz(env),
- method_id, l, as_jint(i), s);
- jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-static base::subtle::AtomicWord g_SampleForTests_addStructA = 0;
-static void Java_SampleForTests_addStructA(JNIEnv* env, jobject obj, jobject a)
- {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "addStructA",
-
-"("
-"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructA;"
-")"
-"V",
- &g_SampleForTests_addStructA);
-
- env->CallVoidMethod(obj,
- method_id, a);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_SampleForTests_iterateAndDoSomething = 0;
-static void Java_SampleForTests_iterateAndDoSomething(JNIEnv* env, jobject obj)
- {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "iterateAndDoSomething",
-
-"("
-")"
-"V",
- &g_SampleForTests_iterateAndDoSomething);
-
- env->CallVoidMethod(obj,
- method_id);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_InnerStructB_getKey = 0;
-static jlong Java_InnerStructB_getKey(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- InnerStructB_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InnerStructB_clazz(env),
- "getKey",
-
-"("
-")"
-"J",
- &g_InnerStructB_getKey);
-
- jlong ret =
- env->CallLongMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_InnerStructB_getValue = 0;
-static ScopedJavaLocalRef<jstring> Java_InnerStructB_getValue(JNIEnv* env,
- jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- InnerStructB_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InnerStructB_clazz(env),
- "getValue",
-
-"("
-")"
-"Ljava/lang/String;",
- &g_InnerStructB_getValue);
-
- jstring ret =
- static_cast<jstring>(env->CallObjectMethod(obj,
- method_id));
- jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jstring>(env, ret);
-}
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsSampleForTests[] = {
- { "nativeInit",
-"("
-"Ljava/lang/String;"
-")"
-"J",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeInit)
- },
- { "nativeDestroy",
-"("
-"J"
-")"
-"V",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeDestroy)
- },
- { "nativeGetDoubleFunction",
-"("
-")"
-"D",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetDoubleFunction)
- },
- { "nativeGetFloatFunction",
-"("
-")"
-"F",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetFloatFunction)
- },
- { "nativeSetNonPODDatatype",
-"("
-"Landroid/graphics/Rect;"
-")"
-"V",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeSetNonPODDatatype)
- },
- { "nativeGetNonPODDatatype",
-"("
-")"
-"Ljava/lang/Object;",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetNonPODDatatype)
- },
- { "nativeMethod",
-"("
-"J"
-")"
-"I",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod)
- },
- { "nativeMethodOtherP0",
-"("
-"J"
-")"
-"D",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethodOtherP0)
- },
- { "nativeAddStructB",
-"("
-"J"
-"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructB;"
-")"
-"V",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeAddStructB)
- },
- { "nativeIterateAndDoSomethingWithStructB",
-"("
-"J"
-")"
-"V",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeIterateAndDoSomethingWithStructB)
- },
- { "nativeReturnAString",
-"("
-"J"
-")"
-"Ljava/lang/String;",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeReturnAString)
- },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_InnerStructA_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kInnerStructAClassPath).obj()));
- g_SampleForTests_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kSampleForTestsClassPath).obj()));
- g_InnerStructB_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kInnerStructBClassPath).obj()));
-
- const int kMethodsSampleForTestsSize = arraysize(kMethodsSampleForTests);
-
- if (env->RegisterNatives(SampleForTests_clazz(env),
- kMethodsSampleForTests,
- kMethodsSampleForTestsSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, SampleForTests_clazz(env), __FILE__);
- return false;
- }
-
- return true;
-}
-
-} // namespace android
-} // namespace base
-
-#endif // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java b/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
index 4958f04..42d8e56 100644
--- a/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
+++ b/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
@@ -10,6 +10,7 @@ import org.chromium.base.annotations.AccessedByNative;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.CalledByNativeUnchecked;
import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeCall;
import org.chromium.base.annotations.NativeClassQualifiedName;
import java.util.ArrayList;
@@ -164,6 +165,13 @@ class SampleForTests {
// String constants that look like comments don't confuse the generator:
private String mArrgh = "*/*";
+ private @interface SomeAnnotation {}
+
+ // The generator is not confused by @Annotated parameters.
+ @CalledByNative
+ void javaMethodWithAnnotatedParam(@SomeAnnotation int foo) {
+ }
+
// ---------------------------------------------------------------------------------------------
// Java fields which are accessed from C++ code only must be annotated with @AccessedByNative to
// prevent them being eliminated when unreferenced code is stripped.
@@ -301,4 +309,10 @@ class SampleForTests {
native void nativeAddStructB(long nativeCPPClass, InnerStructB b);
native void nativeIterateAndDoSomethingWithStructB(long nativeCPPClass);
native String nativeReturnAString(long nativeCPPClass);
+
+ // This inner class shows how to annotate native methods on inner classes.
+ static class InnerClass {
+ @NativeCall("InnerClass")
+ private static native int nativeGetInnerIntFunction();
+ }
}
diff --git a/base/android/jni_generator/jni_generator.gyp b/base/android/jni_generator/jni_generator.gyp
deleted file mode 100644
index ce936a0..0000000
--- a/base/android/jni_generator/jni_generator.gyp
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright (c) 2012 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.
-
-{
- 'targets': [
- # GYP: //base/android/jni_generator:jni_generator_tests
- {
- 'target_name': 'jni_generator_py_tests',
- 'type': 'none',
- 'variables': {
- 'stamp': '<(INTERMEDIATE_DIR)/jni_generator_py_tests.stamp',
- },
- 'actions': [
- {
- 'action_name': 'run_jni_generator_py_tests',
- 'inputs': [
- 'jni_generator.py',
- 'jni_generator_tests.py',
- 'java/src/org/chromium/example/jni_generator/SampleForTests.java',
- 'golden_sample_for_tests_jni.h',
- ],
- 'outputs': [
- '<(stamp)',
- ],
- 'action': [
- 'python', 'jni_generator_tests.py',
- '--stamp=<(stamp)',
- ],
- },
- ],
- },
- # GYP: //base/android/jni_generator:jni_sample_header
- {
- 'target_name': 'jni_sample_header',
- 'type': 'none',
- 'sources': [
- 'java/src/org/chromium/example/jni_generator/SampleForTests.java',
- ],
- 'variables': {
- 'jni_gen_package': 'example',
- },
- 'includes': [ '../../../build/jni_generator.gypi' ],
- },
- # GYP: //base/android/jni_generator:jni_sample_java
- {
- 'target_name': 'jni_sample_java',
- 'type': 'none',
- 'variables': {
- 'java_in_dir': '../../../base/android/jni_generator/java',
- },
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base_java',
- ],
- 'includes': [ '../../../build/java.gypi' ],
- },
- # GYP: //base/android/jni_generator:jni_generator_tests
- {
- 'target_name': 'jni_generator_tests',
- 'type': 'executable',
- 'dependencies': [
- '../../base.gyp:test_support_base',
- 'jni_generator_py_tests',
- 'jni_sample_header',
- 'jni_sample_java',
- ],
- 'sources': [
- 'sample_for_tests.cc',
- ],
- },
- ],
-}
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index b0134d6..99d8b42 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -138,7 +138,7 @@ def JavaDataTypeToC(java_type):
def WrapCTypeForDeclaration(c_type):
"""Wrap the C datatype in a JavaRef if required."""
if re.match(RE_SCOPED_JNI_TYPES, c_type):
- return 'const JavaParamRef<' + c_type + '>&'
+ return 'const base::android::JavaParamRef<' + c_type + '>&'
else:
return c_type
@@ -153,7 +153,11 @@ def JavaDataTypeToCForCalledByNativeParam(java_type):
if java_type == 'int':
return 'JniIntWrapper'
else:
- return JavaDataTypeToC(java_type)
+ c_type = JavaDataTypeToC(java_type)
+ if re.match(RE_SCOPED_JNI_TYPES, c_type):
+ return 'const base::android::JavaRefOrBare<' + c_type + '>&'
+ else:
+ return c_type
def JavaReturnValueToC(java_type):
@@ -352,8 +356,14 @@ class JniParams(object):
ret = []
for p in [p.strip() for p in params.split(',')]:
items = p.split(' ')
+
+ # Remove @Annotations from parameters.
+ while items[0].startswith('@'):
+ del items[0]
+
if 'final' in items:
items.remove('final')
+
param = Param(
datatype=items[0],
name=(items[1] if len(items) > 1 else 'p%s' % len(ret)),
@@ -402,6 +412,19 @@ def ExtractNatives(contents, ptr_type):
return natives
+def IsMainDexJavaClass(contents):
+ """Returns "true" if the class is annotated with "@MainDex", "false" if not.
+
+ JNI registration doesn't always need to be completed for non-browser processes
+ since most Java code is only used by the browser process. Classes that are
+ needed by non-browser processes must explicitly be annotated with @MainDex
+ to force JNI registration.
+ """
+ re_maindex = re.compile(r'@MainDex[\s\S]*class\s+\w+\s*{')
+ found = re.search(re_maindex, contents)
+ return 'true' if found else 'false'
+
+
def GetStaticCastForReturnType(return_type):
type_map = { 'String' : 'jstring',
'java/lang/String' : 'jstring',
@@ -508,11 +531,17 @@ RE_SCOPED_JNI_TYPES = re.compile('jobject|jclass|jstring|jthrowable|.*Array')
RE_CALLED_BY_NATIVE = re.compile(
'@CalledByNative(?P<Unchecked>(Unchecked)*?)(?:\("(?P<annotation>.*)"\))?'
'\s+(?P<prefix>[\w ]*?)'
+ '(:?\s*@\w+)?' # Ignore annotations in return types.
'\s*(?P<return_type>\S+?)'
'\s+(?P<name>\w+)'
'\s*\((?P<params>[^\)]*)\)')
+# Removes empty lines that are indented (i.e. start with 2x spaces).
+def RemoveIndentedEmptyLines(string):
+ return re.sub('^(?: {2})+$\n', '', string, flags=re.MULTILINE)
+
+
def ExtractCalledByNatives(contents):
"""Parses all methods annotated with @CalledByNative.
@@ -618,8 +647,8 @@ class JNIFromJavaP(object):
value=value.group('value')))
self.inl_header_file_generator = InlHeaderFileGenerator(
- self.namespace, self.fully_qualified_class, [],
- self.called_by_natives, self.constant_fields, options)
+ self.namespace, self.fully_qualified_class, [], self.called_by_natives,
+ self.constant_fields, options)
def GetContent(self):
return self.inl_header_file_generator.GetContent()
@@ -653,12 +682,13 @@ class JNIFromJavaSource(object):
jni_namespace = ExtractJNINamespace(contents) or options.namespace
natives = ExtractNatives(contents, options.ptr_type)
called_by_natives = ExtractCalledByNatives(contents)
+ maindex = IsMainDexJavaClass(contents)
if len(natives) == 0 and len(called_by_natives) == 0:
raise SyntaxError('Unable to find any JNI methods for %s.' %
fully_qualified_class)
inl_header_file_generator = InlHeaderFileGenerator(
- jni_namespace, fully_qualified_class, natives, called_by_natives,
- [], options)
+ jni_namespace, fully_qualified_class, natives, called_by_natives, [],
+ options, maindex)
self.content = inl_header_file_generator.GetContent()
@classmethod
@@ -694,7 +724,7 @@ class InlHeaderFileGenerator(object):
"""Generates an inline header file for JNI integration."""
def __init__(self, namespace, fully_qualified_class, natives,
- called_by_natives, constant_fields, options):
+ called_by_natives, constant_fields, options, maindex='false'):
self.namespace = namespace
self.fully_qualified_class = fully_qualified_class
self.class_name = self.fully_qualified_class.split('/')[-1]
@@ -702,6 +732,7 @@ class InlHeaderFileGenerator(object):
self.called_by_natives = called_by_natives
self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI'
self.constant_fields = constant_fields
+ self.maindex = maindex
self.options = options
@@ -760,6 +791,8 @@ $CLOSE_NAMESPACE
'HEADER_GUARD': self.header_guard,
'INCLUDES': self.GetIncludesString(),
}
+ assert ((values['JNI_NATIVE_METHODS'] == '') ==
+ (values['REGISTER_NATIVES'] == ''))
return WrapOutput(template.substitute(values))
def GetClassPathDefinitionsString(self):
@@ -818,7 +851,7 @@ $CLOSE_NAMESPACE
def GetJNINativeMethodsString(self):
"""Returns the implementation of the array of native methods."""
- if self.options.native_exports and not self.options.native_exports_optional:
+ if not self.options.native_exports_optional:
return ''
template = Template("""\
static const JNINativeMethod kMethods${JAVA_CLASS}[] = {
@@ -829,10 +862,13 @@ ${KMETHODS}
def GetRegisterNativesString(self):
"""Returns the code for RegisterNatives."""
+ natives = self.GetRegisterNativesImplString()
+ if not natives:
+ return ''
+
template = Template("""\
${REGISTER_NATIVES_SIGNATURE} {
${EARLY_EXIT}
-${CLASSES}
${NATIVES}
return true;
}
@@ -841,20 +877,20 @@ ${NATIVES}
early_exit = ''
if self.options.native_exports_optional:
early_exit = """\
- if (base::android::IsManualJniRegistrationDisabled()) return true;
-"""
+ if (jni_generator::ShouldSkipJniRegistration(%s))
+ return true;
+""" % self.maindex
- natives = self.GetRegisterNativesImplString()
values = {'REGISTER_NATIVES_SIGNATURE': signature,
'EARLY_EXIT': early_exit,
- 'CLASSES': self.GetFindClasses(),
'NATIVES': natives,
}
+
return template.substitute(values)
def GetRegisterNativesImplString(self):
"""Returns the shared implementation for RegisterNatives."""
- if self.options.native_exports and not self.options.native_exports_optional:
+ if not self.options.native_exports_optional:
return ''
template = Template("""\
@@ -954,7 +990,8 @@ ${NATIVES}
return template.substitute(values)
def GetJavaParamRefForCall(self, c_type, name):
- return Template('JavaParamRef<${TYPE}>(env, ${NAME})').substitute({
+ return Template(
+ 'base::android::JavaParamRef<${TYPE}>(env, ${NAME})').substitute({
'TYPE': c_type,
'NAME': name,
})
@@ -979,15 +1016,15 @@ ${NATIVES}
params_in_call.append(p.name)
params_in_call = ', '.join(params_in_call)
- if self.options.native_exports:
- stub_visibility = 'extern "C" __attribute__((visibility("default")))\n'
- else:
- stub_visibility = 'static '
return_type = return_declaration = JavaDataTypeToC(native.return_type)
post_call = ''
if re.match(RE_SCOPED_JNI_TYPES, return_type):
post_call = '.Release()'
- return_declaration = 'ScopedJavaLocalRef<' + return_type + '>'
+ return_declaration = ('base::android::ScopedJavaLocalRef<' + return_type +
+ '>')
+ profiling_entered_native = ''
+ if self.options.enable_profiling:
+ profiling_entered_native = 'JNI_LINK_SAVED_FRAME_POINTER;'
values = {
'RETURN': return_type,
'RETURN_DECLARATION': return_declaration,
@@ -997,7 +1034,7 @@ ${NATIVES}
'PARAMS_IN_CALL': params_in_call,
'POST_CALL': post_call,
'STUB_NAME': self.GetStubName(native),
- 'STUB_VISIBILITY': stub_visibility,
+ 'PROFILING_ENTERED_NATIVE': profiling_entered_native,
}
if is_method:
@@ -1010,8 +1047,8 @@ ${NATIVES}
'P0_TYPE': native.p0_type,
})
template = Template("""\
-${STUB_VISIBILITY}${RETURN} ${STUB_NAME}(JNIEnv* env,
- ${PARAMS_IN_STUB}) {
+JNI_GENERATOR_EXPORT ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) {
+ ${PROFILING_ENTERED_NATIVE}
${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME});
CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN});
return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL};
@@ -1021,16 +1058,21 @@ ${STUB_VISIBILITY}${RETURN} ${STUB_NAME}(JNIEnv* env,
template = Template("""
static ${RETURN_DECLARATION} ${NAME}(JNIEnv* env, ${PARAMS});
-${STUB_VISIBILITY}${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) {
+JNI_GENERATOR_EXPORT ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) {
+ ${PROFILING_ENTERED_NATIVE}
return ${NAME}(${PARAMS_IN_CALL})${POST_CALL};
}
""")
- return template.substitute(values)
+ return RemoveIndentedEmptyLines(template.substitute(values))
def GetArgument(self, param):
- return ('as_jint(' + param.name + ')'
- if param.datatype == 'int' else param.name)
+ if param.datatype == 'int':
+ return 'as_jint(' + param.name + ')'
+ elif re.match(RE_SCOPED_JNI_TYPES, JavaDataTypeToC(param.datatype)):
+ return param.name + '.obj()'
+ else:
+ return param.name
def GetArgumentsInCall(self, params):
"""Return a string of arguments to call from native into Java"""
@@ -1043,8 +1085,9 @@ ${STUB_VISIBILITY}${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) {
first_param_in_declaration = ''
first_param_in_call = ('%s_clazz(env)' % java_class)
else:
- first_param_in_declaration = ', jobject obj'
- first_param_in_call = 'obj'
+ first_param_in_declaration = (
+ ', const base::android::JavaRefOrBare<jobject>& obj')
+ first_param_in_call = 'obj.obj()'
params_in_declaration = self.GetCalledByNativeParamsInDeclaration(
called_by_native)
if params_in_declaration:
@@ -1070,10 +1113,13 @@ ${STUB_VISIBILITY}${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) {
pre_call = ' ' + pre_call
return_declaration = return_type + ' ret ='
if re.match(RE_SCOPED_JNI_TYPES, return_type):
- return_type = 'ScopedJavaLocalRef<' + return_type + '>'
+ return_type = 'base::android::ScopedJavaLocalRef<' + return_type + '>'
return_clause = 'return ' + return_type + '(env, ret);'
else:
return_clause = 'return ret;'
+ profiling_leaving_native = ''
+ if self.options.enable_profiling:
+ profiling_leaving_native = 'JNI_SAVE_FRAME_POINTER;'
return {
'JAVA_CLASS': java_class,
'RETURN_TYPE': return_type,
@@ -1089,7 +1135,8 @@ ${STUB_VISIBILITY}${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) {
'PARAMS_IN_CALL': params_in_call,
'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
'CHECK_EXCEPTION': check_exception,
- 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native)
+ 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native),
+ 'PROFILING_LEAVING_NATIVE': profiling_leaving_native,
}
@@ -1106,11 +1153,11 @@ ${FUNCTION_SIGNATURE} {""")
template = Template("""
static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0;
${FUNCTION_HEADER}
- /* Must call RegisterNativesImpl() */
CHECK_CLAZZ(env, ${FIRST_PARAM_IN_CALL},
${JAVA_CLASS}_clazz(env)${OPTIONAL_ERROR_RETURN});
jmethodID method_id =
${GET_METHOD_ID_IMPL}
+ ${PROFILING_LEAVING_NATIVE}
${RETURN_DECLARATION}
${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
method_id${PARAMS_IN_CALL})${POST_CALL};
@@ -1125,7 +1172,7 @@ ${FUNCTION_HEADER}
function_header_with_unused_template.substitute(values))
else:
values['FUNCTION_HEADER'] = function_header_template.substitute(values)
- return template.substitute(values)
+ return RemoveIndentedEmptyLines(template.substitute(values))
def GetKMethodArrayEntry(self, native):
template = Template(' { "native${NAME}", ${JNI_SIGNATURE}, ' +
@@ -1153,13 +1200,9 @@ ${FUNCTION_HEADER}
ret = []
template = Template("""\
const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""")
- native_classes = self.GetUniqueClasses(self.natives)
- called_by_native_classes = self.GetUniqueClasses(self.called_by_natives)
- if self.options.native_exports:
- all_classes = called_by_native_classes
- else:
- all_classes = native_classes
- all_classes.update(called_by_native_classes)
+ all_classes = self.GetUniqueClasses(self.called_by_natives)
+ if self.options.native_exports_optional:
+ all_classes.update(self.GetUniqueClasses(self.natives))
for clazz in all_classes:
values = {
@@ -1169,21 +1212,14 @@ const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""")
ret += [template.substitute(values)]
ret += ''
- class_getter_methods = []
- if self.options.native_exports:
- template = Template("""\
+ template = Template("""\
// Leaking this jclass as we cannot use LazyInstance from some threads.
base::subtle::AtomicWord g_${JAVA_CLASS}_clazz __attribute__((unused)) = 0;
#define ${JAVA_CLASS}_clazz(env) \
base::android::LazyGetClass(env, k${JAVA_CLASS}ClassPath, \
&g_${JAVA_CLASS}_clazz)""")
- else:
- template = Template("""\
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_${JAVA_CLASS}_clazz = NULL;
-#define ${JAVA_CLASS}_clazz(env) g_${JAVA_CLASS}_clazz""")
- for clazz in called_by_native_classes:
+ for clazz in all_classes:
values = {
'JAVA_CLASS': clazz,
}
@@ -1191,19 +1227,6 @@ jclass g_${JAVA_CLASS}_clazz = NULL;
return '\n'.join(ret)
- def GetFindClasses(self):
- """Returns the imlementation of FindClass for all known classes."""
- if self.options.native_exports:
- return '\n'
- template = Template("""\
- g_${JAVA_CLASS}_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, k${JAVA_CLASS}ClassPath).obj()));""")
- ret = []
- for clazz in self.GetUniqueClasses(self.called_by_natives):
- values = {'JAVA_CLASS': clazz}
- ret += [template.substitute(values)]
- return '\n'.join(ret)
-
def GetMethodIDImpl(self, called_by_native):
"""Returns the implementation of GetMethodID."""
template = Template("""\
@@ -1366,15 +1389,12 @@ See SampleForTests.java for more details.
help='The path to cpp command.')
option_parser.add_option('--javap', default='javap',
help='The path to javap command.')
- option_parser.add_option('--native_exports', action='store_true',
- help='Native method registration through .so '
- 'exports.')
option_parser.add_option('--native_exports_optional', action='store_true',
help='Support both explicit and native method'
'registration.')
+ option_parser.add_option('--enable_profiling', action='store_true',
+ help='Add additional profiling instrumentation.')
options, args = option_parser.parse_args(argv)
- if options.native_exports_optional:
- options.native_exports = True
if options.jar_file:
input_file = ExtractJarInputFile(options.jar_file, options.input_file,
options.output_dir)
@@ -1391,9 +1411,7 @@ See SampleForTests.java for more details.
GenerateJNIHeader(input_file, output_file, options)
if options.depfile:
- build_utils.WriteDepfile(
- options.depfile,
- build_utils.GetPythonDependencies())
+ build_utils.WriteDepfile(options.depfile, output_file)
if __name__ == '__main__':
diff --git a/base/android/jni_generator/jni_generator_helper.h b/base/android/jni_generator/jni_generator_helper.h
index 9075d3c..3062806 100644
--- a/base/android/jni_generator/jni_generator_helper.h
+++ b/base/android/jni_generator/jni_generator_helper.h
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-
#ifndef BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
#define BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
@@ -11,30 +10,53 @@
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "base/logging.h"
+#include "build/build_config.h"
// Project-specific macros used by the header files generated by
// jni_generator.py. Different projects can then specify their own
// implementation for this file.
#define CHECK_NATIVE_PTR(env, jcaller, native_ptr, method_name, ...) \
- DCHECK(native_ptr) << method_name;
+ DCHECK(native_ptr) << method_name;
-#define CHECK_CLAZZ(env, jcaller, clazz, ...) \
- DCHECK(clazz);
+#define CHECK_CLAZZ(env, jcaller, clazz, ...) DCHECK(clazz);
-namespace jni_generator {
+#if defined(ARCH_CPU_X86)
+// Dalvik JIT generated code doesn't guarantee 16-byte stack alignment on
+// x86 - use force_align_arg_pointer to realign the stack at the JNI
+// boundary. crbug.com/655248
+#define JNI_GENERATOR_EXPORT \
+ extern "C" __attribute__((visibility("default"), force_align_arg_pointer))
+#else
+#define JNI_GENERATOR_EXPORT extern "C" __attribute__((visibility("default")))
+#endif
- inline void HandleRegistrationError(JNIEnv* env, jclass clazz,
- const char* filename) {
- LOG(ERROR) << "RegisterNatives failed in " << filename;
- }
+namespace jni_generator {
- inline void CheckException(JNIEnv* env) {
- base::android::CheckException(env);
+inline void HandleRegistrationError(JNIEnv* env,
+ jclass clazz,
+ const char* filename) {
+ LOG(ERROR) << "RegisterNatives failed in " << filename;
+}
+
+inline void CheckException(JNIEnv* env) {
+ base::android::CheckException(env);
+}
+
+inline bool ShouldSkipJniRegistration(bool is_maindex_class) {
+ switch (base::android::GetJniRegistrationType()) {
+ case base::android::ALL_JNI_REGISTRATION:
+ return false;
+ case base::android::NO_JNI_REGISTRATION:
+ // TODO(estevenson): Change this to a DCHECK.
+ return true;
+ case base::android::SELECTIVE_JNI_REGISTRATION:
+ return !is_maindex_class;
+ default:
+ NOTREACHED();
+ return false;
}
+}
} // namespace jni_generator
-using base::android::ScopedJavaLocalRef;
-using base::android::JavaParamRef;
-
#endif // BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py
index 5126896..c0c8238 100755
--- a/base/android/jni_generator/jni_generator_tests.py
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -40,8 +40,8 @@ class TestOptions(object):
self.ptr_type = 'long'
self.cpp = 'cpp'
self.javap = 'javap'
- self.native_exports = False
- self.native_exports_optional = False
+ self.native_exports_optional = True
+ self.enable_profiling = False
class TestGenerator(unittest.TestCase):
def assertObjEquals(self, first, second):
@@ -403,6 +403,10 @@ class TestGenerator(unittest.TestCase):
return
}
}
+ @CalledByNative
+ public static @Status int updateStatus(@Status int status) {
+ return getAndUpdateStatus(status);
+ }
@CalledByNativeUnchecked
private void uncheckedCall(int iParam);
@@ -525,6 +529,17 @@ class TestGenerator(unittest.TestCase):
unchecked=False,
),
CalledByNative(
+ return_type='int',
+ system_class=False,
+ static=True,
+ name='updateStatus',
+ method_id_var_name='updateStatus',
+ java_class_name='',
+ params=[Param(datatype='int', name='status')],
+ env_call=('Integer', ''),
+ unchecked=False,
+ ),
+ CalledByNative(
return_type='void',
system_class=False,
static=False,
@@ -819,7 +834,7 @@ public class java.util.HashSet {
content = file(os.path.join(script_dir,
'java/src/org/chromium/example/jni_generator/SampleForTests.java')
).read()
- golden_file = os.path.join(script_dir, 'golden_sample_for_tests_jni.h')
+ golden_file = os.path.join(script_dir, 'SampleForTests_jni.golden')
golden_content = file(golden_file).read()
jni_from_java = jni_generator.JNIFromJavaSource(
content, 'org/chromium/example/jni_generator/SampleForTests',
@@ -935,7 +950,34 @@ class Foo {
natives, [], [], test_options)
self.assertGoldenTextEquals(h.GetContent())
- def runNativeExportsOption(self, optional):
+ def testMainDexFile(self):
+ test_data = """
+ package org.chromium.example.jni_generator;
+
+ @MainDex
+ class Test {
+ private static native int nativeStaticMethod(long nativeTest, int arg1);
+ }
+ """
+ options = TestOptions()
+ jni_from_java = jni_generator.JNIFromJavaSource(
+ test_data, 'org/chromium/foo/Bar', options)
+ self.assertGoldenTextEquals(jni_from_java.GetContent())
+
+ def testNonMainDexFile(self):
+ test_data = """
+ package org.chromium.example.jni_generator;
+
+ class Test {
+ private static native int nativeStaticMethod(long nativeTest, int arg1);
+ }
+ """
+ options = TestOptions()
+ jni_from_java = jni_generator.JNIFromJavaSource(
+ test_data, 'org/chromium/foo/Bar', options)
+ self.assertGoldenTextEquals(jni_from_java.GetContent())
+
+ def testNativeExportsOnlyOption(self):
test_data = """
package org.chromium.example.jni_generator;
@@ -967,19 +1009,10 @@ class Foo {
}
"""
options = TestOptions()
- options.native_exports = True
- options.native_exports_optional = optional
+ options.native_exports_optional = False
jni_from_java = jni_generator.JNIFromJavaSource(
test_data, 'org/chromium/example/jni_generator/SampleForTests', options)
- return jni_from_java.GetContent()
-
- def testNativeExportsOption(self):
- content = self.runNativeExportsOption(False)
- self.assertGoldenTextEquals(content)
-
- def testNativeExportsOptionalOption(self):
- content = self.runNativeExportsOption(True)
- self.assertGoldenTextEquals(content)
+ self.assertGoldenTextEquals(jni_from_java.GetContent())
def testOuterInnerRaises(self):
test_data = """
@@ -1041,7 +1074,7 @@ class Foo {
def TouchStamp(stamp_path):
dir_name = os.path.dirname(stamp_path)
if not os.path.isdir(dir_name):
- os.makedirs()
+ os.makedirs(dir_name)
with open(stamp_path, 'a'):
os.utime(stamp_path, None)
diff --git a/base/android/jni_generator/sample_for_tests.cc b/base/android/jni_generator/sample_for_tests.cc
index 08e5ac9..42b2143 100644
--- a/base/android/jni_generator/sample_for_tests.cc
+++ b/base/android/jni_generator/sample_for_tests.cc
@@ -51,8 +51,8 @@ void CPPClass::AddStructB(JNIEnv* env,
const JavaParamRef<jobject>& caller,
const JavaParamRef<jobject>& structb) {
long key = Java_InnerStructB_getKey(env, structb);
- std::string value = ConvertJavaStringToUTF8(
- env, Java_InnerStructB_getValue(env, structb).obj());
+ std::string value =
+ ConvertJavaStringToUTF8(env, Java_InnerStructB_getValue(env, structb));
map_[key] = value;
}
@@ -100,6 +100,10 @@ static ScopedJavaLocalRef<jobject> GetNonPODDatatype(
return ScopedJavaLocalRef<jobject>();
}
+static jint GetInnerIntFunction(JNIEnv*, const JavaParamRef<jclass>&) {
+ return 0;
+}
+
} // namespace android
} // namespace base
@@ -113,7 +117,7 @@ int main() {
// This is how you call a java method from C++. Note that you must have
// obtained the jobject somehow.
- jobject my_java_object = NULL;
+ ScopedJavaLocalRef<jobject> my_java_object;
int bar = base::android::Java_SampleForTests_javaMethod(
env, my_java_object, 1, 2);
@@ -123,14 +127,16 @@ int main() {
// Creates a "struct" that will then be used by the java side.
ScopedJavaLocalRef<jobject> struct_a =
base::android::Java_InnerStructA_create(
- env, 0, 1, ConvertUTF8ToJavaString(env, "test").obj());
- base::android::Java_SampleForTests_addStructA(
- env, my_java_object, struct_a.obj());
+ env, 0, 1, ConvertUTF8ToJavaString(env, "test"));
+ base::android::Java_SampleForTests_addStructA(env, my_java_object,
+ struct_a);
}
base::android::Java_SampleForTests_iterateAndDoSomething(env, my_java_object);
base::android::Java_SampleForTests_packagePrivateJavaMethod(env,
my_java_object);
base::android::Java_SampleForTests_methodThatThrowsException(env,
my_java_object);
+ base::android::Java_SampleForTests_javaMethodWithAnnotatedParam(
+ env, my_java_object, 42);
return 0;
}
diff --git a/base/android/jni_generator/testCalledByNatives.golden b/base/android/jni_generator/testCalledByNatives.golden
index 3bc586c..ac86b2e 100644
--- a/base/android/jni_generator/testCalledByNatives.golden
+++ b/base/android/jni_generator/testCalledByNatives.golden
@@ -21,32 +21,31 @@ namespace {
const char kTestJniClassPath[] = "org/chromium/TestJni";
const char kInfoBarClassPath[] = "org/chromium/TestJni$InfoBar";
// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_TestJni_clazz = NULL;
-#define TestJni_clazz(env) g_TestJni_clazz
+base::subtle::AtomicWord g_TestJni_clazz __attribute__((unused)) = 0;
+#define TestJni_clazz(env) base::android::LazyGetClass(env, kTestJniClassPath, &g_TestJni_clazz)
// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_InfoBar_clazz = NULL;
-#define InfoBar_clazz(env) g_InfoBar_clazz
+base::subtle::AtomicWord g_InfoBar_clazz __attribute__((unused)) = 0;
+#define InfoBar_clazz(env) base::android::LazyGetClass(env, kInfoBarClassPath, &g_InfoBar_clazz)
} // namespace
// Step 2: method stubs.
static base::subtle::AtomicWord g_TestJni_showConfirmInfoBar = 0;
-static ScopedJavaLocalRef<jobject> Java_TestJni_showConfirmInfoBar(JNIEnv* env,
- jobject obj, JniIntWrapper nativeInfoBar,
- jstring buttonOk,
- jstring buttonCancel,
- jstring title,
- jobject icon) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static base::android::ScopedJavaLocalRef<jobject>
+ Java_TestJni_showConfirmInfoBar(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper nativeInfoBar,
+ const base::android::JavaRefOrBare<jstring>& buttonOk,
+ const base::android::JavaRefOrBare<jstring>& buttonCancel,
+ const base::android::JavaRefOrBare<jstring>& title,
+ const base::android::JavaRefOrBare<jobject>& icon) {
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env), NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"showConfirmInfoBar",
-
"("
"I"
"Ljava/lang/String;"
@@ -58,28 +57,27 @@ static ScopedJavaLocalRef<jobject> Java_TestJni_showConfirmInfoBar(JNIEnv* env,
&g_TestJni_showConfirmInfoBar);
jobject ret =
- env->CallObjectMethod(obj,
- method_id, as_jint(nativeInfoBar), buttonOk, buttonCancel, title,
- icon);
+ env->CallObjectMethod(obj.obj(),
+ method_id, as_jint(nativeInfoBar), buttonOk.obj(), buttonCancel.obj(),
+ title.obj(), icon.obj());
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobject>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobject>(env, ret);
}
static base::subtle::AtomicWord g_TestJni_showAutoLoginInfoBar = 0;
-static ScopedJavaLocalRef<jobject> Java_TestJni_showAutoLoginInfoBar(JNIEnv*
- env, jobject obj, JniIntWrapper nativeInfoBar,
- jstring realm,
- jstring account,
- jstring args) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static base::android::ScopedJavaLocalRef<jobject>
+ Java_TestJni_showAutoLoginInfoBar(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper nativeInfoBar,
+ const base::android::JavaRefOrBare<jstring>& realm,
+ const base::android::JavaRefOrBare<jstring>& account,
+ const base::android::JavaRefOrBare<jstring>& args) {
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env), NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"showAutoLoginInfoBar",
-
"("
"I"
"Ljava/lang/String;"
@@ -90,40 +88,39 @@ static ScopedJavaLocalRef<jobject> Java_TestJni_showAutoLoginInfoBar(JNIEnv*
&g_TestJni_showAutoLoginInfoBar);
jobject ret =
- env->CallObjectMethod(obj,
- method_id, as_jint(nativeInfoBar), realm, account, args);
+ env->CallObjectMethod(obj.obj(),
+ method_id, as_jint(nativeInfoBar), realm.obj(), account.obj(),
+ args.obj());
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobject>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobject>(env, ret);
}
static base::subtle::AtomicWord g_InfoBar_dismiss = 0;
-static void Java_InfoBar_dismiss(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static void Java_InfoBar_dismiss(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
InfoBar_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, InfoBar_clazz(env),
"dismiss",
-
"("
")"
"V",
&g_InfoBar_dismiss);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_TestJni_shouldShowAutoLogin = 0;
-static jboolean Java_TestJni_shouldShowAutoLogin(JNIEnv* env, jobject view,
- jstring realm,
- jstring account,
- jstring args) {
- /* Must call RegisterNativesImpl() */
+static jboolean Java_TestJni_shouldShowAutoLogin(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& view,
+ const base::android::JavaRefOrBare<jstring>& realm,
+ const base::android::JavaRefOrBare<jstring>& account,
+ const base::android::JavaRefOrBare<jstring>& args) {
CHECK_CLAZZ(env, TestJni_clazz(env),
TestJni_clazz(env), false);
jmethodID method_id =
@@ -131,7 +128,6 @@ static jboolean Java_TestJni_shouldShowAutoLogin(JNIEnv* env, jobject view,
base::android::MethodID::TYPE_STATIC>(
env, TestJni_clazz(env),
"shouldShowAutoLogin",
-
"("
"Landroid/view/View;"
"Ljava/lang/String;"
@@ -143,15 +139,14 @@ static jboolean Java_TestJni_shouldShowAutoLogin(JNIEnv* env, jobject view,
jboolean ret =
env->CallStaticBooleanMethod(TestJni_clazz(env),
- method_id, view, realm, account, args);
+ method_id, view.obj(), realm.obj(), account.obj(), args.obj());
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_TestJni_openUrl = 0;
-static ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv* env, jstring
- url) {
- /* Must call RegisterNativesImpl() */
+static base::android::ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv*
+ env, const base::android::JavaRefOrBare<jstring>& url) {
CHECK_CLAZZ(env, TestJni_clazz(env),
TestJni_clazz(env), NULL);
jmethodID method_id =
@@ -159,7 +154,6 @@ static ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv* env, jstring
base::android::MethodID::TYPE_STATIC>(
env, TestJni_clazz(env),
"openUrl",
-
"("
"Ljava/lang/String;"
")"
@@ -168,27 +162,25 @@ static ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv* env, jstring
jobject ret =
env->CallStaticObjectMethod(TestJni_clazz(env),
- method_id, url);
+ method_id, url.obj());
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobject>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobject>(env, ret);
}
static base::subtle::AtomicWord g_TestJni_activateHardwareAcceleration = 0;
-static void Java_TestJni_activateHardwareAcceleration(JNIEnv* env, jobject obj,
- jboolean activated,
+static void Java_TestJni_activateHardwareAcceleration(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, jboolean activated,
JniIntWrapper iPid,
JniIntWrapper iType,
JniIntWrapper iPrimaryID,
JniIntWrapper iSecondaryID) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"activateHardwareAcceleration",
-
"("
"Z"
"I"
@@ -199,310 +191,307 @@ static void Java_TestJni_activateHardwareAcceleration(JNIEnv* env, jobject obj,
"V",
&g_TestJni_activateHardwareAcceleration);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id, activated, as_jint(iPid), as_jint(iType),
as_jint(iPrimaryID), as_jint(iSecondaryID));
jni_generator::CheckException(env);
+}
+
+static base::subtle::AtomicWord g_TestJni_updateStatus = 0;
+static jint Java_TestJni_updateStatus(JNIEnv* env, JniIntWrapper status) {
+ CHECK_CLAZZ(env, TestJni_clazz(env),
+ TestJni_clazz(env), 0);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_STATIC>(
+ env, TestJni_clazz(env),
+ "updateStatus",
+"("
+"I"
+")"
+"I",
+ &g_TestJni_updateStatus);
+ jint ret =
+ env->CallStaticIntMethod(TestJni_clazz(env),
+ method_id, as_jint(status));
+ jni_generator::CheckException(env);
+ return ret;
}
static base::subtle::AtomicWord g_TestJni_uncheckedCall = 0;
-static void Java_TestJni_uncheckedCall(JNIEnv* env, jobject obj, JniIntWrapper
- iParam) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static void Java_TestJni_uncheckedCall(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper iParam) {
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"uncheckedCall",
-
"("
"I"
")"
"V",
&g_TestJni_uncheckedCall);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id, as_jint(iParam));
-
}
static base::subtle::AtomicWord g_TestJni_returnByteArray = 0;
-static ScopedJavaLocalRef<jbyteArray> Java_TestJni_returnByteArray(JNIEnv* env,
- jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static base::android::ScopedJavaLocalRef<jbyteArray>
+ Java_TestJni_returnByteArray(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env), NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"returnByteArray",
-
"("
")"
"[B",
&g_TestJni_returnByteArray);
jbyteArray ret =
- static_cast<jbyteArray>(env->CallObjectMethod(obj,
+ static_cast<jbyteArray>(env->CallObjectMethod(obj.obj(),
method_id));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jbyteArray>(env, ret);
+ return base::android::ScopedJavaLocalRef<jbyteArray>(env, ret);
}
static base::subtle::AtomicWord g_TestJni_returnBooleanArray = 0;
-static ScopedJavaLocalRef<jbooleanArray> Java_TestJni_returnBooleanArray(JNIEnv*
- env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static base::android::ScopedJavaLocalRef<jbooleanArray>
+ Java_TestJni_returnBooleanArray(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env), NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"returnBooleanArray",
-
"("
")"
"[Z",
&g_TestJni_returnBooleanArray);
jbooleanArray ret =
- static_cast<jbooleanArray>(env->CallObjectMethod(obj,
+ static_cast<jbooleanArray>(env->CallObjectMethod(obj.obj(),
method_id));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jbooleanArray>(env, ret);
+ return base::android::ScopedJavaLocalRef<jbooleanArray>(env, ret);
}
static base::subtle::AtomicWord g_TestJni_returnCharArray = 0;
-static ScopedJavaLocalRef<jcharArray> Java_TestJni_returnCharArray(JNIEnv* env,
- jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static base::android::ScopedJavaLocalRef<jcharArray>
+ Java_TestJni_returnCharArray(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env), NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"returnCharArray",
-
"("
")"
"[C",
&g_TestJni_returnCharArray);
jcharArray ret =
- static_cast<jcharArray>(env->CallObjectMethod(obj,
+ static_cast<jcharArray>(env->CallObjectMethod(obj.obj(),
method_id));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jcharArray>(env, ret);
+ return base::android::ScopedJavaLocalRef<jcharArray>(env, ret);
}
static base::subtle::AtomicWord g_TestJni_returnShortArray = 0;
-static ScopedJavaLocalRef<jshortArray> Java_TestJni_returnShortArray(JNIEnv*
- env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static base::android::ScopedJavaLocalRef<jshortArray>
+ Java_TestJni_returnShortArray(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env), NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"returnShortArray",
-
"("
")"
"[S",
&g_TestJni_returnShortArray);
jshortArray ret =
- static_cast<jshortArray>(env->CallObjectMethod(obj,
+ static_cast<jshortArray>(env->CallObjectMethod(obj.obj(),
method_id));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jshortArray>(env, ret);
+ return base::android::ScopedJavaLocalRef<jshortArray>(env, ret);
}
static base::subtle::AtomicWord g_TestJni_returnIntArray = 0;
-static ScopedJavaLocalRef<jintArray> Java_TestJni_returnIntArray(JNIEnv* env,
- jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static base::android::ScopedJavaLocalRef<jintArray>
+ Java_TestJni_returnIntArray(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env), NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"returnIntArray",
-
"("
")"
"[I",
&g_TestJni_returnIntArray);
jintArray ret =
- static_cast<jintArray>(env->CallObjectMethod(obj,
+ static_cast<jintArray>(env->CallObjectMethod(obj.obj(),
method_id));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jintArray>(env, ret);
+ return base::android::ScopedJavaLocalRef<jintArray>(env, ret);
}
static base::subtle::AtomicWord g_TestJni_returnLongArray = 0;
-static ScopedJavaLocalRef<jlongArray> Java_TestJni_returnLongArray(JNIEnv* env,
- jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static base::android::ScopedJavaLocalRef<jlongArray>
+ Java_TestJni_returnLongArray(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env), NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"returnLongArray",
-
"("
")"
"[J",
&g_TestJni_returnLongArray);
jlongArray ret =
- static_cast<jlongArray>(env->CallObjectMethod(obj,
+ static_cast<jlongArray>(env->CallObjectMethod(obj.obj(),
method_id));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jlongArray>(env, ret);
+ return base::android::ScopedJavaLocalRef<jlongArray>(env, ret);
}
static base::subtle::AtomicWord g_TestJni_returnDoubleArray = 0;
-static ScopedJavaLocalRef<jdoubleArray> Java_TestJni_returnDoubleArray(JNIEnv*
- env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static base::android::ScopedJavaLocalRef<jdoubleArray>
+ Java_TestJni_returnDoubleArray(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env), NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"returnDoubleArray",
-
"("
")"
"[D",
&g_TestJni_returnDoubleArray);
jdoubleArray ret =
- static_cast<jdoubleArray>(env->CallObjectMethod(obj,
+ static_cast<jdoubleArray>(env->CallObjectMethod(obj.obj(),
method_id));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jdoubleArray>(env, ret);
+ return base::android::ScopedJavaLocalRef<jdoubleArray>(env, ret);
}
static base::subtle::AtomicWord g_TestJni_returnObjectArray = 0;
-static ScopedJavaLocalRef<jobjectArray> Java_TestJni_returnObjectArray(JNIEnv*
- env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static base::android::ScopedJavaLocalRef<jobjectArray>
+ Java_TestJni_returnObjectArray(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env), NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"returnObjectArray",
-
"("
")"
"[Ljava/lang/Object;",
&g_TestJni_returnObjectArray);
jobjectArray ret =
- static_cast<jobjectArray>(env->CallObjectMethod(obj,
+ static_cast<jobjectArray>(env->CallObjectMethod(obj.obj(),
method_id));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobjectArray>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobjectArray>(env, ret);
}
static base::subtle::AtomicWord g_TestJni_returnArrayOfByteArray = 0;
-static ScopedJavaLocalRef<jobjectArray>
- Java_TestJni_returnArrayOfByteArray(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static base::android::ScopedJavaLocalRef<jobjectArray>
+ Java_TestJni_returnArrayOfByteArray(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env), NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"returnArrayOfByteArray",
-
"("
")"
"[[B",
&g_TestJni_returnArrayOfByteArray);
jobjectArray ret =
- static_cast<jobjectArray>(env->CallObjectMethod(obj,
+ static_cast<jobjectArray>(env->CallObjectMethod(obj.obj(),
method_id));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobjectArray>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobjectArray>(env, ret);
}
static base::subtle::AtomicWord g_TestJni_getCompressFormat = 0;
-static ScopedJavaLocalRef<jobject> Java_TestJni_getCompressFormat(JNIEnv* env,
- jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static base::android::ScopedJavaLocalRef<jobject>
+ Java_TestJni_getCompressFormat(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env), NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"getCompressFormat",
-
"("
")"
"Landroid/graphics/Bitmap$CompressFormat;",
&g_TestJni_getCompressFormat);
jobject ret =
- env->CallObjectMethod(obj,
+ env->CallObjectMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobject>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobject>(env, ret);
}
static base::subtle::AtomicWord g_TestJni_getCompressFormatList = 0;
-static ScopedJavaLocalRef<jobject> Java_TestJni_getCompressFormatList(JNIEnv*
- env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static base::android::ScopedJavaLocalRef<jobject>
+ Java_TestJni_getCompressFormatList(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
TestJni_clazz(env), NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, TestJni_clazz(env),
"getCompressFormatList",
-
"("
")"
"Ljava/util/List;",
&g_TestJni_getCompressFormatList);
jobject ret =
- env->CallObjectMethod(obj,
+ env->CallObjectMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobject>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobject>(env, ret);
}
// Step 3: RegisterNatives.
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kTestJniClassPath).obj()));
- g_InfoBar_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kInfoBarClassPath).obj()));
-
- return true;
-}
-
#endif // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testConstantsFromJavaP.golden b/base/android/jni_generator/testConstantsFromJavaP.golden
index 97c00f9..b16956f 100644
--- a/base/android/jni_generator/testConstantsFromJavaP.golden
+++ b/base/android/jni_generator/testConstantsFromJavaP.golden
@@ -20,8 +20,8 @@
namespace {
const char kMotionEventClassPath[] = "android/view/MotionEvent";
// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_MotionEvent_clazz = NULL;
-#define MotionEvent_clazz(env) g_MotionEvent_clazz
+base::subtle::AtomicWord g_MotionEvent_clazz __attribute__((unused)) = 0;
+#define MotionEvent_clazz(env) base::android::LazyGetClass(env, kMotionEventClassPath, &g_MotionEvent_clazz)
} // namespace
@@ -113,11 +113,11 @@ enum Java_MotionEvent_constant_fields {
// Step 2: method stubs.
static base::subtle::AtomicWord g_MotionEvent_finalize = 0;
-static void Java_MotionEvent_finalize(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static void Java_MotionEvent_finalize(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static void Java_MotionEvent_finalize(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static void Java_MotionEvent_finalize(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -127,22 +127,21 @@ static void Java_MotionEvent_finalize(JNIEnv* env, jobject obj) {
"()V",
&g_MotionEvent_finalize);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord
g_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I = 0;
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
Java_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I(JNIEnv*
env, jlong p0,
jlong p1,
JniIntWrapper p2,
JniIntWrapper p3,
- jobjectArray p4,
- jobjectArray p5,
+ const base::android::JavaRefOrBare<jobjectArray>& p4,
+ const base::android::JavaRefOrBare<jobjectArray>& p5,
JniIntWrapper p6,
JniIntWrapper p7,
jfloat p8,
@@ -151,14 +150,14 @@ static ScopedJavaLocalRef<jobject>
JniIntWrapper p11,
JniIntWrapper p12,
JniIntWrapper p13) __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
Java_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I(JNIEnv*
env, jlong p0,
jlong p1,
JniIntWrapper p2,
JniIntWrapper p3,
- jobjectArray p4,
- jobjectArray p5,
+ const base::android::JavaRefOrBare<jobjectArray>& p4,
+ const base::android::JavaRefOrBare<jobjectArray>& p5,
JniIntWrapper p6,
JniIntWrapper p7,
jfloat p8,
@@ -167,7 +166,6 @@ static ScopedJavaLocalRef<jobject>
JniIntWrapper p11,
JniIntWrapper p12,
JniIntWrapper p13) {
- /* Must call RegisterNativesImpl() */
CHECK_CLAZZ(env, MotionEvent_clazz(env),
MotionEvent_clazz(env), NULL);
jmethodID method_id =
@@ -180,23 +178,23 @@ static ScopedJavaLocalRef<jobject>
jobject ret =
env->CallStaticObjectMethod(MotionEvent_clazz(env),
- method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, as_jint(p6),
- as_jint(p7), p8, p9, as_jint(p10), as_jint(p11), as_jint(p12),
- as_jint(p13));
+ method_id, p0, p1, as_jint(p2), as_jint(p3), p4.obj(), p5.obj(),
+ as_jint(p6), as_jint(p7), p8, p9, as_jint(p10), as_jint(p11),
+ as_jint(p12), as_jint(p13));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobject>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobject>(env, ret);
}
static base::subtle::AtomicWord
g_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I = 0;
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
Java_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I(JNIEnv* env,
jlong p0,
jlong p1,
JniIntWrapper p2,
JniIntWrapper p3,
- jintArray p4,
- jobjectArray p5,
+ const base::android::JavaRefOrBare<jintArray>& p4,
+ const base::android::JavaRefOrBare<jobjectArray>& p5,
JniIntWrapper p6,
jfloat p7,
jfloat p8,
@@ -204,14 +202,14 @@ static ScopedJavaLocalRef<jobject>
JniIntWrapper p10,
JniIntWrapper p11,
JniIntWrapper p12) __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
Java_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I(JNIEnv* env,
jlong p0,
jlong p1,
JniIntWrapper p2,
JniIntWrapper p3,
- jintArray p4,
- jobjectArray p5,
+ const base::android::JavaRefOrBare<jintArray>& p4,
+ const base::android::JavaRefOrBare<jobjectArray>& p5,
JniIntWrapper p6,
jfloat p7,
jfloat p8,
@@ -219,7 +217,6 @@ static ScopedJavaLocalRef<jobject>
JniIntWrapper p10,
JniIntWrapper p11,
JniIntWrapper p12) {
- /* Must call RegisterNativesImpl() */
CHECK_CLAZZ(env, MotionEvent_clazz(env),
MotionEvent_clazz(env), NULL);
jmethodID method_id =
@@ -232,15 +229,16 @@ static ScopedJavaLocalRef<jobject>
jobject ret =
env->CallStaticObjectMethod(MotionEvent_clazz(env),
- method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, as_jint(p6), p7,
- p8, as_jint(p9), as_jint(p10), as_jint(p11), as_jint(p12));
+ method_id, p0, p1, as_jint(p2), as_jint(p3), p4.obj(), p5.obj(),
+ as_jint(p6), p7, p8, as_jint(p9), as_jint(p10), as_jint(p11),
+ as_jint(p12));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobject>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobject>(env, ret);
}
static base::subtle::AtomicWord g_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I
= 0;
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
Java_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
jlong p1,
JniIntWrapper p2,
@@ -253,7 +251,7 @@ static ScopedJavaLocalRef<jobject>
jfloat p9,
JniIntWrapper p10,
JniIntWrapper p11) __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
Java_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
jlong p1,
JniIntWrapper p2,
@@ -266,7 +264,6 @@ static ScopedJavaLocalRef<jobject>
jfloat p9,
JniIntWrapper p10,
JniIntWrapper p11) {
- /* Must call RegisterNativesImpl() */
CHECK_CLAZZ(env, MotionEvent_clazz(env),
MotionEvent_clazz(env), NULL);
jmethodID method_id =
@@ -282,12 +279,12 @@ static ScopedJavaLocalRef<jobject>
method_id, p0, p1, as_jint(p2), p3, p4, p5, p6, as_jint(p7), p8, p9,
as_jint(p10), as_jint(p11));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobject>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobject>(env, ret);
}
static base::subtle::AtomicWord
g_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I = 0;
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
Java_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
jlong p1,
JniIntWrapper p2,
@@ -301,7 +298,7 @@ static ScopedJavaLocalRef<jobject>
jfloat p10,
JniIntWrapper p11,
JniIntWrapper p12) __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
Java_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
jlong p1,
JniIntWrapper p2,
@@ -315,7 +312,6 @@ static ScopedJavaLocalRef<jobject>
jfloat p10,
JniIntWrapper p11,
JniIntWrapper p12) {
- /* Must call RegisterNativesImpl() */
CHECK_CLAZZ(env, MotionEvent_clazz(env),
MotionEvent_clazz(env), NULL);
jmethodID method_id =
@@ -331,25 +327,24 @@ static ScopedJavaLocalRef<jobject>
method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, p6, p7,
as_jint(p8), p9, p10, as_jint(p11), as_jint(p12));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobject>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobject>(env, ret);
}
static base::subtle::AtomicWord g_MotionEvent_obtainAVME_J_J_I_F_F_I = 0;
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
Java_MotionEvent_obtainAVME_J_J_I_F_F_I(JNIEnv* env, jlong p0,
jlong p1,
JniIntWrapper p2,
jfloat p3,
jfloat p4,
JniIntWrapper p5) __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
Java_MotionEvent_obtainAVME_J_J_I_F_F_I(JNIEnv* env, jlong p0,
jlong p1,
JniIntWrapper p2,
jfloat p3,
jfloat p4,
JniIntWrapper p5) {
- /* Must call RegisterNativesImpl() */
CHECK_CLAZZ(env, MotionEvent_clazz(env),
MotionEvent_clazz(env), NULL);
jmethodID method_id =
@@ -364,15 +359,16 @@ static ScopedJavaLocalRef<jobject>
env->CallStaticObjectMethod(MotionEvent_clazz(env),
method_id, p0, p1, as_jint(p2), p3, p4, as_jint(p5));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobject>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobject>(env, ret);
}
static base::subtle::AtomicWord g_MotionEvent_obtainAVME_AVME = 0;
-static ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainAVME_AVME(JNIEnv* env,
- jobject p0) __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainAVME_AVME(JNIEnv* env,
- jobject p0) {
- /* Must call RegisterNativesImpl() */
+static base::android::ScopedJavaLocalRef<jobject>
+ Java_MotionEvent_obtainAVME_AVME(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& p0) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+ Java_MotionEvent_obtainAVME_AVME(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& p0) {
CHECK_CLAZZ(env, MotionEvent_clazz(env),
MotionEvent_clazz(env), NULL);
jmethodID method_id =
@@ -385,17 +381,18 @@ static ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainAVME_AVME(JNIEnv* env,
jobject ret =
env->CallStaticObjectMethod(MotionEvent_clazz(env),
- method_id, p0);
+ method_id, p0.obj());
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobject>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobject>(env, ret);
}
static base::subtle::AtomicWord g_MotionEvent_obtainNoHistory = 0;
-static ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainNoHistory(JNIEnv* env,
- jobject p0) __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainNoHistory(JNIEnv* env,
- jobject p0) {
- /* Must call RegisterNativesImpl() */
+static base::android::ScopedJavaLocalRef<jobject>
+ Java_MotionEvent_obtainNoHistory(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& p0) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+ Java_MotionEvent_obtainNoHistory(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& p0) {
CHECK_CLAZZ(env, MotionEvent_clazz(env),
MotionEvent_clazz(env), NULL);
jmethodID method_id =
@@ -408,17 +405,17 @@ static ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainNoHistory(JNIEnv* env,
jobject ret =
env->CallStaticObjectMethod(MotionEvent_clazz(env),
- method_id, p0);
+ method_id, p0.obj());
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobject>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobject>(env, ret);
}
static base::subtle::AtomicWord g_MotionEvent_recycle = 0;
-static void Java_MotionEvent_recycle(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static void Java_MotionEvent_recycle(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static void Java_MotionEvent_recycle(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static void Java_MotionEvent_recycle(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -428,18 +425,17 @@ static void Java_MotionEvent_recycle(JNIEnv* env, jobject obj) {
"()V",
&g_MotionEvent_recycle);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_MotionEvent_getDeviceId = 0;
-static jint Java_MotionEvent_getDeviceId(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jint Java_MotionEvent_getDeviceId(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_MotionEvent_getDeviceId(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jint Java_MotionEvent_getDeviceId(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -450,18 +446,18 @@ static jint Java_MotionEvent_getDeviceId(JNIEnv* env, jobject obj) {
&g_MotionEvent_getDeviceId);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getSource = 0;
-static jint Java_MotionEvent_getSource(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jint Java_MotionEvent_getSource(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_MotionEvent_getSource(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jint Java_MotionEvent_getSource(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -472,19 +468,19 @@ static jint Java_MotionEvent_getSource(JNIEnv* env, jobject obj) {
&g_MotionEvent_getSource);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_setSource = 0;
-static void Java_MotionEvent_setSource(JNIEnv* env, jobject obj, JniIntWrapper
- p0) __attribute__ ((unused));
-static void Java_MotionEvent_setSource(JNIEnv* env, jobject obj, JniIntWrapper
- p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static void Java_MotionEvent_setSource(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static void Java_MotionEvent_setSource(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -494,18 +490,17 @@ static void Java_MotionEvent_setSource(JNIEnv* env, jobject obj, JniIntWrapper
"(I)V",
&g_MotionEvent_setSource);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_MotionEvent_getAction = 0;
-static jint Java_MotionEvent_getAction(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jint Java_MotionEvent_getAction(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_MotionEvent_getAction(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jint Java_MotionEvent_getAction(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -516,18 +511,18 @@ static jint Java_MotionEvent_getAction(JNIEnv* env, jobject obj) {
&g_MotionEvent_getAction);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getActionMasked = 0;
-static jint Java_MotionEvent_getActionMasked(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jint Java_MotionEvent_getActionMasked(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_MotionEvent_getActionMasked(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jint Java_MotionEvent_getActionMasked(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -538,18 +533,18 @@ static jint Java_MotionEvent_getActionMasked(JNIEnv* env, jobject obj) {
&g_MotionEvent_getActionMasked);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getActionIndex = 0;
-static jint Java_MotionEvent_getActionIndex(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jint Java_MotionEvent_getActionIndex(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_MotionEvent_getActionIndex(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jint Java_MotionEvent_getActionIndex(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -560,18 +555,18 @@ static jint Java_MotionEvent_getActionIndex(JNIEnv* env, jobject obj) {
&g_MotionEvent_getActionIndex);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getFlags = 0;
-static jint Java_MotionEvent_getFlags(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jint Java_MotionEvent_getFlags(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_MotionEvent_getFlags(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jint Java_MotionEvent_getFlags(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -582,18 +577,18 @@ static jint Java_MotionEvent_getFlags(JNIEnv* env, jobject obj) {
&g_MotionEvent_getFlags);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getDownTime = 0;
-static jlong Java_MotionEvent_getDownTime(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jlong Java_MotionEvent_getDownTime(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jlong Java_MotionEvent_getDownTime(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jlong Java_MotionEvent_getDownTime(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -604,18 +599,18 @@ static jlong Java_MotionEvent_getDownTime(JNIEnv* env, jobject obj) {
&g_MotionEvent_getDownTime);
jlong ret =
- env->CallLongMethod(obj,
+ env->CallLongMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getEventTime = 0;
-static jlong Java_MotionEvent_getEventTime(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jlong Java_MotionEvent_getEventTime(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jlong Java_MotionEvent_getEventTime(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jlong Java_MotionEvent_getEventTime(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -626,18 +621,18 @@ static jlong Java_MotionEvent_getEventTime(JNIEnv* env, jobject obj) {
&g_MotionEvent_getEventTime);
jlong ret =
- env->CallLongMethod(obj,
+ env->CallLongMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getXF = 0;
-static jfloat Java_MotionEvent_getXF(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jfloat Java_MotionEvent_getXF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getXF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getXF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -648,18 +643,18 @@ static jfloat Java_MotionEvent_getXF(JNIEnv* env, jobject obj) {
&g_MotionEvent_getXF);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getYF = 0;
-static jfloat Java_MotionEvent_getYF(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jfloat Java_MotionEvent_getYF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getYF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getYF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -670,18 +665,18 @@ static jfloat Java_MotionEvent_getYF(JNIEnv* env, jobject obj) {
&g_MotionEvent_getYF);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getPressureF = 0;
-static jfloat Java_MotionEvent_getPressureF(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getPressureF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getPressureF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getPressureF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -692,18 +687,18 @@ static jfloat Java_MotionEvent_getPressureF(JNIEnv* env, jobject obj) {
&g_MotionEvent_getPressureF);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getSizeF = 0;
-static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -714,18 +709,18 @@ static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, jobject obj) {
&g_MotionEvent_getSizeF);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getTouchMajorF = 0;
-static jfloat Java_MotionEvent_getTouchMajorF(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getTouchMajorF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getTouchMajorF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getTouchMajorF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -736,18 +731,18 @@ static jfloat Java_MotionEvent_getTouchMajorF(JNIEnv* env, jobject obj) {
&g_MotionEvent_getTouchMajorF);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getTouchMinorF = 0;
-static jfloat Java_MotionEvent_getTouchMinorF(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getTouchMinorF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getTouchMinorF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getTouchMinorF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -758,18 +753,18 @@ static jfloat Java_MotionEvent_getTouchMinorF(JNIEnv* env, jobject obj) {
&g_MotionEvent_getTouchMinorF);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getToolMajorF = 0;
-static jfloat Java_MotionEvent_getToolMajorF(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getToolMajorF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getToolMajorF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getToolMajorF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -780,18 +775,18 @@ static jfloat Java_MotionEvent_getToolMajorF(JNIEnv* env, jobject obj) {
&g_MotionEvent_getToolMajorF);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getToolMinorF = 0;
-static jfloat Java_MotionEvent_getToolMinorF(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getToolMinorF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getToolMinorF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getToolMinorF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -802,18 +797,18 @@ static jfloat Java_MotionEvent_getToolMinorF(JNIEnv* env, jobject obj) {
&g_MotionEvent_getToolMinorF);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getOrientationF = 0;
-static jfloat Java_MotionEvent_getOrientationF(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getOrientationF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getOrientationF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getOrientationF(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -824,19 +819,19 @@ static jfloat Java_MotionEvent_getOrientationF(JNIEnv* env, jobject obj) {
&g_MotionEvent_getOrientationF);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getAxisValueF_I = 0;
-static jfloat Java_MotionEvent_getAxisValueF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getAxisValueF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getAxisValueF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getAxisValueF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -847,18 +842,18 @@ static jfloat Java_MotionEvent_getAxisValueF_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getAxisValueF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getPointerCount = 0;
-static jint Java_MotionEvent_getPointerCount(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jint Java_MotionEvent_getPointerCount(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_MotionEvent_getPointerCount(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jint Java_MotionEvent_getPointerCount(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -869,19 +864,19 @@ static jint Java_MotionEvent_getPointerCount(JNIEnv* env, jobject obj) {
&g_MotionEvent_getPointerCount);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getPointerId = 0;
-static jint Java_MotionEvent_getPointerId(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jint Java_MotionEvent_getPointerId(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_MotionEvent_getPointerId(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jint Java_MotionEvent_getPointerId(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -892,19 +887,19 @@ static jint Java_MotionEvent_getPointerId(JNIEnv* env, jobject obj,
&g_MotionEvent_getPointerId);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getToolType = 0;
-static jint Java_MotionEvent_getToolType(JNIEnv* env, jobject obj, JniIntWrapper
- p0) __attribute__ ((unused));
-static jint Java_MotionEvent_getToolType(JNIEnv* env, jobject obj, JniIntWrapper
- p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_MotionEvent_getToolType(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jint Java_MotionEvent_getToolType(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -915,19 +910,19 @@ static jint Java_MotionEvent_getToolType(JNIEnv* env, jobject obj, JniIntWrapper
&g_MotionEvent_getToolType);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_findPointerIndex = 0;
-static jint Java_MotionEvent_findPointerIndex(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jint Java_MotionEvent_findPointerIndex(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_MotionEvent_findPointerIndex(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jint Java_MotionEvent_findPointerIndex(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -938,19 +933,19 @@ static jint Java_MotionEvent_findPointerIndex(JNIEnv* env, jobject obj,
&g_MotionEvent_findPointerIndex);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getXF_I = 0;
-static jfloat Java_MotionEvent_getXF_I(JNIEnv* env, jobject obj, JniIntWrapper
- p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getXF_I(JNIEnv* env, jobject obj, JniIntWrapper
- p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getXF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getXF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -961,19 +956,19 @@ static jfloat Java_MotionEvent_getXF_I(JNIEnv* env, jobject obj, JniIntWrapper
&g_MotionEvent_getXF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getYF_I = 0;
-static jfloat Java_MotionEvent_getYF_I(JNIEnv* env, jobject obj, JniIntWrapper
- p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getYF_I(JNIEnv* env, jobject obj, JniIntWrapper
- p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getYF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getYF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -984,19 +979,19 @@ static jfloat Java_MotionEvent_getYF_I(JNIEnv* env, jobject obj, JniIntWrapper
&g_MotionEvent_getYF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getPressureF_I = 0;
-static jfloat Java_MotionEvent_getPressureF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getPressureF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getPressureF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getPressureF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1007,19 +1002,19 @@ static jfloat Java_MotionEvent_getPressureF_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getPressureF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getSizeF_I = 0;
-static jfloat Java_MotionEvent_getSizeF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getSizeF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getSizeF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getSizeF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1030,19 +1025,19 @@ static jfloat Java_MotionEvent_getSizeF_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getSizeF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getTouchMajorF_I = 0;
-static jfloat Java_MotionEvent_getTouchMajorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getTouchMajorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getTouchMajorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getTouchMajorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1053,19 +1048,19 @@ static jfloat Java_MotionEvent_getTouchMajorF_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getTouchMajorF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getTouchMinorF_I = 0;
-static jfloat Java_MotionEvent_getTouchMinorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getTouchMinorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getTouchMinorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getTouchMinorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1076,19 +1071,19 @@ static jfloat Java_MotionEvent_getTouchMinorF_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getTouchMinorF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getToolMajorF_I = 0;
-static jfloat Java_MotionEvent_getToolMajorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getToolMajorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getToolMajorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getToolMajorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1099,19 +1094,19 @@ static jfloat Java_MotionEvent_getToolMajorF_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getToolMajorF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getToolMinorF_I = 0;
-static jfloat Java_MotionEvent_getToolMinorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getToolMinorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getToolMinorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getToolMinorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1122,19 +1117,19 @@ static jfloat Java_MotionEvent_getToolMinorF_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getToolMinorF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getOrientationF_I = 0;
-static jfloat Java_MotionEvent_getOrientationF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getOrientationF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getOrientationF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getOrientationF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1145,21 +1140,20 @@ static jfloat Java_MotionEvent_getOrientationF_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getOrientationF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getAxisValueF_I_I = 0;
-static jfloat Java_MotionEvent_getAxisValueF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
+static jfloat Java_MotionEvent_getAxisValueF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getAxisValueF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
+static jfloat Java_MotionEvent_getAxisValueF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1170,21 +1164,20 @@ static jfloat Java_MotionEvent_getAxisValueF_I_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getAxisValueF_I_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0), as_jint(p1));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getPointerCoords = 0;
-static void Java_MotionEvent_getPointerCoords(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- jobject p1) __attribute__ ((unused));
-static void Java_MotionEvent_getPointerCoords(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- jobject p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static void Java_MotionEvent_getPointerCoords(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
+ const base::android::JavaRefOrBare<jobject>& p1) __attribute__ ((unused));
+static void Java_MotionEvent_getPointerCoords(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
+ const base::android::JavaRefOrBare<jobject>& p1) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1194,21 +1187,19 @@ static void Java_MotionEvent_getPointerCoords(JNIEnv* env, jobject obj,
"(ILandroid/view/MotionEvent$PointerCoords;)V",
&g_MotionEvent_getPointerCoords);
- env->CallVoidMethod(obj,
- method_id, as_jint(p0), p1);
+ env->CallVoidMethod(obj.obj(),
+ method_id, as_jint(p0), p1.obj());
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_MotionEvent_getPointerProperties = 0;
-static void Java_MotionEvent_getPointerProperties(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- jobject p1) __attribute__ ((unused));
-static void Java_MotionEvent_getPointerProperties(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- jobject p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static void Java_MotionEvent_getPointerProperties(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
+ const base::android::JavaRefOrBare<jobject>& p1) __attribute__ ((unused));
+static void Java_MotionEvent_getPointerProperties(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
+ const base::android::JavaRefOrBare<jobject>& p1) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1218,18 +1209,17 @@ static void Java_MotionEvent_getPointerProperties(JNIEnv* env, jobject obj,
"(ILandroid/view/MotionEvent$PointerProperties;)V",
&g_MotionEvent_getPointerProperties);
- env->CallVoidMethod(obj,
- method_id, as_jint(p0), p1);
+ env->CallVoidMethod(obj.obj(),
+ method_id, as_jint(p0), p1.obj());
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_MotionEvent_getMetaState = 0;
-static jint Java_MotionEvent_getMetaState(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jint Java_MotionEvent_getMetaState(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_MotionEvent_getMetaState(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jint Java_MotionEvent_getMetaState(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1240,18 +1230,18 @@ static jint Java_MotionEvent_getMetaState(JNIEnv* env, jobject obj) {
&g_MotionEvent_getMetaState);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getButtonState = 0;
-static jint Java_MotionEvent_getButtonState(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jint Java_MotionEvent_getButtonState(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_MotionEvent_getButtonState(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jint Java_MotionEvent_getButtonState(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1262,18 +1252,18 @@ static jint Java_MotionEvent_getButtonState(JNIEnv* env, jobject obj) {
&g_MotionEvent_getButtonState);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getRawX = 0;
-static jfloat Java_MotionEvent_getRawX(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jfloat Java_MotionEvent_getRawX(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getRawX(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getRawX(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1284,18 +1274,18 @@ static jfloat Java_MotionEvent_getRawX(JNIEnv* env, jobject obj) {
&g_MotionEvent_getRawX);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getRawY = 0;
-static jfloat Java_MotionEvent_getRawY(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jfloat Java_MotionEvent_getRawY(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getRawY(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getRawY(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1306,18 +1296,18 @@ static jfloat Java_MotionEvent_getRawY(JNIEnv* env, jobject obj) {
&g_MotionEvent_getRawY);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getXPrecision = 0;
-static jfloat Java_MotionEvent_getXPrecision(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getXPrecision(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getXPrecision(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getXPrecision(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1328,18 +1318,18 @@ static jfloat Java_MotionEvent_getXPrecision(JNIEnv* env, jobject obj) {
&g_MotionEvent_getXPrecision);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getYPrecision = 0;
-static jfloat Java_MotionEvent_getYPrecision(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getYPrecision(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getYPrecision(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getYPrecision(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1350,18 +1340,18 @@ static jfloat Java_MotionEvent_getYPrecision(JNIEnv* env, jobject obj) {
&g_MotionEvent_getYPrecision);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistorySize = 0;
-static jint Java_MotionEvent_getHistorySize(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jint Java_MotionEvent_getHistorySize(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_MotionEvent_getHistorySize(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jint Java_MotionEvent_getHistorySize(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1372,19 +1362,19 @@ static jint Java_MotionEvent_getHistorySize(JNIEnv* env, jobject obj) {
&g_MotionEvent_getHistorySize);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalEventTime = 0;
-static jlong Java_MotionEvent_getHistoricalEventTime(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jlong Java_MotionEvent_getHistoricalEventTime(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jlong Java_MotionEvent_getHistoricalEventTime(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jlong Java_MotionEvent_getHistoricalEventTime(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1395,19 +1385,19 @@ static jlong Java_MotionEvent_getHistoricalEventTime(JNIEnv* env, jobject obj,
&g_MotionEvent_getHistoricalEventTime);
jlong ret =
- env->CallLongMethod(obj,
+ env->CallLongMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalXF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalXF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalXF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getHistoricalXF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getHistoricalXF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1418,19 +1408,19 @@ static jfloat Java_MotionEvent_getHistoricalXF_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getHistoricalXF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalYF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalYF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalYF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getHistoricalYF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getHistoricalYF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1441,19 +1431,19 @@ static jfloat Java_MotionEvent_getHistoricalYF_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getHistoricalYF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalPressureF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalPressureF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalPressureF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getHistoricalPressureF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getHistoricalPressureF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1464,19 +1454,19 @@ static jfloat Java_MotionEvent_getHistoricalPressureF_I(JNIEnv* env, jobject
&g_MotionEvent_getHistoricalPressureF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalSizeF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalSizeF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalSizeF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getHistoricalSizeF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getHistoricalSizeF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1487,19 +1477,19 @@ static jfloat Java_MotionEvent_getHistoricalSizeF_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getHistoricalSizeF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMajorF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1510,19 +1500,19 @@ static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I(JNIEnv* env, jobject
&g_MotionEvent_getHistoricalTouchMajorF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMinorF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1533,19 +1523,19 @@ static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I(JNIEnv* env, jobject
&g_MotionEvent_getHistoricalTouchMinorF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMajorF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalToolMajorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalToolMajorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getHistoricalToolMajorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getHistoricalToolMajorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1556,19 +1546,19 @@ static jfloat Java_MotionEvent_getHistoricalToolMajorF_I(JNIEnv* env, jobject
&g_MotionEvent_getHistoricalToolMajorF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMinorF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalToolMinorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalToolMinorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getHistoricalToolMinorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getHistoricalToolMinorF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1579,19 +1569,19 @@ static jfloat Java_MotionEvent_getHistoricalToolMinorF_I(JNIEnv* env, jobject
&g_MotionEvent_getHistoricalToolMinorF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalOrientationF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalOrientationF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalOrientationF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jfloat Java_MotionEvent_getHistoricalOrientationF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static jfloat Java_MotionEvent_getHistoricalOrientationF_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1602,21 +1592,20 @@ static jfloat Java_MotionEvent_getHistoricalOrientationF_I(JNIEnv* env, jobject
&g_MotionEvent_getHistoricalOrientationF_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalAxisValueF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1627,21 +1616,20 @@ static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I(JNIEnv* env, jobject
&g_MotionEvent_getHistoricalAxisValueF_I_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0), as_jint(p1));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalXF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalXF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalXF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalXF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalXF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1652,21 +1640,20 @@ static jfloat Java_MotionEvent_getHistoricalXF_I_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getHistoricalXF_I_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0), as_jint(p1));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalYF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalYF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalYF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalYF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalYF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1677,21 +1664,20 @@ static jfloat Java_MotionEvent_getHistoricalYF_I_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getHistoricalYF_I_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0), as_jint(p1));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalPressureF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalPressureF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalPressureF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalPressureF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalPressureF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1702,21 +1688,20 @@ static jfloat Java_MotionEvent_getHistoricalPressureF_I_I(JNIEnv* env, jobject
&g_MotionEvent_getHistoricalPressureF_I_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0), as_jint(p1));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalSizeF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalSizeF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalSizeF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalSizeF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalSizeF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1727,21 +1712,20 @@ static jfloat Java_MotionEvent_getHistoricalSizeF_I_I(JNIEnv* env, jobject obj,
&g_MotionEvent_getHistoricalSizeF_I_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0), as_jint(p1));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMajorF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1752,21 +1736,20 @@ static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I_I(JNIEnv* env, jobject
&g_MotionEvent_getHistoricalTouchMajorF_I_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0), as_jint(p1));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMinorF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1777,21 +1760,20 @@ static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I_I(JNIEnv* env, jobject
&g_MotionEvent_getHistoricalTouchMinorF_I_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0), as_jint(p1));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMajorF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalToolMajorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalToolMajorF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalToolMajorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalToolMajorF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1802,21 +1784,20 @@ static jfloat Java_MotionEvent_getHistoricalToolMajorF_I_I(JNIEnv* env, jobject
&g_MotionEvent_getHistoricalToolMajorF_I_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0), as_jint(p1));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMinorF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalToolMinorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalToolMinorF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalToolMinorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalToolMinorF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1827,21 +1808,20 @@ static jfloat Java_MotionEvent_getHistoricalToolMinorF_I_I(JNIEnv* env, jobject
&g_MotionEvent_getHistoricalToolMinorF_I_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0), as_jint(p1));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalOrientationF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalOrientationF_I_I(JNIEnv* env,
- jobject obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalOrientationF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalOrientationF_I_I(JNIEnv* env,
- jobject obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalOrientationF_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1852,23 +1832,22 @@ static jfloat Java_MotionEvent_getHistoricalOrientationF_I_I(JNIEnv* env,
&g_MotionEvent_getHistoricalOrientationF_I_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0), as_jint(p1));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalAxisValueF_I_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I_I(JNIEnv* env,
- jobject obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1,
JniIntWrapper p2) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I_I(JNIEnv* env,
- jobject obj, JniIntWrapper p0,
+static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1,
JniIntWrapper p2) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1879,23 +1858,22 @@ static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I_I(JNIEnv* env,
&g_MotionEvent_getHistoricalAxisValueF_I_I_I);
jfloat ret =
- env->CallFloatMethod(obj,
+ env->CallFloatMethod(obj.obj(),
method_id, as_jint(p0), as_jint(p1), as_jint(p2));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_getHistoricalPointerCoords = 0;
-static void Java_MotionEvent_getHistoricalPointerCoords(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
+static void Java_MotionEvent_getHistoricalPointerCoords(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1,
- jobject p2) __attribute__ ((unused));
-static void Java_MotionEvent_getHistoricalPointerCoords(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
+ const base::android::JavaRefOrBare<jobject>& p2) __attribute__ ((unused));
+static void Java_MotionEvent_getHistoricalPointerCoords(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0,
JniIntWrapper p1,
- jobject p2) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ const base::android::JavaRefOrBare<jobject>& p2) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1905,18 +1883,17 @@ static void Java_MotionEvent_getHistoricalPointerCoords(JNIEnv* env, jobject
"(IILandroid/view/MotionEvent$PointerCoords;)V",
&g_MotionEvent_getHistoricalPointerCoords);
- env->CallVoidMethod(obj,
- method_id, as_jint(p0), as_jint(p1), p2);
+ env->CallVoidMethod(obj.obj(),
+ method_id, as_jint(p0), as_jint(p1), p2.obj());
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_MotionEvent_getEdgeFlags = 0;
-static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1927,19 +1904,19 @@ static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, jobject obj) {
&g_MotionEvent_getEdgeFlags);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_setEdgeFlags = 0;
-static void Java_MotionEvent_setEdgeFlags(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static void Java_MotionEvent_setEdgeFlags(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static void Java_MotionEvent_setEdgeFlags(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static void Java_MotionEvent_setEdgeFlags(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1949,19 +1926,18 @@ static void Java_MotionEvent_setEdgeFlags(JNIEnv* env, jobject obj,
"(I)V",
&g_MotionEvent_setEdgeFlags);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_MotionEvent_setAction = 0;
-static void Java_MotionEvent_setAction(JNIEnv* env, jobject obj, JniIntWrapper
- p0) __attribute__ ((unused));
-static void Java_MotionEvent_setAction(JNIEnv* env, jobject obj, JniIntWrapper
- p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static void Java_MotionEvent_setAction(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static void Java_MotionEvent_setAction(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1971,19 +1947,19 @@ static void Java_MotionEvent_setAction(JNIEnv* env, jobject obj, JniIntWrapper
"(I)V",
&g_MotionEvent_setAction);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_MotionEvent_offsetLocation = 0;
-static void Java_MotionEvent_offsetLocation(JNIEnv* env, jobject obj, jfloat p0,
+static void Java_MotionEvent_offsetLocation(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, jfloat p0,
jfloat p1) __attribute__ ((unused));
-static void Java_MotionEvent_offsetLocation(JNIEnv* env, jobject obj, jfloat p0,
+static void Java_MotionEvent_offsetLocation(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, jfloat p0,
jfloat p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -1993,19 +1969,19 @@ static void Java_MotionEvent_offsetLocation(JNIEnv* env, jobject obj, jfloat p0,
"(FF)V",
&g_MotionEvent_offsetLocation);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id, p0, p1);
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_MotionEvent_setLocation = 0;
-static void Java_MotionEvent_setLocation(JNIEnv* env, jobject obj, jfloat p0,
+static void Java_MotionEvent_setLocation(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, jfloat p0,
jfloat p1) __attribute__ ((unused));
-static void Java_MotionEvent_setLocation(JNIEnv* env, jobject obj, jfloat p0,
+static void Java_MotionEvent_setLocation(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, jfloat p0,
jfloat p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -2015,18 +1991,19 @@ static void Java_MotionEvent_setLocation(JNIEnv* env, jobject obj, jfloat p0,
"(FF)V",
&g_MotionEvent_setLocation);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id, p0, p1);
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_MotionEvent_transform = 0;
-static void Java_MotionEvent_transform(JNIEnv* env, jobject obj, jobject p0)
- __attribute__ ((unused));
-static void Java_MotionEvent_transform(JNIEnv* env, jobject obj, jobject p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static void Java_MotionEvent_transform(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, const
+ base::android::JavaRefOrBare<jobject>& p0) __attribute__ ((unused));
+static void Java_MotionEvent_transform(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, const
+ base::android::JavaRefOrBare<jobject>& p0) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -2036,29 +2013,27 @@ static void Java_MotionEvent_transform(JNIEnv* env, jobject obj, jobject p0) {
"(Landroid/graphics/Matrix;)V",
&g_MotionEvent_transform);
- env->CallVoidMethod(obj,
- method_id, p0);
+ env->CallVoidMethod(obj.obj(),
+ method_id, p0.obj());
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_MotionEvent_addBatchV_J_F_F_F_F_I = 0;
-static void Java_MotionEvent_addBatchV_J_F_F_F_F_I(JNIEnv* env, jobject obj,
- jlong p0,
+static void Java_MotionEvent_addBatchV_J_F_F_F_F_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, jlong p0,
jfloat p1,
jfloat p2,
jfloat p3,
jfloat p4,
JniIntWrapper p5) __attribute__ ((unused));
-static void Java_MotionEvent_addBatchV_J_F_F_F_F_I(JNIEnv* env, jobject obj,
- jlong p0,
+static void Java_MotionEvent_addBatchV_J_F_F_F_F_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, jlong p0,
jfloat p1,
jfloat p2,
jfloat p3,
jfloat p4,
JniIntWrapper p5) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -2068,23 +2043,21 @@ static void Java_MotionEvent_addBatchV_J_F_F_F_F_I(JNIEnv* env, jobject obj,
"(JFFFFI)V",
&g_MotionEvent_addBatchV_J_F_F_F_F_I);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id, p0, p1, p2, p3, p4, as_jint(p5));
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_MotionEvent_addBatchV_J_LAVMEPC_I = 0;
-static void Java_MotionEvent_addBatchV_J_LAVMEPC_I(JNIEnv* env, jobject obj,
- jlong p0,
- jobjectArray p1,
+static void Java_MotionEvent_addBatchV_J_LAVMEPC_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, jlong p0,
+ const base::android::JavaRefOrBare<jobjectArray>& p1,
JniIntWrapper p2) __attribute__ ((unused));
-static void Java_MotionEvent_addBatchV_J_LAVMEPC_I(JNIEnv* env, jobject obj,
- jlong p0,
- jobjectArray p1,
+static void Java_MotionEvent_addBatchV_J_LAVMEPC_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, jlong p0,
+ const base::android::JavaRefOrBare<jobjectArray>& p1,
JniIntWrapper p2) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -2094,19 +2067,19 @@ static void Java_MotionEvent_addBatchV_J_LAVMEPC_I(JNIEnv* env, jobject obj,
"(J[Landroid/view/MotionEvent$PointerCoords;I)V",
&g_MotionEvent_addBatchV_J_LAVMEPC_I);
- env->CallVoidMethod(obj,
- method_id, p0, p1, as_jint(p2));
+ env->CallVoidMethod(obj.obj(),
+ method_id, p0, p1.obj(), as_jint(p2));
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_MotionEvent_toString = 0;
-static ScopedJavaLocalRef<jstring> Java_MotionEvent_toString(JNIEnv* env,
- jobject obj) __attribute__ ((unused));
-static ScopedJavaLocalRef<jstring> Java_MotionEvent_toString(JNIEnv* env,
- jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static base::android::ScopedJavaLocalRef<jstring>
+ Java_MotionEvent_toString(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jstring>
+ Java_MotionEvent_toString(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env), NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -2117,18 +2090,18 @@ static ScopedJavaLocalRef<jstring> Java_MotionEvent_toString(JNIEnv* env,
&g_MotionEvent_toString);
jstring ret =
- static_cast<jstring>(env->CallObjectMethod(obj,
+ static_cast<jstring>(env->CallObjectMethod(obj.obj(),
method_id));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jstring>(env, ret);
+ return base::android::ScopedJavaLocalRef<jstring>(env, ret);
}
static base::subtle::AtomicWord g_MotionEvent_actionToString = 0;
-static ScopedJavaLocalRef<jstring> Java_MotionEvent_actionToString(JNIEnv* env,
- JniIntWrapper p0) __attribute__ ((unused));
-static ScopedJavaLocalRef<jstring> Java_MotionEvent_actionToString(JNIEnv* env,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
+static base::android::ScopedJavaLocalRef<jstring>
+ Java_MotionEvent_actionToString(JNIEnv* env, JniIntWrapper p0) __attribute__
+ ((unused));
+static base::android::ScopedJavaLocalRef<jstring>
+ Java_MotionEvent_actionToString(JNIEnv* env, JniIntWrapper p0) {
CHECK_CLAZZ(env, MotionEvent_clazz(env),
MotionEvent_clazz(env), NULL);
jmethodID method_id =
@@ -2143,15 +2116,15 @@ static ScopedJavaLocalRef<jstring> Java_MotionEvent_actionToString(JNIEnv* env,
static_cast<jstring>(env->CallStaticObjectMethod(MotionEvent_clazz(env),
method_id, as_jint(p0)));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jstring>(env, ret);
+ return base::android::ScopedJavaLocalRef<jstring>(env, ret);
}
static base::subtle::AtomicWord g_MotionEvent_axisToString = 0;
-static ScopedJavaLocalRef<jstring> Java_MotionEvent_axisToString(JNIEnv* env,
- JniIntWrapper p0) __attribute__ ((unused));
-static ScopedJavaLocalRef<jstring> Java_MotionEvent_axisToString(JNIEnv* env,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
+static base::android::ScopedJavaLocalRef<jstring>
+ Java_MotionEvent_axisToString(JNIEnv* env, JniIntWrapper p0) __attribute__
+ ((unused));
+static base::android::ScopedJavaLocalRef<jstring>
+ Java_MotionEvent_axisToString(JNIEnv* env, JniIntWrapper p0) {
CHECK_CLAZZ(env, MotionEvent_clazz(env),
MotionEvent_clazz(env), NULL);
jmethodID method_id =
@@ -2166,14 +2139,14 @@ static ScopedJavaLocalRef<jstring> Java_MotionEvent_axisToString(JNIEnv* env,
static_cast<jstring>(env->CallStaticObjectMethod(MotionEvent_clazz(env),
method_id, as_jint(p0)));
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jstring>(env, ret);
+ return base::android::ScopedJavaLocalRef<jstring>(env, ret);
}
static base::subtle::AtomicWord g_MotionEvent_axisFromString = 0;
-static jint Java_MotionEvent_axisFromString(JNIEnv* env, jstring p0)
- __attribute__ ((unused));
-static jint Java_MotionEvent_axisFromString(JNIEnv* env, jstring p0) {
- /* Must call RegisterNativesImpl() */
+static jint Java_MotionEvent_axisFromString(JNIEnv* env, const
+ base::android::JavaRefOrBare<jstring>& p0) __attribute__ ((unused));
+static jint Java_MotionEvent_axisFromString(JNIEnv* env, const
+ base::android::JavaRefOrBare<jstring>& p0) {
CHECK_CLAZZ(env, MotionEvent_clazz(env),
MotionEvent_clazz(env), 0);
jmethodID method_id =
@@ -2186,18 +2159,21 @@ static jint Java_MotionEvent_axisFromString(JNIEnv* env, jstring p0) {
jint ret =
env->CallStaticIntMethod(MotionEvent_clazz(env),
- method_id, p0);
+ method_id, p0.obj());
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_MotionEvent_writeToParcel = 0;
-static void Java_MotionEvent_writeToParcel(JNIEnv* env, jobject obj, jobject p0,
+static void Java_MotionEvent_writeToParcel(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, const
+ base::android::JavaRefOrBare<jobject>& p0,
JniIntWrapper p1) __attribute__ ((unused));
-static void Java_MotionEvent_writeToParcel(JNIEnv* env, jobject obj, jobject p0,
+static void Java_MotionEvent_writeToParcel(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, const
+ base::android::JavaRefOrBare<jobject>& p0,
JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
MotionEvent_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -2207,22 +2183,13 @@ static void Java_MotionEvent_writeToParcel(JNIEnv* env, jobject obj, jobject p0,
"(Landroid/os/Parcel;I)V",
&g_MotionEvent_writeToParcel);
- env->CallVoidMethod(obj,
- method_id, p0, as_jint(p1));
+ env->CallVoidMethod(obj.obj(),
+ method_id, p0.obj(), as_jint(p1));
jni_generator::CheckException(env);
-
}
// Step 3: RegisterNatives.
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_MotionEvent_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kMotionEventClassPath).obj()));
-
- return true;
-}
-
} // namespace JNI_MotionEvent
#endif // android_view_MotionEvent_JNI
diff --git a/base/android/jni_generator/testFromJavaP.golden b/base/android/jni_generator/testFromJavaP.golden
index f32666c..18a9430 100644
--- a/base/android/jni_generator/testFromJavaP.golden
+++ b/base/android/jni_generator/testFromJavaP.golden
@@ -20,8 +20,8 @@
namespace {
const char kInputStreamClassPath[] = "java/io/InputStream";
// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_InputStream_clazz = NULL;
-#define InputStream_clazz(env) g_InputStream_clazz
+base::subtle::AtomicWord g_InputStream_clazz __attribute__((unused)) = 0;
+#define InputStream_clazz(env) base::android::LazyGetClass(env, kInputStreamClassPath, &g_InputStream_clazz)
} // namespace
@@ -30,11 +30,11 @@ namespace JNI_InputStream {
// Step 2: method stubs.
static base::subtle::AtomicWord g_InputStream_available = 0;
-static jint Java_InputStream_available(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jint Java_InputStream_available(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_InputStream_available(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jint Java_InputStream_available(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
InputStream_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -45,18 +45,18 @@ static jint Java_InputStream_available(JNIEnv* env, jobject obj) {
&g_InputStream_available);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_InputStream_close = 0;
-static void Java_InputStream_close(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static void Java_InputStream_close(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static void Java_InputStream_close(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static void Java_InputStream_close(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
InputStream_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -66,18 +66,18 @@ static void Java_InputStream_close(JNIEnv* env, jobject obj) {
"()V",
&g_InputStream_close);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_InputStream_mark = 0;
-static void Java_InputStream_mark(JNIEnv* env, jobject obj, JniIntWrapper p0)
- __attribute__ ((unused));
-static void Java_InputStream_mark(JNIEnv* env, jobject obj, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static void Java_InputStream_mark(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) __attribute__
+ ((unused));
+static void Java_InputStream_mark(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, JniIntWrapper p0) {
+ CHECK_CLAZZ(env, obj.obj(),
InputStream_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -87,18 +87,17 @@ static void Java_InputStream_mark(JNIEnv* env, jobject obj, JniIntWrapper p0) {
"(I)V",
&g_InputStream_mark);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id, as_jint(p0));
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_InputStream_markSupported = 0;
-static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jboolean Java_InputStream_markSupported(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jboolean Java_InputStream_markSupported(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
InputStream_clazz(env), false);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -109,18 +108,18 @@ static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj) {
&g_InputStream_markSupported);
jboolean ret =
- env->CallBooleanMethod(obj,
+ env->CallBooleanMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_InputStream_readI = 0;
-static jint Java_InputStream_readI(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jint Java_InputStream_readI(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_InputStream_readI(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static jint Java_InputStream_readI(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
InputStream_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -131,18 +130,20 @@ static jint Java_InputStream_readI(JNIEnv* env, jobject obj) {
&g_InputStream_readI);
jint ret =
- env->CallIntMethod(obj,
+ env->CallIntMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_InputStream_readI_AB = 0;
-static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0)
- __attribute__ ((unused));
-static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jint Java_InputStream_readI_AB(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, const
+ base::android::JavaRefOrBare<jbyteArray>& p0) __attribute__ ((unused));
+static jint Java_InputStream_readI_AB(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, const
+ base::android::JavaRefOrBare<jbyteArray>& p0) {
+ CHECK_CLAZZ(env, obj.obj(),
InputStream_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -153,23 +154,24 @@ static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0) {
&g_InputStream_readI_AB);
jint ret =
- env->CallIntMethod(obj,
- method_id, p0);
+ env->CallIntMethod(obj.obj(),
+ method_id, p0.obj());
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_InputStream_readI_AB_I_I = 0;
-static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray
- p0,
+static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, const
+ base::android::JavaRefOrBare<jbyteArray>& p0,
JniIntWrapper p1,
JniIntWrapper p2) __attribute__ ((unused));
-static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray
- p0,
+static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, const
+ base::android::JavaRefOrBare<jbyteArray>& p0,
JniIntWrapper p1,
JniIntWrapper p2) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+ CHECK_CLAZZ(env, obj.obj(),
InputStream_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -180,18 +182,18 @@ static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray
&g_InputStream_readI_AB_I_I);
jint ret =
- env->CallIntMethod(obj,
- method_id, p0, as_jint(p1), as_jint(p2));
+ env->CallIntMethod(obj.obj(),
+ method_id, p0.obj(), as_jint(p1), as_jint(p2));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_InputStream_reset = 0;
-static void Java_InputStream_reset(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static void Java_InputStream_reset(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static void Java_InputStream_reset(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static void Java_InputStream_reset(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
InputStream_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -201,18 +203,18 @@ static void Java_InputStream_reset(JNIEnv* env, jobject obj) {
"()V",
&g_InputStream_reset);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
-
}
static base::subtle::AtomicWord g_InputStream_skip = 0;
-static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0)
- __attribute__ ((unused));
-static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static jlong Java_InputStream_skip(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, jlong p0) __attribute__
+ ((unused));
+static jlong Java_InputStream_skip(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj, jlong p0) {
+ CHECK_CLAZZ(env, obj.obj(),
InputStream_clazz(env), 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -223,17 +225,17 @@ static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0) {
&g_InputStream_skip);
jlong ret =
- env->CallLongMethod(obj,
+ env->CallLongMethod(obj.obj(),
method_id, p0);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_InputStream_Constructor = 0;
-static ScopedJavaLocalRef<jobject> Java_InputStream_Constructor(JNIEnv* env)
- __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject> Java_InputStream_Constructor(JNIEnv* env) {
- /* Must call RegisterNativesImpl() */
+static base::android::ScopedJavaLocalRef<jobject>
+ Java_InputStream_Constructor(JNIEnv* env) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+ Java_InputStream_Constructor(JNIEnv* env) {
CHECK_CLAZZ(env, InputStream_clazz(env),
InputStream_clazz(env), NULL);
jmethodID method_id =
@@ -248,19 +250,11 @@ static ScopedJavaLocalRef<jobject> Java_InputStream_Constructor(JNIEnv* env) {
env->NewObject(InputStream_clazz(env),
method_id);
jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jobject>(env, ret);
+ return base::android::ScopedJavaLocalRef<jobject>(env, ret);
}
// Step 3: RegisterNatives.
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_InputStream_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kInputStreamClassPath).obj()));
-
- return true;
-}
-
} // namespace JNI_InputStream
#endif // java_io_InputStream_JNI
diff --git a/base/android/jni_generator/testFromJavaPGenerics.golden b/base/android/jni_generator/testFromJavaPGenerics.golden
index 489872c..c076c39 100644
--- a/base/android/jni_generator/testFromJavaPGenerics.golden
+++ b/base/android/jni_generator/testFromJavaPGenerics.golden
@@ -20,8 +20,8 @@
namespace {
const char kHashSetClassPath[] = "java/util/HashSet";
// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_HashSet_clazz = NULL;
-#define HashSet_clazz(env) g_HashSet_clazz
+base::subtle::AtomicWord g_HashSet_clazz __attribute__((unused)) = 0;
+#define HashSet_clazz(env) base::android::LazyGetClass(env, kHashSetClassPath, &g_HashSet_clazz)
} // namespace
@@ -30,11 +30,11 @@ namespace JNI_HashSet {
// Step 2: method stubs.
static base::subtle::AtomicWord g_HashSet_dummy = 0;
-static void Java_HashSet_dummy(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static void Java_HashSet_dummy(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
+static void Java_HashSet_dummy(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) __attribute__ ((unused));
+static void Java_HashSet_dummy(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& obj) {
+ CHECK_CLAZZ(env, obj.obj(),
HashSet_clazz(env));
jmethodID method_id =
base::android::MethodID::LazyGet<
@@ -44,22 +44,13 @@ static void Java_HashSet_dummy(JNIEnv* env, jobject obj) {
"()V",
&g_HashSet_dummy);
- env->CallVoidMethod(obj,
+ env->CallVoidMethod(obj.obj(),
method_id);
jni_generator::CheckException(env);
-
}
// Step 3: RegisterNatives.
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_HashSet_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kHashSetClassPath).obj()));
-
- return true;
-}
-
} // namespace JNI_HashSet
#endif // java_util_HashSet_JNI
diff --git a/base/android/jni_generator/testInnerClassNatives.golden b/base/android/jni_generator/testInnerClassNatives.golden
index ad140e2..20b8830 100644
--- a/base/android/jni_generator/testInnerClassNatives.golden
+++ b/base/android/jni_generator/testInnerClassNatives.golden
@@ -21,18 +21,23 @@ namespace {
const char kTestJniClassPath[] = "org/chromium/TestJni";
const char kMyInnerClassClassPath[] = "org/chromium/TestJni$MyInnerClass";
// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_TestJni_clazz = NULL;
-#define TestJni_clazz(env) g_TestJni_clazz
+base::subtle::AtomicWord g_TestJni_clazz __attribute__((unused)) = 0;
+#define TestJni_clazz(env) base::android::LazyGetClass(env, kTestJniClassPath, &g_TestJni_clazz)
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+base::subtle::AtomicWord g_MyInnerClass_clazz __attribute__((unused)) = 0;
+#define MyInnerClass_clazz(env) base::android::LazyGetClass(env, kMyInnerClassClassPath, &g_MyInnerClass_clazz)
} // namespace
// Step 2: method stubs.
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+ jcaller);
-static jint Java_org_chromium_TestJni_00024MyInnerClass_nativeInit(JNIEnv* env,
- jobject jcaller) {
- return Init(env, JavaParamRef<jobject>(env, jcaller));
+JNI_GENERATOR_EXPORT jint
+ Java_org_chromium_TestJni_00024MyInnerClass_nativeInit(JNIEnv* env, jobject
+ jcaller) {
+ return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
}
// Step 3: RegisterNatives.
@@ -47,9 +52,8 @@ static const JNINativeMethod kMethodsMyInnerClass[] = {
};
static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kTestJniClassPath).obj()));
+ if (jni_generator::ShouldSkipJniRegistration(false))
+ return true;
const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
diff --git a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
index 0a890e7..67352e7 100644
--- a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
+++ b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
@@ -22,24 +22,31 @@ const char kMyOtherInnerClassClassPath[] =
"org/chromium/TestJni$MyOtherInnerClass";
const char kTestJniClassPath[] = "org/chromium/TestJni";
// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_TestJni_clazz = NULL;
-#define TestJni_clazz(env) g_TestJni_clazz
+base::subtle::AtomicWord g_MyOtherInnerClass_clazz __attribute__((unused)) = 0;
+#define MyOtherInnerClass_clazz(env) base::android::LazyGetClass(env, kMyOtherInnerClassClassPath, &g_MyOtherInnerClass_clazz)
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+base::subtle::AtomicWord g_TestJni_clazz __attribute__((unused)) = 0;
+#define TestJni_clazz(env) base::android::LazyGetClass(env, kTestJniClassPath, &g_TestJni_clazz)
} // namespace
// Step 2: method stubs.
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+ jcaller);
-static jint Java_org_chromium_TestJni_nativeInit(JNIEnv* env, jobject jcaller) {
- return Init(env, JavaParamRef<jobject>(env, jcaller));
+JNI_GENERATOR_EXPORT jint Java_org_chromium_TestJni_nativeInit(JNIEnv* env,
+ jobject jcaller) {
+ return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
}
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+ jcaller);
-static jint Java_org_chromium_TestJni_00024MyOtherInnerClass_nativeInit(JNIEnv*
- env, jobject jcaller) {
- return Init(env, JavaParamRef<jobject>(env, jcaller));
+JNI_GENERATOR_EXPORT jint
+ Java_org_chromium_TestJni_00024MyOtherInnerClass_nativeInit(JNIEnv* env,
+ jobject jcaller) {
+ return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
}
// Step 3: RegisterNatives.
@@ -61,9 +68,8 @@ static const JNINativeMethod kMethodsTestJni[] = {
};
static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kTestJniClassPath).obj()));
+ if (jni_generator::ShouldSkipJniRegistration(false))
+ return true;
const int kMethodsMyOtherInnerClassSize =
arraysize(kMethodsMyOtherInnerClass);
diff --git a/base/android/jni_generator/testInnerClassNativesMultiple.golden b/base/android/jni_generator/testInnerClassNativesMultiple.golden
index 268f794..7807efa 100644
--- a/base/android/jni_generator/testInnerClassNativesMultiple.golden
+++ b/base/android/jni_generator/testInnerClassNativesMultiple.golden
@@ -23,25 +23,35 @@ const char kMyOtherInnerClassClassPath[] =
const char kTestJniClassPath[] = "org/chromium/TestJni";
const char kMyInnerClassClassPath[] = "org/chromium/TestJni$MyInnerClass";
// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_TestJni_clazz = NULL;
-#define TestJni_clazz(env) g_TestJni_clazz
+base::subtle::AtomicWord g_MyOtherInnerClass_clazz __attribute__((unused)) = 0;
+#define MyOtherInnerClass_clazz(env) base::android::LazyGetClass(env, kMyOtherInnerClassClassPath, &g_MyOtherInnerClass_clazz)
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+base::subtle::AtomicWord g_TestJni_clazz __attribute__((unused)) = 0;
+#define TestJni_clazz(env) base::android::LazyGetClass(env, kTestJniClassPath, &g_TestJni_clazz)
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+base::subtle::AtomicWord g_MyInnerClass_clazz __attribute__((unused)) = 0;
+#define MyInnerClass_clazz(env) base::android::LazyGetClass(env, kMyInnerClassClassPath, &g_MyInnerClass_clazz)
} // namespace
// Step 2: method stubs.
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+ jcaller);
-static jint Java_org_chromium_TestJni_00024MyInnerClass_nativeInit(JNIEnv* env,
- jobject jcaller) {
- return Init(env, JavaParamRef<jobject>(env, jcaller));
+JNI_GENERATOR_EXPORT jint
+ Java_org_chromium_TestJni_00024MyInnerClass_nativeInit(JNIEnv* env, jobject
+ jcaller) {
+ return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
}
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+ jcaller);
-static jint Java_org_chromium_TestJni_00024MyOtherInnerClass_nativeInit(JNIEnv*
- env, jobject jcaller) {
- return Init(env, JavaParamRef<jobject>(env, jcaller));
+JNI_GENERATOR_EXPORT jint
+ Java_org_chromium_TestJni_00024MyOtherInnerClass_nativeInit(JNIEnv* env,
+ jobject jcaller) {
+ return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
}
// Step 3: RegisterNatives.
@@ -65,9 +75,8 @@ static const JNINativeMethod kMethodsMyInnerClass[] = {
};
static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kTestJniClassPath).obj()));
+ if (jni_generator::ShouldSkipJniRegistration(false))
+ return true;
const int kMethodsMyOtherInnerClassSize =
arraysize(kMethodsMyOtherInnerClass);
diff --git a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
index 6de8c21..0eecb5a 100644
--- a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
+++ b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
@@ -20,30 +20,31 @@
namespace {
const char kFooClassPath[] = "org/chromium/foo/Foo";
// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_Foo_clazz = NULL;
-#define Foo_clazz(env) g_Foo_clazz
+base::subtle::AtomicWord g_Foo_clazz __attribute__((unused)) = 0;
+#define Foo_clazz(env) base::android::LazyGetClass(env, kFooClassPath, &g_Foo_clazz)
} // namespace
// Step 2: method stubs.
-static void DoSomething(JNIEnv* env, const JavaParamRef<jclass>& jcaller,
- const JavaParamRef<jobject>& callback1,
- const JavaParamRef<jobject>& callback2);
-
-static void Java_org_chromium_foo_Foo_nativeDoSomething(JNIEnv* env, jclass
+static void DoSomething(JNIEnv* env, const base::android::JavaParamRef<jclass>&
jcaller,
+ const base::android::JavaParamRef<jobject>& callback1,
+ const base::android::JavaParamRef<jobject>& callback2);
+
+JNI_GENERATOR_EXPORT void Java_org_chromium_foo_Foo_nativeDoSomething(JNIEnv*
+ env, jclass jcaller,
jobject callback1,
jobject callback2) {
- return DoSomething(env, JavaParamRef<jclass>(env, jcaller),
- JavaParamRef<jobject>(env, callback1), JavaParamRef<jobject>(env,
- callback2));
+ return DoSomething(env, base::android::JavaParamRef<jclass>(env, jcaller),
+ base::android::JavaParamRef<jobject>(env, callback1),
+ base::android::JavaParamRef<jobject>(env, callback2));
}
static base::subtle::AtomicWord g_Foo_calledByNative = 0;
-static void Java_Foo_calledByNative(JNIEnv* env, jobject callback1,
- jobject callback2) {
- /* Must call RegisterNativesImpl() */
+static void Java_Foo_calledByNative(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& callback1,
+ const base::android::JavaRefOrBare<jobject>& callback2) {
CHECK_CLAZZ(env, Foo_clazz(env),
Foo_clazz(env));
jmethodID method_id =
@@ -51,7 +52,6 @@ static void Java_Foo_calledByNative(JNIEnv* env, jobject callback1,
base::android::MethodID::TYPE_STATIC>(
env, Foo_clazz(env),
"calledByNative",
-
"("
"Lorg/chromium/foo/Bar1$Callback;"
"Lorg/chromium/foo/Bar2$Callback;"
@@ -60,9 +60,8 @@ static void Java_Foo_calledByNative(JNIEnv* env, jobject callback1,
&g_Foo_calledByNative);
env->CallStaticVoidMethod(Foo_clazz(env),
- method_id, callback1, callback2);
+ method_id, callback1.obj(), callback2.obj());
jni_generator::CheckException(env);
-
}
// Step 3: RegisterNatives.
@@ -77,9 +76,8 @@ static const JNINativeMethod kMethodsFoo[] = {
};
static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_Foo_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kFooClassPath).obj()));
+ if (jni_generator::ShouldSkipJniRegistration(false))
+ return true;
const int kMethodsFooSize = arraysize(kMethodsFoo);
diff --git a/base/android/jni_generator/testNativeExportsOption.golden b/base/android/jni_generator/testNativeExportsOption.golden
deleted file mode 100644
index 2c89e3b..0000000
--- a/base/android/jni_generator/testNativeExportsOption.golden
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file is autogenerated by
-// base/android/jni_generator/jni_generator.py
-// For
-// org/chromium/example/jni_generator/SampleForTests
-
-#ifndef org_chromium_example_jni_generator_SampleForTests_JNI
-#define org_chromium_example_jni_generator_SampleForTests_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// Step 1: forward declarations.
-namespace {
-const char kSampleForTestsClassPath[] =
- "org/chromium/example/jni_generator/SampleForTests";
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-base::subtle::AtomicWord g_SampleForTests_clazz __attribute__((unused)) = 0;
-#define SampleForTests_clazz(env) base::android::LazyGetClass(env, kSampleForTestsClassPath, &g_SampleForTests_clazz)
-
-} // namespace
-
-// Step 2: method stubs.
-extern "C" __attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod(JNIEnv*
- env,
- jobject jcaller,
- jlong nativeTest,
- jint arg1) {
- Test* native = reinterpret_cast<Test*>(nativeTest);
- CHECK_NATIVE_PTR(env, jcaller, native, "StaticMethod", 0);
- return native->StaticMethod(env, JavaParamRef<jobject>(env, jcaller), arg1);
-}
-
-extern "C" __attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(JNIEnv*
- env,
- jobject jcaller,
- jlong nativeTest,
- jint arg1) {
- Test* native = reinterpret_cast<Test*>(nativeTest);
- CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
- return native->Method(env, JavaParamRef<jobject>(env, jcaller), arg1);
-}
-
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
-
-extern "C" __attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
- env, jobject jcaller) {
- return Init(env, JavaParamRef<jobject>(env, jcaller));
-}
-
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
-
-extern "C" __attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
- env, jobject jcaller) {
- return Init(env, JavaParamRef<jobject>(env, jcaller));
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testMethodWithParam = 0;
-static void Java_SampleForTests_testMethodWithParam(JNIEnv* env, jobject obj,
- JniIntWrapper iParam) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "testMethodWithParam",
-
-"("
-"I"
-")"
-"V",
- &g_SampleForTests_testMethodWithParam);
-
- env->CallVoidMethod(obj,
- method_id, as_jint(iParam));
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testMethodWithParamAndReturn =
- 0;
-static ScopedJavaLocalRef<jstring>
- Java_SampleForTests_testMethodWithParamAndReturn(JNIEnv* env, jobject obj,
- JniIntWrapper iParam) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "testMethodWithParamAndReturn",
-
-"("
-"I"
-")"
-"Ljava/lang/String;",
- &g_SampleForTests_testMethodWithParamAndReturn);
-
- jstring ret =
- static_cast<jstring>(env->CallObjectMethod(obj,
- method_id, as_jint(iParam)));
- jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jstring>(env, ret);
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithParam = 0;
-static jint Java_SampleForTests_testStaticMethodWithParam(JNIEnv* env,
- JniIntWrapper iParam) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, SampleForTests_clazz(env),
- SampleForTests_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, SampleForTests_clazz(env),
- "testStaticMethodWithParam",
-
-"("
-"I"
-")"
-"I",
- &g_SampleForTests_testStaticMethodWithParam);
-
- jint ret =
- env->CallStaticIntMethod(SampleForTests_clazz(env),
- method_id, as_jint(iParam));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testMethodWithNoParam = 0;
-static jdouble Java_SampleForTests_testMethodWithNoParam(JNIEnv* env) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, SampleForTests_clazz(env),
- SampleForTests_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, SampleForTests_clazz(env),
- "testMethodWithNoParam",
-
-"("
-")"
-"D",
- &g_SampleForTests_testMethodWithNoParam);
-
- jdouble ret =
- env->CallStaticDoubleMethod(SampleForTests_clazz(env),
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithNoParam =
- 0;
-static ScopedJavaLocalRef<jstring>
- Java_SampleForTests_testStaticMethodWithNoParam(JNIEnv* env) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, SampleForTests_clazz(env),
- SampleForTests_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, SampleForTests_clazz(env),
- "testStaticMethodWithNoParam",
-
-"("
-")"
-"Ljava/lang/String;",
- &g_SampleForTests_testStaticMethodWithNoParam);
-
- jstring ret =
-static_cast<jstring>(env->CallStaticObjectMethod(SampleForTests_clazz(env),
- method_id));
- jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jstring>(env, ret);
-}
-
-// Step 3: RegisterNatives.
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- return true;
-}
-
-#endif // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/base/android/jni_generator/testNativeExportsOptionalOption.golden b/base/android/jni_generator/testNativeExportsOptionalOption.golden
deleted file mode 100644
index 03484c9..0000000
--- a/base/android/jni_generator/testNativeExportsOptionalOption.golden
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file is autogenerated by
-// base/android/jni_generator/jni_generator.py
-// For
-// org/chromium/example/jni_generator/SampleForTests
-
-#ifndef org_chromium_example_jni_generator_SampleForTests_JNI
-#define org_chromium_example_jni_generator_SampleForTests_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// Step 1: forward declarations.
-namespace {
-const char kSampleForTestsClassPath[] =
- "org/chromium/example/jni_generator/SampleForTests";
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-base::subtle::AtomicWord g_SampleForTests_clazz __attribute__((unused)) = 0;
-#define SampleForTests_clazz(env) base::android::LazyGetClass(env, kSampleForTestsClassPath, &g_SampleForTests_clazz)
-
-} // namespace
-
-// Step 2: method stubs.
-extern "C" __attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod(JNIEnv*
- env,
- jobject jcaller,
- jlong nativeTest,
- jint arg1) {
- Test* native = reinterpret_cast<Test*>(nativeTest);
- CHECK_NATIVE_PTR(env, jcaller, native, "StaticMethod", 0);
- return native->StaticMethod(env, JavaParamRef<jobject>(env, jcaller), arg1);
-}
-
-extern "C" __attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(JNIEnv*
- env,
- jobject jcaller,
- jlong nativeTest,
- jint arg1) {
- Test* native = reinterpret_cast<Test*>(nativeTest);
- CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
- return native->Method(env, JavaParamRef<jobject>(env, jcaller), arg1);
-}
-
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
-
-extern "C" __attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
- env, jobject jcaller) {
- return Init(env, JavaParamRef<jobject>(env, jcaller));
-}
-
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
-
-extern "C" __attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
- env, jobject jcaller) {
- return Init(env, JavaParamRef<jobject>(env, jcaller));
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testMethodWithParam = 0;
-static void Java_SampleForTests_testMethodWithParam(JNIEnv* env, jobject obj,
- JniIntWrapper iParam) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "testMethodWithParam",
-
-"("
-"I"
-")"
-"V",
- &g_SampleForTests_testMethodWithParam);
-
- env->CallVoidMethod(obj,
- method_id, as_jint(iParam));
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testMethodWithParamAndReturn =
- 0;
-static ScopedJavaLocalRef<jstring>
- Java_SampleForTests_testMethodWithParamAndReturn(JNIEnv* env, jobject obj,
- JniIntWrapper iParam) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "testMethodWithParamAndReturn",
-
-"("
-"I"
-")"
-"Ljava/lang/String;",
- &g_SampleForTests_testMethodWithParamAndReturn);
-
- jstring ret =
- static_cast<jstring>(env->CallObjectMethod(obj,
- method_id, as_jint(iParam)));
- jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jstring>(env, ret);
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithParam = 0;
-static jint Java_SampleForTests_testStaticMethodWithParam(JNIEnv* env,
- JniIntWrapper iParam) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, SampleForTests_clazz(env),
- SampleForTests_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, SampleForTests_clazz(env),
- "testStaticMethodWithParam",
-
-"("
-"I"
-")"
-"I",
- &g_SampleForTests_testStaticMethodWithParam);
-
- jint ret =
- env->CallStaticIntMethod(SampleForTests_clazz(env),
- method_id, as_jint(iParam));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testMethodWithNoParam = 0;
-static jdouble Java_SampleForTests_testMethodWithNoParam(JNIEnv* env) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, SampleForTests_clazz(env),
- SampleForTests_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, SampleForTests_clazz(env),
- "testMethodWithNoParam",
-
-"("
-")"
-"D",
- &g_SampleForTests_testMethodWithNoParam);
-
- jdouble ret =
- env->CallStaticDoubleMethod(SampleForTests_clazz(env),
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithNoParam =
- 0;
-static ScopedJavaLocalRef<jstring>
- Java_SampleForTests_testStaticMethodWithNoParam(JNIEnv* env) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, SampleForTests_clazz(env),
- SampleForTests_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, SampleForTests_clazz(env),
- "testStaticMethodWithNoParam",
-
-"("
-")"
-"Ljava/lang/String;",
- &g_SampleForTests_testStaticMethodWithNoParam);
-
- jstring ret =
-static_cast<jstring>(env->CallStaticObjectMethod(SampleForTests_clazz(env),
- method_id));
- jni_generator::CheckException(env);
- return ScopedJavaLocalRef<jstring>(env, ret);
-}
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
- { "nativeInit",
-"("
-")"
-"I",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit)
- },
-};
-
-static const JNINativeMethod kMethodsMyInnerClass[] = {
- { "nativeInit",
-"("
-")"
-"I",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit)
- },
-};
-
-static const JNINativeMethod kMethodsSampleForTests[] = {
- { "nativeStaticMethod",
-"("
-"J"
-"I"
-")"
-"I",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod)
- },
- { "nativeMethod",
-"("
-"J"
-"I"
-")"
-"I",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod)
- },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env) {
- if (base::android::IsManualJniRegistrationDisabled()) return true;
-
- const int kMethodsMyOtherInnerClassSize =
- arraysize(kMethodsMyOtherInnerClass);
-
- if (env->RegisterNatives(MyOtherInnerClass_clazz(env),
- kMethodsMyOtherInnerClass,
- kMethodsMyOtherInnerClassSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, MyOtherInnerClass_clazz(env), __FILE__);
- return false;
- }
-
- const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
-
- if (env->RegisterNatives(MyInnerClass_clazz(env),
- kMethodsMyInnerClass,
- kMethodsMyInnerClassSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, MyInnerClass_clazz(env), __FILE__);
- return false;
- }
-
- const int kMethodsSampleForTestsSize = arraysize(kMethodsSampleForTests);
-
- if (env->RegisterNatives(SampleForTests_clazz(env),
- kMethodsSampleForTests,
- kMethodsSampleForTestsSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, SampleForTests_clazz(env), __FILE__);
- return false;
- }
-
- return true;
-}
-
-#endif // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/base/android/jni_generator/testNatives.golden b/base/android/jni_generator/testNatives.golden
index f9538a3..3362c92 100644
--- a/base/android/jni_generator/testNatives.golden
+++ b/base/android/jni_generator/testNatives.golden
@@ -20,30 +20,33 @@
namespace {
const char kTestJniClassPath[] = "org/chromium/TestJni";
// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_TestJni_clazz = NULL;
-#define TestJni_clazz(env) g_TestJni_clazz
+base::subtle::AtomicWord g_TestJni_clazz __attribute__((unused)) = 0;
+#define TestJni_clazz(env) base::android::LazyGetClass(env, kTestJniClassPath, &g_TestJni_clazz)
} // namespace
// Step 2: method stubs.
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+ jcaller);
-static jint Java_org_chromium_TestJni_nativeInit(JNIEnv* env, jobject jcaller) {
- return Init(env, JavaParamRef<jobject>(env, jcaller));
+JNI_GENERATOR_EXPORT jint Java_org_chromium_TestJni_nativeInit(JNIEnv* env,
+ jobject jcaller) {
+ return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
}
-static void Java_org_chromium_TestJni_nativeDestroy(JNIEnv* env,
+JNI_GENERATOR_EXPORT void Java_org_chromium_TestJni_nativeDestroy(JNIEnv* env,
jobject jcaller,
jint nativeChromeBrowserProvider) {
ChromeBrowserProvider* native =
reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
- return native->Destroy(env, JavaParamRef<jobject>(env, jcaller));
+ return native->Destroy(env, base::android::JavaParamRef<jobject>(env,
+ jcaller));
}
-static jlong Java_org_chromium_TestJni_nativeAddBookmark(JNIEnv* env,
- jobject jcaller,
+JNI_GENERATOR_EXPORT jlong Java_org_chromium_TestJni_nativeAddBookmark(JNIEnv*
+ env, jobject jcaller,
jint nativeChromeBrowserProvider,
jstring url,
jstring title,
@@ -52,71 +55,79 @@ static jlong Java_org_chromium_TestJni_nativeAddBookmark(JNIEnv* env,
ChromeBrowserProvider* native =
reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
CHECK_NATIVE_PTR(env, jcaller, native, "AddBookmark", 0);
- return native->AddBookmark(env, JavaParamRef<jobject>(env, jcaller),
- JavaParamRef<jstring>(env, url), JavaParamRef<jstring>(env, title),
- isFolder, parentId);
+ return native->AddBookmark(env, base::android::JavaParamRef<jobject>(env,
+ jcaller), base::android::JavaParamRef<jstring>(env, url),
+ base::android::JavaParamRef<jstring>(env, title), isFolder, parentId);
}
-static ScopedJavaLocalRef<jstring> GetDomainAndRegistry(JNIEnv* env, const
- JavaParamRef<jclass>& jcaller,
- const JavaParamRef<jstring>& url);
+static base::android::ScopedJavaLocalRef<jstring> GetDomainAndRegistry(JNIEnv*
+ env, const base::android::JavaParamRef<jclass>& jcaller,
+ const base::android::JavaParamRef<jstring>& url);
-static jstring Java_org_chromium_TestJni_nativeGetDomainAndRegistry(JNIEnv* env,
- jclass jcaller,
+JNI_GENERATOR_EXPORT jstring
+ Java_org_chromium_TestJni_nativeGetDomainAndRegistry(JNIEnv* env, jclass
+ jcaller,
jstring url) {
- return GetDomainAndRegistry(env, JavaParamRef<jclass>(env, jcaller),
- JavaParamRef<jstring>(env, url)).Release();
+ return GetDomainAndRegistry(env, base::android::JavaParamRef<jclass>(env,
+ jcaller), base::android::JavaParamRef<jstring>(env, url)).Release();
}
static void CreateHistoricalTabFromState(JNIEnv* env, const
- JavaParamRef<jclass>& jcaller,
- const JavaParamRef<jbyteArray>& state,
+ base::android::JavaParamRef<jclass>& jcaller,
+ const base::android::JavaParamRef<jbyteArray>& state,
jint tab_index);
-static void Java_org_chromium_TestJni_nativeCreateHistoricalTabFromState(JNIEnv*
- env, jclass jcaller,
+JNI_GENERATOR_EXPORT void
+ Java_org_chromium_TestJni_nativeCreateHistoricalTabFromState(JNIEnv* env,
+ jclass jcaller,
jbyteArray state,
jint tab_index) {
- return CreateHistoricalTabFromState(env, JavaParamRef<jclass>(env, jcaller),
- JavaParamRef<jbyteArray>(env, state), tab_index);
+ return CreateHistoricalTabFromState(env,
+ base::android::JavaParamRef<jclass>(env, jcaller),
+ base::android::JavaParamRef<jbyteArray>(env, state), tab_index);
}
-static ScopedJavaLocalRef<jbyteArray> GetStateAsByteArray(JNIEnv* env, const
- JavaParamRef<jobject>& jcaller,
- const JavaParamRef<jobject>& view);
+static base::android::ScopedJavaLocalRef<jbyteArray> GetStateAsByteArray(JNIEnv*
+ env, const base::android::JavaParamRef<jobject>& jcaller,
+ const base::android::JavaParamRef<jobject>& view);
-static jbyteArray Java_org_chromium_TestJni_nativeGetStateAsByteArray(JNIEnv*
- env, jobject jcaller,
+JNI_GENERATOR_EXPORT jbyteArray
+ Java_org_chromium_TestJni_nativeGetStateAsByteArray(JNIEnv* env, jobject
+ jcaller,
jobject view) {
- return GetStateAsByteArray(env, JavaParamRef<jobject>(env, jcaller),
- JavaParamRef<jobject>(env, view)).Release();
+ return GetStateAsByteArray(env, base::android::JavaParamRef<jobject>(env,
+ jcaller), base::android::JavaParamRef<jobject>(env, view)).Release();
}
-static ScopedJavaLocalRef<jobjectArray> GetAutofillProfileGUIDs(JNIEnv* env,
- const JavaParamRef<jclass>& jcaller);
+static base::android::ScopedJavaLocalRef<jobjectArray>
+ GetAutofillProfileGUIDs(JNIEnv* env, const
+ base::android::JavaParamRef<jclass>& jcaller);
-static jobjectArray
+JNI_GENERATOR_EXPORT jobjectArray
Java_org_chromium_TestJni_nativeGetAutofillProfileGUIDs(JNIEnv* env, jclass
jcaller) {
- return GetAutofillProfileGUIDs(env, JavaParamRef<jclass>(env,
+ return GetAutofillProfileGUIDs(env, base::android::JavaParamRef<jclass>(env,
jcaller)).Release();
}
-static void SetRecognitionResults(JNIEnv* env, const JavaParamRef<jobject>&
- jcaller,
+static void SetRecognitionResults(JNIEnv* env, const
+ base::android::JavaParamRef<jobject>& jcaller,
jint sessionId,
- const JavaParamRef<jobjectArray>& results);
+ const base::android::JavaParamRef<jobjectArray>& results);
-static void Java_org_chromium_TestJni_nativeSetRecognitionResults(JNIEnv* env,
- jobject jcaller,
+JNI_GENERATOR_EXPORT void
+ Java_org_chromium_TestJni_nativeSetRecognitionResults(JNIEnv* env, jobject
+ jcaller,
jint sessionId,
jobjectArray results) {
- return SetRecognitionResults(env, JavaParamRef<jobject>(env, jcaller),
- sessionId, JavaParamRef<jobjectArray>(env, results));
+ return SetRecognitionResults(env, base::android::JavaParamRef<jobject>(env,
+ jcaller), sessionId, base::android::JavaParamRef<jobjectArray>(env,
+ results));
}
-static jlong Java_org_chromium_TestJni_nativeAddBookmarkFromAPI(JNIEnv* env,
- jobject jcaller,
+JNI_GENERATOR_EXPORT jlong
+ Java_org_chromium_TestJni_nativeAddBookmarkFromAPI(JNIEnv* env, jobject
+ jcaller,
jint nativeChromeBrowserProvider,
jstring url,
jobject created,
@@ -128,33 +139,39 @@ static jlong Java_org_chromium_TestJni_nativeAddBookmarkFromAPI(JNIEnv* env,
ChromeBrowserProvider* native =
reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
CHECK_NATIVE_PTR(env, jcaller, native, "AddBookmarkFromAPI", 0);
- return native->AddBookmarkFromAPI(env, JavaParamRef<jobject>(env, jcaller),
- JavaParamRef<jstring>(env, url), JavaParamRef<jobject>(env, created),
- JavaParamRef<jobject>(env, isBookmark), JavaParamRef<jobject>(env, date),
- JavaParamRef<jbyteArray>(env, favicon), JavaParamRef<jstring>(env, title),
- JavaParamRef<jobject>(env, visits));
+ return native->AddBookmarkFromAPI(env,
+ base::android::JavaParamRef<jobject>(env, jcaller),
+ base::android::JavaParamRef<jstring>(env, url),
+ base::android::JavaParamRef<jobject>(env, created),
+ base::android::JavaParamRef<jobject>(env, isBookmark),
+ base::android::JavaParamRef<jobject>(env, date),
+ base::android::JavaParamRef<jbyteArray>(env, favicon),
+ base::android::JavaParamRef<jstring>(env, title),
+ base::android::JavaParamRef<jobject>(env, visits));
}
-static jint FindAll(JNIEnv* env, const JavaParamRef<jobject>& jcaller,
- const JavaParamRef<jstring>& find);
-
-static jint Java_org_chromium_TestJni_nativeFindAll(JNIEnv* env, jobject
+static jint FindAll(JNIEnv* env, const base::android::JavaParamRef<jobject>&
jcaller,
+ const base::android::JavaParamRef<jstring>& find);
+
+JNI_GENERATOR_EXPORT jint Java_org_chromium_TestJni_nativeFindAll(JNIEnv* env,
+ jobject jcaller,
jstring find) {
- return FindAll(env, JavaParamRef<jobject>(env, jcaller),
- JavaParamRef<jstring>(env, find));
+ return FindAll(env, base::android::JavaParamRef<jobject>(env, jcaller),
+ base::android::JavaParamRef<jstring>(env, find));
}
-static ScopedJavaLocalRef<jobject> GetInnerClass(JNIEnv* env, const
- JavaParamRef<jclass>& jcaller);
+static base::android::ScopedJavaLocalRef<jobject> GetInnerClass(JNIEnv* env,
+ const base::android::JavaParamRef<jclass>& jcaller);
-static jobject Java_org_chromium_TestJni_nativeGetInnerClass(JNIEnv* env, jclass
- jcaller) {
- return GetInnerClass(env, JavaParamRef<jclass>(env, jcaller)).Release();
+JNI_GENERATOR_EXPORT jobject
+ Java_org_chromium_TestJni_nativeGetInnerClass(JNIEnv* env, jclass jcaller) {
+ return GetInnerClass(env, base::android::JavaParamRef<jclass>(env,
+ jcaller)).Release();
}
-static jobject Java_org_chromium_TestJni_nativeQueryBitmap(JNIEnv* env,
- jobject jcaller,
+JNI_GENERATOR_EXPORT jobject Java_org_chromium_TestJni_nativeQueryBitmap(JNIEnv*
+ env, jobject jcaller,
jint nativeChromeBrowserProvider,
jobjectArray projection,
jstring selection,
@@ -163,14 +180,15 @@ static jobject Java_org_chromium_TestJni_nativeQueryBitmap(JNIEnv* env,
ChromeBrowserProvider* native =
reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
CHECK_NATIVE_PTR(env, jcaller, native, "QueryBitmap", NULL);
- return native->QueryBitmap(env, JavaParamRef<jobject>(env, jcaller),
- JavaParamRef<jobjectArray>(env, projection), JavaParamRef<jstring>(env,
- selection), JavaParamRef<jobjectArray>(env, selectionArgs),
- JavaParamRef<jstring>(env, sortOrder)).Release();
+ return native->QueryBitmap(env, base::android::JavaParamRef<jobject>(env,
+ jcaller), base::android::JavaParamRef<jobjectArray>(env, projection),
+ base::android::JavaParamRef<jstring>(env, selection),
+ base::android::JavaParamRef<jobjectArray>(env, selectionArgs),
+ base::android::JavaParamRef<jstring>(env, sortOrder)).Release();
}
-static void Java_org_chromium_TestJni_nativeGotOrientation(JNIEnv* env,
- jobject jcaller,
+JNI_GENERATOR_EXPORT void Java_org_chromium_TestJni_nativeGotOrientation(JNIEnv*
+ env, jobject jcaller,
jint nativeDataFetcherImplAndroid,
jdouble alpha,
jdouble beta,
@@ -178,19 +196,21 @@ static void Java_org_chromium_TestJni_nativeGotOrientation(JNIEnv* env,
DataFetcherImplAndroid* native =
reinterpret_cast<DataFetcherImplAndroid*>(nativeDataFetcherImplAndroid);
CHECK_NATIVE_PTR(env, jcaller, native, "GotOrientation");
- return native->GotOrientation(env, JavaParamRef<jobject>(env, jcaller), alpha,
- beta, gamma);
+ return native->GotOrientation(env, base::android::JavaParamRef<jobject>(env,
+ jcaller), alpha, beta, gamma);
}
-static ScopedJavaLocalRef<jthrowable> MessWithJavaException(JNIEnv* env, const
- JavaParamRef<jclass>& jcaller,
- const JavaParamRef<jthrowable>& e);
+static base::android::ScopedJavaLocalRef<jthrowable>
+ MessWithJavaException(JNIEnv* env, const
+ base::android::JavaParamRef<jclass>& jcaller,
+ const base::android::JavaParamRef<jthrowable>& e);
-static jthrowable Java_org_chromium_TestJni_nativeMessWithJavaException(JNIEnv*
- env, jclass jcaller,
+JNI_GENERATOR_EXPORT jthrowable
+ Java_org_chromium_TestJni_nativeMessWithJavaException(JNIEnv* env, jclass
+ jcaller,
jthrowable e) {
- return MessWithJavaException(env, JavaParamRef<jclass>(env, jcaller),
- JavaParamRef<jthrowable>(env, e)).Release();
+ return MessWithJavaException(env, base::android::JavaParamRef<jclass>(env,
+ jcaller), base::android::JavaParamRef<jthrowable>(env, e)).Release();
}
// Step 3: RegisterNatives.
@@ -301,9 +321,8 @@ static const JNINativeMethod kMethodsTestJni[] = {
};
static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kTestJniClassPath).obj()));
+ if (jni_generator::ShouldSkipJniRegistration(false))
+ return true;
const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
diff --git a/base/android/jni_generator/testNativesLong.golden b/base/android/jni_generator/testNativesLong.golden
index d5b67ba..ec029ce 100644
--- a/base/android/jni_generator/testNativesLong.golden
+++ b/base/android/jni_generator/testNativesLong.golden
@@ -20,19 +20,20 @@
namespace {
const char kTestJniClassPath[] = "org/chromium/TestJni";
// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_TestJni_clazz = NULL;
-#define TestJni_clazz(env) g_TestJni_clazz
+base::subtle::AtomicWord g_TestJni_clazz __attribute__((unused)) = 0;
+#define TestJni_clazz(env) base::android::LazyGetClass(env, kTestJniClassPath, &g_TestJni_clazz)
} // namespace
// Step 2: method stubs.
-static void Java_org_chromium_TestJni_nativeDestroy(JNIEnv* env,
+JNI_GENERATOR_EXPORT void Java_org_chromium_TestJni_nativeDestroy(JNIEnv* env,
jobject jcaller,
jlong nativeChromeBrowserProvider) {
ChromeBrowserProvider* native =
reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
- return native->Destroy(env, JavaParamRef<jobject>(env, jcaller));
+ return native->Destroy(env, base::android::JavaParamRef<jobject>(env,
+ jcaller));
}
// Step 3: RegisterNatives.
@@ -46,9 +47,8 @@ static const JNINativeMethod kMethodsTestJni[] = {
};
static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kTestJniClassPath).obj()));
+ if (jni_generator::ShouldSkipJniRegistration(false))
+ return true;
const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
diff --git a/base/android/jni_generator/testSingleJNIAdditionalImport.golden b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
index 1b2895e..ef618da 100644
--- a/base/android/jni_generator/testSingleJNIAdditionalImport.golden
+++ b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
@@ -20,26 +20,27 @@
namespace {
const char kFooClassPath[] = "org/chromium/foo/Foo";
// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_Foo_clazz = NULL;
-#define Foo_clazz(env) g_Foo_clazz
+base::subtle::AtomicWord g_Foo_clazz __attribute__((unused)) = 0;
+#define Foo_clazz(env) base::android::LazyGetClass(env, kFooClassPath, &g_Foo_clazz)
} // namespace
// Step 2: method stubs.
-static void DoSomething(JNIEnv* env, const JavaParamRef<jclass>& jcaller,
- const JavaParamRef<jobject>& callback);
-
-static void Java_org_chromium_foo_Foo_nativeDoSomething(JNIEnv* env, jclass
+static void DoSomething(JNIEnv* env, const base::android::JavaParamRef<jclass>&
jcaller,
+ const base::android::JavaParamRef<jobject>& callback);
+
+JNI_GENERATOR_EXPORT void Java_org_chromium_foo_Foo_nativeDoSomething(JNIEnv*
+ env, jclass jcaller,
jobject callback) {
- return DoSomething(env, JavaParamRef<jclass>(env, jcaller),
- JavaParamRef<jobject>(env, callback));
+ return DoSomething(env, base::android::JavaParamRef<jclass>(env, jcaller),
+ base::android::JavaParamRef<jobject>(env, callback));
}
static base::subtle::AtomicWord g_Foo_calledByNative = 0;
-static void Java_Foo_calledByNative(JNIEnv* env, jobject callback) {
- /* Must call RegisterNativesImpl() */
+static void Java_Foo_calledByNative(JNIEnv* env, const
+ base::android::JavaRefOrBare<jobject>& callback) {
CHECK_CLAZZ(env, Foo_clazz(env),
Foo_clazz(env));
jmethodID method_id =
@@ -47,7 +48,6 @@ static void Java_Foo_calledByNative(JNIEnv* env, jobject callback) {
base::android::MethodID::TYPE_STATIC>(
env, Foo_clazz(env),
"calledByNative",
-
"("
"Lorg/chromium/foo/Bar$Callback;"
")"
@@ -55,9 +55,8 @@ static void Java_Foo_calledByNative(JNIEnv* env, jobject callback) {
&g_Foo_calledByNative);
env->CallStaticVoidMethod(Foo_clazz(env),
- method_id, callback);
+ method_id, callback.obj());
jni_generator::CheckException(env);
-
}
// Step 3: RegisterNatives.
@@ -71,9 +70,8 @@ static const JNINativeMethod kMethodsFoo[] = {
};
static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_Foo_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kFooClassPath).obj()));
+ if (jni_generator::ShouldSkipJniRegistration(false))
+ return true;
const int kMethodsFooSize = arraysize(kMethodsFoo);
diff --git a/base/android/jni_utils.cc b/base/android/jni_utils.cc
index b4d682b..848dfd7 100644
--- a/base/android/jni_utils.cc
+++ b/base/android/jni_utils.cc
@@ -4,7 +4,6 @@
#include "base/android/jni_utils.h"
-#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "jni/JNIUtils_jni.h"
@@ -16,8 +15,8 @@ ScopedJavaLocalRef<jobject> GetClassLoader(JNIEnv* env) {
return Java_JNIUtils_getClassLoader(env);
}
-bool RegisterJNIUtils(JNIEnv* env) {
- return RegisterNativesImpl(env);
+bool isSelectiveJniRegistrationEnabled(JNIEnv* env) {
+ return Java_JNIUtils_isSelectiveJniRegistrationEnabled(env);
}
} // namespace android
diff --git a/base/android/jni_utils.h b/base/android/jni_utils.h
index b793aed..ef645c2 100644
--- a/base/android/jni_utils.h
+++ b/base/android/jni_utils.h
@@ -18,7 +18,8 @@ namespace android {
// via JNI from Java.
BASE_EXPORT ScopedJavaLocalRef<jobject> GetClassLoader(JNIEnv* env);
-bool RegisterJNIUtils(JNIEnv* env);
+// Returns true if the current process permits selective JNI registration.
+BASE_EXPORT bool isSelectiveJniRegistrationEnabled(JNIEnv* env);
} // namespace android
} // namespace base
diff --git a/base/android/jni_weak_ref.cc b/base/android/jni_weak_ref.cc
index 55244f2..fe7ea2e 100644
--- a/base/android/jni_weak_ref.cc
+++ b/base/android/jni_weak_ref.cc
@@ -4,24 +4,34 @@
#include "base/android/jni_weak_ref.h"
+#include <utility>
+
#include "base/android/jni_android.h"
#include "base/logging.h"
using base::android::AttachCurrentThread;
-JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef()
- : obj_(NULL) {
-}
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef() : obj_(nullptr) {}
JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(
const JavaObjectWeakGlobalRef& orig)
- : obj_(NULL) {
+ : obj_(nullptr) {
Assign(orig);
}
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(JavaObjectWeakGlobalRef&& orig)
+ : obj_(orig.obj_) {
+ orig.obj_ = nullptr;
+}
+
JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(JNIEnv* env, jobject obj)
: obj_(env->NewWeakGlobalRef(obj)) {
- DCHECK(obj_);
+}
+
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& obj)
+ : obj_(env->NewWeakGlobalRef(obj.obj())) {
}
JavaObjectWeakGlobalRef::~JavaObjectWeakGlobalRef() {
@@ -32,10 +42,14 @@ void JavaObjectWeakGlobalRef::operator=(const JavaObjectWeakGlobalRef& rhs) {
Assign(rhs);
}
+void JavaObjectWeakGlobalRef::operator=(JavaObjectWeakGlobalRef&& rhs) {
+ std::swap(obj_, rhs.obj_);
+}
+
void JavaObjectWeakGlobalRef::reset() {
if (obj_) {
AttachCurrentThread()->DeleteWeakGlobalRef(obj_);
- obj_ = NULL;
+ obj_ = nullptr;
}
}
@@ -46,7 +60,7 @@ base::android::ScopedJavaLocalRef<jobject>
base::android::ScopedJavaLocalRef<jobject> GetRealObject(
JNIEnv* env, jweak obj) {
- jobject real = NULL;
+ jobject real = nullptr;
if (obj)
real = env->NewLocalRef(obj);
return base::android::ScopedJavaLocalRef<jobject>(env, real);
@@ -60,5 +74,5 @@ void JavaObjectWeakGlobalRef::Assign(const JavaObjectWeakGlobalRef& other) {
if (obj_)
env->DeleteWeakGlobalRef(obj_);
- obj_ = other.obj_ ? env->NewWeakGlobalRef(other.obj_) : NULL;
+ obj_ = other.obj_ ? env->NewWeakGlobalRef(other.obj_) : nullptr;
}
diff --git a/base/android/jni_weak_ref.h b/base/android/jni_weak_ref.h
index c851046..223c47b 100644
--- a/base/android/jni_weak_ref.h
+++ b/base/android/jni_weak_ref.h
@@ -18,14 +18,22 @@ class BASE_EXPORT JavaObjectWeakGlobalRef {
public:
JavaObjectWeakGlobalRef();
JavaObjectWeakGlobalRef(const JavaObjectWeakGlobalRef& orig);
+ JavaObjectWeakGlobalRef(JavaObjectWeakGlobalRef&& orig);
JavaObjectWeakGlobalRef(JNIEnv* env, jobject obj);
+ JavaObjectWeakGlobalRef(JNIEnv* env,
+ const base::android::JavaRef<jobject>& obj);
virtual ~JavaObjectWeakGlobalRef();
void operator=(const JavaObjectWeakGlobalRef& rhs);
+ void operator=(JavaObjectWeakGlobalRef&& rhs);
base::android::ScopedJavaLocalRef<jobject> get(JNIEnv* env) const;
- bool is_empty() const { return obj_ == NULL; }
+ // Returns true if the weak reference has not been initialized to point at
+ // an object (or ḣas had reset() called).
+ // Do not call this to test if the object referred to still exists! The weak
+ // reference remains initialized even if the target object has been collected.
+ bool is_uninitialized() const { return obj_ == nullptr; }
void reset();
diff --git a/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java b/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java
index bfcd7aa..269f84b 100644
--- a/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java
+++ b/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java
@@ -10,18 +10,19 @@ import static org.mockito.Mockito.verify;
import android.app.Activity;
import android.view.KeyEvent;
-import junit.framework.Assert;
-
import org.chromium.base.BaseChromiumApplication.WindowFocusChangedListener;
-import org.chromium.base.test.shadows.ShadowMultiDex;
import org.chromium.testing.local.LocalRobolectricTestRunner;
+import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowActivity;
+import org.robolectric.shadows.multidex.ShadowMultiDex;
import org.robolectric.util.ActivityController;
/** Unit tests for {@link BaseChromiumApplication}. */
@@ -52,7 +53,7 @@ public class BaseChromiumApplicationTest {
@Test
public void testWindowsFocusChanged() throws Exception {
- BaseChromiumApplication app = (BaseChromiumApplication) Robolectric.application;
+ BaseChromiumApplication app = (BaseChromiumApplication) RuntimeEnvironment.application;
WindowFocusChangedListener mock = mock(WindowFocusChangedListener.class);
app.registerWindowFocusChangedListener(mock);
@@ -60,7 +61,7 @@ public class BaseChromiumApplicationTest {
ActivityController<Activity> controller =
Robolectric.buildActivity(Activity.class).create().start().visible();
TrackingShadowActivity shadow =
- (TrackingShadowActivity) Robolectric.shadowOf(controller.get());
+ (TrackingShadowActivity) Shadows.shadowOf(controller.get());
controller.get().getWindow().getCallback().onWindowFocusChanged(true);
// Assert that listeners were notified.
diff --git a/base/android/library_loader/library_loader_hooks.cc b/base/android/library_loader/library_loader_hooks.cc
index 025075e..621575c 100644
--- a/base/android/library_loader/library_loader_hooks.cc
+++ b/base/android/library_loader/library_loader_hooks.cc
@@ -10,7 +10,7 @@
#include "base/android/library_loader/library_prefetcher.h"
#include "base/at_exit.h"
#include "base/metrics/histogram.h"
-#include "base/metrics/sparse_histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "jni/LibraryLoader_jni.h"
namespace base {
@@ -21,6 +21,7 @@ namespace {
base::AtExitManager* g_at_exit_manager = NULL;
const char* g_library_version_number = "";
LibraryLoadedHook* g_registration_callback = NULL;
+NativeInitializationHook* g_native_initialization_hook = NULL;
enum RendererHistogramCode {
// Renderer load at fixed address success, fail, or not attempted.
@@ -149,6 +150,11 @@ static void RegisterLibraryPreloaderRendererHistogram(
g_library_preloader_renderer_histogram_code_registered = true;
}
+void SetNativeInitializationHook(
+ NativeInitializationHook native_initialization_hook) {
+ g_native_initialization_hook = native_initialization_hook;
+}
+
void RecordLibraryLoaderRendererHistograms() {
RecordChromiumAndroidLinkerRendererHistogram();
RecordLibraryPreloaderRendereHistogram();
@@ -167,6 +173,9 @@ static void InitCommandLine(
static jboolean LibraryLoaded(JNIEnv* env,
const JavaParamRef<jobject>& jcaller) {
+ if (g_native_initialization_hook && !g_native_initialization_hook()) {
+ return false;
+ }
if (g_registration_callback == NULL) {
return true;
}
diff --git a/base/android/library_loader/library_loader_hooks.h b/base/android/library_loader/library_loader_hooks.h
index 3e8969b..5c37e6e 100644
--- a/base/android/library_loader/library_loader_hooks.h
+++ b/base/android/library_loader/library_loader_hooks.h
@@ -8,6 +8,7 @@
#include <jni.h>
#include "base/base_export.h"
+#include "base/callback.h"
namespace base {
namespace android {
@@ -27,6 +28,11 @@ enum LibraryProcessType {
PROCESS_WEBVIEW_CHILD = 4,
};
+typedef bool NativeInitializationHook();
+
+BASE_EXPORT void SetNativeInitializationHook(
+ NativeInitializationHook native_initialization_hook);
+
// Record any pending renderer histogram value as histograms. Pending values
// are set by RegisterChromiumAndroidLinkerRendererHistogram and
// RegisterLibraryPreloaderRendererHistogram.
diff --git a/base/android/library_loader/library_prefetcher.cc b/base/android/library_loader/library_prefetcher.cc
index c7ec990..a946c82 100644
--- a/base/android/library_loader/library_prefetcher.cc
+++ b/base/android/library_loader/library_prefetcher.cc
@@ -16,6 +16,7 @@
#include "base/macros.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_util.h"
+#include "build/build_config.h"
namespace base {
namespace android {
@@ -50,6 +51,13 @@ bool PathMatchesSuffix(const std::string& path) {
// Heap allocations, syscalls and library functions are not allowed in this
// function.
// Returns true for success.
+#if defined(ADDRESS_SANITIZER)
+// Disable AddressSanitizer instrumentation for this function. It is touching
+// memory that hasn't been allocated by the app, though the addresses are
+// valid. Furthermore, this takes place in a child process. See crbug.com/653372
+// for the context.
+__attribute__((no_sanitize_address))
+#endif
bool Prefetch(const std::vector<std::pair<uintptr_t, uintptr_t>>& ranges) {
for (const auto& range : ranges) {
const uintptr_t page_mask = kPageSize - 1;
diff --git a/base/android/linker/BUILD.gn b/base/android/linker/BUILD.gn
index 3724b88..c2bfb11 100644
--- a/base/android/linker/BUILD.gn
+++ b/base/android/linker/BUILD.gn
@@ -6,7 +6,6 @@ import("//build/config/android/config.gni")
assert(is_android)
-# GYP: //base/base.gyp:chromium_android_linker
shared_library("chromium_android_linker") {
sources = [
"android_dlext.h",
diff --git a/base/android/linker/config.gni b/base/android/linker/config.gni
index 174c1ab..27793ff 100644
--- a/base/android/linker/config.gni
+++ b/base/android/linker/config.gni
@@ -6,7 +6,8 @@ import("//build/config/android/config.gni")
import("//build/config/compiler/compiler.gni")
import("//build/config/sanitizers/sanitizers.gni")
-# Chromium linker crashes on component builds on Android 4.4. See b/11379966
+# Chromium linker doesn't reliably support loading multiple libraries;
+# disable for component builds, see crbug.com/657093.
# Chromium linker causes instrumentation to return incorrect results.
chromium_linker_supported =
!is_component_build && !enable_profiling && !use_order_profiling && !is_asan
diff --git a/base/android/locale_utils.cc b/base/android/locale_utils.cc
index af46f89..b3a2346 100644
--- a/base/android/locale_utils.cc
+++ b/base/android/locale_utils.cc
@@ -16,16 +16,12 @@ std::string GetDefaultCountryCode() {
return ConvertJavaStringToUTF8(Java_LocaleUtils_getDefaultCountryCode(env));
}
-std::string GetDefaultLocale() {
+std::string GetDefaultLocaleString() {
JNIEnv* env = base::android::AttachCurrentThread();
- ScopedJavaLocalRef<jstring> locale = Java_LocaleUtils_getDefaultLocale(
- env);
+ ScopedJavaLocalRef<jstring> locale =
+ Java_LocaleUtils_getDefaultLocaleString(env);
return ConvertJavaStringToUTF8(locale);
}
-bool RegisterLocaleUtils(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace android
} // namespace base
diff --git a/base/android/locale_utils.h b/base/android/locale_utils.h
index 9e03b83..be68890 100644
--- a/base/android/locale_utils.h
+++ b/base/android/locale_utils.h
@@ -16,10 +16,8 @@ namespace android {
BASE_EXPORT std::string GetDefaultCountryCode();
-// Return the current default locale of the device.
-BASE_EXPORT std::string GetDefaultLocale();
-
-BASE_EXPORT bool RegisterLocaleUtils(JNIEnv* env);
+// Return the current default locale of the device as string.
+BASE_EXPORT std::string GetDefaultLocaleString();
} // namespace android
} // namespace base
diff --git a/base/android/memory_pressure_listener_android.cc b/base/android/memory_pressure_listener_android.cc
index 5975b94..32e0871 100644
--- a/base/android/memory_pressure_listener_android.cc
+++ b/base/android/memory_pressure_listener_android.cc
@@ -8,6 +8,8 @@
#include "base/memory/memory_pressure_listener.h"
#include "jni/MemoryPressureListener_jni.h"
+using base::android::JavaParamRef;
+
// Defined and called by JNI.
static void OnMemoryPressure(JNIEnv* env,
const JavaParamRef<jclass>& clazz,
diff --git a/base/android/path_utils.cc b/base/android/path_utils.cc
index b765449..89ab833 100644
--- a/base/android/path_utils.cc
+++ b/base/android/path_utils.cc
@@ -17,8 +17,7 @@ namespace android {
bool GetDataDirectory(FilePath* result) {
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> path =
- Java_PathUtils_getDataDirectory(env, GetApplicationContext());
+ ScopedJavaLocalRef<jstring> path = Java_PathUtils_getDataDirectory(env);
FilePath data_path(ConvertJavaStringToUTF8(path));
*result = data_path;
return true;
@@ -26,8 +25,7 @@ bool GetDataDirectory(FilePath* result) {
bool GetDatabaseDirectory(FilePath* result) {
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> path =
- Java_PathUtils_getDatabaseDirectory(env, GetApplicationContext());
+ ScopedJavaLocalRef<jstring> path = Java_PathUtils_getDatabaseDirectory(env);
FilePath data_path(ConvertJavaStringToUTF8(path));
*result = data_path;
return true;
@@ -35,8 +33,7 @@ bool GetDatabaseDirectory(FilePath* result) {
bool GetCacheDirectory(FilePath* result) {
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> path =
- Java_PathUtils_getCacheDirectory(env, GetApplicationContext());
+ ScopedJavaLocalRef<jstring> path = Java_PathUtils_getCacheDirectory(env);
FilePath cache_path(ConvertJavaStringToUTF8(path));
*result = cache_path;
return true;
@@ -45,7 +42,7 @@ bool GetCacheDirectory(FilePath* result) {
bool GetThumbnailCacheDirectory(FilePath* result) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jstring> path =
- Java_PathUtils_getThumbnailCacheDirectory(env, GetApplicationContext());
+ Java_PathUtils_getThumbnailCacheDirectory(env);
FilePath thumbnail_cache_path(ConvertJavaStringToUTF8(path));
*result = thumbnail_cache_path;
return true;
@@ -53,8 +50,7 @@ bool GetThumbnailCacheDirectory(FilePath* result) {
bool GetDownloadsDirectory(FilePath* result) {
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> path =
- Java_PathUtils_getDownloadsDirectory(env, GetApplicationContext());
+ ScopedJavaLocalRef<jstring> path = Java_PathUtils_getDownloadsDirectory(env);
FilePath downloads_path(ConvertJavaStringToUTF8(path));
*result = downloads_path;
return true;
@@ -63,7 +59,7 @@ bool GetDownloadsDirectory(FilePath* result) {
bool GetNativeLibraryDirectory(FilePath* result) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jstring> path =
- Java_PathUtils_getNativeLibraryDirectory(env, GetApplicationContext());
+ Java_PathUtils_getNativeLibraryDirectory(env);
FilePath library_path(ConvertJavaStringToUTF8(path));
*result = library_path;
return true;
@@ -78,9 +74,5 @@ bool GetExternalStorageDirectory(FilePath* result) {
return true;
}
-bool RegisterPathUtils(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace android
} // namespace base
diff --git a/base/android/path_utils.h b/base/android/path_utils.h
index 6501f1b..7402644 100644
--- a/base/android/path_utils.h
+++ b/base/android/path_utils.h
@@ -48,8 +48,6 @@ BASE_EXPORT bool GetNativeLibraryDirectory(FilePath* result);
// is placed in the FilePath pointed to by 'result'.
BASE_EXPORT bool GetExternalStorageDirectory(FilePath* result);
-bool RegisterPathUtils(JNIEnv* env);
-
} // namespace android
} // namespace base
diff --git a/base/android/record_histogram.cc b/base/android/record_histogram.cc
index 3c51fe2..1a207a1 100644
--- a/base/android/record_histogram.cc
+++ b/base/android/record_histogram.cc
@@ -53,12 +53,16 @@ class HistogramCache {
jstring j_histogram_name,
int32_t expected_min,
int32_t expected_max,
- int32_t expected_bucket_count,
+ uint32_t expected_bucket_count,
HistogramBase* histogram) {
+ std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+ bool valid_arguments = Histogram::InspectConstructionArguments(
+ histogram_name, &expected_min, &expected_max, &expected_bucket_count);
+ DCHECK(valid_arguments);
DCHECK(histogram->HasConstructionArguments(expected_min, expected_max,
expected_bucket_count))
- << ConvertJavaStringToUTF8(env, j_histogram_name) << "/" << expected_min
- << "/" << expected_max << "/" << expected_bucket_count << " vs. "
+ << histogram_name << "/" << expected_min << "/" << expected_max << "/"
+ << expected_bucket_count << " vs. "
<< HistogramConstructionParamsToString(histogram);
}
@@ -113,6 +117,8 @@ class HistogramCache {
return histogram;
}
+ DCHECK_GE(min, 1) << "The min expected sample must be >= 1";
+
std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
histogram =
Histogram::FactoryGet(histogram_name, min, max, num_buckets,
diff --git a/base/android/scoped_java_ref.cc b/base/android/scoped_java_ref.cc
index 4d4ef6d..2876ba4 100644
--- a/base/android/scoped_java_ref.cc
+++ b/base/android/scoped_java_ref.cc
@@ -26,7 +26,9 @@ ScopedJavaLocalFrame::ScopedJavaLocalFrame(JNIEnv* env, int capacity)
DCHECK(!failed);
}
-ScopedJavaLocalFrame::~ScopedJavaLocalFrame() { env_->PopLocalFrame(NULL); }
+ScopedJavaLocalFrame::~ScopedJavaLocalFrame() {
+ env_->PopLocalFrame(nullptr);
+}
#if DCHECK_IS_ON()
// This constructor is inlined when DCHECKs are disabled; don't add anything
@@ -69,14 +71,14 @@ void JavaRef<jobject>::ResetLocalRef(JNIEnv* env) {
if (obj_) {
DCHECK_EQ(env, AttachCurrentThread()); // Is |env| on correct thread.
env->DeleteLocalRef(obj_);
- obj_ = NULL;
+ obj_ = nullptr;
}
}
void JavaRef<jobject>::ResetGlobalRef() {
if (obj_) {
AttachCurrentThread()->DeleteGlobalRef(obj_);
- obj_ = NULL;
+ obj_ = nullptr;
}
}
diff --git a/base/android/scoped_java_ref.h b/base/android/scoped_java_ref.h
index a1b4b13..6d728e9 100644
--- a/base/android/scoped_java_ref.h
+++ b/base/android/scoped_java_ref.h
@@ -9,6 +9,7 @@
#include <stddef.h>
#include <type_traits>
+#include <utility>
#include "base/base_export.h"
#include "base/logging.h"
@@ -43,23 +44,23 @@ template<typename T> class JavaRef;
template<>
class BASE_EXPORT JavaRef<jobject> {
public:
+ // Initializes a null reference. Don't add anything else here; it's inlined.
+ JavaRef() : obj_(nullptr) {}
+
// Allow nullptr to be converted to JavaRef. This avoids having to declare an
- // empty ScopedJavaLocalRef just to pass null to a function with a JavaRef
- // parameter, and makes C++ "nullptr" and Java "null" equivalent.
+ // empty JavaRef just to pass null to a function, and makes C++ "nullptr" and
+ // Java "null" equivalent.
JavaRef(std::nullptr_t) : JavaRef() {}
- // Public to allow destruction of temporary JavaRef objects created by the
- // nullptr conversion. Don't add anything else here; it's inlined.
+ // Public to allow destruction of null JavaRef objects.
+ // Don't add anything else here; it's inlined.
~JavaRef() {}
jobject obj() const { return obj_; }
- bool is_null() const { return obj_ == NULL; }
+ bool is_null() const { return obj_ == nullptr; }
protected:
- // Initializes a NULL reference. Don't add anything else here; it's inlined.
- JavaRef() : obj_(NULL) {}
-
// Takes ownership of the |obj| reference passed; requires it to be a local
// reference type.
#if DCHECK_IS_ON()
@@ -70,6 +71,8 @@ class BASE_EXPORT JavaRef<jobject> {
JavaRef(JNIEnv* env, jobject obj) : obj_(obj) {}
#endif
+ void swap(JavaRef& other) { std::swap(obj_, other.obj_); }
+
// The following are implementation detail convenience methods, for
// use by the sub-classes.
JNIEnv* SetNewLocalRef(JNIEnv* env, jobject obj);
@@ -90,14 +93,13 @@ class BASE_EXPORT JavaRef<jobject> {
template<typename T>
class JavaRef : public JavaRef<jobject> {
public:
+ JavaRef() {}
JavaRef(std::nullptr_t) : JavaRef<jobject>(nullptr) {}
~JavaRef() {}
T obj() const { return static_cast<T>(JavaRef<jobject>::obj()); }
protected:
- JavaRef() {}
-
JavaRef(JNIEnv* env, T obj) : JavaRef<jobject>(env, obj) {}
private:
@@ -144,7 +146,8 @@ class JavaParamRef : public JavaRef<T> {
template<typename T>
class ScopedJavaLocalRef : public JavaRef<T> {
public:
- ScopedJavaLocalRef() : env_(NULL) {}
+ ScopedJavaLocalRef() : env_(nullptr) {}
+ ScopedJavaLocalRef(std::nullptr_t) : env_(nullptr) {}
// Non-explicit copy constructor, to allow ScopedJavaLocalRef to be returned
// by value as this is the normal usage pattern.
@@ -153,14 +156,18 @@ class ScopedJavaLocalRef : public JavaRef<T> {
this->SetNewLocalRef(env_, other.obj());
}
- template<typename U>
- explicit ScopedJavaLocalRef(const U& other)
- : env_(NULL) {
+ ScopedJavaLocalRef(ScopedJavaLocalRef<T>&& other) : env_(other.env_) {
+ this->swap(other);
+ }
+
+ explicit ScopedJavaLocalRef(const JavaRef<T>& other) : env_(nullptr) {
this->Reset(other);
}
// Assumes that |obj| is a local reference to a Java object and takes
// ownership of this local reference.
+ // TODO(torne): this shouldn't be used outside of JNI helper functions but
+ // there are currently some cases where there aren't helpers for things.
ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef<T>(env, obj), env_(env) {}
~ScopedJavaLocalRef() {
@@ -173,31 +180,32 @@ class ScopedJavaLocalRef : public JavaRef<T> {
this->Reset(other);
}
+ void operator=(ScopedJavaLocalRef<T>&& other) {
+ env_ = other.env_;
+ this->swap(other);
+ }
+
void Reset() {
this->ResetLocalRef(env_);
}
- template<typename U>
- void Reset(const ScopedJavaLocalRef<U>& other) {
+ void Reset(const ScopedJavaLocalRef<T>& other) {
// We can copy over env_ here as |other| instance must be from the same
// thread as |this| local ref. (See class comment for multi-threading
// limitations, and alternatives).
this->Reset(other.env_, other.obj());
}
- template<typename U>
- void Reset(const U& other) {
- // If |env_| was not yet set (is still NULL) it will be attached to the
+ void Reset(const JavaRef<T>& other) {
+ // If |env_| was not yet set (is still null) it will be attached to the
// current thread in SetNewLocalRef().
this->Reset(env_, other.obj());
}
- template<typename U>
- void Reset(JNIEnv* env, U obj) {
- static_assert(std::is_convertible<U, T>::value,
- "U must be convertible to T");
- env_ = this->SetNewLocalRef(env, obj);
- }
+ // Creates a new local reference to the Java object, unlike the constructor
+ // with the same parameters that takes ownership of the existing reference.
+ // TODO(torne): these should match as this is confusing.
+ void Reset(JNIEnv* env, T obj) { env_ = this->SetNewLocalRef(env, obj); }
// Releases the local reference to the caller. The caller *must* delete the
// local reference when it is done with it. Note that calling a Java method
@@ -227,17 +235,17 @@ template<typename T>
class ScopedJavaGlobalRef : public JavaRef<T> {
public:
ScopedJavaGlobalRef() {}
+ ScopedJavaGlobalRef(std::nullptr_t) {}
ScopedJavaGlobalRef(const ScopedJavaGlobalRef<T>& other) {
this->Reset(other);
}
+ ScopedJavaGlobalRef(ScopedJavaGlobalRef<T>&& other) { this->swap(other); }
+
ScopedJavaGlobalRef(JNIEnv* env, T obj) { this->Reset(env, obj); }
- template<typename U>
- explicit ScopedJavaGlobalRef(const U& other) {
- this->Reset(other);
- }
+ explicit ScopedJavaGlobalRef(const JavaRef<T>& other) { this->Reset(other); }
~ScopedJavaGlobalRef() {
this->Reset();
@@ -249,26 +257,19 @@ class ScopedJavaGlobalRef : public JavaRef<T> {
this->Reset(other);
}
+ void operator=(ScopedJavaGlobalRef<T>&& other) { this->swap(other); }
+
void Reset() {
this->ResetGlobalRef();
}
- template<typename U>
- void Reset(const U& other) {
- this->Reset(NULL, other.obj());
- }
+ void Reset(const JavaRef<T>& other) { this->Reset(nullptr, other.obj()); }
- template<typename U>
- void Reset(JNIEnv* env, const JavaParamRef<U>& other) {
+ void Reset(JNIEnv* env, const JavaParamRef<T>& other) {
this->Reset(env, other.obj());
}
- template<typename U>
- void Reset(JNIEnv* env, U obj) {
- static_assert(std::is_convertible<U, T>::value,
- "U must be convertible to T");
- this->SetNewGlobalRef(env, obj);
- }
+ void Reset(JNIEnv* env, T obj) { this->SetNewGlobalRef(env, obj); }
// Releases the global reference to the caller. The caller *must* delete the
// global reference when it is done with it. Note that calling a Java method
@@ -278,6 +279,22 @@ class ScopedJavaGlobalRef : public JavaRef<T> {
}
};
+// Temporary type for parameters to Java functions, to allow incremental
+// migration from bare jobject to JavaRef. Don't use outside JNI generator.
+template <typename T>
+class JavaRefOrBare {
+ public:
+ JavaRefOrBare(std::nullptr_t) : obj_(nullptr) {}
+ JavaRefOrBare(const JavaRef<T>& ref) : obj_(ref.obj()) {}
+ JavaRefOrBare(T obj) : obj_(obj) {}
+ T obj() const { return obj_; }
+
+ private:
+ T obj_;
+
+ DISALLOW_COPY_AND_ASSIGN(JavaRefOrBare);
+};
+
} // namespace android
} // namespace base
diff --git a/base/android/scoped_java_ref_unittest.cc b/base/android/scoped_java_ref_unittest.cc
index 3f4419a..99d035b 100644
--- a/base/android/scoped_java_ref_unittest.cc
+++ b/base/android/scoped_java_ref_unittest.cc
@@ -106,6 +106,17 @@ TEST_F(ScopedJavaRefTest, RefCounts) {
EXPECT_EQ(2, g_local_refs);
}
EXPECT_EQ(1, g_local_refs);
+ {
+ ScopedJavaLocalRef<jstring> str4((ScopedJavaLocalRef<jstring>(str2)));
+ EXPECT_EQ(2, g_local_refs);
+ }
+ EXPECT_EQ(1, g_local_refs);
+ {
+ ScopedJavaLocalRef<jstring> str5;
+ str5 = ScopedJavaLocalRef<jstring>(str2);
+ EXPECT_EQ(2, g_local_refs);
+ }
+ EXPECT_EQ(1, g_local_refs);
str2.Reset();
EXPECT_EQ(0, g_local_refs);
global_str.Reset();
diff --git a/base/android/sys_utils.cc b/base/android/sys_utils.cc
index e89c1b3..a576644 100644
--- a/base/android/sys_utils.cc
+++ b/base/android/sys_utils.cc
@@ -11,10 +11,6 @@
namespace base {
namespace android {
-bool SysUtils::Register(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
bool SysUtils::IsLowEndDeviceFromJni() {
JNIEnv* env = AttachCurrentThread();
return Java_SysUtils_isLowEndDevice(env);
@@ -22,4 +18,4 @@ bool SysUtils::IsLowEndDeviceFromJni() {
} // namespace android
-} // namespace base \ No newline at end of file
+} // namespace base
diff --git a/base/android/sys_utils.h b/base/android/sys_utils.h
index 85dc035..2edbdd5 100644
--- a/base/android/sys_utils.h
+++ b/base/android/sys_utils.h
@@ -12,8 +12,6 @@ namespace android {
class BASE_EXPORT SysUtils {
public:
- static bool Register(JNIEnv* env);
-
// Returns true iff this is a low-end device.
static bool IsLowEndDeviceFromJni();
};
diff --git a/base/android/thread_utils.h b/base/android/thread_utils.h
deleted file mode 100644
index cbe65f0..0000000
--- a/base/android/thread_utils.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2012 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 BASE_ANDROID_THREAD_UTILS_H_
-#define BASE_ANDROID_THREAD_UTILS_H_
-
-#include "base/android/jni_android.h"
-
-namespace base {
-
-bool RegisterThreadUtils(JNIEnv* env);
-
-} // namespace base
-
-#endif // BASE_ANDROID_THREAD_UTILS_H_
diff --git a/base/debug/stack_trace_android.cc b/base/debug/stack_trace_android.cc
index 1e80385..329204c 100644
--- a/base/debug/stack_trace_android.cc
+++ b/base/debug/stack_trace_android.cc
@@ -7,6 +7,8 @@
#include <android/log.h>
#include <stddef.h>
#include <unwind.h>
+
+#include <algorithm>
#include <ostream>
#include "base/debug/proc_maps_linux.h"
@@ -67,8 +69,10 @@ bool EnableInProcessStackDumping() {
return (sigaction(SIGPIPE, &action, NULL) == 0);
}
-StackTrace::StackTrace() {
- StackCrawlState state(reinterpret_cast<uintptr_t*>(trace_), kMaxTraces);
+StackTrace::StackTrace(size_t count) {
+ count = std::min(arraysize(trace_), count);
+
+ StackCrawlState state(reinterpret_cast<uintptr_t*>(trace_), count);
_Unwind_Backtrace(&TraceStackFrame, &state);
count_ = state.frame_count;
}
diff --git a/base/i18n/base_i18n_export.h b/base/i18n/base_i18n_export.h
new file mode 100644
index 0000000..e8a2add
--- /dev/null
+++ b/base/i18n/base_i18n_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 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 BASE_I18N_BASE_I18N_EXPORT_H_
+#define BASE_I18N_BASE_I18N_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(BASE_I18N_IMPLEMENTATION)
+#define BASE_I18N_EXPORT __declspec(dllexport)
+#else
+#define BASE_I18N_EXPORT __declspec(dllimport)
+#endif // defined(BASE_I18N_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(BASE_I18N_IMPLEMENTATION)
+#define BASE_I18N_EXPORT __attribute__((visibility("default")))
+#else
+#define BASE_I18N_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define BASE_I18N_EXPORT
+#endif
+
+#endif // BASE_I18N_BASE_I18N_EXPORT_H_
diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h
new file mode 100644
index 0000000..df15cd0
--- /dev/null
+++ b/base/i18n/rtl.h
@@ -0,0 +1,155 @@
+// Copyright (c) 2011 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 BASE_I18N_RTL_H_
+#define BASE_I18N_RTL_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class FilePath;
+
+namespace i18n {
+
+const char16 kRightToLeftMark = 0x200F;
+const char16 kLeftToRightMark = 0x200E;
+const char16 kLeftToRightEmbeddingMark = 0x202A;
+const char16 kRightToLeftEmbeddingMark = 0x202B;
+const char16 kPopDirectionalFormatting = 0x202C;
+const char16 kLeftToRightOverride = 0x202D;
+const char16 kRightToLeftOverride = 0x202E;
+
+// Locale.java mirrored this enum TextDirection. Please keep in sync.
+enum TextDirection {
+ UNKNOWN_DIRECTION = 0,
+ RIGHT_TO_LEFT = 1,
+ LEFT_TO_RIGHT = 2,
+ TEXT_DIRECTION_MAX = LEFT_TO_RIGHT,
+};
+
+// Get the locale that the currently running process has been configured to use.
+// The return value is of the form language[-country] (e.g., en-US) where the
+// language is the 2 or 3 letter code from ISO-639.
+BASE_I18N_EXPORT std::string GetConfiguredLocale();
+
+// Canonicalize a string (eg. a POSIX locale string) to a Chrome locale name.
+BASE_I18N_EXPORT std::string GetCanonicalLocale(const std::string& locale);
+
+// Sets the default locale of ICU.
+// Once the application locale of Chrome in GetApplicationLocale is determined,
+// the default locale of ICU need to be changed to match the application locale
+// so that ICU functions work correctly in a locale-dependent manner.
+// This is handy in that we don't have to call GetApplicationLocale()
+// everytime we call locale-dependent ICU APIs as long as we make sure
+// that this is called before any locale-dependent API is called.
+BASE_I18N_EXPORT void SetICUDefaultLocale(const std::string& locale_string);
+
+// Returns true if the application text direction is right-to-left.
+BASE_I18N_EXPORT bool IsRTL();
+
+// Returns whether the text direction for the default ICU locale is RTL. This
+// assumes that SetICUDefaultLocale has been called to set the default locale to
+// the UI locale of Chrome.
+// NOTE: Generally, you should call IsRTL() instead of this.
+BASE_I18N_EXPORT bool ICUIsRTL();
+
+// Returns the text direction for |locale_name|.
+// As a startup optimization, this method checks the locale against a list of
+// Chrome-supported RTL locales.
+BASE_I18N_EXPORT TextDirection
+GetTextDirectionForLocaleInStartUp(const char* locale_name);
+
+// Returns the text direction for |locale_name|.
+BASE_I18N_EXPORT TextDirection GetTextDirectionForLocale(
+ const char* locale_name);
+
+// Given the string in |text|, returns the directionality of the first or last
+// character with strong directionality in the string. If no character in the
+// text has strong directionality, LEFT_TO_RIGHT is returned. The Bidi
+// character types L, LRE, LRO, R, AL, RLE, and RLO are considered as strong
+// directionality characters. Please refer to http://unicode.org/reports/tr9/
+// for more information.
+BASE_I18N_EXPORT TextDirection GetFirstStrongCharacterDirection(
+ const string16& text);
+BASE_I18N_EXPORT TextDirection GetLastStrongCharacterDirection(
+ const string16& text);
+
+// Given the string in |text|, returns LEFT_TO_RIGHT or RIGHT_TO_LEFT if all the
+// strong directionality characters in the string are of the same
+// directionality. It returns UNKNOWN_DIRECTION if the string contains a mix of
+// LTR and RTL strong directionality characters. Defaults to LEFT_TO_RIGHT if
+// the string does not contain directionality characters. Please refer to
+// http://unicode.org/reports/tr9/ for more information.
+BASE_I18N_EXPORT TextDirection GetStringDirection(const string16& text);
+
+// Given the string in |text|, this function modifies the string in place with
+// the appropriate Unicode formatting marks that mark the string direction
+// (either left-to-right or right-to-left). The function checks both the current
+// locale and the contents of the string in order to determine the direction of
+// the returned string. The function returns true if the string in |text| was
+// properly adjusted.
+//
+// Certain LTR strings are not rendered correctly when the context is RTL. For
+// example, the string "Foo!" will appear as "!Foo" if it is rendered as is in
+// an RTL context. Calling this function will make sure the returned localized
+// string is always treated as a right-to-left string. This is done by
+// inserting certain Unicode formatting marks into the returned string.
+//
+// ** Notes about the Windows version of this function:
+// TODO(idana) bug 6806: this function adjusts the string in question only
+// if the current locale is right-to-left. The function does not take care of
+// the opposite case (an RTL string displayed in an LTR context) since
+// adjusting the string involves inserting Unicode formatting characters that
+// Windows does not handle well unless right-to-left language support is
+// installed. Since the English version of Windows doesn't have right-to-left
+// language support installed by default, inserting the direction Unicode mark
+// results in Windows displaying squares.
+BASE_I18N_EXPORT bool AdjustStringForLocaleDirection(string16* text);
+
+// Undoes the actions of the above function (AdjustStringForLocaleDirection).
+BASE_I18N_EXPORT bool UnadjustStringForLocaleDirection(string16* text);
+
+// Returns true if the string contains at least one character with strong right
+// to left directionality; that is, a character with either R or AL Unicode
+// BiDi character type.
+BASE_I18N_EXPORT bool StringContainsStrongRTLChars(const string16& text);
+
+// Wraps a string with an LRE-PDF pair which essentialy marks the string as a
+// Left-To-Right string. Doing this is useful in order to make sure LTR
+// strings are rendered properly in an RTL context.
+BASE_I18N_EXPORT void WrapStringWithLTRFormatting(string16* text);
+
+// Wraps a string with an RLE-PDF pair which essentialy marks the string as a
+// Right-To-Left string. Doing this is useful in order to make sure RTL
+// strings are rendered properly in an LTR context.
+BASE_I18N_EXPORT void WrapStringWithRTLFormatting(string16* text);
+
+// Wraps file path to get it to display correctly in RTL UI. All filepaths
+// should be passed through this function before display in UI for RTL locales.
+BASE_I18N_EXPORT void WrapPathWithLTRFormatting(const FilePath& path,
+ string16* rtl_safe_path);
+
+// Return the string in |text| wrapped with LRE (Left-To-Right Embedding) and
+// PDF (Pop Directional Formatting) marks, if needed for UI display purposes.
+BASE_I18N_EXPORT string16 GetDisplayStringInLTRDirectionality(
+ const string16& text) WARN_UNUSED_RESULT;
+
+// Strip the beginning (U+202A..U+202B, U+202D..U+202E) and/or ending (U+202C)
+// explicit bidi control characters from |text|, if there are any. Otherwise,
+// return the text itself. Explicit bidi control characters display and have
+// semantic effect. They can be deleted so they might not always appear in a
+// pair.
+BASE_I18N_EXPORT string16 StripWrappingBidiControlCharacters(
+ const string16& text) WARN_UNUSED_RESULT;
+
+} // namespace i18n
+} // namespace base
+
+#endif // BASE_I18N_RTL_H_
diff --git a/base/message_loop/message_pump_android.cc b/base/message_loop/message_pump_android.cc
index a0eee12..bedb205 100644
--- a/base/message_loop/message_pump_android.cc
+++ b/base/message_loop/message_pump_android.cc
@@ -6,14 +6,17 @@
#include <jni.h>
+#include "base/android/java_message_handler_factory.h"
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/time/time.h"
#include "jni/SystemMessageHandler_jni.h"
+using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
// ----------------------------------------------------------------------------
@@ -24,10 +27,14 @@ using base::android::ScopedJavaLocalRef;
static void DoRunLoopOnce(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong native_delegate,
+ jlong native_message_pump,
jlong delayed_scheduled_time_ticks) {
base::MessagePump::Delegate* delegate =
reinterpret_cast<base::MessagePump::Delegate*>(native_delegate);
DCHECK(delegate);
+ base::MessagePumpForUI* pump =
+ reinterpret_cast<base::MessagePumpForUI*>(native_message_pump);
+ DCHECK(pump);
// This is based on MessagePumpForUI::DoRunLoop() from desktop.
// Note however that our system queue is handled in the java side.
// In desktop we inspect and process a single system message and then
@@ -35,6 +42,11 @@ static void DoRunLoopOnce(JNIEnv* env,
// On Android, the java message queue may contain messages for other handlers
// that will be processed before calling here again.
bool did_work = delegate->DoWork();
+ if (pump->ShouldAbort()) {
+ // There is a pending JNI exception, return to Java so that the exception is
+ // thrown correctly.
+ return;
+ }
// In the java side, |SystemMessageHandler| keeps a single "delayed" message.
// It's an expensive operation to |removeMessage| there, so this is optimized
@@ -60,6 +72,11 @@ static void DoRunLoopOnce(JNIEnv* env,
// avoid comparisons with TimeDelta / Now() (expensive).
base::TimeTicks next_delayed_work_time;
did_work |= delegate->DoDelayedWork(&next_delayed_work_time);
+ if (pump->ShouldAbort()) {
+ // There is a pending JNI exception, return to Java so that the exception is
+ // thrown correctly
+ return;
+ }
if (!next_delayed_work_time.is_null()) {
// Schedule a new message if there's nothing already scheduled or there's a
@@ -81,13 +98,16 @@ static void DoRunLoopOnce(JNIEnv* env,
return;
delegate->DoIdleWork();
+ // Note that we do not check whether we should abort here since we are
+ // returning to the JVM anyway. If, in the future, we add any more code after
+ // the call to DoIdleWork() here, we should add an abort-check and return
+ // immediately if the check passes.
}
namespace base {
MessagePumpForUI::MessagePumpForUI()
- : run_loop_(NULL) {
-}
+ : run_loop_(nullptr), should_abort_(false) {}
MessagePumpForUI::~MessagePumpForUI() {
}
@@ -97,7 +117,7 @@ void MessagePumpForUI::Run(Delegate* delegate) {
" test_stub_android.h";
}
-void MessagePumpForUI::Start(Delegate* delegate) {
+JNIEnv* MessagePumpForUI::StartInternal() {
run_loop_ = new RunLoop();
// Since the RunLoop was just created above, BeforeRun should be guaranteed to
// return true (it only returns false if the RunLoop has been Quit already).
@@ -108,10 +128,23 @@ void MessagePumpForUI::Start(Delegate* delegate) {
JNIEnv* env = base::android::AttachCurrentThread();
DCHECK(env);
+ return env;
+}
+
+void MessagePumpForUI::Start(Delegate* delegate) {
+ JNIEnv* env = StartInternal();
+ system_message_handler_obj_.Reset(Java_SystemMessageHandler_create(
+ env, reinterpret_cast<intptr_t>(delegate),
+ reinterpret_cast<intptr_t>(this)));
+}
+void MessagePumpForUI::StartForUnitTest(
+ Delegate* delegate,
+ base::android::JavaMessageHandlerFactory* factory,
+ WaitableEvent* test_done_event) {
+ JNIEnv* env = StartInternal();
system_message_handler_obj_.Reset(
- Java_SystemMessageHandler_create(
- env, reinterpret_cast<intptr_t>(delegate)));
+ factory->CreateMessageHandler(env, delegate, this, test_done_event));
}
void MessagePumpForUI::Quit() {
@@ -119,8 +152,8 @@ void MessagePumpForUI::Quit() {
JNIEnv* env = base::android::AttachCurrentThread();
DCHECK(env);
- Java_SystemMessageHandler_removeAllPendingMessages(env,
- system_message_handler_obj_.obj());
+ Java_SystemMessageHandler_removeAllPendingMessages(
+ env, system_message_handler_obj_);
system_message_handler_obj_.Reset();
}
@@ -137,8 +170,7 @@ void MessagePumpForUI::ScheduleWork() {
JNIEnv* env = base::android::AttachCurrentThread();
DCHECK(env);
- Java_SystemMessageHandler_scheduleWork(env,
- system_message_handler_obj_.obj());
+ Java_SystemMessageHandler_scheduleWork(env, system_message_handler_obj_);
}
void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
@@ -151,9 +183,9 @@ void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
(delayed_work_time - TimeTicks::Now()).InMillisecondsRoundedUp();
// Note that we're truncating to milliseconds as required by the java side,
// even though delayed_work_time is microseconds resolution.
- Java_SystemMessageHandler_scheduleDelayedWork(env,
- system_message_handler_obj_.obj(),
- delayed_work_time.ToInternalValue(), millis);
+ Java_SystemMessageHandler_scheduleDelayedWork(
+ env, system_message_handler_obj_, delayed_work_time.ToInternalValue(),
+ millis);
}
// static
diff --git a/base/message_loop/message_pump_android.h b/base/message_loop/message_pump_android.h
index 795bd5e..e4adaf6 100644
--- a/base/message_loop/message_pump_android.h
+++ b/base/message_loop/message_pump_android.h
@@ -15,8 +15,13 @@
namespace base {
+namespace android {
+class JavaMessageHandlerFactory;
+}
+
class RunLoop;
class TimeTicks;
+class WaitableEvent;
// This class implements a MessagePump needed for TYPE_UI MessageLoops on
// OS_ANDROID platform.
@@ -31,12 +36,25 @@ class BASE_EXPORT MessagePumpForUI : public MessagePump {
void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
virtual void Start(Delegate* delegate);
+ void StartForUnitTest(Delegate* delegate,
+ base::android::JavaMessageHandlerFactory* factory,
+ WaitableEvent* test_done_event);
+
+ // We call Abort when there is a pending JNI exception, meaning that the
+ // current thread will crash when we return to Java.
+ // We can't call any JNI-methods before returning to Java as we would then
+ // cause a native crash (instead of the original Java crash).
+ void Abort() { should_abort_ = true; }
+ bool ShouldAbort() const { return should_abort_; }
static bool RegisterBindings(JNIEnv* env);
private:
+ JNIEnv* StartInternal();
+
RunLoop* run_loop_;
base::android::ScopedJavaGlobalRef<jobject> system_message_handler_obj_;
+ bool should_abort_;
DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI);
};
diff --git a/base/path_service.cc b/base/path_service.cc
index 3f954d7..1b9d394 100644
--- a/base/path_service.cc
+++ b/base/path_service.cc
@@ -13,7 +13,6 @@
#include "base/containers/hash_tables.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
-#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/synchronization/lock.h"
#include "build/build_config.h"
@@ -129,10 +128,9 @@ struct PathData {
}
};
-static LazyInstance<PathData>::Leaky g_path_data = LAZY_INSTANCE_INITIALIZER;
-
static PathData* GetPathData() {
- return g_path_data.Pointer();
+ static auto* path_data = new PathData();
+ return path_data;
}
// Tries to find |key| in the cache. |path_data| should be locked by the caller!
diff --git a/base/threading/thread_local_android.cc b/base/threading/thread_local_android.cc
deleted file mode 100644
index 813dd78..0000000
--- a/base/threading/thread_local_android.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/threading/thread_local.h"
-
-namespace base {
-namespace internal {
-
-// static
-void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
- slot->Initialize(nullptr);
-}
-
-// static
-void ThreadLocalPlatform::FreeSlot(SlotType slot) {
- slot.Free();
-}
-
-// static
-void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
- return slot.Get();
-}
-
-// static
-void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
- slot.Set(value);
-}
-
-} // namespace internal
-} // namespace base
diff --git a/base/trace_event/trace_event_android.cc b/base/trace_event/trace_event_android.cc
index a28c54a..0a4e6ea 100644
--- a/base/trace_event/trace_event_android.cc
+++ b/base/trace_event/trace_event_android.cc
@@ -13,6 +13,7 @@
#include "base/posix/eintr_wrapper.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
#include "base/trace_event/trace_event.h"
namespace base {
diff --git a/base/unguessable_token.cc b/base/unguessable_token.cc
new file mode 100644
index 0000000..cd9830e
--- /dev/null
+++ b/base/unguessable_token.cc
@@ -0,0 +1,41 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/unguessable_token.h"
+
+#include "base/format_macros.h"
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+
+UnguessableToken::UnguessableToken(uint64_t high, uint64_t low)
+ : high_(high), low_(low) {}
+
+std::string UnguessableToken::ToString() const {
+ return base::StringPrintf("(%08" PRIX64 "%08" PRIX64 ")", high_, low_);
+}
+
+// static
+UnguessableToken UnguessableToken::Create() {
+ UnguessableToken token;
+ // Use base::RandBytes instead of crypto::RandBytes, because crypto calls the
+ // base version directly, and to prevent the dependency from base/ to crypto/.
+ base::RandBytes(&token, sizeof(token));
+ return token;
+}
+
+// static
+UnguessableToken UnguessableToken::Deserialize(uint64_t high, uint64_t low) {
+ // Receiving a zeroed out UnguessableToken from another process means that it
+ // was never initialized via Create(). Treat this case as a security issue.
+ DCHECK(!(high == 0 && low == 0));
+ return UnguessableToken(high, low);
+}
+
+std::ostream& operator<<(std::ostream& out, const UnguessableToken& token) {
+ return out << token.ToString();
+}
+
+} // namespace base
diff --git a/base/unguessable_token.h b/base/unguessable_token.h
new file mode 100644
index 0000000..9f38783
--- /dev/null
+++ b/base/unguessable_token.h
@@ -0,0 +1,103 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_UNGUESSABLE_TOKEN_H_
+#define BASE_UNGUESSABLE_TOKEN_H_
+
+#include <stdint.h>
+#include <string.h>
+#include <iosfwd>
+#include <tuple>
+
+#include "base/base_export.h"
+#include "base/hash.h"
+#include "base/logging.h"
+
+namespace base {
+
+struct UnguessableTokenHash;
+
+// A UnguessableToken is an 128-bit token generated from a cryptographically
+// strong random source.
+//
+// UnguessableToken should be used when a sensitive ID needs to be unguessable,
+// and is shared across processes. It can be used as part of a larger aggregate
+// type, or as an ID in and of itself.
+//
+// Use Create() for creating new UnguessableTokens.
+//
+// NOTE: It is illegal to send empty UnguessableTokens across processes, and
+// sending/receiving empty tokens should be treated as a security issue.
+// If there is a valid scenario for sending "no token" across processes,
+// base::Optional should be used instead of an empty token.
+class BASE_EXPORT UnguessableToken {
+ public:
+ // Create a unique UnguessableToken.
+ static UnguessableToken Create();
+
+ // Return a UnguessableToken built from the high/low bytes provided.
+ // It should only be used in deserialization scenarios.
+ //
+ // NOTE: If the deserialized token is empty, it means that it was never
+ // initialized via Create(). This is a security issue, and should be handled.
+ static UnguessableToken Deserialize(uint64_t high, uint64_t low);
+
+ // Creates an empty UnguessableToken.
+ // Assign to it with Create() before using it.
+ constexpr UnguessableToken() = default;
+
+ // NOTE: Serializing an empty UnguessableToken is an illegal operation.
+ uint64_t GetHighForSerialization() const {
+ DCHECK(!is_empty());
+ return high_;
+ };
+
+ // NOTE: Serializing an empty UnguessableToken is an illegal operation.
+ uint64_t GetLowForSerialization() const {
+ DCHECK(!is_empty());
+ return low_;
+ }
+
+ bool is_empty() const { return high_ == 0 && low_ == 0; }
+
+ std::string ToString() const;
+
+ explicit operator bool() const { return !is_empty(); }
+
+ bool operator<(const UnguessableToken& other) const {
+ return std::tie(high_, low_) < std::tie(other.high_, other.low_);
+ }
+
+ bool operator==(const UnguessableToken& other) const {
+ return high_ == other.high_ && low_ == other.low_;
+ }
+
+ bool operator!=(const UnguessableToken& other) const {
+ return !(*this == other);
+ }
+
+ private:
+ friend struct UnguessableTokenHash;
+ UnguessableToken(uint64_t high, uint64_t low);
+
+ // Note: Two uint64_t are used instead of uint8_t[16], in order to have a
+ // simpler ToString() and is_empty().
+ uint64_t high_ = 0;
+ uint64_t low_ = 0;
+};
+
+BASE_EXPORT std::ostream& operator<<(std::ostream& out,
+ const UnguessableToken& token);
+
+// For use in std::unordered_map.
+struct UnguessableTokenHash {
+ size_t operator()(const base::UnguessableToken& token) const {
+ DCHECK(token);
+ return base::HashInts64(token.high_, token.low_);
+ }
+};
+
+} // namespace base
+
+#endif // BASE_UNGUESSABLE_TOKEN_H_
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
index 371ad90..7b2f48d 100644
--- a/build/android/gyp/util/build_utils.py
+++ b/build/android/gyp/util/build_utils.py
@@ -23,12 +23,16 @@ import md5_check # pylint: disable=relative-import
sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
from pylib.constants import host_paths
+sys.path.append(os.path.join(os.path.dirname(__file__),
+ os.pardir, os.pardir, os.pardir))
+import gn_helpers
+
COLORAMA_ROOT = os.path.join(host_paths.DIR_SOURCE_ROOT,
'third_party', 'colorama', 'src')
# aapt should ignore OWNERS files in addition the default ignore pattern.
AAPT_IGNORE_PATTERN = ('!OWNERS:!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:' +
'!CVS:!thumbs.db:!picasa.ini:!*~:!*.d.stamp')
-_HERMETIC_TIMESTAMP = (2001, 1, 1, 0, 0, 0)
+HERMETIC_TIMESTAMP = (2001, 1, 1, 0, 0, 0)
_HERMETIC_FILE_ATTR = (0644 << 16L)
@@ -78,31 +82,23 @@ def FindInDirectories(directories, filename_filter):
def ParseGnList(gn_string):
- # TODO(brettw) bug 573132: This doesn't handle GN escaping properly, so any
- # weird characters like $ or \ in the strings will be corrupted.
- #
- # The code should import build/gn_helpers.py and then do:
- # parser = gn_helpers.GNValueParser(gn_string)
- # return return parser.ParseList()
- # As of this writing, though, there is a CastShell build script that sends
- # JSON through this function, and using correct GN parsing corrupts that.
- #
- # We need to be consistent about passing either JSON or GN lists through
- # this function.
- return ast.literal_eval(gn_string)
-
-
-def ParseGypList(gyp_string):
- # The ninja generator doesn't support $ in strings, so use ## to
- # represent $.
- # TODO(cjhopman): Remove when
- # https://code.google.com/p/gyp/issues/detail?id=327
- # is addressed.
- gyp_string = gyp_string.replace('##', '$')
-
- if gyp_string.startswith('['):
- return ParseGnList(gyp_string)
- return shlex.split(gyp_string)
+ """Converts a command-line parameter into a list.
+
+ If the input starts with a '[' it is assumed to be a GN-formatted list and
+ it will be parsed accordingly. When empty an empty list will be returned.
+ Otherwise, the parameter will be treated as a single raw string (not
+ GN-formatted in that it's not assumed to have literal quotes that must be
+ removed) and a list will be returned containing that string.
+
+ The common use for this behavior is in the Android build where things can
+ take lists of @FileArg references that are expanded via ExpandFileArgs.
+ """
+ if gn_string.startswith('['):
+ parser = gn_helpers.GNValueParser(gn_string)
+ return parser.ParseList()
+ if len(gn_string):
+ return [ gn_string ]
+ return []
def CheckOptions(options, parser, required=None):
@@ -228,6 +224,7 @@ def ExtractAll(zip_path, path=None, no_clobber=True, pattern=None,
if not zipfile.is_zipfile(zip_path):
raise Exception('Invalid zip file: %s' % zip_path)
+ extracted = []
with zipfile.ZipFile(zip_path) as z:
for name in z.namelist():
if name.endswith('/'):
@@ -248,8 +245,12 @@ def ExtractAll(zip_path, path=None, no_clobber=True, pattern=None,
dest = os.path.join(path, name)
MakeDirectory(os.path.dirname(dest))
os.symlink(z.read(name), dest)
+ extracted.append(dest)
else:
z.extract(name, path)
+ extracted.append(os.path.join(path, name))
+
+ return extracted
def AddToZipHermetic(zip_file, zip_path, src_path=None, data=None,
@@ -267,7 +268,7 @@ def AddToZipHermetic(zip_file, zip_path, src_path=None, data=None,
assert (src_path is None) != (data is None), (
'|src_path| and |data| are mutually exclusive.')
CheckZipPath(zip_path)
- zipinfo = zipfile.ZipInfo(filename=zip_path, date_time=_HERMETIC_TIMESTAMP)
+ zipinfo = zipfile.ZipInfo(filename=zip_path, date_time=HERMETIC_TIMESTAMP)
zipinfo.external_attr = _HERMETIC_FILE_ATTR
if src_path and os.path.islink(src_path):
@@ -332,7 +333,14 @@ def MergeZips(output, inputs, exclude_patterns=None, path_transform=None):
path_transform = path_transform or (lambda p, z: p)
added_names = set()
- with zipfile.ZipFile(output, 'w') as out_zip:
+ output_is_already_open = not isinstance(output, basestring)
+ if output_is_already_open:
+ assert isinstance(output, zipfile.ZipFile)
+ out_zip = output
+ else:
+ out_zip = zipfile.ZipFile(output, 'w')
+
+ try:
for in_file in inputs:
with zipfile.ZipFile(in_file, 'r') as in_zip:
in_zip._expected_crc = None
@@ -343,8 +351,12 @@ def MergeZips(output, inputs, exclude_patterns=None, path_transform=None):
dst_name = path_transform(info.filename, in_file)
already_added = dst_name in added_names
if not already_added and not MatchesGlob(dst_name, exclude_patterns):
- AddToZipHermetic(out_zip, dst_name, data=in_zip.read(info))
+ AddToZipHermetic(out_zip, dst_name, data=in_zip.read(info),
+ compress=info.compress_type != zipfile.ZIP_STORED)
added_names.add(dst_name)
+ finally:
+ if not output_is_already_open:
+ out_zip.close()
def PrintWarning(message):
@@ -399,8 +411,7 @@ def GetPythonDependencies():
A path is assumed to be a "system" import if it is outside of chromium's
src/. The paths will be relative to the current directory.
"""
- module_paths = (m.__file__ for m in sys.modules.itervalues()
- if m is not None and hasattr(m, '__file__'))
+ module_paths = GetModulePaths()
abs_module_paths = map(os.path.abspath, module_paths)
@@ -417,6 +428,30 @@ def GetPythonDependencies():
return sorted(set(non_system_module_paths))
+def GetModulePaths():
+ """Returns the paths to all of the modules in sys.modules."""
+ ForceLazyModulesToLoad()
+ return (m.__file__ for m in sys.modules.itervalues()
+ if m is not None and hasattr(m, '__file__'))
+
+
+def ForceLazyModulesToLoad():
+ """Forces any lazily imported modules to fully load themselves.
+
+ Inspecting the modules' __file__ attribute causes lazily imported modules
+ (e.g. from email) to get fully imported and update sys.modules. Iterate
+ over the values until sys.modules stabilizes so that no modules are missed.
+ """
+ while True:
+ num_modules_before = len(sys.modules.keys())
+ for m in sys.modules.values():
+ if m is not None and hasattr(m, '__file__'):
+ _ = m.__file__
+ num_modules_after = len(sys.modules.keys())
+ if num_modules_before == num_modules_after:
+ break
+
+
def AddDepfileOption(parser):
# TODO(agrieve): Get rid of this once we've moved to argparse.
if hasattr(parser, 'add_option'):
@@ -424,14 +459,20 @@ def AddDepfileOption(parser):
else:
func = parser.add_argument
func('--depfile',
- help='Path to depfile. Must be specified as the action\'s first output.')
-
-
-def WriteDepfile(path, dependencies):
- with open(path, 'w') as depfile:
- depfile.write(path)
+ help='Path to depfile (refer to `gn help depfile`)')
+
+
+def WriteDepfile(depfile_path, first_gn_output, inputs=None, add_pydeps=True):
+ assert depfile_path != first_gn_output # http://crbug.com/646165
+ inputs = inputs or []
+ if add_pydeps:
+ inputs = GetPythonDependencies() + inputs
+ MakeDirectory(os.path.dirname(depfile_path))
+ # Ninja does not support multiple outputs in depfiles.
+ with open(depfile_path, 'w') as depfile:
+ depfile.write(first_gn_output.replace(' ', '\\ '))
depfile.write(': ')
- depfile.write(' '.join(dependencies))
+ depfile.write(' '.join(i.replace(' ', '\\ ') for i in inputs))
depfile.write('\n')
@@ -469,11 +510,25 @@ def ExpandFileArgs(args):
for k in lookup_path[1:]:
expansion = expansion[k]
- new_args[i] = arg[:match.start()] + str(expansion)
+ # This should match ParseGNList. The output is either a GN-formatted list
+ # or a literal (with no quotes).
+ if isinstance(expansion, list):
+ new_args[i] = arg[:match.start()] + gn_helpers.ToGNString(expansion)
+ else:
+ new_args[i] = arg[:match.start()] + str(expansion)
return new_args
+def ReadSourcesList(sources_list_file_name):
+ """Reads a GN-written file containing list of file names and returns a list.
+
+ Note that this function should not be used to parse response files.
+ """
+ with open(sources_list_file_name) as f:
+ return [file_name.strip() for file_name in f]
+
+
def CallAndWriteDepfileIfStale(function, options, record_path=None,
input_paths=None, input_strings=None,
output_paths=None, force=False,
@@ -513,7 +568,8 @@ def CallAndWriteDepfileIfStale(function, options, record_path=None,
all_depfile_deps = list(python_deps)
if depfile_deps:
all_depfile_deps.extend(depfile_deps)
- WriteDepfile(options.depfile, all_depfile_deps)
+ WriteDepfile(options.depfile, output_paths[0], all_depfile_deps,
+ add_pydeps=False)
if stamp_file:
Touch(stamp_file)
diff --git a/build/android/pylib/__init__.py b/build/android/pylib/__init__.py
index 16ee312..b93eb4f 100644
--- a/build/android/pylib/__init__.py
+++ b/build/android/pylib/__init__.py
@@ -5,9 +5,27 @@
import os
import sys
-_DEVIL_PATH = os.path.abspath(os.path.join(
- os.path.dirname(__file__), '..', '..', '..', 'third_party', 'catapult',
- 'devil'))
+
+_CATAPULT_PATH = os.path.abspath(os.path.join(
+ os.path.dirname(__file__), '..', '..', '..', 'third_party', 'catapult'))
+
+_DEVIL_PATH = os.path.join(_CATAPULT_PATH, 'devil')
+
+_PYTRACE_PATH = os.path.join(_CATAPULT_PATH, 'common', 'py_trace_event')
+
+_PY_UTILS_PATH = os.path.join(_CATAPULT_PATH, 'common', 'py_utils')
+
+_TRACE2HTML_PATH = os.path.join(_CATAPULT_PATH, 'tracing')
+
if _DEVIL_PATH not in sys.path:
sys.path.append(_DEVIL_PATH)
+
+if _PYTRACE_PATH not in sys.path:
+ sys.path.append(_PYTRACE_PATH)
+
+if _PY_UTILS_PATH not in sys.path:
+ sys.path.append(_PY_UTILS_PATH)
+
+if _TRACE2HTML_PATH not in sys.path:
+ sys.path.append(_TRACE2HTML_PATH)
diff --git a/build/android/pylib/constants/__init__.py b/build/android/pylib/constants/__init__.py
index 9b25dcd..916ee27 100644
--- a/build/android/pylib/constants/__init__.py
+++ b/build/android/pylib/constants/__init__.py
@@ -37,28 +37,28 @@ PACKAGE_INFO.update({
'chromecast_shell': chrome.PackageInfo(
'com.google.android.apps.mediashell',
'com.google.android.apps.mediashell.MediaShellActivity',
- '/data/local/tmp/castshell-command-line',
+ 'castshell-command-line',
None),
'android_webview_shell': chrome.PackageInfo(
'org.chromium.android_webview.shell',
'org.chromium.android_webview.shell.AwShellActivity',
- '/data/local/tmp/android-webview-command-line',
+ 'android-webview-command-line',
None),
'gtest': chrome.PackageInfo(
'org.chromium.native_test',
'org.chromium.native_test.NativeUnitTestActivity',
- '/data/local/tmp/chrome-native-tests-command-line',
+ 'chrome-native-tests-command-line',
None),
'components_browsertests': chrome.PackageInfo(
'org.chromium.components_browsertests_apk',
('org.chromium.components_browsertests_apk' +
'.ComponentsBrowserTestsActivity'),
- '/data/local/tmp/chrome-native-tests-command-line',
+ 'chrome-native-tests-command-line',
None),
'content_browsertests': chrome.PackageInfo(
'org.chromium.content_browsertests_apk',
'org.chromium.content_browsertests_apk.ContentBrowserTestsActivity',
- '/data/local/tmp/chrome-native-tests-command-line',
+ 'chrome-native-tests-command-line',
None),
'chromedriver_webview_shell': chrome.PackageInfo(
'org.chromium.chromedriver_webview_shell',
@@ -96,7 +96,7 @@ DEVICE_PERF_OUTPUT_DIR = (
SCREENSHOTS_DIR = os.path.join(DIR_SOURCE_ROOT, 'out_screenshots')
ANDROID_SDK_VERSION = version_codes.MARSHMALLOW
-ANDROID_SDK_BUILD_TOOLS_VERSION = '23.0.1'
+ANDROID_SDK_BUILD_TOOLS_VERSION = '24.0.2'
ANDROID_SDK_ROOT = os.path.join(DIR_SOURCE_ROOT,
'third_party', 'android_tools', 'sdk')
ANDROID_SDK_TOOLS = os.path.join(ANDROID_SDK_ROOT,
@@ -140,9 +140,9 @@ PYTHON_UNIT_TEST_SUITES = {
}
LOCAL_MACHINE_TESTS = ['junit', 'python']
-VALID_ENVIRONMENTS = ['local', 'remote_device']
+VALID_ENVIRONMENTS = ['local']
VALID_TEST_TYPES = ['gtest', 'instrumentation', 'junit', 'linker', 'monkey',
- 'perf', 'python', 'uirobot']
+ 'perf', 'python']
VALID_DEVICE_TYPES = ['Android', 'iOS']
diff --git a/build/build_config.h b/build/build_config.h
index c3d82d0..fd5489f 100644
--- a/build/build_config.h
+++ b/build/build_config.h
@@ -6,6 +6,7 @@
// Operating System:
// OS_WIN / OS_MACOSX / OS_LINUX / OS_POSIX (MACOSX or LINUX) /
// OS_NACL (NACL_SFI or NACL_NONSFI) / OS_NACL_SFI / OS_NACL_NONSFI
+// OS_CHROMEOS is set by the build system
// Compiler:
// COMPILER_MSVC / COMPILER_GCC
// Processor:
@@ -48,9 +49,10 @@
#endif
#elif defined(_WIN32)
#define OS_WIN 1
-#define TOOLKIT_VIEWS 1
#elif defined(__FreeBSD__)
#define OS_FREEBSD 1
+#elif defined(__NetBSD__)
+#define OS_NETBSD 1
#elif defined(__OpenBSD__)
#define OS_OPENBSD 1
#elif defined(__sun)
@@ -67,15 +69,16 @@
// For access to standard BSD features, use OS_BSD instead of a
// more specific macro.
-#if defined(OS_FREEBSD) || defined(OS_OPENBSD)
+#if defined(OS_FREEBSD) || defined(OS_NETBSD) || defined(OS_OPENBSD)
#define OS_BSD 1
#endif
// For access to standard POSIXish features, use OS_POSIX instead of a
// more specific macro.
#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_FREEBSD) || \
- defined(OS_OPENBSD) || defined(OS_SOLARIS) || defined(OS_ANDROID) || \
- defined(OS_NACL) || defined(OS_QNX)
+ defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_SOLARIS) || \
+ defined(OS_ANDROID) || defined(OS_OPENBSD) || defined(OS_SOLARIS) || \
+ defined(OS_ANDROID) || defined(OS_NACL) || defined(OS_QNX)
#define OS_POSIX 1
#endif
@@ -108,6 +111,31 @@
#define ARCH_CPU_X86 1
#define ARCH_CPU_32_BITS 1
#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__s390x__)
+#define ARCH_CPU_S390_FAMILY 1
+#define ARCH_CPU_S390X 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_BIG_ENDIAN 1
+#elif defined(__s390__)
+#define ARCH_CPU_S390_FAMILY 1
+#define ARCH_CPU_S390 1
+#define ARCH_CPU_31_BITS 1
+#define ARCH_CPU_BIG_ENDIAN 1
+#elif defined(__PPC64__) && defined(__BIG_ENDIAN__)
+#define ARCH_CPU_PPC64_FAMILY 1
+#define ARCH_CPU_PPC64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_BIG_ENDIAN 1
+#elif defined(__PPC64__) && defined(__LITTLE_ENDIAN__)
+#define ARCH_CPU_PPC64_FAMILY 1
+#define ARCH_CPU_PPC64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__PPC__)
+#define ARCH_CPU_PPC_FAMILY 1
+#define ARCH_CPU_PPC 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_BIG_ENDIAN 1
#elif defined(__ARMEL__)
#define ARCH_CPU_ARM_FAMILY 1
#define ARCH_CPU_ARMEL 1
diff --git a/build/gn_helpers.py b/build/gn_helpers.py
new file mode 100644
index 0000000..33cc578
--- /dev/null
+++ b/build/gn_helpers.py
@@ -0,0 +1,351 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Helper functions useful when writing scripts that integrate with GN.
+
+The main functions are ToGNString and FromGNString which convert between
+serialized GN veriables and Python variables.
+
+To use in a random python file in the build:
+
+ import os
+ import sys
+
+ sys.path.append(os.path.join(os.path.dirname(__file__),
+ os.pardir, os.pardir, "build"))
+ import gn_helpers
+
+Where the sequence of parameters to join is the relative path from your source
+file to the build directory."""
+
+class GNException(Exception):
+ pass
+
+
+def ToGNString(value, allow_dicts = True):
+ """Returns a stringified GN equivalent of the Python value.
+
+ allow_dicts indicates if this function will allow converting dictionaries
+ to GN scopes. This is only possible at the top level, you can't nest a
+ GN scope in a list, so this should be set to False for recursive calls."""
+ if isinstance(value, basestring):
+ if value.find('\n') >= 0:
+ raise GNException("Trying to print a string with a newline in it.")
+ return '"' + \
+ value.replace('\\', '\\\\').replace('"', '\\"').replace('$', '\\$') + \
+ '"'
+
+ if isinstance(value, unicode):
+ return ToGNString(value.encode('utf-8'))
+
+ if isinstance(value, bool):
+ if value:
+ return "true"
+ return "false"
+
+ if isinstance(value, list):
+ return '[ %s ]' % ', '.join(ToGNString(v) for v in value)
+
+ if isinstance(value, dict):
+ if not allow_dicts:
+ raise GNException("Attempting to recursively print a dictionary.")
+ result = ""
+ for key in sorted(value):
+ if not isinstance(key, basestring):
+ raise GNException("Dictionary key is not a string.")
+ result += "%s = %s\n" % (key, ToGNString(value[key], False))
+ return result
+
+ if isinstance(value, int):
+ return str(value)
+
+ raise GNException("Unsupported type when printing to GN.")
+
+
+def FromGNString(input_string):
+ """Converts the input string from a GN serialized value to Python values.
+
+ For details on supported types see GNValueParser.Parse() below.
+
+ If your GN script did:
+ something = [ "file1", "file2" ]
+ args = [ "--values=$something" ]
+ The command line would look something like:
+ --values="[ \"file1\", \"file2\" ]"
+ Which when interpreted as a command line gives the value:
+ [ "file1", "file2" ]
+
+ You can parse this into a Python list using GN rules with:
+ input_values = FromGNValues(options.values)
+ Although the Python 'ast' module will parse many forms of such input, it
+ will not handle GN escaping properly, nor GN booleans. You should use this
+ function instead.
+
+
+ A NOTE ON STRING HANDLING:
+
+ If you just pass a string on the command line to your Python script, or use
+ string interpolation on a string variable, the strings will not be quoted:
+ str = "asdf"
+ args = [ str, "--value=$str" ]
+ Will yield the command line:
+ asdf --value=asdf
+ The unquoted asdf string will not be valid input to this function, which
+ accepts only quoted strings like GN scripts. In such cases, you can just use
+ the Python string literal directly.
+
+ The main use cases for this is for other types, in particular lists. When
+ using string interpolation on a list (as in the top example) the embedded
+ strings will be quoted and escaped according to GN rules so the list can be
+ re-parsed to get the same result."""
+ parser = GNValueParser(input_string)
+ return parser.Parse()
+
+
+def FromGNArgs(input_string):
+ """Converts a string with a bunch of gn arg assignments into a Python dict.
+
+ Given a whitespace-separated list of
+
+ <ident> = (integer | string | boolean | <list of the former>)
+
+ gn assignments, this returns a Python dict, i.e.:
+
+ FromGNArgs("foo=true\nbar=1\n") -> { 'foo': True, 'bar': 1 }.
+
+ Only simple types and lists supported; variables, structs, calls
+ and other, more complicated things are not.
+
+ This routine is meant to handle only the simple sorts of values that
+ arise in parsing --args.
+ """
+ parser = GNValueParser(input_string)
+ return parser.ParseArgs()
+
+
+def UnescapeGNString(value):
+ """Given a string with GN escaping, returns the unescaped string.
+
+ Be careful not to feed with input from a Python parsing function like
+ 'ast' because it will do Python unescaping, which will be incorrect when
+ fed into the GN unescaper."""
+ result = ''
+ i = 0
+ while i < len(value):
+ if value[i] == '\\':
+ if i < len(value) - 1:
+ next_char = value[i + 1]
+ if next_char in ('$', '"', '\\'):
+ # These are the escaped characters GN supports.
+ result += next_char
+ i += 1
+ else:
+ # Any other backslash is a literal.
+ result += '\\'
+ else:
+ result += value[i]
+ i += 1
+ return result
+
+
+def _IsDigitOrMinus(char):
+ return char in "-0123456789"
+
+
+class GNValueParser(object):
+ """Duplicates GN parsing of values and converts to Python types.
+
+ Normally you would use the wrapper function FromGNValue() below.
+
+ If you expect input as a specific type, you can also call one of the Parse*
+ functions directly. All functions throw GNException on invalid input. """
+ def __init__(self, string):
+ self.input = string
+ self.cur = 0
+
+ def IsDone(self):
+ return self.cur == len(self.input)
+
+ def ConsumeWhitespace(self):
+ while not self.IsDone() and self.input[self.cur] in ' \t\n':
+ self.cur += 1
+
+ def Parse(self):
+ """Converts a string representing a printed GN value to the Python type.
+
+ See additional usage notes on FromGNString above.
+
+ - GN booleans ('true', 'false') will be converted to Python booleans.
+
+ - GN numbers ('123') will be converted to Python numbers.
+
+ - GN strings (double-quoted as in '"asdf"') will be converted to Python
+ strings with GN escaping rules. GN string interpolation (embedded
+ variables preceeded by $) are not supported and will be returned as
+ literals.
+
+ - GN lists ('[1, "asdf", 3]') will be converted to Python lists.
+
+ - GN scopes ('{ ... }') are not supported."""
+ result = self._ParseAllowTrailing()
+ self.ConsumeWhitespace()
+ if not self.IsDone():
+ raise GNException("Trailing input after parsing:\n " +
+ self.input[self.cur:])
+ return result
+
+ def ParseArgs(self):
+ """Converts a whitespace-separated list of ident=literals to a dict.
+
+ See additional usage notes on FromGNArgs, above.
+ """
+ d = {}
+
+ self.ConsumeWhitespace()
+ while not self.IsDone():
+ ident = self._ParseIdent()
+ self.ConsumeWhitespace()
+ if self.input[self.cur] != '=':
+ raise GNException("Unexpected token: " + self.input[self.cur:])
+ self.cur += 1
+ self.ConsumeWhitespace()
+ val = self._ParseAllowTrailing()
+ self.ConsumeWhitespace()
+ d[ident] = val
+
+ return d
+
+ def _ParseAllowTrailing(self):
+ """Internal version of Parse that doesn't check for trailing stuff."""
+ self.ConsumeWhitespace()
+ if self.IsDone():
+ raise GNException("Expected input to parse.")
+
+ next_char = self.input[self.cur]
+ if next_char == '[':
+ return self.ParseList()
+ elif _IsDigitOrMinus(next_char):
+ return self.ParseNumber()
+ elif next_char == '"':
+ return self.ParseString()
+ elif self._ConstantFollows('true'):
+ return True
+ elif self._ConstantFollows('false'):
+ return False
+ else:
+ raise GNException("Unexpected token: " + self.input[self.cur:])
+
+ def _ParseIdent(self):
+ ident = ''
+
+ next_char = self.input[self.cur]
+ if not next_char.isalpha() and not next_char=='_':
+ raise GNException("Expected an identifier: " + self.input[self.cur:])
+
+ ident += next_char
+ self.cur += 1
+
+ next_char = self.input[self.cur]
+ while next_char.isalpha() or next_char.isdigit() or next_char=='_':
+ ident += next_char
+ self.cur += 1
+ next_char = self.input[self.cur]
+
+ return ident
+
+ def ParseNumber(self):
+ self.ConsumeWhitespace()
+ if self.IsDone():
+ raise GNException('Expected number but got nothing.')
+
+ begin = self.cur
+
+ # The first character can include a negative sign.
+ if not self.IsDone() and _IsDigitOrMinus(self.input[self.cur]):
+ self.cur += 1
+ while not self.IsDone() and self.input[self.cur].isdigit():
+ self.cur += 1
+
+ number_string = self.input[begin:self.cur]
+ if not len(number_string) or number_string == '-':
+ raise GNException("Not a valid number.")
+ return int(number_string)
+
+ def ParseString(self):
+ self.ConsumeWhitespace()
+ if self.IsDone():
+ raise GNException('Expected string but got nothing.')
+
+ if self.input[self.cur] != '"':
+ raise GNException('Expected string beginning in a " but got:\n ' +
+ self.input[self.cur:])
+ self.cur += 1 # Skip over quote.
+
+ begin = self.cur
+ while not self.IsDone() and self.input[self.cur] != '"':
+ if self.input[self.cur] == '\\':
+ self.cur += 1 # Skip over the backslash.
+ if self.IsDone():
+ raise GNException("String ends in a backslash in:\n " +
+ self.input)
+ self.cur += 1
+
+ if self.IsDone():
+ raise GNException('Unterminated string:\n ' + self.input[begin:])
+
+ end = self.cur
+ self.cur += 1 # Consume trailing ".
+
+ return UnescapeGNString(self.input[begin:end])
+
+ def ParseList(self):
+ self.ConsumeWhitespace()
+ if self.IsDone():
+ raise GNException('Expected list but got nothing.')
+
+ # Skip over opening '['.
+ if self.input[self.cur] != '[':
+ raise GNException("Expected [ for list but got:\n " +
+ self.input[self.cur:])
+ self.cur += 1
+ self.ConsumeWhitespace()
+ if self.IsDone():
+ raise GNException("Unterminated list:\n " + self.input)
+
+ list_result = []
+ previous_had_trailing_comma = True
+ while not self.IsDone():
+ if self.input[self.cur] == ']':
+ self.cur += 1 # Skip over ']'.
+ return list_result
+
+ if not previous_had_trailing_comma:
+ raise GNException("List items not separated by comma.")
+
+ list_result += [ self._ParseAllowTrailing() ]
+ self.ConsumeWhitespace()
+ if self.IsDone():
+ break
+
+ # Consume comma if there is one.
+ previous_had_trailing_comma = self.input[self.cur] == ','
+ if previous_had_trailing_comma:
+ # Consume comma.
+ self.cur += 1
+ self.ConsumeWhitespace()
+
+ raise GNException("Unterminated list:\n " + self.input)
+
+ def _ConstantFollows(self, constant):
+ """Returns true if the given constant follows immediately at the current
+ location in the input. If it does, the text is consumed and the function
+ returns true. Otherwise, returns false and the current position is
+ unchanged."""
+ end = self.cur + len(constant)
+ if end > len(self.input):
+ return False # Not enough room.
+ if self.input[self.cur:end] == constant:
+ self.cur = end
+ return True
+ return False
diff --git a/build_mojom.mk b/build_mojom.mk
index 31f252e..2af9e49 100644
--- a/build_mojom.mk
+++ b/build_mojom.mk
@@ -19,10 +19,11 @@ mojom_file := $(1)
local_path := $(LOCAL_PATH)
target_path := $(generated_sources_dir)
gen_cc := $$(target_path)/$$(mojom_file).cc
+gen_shared_cc := $$(target_path)/$$(mojom_file)-shared.cc
gen_h := $$(target_path)/$$(mojom_file).h
gen_internal_h := $$(target_path)/$$(mojom_file)-internal.h
gen_srcjar := $$(target_path)/$$(mojom_file).srcjar
-gen_src := $$(gen_cc) $$(gen_h) $$(gen_internal_h) $$(gen_srcjar)
+gen_src := $$(gen_cc) $$(gen_shared_cc) $$(gen_h) $$(gen_internal_h) $$(gen_srcjar)
mojom_bindings_generator_flags := $$(LOCAL_MOJOM_BINDINGS_GENERATOR_FLAGS)
# TODO(lhchavez): Generate these files instead of expecting them to be there.
mojom_type_mappings :=
@@ -31,6 +32,7 @@ ifneq ($$(LOCAL_MOJOM_TYPE_MAPPINGS),)
mojom_bindings_generator_flags += --typemap $$(abspath $$(mojom_type_mappings))
endif
+
$$(gen_cc) : PRIVATE_PATH := $$(local_path)
$$(gen_cc) : PRIVATE_MOJO_ROOT := $$(LOCAL_MOJO_ROOT)
$$(gen_cc) : PRIVATE_TARGET := $$(target_path)
@@ -49,10 +51,30 @@ $$(gen_cc) : $$(local_path)/$$(mojom_file) $$(mojom_type_mappings) \
$$(MOJOM_TEMPLATE_TOOLS) $$(generated_templates_dir)/.stamp
$$(transform-generated-source)
-# Make the other generated files depend on the .cc file. Unfortunately, the
+$$(gen_shared_cc) : PRIVATE_PATH := $$(local_path)
+$$(gen_shared_cc) : PRIVATE_MOJO_ROOT := $$(LOCAL_MOJO_ROOT)
+$$(gen_shared_cc) : PRIVATE_TARGET := $$(target_path)
+$$(gen_shared_cc) : PRIVATE_FLAGS := $$(mojom_bindings_generator_flags)
+$$(gen_shared_cc) : PRIVATE_CUSTOM_TOOL = \
+ (cd $$(PRIVATE_PATH) && \
+ python $$(abspath $$(MOJOM_BINDINGS_GENERATOR)) \
+ --use_bundled_pylibs generate \
+ $$(subst $$(PRIVATE_PATH)/,,$$<) \
+ -I $$(abspath $$(PRIVATE_MOJO_ROOT)):$$(abspath $$(PRIVATE_MOJO_ROOT)) \
+ -o $$(abspath $$(PRIVATE_TARGET)) \
+ --bytecode_path $$(abspath $$(generated_templates_dir)) \
+ --generate_non_variant_code \
+ -g c++,java \
+ $$(PRIVATE_FLAGS))
+$$(gen_shared_cc) : $$(local_path)/$$(mojom_file) $$(mojom_type_mappings) \
+ $$(MOJOM_TEMPLATE_TOOLS) $$(generated_templates_dir)/.stamp
+ $$(transform-generated-source)
+
+
+# Make the other generated files depend on the .cc files. Unfortunately, the
# Make->ninja translation would generate one individual rule for each generated
# file, resulting in the files being (racily) generated multiple times.
-$$(gen_internal_h): $$(gen_cc)
+$$(gen_internal_h): $$(gen_cc) $$(gen_shared_cc)
$$(hide) touch $$@
$$(gen_h): $$(gen_cc)
diff --git a/common.mk b/common.mk
new file mode 100644
index 0000000..aed7d3e
--- /dev/null
+++ b/common.mk
@@ -0,0 +1,934 @@
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# If this file is part of another source distribution, it's license may be
+# stored in LICENSE.makefile or LICENSE.common.mk.
+#
+# NOTE NOTE NOTE
+# The authoritative common.mk is located in:
+# https://chromium.googlesource.com/chromiumos/platform2/+/master/common-mk
+# Please make all changes there, then copy into place in other repos.
+# NOTE NOTE NOTE
+#
+# This file provides a common architecture for building C/C++ source trees.
+# It uses recursive makefile inclusion to create a single make process which
+# can be built in the source tree or with the build artifacts placed elsewhere.
+#
+# It is fully parallelizable for all targets, including static archives.
+#
+# To use:
+# 1. Place common.mk in your top source level
+# 2. In your top-level Makefile, place "include common.mk" at the top
+# 3. In all subdirectories, create a 'module.mk' file that starts with:
+# include common.mk
+# And then contains the remainder of your targets.
+# 4. All build targets should look like:
+# relative/path/target: relative/path/obj.o
+#
+# See existing makefiles for rule examples.
+#
+# Exported macros:
+# - cc_binary, cxx_binary provide standard compilation steps for binaries
+# - cxx_library, cc_library provide standard compilation steps for
+# shared objects.
+# All of the above optionally take an argument for extra flags.
+# - update_archive creates/updates a given .a target
+#
+# Instead of using the build macros, most users can just use wrapped targets:
+# - CXX_BINARY, CC_BINARY, CC_STATIC_BINARY, CXX_STATIC_BINARY
+# - CXX_LIBRARY, CC_LIBRARY, CC_STATIC_LIBRARY, CXX_STATIC_LIBRARY
+# - E.g., CXX_BINARY(mahbinary): foo.o
+# - object.depends targets may be used when a prerequisite is required for an
+# object file. Because object files result in multiple build artifacts to
+# handle PIC and PIE weirdness. E.g.
+# foo.o.depends: generated/dbus.h
+# - TEST(binary) or TEST(CXX_BINARY(binary)) may be used as a prerequisite
+# for the tests target to trigger an automated test run.
+# - CLEAN(file_or_dir) dependency can be added to 'clean'.
+#
+# If source code is being generated, rules will need to be registered for
+# compiling the objects. This can be done by adding one of the following
+# to the Makefile:
+# - For C source files
+# $(eval $(call add_object_rules,sub/dir/gen_a.o sub/dir/b.o,CC,c,CFLAGS))
+# - For C++ source files
+# $(eval $(call add_object_rules,sub/dir/gen_a.o sub/dir/b.o,CXX,cc,CXXFLAGS))
+#
+# Exported targets meant to have prerequisites added to:
+# - all - Your desired targets should be given
+# - tests - Any TEST(test_binary) targets should be given
+# - FORCE - force the given target to run regardless of changes
+# In most cases, using .PHONY is preferred.
+#
+# Possible command line variables:
+# - COLOR=[0|1] to set ANSI color output (default: 1)
+# - VERBOSE=[0|1] to hide/show commands (default: 0)
+# - MODE=[opt|dbg|profiling] (default: opt)
+# opt - Enable optimizations for release builds
+# dbg - Turn down optimization for debugging
+# profiling - Turn off optimization and turn on profiling/coverage
+# support.
+# - ARCH=[x86|arm|supported qemu name] (default: from portage or uname -m)
+# - SPLITDEBUG=[0|1] splits debug info in target.debug (default: 0)
+# If NOSTRIP=1, SPLITDEBUG will never strip the final emitted objects.
+# - NOSTRIP=[0|1] determines if binaries are stripped. (default: 1)
+# NOSTRIP=0 and MODE=opt will also drop -g from the CFLAGS.
+# - VALGRIND=[0|1] runs tests under valgrind (default: 0)
+# - OUT=/path/to/builddir puts all output in given path (default: $PWD)
+# - VALGRIND_ARGS="" supplies extra memcheck arguments
+#
+# Per-target(-ish) variable:
+# - NEEDS_ROOT=[0|1] allows a TEST() target to run with root.
+# Default is 0 unless it is running under QEmu.
+# - NEEDS_MOUNTS=[0|1] allows a TEST() target running on QEmu to get
+# setup mounts in the $(SYSROOT)
+#
+# Caveats:
+# - Directories or files with spaces in them DO NOT get along with GNU Make.
+# If you need them, all uses of dir/notdir/etc will need to have magic
+# wrappers. Proceed at risk to your own sanity.
+# - External CXXFLAGS and CFLAGS should be passed via the environment since
+# this file does not use 'override' to control them.
+# - Our version of GNU Make doesn't seem to support the 'private' variable
+# annotation, so you can't tag a variable private on a wrapping target.
+
+# Behavior configuration variables
+SPLITDEBUG ?= 0
+NOSTRIP ?= 1
+VALGRIND ?= 0
+COLOR ?= 1
+VERBOSE ?= 0
+MODE ?= opt
+CXXEXCEPTIONS ?= 0
+ARCH ?= $(shell uname -m)
+
+# Put objects in a separate tree based on makefile locations
+# This means you can build a tree without touching it:
+# make -C $SRCDIR # will create ./build-$(MODE)
+# Or
+# make -C $SRCDIR OUT=$PWD
+# This variable is extended on subdir calls and doesn't need to be re-called.
+OUT ?= $(PWD)/
+
+# Make OUT now so we can use realpath.
+$(shell mkdir -p "$(OUT)")
+
+# TODO(wad) Relative paths are resolved against SRC and not the calling dir.
+# Ensure a command-line supplied OUT has a slash
+override OUT := $(realpath $(OUT))/
+
+# SRC is not meant to be set by the end user, but during make call relocation.
+# $(PWD) != $(CURDIR) all the time.
+export SRC ?= $(CURDIR)
+
+# Re-start in the $(OUT) directory if we're not there.
+# We may be invoked using -C or bare and we need to ensure behavior
+# is consistent so we check both PWD vs OUT and PWD vs CURDIR.
+override RELOCATE_BUILD := 0
+ifneq (${PWD}/,${OUT})
+override RELOCATE_BUILD := 1
+endif
+# Make sure we're running with no builtin targets. They cause
+# leakage and mayhem!
+ifneq (${PWD},${CURDIR})
+override RELOCATE_BUILD := 1
+# If we're run from the build dir, don't let it get cleaned up later.
+ifeq (${PWD}/,${OUT})
+$(shell touch "$(PWD)/.dont_delete_on_clean")
+endif
+endif # ifneq (${PWD},${CURDIR}
+
+# "Relocate" if we need to restart without implicit rules.
+ifeq ($(subst r,,$(MAKEFLAGS)),$(MAKEFLAGS))
+override RELOCATE_BUILD := 1
+endif
+
+ifeq (${RELOCATE_BUILD},1)
+# By default, silence build output. Reused below as well.
+QUIET = @
+ifeq ($(VERBOSE),1)
+ QUIET=
+endif
+
+# This target will override all targets, including prerequisites. To avoid
+# calling $(MAKE) once per prereq on the given CMDGOAL, we guard it with a local
+# variable.
+RUN_ONCE := 0
+MAKECMDGOALS ?= all
+# Keep the rules split as newer make does not allow them to be declared
+# on the same line. But the way :: rules work, the _all here will also
+# invoke the %:: rule while retaining "_all" as the default.
+_all::
+%::
+ $(if $(filter 0,$(RUN_ONCE)), \
+ cd "$(OUT)" && \
+ $(MAKE) -r -I "$(SRC)" -f "$(CURDIR)/Makefile" \
+ SRC="$(CURDIR)" OUT="$(OUT)" $(foreach g,$(MAKECMDGOALS),"$(g)"),)
+ $(eval RUN_ONCE := 1)
+pass-to-subcall := 1
+endif
+
+ifeq ($(pass-to-subcall),)
+
+# Only call MODULE if we're in a submodule
+MODULES_LIST := $(filter-out Makefile %.d,$(MAKEFILE_LIST))
+ifeq ($(words $(filter-out Makefile common.mk %.d $(SRC)/Makefile \
+ $(SRC)/common.mk,$(MAKEFILE_LIST))),0)
+
+# All the top-level defines outside of module.mk.
+
+#
+# Helper macros
+#
+
+# Create the directory if it doesn't yet exist.
+define auto_mkdir
+ $(if $(wildcard $(dir $1)),$2,$(QUIET)mkdir -p "$(dir $1)")
+endef
+
+# Creates the actual archive with an index.
+# The target $@ must end with .pic.a or .pie.a.
+define update_archive
+ $(call auto_mkdir,$(TARGET_OR_MEMBER))
+ $(QUIET)# Create the archive in one step to avoid parallel use accessing it
+ $(QUIET)# before all the symbols are present.
+ @$(ECHO) "AR $(subst \
+$(SRC)/,,$(^:.o=$(suffix $(basename $(TARGET_OR_MEMBER))).o)) \
+-> $(subst $(SRC)/,,$(TARGET_OR_MEMBER))"
+ $(QUIET)$(AR) rcs $(TARGET_OR_MEMBER) \
+ $(subst $(SRC)/,,$(^:.o=$(suffix $(basename $(TARGET_OR_MEMBER))).o))
+endef
+
+# Default compile from objects using pre-requisites but filters out
+# subdirs and .d files.
+define cc_binary
+ $(call COMPILE_BINARY_implementation,CC,$(CFLAGS) $(1),$(EXTRA_FLAGS))
+endef
+
+define cxx_binary
+ $(call COMPILE_BINARY_implementation,CXX,$(CXXFLAGS) $(1),$(EXTRA_FLAGS))
+endef
+
+# Default compile from objects using pre-requisites but filters out
+# subdirs and .d files.
+define cc_library
+ $(call COMPILE_LIBRARY_implementation,CC,$(CFLAGS) $(1),$(EXTRA_FLAGS))
+endef
+define cxx_library
+ $(call COMPILE_LIBRARY_implementation,CXX,$(CXXFLAGS) $(1),$(EXTRA_FLAGS))
+endef
+
+# Deletes files silently if they exist. Meant for use in any local
+# clean targets.
+define silent_rm
+ $(if $(wildcard $(1)),
+ $(QUIET)($(ECHO) -n '$(COLOR_RED)CLEANFILE$(COLOR_RESET) ' && \
+ $(ECHO) '$(subst $(OUT)/,,$(wildcard $(1)))' && \
+ $(RM) $(1) 2>/dev/null) || true,)
+endef
+define silent_rmdir
+ $(if $(wildcard $(1)),
+ $(if $(wildcard $(1)/*),
+ $(QUIET)# $(1) not empty [$(wildcard $(1)/*)]. Not deleting.,
+ $(QUIET)($(ECHO) -n '$(COLOR_RED)CLEANDIR$(COLOR_RESET) ' && \
+ $(ECHO) '$(subst $(OUT)/,,$(wildcard $(1)))' && \
+ $(RMDIR) $(1) 2>/dev/null) || true),)
+endef
+
+#
+# Default variable values
+#
+
+# Only override toolchain vars if they are from make.
+CROSS_COMPILE ?=
+define override_var
+ifneq ($(filter undefined default,$(origin $1)),)
+$1 = $(CROSS_COMPILE)$2
+endif
+endef
+$(eval $(call override_var,AR,ar))
+$(eval $(call override_var,CC,gcc))
+$(eval $(call override_var,CXX,g++))
+$(eval $(call override_var,OBJCOPY,objcopy))
+$(eval $(call override_var,PKG_CONFIG,pkg-config))
+$(eval $(call override_var,RANLIB,ranlib))
+$(eval $(call override_var,STRIP,strip))
+
+RMDIR ?= rmdir
+ECHO = /bin/echo -e
+
+ifeq ($(lastword $(subst /, ,$(CC))),clang)
+CDRIVER = clang
+else
+CDRIVER = gcc
+endif
+
+ifeq ($(lastword $(subst /, ,$(CXX))),clang++)
+CXXDRIVER = clang
+else
+CXXDRIVER = gcc
+endif
+
+# Internal macro to support check_XXX macros below.
+# Usage: $(call check_compile, [code], [compiler], [code_type], [c_flags],
+# [extra_c_flags], [library_flags], [success_ret], [fail_ret])
+# Return: [success_ret] if compile succeeded, otherwise [fail_ret]
+check_compile = $(shell printf '%b\n' $(1) | \
+ $($(2)) $($(4)) -x $(3) $(LDFLAGS) $(5) - $(6) -o /dev/null > /dev/null 2>&1 \
+ && echo "$(7)" || echo "$(8)")
+
+# Helper macro to check whether a test program will compile with the specified
+# compiler flags.
+# Usage: $(call check_compile_cc, [code], [flags], [alternate_flags])
+# Return: [flags] if compile succeeded, otherwise [alternate_flags]
+check_compile_cc = $(call check_compile,$(1),CC,c,CFLAGS,$(2),,$(2),$(3))
+check_compile_cxx = $(call check_compile,$(1),CXX,c++,CXXFLAGS,$(2),,$(2),$(3))
+
+# Helper macro to check whether a test program will compile with the specified
+# libraries.
+# Usage: $(call check_compile_cc, [code], [library_flags], [alternate_flags])
+# Return: [library_flags] if compile succeeded, otherwise [alternate_flags]
+check_libs_cc = $(call check_compile,$(1),CC,c,CFLAGS,,$(2),$(2),$(3))
+check_libs_cxx = $(call check_compile,$(1),CXX,c++,CXXFLAGS,,$(2),$(2),$(3))
+
+# Helper macro to check whether the compiler accepts the specified flags.
+# Usage: $(call check_compile_cc, [flags], [alternate_flags])
+# Return: [flags] if compile succeeded, otherwise [alternate_flags]
+check_cc = $(call check_compile_cc,'int main() { return 0; }',$(1),$(2))
+check_cxx = $(call check_compile_cxx,'int main() { return 0; }',$(1),$(2))
+
+# Choose the stack protector flags based on whats supported by the compiler.
+SSP_CFLAGS := $(call check_cc,-fstack-protector-strong)
+ifeq ($(SSP_CFLAGS),)
+ SSP_CFLAGS := $(call check_cc,-fstack-protector-all)
+endif
+
+# To update these from an including Makefile:
+# CXXFLAGS += -mahflag # Append to the list
+# CXXFLAGS := -mahflag $(CXXFLAGS) # Prepend to the list
+# CXXFLAGS := $(filter-out badflag,$(CXXFLAGS)) # Filter out a value
+# The same goes for CFLAGS.
+COMMON_CFLAGS-gcc := -fvisibility=internal -ggdb3 -Wa,--noexecstack
+COMMON_CFLAGS-clang := -fvisibility=hidden -ggdb
+COMMON_CFLAGS := -Wall -Werror -fno-strict-aliasing $(SSP_CFLAGS) -O1 -Wformat=2
+CXXFLAGS += $(COMMON_CFLAGS) $(COMMON_CFLAGS-$(CXXDRIVER))
+CFLAGS += $(COMMON_CFLAGS) $(COMMON_CFLAGS-$(CDRIVER))
+CPPFLAGS += -D_FORTIFY_SOURCE=2
+
+# Enable large file support.
+CPPFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
+
+# Disable exceptions based on the CXXEXCEPTIONS setting.
+ifeq ($(CXXEXCEPTIONS),0)
+ CXXFLAGS := $(CXXFLAGS) -fno-exceptions -fno-unwind-tables \
+ -fno-asynchronous-unwind-tables
+endif
+
+ifeq ($(MODE),opt)
+ # Up the optimizations.
+ CFLAGS := $(filter-out -O1,$(CFLAGS)) -O2
+ CXXFLAGS := $(filter-out -O1,$(CXXFLAGS)) -O2
+ # Only drop -g* if symbols aren't desired.
+ ifeq ($(NOSTRIP),0)
+ # TODO: do we want -fomit-frame-pointer on x86?
+ CFLAGS := $(filter-out -ggdb3,$(CFLAGS))
+ CXXFLAGS := $(filter-out -ggdb3,$(CXXFLAGS))
+ endif
+endif
+
+ifeq ($(MODE),profiling)
+ CFLAGS := $(CFLAGS) -O0 -g --coverage
+ CXXFLAGS := $(CXXFLAGS) -O0 -g --coverage
+ LDFLAGS := $(LDFLAGS) --coverage
+endif
+
+LDFLAGS := $(LDFLAGS) -Wl,-z,relro -Wl,-z,noexecstack -Wl,-z,now
+
+# Fancy helpers for color if a prompt is defined
+ifeq ($(COLOR),1)
+COLOR_RESET = \x1b[0m
+COLOR_GREEN = \x1b[32;01m
+COLOR_RED = \x1b[31;01m
+COLOR_YELLOW = \x1b[33;01m
+endif
+
+# By default, silence build output.
+QUIET = @
+ifeq ($(VERBOSE),1)
+ QUIET=
+endif
+
+#
+# Implementation macros for compile helpers above
+#
+
+# Useful for dealing with pie-broken toolchains.
+# Call make with PIE=0 to disable default PIE use.
+OBJ_PIE_FLAG = -fPIE
+COMPILE_PIE_FLAG = -pie
+ifeq ($(PIE),0)
+ OBJ_PIE_FLAG =
+ COMPILE_PIE_FLAG =
+endif
+
+# Favor member targets first for CXX_BINARY(%) magic.
+# And strip out nested members if possible.
+LP := (
+RP := )
+TARGET_OR_MEMBER = $(lastword $(subst $(LP), ,$(subst $(RP),,$(or $%,$@))))
+
+# Default compile from objects using pre-requisites but filters out
+# all non-.o files.
+define COMPILE_BINARY_implementation
+ @$(ECHO) "LD$(1) $(subst $(PWD)/,,$(TARGET_OR_MEMBER))"
+ $(call auto_mkdir,$(TARGET_OR_MEMBER))
+ $(QUIET)$($(1)) $(COMPILE_PIE_FLAGS) -o $(TARGET_OR_MEMBER) \
+ $(2) $(LDFLAGS) \
+ $(filter %.o %.a,$(^:.o=.pie.o)) \
+ $(foreach so,$(filter %.so,$^),-L$(dir $(so)) \
+ -l$(patsubst lib%,%,$(basename $(notdir $(so))))) \
+ $(LDLIBS)
+ $(call conditional_strip)
+ @$(ECHO) -n "BIN "
+ @$(ECHO) "$(COLOR_GREEN)$(subst $(PWD)/,,$(TARGET_OR_MEMBER))$(COLOR_RESET)"
+ @$(ECHO) " $(COLOR_YELLOW)-----$(COLOR_RESET)"
+endef
+
+# TODO: add version support extracted from PV environment variable
+#ifeq ($(PV),9999)
+#$(warning PV=$(PV). If shared object versions matter, please force PV=.)
+#endif
+# Then add -Wl,-soname,$@.$(PV) ?
+
+# Default compile from objects using pre-requisites but filters out
+# all non-.o values. (Remember to add -L$(OUT) -llib)
+COMMA := ,
+define COMPILE_LIBRARY_implementation
+ @$(ECHO) "SHARED$(1) $(subst $(PWD)/,,$(TARGET_OR_MEMBER))"
+ $(call auto_mkdir,$(TARGET_OR_MEMBER))
+ $(QUIET)$($(1)) -shared -Wl,-E -o $(TARGET_OR_MEMBER) \
+ $(2) $(LDFLAGS) \
+ $(if $(filter %.a,$^),-Wl$(COMMA)--whole-archive,) \
+ $(filter %.o ,$(^:.o=.pic.o)) \
+ $(foreach a,$(filter %.a,$^),-L$(dir $(a)) \
+ -l$(patsubst lib%,%,$(basename $(notdir $(a))))) \
+ $(foreach so,$(filter %.so,$^),-L$(dir $(so)) \
+ -l$(patsubst lib%,%,$(basename $(notdir $(so))))) \
+ $(LDLIBS)
+ $(call conditional_strip)
+ @$(ECHO) -n "LIB $(COLOR_GREEN)"
+ @$(ECHO) "$(subst $(PWD)/,,$(TARGET_OR_MEMBER))$(COLOR_RESET)"
+ @$(ECHO) " $(COLOR_YELLOW)-----$(COLOR_RESET)"
+endef
+
+define conditional_strip
+ $(if $(filter 0,$(NOSTRIP)),$(call strip_artifact))
+endef
+
+define strip_artifact
+ @$(ECHO) "STRIP $(subst $(OUT)/,,$(TARGET_OR_MEMBER))"
+ $(if $(filter 1,$(SPLITDEBUG)), @$(ECHO) -n "DEBUG "; \
+ $(ECHO) "$(COLOR_YELLOW)\
+$(subst $(OUT)/,,$(TARGET_OR_MEMBER)).debug$(COLOR_RESET)")
+ $(if $(filter 1,$(SPLITDEBUG)), \
+ $(QUIET)$(OBJCOPY) --only-keep-debug "$(TARGET_OR_MEMBER)" \
+ "$(TARGET_OR_MEMBER).debug")
+ $(if $(filter-out dbg,$(MODE)),$(QUIET)$(STRIP) --strip-unneeded \
+ "$(TARGET_OR_MEMBER)",)
+endef
+
+#
+# Global pattern rules
+#
+
+# Below, the archive member syntax is abused to create fancier
+# syntactic sugar for recipe authors that avoids needed to know
+# subcall options. The downside is that make attempts to look
+# into the phony archives for timestamps. This will cause the final
+# target to be rebuilt/linked on _every_ call to make even when nothing
+# has changed. Until a better way presents itself, we have helpers that
+# do the stat check on make's behalf. Dodgy but simple.
+define old_or_no_timestamp
+ $(if $(realpath $%),,$(1))
+ $(if $(shell find $^ -cnewer "$%" 2>/dev/null),$(1))
+endef
+
+define check_deps
+ $(if $(filter 0,$(words $^)),\
+ $(error Missing dependencies or declaration of $@($%)),)
+endef
+
+# Build a cxx target magically
+CXX_BINARY(%):
+ $(call check_deps)
+ $(call old_or_no_timestamp,$(call cxx_binary))
+clean: CLEAN(CXX_BINARY*)
+
+CC_BINARY(%):
+ $(call check_deps)
+ $(call old_or_no_timestamp,$(call cc_binary))
+clean: CLEAN(CC_BINARY*)
+
+CXX_STATIC_BINARY(%):
+ $(call check_deps)
+ $(call old_or_no_timestamp,$(call cxx_binary,-static))
+clean: CLEAN(CXX_STATIC_BINARY*)
+
+CC_STATIC_BINARY(%):
+ $(call check_deps)
+ $(call old_or_no_timestamp,$(call cc_binary,-static))
+clean: CLEAN(CC_STATIC_BINARY*)
+
+CXX_LIBRARY(%):
+ $(call check_deps)
+ $(call old_or_no_timestamp,$(call cxx_library))
+clean: CLEAN(CXX_LIBRARY*)
+
+CXX_LIBARY(%):
+ $(error Typo alert! LIBARY != LIBRARY)
+
+CC_LIBRARY(%):
+ $(call check_deps)
+ $(call old_or_no_timestamp,$(call cc_library))
+clean: CLEAN(CC_LIBRARY*)
+
+CC_LIBARY(%):
+ $(error Typo alert! LIBARY != LIBRARY)
+
+CXX_STATIC_LIBRARY(%):
+ $(call check_deps)
+ $(call old_or_no_timestamp,$(call update_archive))
+clean: CLEAN(CXX_STATIC_LIBRARY*)
+
+CXX_STATIC_LIBARY(%):
+ $(error Typo alert! LIBARY != LIBRARY)
+
+CC_STATIC_LIBRARY(%):
+ $(call check_deps)
+ $(call old_or_no_timestamp,$(call update_archive))
+clean: CLEAN(CC_STATIC_LIBRARY*)
+
+CC_STATIC_LIBARY(%):
+ $(error Typo alert! LIBARY != LIBRARY)
+
+
+TEST(%): % qemu_chroot_install
+ $(call TEST_implementation)
+.PHONY: TEST
+
+# multiple targets with a wildcard need to share an directory.
+# Don't use this directly it just makes sure the directory is removed _after_
+# the files are.
+CLEANFILE(%):
+ $(call silent_rm,$(TARGET_OR_MEMBER))
+.PHONY: CLEANFILE
+
+CLEAN(%): CLEANFILE(%)
+ $(QUIET)# CLEAN($%) meta-target called
+ $(if $(filter-out $(PWD)/,$(dir $(abspath $(TARGET_OR_MEMBER)))), \
+ $(call silent_rmdir,$(dir $(abspath $(TARGET_OR_MEMBER)))),\
+ $(QUIET)# Not deleting $(dir $(abspath $(TARGET_OR_MEMBER))) yet.)
+.PHONY: CLEAN
+
+#
+# Top-level objects and pattern rules
+#
+
+# All objects for .c files at the top level
+C_OBJECTS = $(patsubst $(SRC)/%.c,%.o,$(wildcard $(SRC)/*.c))
+
+
+# All objects for .cxx files at the top level
+CXX_OBJECTS = $(patsubst $(SRC)/%.cc,%.o,$(wildcard $(SRC)/*.cc))
+
+# Note, the catch-all pattern rules don't work in subdirectories because
+# we're building from the $(OUT) directory. At the top-level (here) they will
+# work, but we go ahead and match using the module form. Then we can place a
+# generic pattern rule to capture leakage from the main Makefile. (Later in the
+# file.)
+#
+# The reason target specific pattern rules work well for modules,
+# MODULE_C_OBJECTS, is because it scopes the behavior to the given target which
+# ensures we get a relative directory offset from $(OUT) which otherwise would
+# not match without further magic on a per-subdirectory basis.
+
+# Creates object file rules. Call with eval.
+# $(1) list of .o files
+# $(2) source type (CC or CXX)
+# $(3) source suffix (cc or c)
+# $(4) compiler flag name (CFLAGS or CXXFLAGS)
+# $(5) source dir: _only_ if $(SRC). Leave blank for obj tree.
+define add_object_rules
+$(patsubst %.o,%.pie.o,$(1)): %.pie.o: $(5)%.$(3) %.o.depends
+ $$(call auto_mkdir,$$@)
+ $$(call OBJECT_PATTERN_implementation,$(2),\
+ $$(basename $$@),$$($(4)) $$(CPPFLAGS) $$(OBJ_PIE_FLAG))
+
+$(patsubst %.o,%.pic.o,$(1)): %.pic.o: $(5)%.$(3) %.o.depends
+ $$(call auto_mkdir,$$@)
+ $$(call OBJECT_PATTERN_implementation,$(2),\
+ $$(basename $$@),$$($(4)) $$(CPPFLAGS) -fPIC)
+
+# Placeholder for depends
+$(patsubst %.o,%.o.depends,$(1)):
+ $$(call auto_mkdir,$$@)
+ $$(QUIET)touch "$$@"
+
+$(1): %.o: %.pic.o %.pie.o
+ $$(call auto_mkdir,$$@)
+ $$(QUIET)touch "$$@"
+endef
+
+define OBJECT_PATTERN_implementation
+ @$(ECHO) "$(1) $(subst $(SRC)/,,$<) -> $(2).o"
+ $(call auto_mkdir,$@)
+ $(QUIET)$($(1)) -c -MD -MF $(2).d $(3) -o $(2).o $<
+ $(QUIET)# Wrap all the deps in $$(wildcard) so a missing header
+ $(QUIET)# won't cause weirdness. First we remove newlines and \,
+ $(QUIET)# then wrap it.
+ $(QUIET)sed -i -e :j -e '$$!N;s|\\\s*\n| |;tj' \
+ -e 's|^\(.*\s*:\s*\)\(.*\)$$|\1 $$\(wildcard \2\)|' $(2).d
+endef
+
+# Now actually register handlers for C(XX)_OBJECTS.
+$(eval $(call add_object_rules,$(C_OBJECTS),CC,c,CFLAGS,$(SRC)/))
+$(eval $(call add_object_rules,$(CXX_OBJECTS),CXX,cc,CXXFLAGS,$(SRC)/))
+
+# Disable default pattern rules to help avoid leakage.
+# These may already be handled by '-r', but let's keep it to be safe.
+%: %.o ;
+%.a: %.o ;
+%.o: %.c ;
+%.o: %.cc ;
+
+# NOTE: A specific rule for archive objects is avoided because parallel
+# update of the archive causes build flakiness.
+# Instead, just make the objects the prerequisites and use update_archive
+# To use the foo.a(obj.o) functionality, targets would need to specify the
+# explicit object they expect on the prerequisite line.
+
+#
+# Architecture detection and QEMU wrapping
+#
+
+HOST_ARCH ?= $(shell uname -m)
+override ARCH := $(strip $(ARCH))
+override HOST_ARCH := $(strip $(HOST_ARCH))
+# emake will supply "x86" or "arm" for ARCH, but
+# if uname -m runs and you get x86_64, then this subst
+# will break.
+ifeq ($(subst x86,i386,$(ARCH)),i386)
+ QEMU_ARCH := $(subst x86,i386,$(ARCH)) # x86 -> i386
+else ifeq ($(subst amd64,x86_64,$(ARCH)),x86_64)
+ QEMU_ARCH := $(subst amd64,x86_64,$(ARCH)) # amd64 -> x86_64
+else
+ QEMU_ARCH = $(ARCH)
+endif
+override QEMU_ARCH := $(strip $(QEMU_ARCH))
+
+# If we're cross-compiling, try to use qemu for running the tests.
+ifneq ($(QEMU_ARCH),$(HOST_ARCH))
+ ifeq ($(SYSROOT),)
+ $(info SYSROOT not defined. qemu-based testing disabled)
+ else
+ # A SYSROOT is assumed for QEmu use.
+ USE_QEMU ?= 1
+
+ # Allow 64-bit hosts to run 32-bit without qemu.
+ ifeq ($(HOST_ARCH),x86_64)
+ ifeq ($(QEMU_ARCH),i386)
+ USE_QEMU = 0
+ endif
+ endif
+ endif
+else
+ USE_QEMU ?= 0
+endif
+
+# Normally we don't need to run as root or do bind mounts, so only
+# enable it by default when we're using QEMU.
+NEEDS_ROOT ?= $(USE_QEMU)
+NEEDS_MOUNTS ?= $(USE_QEMU)
+
+SYSROOT_OUT = $(OUT)
+ifneq ($(SYSROOT),)
+ SYSROOT_OUT = $(subst $(SYSROOT),,$(OUT))
+else
+ # Default to / when all the empty-sysroot logic is done.
+ SYSROOT = /
+endif
+
+QEMU_NAME = qemu-$(QEMU_ARCH)
+QEMU_PATH = /build/bin/$(QEMU_NAME)
+QEMU_SYSROOT_PATH = $(SYSROOT)$(QEMU_PATH)
+QEMU_SRC_PATH = /usr/bin/$(QEMU_NAME)
+QEMU_BINFMT_PATH = /proc/sys/fs/binfmt_misc/$(QEMU_NAME)
+QEMU_REGISTER_PATH = /proc/sys/fs/binfmt_misc/register
+
+QEMU_MAGIC_arm = ":$(QEMU_NAME):M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/build/bin/qemu-arm:"
+
+
+#
+# Output full configuration at top level
+#
+
+# Don't show on clean
+ifneq ($(MAKECMDGOALS),clean)
+ $(info build configuration:)
+ $(info - OUT=$(OUT))
+ $(info - SRC=$(SRC))
+ $(info - MODE=$(MODE))
+ $(info - SPLITDEBUG=$(SPLITDEBUG))
+ $(info - NOSTRIP=$(NOSTRIP))
+ $(info - VALGRIND=$(VALGRIND))
+ $(info - COLOR=$(COLOR))
+ $(info - CXXEXCEPTIONS=$(CXXEXCEPTIONS))
+ $(info - ARCH=$(ARCH))
+ $(info - QEMU_ARCH=$(QEMU_ARCH))
+ $(info - USE_QEMU=$(USE_QEMU))
+ $(info - NEEDS_ROOT=$(NEEDS_ROOT))
+ $(info - NEEDS_MOUNTS=$(NEEDS_MOUNTS))
+ $(info - SYSROOT=$(SYSROOT))
+ $(info )
+endif
+
+#
+# Standard targets with detection for when they are improperly configured.
+#
+
+# all does not include tests by default
+all:
+ $(QUIET)(test -z "$^" && \
+ $(ECHO) "You must add your targets as 'all' prerequisites") || true
+ $(QUIET)test -n "$^"
+
+# Builds and runs tests for the target arch
+# Run them in parallel
+# After the test have completed, if profiling, run coverage analysis
+tests:
+ifeq ($(MODE),profiling)
+ @$(ECHO) "COVERAGE [$(COLOR_YELLOW)STARTED$(COLOR_RESET)]"
+ $(QUIET)FILES=""; \
+ for GCNO in `find . -name "*.gcno"`; do \
+ GCDA="$${GCNO%.gcno}.gcda"; \
+ if [ -e $${GCDA} ]; then \
+ FILES="$${FILES} $${GCDA}"; \
+ fi \
+ done; \
+ if [ -n "$${FILES}" ]; then \
+ gcov -l $${FILES}; \
+ lcov --capture --directory . \
+ --output-file=lcov-coverage.info; \
+ genhtml lcov-coverage.info \
+ --output-directory lcov-html; \
+ fi
+ @$(ECHO) "COVERAGE [$(COLOR_YELLOW)FINISHED$(COLOR_RESET)]"
+endif
+.PHONY: tests
+
+qemu_chroot_install:
+ifeq ($(USE_QEMU),1)
+ $(QUIET)$(ECHO) "QEMU Preparing $(QEMU_NAME)"
+ @# Copying strategy
+ @# Compare /usr/bin/qemu inode to /build/$board/build/bin/qemu, if different
+ @# hard link to a temporary file, then rename temp to target. This should
+ @# ensure that once $QEMU_SYSROOT_PATH exists it will always exist, regardless
+ @# of simultaneous test setups.
+ $(QUIET)if [[ ! -e $(QEMU_SYSROOT_PATH) || \
+ `stat -c %i $(QEMU_SRC_PATH)` != `stat -c %i $(QEMU_SYSROOT_PATH)` \
+ ]]; then \
+ $(ROOT_CMD) ln -Tf $(QEMU_SRC_PATH) $(QEMU_SYSROOT_PATH).$$$$; \
+ $(ROOT_CMD) mv -Tf $(QEMU_SYSROOT_PATH).$$$$ $(QEMU_SYSROOT_PATH); \
+ fi
+
+ @# Prep the binfmt handler. First mount if needed, then unregister any bad
+ @# mappings and then register our mapping.
+ @# There may still be some race conditions here where one script de-registers
+ @# and another script starts executing before it gets re-registered, however
+ @# it should be rare.
+ -$(QUIET)[[ -e $(QEMU_REGISTER_PATH) ]] || \
+ $(ROOT_CMD) mount binfmt_misc -t binfmt_misc \
+ /proc/sys/fs/binfmt_misc
+
+ -$(QUIET)if [[ -e $(QEMU_BINFMT_PATH) && \
+ `awk '$$1 == "interpreter" {print $$NF}' $(QEMU_BINFMT_PATH)` != \
+ "$(QEMU_PATH)" ]]; then \
+ echo -1 | $(ROOT_CMD) tee $(QEMU_BINFMT_PATH) >/dev/null; \
+ fi
+
+ -$(if $(QEMU_MAGIC_$(ARCH)),$(QUIET)[[ -e $(QEMU_BINFMT_PATH) ]] || \
+ echo $(QEMU_MAGIC_$(ARCH)) | $(ROOT_CMD) tee $(QEMU_REGISTER_PATH) \
+ >/dev/null)
+endif
+.PHONY: qemu_clean qemu_chroot_install
+
+# TODO(wad) Move to -L $(SYSROOT) and fakechroot when qemu-user
+# doesn't hang traversing /proc from SYSROOT.
+SUDO_CMD = sudo
+UNSHARE_CMD = unshare
+QEMU_CMD =
+ROOT_CMD = $(if $(filter 1,$(NEEDS_ROOT)),$(SUDO_CMD) , )
+MOUNT_CMD = $(if $(filter 1,$(NEEDS_MOUNTS)),$(ROOT_CMD) mount, \#)
+UMOUNT_CMD = $(if $(filter 1,$(NEEDS_MOUNTS)),$(ROOT_CMD) umount, \#)
+QEMU_LDPATH = $(SYSROOT_LDPATH):/lib64:/lib:/usr/lib64:/usr/lib
+ROOT_CMD_LDPATH = $(SYSROOT_LDPATH):$(SYSROOT)/lib64:
+ROOT_CMD_LDPATH := $(ROOT_CMD_LDPATH):$(SYSROOT)/lib:$(SYSROOT)/usr/lib64:
+ROOT_CMD_LDPATH := $(ROOT_CMD_LDPATH):$(SYSROOT)/usr/lib
+ifeq ($(USE_QEMU),1)
+ export QEMU_CMD = \
+ $(SUDO_CMD) chroot $(SYSROOT) $(QEMU_PATH) \
+ -drop-ld-preload \
+ -E LD_LIBRARY_PATH="$(QEMU_LDPATH):$(patsubst $(OUT),,$(LD_DIRS))" \
+ -E HOME="$(HOME)" -E SRC="$(SRC)" --
+ # USE_QEMU conditional function
+ define if_qemu
+ $(1)
+ endef
+else
+ ROOT_CMD = $(if $(filter 1,$(NEEDS_ROOT)),sudo, ) \
+ LD_LIBRARY_PATH="$(ROOT_CMD_LDPATH):$(LD_DIRS)"
+ define if_qemu
+ $(2)
+ endef
+endif
+
+VALGRIND_CMD =
+ifeq ($(VALGRIND),1)
+ VALGRIND_CMD = /usr/bin/valgrind --tool=memcheck $(VALGRIND_ARGS) --
+endif
+
+define TEST_implementation
+ $(QUIET)$(call TEST_setup)
+ $(QUIET)$(call TEST_run)
+ $(QUIET)$(call TEST_teardown)
+ $(QUIET)exit $$(cat $(OUT)$(TARGET_OR_MEMBER).status.test)
+endef
+
+define TEST_setup
+ @$(ECHO) -n "TEST $(TARGET_OR_MEMBER) "
+ @$(ECHO) "[$(COLOR_YELLOW)SETUP$(COLOR_RESET)]"
+ $(QUIET)# Setup a target-specific results file
+ $(QUIET)(echo > $(OUT)$(TARGET_OR_MEMBER).setup.test)
+ $(QUIET)(echo 1 > $(OUT)$(TARGET_OR_MEMBER).status.test)
+ $(QUIET)(echo > $(OUT)$(TARGET_OR_MEMBER).cleanup.test)
+ $(QUIET)# No setup if we are not using QEMU
+ $(QUIET)# TODO(wad) this is racy until we use a vfs namespace
+ $(call if_qemu,\
+ $(QUIET)(echo "mkdir -p '$(SYSROOT)/proc' '$(SYSROOT)/dev' \
+ '$(SYSROOT)/mnt/host/source'" \
+ >> "$(OUT)$(TARGET_OR_MEMBER).setup.test"))
+ $(call if_qemu,\
+ $(QUIET)(echo "$(MOUNT_CMD) --bind /mnt/host/source \
+ '$(SYSROOT)/mnt/host/source'" \
+ >> "$(OUT)$(TARGET_OR_MEMBER).setup.test"))
+ $(call if_qemu,\
+ $(QUIET)(echo "$(MOUNT_CMD) --bind /proc '$(SYSROOT)/proc'" \
+ >> "$(OUT)$(TARGET_OR_MEMBER).setup.test"))
+ $(call if_qemu,\
+ $(QUIET)(echo "$(MOUNT_CMD) --bind /dev '$(SYSROOT)/dev'" \
+ >> "$(OUT)$(TARGET_OR_MEMBER).setup.test"))
+endef
+
+define TEST_teardown
+ @$(ECHO) -n "TEST $(TARGET_OR_MEMBER) "
+ @$(ECHO) "[$(COLOR_YELLOW)TEARDOWN$(COLOR_RESET)]"
+ $(call if_qemu, $(QUIET)$(SHELL) "$(OUT)$(TARGET_OR_MEMBER).cleanup.test")
+endef
+
+# Use GTEST_ARGS.[arch] if defined.
+override GTEST_ARGS.real = \
+ $(call if_qemu,$(GTEST_ARGS.qemu.$(QEMU_ARCH)),$(GTEST_ARGS.host.$(HOST_ARCH)))
+
+define TEST_run
+ @$(ECHO) -n "TEST $(TARGET_OR_MEMBER) "
+ @$(ECHO) "[$(COLOR_GREEN)RUN$(COLOR_RESET)]"
+ $(QUIET)(echo 1 > "$(OUT)$(TARGET_OR_MEMBER).status.test")
+ $(QUIET)(echo $(ROOT_CMD) SRC="$(SRC)" $(QEMU_CMD) $(VALGRIND_CMD) \
+ "$(strip $(call if_qemu, $(SYSROOT_OUT),$(OUT))$(TARGET_OR_MEMBER))" \
+ $(if $(filter-out 0,$(words $(GTEST_ARGS.real))),$(GTEST_ARGS.real),\
+ $(GTEST_ARGS)) >> "$(OUT)$(TARGET_OR_MEMBER).setup.test")
+ -$(QUIET)$(call if_qemu,$(SUDO_CMD) $(UNSHARE_CMD) -m) $(SHELL) \
+ $(OUT)$(TARGET_OR_MEMBER).setup.test \
+ && echo 0 > "$(OUT)$(TARGET_OR_MEMBER).status.test"
+endef
+
+# Recursive list reversal so that we get RMDIR_ON_CLEAN in reverse order.
+define reverse
+$(if $(1),$(call reverse,$(wordlist 2,$(words $(1)),$(1)))) $(firstword $(1))
+endef
+
+clean: qemu_clean
+clean: CLEAN($(OUT)*.d) CLEAN($(OUT)*.o) CLEAN($(OUT)*.debug)
+clean: CLEAN($(OUT)*.test) CLEAN($(OUT)*.depends)
+clean: CLEAN($(OUT)*.gcno) CLEAN($(OUT)*.gcda) CLEAN($(OUT)*.gcov)
+clean: CLEAN($(OUT)lcov-coverage.info) CLEAN($(OUT)lcov-html)
+
+clean:
+ $(QUIET)# Always delete the containing directory last.
+ $(call silent_rmdir,$(OUT))
+
+FORCE: ;
+# Empty rule for use when no special targets are needed, like large_tests
+NONE:
+
+.PHONY: clean NONE valgrind NONE
+.DEFAULT_GOAL := all
+# Don't let make blow away "intermediates"
+.PRECIOUS: %.pic.o %.pie.o %.a %.pic.a %.pie.a %.test
+
+# Start accruing build info
+OUT_DIRS = $(OUT)
+LD_DIRS = $(OUT)
+SRC_DIRS = $(SRC)
+
+include $(wildcard $(OUT)*.d)
+SUBMODULE_DIRS = $(wildcard $(SRC)/*/module.mk)
+include $(SUBMODULE_DIRS)
+
+
+else ## In duplicate inclusions of common.mk
+
+# Get the current inclusion directory without a trailing slash
+MODULE := $(patsubst %/,%, \
+ $(dir $(lastword $(filter-out %common.mk,$(MAKEFILE_LIST)))))
+MODULE := $(subst $(SRC)/,,$(MODULE))
+MODULE_NAME := $(subst /,_,$(MODULE))
+#VPATH := $(MODULE):$(VPATH)
+
+
+# Depth first
+$(eval OUT_DIRS += $(OUT)$(MODULE))
+$(eval SRC_DIRS += $(OUT)$(MODULE))
+$(eval LD_DIRS := $(LD_DIRS):$(OUT)$(MODULE))
+
+# Add the defaults from this dir to rm_clean
+clean: CLEAN($(OUT)$(MODULE)/*.d) CLEAN($(OUT)$(MODULE)/*.o)
+clean: CLEAN($(OUT)$(MODULE)/*.debug) CLEAN($(OUT)$(MODULE)/*.test)
+clean: CLEAN($(OUT)$(MODULE)/*.depends)
+clean: CLEAN($(OUT)$(MODULE)/*.gcno) CLEAN($(OUT)$(MODULE)/*.gcda)
+clean: CLEAN($(OUT)$(MODULE)/*.gcov) CLEAN($(OUT)lcov-coverage.info)
+clean: CLEAN($(OUT)lcov-html)
+
+$(info + submodule: $(MODULE_NAME))
+# We must eval otherwise they may be dropped.
+MODULE_C_OBJECTS = $(patsubst $(SRC)/$(MODULE)/%.c,$(MODULE)/%.o,\
+ $(wildcard $(SRC)/$(MODULE)/*.c))
+$(eval $(MODULE_NAME)_C_OBJECTS ?= $(MODULE_C_OBJECTS))
+MODULE_CXX_OBJECTS = $(patsubst $(SRC)/$(MODULE)/%.cc,$(MODULE)/%.o,\
+ $(wildcard $(SRC)/$(MODULE)/*.cc))
+$(eval $(MODULE_NAME)_CXX_OBJECTS ?= $(MODULE_CXX_OBJECTS))
+
+# Note, $(MODULE) is implicit in the path to the %.c.
+# See $(C_OBJECTS) for more details.
+# Register rules for the module objects.
+$(eval $(call add_object_rules,$(MODULE_C_OBJECTS),CC,c,CFLAGS,$(SRC)/))
+$(eval $(call add_object_rules,$(MODULE_CXX_OBJECTS),CXX,cc,CXXFLAGS,$(SRC)/))
+
+# Continue recursive inclusion of module.mk files
+SUBMODULE_DIRS = $(wildcard $(SRC)/$(MODULE)/*/module.mk)
+include $(wildcard $(OUT)$(MODULE)/*.d)
+include $(SUBMODULE_DIRS)
+
+endif
+endif ## pass-to-subcall wrapper for relocating the call directory
diff --git a/gen/mojo/common/common_custom_types__type_mappings b/gen/mojo/common/common_custom_types__type_mappings
index 4602371..1906049 100644
--- a/gen/mojo/common/common_custom_types__type_mappings
+++ b/gen/mojo/common/common_custom_types__type_mappings
@@ -1,93 +1,193 @@
{
"c++": {
- "mojo.common.mojom.ListValue": {
- "typename": "base::ListValue",
+ "mojo.common.mojom.Value": {
+ "hashable": false,
+ "typename": "std::unique_ptr<base::Value>",
+ "traits_headers": [
+ "ipc/ipc_message_utils.h",
+ "mojo/common/values_struct_traits.h"
+ ],
+ "copyable_pass_by_value": false,
+ "move_only": true,
+ "nullable_is_same_type": true,
+ "non_copyable_non_movable": false,
+ "public_headers": [
+ "base/values.h"
+ ]
+ },
+ "mojo.common.mojom.UnguessableToken": {
+ "hashable": false,
+ "typename": "base::UnguessableToken",
"traits_headers": [
- "ipc/ipc_message_utils.h",
"mojo/common/common_custom_types_struct_traits.h"
- ],
- "copyable_pass_by_value": false,
- "move_only": false,
- "nullable_is_same_type": false,
+ ],
+ "copyable_pass_by_value": false,
+ "move_only": false,
+ "nullable_is_same_type": false,
+ "non_copyable_non_movable": false,
+ "public_headers": [
+ "base/unguessable_token.h"
+ ]
+ },
+ "mojo.common.mojom.TextDirection": {
+ "hashable": false,
+ "typename": "base::i18n::TextDirection",
+ "traits_headers": [
+ "mojo/common/common_custom_types_struct_traits.h"
+ ],
+ "copyable_pass_by_value": false,
+ "move_only": false,
+ "nullable_is_same_type": false,
+ "non_copyable_non_movable": false,
+ "public_headers": [
+ "base/i18n/rtl.h"
+ ]
+ },
+ "mojo.common.mojom.ListValue": {
+ "hashable": false,
+ "typename": "std::unique_ptr<base::ListValue>",
+ "traits_headers": [
+ "ipc/ipc_message_utils.h",
+ "mojo/common/values_struct_traits.h"
+ ],
+ "copyable_pass_by_value": false,
+ "move_only": true,
+ "nullable_is_same_type": true,
+ "non_copyable_non_movable": false,
"public_headers": [
"base/values.h"
]
- },
+ },
"mojo.common.mojom.String16": {
- "typename": "base::string16",
+ "hashable": false,
+ "typename": "base::string16",
"traits_headers": [
- "ipc/ipc_message_utils.h",
"mojo/common/common_custom_types_struct_traits.h"
- ],
- "copyable_pass_by_value": false,
- "move_only": false,
- "nullable_is_same_type": false,
+ ],
+ "copyable_pass_by_value": false,
+ "move_only": false,
+ "nullable_is_same_type": false,
+ "non_copyable_non_movable": false,
"public_headers": [
"base/strings/string16.h"
]
- },
+ },
"mojo.common.mojom.Time": {
- "typename": "base::Time",
+ "hashable": false,
+ "typename": "base::Time",
"traits_headers": [
- "ipc/ipc_message_utils.h",
+ "ipc/ipc_message_utils.h",
"mojo/common/common_custom_types_struct_traits.h"
- ],
- "copyable_pass_by_value": true,
- "move_only": false,
- "nullable_is_same_type": false,
+ ],
+ "copyable_pass_by_value": true,
+ "move_only": false,
+ "nullable_is_same_type": false,
+ "non_copyable_non_movable": false,
"public_headers": [
"base/time/time.h"
]
- },
+ },
"mojo.common.mojom.TimeDelta": {
- "typename": "base::TimeDelta",
+ "hashable": false,
+ "typename": "base::TimeDelta",
"traits_headers": [
- "ipc/ipc_message_utils.h",
+ "ipc/ipc_message_utils.h",
"mojo/common/common_custom_types_struct_traits.h"
- ],
- "copyable_pass_by_value": true,
- "move_only": false,
- "nullable_is_same_type": false,
+ ],
+ "copyable_pass_by_value": true,
+ "move_only": false,
+ "nullable_is_same_type": false,
+ "non_copyable_non_movable": false,
"public_headers": [
"base/time/time.h"
]
- },
+ },
"mojo.common.mojom.TimeTicks": {
- "typename": "base::TimeTicks",
+ "hashable": false,
+ "typename": "base::TimeTicks",
"traits_headers": [
- "ipc/ipc_message_utils.h",
+ "ipc/ipc_message_utils.h",
"mojo/common/common_custom_types_struct_traits.h"
- ],
- "copyable_pass_by_value": true,
- "move_only": false,
- "nullable_is_same_type": false,
+ ],
+ "copyable_pass_by_value": true,
+ "move_only": false,
+ "nullable_is_same_type": false,
+ "non_copyable_non_movable": false,
"public_headers": [
"base/time/time.h"
]
- },
+ },
+ "mojo.common.mojom.LegacyListValue": {
+ "hashable": false,
+ "typename": "base::ListValue",
+ "traits_headers": [
+ "ipc/ipc_message_utils.h",
+ "mojo/common/values_struct_traits.h"
+ ],
+ "copyable_pass_by_value": false,
+ "move_only": false,
+ "nullable_is_same_type": false,
+ "non_copyable_non_movable": true,
+ "public_headers": [
+ "base/values.h"
+ ]
+ },
+ "mojo.common.mojom.File": {
+ "hashable": false,
+ "typename": "base::File",
+ "traits_headers": [
+ "mojo/common/common_custom_types_struct_traits.h"
+ ],
+ "copyable_pass_by_value": false,
+ "move_only": true,
+ "nullable_is_same_type": true,
+ "non_copyable_non_movable": false,
+ "public_headers": [
+ "base/files/file.h"
+ ]
+ },
"mojo.common.mojom.FilePath": {
- "typename": "base::FilePath",
+ "hashable": false,
+ "typename": "base::FilePath",
"traits_headers": [
"ipc/ipc_message_utils.h"
- ],
- "copyable_pass_by_value": false,
- "move_only": false,
- "nullable_is_same_type": false,
+ ],
+ "copyable_pass_by_value": false,
+ "move_only": false,
+ "nullable_is_same_type": false,
+ "non_copyable_non_movable": false,
"public_headers": [
"base/files/file_path.h"
]
- },
+ },
"mojo.common.mojom.DictionaryValue": {
- "typename": "base::DictionaryValue",
+ "hashable": false,
+ "typename": "std::unique_ptr<base::DictionaryValue>",
"traits_headers": [
- "ipc/ipc_message_utils.h"
- ],
- "copyable_pass_by_value": false,
- "move_only": false,
- "nullable_is_same_type": false,
+ "ipc/ipc_message_utils.h",
+ "mojo/common/values_struct_traits.h"
+ ],
+ "copyable_pass_by_value": false,
+ "move_only": true,
+ "nullable_is_same_type": true,
+ "non_copyable_non_movable": false,
"public_headers": [
"base/values.h"
]
+ },
+ "mojo.common.mojom.Version": {
+ "hashable": false,
+ "typename": "base::Version",
+ "traits_headers": [
+ "mojo/common/common_custom_types_struct_traits.h"
+ ],
+ "copyable_pass_by_value": false,
+ "move_only": false,
+ "nullable_is_same_type": false,
+ "non_copyable_non_movable": false,
+ "public_headers": [
+ "base/version.h"
+ ]
}
}
-}
+} \ No newline at end of file
diff --git a/ipc/attachment_broker.h b/ipc/attachment_broker.h
deleted file mode 100644
index a106e29..0000000
--- a/ipc/attachment_broker.h
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IPC_ATTACHMENT_BROKER_H_
-#define IPC_ATTACHMENT_BROKER_H_
-
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/process/process_handle.h"
-#include "base/synchronization/lock.h"
-#include "build/build_config.h"
-#include "ipc/brokerable_attachment.h"
-#include "ipc/ipc_export.h"
-#include "ipc/ipc_listener.h"
-
-// If the platform has no attachments that need brokering, then it shouldn't
-// compile any code that calls member functions of AttachmentBroker. This
-// prevents symbols only used by AttachmentBroker and its subclasses from
-// making it into the binary.
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
-#define USE_ATTACHMENT_BROKER 1
-#else
-#define USE_ATTACHMENT_BROKER 0
-#endif // defined(OS_WIN)
-
-namespace base {
-class SequencedTaskRunner;
-class SingleThreadTaskRunner;
-};
-
-namespace IPC {
-
-class AttachmentBroker;
-class Endpoint;
-
-// Classes that inherit from this abstract base class are capable of
-// communicating with a broker to send and receive attachments to Chrome IPC
-// messages.
-class IPC_EXPORT SupportsAttachmentBrokering {
- public:
- // Returns an AttachmentBroker used to broker attachments of IPC messages to
- // other processes. There must be exactly one AttachmentBroker per process.
- virtual AttachmentBroker* GetAttachmentBroker() = 0;
-};
-
-// Responsible for brokering attachments to Chrome IPC messages. On platforms
-// that support attachment brokering, every IPC channel should have a reference
-// to a AttachmentBroker.
-// This class is not thread safe. The implementation of this class assumes that
-// it is only ever used on the same thread as its consumers.
-class IPC_EXPORT AttachmentBroker : public Listener {
- public:
- // A standard observer interface that allows consumers of the AttachmentBroker
- // to be notified when a new attachment has been received.
- class Observer {
- public:
- virtual void ReceivedBrokerableAttachmentWithId(
- const BrokerableAttachment::AttachmentId& id) = 0;
- };
-
- // Each process has at most one attachment broker. The process is responsible
- // for ensuring that |broker| stays alive for as long as the process is
- // sending/receiving ipc messages.
- static void SetGlobal(AttachmentBroker* broker);
- static AttachmentBroker* GetGlobal();
-
- AttachmentBroker();
- ~AttachmentBroker() override;
-
- // Sends |attachment| to |destination_process|. The implementation uses an
- // IPC::Channel to communicate with the broker process. This may be the same
- // IPC::Channel that is requesting the brokering of an attachment.
- // Returns true on success and false otherwise.
- virtual bool SendAttachmentToProcess(
- const scoped_refptr<BrokerableAttachment>& attachment,
- base::ProcessId destination_process) = 0;
-
- // Returns whether the attachment was available. If the attachment was
- // available, populates the output parameter |attachment|.
- bool GetAttachmentWithId(BrokerableAttachment::AttachmentId id,
- scoped_refptr<BrokerableAttachment>* attachment);
-
- // Any given observer should only ever add itself once to the observer list.
- // Notifications to |observer| will be posted to |runner|.
- // The |observer| is expected to call RemoveObserver() before being destroyed.
- void AddObserver(Observer* observer,
- const scoped_refptr<base::SequencedTaskRunner>& runner);
- void RemoveObserver(Observer* observer);
-
- // These two methods should only be called by the broker process.
- //
- // Each unprivileged process should have one IPC channel on which it
- // communicates attachment information with the broker process. In the broker
- // process, these channels must be registered and deregistered with the
- // Attachment Broker as they are created and destroyed.
- //
- // Invocations of Send() on |endpoint| will occur on thread bound to |runner|.
- virtual void RegisterCommunicationChannel(
- Endpoint* endpoint,
- scoped_refptr<base::SingleThreadTaskRunner> runner);
- virtual void DeregisterCommunicationChannel(Endpoint* endpoint);
-
- // In each unprivileged process, exactly one channel should be used to
- // communicate brokerable attachments with the broker process.
- virtual void RegisterBrokerCommunicationChannel(Endpoint* endpoint);
- virtual void DeregisterBrokerCommunicationChannel(Endpoint* endpoint);
-
- // Informs the attachment broker that a channel endpoint has received its
- // peer's PID.
- virtual void ReceivedPeerPid(base::ProcessId peer_pid);
-
- // True if and only if this broker is privileged.
- virtual bool IsPrivilegedBroker();
-
- protected:
- using AttachmentVector = std::vector<scoped_refptr<BrokerableAttachment>>;
-
- // Adds |attachment| to |attachments_|, and notifies the observers.
- void HandleReceivedAttachment(
- const scoped_refptr<BrokerableAttachment>& attachment);
-
- // Informs the observers that a new BrokerableAttachment has been received.
- void NotifyObservers(const BrokerableAttachment::AttachmentId& id);
-
- // Informs the observer identified by |unique_id| that a new
- // BrokerableAttachment has been received.
- void NotifyObserver(int unique_id,
- const BrokerableAttachment::AttachmentId& id);
-
- // This method is exposed for testing only.
- AttachmentVector* get_attachments() { return &attachments_; }
-
- base::Lock* get_lock() { return &lock_; }
-
- private:
-#if defined(OS_WIN)
- FRIEND_TEST_ALL_PREFIXES(AttachmentBrokerUnprivilegedWinTest,
- ReceiveValidMessage);
- FRIEND_TEST_ALL_PREFIXES(AttachmentBrokerUnprivilegedWinTest,
- ReceiveInvalidMessage);
-#endif // defined(OS_WIN)
-
- // A vector of BrokerableAttachments that have been received, but not yet
- // consumed.
- // A std::vector is used instead of a std::map because this container is
- // expected to have few elements, for which a std::vector is expected to have
- // better performance.
- AttachmentVector attachments_;
-
- struct ObserverInfo {
- ObserverInfo();
- ObserverInfo(const ObserverInfo& other);
- ~ObserverInfo();
-
- Observer* observer;
- int unique_id;
-
- // Notifications must be dispatched onto |runner|.
- scoped_refptr<base::SequencedTaskRunner> runner;
- };
- std::vector<ObserverInfo> observers_;
-
- // This member holds the last id given to an ObserverInfo.
- int last_unique_id_;
-
- // The AttachmentBroker can be accessed from any thread, so modifications to
- // internal state must be guarded by a lock.
- base::Lock lock_;
- DISALLOW_COPY_AND_ASSIGN(AttachmentBroker);
-};
-
-} // namespace IPC
-
-#endif // IPC_ATTACHMENT_BROKER_H_
diff --git a/ipc/brokerable_attachment.cc b/ipc/brokerable_attachment.cc
deleted file mode 100644
index 96ce5bb..0000000
--- a/ipc/brokerable_attachment.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ipc/brokerable_attachment.h"
-
-#include <stddef.h>
-
-#include "build/build_config.h"
-#include "ipc/attachment_broker.h"
-
-namespace IPC {
-
-// BrokerableAttachment::AttachmentId ------------------------------------------
-#if !USE_ATTACHMENT_BROKER
-// static
-BrokerableAttachment::AttachmentId
-BrokerableAttachment::AttachmentId::CreateIdWithRandomNonce() {
- CHECK(false) << "Platforms that don't support attachment brokering shouldn't "
- "be trying to generating a random nonce.";
- return AttachmentId();
-}
-#endif
-
-BrokerableAttachment::AttachmentId::AttachmentId() {
- for (size_t i = 0; i < BrokerableAttachment::kNonceSize; ++i)
- nonce[i] = 0;
-}
-
-BrokerableAttachment::AttachmentId::AttachmentId(const char* start_address,
- size_t size) {
- DCHECK(size == BrokerableAttachment::kNonceSize);
- for (size_t i = 0; i < BrokerableAttachment::kNonceSize; ++i)
- nonce[i] = start_address[i];
-}
-
-void BrokerableAttachment::AttachmentId::SerializeToBuffer(char* start_address,
- size_t size) {
- DCHECK(size == BrokerableAttachment::kNonceSize);
- for (size_t i = 0; i < BrokerableAttachment::kNonceSize; ++i)
- start_address[i] = nonce[i];
-}
-
-// BrokerableAttachment::BrokerableAttachment ----------------------------------
-
-BrokerableAttachment::BrokerableAttachment()
- : id_(AttachmentId::CreateIdWithRandomNonce()) {}
-
-BrokerableAttachment::BrokerableAttachment(const AttachmentId& id) : id_(id) {}
-
-BrokerableAttachment::~BrokerableAttachment() {}
-
-BrokerableAttachment::AttachmentId BrokerableAttachment::GetIdentifier() const {
- return id_;
-}
-
-bool BrokerableAttachment::NeedsBrokering() const {
- return GetBrokerableType() == PLACEHOLDER;
-}
-
-BrokerableAttachment::Type BrokerableAttachment::GetType() const {
- return TYPE_BROKERABLE_ATTACHMENT;
-}
-
-#if defined(OS_POSIX)
-base::PlatformFile BrokerableAttachment::TakePlatformFile() {
- NOTREACHED();
- return base::PlatformFile();
-}
-#endif // OS_POSIX
-
-} // namespace IPC
diff --git a/ipc/brokerable_attachment.h b/ipc/brokerable_attachment.h
deleted file mode 100644
index 50e7fd2..0000000
--- a/ipc/brokerable_attachment.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IPC_BROKERABLE_ATTACHMENT_H_
-#define IPC_BROKERABLE_ATTACHMENT_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-
-#include "base/macros.h"
-#include "build/build_config.h"
-#include "ipc/ipc_export.h"
-#include "ipc/ipc_message_attachment.h"
-
-namespace IPC {
-
-// This subclass of MessageAttachment requires an AttachmentBroker to be
-// attached to a Chrome IPC message.
-class IPC_EXPORT BrokerableAttachment : public MessageAttachment {
- public:
- static const size_t kNonceSize = 16;
- // An id uniquely identifies an attachment sent via a broker.
- struct IPC_EXPORT AttachmentId {
- uint8_t nonce[kNonceSize];
-
- // Generates an AttachmentId with an unguessable, random nonce.
- static AttachmentId CreateIdWithRandomNonce();
-
- // Creates an AttachmentId with a zeroed nonce. This should only be used by
- // the IPC translation system, which requires that classes have a default
- // constructor.
- AttachmentId();
-
- // Constructs an AttachmentId from a buffer.
- AttachmentId(const char* start_address, size_t size);
-
- // Writes the nonce into a buffer.
- void SerializeToBuffer(char* start_address, size_t size);
-
- bool operator==(const AttachmentId& rhs) const {
- return std::equal(nonce, nonce + kNonceSize, rhs.nonce);
- }
-
- bool operator<(const AttachmentId& rhs) const {
- return std::lexicographical_compare(nonce, nonce + kNonceSize, rhs.nonce,
- rhs.nonce + kNonceSize);
- }
- };
-
- enum BrokerableType {
- PLACEHOLDER,
- WIN_HANDLE,
- MACH_PORT,
- };
-
- // The identifier is unique across all Chrome processes.
- AttachmentId GetIdentifier() const;
-
- // Whether the attachment still needs information from the broker before it
- // can be used.
- bool NeedsBrokering() const;
-
- // Returns TYPE_BROKERABLE_ATTACHMENT
- Type GetType() const override;
-
- virtual BrokerableType GetBrokerableType() const = 0;
-
-// MessageAttachment override.
-#if defined(OS_POSIX)
- base::PlatformFile TakePlatformFile() override;
-#endif // OS_POSIX
-
- protected:
- BrokerableAttachment();
- BrokerableAttachment(const AttachmentId& id);
- ~BrokerableAttachment() override;
-
- private:
- // This member uniquely identifies a BrokerableAttachment across all Chrome
- // processes.
- const AttachmentId id_;
-
- DISALLOW_COPY_AND_ASSIGN(BrokerableAttachment);
-};
-
-} // namespace IPC
-
-#endif // IPC_BROKERABLE_ATTACHMENT_H_
diff --git a/ipc/ipc.mojom b/ipc/ipc.mojom
new file mode 100644
index 0000000..0a4fcfa
--- /dev/null
+++ b/ipc/ipc.mojom
@@ -0,0 +1,40 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module IPC.mojom;
+
+// NOTE: This MUST match the value of MSG_ROUTING_NONE in src/ipc/ipc_message.h.
+const int32 kRoutingIdNone = -2;
+
+struct SerializedHandle {
+ handle the_handle;
+
+ enum Type {
+ MOJO_HANDLE,
+ PLATFORM_FILE,
+ WIN_HANDLE,
+ MACH_PORT,
+ };
+
+ Type type;
+};
+
+// A placeholder interface type since we don't yet support generic associated
+// message pipe handles.
+interface GenericInterface {};
+
+interface Channel {
+ // Informs the remote end of this client's PID. Must be called exactly once,
+ // before any calls to Receive() below.
+ SetPeerPid(int32 pid);
+
+ // Transmits a classical Chrome IPC message.
+ Receive(array<uint8> data, array<SerializedHandle>? handles);
+
+ // Requests a Channel-associated interface.
+ GetAssociatedInterface(string name, associated GenericInterface& request);
+};
+
+// A strictly nominal interface used to identify Channel bootstrap requests.
+interface ChannelBootstrap {};
diff --git a/ipc/ipc_channel_handle.h b/ipc/ipc_channel_handle.h
index 2e9dc3e..ef31b84 100644
--- a/ipc/ipc_channel_handle.h
+++ b/ipc/ipc_channel_handle.h
@@ -10,60 +10,31 @@
#include "build/build_config.h"
#include "mojo/public/cpp/system/message_pipe.h"
-#if defined(OS_POSIX)
+#if defined(OS_NACL_SFI)
#include "base/file_descriptor_posix.h"
-#elif defined(OS_WIN)
-#include <windows.h>
-#endif // defined (OS_WIN)
-
-// On Windows, any process can create an IPC channel and others can fetch
-// it by name. We pass around the channel names over IPC.
-// On Windows the initialization of ChannelHandle with an existing pipe
-// handle is provided for convenience.
-// NOTE: A ChannelHandle with a pipe handle Will NOT be marshalled over IPC.
-
-// On POSIX, we instead pass around handles to channel endpoints via IPC.
-// When it's time to IPC a new channel endpoint around, we send both the
-// channel name as well as a base::FileDescriptor, which is itself a special
-// type that knows how to copy a socket endpoint over IPC.
-//
-// In sum, this data structure can be used to pass channel information by name
-// in both Windows and Posix. When passing a handle to a channel over IPC,
-// use this data structure only for POSIX.
+#endif // defined (OS_NACL_SFI)
namespace IPC {
+// Note that serialization for this object is defined in the ParamTraits
+// template specialization in ipc_message_utils.h.
+#if defined(OS_NACL_SFI)
struct ChannelHandle {
- // Note that serialization for this object is defined in the ParamTraits
- // template specialization in ipc_message_utils.h.
ChannelHandle() {}
- // The name that is passed in should be an absolute path for Posix.
- // Otherwise there may be a problem in IPC communication between
- // processes with different working directories.
- ChannelHandle(const std::string& n) : name(n) {}
- ChannelHandle(const char* n) : name(n) {}
-#if defined(OS_WIN)
- explicit ChannelHandle(HANDLE h) : pipe(h) {}
-#elif defined(OS_POSIX)
- ChannelHandle(const std::string& n, const base::FileDescriptor& s)
- : name(n), socket(s) {}
-#endif // defined(OS_POSIX)
- ChannelHandle(mojo::MessagePipeHandle h) : mojo_handle(h) {}
+ explicit ChannelHandle(const base::FileDescriptor& s) : socket(s) {}
- std::string name;
-#if defined(OS_POSIX)
base::FileDescriptor socket;
-#elif defined(OS_WIN)
- // A simple container to automatically initialize pipe handle
- struct PipeHandle {
- PipeHandle() : handle(NULL) {}
- PipeHandle(HANDLE h) : handle(h) {}
- HANDLE handle;
- };
- PipeHandle pipe;
-#endif // defined (OS_WIN)
+};
+#else
+struct ChannelHandle {
+ ChannelHandle() {}
+ ChannelHandle(mojo::MessagePipeHandle h) : mojo_handle(h) {}
+
+ bool is_mojo_channel_handle() const { return mojo_handle.is_valid(); }
+
mojo::MessagePipeHandle mojo_handle;
};
+#endif // defined(OS_NACL_SFI)
} // namespace IPC
diff --git a/ipc/ipc_listener.h b/ipc/ipc_listener.h
index 0277086..d7ad75c 100644
--- a/ipc/ipc_listener.h
+++ b/ipc/ipc_listener.h
@@ -7,8 +7,11 @@
#include <stdint.h>
+#include <string>
+
#include "build/build_config.h"
#include "ipc/ipc_export.h"
+#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
namespace IPC {
@@ -32,6 +35,12 @@ class IPC_EXPORT Listener {
// Called when a message's deserialization failed.
virtual void OnBadMessageReceived(const Message& message) {}
+ // Called when an associated interface request is received on a Channel and
+ // the Channel has no registered handler for it.
+ virtual void OnAssociatedInterfaceRequest(
+ const std::string& interface_name,
+ mojo::ScopedInterfaceEndpointHandle handle) {}
+
#if defined(OS_POSIX)
// Called on the server side when a channel that listens for connections
// denies an attempt to connect.
diff --git a/ipc/ipc_message.cc b/ipc/ipc_message.cc
index 83ee495..f5e9ac7 100644
--- a/ipc/ipc_message.cc
+++ b/ipc/ipc_message.cc
@@ -11,10 +11,8 @@
#include "base/atomic_sequence_num.h"
#include "base/logging.h"
#include "build/build_config.h"
-#include "ipc/attachment_broker.h"
#include "ipc/ipc_message_attachment.h"
#include "ipc/ipc_message_attachment_set.h"
-#include "ipc/placeholder_brokerable_attachment.h"
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
@@ -52,9 +50,6 @@ Message::~Message() {
Message::Message() : base::Pickle(sizeof(Header)) {
header()->routing = header()->type = 0;
header()->flags = GetRefNumUpper24();
-#if USE_ATTACHMENT_BROKER
- header()->num_brokered_attachments = 0;
-#endif
#if defined(OS_POSIX)
header()->num_fds = 0;
header()->pad = 0;
@@ -68,9 +63,6 @@ Message::Message(int32_t routing_id, uint32_t type, PriorityValue priority)
header()->type = type;
DCHECK((priority & 0xffffff00) == 0);
header()->flags = priority | GetRefNumUpper24();
-#if USE_ATTACHMENT_BROKER
- header()->num_brokered_attachments = 0;
-#endif
#if defined(OS_POSIX)
header()->num_fds = 0;
header()->pad = 0;
@@ -86,12 +78,10 @@ Message::Message(const char* data, int data_len)
Message::Message(const Message& other) : base::Pickle(other) {
Init();
attachment_set_ = other.attachment_set_;
- sender_pid_ = other.sender_pid_;
}
void Message::Init() {
dispatch_error_ = false;
- sender_pid_ = base::kNullProcessId;
#ifdef IPC_MESSAGE_LOG_ENABLED
received_time_ = 0;
dont_log_ = false;
@@ -102,7 +92,6 @@ void Message::Init() {
Message& Message::operator=(const Message& other) {
*static_cast<base::Pickle*>(this) = other;
attachment_set_ = other.attachment_set_;
- sender_pid_ = other.sender_pid_;
return *this;
}
@@ -146,26 +135,6 @@ Message::NextMessageInfo::NextMessageInfo()
message_end(nullptr) {}
Message::NextMessageInfo::~NextMessageInfo() {}
-Message::SerializedAttachmentIds
-Message::SerializedIdsOfBrokerableAttachments() {
- DCHECK(HasBrokerableAttachments());
- std::vector<scoped_refptr<IPC::BrokerableAttachment>> attachments(
- attachment_set_->GetBrokerableAttachments());
- CHECK_LE(attachments.size(), std::numeric_limits<size_t>::max() /
- BrokerableAttachment::kNonceSize);
- size_t size = attachments.size() * BrokerableAttachment::kNonceSize;
- char* buffer = static_cast<char*>(malloc(size));
- for (size_t i = 0; i < attachments.size(); ++i) {
- char* start_range = buffer + i * BrokerableAttachment::kNonceSize;
- BrokerableAttachment::AttachmentId id = attachments[i]->GetIdentifier();
- id.SerializeToBuffer(start_range, BrokerableAttachment::kNonceSize);
- }
- SerializedAttachmentIds ids;
- ids.buffer = buffer;
- ids.size = size;
- return ids;
-}
-
// static
void Message::FindNext(const char* range_start,
const char* range_end,
@@ -182,43 +151,6 @@ void Message::FindNext(const char* range_start,
bool have_entire_pickle =
static_cast<size_t>(range_end - range_start) >= pickle_size;
-#if USE_ATTACHMENT_BROKER
- // TODO(dskiba): determine message_size when entire pickle is not available
-
- if (!have_entire_pickle)
- return;
-
- const char* pickle_end = range_start + pickle_size;
-
- // The data is not copied.
- Message message(range_start, static_cast<int>(pickle_size));
- size_t num_attachments = message.header()->num_brokered_attachments;
-
- // Check for possible overflows.
- size_t max_size_t = std::numeric_limits<size_t>::max();
- if (num_attachments >= max_size_t / BrokerableAttachment::kNonceSize)
- return;
-
- size_t attachment_length = num_attachments * BrokerableAttachment::kNonceSize;
- if (pickle_size > max_size_t - attachment_length)
- return;
-
- // Check whether the range includes the attachments.
- size_t buffer_length = static_cast<size_t>(range_end - range_start);
- if (buffer_length < attachment_length + pickle_size)
- return;
-
- for (size_t i = 0; i < num_attachments; ++i) {
- const char* attachment_start =
- pickle_end + i * BrokerableAttachment::kNonceSize;
- BrokerableAttachment::AttachmentId id(attachment_start,
- BrokerableAttachment::kNonceSize);
- info->attachment_ids.push_back(id);
- }
- info->message_end =
- pickle_end + num_attachments * BrokerableAttachment::kNonceSize;
- info->message_size = info->message_end - range_start;
-#else
info->message_size = pickle_size;
if (!have_entire_pickle)
@@ -227,53 +159,32 @@ void Message::FindNext(const char* range_start,
const char* pickle_end = range_start + pickle_size;
info->message_end = pickle_end;
-#endif // USE_ATTACHMENT_BROKER
info->pickle_end = pickle_end;
info->message_found = true;
}
-bool Message::AddPlaceholderBrokerableAttachmentWithId(
- BrokerableAttachment::AttachmentId id) {
- scoped_refptr<PlaceholderBrokerableAttachment> attachment(
- new PlaceholderBrokerableAttachment(id));
- return attachment_set()->AddAttachment(attachment);
-}
-
bool Message::WriteAttachment(
scoped_refptr<base::Pickle::Attachment> attachment) {
- bool brokerable;
size_t index;
bool success = attachment_set()->AddAttachment(
make_scoped_refptr(static_cast<MessageAttachment*>(attachment.get())),
- &index, &brokerable);
+ &index);
DCHECK(success);
// NOTE: If you add more data to the pickle, make sure to update
// PickleSizer::AddAttachment.
- // Write the type of descriptor.
- WriteBool(brokerable);
-
// Write the index of the descriptor so that we don't have to
// keep the current descriptor as extra decoding state when deserialising.
WriteInt(static_cast<int>(index));
-#if USE_ATTACHMENT_BROKER
- if (brokerable)
- header()->num_brokered_attachments++;
-#endif
-
return success;
}
bool Message::ReadAttachment(
base::PickleIterator* iter,
scoped_refptr<base::Pickle::Attachment>* attachment) const {
- bool brokerable;
- if (!iter->ReadBool(&brokerable))
- return false;
-
int index;
if (!iter->ReadInt(&index))
return false;
@@ -282,9 +193,7 @@ bool Message::ReadAttachment(
if (!attachment_set)
return false;
- *attachment = brokerable
- ? attachment_set->GetBrokerableAttachmentAt(index)
- : attachment_set->GetNonBrokerableAttachmentAt(index);
+ *attachment = attachment_set->GetAttachmentAt(index);
return nullptr != attachment->get();
}
@@ -293,13 +202,4 @@ bool Message::HasAttachments() const {
return attachment_set_.get() && !attachment_set_->empty();
}
-bool Message::HasMojoHandles() const {
- return attachment_set_.get() && attachment_set_->num_mojo_handles() > 0;
-}
-
-bool Message::HasBrokerableAttachments() const {
- return attachment_set_.get() &&
- attachment_set_->num_brokerable_attachments() > 0;
-}
-
} // namespace IPC
diff --git a/ipc/ipc_message.h b/ipc/ipc_message.h
index 56c3a46..43e9ae3 100644
--- a/ipc/ipc_message.h
+++ b/ipc/ipc_message.h
@@ -15,8 +15,6 @@
#include "base/pickle.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
-#include "ipc/attachment_broker.h"
-#include "ipc/brokerable_attachment.h"
#include "ipc/ipc_export.h"
#if !defined(NDEBUG)
@@ -32,7 +30,6 @@ class ChannelReader;
//------------------------------------------------------------------------------
struct LogData;
-class MessageAttachment;
class MessageAttachmentSet;
class IPC_EXPORT Message : public base::Pickle {
@@ -191,34 +188,13 @@ class IPC_EXPORT Message : public base::Pickle {
// The end address of the message should be used to determine the start
// address of the next message.
const char* message_end;
- // If the message has brokerable attachments, this vector will contain the
- // ids of the brokerable attachments. The caller of FindNext() is
- // responsible for adding the attachments to the message.
- std::vector<BrokerableAttachment::AttachmentId> attachment_ids;
};
- struct SerializedAttachmentIds {
- void* buffer;
- size_t size;
- };
- // Creates a buffer that contains a serialization of the ids of the brokerable
- // attachments of the message. This buffer is intended to be sent over the IPC
- // channel immediately after the pickled message. The caller takes ownership
- // of the buffer.
- // This method should only be called if the message has brokerable
- // attachments.
- SerializedAttachmentIds SerializedIdsOfBrokerableAttachments();
-
// |info| is an output parameter and must not be nullptr.
static void FindNext(const char* range_start,
const char* range_end,
NextMessageInfo* info);
- // Adds a placeholder brokerable attachment that must be replaced before the
- // message can be dispatched.
- bool AddPlaceholderBrokerableAttachmentWithId(
- BrokerableAttachment::AttachmentId id);
-
// WriteAttachment appends |attachment| to the end of the set. It returns
// false iff the set is full.
bool WriteAttachment(
@@ -230,13 +206,6 @@ class IPC_EXPORT Message : public base::Pickle {
scoped_refptr<base::Pickle::Attachment>* attachment) const override;
// Returns true if there are any attachment in this message.
bool HasAttachments() const override;
- // Returns true if there are any MojoHandleAttachments in this message.
- bool HasMojoHandles() const;
- // Whether the message has any brokerable attachments.
- bool HasBrokerableAttachments() const;
-
- void set_sender_pid(base::ProcessId id) { sender_pid_ = id; }
- base::ProcessId get_sender_pid() const { return sender_pid_; }
#ifdef IPC_MESSAGE_LOG_ENABLED
// Adds the outgoing time from Time::Now() at the end of the message and sets
@@ -273,12 +242,6 @@ class IPC_EXPORT Message : public base::Pickle {
int32_t routing; // ID of the view that this message is destined for
uint32_t type; // specifies the user-defined message type
uint32_t flags; // specifies control flags for the message
-#if USE_ATTACHMENT_BROKER
- // The number of brokered attachments included with this message. The
- // ids of the brokered attachment ids are sent immediately after the pickled
- // message, before the next pickled message is sent.
- uint32_t num_brokered_attachments;
-#endif
#if defined(OS_POSIX)
uint16_t num_fds; // the number of descriptors included with this message
uint16_t pad; // explicitly initialize this to appease valgrind
@@ -312,10 +275,6 @@ class IPC_EXPORT Message : public base::Pickle {
return attachment_set_.get();
}
- // The process id of the sender of the message. This member is populated with
- // a valid value for every message dispatched to listeners.
- base::ProcessId sender_pid_;
-
#ifdef IPC_MESSAGE_LOG_ENABLED
// Used for logging.
mutable int64_t received_time_;
diff --git a/ipc/ipc_message_attachment.h b/ipc/ipc_message_attachment.h
index 7f7137d..9ff1de8 100644
--- a/ipc/ipc_message_attachment.h
+++ b/ipc/ipc_message_attachment.h
@@ -10,6 +10,7 @@
#include "base/memory/ref_counted.h"
#include "base/pickle.h"
#include "build/build_config.h"
+#include "ipc/ipc.mojom.h"
#include "ipc/ipc_export.h"
namespace IPC {
@@ -18,18 +19,10 @@ namespace IPC {
// or a mojo |MessagePipe|. |GetType()| returns the type of the subclass.
class IPC_EXPORT MessageAttachment : public base::Pickle::Attachment {
public:
- enum Type {
- TYPE_PLATFORM_FILE, // The instance is |PlatformFileAttachment|.
- TYPE_MOJO_HANDLE, // The instance is |MojoHandleAttachment|.
- TYPE_BROKERABLE_ATTACHMENT, // The instance is |BrokerableAttachment|.
- };
+ using Type = mojom::SerializedHandle::Type;
virtual Type GetType() const = 0;
-#if defined(OS_POSIX)
- virtual base::PlatformFile TakePlatformFile() = 0;
-#endif // OS_POSIX
-
protected:
friend class base::RefCountedThreadSafe<MessageAttachment>;
MessageAttachment();
diff --git a/ipc/ipc_message_attachment_set.cc b/ipc/ipc_message_attachment_set.cc
index 3b7eefb..b9a990d 100644
--- a/ipc/ipc_message_attachment_set.cc
+++ b/ipc/ipc_message_attachment_set.cc
@@ -11,16 +11,8 @@
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "build/build_config.h"
-#include "ipc/brokerable_attachment.h"
#include "ipc/ipc_message_attachment.h"
-#if defined(OS_POSIX)
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include "ipc/ipc_platform_file_attachment_posix.h"
-#endif // OS_POSIX
-
namespace IPC {
namespace {
@@ -43,7 +35,7 @@ MessageAttachmentSet::MessageAttachmentSet()
}
MessageAttachmentSet::~MessageAttachmentSet() {
- if (consumed_descriptor_highwater_ == num_non_brokerable_attachments())
+ if (consumed_descriptor_highwater_ == size())
return;
// We close all the owning descriptors. If this message should have
@@ -54,39 +46,24 @@ MessageAttachmentSet::~MessageAttachmentSet() {
// (which could a DOS against the browser by a rogue renderer) then all
// the descriptors have their close flag set and we free all the extra
// kernel resources.
- LOG(WARNING) << "MessageAttachmentSet destroyed with unconsumed descriptors: "
- << consumed_descriptor_highwater_ << "/" << num_descriptors();
+ LOG(WARNING) << "MessageAttachmentSet destroyed with unconsumed attachments: "
+ << consumed_descriptor_highwater_ << "/" << size();
}
unsigned MessageAttachmentSet::num_descriptors() const {
return count_attachments_of_type(attachments_,
- MessageAttachment::TYPE_PLATFORM_FILE);
-}
-
-unsigned MessageAttachmentSet::num_mojo_handles() const {
- return count_attachments_of_type(attachments_,
- MessageAttachment::TYPE_MOJO_HANDLE);
-}
-
-unsigned MessageAttachmentSet::num_brokerable_attachments() const {
- return static_cast<unsigned>(brokerable_attachments_.size());
-}
-
-unsigned MessageAttachmentSet::num_non_brokerable_attachments() const {
- return static_cast<unsigned>(attachments_.size());
+ MessageAttachment::Type::PLATFORM_FILE);
}
unsigned MessageAttachmentSet::size() const {
- return static_cast<unsigned>(attachments_.size() +
- brokerable_attachments_.size());
+ return static_cast<unsigned>(attachments_.size());
}
bool MessageAttachmentSet::AddAttachment(
scoped_refptr<MessageAttachment> attachment,
- size_t* index,
- bool* brokerable) {
+ size_t* index) {
#if defined(OS_POSIX)
- if (attachment->GetType() == MessageAttachment::TYPE_PLATFORM_FILE &&
+ if (attachment->GetType() == MessageAttachment::Type::PLATFORM_FILE &&
num_descriptors() == kMaxDescriptorsPerMessage) {
DLOG(WARNING) << "Cannot add file descriptor. MessageAttachmentSet full.";
return false;
@@ -94,19 +71,12 @@ bool MessageAttachmentSet::AddAttachment(
#endif
switch (attachment->GetType()) {
- case MessageAttachment::TYPE_PLATFORM_FILE:
- case MessageAttachment::TYPE_MOJO_HANDLE:
+ case MessageAttachment::Type::PLATFORM_FILE:
+ case MessageAttachment::Type::MOJO_HANDLE:
+ case MessageAttachment::Type::WIN_HANDLE:
+ case MessageAttachment::Type::MACH_PORT:
attachments_.push_back(attachment);
*index = attachments_.size() - 1;
- *brokerable = false;
- return true;
- case MessageAttachment::TYPE_BROKERABLE_ATTACHMENT:
- BrokerableAttachment* brokerable_attachment =
- static_cast<BrokerableAttachment*>(attachment.get());
- scoped_refptr<BrokerableAttachment> a(brokerable_attachment);
- brokerable_attachments_.push_back(a);
- *index = brokerable_attachments_.size() - 1;
- *brokerable = true;
return true;
}
return false;
@@ -114,16 +84,14 @@ bool MessageAttachmentSet::AddAttachment(
bool MessageAttachmentSet::AddAttachment(
scoped_refptr<MessageAttachment> attachment) {
- bool brokerable;
size_t index;
- return AddAttachment(attachment, &index, &brokerable);
+ return AddAttachment(attachment, &index);
}
-scoped_refptr<MessageAttachment>
-MessageAttachmentSet::GetNonBrokerableAttachmentAt(unsigned index) {
- if (index >= num_non_brokerable_attachments()) {
- DLOG(WARNING) << "Accessing out of bound index:" << index << "/"
- << num_non_brokerable_attachments();
+scoped_refptr<MessageAttachment> MessageAttachmentSet::GetAttachmentAt(
+ unsigned index) {
+ if (index >= size()) {
+ DLOG(WARNING) << "Accessing out of bound index:" << index << "/" << size();
return scoped_refptr<MessageAttachment>();
}
@@ -148,8 +116,7 @@ MessageAttachmentSet::GetNonBrokerableAttachmentAt(unsigned index) {
// end of the array and index 0 is requested, we reset the highwater value.
// TODO(morrita): This is absurd. This "wringle" disallow to introduce clearer
// ownership model. Only client is NaclIPCAdapter. See crbug.com/415294
- if (index == 0 &&
- consumed_descriptor_highwater_ == num_non_brokerable_attachments()) {
+ if (index == 0 && consumed_descriptor_highwater_ == size()) {
consumed_descriptor_highwater_ = 0;
}
@@ -161,90 +128,9 @@ MessageAttachmentSet::GetNonBrokerableAttachmentAt(unsigned index) {
return attachments_[index];
}
-scoped_refptr<MessageAttachment>
-MessageAttachmentSet::GetBrokerableAttachmentAt(unsigned index) {
- if (index >= num_brokerable_attachments()) {
- DLOG(WARNING) << "Accessing out of bound index:" << index << "/"
- << num_brokerable_attachments();
- return scoped_refptr<MessageAttachment>();
- }
-
- scoped_refptr<BrokerableAttachment> brokerable_attachment(
- brokerable_attachments_[index]);
- return scoped_refptr<MessageAttachment>(brokerable_attachment.get());
-}
-
void MessageAttachmentSet::CommitAllDescriptors() {
attachments_.clear();
consumed_descriptor_highwater_ = 0;
}
-std::vector<scoped_refptr<IPC::BrokerableAttachment>>
-MessageAttachmentSet::GetBrokerableAttachments() const {
- return brokerable_attachments_;
-}
-
-void MessageAttachmentSet::ReplacePlaceholderWithAttachment(
- const scoped_refptr<BrokerableAttachment>& attachment) {
- DCHECK_NE(BrokerableAttachment::PLACEHOLDER, attachment->GetBrokerableType());
- for (auto it = brokerable_attachments_.begin();
- it != brokerable_attachments_.end(); ++it) {
- if ((*it)->GetBrokerableType() == BrokerableAttachment::PLACEHOLDER &&
- (*it)->GetIdentifier() == attachment->GetIdentifier()) {
- *it = attachment;
- return;
- }
- }
-
- // This function should only be called if there is a placeholder ready to be
- // replaced.
- NOTREACHED();
-}
-
-#if defined(OS_POSIX)
-
-void MessageAttachmentSet::PeekDescriptors(base::PlatformFile* buffer) const {
- for (size_t i = 0; i != attachments_.size(); ++i)
- buffer[i] = internal::GetPlatformFile(attachments_[i]);
-}
-
-bool MessageAttachmentSet::ContainsDirectoryDescriptor() const {
- struct stat st;
-
- for (auto i = attachments_.begin(); i != attachments_.end(); ++i) {
- if (fstat(internal::GetPlatformFile(*i), &st) == 0 && S_ISDIR(st.st_mode))
- return true;
- }
-
- return false;
-}
-
-void MessageAttachmentSet::ReleaseFDsToClose(
- std::vector<base::PlatformFile>* fds) {
- for (size_t i = 0; i < attachments_.size(); ++i) {
- internal::PlatformFileAttachment* file =
- static_cast<internal::PlatformFileAttachment*>(attachments_[i].get());
- if (file->Owns())
- fds->push_back(file->TakePlatformFile());
- }
-
- CommitAllDescriptors();
-}
-
-void MessageAttachmentSet::AddDescriptorsToOwn(const base::PlatformFile* buffer,
- unsigned count) {
- DCHECK(count <= kMaxDescriptorsPerMessage);
- DCHECK_EQ(num_descriptors(), 0u);
- DCHECK_EQ(consumed_descriptor_highwater_, 0u);
-
- attachments_.reserve(count);
- for (unsigned i = 0; i < count; ++i)
- AddAttachment(
- new internal::PlatformFileAttachment(base::ScopedFD(buffer[i])));
-}
-
-#endif // OS_POSIX
-
} // namespace IPC
-
-
diff --git a/ipc/ipc_message_attachment_set.h b/ipc/ipc_message_attachment_set.h
index 764c818..de37211 100644
--- a/ipc/ipc_message_attachment_set.h
+++ b/ipc/ipc_message_attachment_set.h
@@ -14,31 +14,17 @@
#include "build/build_config.h"
#include "ipc/ipc_export.h"
-#if defined(OS_POSIX)
-#include "base/files/file.h"
-#endif
-
namespace IPC {
-class BrokerableAttachment;
class MessageAttachment;
// -----------------------------------------------------------------------------
// A MessageAttachmentSet is an ordered set of MessageAttachment objects
-// associated with an IPC message. There are three types of MessageAttachments:
-// 1) TYPE_PLATFORM_FILE is transmitted over the Channel's underlying
-// UNIX domain socket
-// 2) TYPE_MOJO_HANDLE is transmitted over the Mojo MessagePipe.
-// 3) TYPE_BROKERABLE_ATTACHMENT is transmitted by the Attachment Broker.
-// Any given IPC Message can have attachments of type (1) or (2), but not both.
-// These are stored in |attachments_|. Attachments of type (3) are stored in
-// |brokerable_attachments_|.
-//
-// To produce a deterministic ordering, all attachments in |attachments_| are
-// considered to come before those in |brokerable_attachments_|. These
-// attachments are transmitted across different communication channels, and
-// multiplexed by the receiver, so ordering between them cannot be guaranteed.
+// associated with an IPC message. All attachments are wrapped in a mojo handle
+// if necessary and sent over the mojo message pipe.
//
+// For ChannelNacl under SFI NaCl, only Type::PLATFORM_FILE is supported. In
+// that case, the FD is sent over socket.
// -----------------------------------------------------------------------------
class IPC_EXPORT MessageAttachmentSet
: public base::RefCountedThreadSafe<MessageAttachmentSet> {
@@ -47,57 +33,31 @@ class IPC_EXPORT MessageAttachmentSet
// Return the number of attachments
unsigned size() const;
- // Return the number of file descriptors
- unsigned num_descriptors() const;
- // Return the number of mojo handles in the attachment set
- unsigned num_mojo_handles() const;
- // Return the number of brokerable attachments in the attachment set.
- unsigned num_brokerable_attachments() const;
- // Return the number of non-brokerable attachments in the attachment set.
- unsigned num_non_brokerable_attachments() const;
// Return true if no unconsumed descriptors remain
- bool empty() const { return 0 == size(); }
+ bool empty() const { return attachments_.empty(); }
// Returns whether the attachment was successfully added.
// |index| is an output variable. On success, it contains the index of the
// newly added attachment.
- // |brokerable| is an output variable. On success, it describes which vector
- // the attachment was added to.
bool AddAttachment(scoped_refptr<MessageAttachment> attachment,
- size_t* index,
- bool* brokerable);
+ size_t* index);
// Similar to the above method, but without output variables.
bool AddAttachment(scoped_refptr<MessageAttachment> attachment);
- // Take the nth non-brokerable attachment from the beginning of the vector,
- // Code using this /must/ access the attachments in order, and must do it at
- // most once.
+ // Take the nth from the beginning of the vector, Code using this /must/
+ // access the attachments in order, and must do it at most once.
//
// This interface is designed for the deserialising code as it doesn't
// support close flags.
// returns: an attachment, or nullptr on error
- scoped_refptr<MessageAttachment> GetNonBrokerableAttachmentAt(unsigned index);
+ scoped_refptr<MessageAttachment> GetAttachmentAt(unsigned index);
- // Similar to GetNonBrokerableAttachmentAt, but there are no ordering
- // requirements.
- scoped_refptr<MessageAttachment> GetBrokerableAttachmentAt(unsigned index);
-
- // This must be called after transmitting the descriptors returned by
- // PeekDescriptors. It marks all the non-brokerable descriptors as consumed
- // and closes those which are auto-close.
+ // Marks all the descriptors as consumed and closes those which are
+ // auto-close.
void CommitAllDescriptors();
- // Returns a vector of all brokerable attachments.
- std::vector<scoped_refptr<IPC::BrokerableAttachment>>
- GetBrokerableAttachments() const;
-
- // Replaces a placeholder brokerable attachment with |attachment|, matching
- // them by their id.
- void ReplacePlaceholderWithAttachment(
- const scoped_refptr<BrokerableAttachment>& attachment);
-
#if defined(OS_POSIX)
// This is the maximum number of descriptors per message. We need to know this
// because the control message kernel interface has to be given a buffer which
@@ -108,32 +68,6 @@ class IPC_EXPORT MessageAttachmentSet
// In debugging mode, it's a fatal error to try and add more than this number
// of descriptors to a MessageAttachmentSet.
static const size_t kMaxDescriptorsPerMessage = 7;
-
- // ---------------------------------------------------------------------------
- // Interfaces for transmission...
-
- // Fill an array with file descriptors without 'consuming' them.
- // CommitAllDescriptors must be called after these descriptors have been
- // transmitted.
- // buffer: (output) a buffer of, at least, size() integers.
- void PeekDescriptors(base::PlatformFile* buffer) const;
- // Returns true if any contained file descriptors appear to be handles to a
- // directory.
- bool ContainsDirectoryDescriptor() const;
- // Fetch all filedescriptors with the "auto close" property. Used instead of
- // CommitAllDescriptors() when closing must be handled manually.
- void ReleaseFDsToClose(std::vector<base::PlatformFile>* fds);
-
- // ---------------------------------------------------------------------------
-
- // ---------------------------------------------------------------------------
- // Interfaces for receiving...
-
- // Set the contents of the set from the given buffer. This set must be empty
- // before calling. The auto-close flag is set on all the descriptors so that
- // unconsumed descriptors are closed on destruction.
- void AddDescriptorsToOwn(const base::PlatformFile* buffer, unsigned count);
-
#endif // OS_POSIX
// ---------------------------------------------------------------------------
@@ -143,17 +77,16 @@ class IPC_EXPORT MessageAttachmentSet
~MessageAttachmentSet();
- // All elements either have type TYPE_PLATFORM_FILE or TYPE_MOJO_HANDLE.
- std::vector<scoped_refptr<MessageAttachment>> attachments_;
+ // Return the number of file descriptors
+ unsigned num_descriptors() const;
- // All elements have type TYPE_BROKERABLE_ATTACHMENT.
- std::vector<scoped_refptr<BrokerableAttachment>> brokerable_attachments_;
+ std::vector<scoped_refptr<MessageAttachment>> attachments_;
// This contains the index of the next descriptor which should be consumed.
// It's used in a couple of ways. Firstly, at destruction we can check that
// all the descriptors have been read (with GetNthDescriptor). Secondly, we
// can check that they are read in order.
- mutable unsigned consumed_descriptor_highwater_;
+ unsigned consumed_descriptor_highwater_;
DISALLOW_COPY_AND_ASSIGN(MessageAttachmentSet);
};
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h
index c1e1b9f..3c41f04 100644
--- a/ipc/ipc_message_start.h
+++ b/ipc/ipc_message_start.h
@@ -29,9 +29,7 @@ enum IPCMessageStart {
FileUtilitiesMsgStart,
DatabaseMsgStart,
DOMStorageMsgStart,
- IndexedDBMsgStart,
SpeechRecognitionMsgStart,
- AutofillMsgStart,
SafeBrowsingMsgStart,
P2PMsgStart,
ResourceMsgStart,
@@ -86,7 +84,6 @@ enum IPCMessageStart {
ScreenOrientationMsgStart,
MediaStreamTrackMetricsHostMsgStart,
ChromeExtensionMsgStart,
- TranslateMsgStart,
PushMessagingMsgStart,
GinJavaBridgeMsgStart,
ChromeUtilityPrintingMsgStart,
@@ -110,13 +107,11 @@ enum IPCMessageStart {
CastCryptoMsgStart,
CastChannelMsgStart,
DataReductionProxyStart,
- ContentSettingsMsgStart,
ChromeAppBannerMsgStart,
AttachmentBrokerMsgStart,
RenderProcessMsgStart,
PageLoadMetricsMsgStart,
MemoryMsgStart,
- MediaSessionMsgStart,
IPCTestMsgStart,
ArcInstanceMsgStart,
ArcInstanceHostMsgStart,
diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc
index 60c12ab..bf8daa5 100644
--- a/ipc/ipc_message_utils.cc
+++ b/ipc/ipc_message_utils.cc
@@ -13,6 +13,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
+#include "base/unguessable_token.h"
#include "base/values.h"
#include "build/build_config.h"
#include "ipc/ipc_channel_handle.h"
@@ -21,6 +22,7 @@
#include "ipc/ipc_mojo_param_traits.h"
#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
#include "ipc/ipc_platform_file_attachment_posix.h"
#endif
@@ -41,7 +43,7 @@ namespace IPC {
namespace {
-const int kMaxRecursionDepth = 100;
+const int kMaxRecursionDepth = 200;
template<typename CharType>
void LogBytes(const std::vector<CharType>& data, std::string* out) {
@@ -76,25 +78,25 @@ void GetValueSize(base::PickleSizer* sizer,
const base::Value* value,
int recursion) {
if (recursion > kMaxRecursionDepth) {
- LOG(WARNING) << "Max recursion depth hit in GetValueSize.";
+ LOG(ERROR) << "Max recursion depth hit in GetValueSize.";
return;
}
sizer->AddInt();
switch (value->GetType()) {
- case base::Value::TYPE_NULL:
+ case base::Value::Type::NONE:
break;
- case base::Value::TYPE_BOOLEAN:
+ case base::Value::Type::BOOLEAN:
sizer->AddBool();
break;
- case base::Value::TYPE_INTEGER:
+ case base::Value::Type::INTEGER:
sizer->AddInt();
break;
- case base::Value::TYPE_DOUBLE:
+ case base::Value::Type::DOUBLE:
sizer->AddDouble();
break;
- case base::Value::TYPE_STRING: {
- const base::StringValue* result;
+ case base::Value::Type::STRING: {
+ const base::Value* result;
value->GetAsString(&result);
if (value->GetAsString(&result)) {
DCHECK(result);
@@ -107,13 +109,11 @@ void GetValueSize(base::PickleSizer* sizer,
}
break;
}
- case base::Value::TYPE_BINARY: {
- const base::BinaryValue* binary =
- static_cast<const base::BinaryValue*>(value);
- sizer->AddData(static_cast<int>(binary->GetSize()));
+ case base::Value::Type::BINARY: {
+ sizer->AddData(static_cast<int>(value->GetSize()));
break;
}
- case base::Value::TYPE_DICTIONARY: {
+ case base::Value::Type::DICTIONARY: {
sizer->AddInt();
const base::DictionaryValue* dict =
static_cast<const base::DictionaryValue*>(value);
@@ -124,7 +124,7 @@ void GetValueSize(base::PickleSizer* sizer,
}
break;
}
- case base::Value::TYPE_LIST: {
+ case base::Value::Type::LIST: {
sizer->AddInt();
const base::ListValue* list = static_cast<const base::ListValue*>(value);
for (const auto& entry : *list) {
@@ -140,50 +140,48 @@ void GetValueSize(base::PickleSizer* sizer,
void WriteValue(base::Pickle* m, const base::Value* value, int recursion) {
bool result;
if (recursion > kMaxRecursionDepth) {
- LOG(WARNING) << "Max recursion depth hit in WriteValue.";
+ LOG(ERROR) << "Max recursion depth hit in WriteValue.";
return;
}
- m->WriteInt(value->GetType());
+ m->WriteInt(static_cast<int>(value->GetType()));
switch (value->GetType()) {
- case base::Value::TYPE_NULL:
+ case base::Value::Type::NONE:
break;
- case base::Value::TYPE_BOOLEAN: {
+ case base::Value::Type::BOOLEAN: {
bool val;
result = value->GetAsBoolean(&val);
DCHECK(result);
WriteParam(m, val);
break;
}
- case base::Value::TYPE_INTEGER: {
+ case base::Value::Type::INTEGER: {
int val;
result = value->GetAsInteger(&val);
DCHECK(result);
WriteParam(m, val);
break;
}
- case base::Value::TYPE_DOUBLE: {
+ case base::Value::Type::DOUBLE: {
double val;
result = value->GetAsDouble(&val);
DCHECK(result);
WriteParam(m, val);
break;
}
- case base::Value::TYPE_STRING: {
+ case base::Value::Type::STRING: {
std::string val;
result = value->GetAsString(&val);
DCHECK(result);
WriteParam(m, val);
break;
}
- case base::Value::TYPE_BINARY: {
- const base::BinaryValue* binary =
- static_cast<const base::BinaryValue*>(value);
- m->WriteData(binary->GetBuffer(), static_cast<int>(binary->GetSize()));
+ case base::Value::Type::BINARY: {
+ m->WriteData(value->GetBuffer(), static_cast<int>(value->GetSize()));
break;
}
- case base::Value::TYPE_DICTIONARY: {
+ case base::Value::Type::DICTIONARY: {
const base::DictionaryValue* dict =
static_cast<const base::DictionaryValue*>(value);
@@ -196,7 +194,7 @@ void WriteValue(base::Pickle* m, const base::Value* value, int recursion) {
}
break;
}
- case base::Value::TYPE_LIST: {
+ case base::Value::Type::LIST: {
const base::ListValue* list = static_cast<const base::ListValue*>(value);
WriteParam(m, static_cast<int>(list->GetSize()));
for (const auto& entry : *list) {
@@ -254,7 +252,7 @@ bool ReadValue(const base::Pickle* m,
base::Value** value,
int recursion) {
if (recursion > kMaxRecursionDepth) {
- LOG(WARNING) << "Max recursion depth hit in ReadValue.";
+ LOG(ERROR) << "Max recursion depth hit in ReadValue.";
return false;
}
@@ -262,39 +260,39 @@ bool ReadValue(const base::Pickle* m,
if (!ReadParam(m, iter, &type))
return false;
- switch (type) {
- case base::Value::TYPE_NULL:
+ switch (static_cast<base::Value::Type>(type)) {
+ case base::Value::Type::NONE:
*value = base::Value::CreateNullValue().release();
break;
- case base::Value::TYPE_BOOLEAN: {
+ case base::Value::Type::BOOLEAN: {
bool val;
if (!ReadParam(m, iter, &val))
return false;
- *value = new base::FundamentalValue(val);
+ *value = new base::Value(val);
break;
}
- case base::Value::TYPE_INTEGER: {
+ case base::Value::Type::INTEGER: {
int val;
if (!ReadParam(m, iter, &val))
return false;
- *value = new base::FundamentalValue(val);
+ *value = new base::Value(val);
break;
}
- case base::Value::TYPE_DOUBLE: {
+ case base::Value::Type::DOUBLE: {
double val;
if (!ReadParam(m, iter, &val))
return false;
- *value = new base::FundamentalValue(val);
+ *value = new base::Value(val);
break;
}
- case base::Value::TYPE_STRING: {
+ case base::Value::Type::STRING: {
std::string val;
if (!ReadParam(m, iter, &val))
return false;
- *value = new base::StringValue(val);
+ *value = new base::Value(val);
break;
}
- case base::Value::TYPE_BINARY: {
+ case base::Value::Type::BINARY: {
const char* data;
int length;
if (!iter->ReadData(&data, &length))
@@ -304,14 +302,14 @@ bool ReadValue(const base::Pickle* m,
*value = val.release();
break;
}
- case base::Value::TYPE_DICTIONARY: {
+ case base::Value::Type::DICTIONARY: {
std::unique_ptr<base::DictionaryValue> val(new base::DictionaryValue());
if (!ReadDictionaryValue(m, iter, val.get(), recursion))
return false;
*value = val.release();
break;
}
- case base::Value::TYPE_LIST: {
+ case base::Value::Type::LIST: {
std::unique_ptr<base::ListValue> val(new base::ListValue());
if (!ReadListValue(m, iter, val.get(), recursion))
return false;
@@ -586,28 +584,6 @@ void ParamTraits<std::vector<bool> >::Log(const param_type& p, std::string* l) {
}
}
-void ParamTraits<BrokerableAttachment::AttachmentId>::Write(
- base::Pickle* m,
- const param_type& p) {
- m->WriteBytes(p.nonce, BrokerableAttachment::kNonceSize);
-}
-
-bool ParamTraits<BrokerableAttachment::AttachmentId>::Read(
- const base::Pickle* m,
- base::PickleIterator* iter,
- param_type* r) {
- const char* data;
- if (!iter->ReadBytes(&data, BrokerableAttachment::kNonceSize))
- return false;
- memcpy(r->nonce, data, BrokerableAttachment::kNonceSize);
- return true;
-}
-
-void ParamTraits<BrokerableAttachment::AttachmentId>::Log(const param_type& p,
- std::string* l) {
- l->append(base::HexEncode(p.nonce, BrokerableAttachment::kNonceSize));
-}
-
void ParamTraits<base::DictionaryValue>::GetSize(base::PickleSizer* sizer,
const param_type& p) {
GetValueSize(sizer, &p, 0);
@@ -622,7 +598,8 @@ bool ParamTraits<base::DictionaryValue>::Read(const base::Pickle* m,
base::PickleIterator* iter,
param_type* r) {
int type;
- if (!ReadParam(m, iter, &type) || type != base::Value::TYPE_DICTIONARY)
+ if (!ReadParam(m, iter, &type) ||
+ type != static_cast<int>(base::Value::Type::DICTIONARY))
return false;
return ReadDictionaryValue(m, iter, r, 0);
@@ -678,8 +655,14 @@ bool ParamTraits<base::FileDescriptor>::Read(const base::Pickle* m,
if (!m->ReadAttachment(iter, &attachment))
return false;
+ if (static_cast<MessageAttachment*>(attachment.get())->GetType() !=
+ MessageAttachment::Type::PLATFORM_FILE) {
+ return false;
+ }
+
*r = base::FileDescriptor(
- static_cast<MessageAttachment*>(attachment.get())->TakePlatformFile(),
+ static_cast<internal::PlatformFileAttachment*>(attachment.get())
+ ->TakePlatformFile(),
true);
return true;
}
@@ -832,7 +815,8 @@ bool ParamTraits<base::ListValue>::Read(const base::Pickle* m,
base::PickleIterator* iter,
param_type* r) {
int type;
- if (!ReadParam(m, iter, &type) || type != base::Value::TYPE_LIST)
+ if (!ReadParam(m, iter, &type) ||
+ type != static_cast<int>(base::Value::Type::LIST))
return false;
return ReadListValue(m, iter, r, 0);
@@ -998,47 +982,81 @@ void ParamTraits<base::TimeTicks>::Log(const param_type& p, std::string* l) {
ParamTraits<int64_t>::Log(p.ToInternalValue(), l);
}
+// If base::UnguessableToken is no longer 128 bits, the IPC serialization logic
+// below should be updated.
+static_assert(sizeof(base::UnguessableToken) == 2 * sizeof(uint64_t),
+ "base::UnguessableToken should be of size 2 * sizeof(uint64_t).");
+
+void ParamTraits<base::UnguessableToken>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddBytes(2 * sizeof(uint64_t));
+}
+
+void ParamTraits<base::UnguessableToken>::Write(base::Pickle* m,
+ const param_type& p) {
+ DCHECK(!p.is_empty());
+
+ ParamTraits<uint64_t>::Write(m, p.GetHighForSerialization());
+ ParamTraits<uint64_t>::Write(m, p.GetLowForSerialization());
+}
+
+bool ParamTraits<base::UnguessableToken>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ uint64_t high, low;
+ if (!ParamTraits<uint64_t>::Read(m, iter, &high) ||
+ !ParamTraits<uint64_t>::Read(m, iter, &low))
+ return false;
+
+ // Receiving a zeroed UnguessableToken is a security issue.
+ if (high == 0 && low == 0)
+ return false;
+
+ *r = base::UnguessableToken::Deserialize(high, low);
+ return true;
+}
+
+void ParamTraits<base::UnguessableToken>::Log(const param_type& p,
+ std::string* l) {
+ l->append(p.ToString());
+}
+
void ParamTraits<IPC::ChannelHandle>::GetSize(base::PickleSizer* sizer,
const param_type& p) {
- GetParamSize(sizer, p.name);
-#if defined(OS_POSIX)
+#if defined(OS_NACL_SFI)
GetParamSize(sizer, p.socket);
-#endif
+#else
GetParamSize(sizer, p.mojo_handle);
+#endif
}
void ParamTraits<IPC::ChannelHandle>::Write(base::Pickle* m,
const param_type& p) {
-#if defined(OS_WIN)
- // On Windows marshalling pipe handle is not supported.
- DCHECK(p.pipe.handle == NULL);
-#endif // defined (OS_WIN)
- WriteParam(m, p.name);
-#if defined(OS_POSIX)
+#if defined(OS_NACL_SFI)
WriteParam(m, p.socket);
-#endif
+#else
WriteParam(m, p.mojo_handle);
+#endif
}
bool ParamTraits<IPC::ChannelHandle>::Read(const base::Pickle* m,
base::PickleIterator* iter,
param_type* r) {
- return ReadParam(m, iter, &r->name)
-#if defined(OS_POSIX)
- && ReadParam(m, iter, &r->socket)
+#if defined(OS_NACL_SFI)
+ return ReadParam(m, iter, &r->socket);
+#else
+ return ReadParam(m, iter, &r->mojo_handle);
#endif
- && ReadParam(m, iter, &r->mojo_handle);
}
void ParamTraits<IPC::ChannelHandle>::Log(const param_type& p,
std::string* l) {
- l->append(base::StringPrintf("ChannelHandle(%s", p.name.c_str()));
-#if defined(OS_POSIX)
- l->append(", ");
+ l->append("ChannelHandle(");
+#if defined(OS_NACL_SFI)
ParamTraits<base::FileDescriptor>::Log(p.socket, l);
-#endif
- l->append(", ");
+#else
LogParam(p.mojo_handle, l);
+#endif
l->append(")");
}
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h
index 6712d3c..40dd670 100644
--- a/ipc/ipc_message_utils.h
+++ b/ipc/ipc_message_utils.h
@@ -27,7 +27,6 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
-#include "ipc/brokerable_attachment.h"
#include "ipc/ipc_message_start.h"
#include "ipc/ipc_param_traits.h"
#include "ipc/ipc_sync_message.h"
@@ -40,6 +39,7 @@ class NullableString16;
class Time;
class TimeDelta;
class TimeTicks;
+class UnguessableToken;
struct FileDescriptor;
#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
@@ -307,6 +307,37 @@ struct IPC_EXPORT ParamTraits<double> {
static void Log(const param_type& p, std::string* l);
};
+template <class P, size_t Size>
+struct ParamTraits<P[Size]> {
+ using param_type = P[Size];
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ for (const P& element : p)
+ GetParamSize(sizer, element);
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ for (const P& element : p)
+ WriteParam(m, element);
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ for (P& element : *r) {
+ if (!ReadParam(m, iter, &element))
+ return false;
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append("[");
+ for (const P& element : p) {
+ if (&element != &p[0])
+ l->append(" ");
+ LogParam(element, l);
+ }
+ l->append("]");
+ }
+};
+
// STL ParamTraits -------------------------------------------------------------
template <>
@@ -512,17 +543,6 @@ struct ParamTraits<std::pair<A, B> > {
}
};
-// IPC ParamTraits -------------------------------------------------------------
-template <>
-struct IPC_EXPORT ParamTraits<BrokerableAttachment::AttachmentId> {
- typedef BrokerableAttachment::AttachmentId param_type;
- static void Write(base::Pickle* m, const param_type& p);
- static bool Read(const base::Pickle* m,
- base::PickleIterator* iter,
- param_type* r);
- static void Log(const param_type& p, std::string* l);
-};
-
// Base ParamTraits ------------------------------------------------------------
template <>
@@ -667,6 +687,17 @@ struct IPC_EXPORT ParamTraits<base::TimeTicks> {
};
template <>
+struct IPC_EXPORT ParamTraits<base::UnguessableToken> {
+ typedef base::UnguessableToken param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
struct ParamTraits<std::tuple<>> {
typedef std::tuple<> param_type;
static void GetSize(base::PickleSizer* sizer, const param_type& p) {}
@@ -1099,10 +1130,9 @@ struct IPC_EXPORT ParamTraits<MSG> {
// Generic message subclasses
// defined in ipc_logging.cc
-IPC_EXPORT void GenerateLogData(const std::string& channel,
- const Message& message,
- LogData* data, bool get_params);
-
+IPC_EXPORT void GenerateLogData(const Message& message,
+ LogData* data,
+ bool get_params);
#if defined(IPC_MESSAGE_LOG_ENABLED)
inline void AddOutputParamsToLog(const Message* msg, std::string* l) {
@@ -1129,7 +1159,7 @@ inline void ConnectMessageAndReply(const Message* msg, Message* reply) {
// output parameters at that point. Instead, save its data and log it
// with the outgoing reply message when it's sent.
LogData* data = new LogData;
- GenerateLogData("", *msg, data, true);
+ GenerateLogData(*msg, data, true);
msg->set_dont_log();
reply->set_sync_log_data(data);
}
diff --git a/ipc/ipc_mojo_handle_attachment.cc b/ipc/ipc_mojo_handle_attachment.cc
index 819a12b..e3421c3 100644
--- a/ipc/ipc_mojo_handle_attachment.cc
+++ b/ipc/ipc_mojo_handle_attachment.cc
@@ -18,16 +18,9 @@ MojoHandleAttachment::~MojoHandleAttachment() {
}
MessageAttachment::Type MojoHandleAttachment::GetType() const {
- return TYPE_MOJO_HANDLE;
+ return Type::MOJO_HANDLE;
}
-#if defined(OS_POSIX)
-base::PlatformFile MojoHandleAttachment::TakePlatformFile() {
- NOTREACHED();
- return base::kInvalidPlatformFile;
-}
-#endif // OS_POSIX
-
mojo::ScopedHandle MojoHandleAttachment::TakeHandle() {
return std::move(handle_);
}
diff --git a/ipc/ipc_mojo_handle_attachment.h b/ipc/ipc_mojo_handle_attachment.h
index 6aa1888..d615276 100644
--- a/ipc/ipc_mojo_handle_attachment.h
+++ b/ipc/ipc_mojo_handle_attachment.h
@@ -26,11 +26,6 @@ class IPC_EXPORT MojoHandleAttachment : public MessageAttachment {
Type GetType() const override;
-#if defined(OS_POSIX)
- // Should not be called.
- base::PlatformFile TakePlatformFile() override;
-#endif // OS_POSIX
-
// Returns the owning handle transferring the ownership.
mojo::ScopedHandle TakeHandle();
diff --git a/ipc/ipc_mojo_message_helper.cc b/ipc/ipc_mojo_message_helper.cc
index 8f86945..a87a2d6 100644
--- a/ipc/ipc_mojo_message_helper.cc
+++ b/ipc/ipc_mojo_message_helper.cc
@@ -32,7 +32,7 @@ bool MojoMessageHelper::ReadMessagePipeFrom(
MessageAttachment::Type type =
static_cast<MessageAttachment*>(attachment.get())->GetType();
- if (type != MessageAttachment::TYPE_MOJO_HANDLE) {
+ if (type != MessageAttachment::Type::MOJO_HANDLE) {
LOG(ERROR) << "Unxpected attachment type:" << type;
return false;
}
diff --git a/ipc/ipc_platform_file_attachment_posix.cc b/ipc/ipc_platform_file_attachment_posix.cc
index b130ab2..7111cfa 100644
--- a/ipc/ipc_platform_file_attachment_posix.cc
+++ b/ipc/ipc_platform_file_attachment_posix.cc
@@ -20,7 +20,7 @@ PlatformFileAttachment::~PlatformFileAttachment() {
}
MessageAttachment::Type PlatformFileAttachment::GetType() const {
- return TYPE_PLATFORM_FILE;
+ return Type::PLATFORM_FILE;
}
base::PlatformFile PlatformFileAttachment::TakePlatformFile() {
@@ -30,7 +30,7 @@ base::PlatformFile PlatformFileAttachment::TakePlatformFile() {
base::PlatformFile GetPlatformFile(
scoped_refptr<MessageAttachment> attachment) {
- DCHECK_EQ(attachment->GetType(), MessageAttachment::TYPE_PLATFORM_FILE);
+ DCHECK_EQ(attachment->GetType(), MessageAttachment::Type::PLATFORM_FILE);
return static_cast<PlatformFileAttachment*>(attachment.get())->file();
}
diff --git a/ipc/ipc_platform_file_attachment_posix.h b/ipc/ipc_platform_file_attachment_posix.h
index d1eff60..9b07900 100644
--- a/ipc/ipc_platform_file_attachment_posix.h
+++ b/ipc/ipc_platform_file_attachment_posix.h
@@ -23,7 +23,7 @@ class IPC_EXPORT PlatformFileAttachment : public MessageAttachment {
explicit PlatformFileAttachment(base::ScopedFD file);
Type GetType() const override;
- base::PlatformFile TakePlatformFile() override;
+ base::PlatformFile TakePlatformFile();
base::PlatformFile file() const { return file_; }
bool Owns() const { return owning_.is_valid(); }
diff --git a/ipc/placeholder_brokerable_attachment.cc b/ipc/placeholder_brokerable_attachment.cc
deleted file mode 100644
index e64e398..0000000
--- a/ipc/placeholder_brokerable_attachment.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ipc/placeholder_brokerable_attachment.h"
-
-namespace IPC {
-
-BrokerableAttachment::BrokerableType
-PlaceholderBrokerableAttachment::GetBrokerableType() const {
- return PLACEHOLDER;
-}
-
-} // namespace IPC
diff --git a/ipc/placeholder_brokerable_attachment.h b/ipc/placeholder_brokerable_attachment.h
deleted file mode 100644
index a8b08ef..0000000
--- a/ipc/placeholder_brokerable_attachment.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IPC_PLACEHOLDER_BROKERABLE_ATTACHMENT_H_
-#define IPC_PLACEHOLDER_BROKERABLE_ATTACHMENT_H_
-
-#include "base/macros.h"
-#include "ipc/brokerable_attachment.h"
-#include "ipc/ipc_export.h"
-
-namespace IPC {
-
-// This subclass of BrokerableAttachment has an AttachmentId, and nothing else.
-// It is intended to be replaced by the attachment broker.
-class IPC_EXPORT PlaceholderBrokerableAttachment : public BrokerableAttachment {
- public:
- PlaceholderBrokerableAttachment(const AttachmentId& id)
- : BrokerableAttachment(id){};
- BrokerableType GetBrokerableType() const override;
-
- protected:
- ~PlaceholderBrokerableAttachment() override{};
- DISALLOW_COPY_AND_ASSIGN(PlaceholderBrokerableAttachment);
-};
-
-} // namespace IPC
-
-#endif // IPC_PLACEHOLDER_BROKERABLE_ATTACHMENT_H_
diff --git a/libmojo.pc.in b/libmojo.pc.in
new file mode 100644
index 0000000..cceadd4
--- /dev/null
+++ b/libmojo.pc.in
@@ -0,0 +1,13 @@
+bslot=@BSLOT@
+prefix=/usr
+exec_prefix=${prefix}
+libdir=${exec_prefix}/@LIB@
+includedir=${prefix}/include
+
+Name: libmojo
+Description: Chrome Mojo IPC library
+Requires.private:
+Version: ${bslot}
+Libs: -lmojo-${bslot}.pie
+Libs.private:
+Cflags: -I${includedir}/libmojo-${bslot} -Wno-cast-qual -Wno-cast-align
diff --git a/mojo/BUILD.gn b/mojo/BUILD.gn
index 2dac654..070e2d1 100644
--- a/mojo/BUILD.gn
+++ b/mojo/BUILD.gn
@@ -13,9 +13,6 @@ group("mojo") {
]
if (!(is_linux && current_cpu == "x86")) {
- # TODO(GYP): Figure out if this needs to be supported. Right now
- # it won't work on x86 official builds because it needs stuff in the
- # sysroot that doesn't exist.
deps += [ "//mojo/public" ]
}
@@ -23,7 +20,7 @@ group("mojo") {
deps += [ "//mojo/android" ]
}
- deps += [ "//services/shell:all" ]
+ deps += [ "//services/service_manager:all" ]
}
group("tests") {
@@ -31,17 +28,14 @@ group("tests") {
deps = [
"//ipc:ipc_tests",
"//mojo/common:mojo_common_unittests",
- "//mojo/converters/blink:blink_converters_unittests",
- "//mojo/edk/js/test:js_integration_tests",
- "//mojo/edk/js/test:js_unittests",
+ "//mojo/edk/js/tests",
"//mojo/edk/system:mojo_message_pipe_perftests",
"//mojo/edk/system:mojo_system_unittests",
"//mojo/edk/test:mojo_public_bindings_perftests",
"//mojo/edk/test:mojo_public_bindings_unittests",
"//mojo/edk/test:mojo_public_system_perftests",
"//mojo/edk/test:mojo_public_system_unittests",
- "//services/shell/public/cpp/tests:mojo_public_application_unittests",
- "//services/shell/runner/host:mojo_runner_host_unittests",
- "//services/shell/tests",
+ "//services/service_manager/public/cpp/tests:mojo_public_application_unittests",
+ "//services/service_manager/tests",
]
}
diff --git a/mojo/DEPS b/mojo/DEPS
index a659200..49d7fd3 100644
--- a/mojo/DEPS
+++ b/mojo/DEPS
@@ -3,5 +3,5 @@ include_rules = [
"+build",
"+testing",
- "+services/shell",
+ "+services/service_manager",
]
diff --git a/mojo/android/BUILD.gn b/mojo/android/BUILD.gn
index 813701c..1a8cdbd 100644
--- a/mojo/android/BUILD.gn
+++ b/mojo/android/BUILD.gn
@@ -29,6 +29,7 @@ generate_jni("system_java_jni_headers") {
sources = [
"system/src/org/chromium/mojo/system/impl/BaseRunLoop.java",
"system/src/org/chromium/mojo/system/impl/CoreImpl.java",
+ "system/src/org/chromium/mojo/system/impl/WatcherImpl.java",
]
jni_package = "mojo"
@@ -40,12 +41,15 @@ source_set("libsystem_java") {
"system/base_run_loop.h",
"system/core_impl.cc",
"system/core_impl.h",
+ "system/watcher_impl.cc",
+ "system/watcher_impl.h",
]
deps = [
":system_java_jni_headers",
"//base",
- "//mojo/message_pump",
+ "//mojo/public/c/system",
+ "//mojo/public/cpp/system",
]
}
@@ -59,11 +63,12 @@ android_library("system_java") {
"system/src/org/chromium/mojo/system/impl/MessagePipeHandleImpl.java",
"system/src/org/chromium/mojo/system/impl/SharedBufferHandleImpl.java",
"system/src/org/chromium/mojo/system/impl/UntypedHandleImpl.java",
+ "system/src/org/chromium/mojo/system/impl/WatcherImpl.java",
]
deps = [
"//base:base_java",
- "//mojo/public/java:system",
+ "//mojo/public/java:system_java",
]
}
@@ -90,6 +95,7 @@ android_library("mojo_javatests") {
"javatests/src/org/chromium/mojo/bindings/ValidationTestUtil.java",
"javatests/src/org/chromium/mojo/bindings/ValidationTestUtilTest.java",
"javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java",
+ "javatests/src/org/chromium/mojo/system/impl/WatcherImplTest.java",
]
deps = [
@@ -99,8 +105,13 @@ android_library("mojo_javatests") {
"//mojo/public/interfaces/bindings/tests:test_interfaces_java",
"//mojo/public/interfaces/bindings/tests:test_mojom_import2_java",
"//mojo/public/interfaces/bindings/tests:test_mojom_import_java",
- "//mojo/public/java:bindings",
- "//mojo/public/java:system",
+ "//mojo/public/java:bindings_java",
+ "//mojo/public/java:system_java",
+ "//third_party/android_support_test_runner:runner_java",
+ ]
+
+ data = [
+ "//mojo/public/interfaces/bindings/tests/data/validation/",
]
}
@@ -120,10 +131,9 @@ shared_library("mojo_java_unittests") {
":libsystem_java",
":system_java_jni_headers",
"//base",
- "//base/test/:test_support",
+ "//base/test:test_support",
"//build/config/sanitizers:deps",
"//mojo/edk/system",
- "//mojo/message_pump",
"//mojo/public/cpp/bindings/tests:mojo_public_bindings_test_utils",
"//mojo/public/cpp/test_support:test_utils",
]
@@ -136,10 +146,10 @@ instrumentation_test_apk("mojo_test_apk") {
":system_java",
"//base:base_java",
"//mojo/public/interfaces/bindings/tests:test_interfaces",
- "//mojo/public/java:bindings",
+ "//mojo/public/java:bindings_java",
+ "//third_party/android_support_test_runner:runner_java",
]
shared_libraries = [ ":mojo_java_unittests" ]
apk_name = "MojoTest"
android_manifest = "javatests/AndroidManifest.xml"
- isolate_file = "../mojo_test_apk.isolate"
}
diff --git a/mojo/android/javatests/init_library.cc b/mojo/android/javatests/init_library.cc
index d2d9423..9e1a593 100644
--- a/mojo/android/javatests/init_library.cc
+++ b/mojo/android/javatests/init_library.cc
@@ -6,27 +6,33 @@
#include "base/android/base_jni_registrar.h"
#include "base/android/jni_android.h"
#include "base/android/jni_registrar.h"
+#include "base/android/library_loader/library_loader_hooks.h"
#include "base/bind.h"
#include "mojo/android/javatests/mojo_test_case.h"
#include "mojo/android/javatests/validation_test_util.h"
#include "mojo/android/system/core_impl.h"
+#include "mojo/android/system/watcher_impl.h"
#include "mojo/edk/embedder/embedder.h"
namespace {
base::android::RegistrationMethod kMojoRegisteredMethods[] = {
- { "CoreImpl", mojo::android::RegisterCoreImpl },
- { "MojoTestCase", mojo::android::RegisterMojoTestCase },
- { "ValidationTestUtil", mojo::android::RegisterValidationTestUtil },
+ {"CoreImpl", mojo::android::RegisterCoreImpl},
+ {"MojoTestCase", mojo::android::RegisterMojoTestCase},
+ {"ValidationTestUtil", mojo::android::RegisterValidationTestUtil},
+ {"WatcherImpl", mojo::android::RegisterWatcherImpl},
};
bool RegisterJNI(JNIEnv* env) {
return base::android::RegisterJni(env) &&
- RegisterNativeMethods(env, kMojoRegisteredMethods,
- arraysize(kMojoRegisteredMethods));
+ RegisterNativeMethods(env, kMojoRegisteredMethods,
+ arraysize(kMojoRegisteredMethods));
}
-bool Init() {
+bool NativeInit() {
+ if (!base::android::OnJNIOnLoadInit())
+ return false;
+
mojo::edk::Init();
return true;
}
@@ -34,13 +40,11 @@ bool Init() {
} // namespace
JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
- std::vector<base::android::RegisterCallback> register_callbacks;
- register_callbacks.push_back(base::Bind(&RegisterJNI));
- std::vector<base::android::InitCallback> init_callbacks;
- init_callbacks.push_back(base::Bind(&Init));
- if (!base::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) ||
- !base::android::OnJNIOnLoadInit(init_callbacks))
+ base::android::InitVM(vm);
+ JNIEnv* env = base::android::AttachCurrentThread();
+ if (!base::android::OnJNIOnLoadRegisterJNI(env) || !RegisterJNI(env) ||
+ !NativeInit()) {
return -1;
-
+ }
return JNI_VERSION_1_4;
}
diff --git a/mojo/android/javatests/mojo_test_case.cc b/mojo/android/javatests/mojo_test_case.cc
index 6d88985..fc59009 100644
--- a/mojo/android/javatests/mojo_test_case.cc
+++ b/mojo/android/javatests/mojo_test_case.cc
@@ -16,12 +16,13 @@
#include "base/test/test_support_android.h"
#include "base/threading/thread_task_runner_handle.h"
#include "jni/MojoTestCase_jni.h"
-#include "mojo/message_pump/message_pump_mojo.h"
+
+using base::android::JavaParamRef;
namespace {
struct TestEnvironment {
- TestEnvironment() : message_loop(mojo::common::MessagePumpMojo::Create()) {}
+ TestEnvironment() {}
base::ShadowingAtExitManager at_exit;
base::MessageLoop message_loop;
diff --git a/mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java b/mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java
index c7348ca..f4d7ab7 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java
@@ -4,7 +4,6 @@
package org.chromium.mojo;
-import android.content.Context;
import android.test.InstrumentationTestCase;
import org.chromium.base.ContextUtils;
@@ -26,9 +25,9 @@ public class MojoTestCase extends InstrumentationTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
- Context appContext = getInstrumentation().getTargetContext().getApplicationContext();
- ContextUtils.initApplicationContext(appContext);
- LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized(appContext);
+ ContextUtils.initApplicationContext(
+ getInstrumentation().getTargetContext().getApplicationContext());
+ LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized();
nativeInit();
mTestEnvironmentPointer = nativeSetupTestEnvironment();
}
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsHelperTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsHelperTest.java
index a46a157..38bd348 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsHelperTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsHelperTest.java
@@ -4,7 +4,7 @@
package org.chromium.mojo.bindings;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import junit.framework.TestCase;
@@ -34,8 +34,8 @@ public class BindingsHelperTest extends TestCase {
BindingsHelper.utf8StringSizeInBytes(s));
}
assertEquals(1, BindingsHelper.utf8StringSizeInBytes("\0"));
- String s = new StringBuilder().appendCodePoint(0x0).appendCodePoint(0x80).
- appendCodePoint(0x800).appendCodePoint(0x10000).toString();
+ String s = new StringBuilder().appendCodePoint(0x0).appendCodePoint(0x80)
+ .appendCodePoint(0x800).appendCodePoint(0x10000).toString();
assertEquals(10, BindingsHelper.utf8StringSizeInBytes(s));
assertEquals(10, s.getBytes(Charset.forName("utf8")).length);
}
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsTest.java
index 6886023..d280c77 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsTest.java
@@ -4,7 +4,7 @@
package org.chromium.mojo.bindings;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import junit.framework.TestCase;
@@ -21,12 +21,15 @@ import org.chromium.mojo.bindings.test.mojom.sample.Foo;
import org.chromium.mojo.bindings.test.mojom.sample.InterfaceConstants;
import org.chromium.mojo.bindings.test.mojom.sample.SampleServiceConstants;
import org.chromium.mojo.bindings.test.mojom.test_structs.EmptyStruct;
+import org.chromium.mojo.bindings.test.mojom.test_structs.Rect;
import org.chromium.mojo.system.DataPipe.ConsumerHandle;
import org.chromium.mojo.system.DataPipe.ProducerHandle;
import org.chromium.mojo.system.MessagePipeHandle;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
/**
* Testing generated classes and associated features.
@@ -81,6 +84,15 @@ public class BindingsTest extends TestCase {
return foo;
}
+ private static Rect createRect(int x, int y, int width, int height) {
+ Rect rect = new Rect();
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ return rect;
+ }
+
private static <T> void checkConstantField(
Field field, Class<T> expectedClass, T value) throws IllegalAccessException {
assertEquals(expectedClass, field.getType());
@@ -209,4 +221,21 @@ public class BindingsTest extends TestCase {
assertNotNull(emptyStruct);
}
+ // In testing maps we want to make sure that the key used when inserting an
+ // item the key used when looking it up again are different objects. Java
+ // has default implementations of equals and hashCode that use reference
+ // equality and hashing, respectively, and that's not what we want for our
+ // mojom values.
+ @SmallTest
+ public void testHashMapStructKey() {
+ Map<Rect, Integer> map = new HashMap<>();
+ map.put(createRect(1, 2, 3, 4), 123);
+
+ Rect key = createRect(1, 2, 3, 4);
+ assertNotNull(map.get(key));
+ assertEquals(123, map.get(key).intValue());
+
+ map.remove(key);
+ assertTrue(map.isEmpty());
+ }
}
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsVersioningTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsVersioningTest.java
index f0c0f7c..eea92ab 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsVersioningTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsVersioningTest.java
@@ -4,7 +4,7 @@
package org.chromium.mojo.bindings;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import org.chromium.mojo.MojoTestCase;
import org.chromium.mojo.bindings.test.mojom.test_structs.MultiVersionStruct;
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/CallbacksTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/CallbacksTest.java
index dfb8e21..497be65 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/bindings/CallbacksTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/CallbacksTest.java
@@ -4,7 +4,7 @@
package org.chromium.mojo.bindings;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/ConnectorTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/ConnectorTest.java
index 9c26875..15f9f1f 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/bindings/ConnectorTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/ConnectorTest.java
@@ -4,7 +4,7 @@
package org.chromium.mojo.bindings;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import org.chromium.mojo.MojoTestCase;
import org.chromium.mojo.bindings.BindingsTestUtils.CapturingErrorHandler;
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/ExecutorFactoryTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/ExecutorFactoryTest.java
index 56f4b40..cabe230 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/bindings/ExecutorFactoryTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/ExecutorFactoryTest.java
@@ -4,7 +4,7 @@
package org.chromium.mojo.bindings;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import org.chromium.mojo.MojoTestCase;
import org.chromium.mojo.system.impl.CoreImpl;
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfaceControlMessageTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfaceControlMessageTest.java
index c101675..8cdd4ab 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfaceControlMessageTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfaceControlMessageTest.java
@@ -4,7 +4,7 @@
package org.chromium.mojo.bindings;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import org.chromium.mojo.MojoTestCase;
import org.chromium.mojo.bindings.Callbacks.Callback1;
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfacesTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfacesTest.java
index f96b1e3..d8bd3e8 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfacesTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/InterfacesTest.java
@@ -4,7 +4,7 @@
package org.chromium.mojo.bindings;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import org.chromium.mojo.MojoTestCase;
import org.chromium.mojo.bindings.BindingsTestUtils.CapturingErrorHandler;
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/MessageHeaderTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/MessageHeaderTest.java
index 8af8be1..b2e6ac8 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/bindings/MessageHeaderTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/MessageHeaderTest.java
@@ -4,7 +4,7 @@
package org.chromium.mojo.bindings;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/ReadAndDispatchMessageTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/ReadAndDispatchMessageTest.java
index f2edb01..51dbd22 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/bindings/ReadAndDispatchMessageTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/ReadAndDispatchMessageTest.java
@@ -4,7 +4,7 @@
package org.chromium.mojo.bindings;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import org.chromium.mojo.MojoTestCase;
import org.chromium.mojo.bindings.BindingsTestUtils.RecordingMessageReceiver;
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/RouterTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/RouterTest.java
index 0b632a9..5affb8f 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/bindings/RouterTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/RouterTest.java
@@ -4,7 +4,7 @@
package org.chromium.mojo.bindings;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import org.chromium.base.annotations.SuppressFBWarnings;
import org.chromium.mojo.MojoTestCase;
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/SerializationTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/SerializationTest.java
index a7e213c..2c17e3a 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/bindings/SerializationTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/SerializationTest.java
@@ -4,7 +4,7 @@
package org.chromium.mojo.bindings;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import junit.framework.TestCase;
@@ -17,6 +17,8 @@ import org.chromium.mojo.bindings.test.mojom.mojo.Struct5;
import org.chromium.mojo.bindings.test.mojom.mojo.Struct6;
import org.chromium.mojo.bindings.test.mojom.mojo.StructOfNullables;
+import java.nio.ByteBuffer;
+
/**
* Tests for the serialization logic of the generated structs, using structs defined in
* mojo/public/interfaces/bindings/tests/serialization_test_structs.mojom .
@@ -128,4 +130,46 @@ public class SerializationTest extends TestCase {
assertNull(struct.str);
struct.serialize(null);
}
+
+ /**
+ * Verifies that a struct can be serialized to and deserialized from a ByteBuffer.
+ */
+ @SmallTest
+ public void testByteBufferSerialization() {
+ Struct1 input = new Struct1();
+ input.i = 0x7F;
+
+ ByteBuffer buf = input.serialize();
+
+ byte[] expected_raw_bytes = {16, 0, 0, 0, 0, 0, 0, 0, 0x7F, 0, 0, 0, 0, 0, 0, 0};
+ ByteBuffer expected_buf = ByteBuffer.wrap(expected_raw_bytes);
+ assertEquals(expected_buf, buf);
+
+ Struct1 output = Struct1.deserialize(buf);
+ assertEquals(0x7F, output.i);
+ }
+
+ /**
+ * Verifies that a struct with handles cannot be serialized to a ByteBuffer.
+ */
+ @SmallTest
+ public void testByteBufferSerializationWithHandles() {
+ StructOfNullables struct = new StructOfNullables();
+ assertFalse(struct.hdl.isValid());
+ assertNull(struct.struct1);
+ assertNull(struct.str);
+
+ // It is okay to serialize invalid handles.
+ struct.serialize();
+
+ struct.hdl = new HandleMock();
+
+ try {
+ struct.serialize();
+ fail("Serializing a struct with handles to a ByteBuffer should have thrown an "
+ + "exception.");
+ } catch (UnsupportedOperationException ex) {
+ // Expected.
+ }
+ }
}
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTest.java
index e5c4549..8424618 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTest.java
@@ -4,7 +4,7 @@
package org.chromium.mojo.bindings;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import org.chromium.base.test.util.UrlUtils;
import org.chromium.mojo.HandleMock;
@@ -13,6 +13,7 @@ import org.chromium.mojo.bindings.test.mojom.mojo.ConformanceTestInterface;
import org.chromium.mojo.bindings.test.mojom.mojo.IntegrationTestInterface;
import org.chromium.mojo.bindings.test.mojom.mojo.IntegrationTestInterfaceTestHelper;
import org.chromium.mojo.system.Handle;
+import org.chromium.mojo.system.impl.CoreImpl;
import java.io.File;
import java.io.FileFilter;
@@ -189,8 +190,10 @@ public class ValidationTest extends MojoTestCase {
*/
@SmallTest
public void testConformance() throws FileNotFoundException {
- runTest("conformance_", ConformanceTestInterface.MANAGER.buildStub(null,
- ConformanceTestInterface.MANAGER.buildProxy(null, new SinkMessageReceiver())));
+ runTest("conformance_",
+ ConformanceTestInterface.MANAGER.buildStub(CoreImpl.getInstance(),
+ ConformanceTestInterface.MANAGER.buildProxy(
+ CoreImpl.getInstance(), new SinkMessageReceiver())));
}
/**
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTestUtilTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTestUtilTest.java
index 14259ef..623abc3 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTestUtilTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTestUtilTest.java
@@ -4,7 +4,7 @@
package org.chromium.mojo.bindings;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import org.chromium.mojo.MojoTestCase;
diff --git a/mojo/android/javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java b/mojo/android/javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java
index 16c16f2..77a9bda 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java
@@ -4,12 +4,9 @@
package org.chromium.mojo.system.impl;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import org.chromium.mojo.MojoTestCase;
-import org.chromium.mojo.system.AsyncWaiter;
-import org.chromium.mojo.system.AsyncWaiter.Callback;
-import org.chromium.mojo.system.AsyncWaiter.Cancellable;
import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.Core.HandleSignals;
import org.chromium.mojo.system.Core.HandleSignalsState;
@@ -584,266 +581,6 @@ public class CoreImplTest extends MojoTestCase {
}
}
- private static class AsyncWaiterResult implements Callback {
- private int mResult = Integer.MIN_VALUE;
- private MojoException mException = null;
-
- /**
- * @see Callback#onResult(int)
- */
- @Override
- public void onResult(int result) {
- this.mResult = result;
- }
-
- /**
- * @see Callback#onError(MojoException)
- */
- @Override
- public void onError(MojoException exception) {
- this.mException = exception;
- }
-
- /**
- * @return the result
- */
- public int getResult() {
- return mResult;
- }
-
- /**
- * @return the exception
- */
- public MojoException getException() {
- return mException;
- }
- }
-
- /**
- * Testing core {@link AsyncWaiter} implementation.
- */
- @SmallTest
- public void testAsyncWaiterCorrectResult() {
- Core core = CoreImpl.getInstance();
-
- // Checking a correct result.
- Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
- addHandlePairToClose(handles);
- final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult();
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- core.getDefaultAsyncWaiter().asyncWait(handles.first, Core.HandleSignals.READABLE,
- Core.DEADLINE_INFINITE, asyncWaiterResult);
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- handles.second.writeMessage(
- ByteBuffer.allocateDirect(1), null, MessagePipeHandle.WriteFlags.NONE);
- runLoopUntilIdle();
- assertNull(asyncWaiterResult.getException());
- assertEquals(MojoResult.OK, asyncWaiterResult.getResult());
- }
-
- /**
- * Testing core {@link AsyncWaiter} implementation.
- */
- @SmallTest
- public void testAsyncWaiterClosingPeerHandle() {
- Core core = CoreImpl.getInstance();
-
- // Closing the peer handle.
- Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
- addHandlePairToClose(handles);
-
- final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult();
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- core.getDefaultAsyncWaiter().asyncWait(handles.first, Core.HandleSignals.READABLE,
- Core.DEADLINE_INFINITE, asyncWaiterResult);
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- runLoopUntilIdle();
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- handles.second.close();
- runLoopUntilIdle();
- assertNull(asyncWaiterResult.getException());
- assertEquals(MojoResult.FAILED_PRECONDITION, asyncWaiterResult.getResult());
- }
-
- /**
- * Testing core {@link AsyncWaiter} implementation.
- */
- @SmallTest
- public void testAsyncWaiterClosingWaitingHandle() {
- Core core = CoreImpl.getInstance();
-
- // Closing the peer handle.
- Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
- addHandlePairToClose(handles);
-
- final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult();
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- core.getDefaultAsyncWaiter().asyncWait(handles.first, Core.HandleSignals.READABLE,
- Core.DEADLINE_INFINITE, asyncWaiterResult);
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- runLoopUntilIdle();
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- handles.first.close();
- runLoopUntilIdle();
- // TODO(qsr) Re-enable when MojoWaitMany handles it correctly.
- // assertNull(asyncWaiterResult.getException());
- // assertEquals(MojoResult.CANCELLED, asyncWaiterResult.getResult());
- }
-
- /**
- * Testing core {@link AsyncWaiter} implementation.
- */
- @SmallTest
- public void testAsyncWaiterWaitingOnInvalidHandle() {
- Core core = CoreImpl.getInstance();
-
- // Closing the peer handle.
- Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
- addHandlePairToClose(handles);
-
- final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult();
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- handles.first.close();
- core.getDefaultAsyncWaiter().asyncWait(handles.first, Core.HandleSignals.READABLE,
- Core.DEADLINE_INFINITE, asyncWaiterResult);
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- runLoopUntilIdle();
- assertNotNull(asyncWaiterResult.getException());
- assertEquals(MojoResult.INVALID_ARGUMENT,
- asyncWaiterResult.getException().getMojoResult());
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- }
-
- /**
- * Testing core {@link AsyncWaiter} implementation.
- */
- @SmallTest
- public void testAsyncWaiterWaitingOnDefaultInvalidHandle() {
- Core core = CoreImpl.getInstance();
-
- final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult();
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- core.getDefaultAsyncWaiter().asyncWait(InvalidHandle.INSTANCE, Core.HandleSignals.READABLE,
- Core.DEADLINE_INFINITE, asyncWaiterResult);
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- runLoopUntilIdle();
- assertNotNull(asyncWaiterResult.getException());
- assertEquals(MojoResult.INVALID_ARGUMENT, asyncWaiterResult.getException().getMojoResult());
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- }
-
- /**
- * Testing core {@link AsyncWaiter} implementation.
- */
- @SmallTest
- public void testAsyncWaiterWaitingWithTimeout() {
- Core core = CoreImpl.getInstance();
-
- // Closing the peer handle.
- Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
- addHandlePairToClose(handles);
-
- final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult();
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- core.getDefaultAsyncWaiter().asyncWait(
- handles.first, Core.HandleSignals.READABLE, RUN_LOOP_TIMEOUT_MS, asyncWaiterResult);
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- runLoopUntilIdle();
- assertNull(asyncWaiterResult.getException());
- assertEquals(MojoResult.DEADLINE_EXCEEDED, asyncWaiterResult.getResult());
- }
-
- /**
- * Testing core {@link AsyncWaiter} implementation.
- */
- @SmallTest
- public void testAsyncWaiterCancelWaiting() {
- Core core = CoreImpl.getInstance();
-
- // Closing the peer handle.
- Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
- addHandlePairToClose(handles);
-
- final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult();
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- Cancellable cancellable = core.getDefaultAsyncWaiter().asyncWait(handles.first,
- Core.HandleSignals.READABLE, Core.DEADLINE_INFINITE, asyncWaiterResult);
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- runLoopUntilIdle();
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- cancellable.cancel();
- runLoopUntilIdle();
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- handles.second.writeMessage(
- ByteBuffer.allocateDirect(1), null, MessagePipeHandle.WriteFlags.NONE);
- runLoopUntilIdle();
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
- }
-
- /**
- * Testing core {@link AsyncWaiter} implementation.
- */
- @SmallTest
- public void testAsyncWaiterImmediateCancelOnInvalidHandle() {
- Core core = CoreImpl.getInstance();
-
- // Closing the peer handle.
- Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
- addHandlePairToClose(handles);
-
- final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult();
- handles.first.close();
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
-
- Cancellable cancellable = core.getDefaultAsyncWaiter().asyncWait(handles.first,
- Core.HandleSignals.READABLE, Core.DEADLINE_INFINITE, asyncWaiterResult);
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
- cancellable.cancel();
-
- runLoopUntilIdle();
- assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult());
- assertEquals(null, asyncWaiterResult.getException());
- }
-
/**
* Testing the pass method on message pipes.
*/
diff --git a/mojo/android/javatests/validation_test_util.cc b/mojo/android/javatests/validation_test_util.cc
index fb4d140..75f79b3 100644
--- a/mojo/android/javatests/validation_test_util.cc
+++ b/mojo/android/javatests/validation_test_util.cc
@@ -14,6 +14,9 @@
#include "jni/ValidationTestUtil_jni.h"
#include "mojo/public/cpp/bindings/tests/validation_test_input_parser.h"
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
namespace mojo {
namespace android {
@@ -34,8 +37,7 @@ ScopedJavaLocalRef<jobject> ParseData(
input, &data, &num_handles, &error_message)) {
ScopedJavaLocalRef<jstring> j_error_message =
base::android::ConvertUTF8ToJavaString(env, error_message);
- return Java_ValidationTestUtil_buildData(env, NULL, 0,
- j_error_message.obj());
+ return Java_ValidationTestUtil_buildData(env, nullptr, 0, j_error_message);
}
void* data_ptr = &data[0];
if (!data_ptr) {
@@ -44,7 +46,8 @@ ScopedJavaLocalRef<jobject> ParseData(
}
jobject byte_buffer =
env->NewDirectByteBuffer(data_ptr, data.size());
- return Java_ValidationTestUtil_buildData(env, byte_buffer, num_handles, NULL);
+ return Java_ValidationTestUtil_buildData(env, byte_buffer, num_handles,
+ nullptr);
}
} // namespace android
diff --git a/mojo/android/system/base_run_loop.cc b/mojo/android/system/base_run_loop.cc
index e48d2f0..22511f3 100644
--- a/mojo/android/system/base_run_loop.cc
+++ b/mojo/android/system/base_run_loop.cc
@@ -10,30 +10,31 @@
#include "base/android/jni_android.h"
#include "base/android/jni_registrar.h"
#include "base/bind.h"
+#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "jni/BaseRunLoop_jni.h"
-#include "mojo/message_pump/message_pump_mojo.h"
+
+using base::android::JavaParamRef;
namespace mojo {
namespace android {
static jlong CreateBaseRunLoop(JNIEnv* env,
const JavaParamRef<jobject>& jcaller) {
- base::MessageLoop* message_loop =
- new base::MessageLoop(common::MessagePumpMojo::Create());
+ base::MessageLoop* message_loop = new base::MessageLoop;
return reinterpret_cast<uintptr_t>(message_loop);
}
static void Run(JNIEnv* env,
- const JavaParamRef<jobject>& jcaller,
- jlong runLoopID) {
- reinterpret_cast<base::MessageLoop*>(runLoopID)->Run();
+ const JavaParamRef<jobject>& jcaller) {
+ base::RunLoop().Run();
}
static void RunUntilIdle(JNIEnv* env,
- const JavaParamRef<jobject>& jcaller,
- jlong runLoopID) {
- reinterpret_cast<base::MessageLoop*>(runLoopID)->RunUntilIdle();
+ const JavaParamRef<jobject>& jcaller) {
+ base::RunLoop().RunUntilIdle();
}
static void Quit(JNIEnv* env,
@@ -45,7 +46,7 @@ static void Quit(JNIEnv* env,
static void RunJavaRunnable(
const base::android::ScopedJavaGlobalRef<jobject>& runnable_ref) {
Java_BaseRunLoop_runRunnable(base::android::AttachCurrentThread(),
- runnable_ref.obj());
+ runnable_ref);
}
static void PostDelayedTask(JNIEnv* env,
@@ -58,9 +59,10 @@ static void PostDelayedTask(JNIEnv* env,
// use it across threads. |RunJavaRunnable| will acquire a new JNIEnv before
// running the Runnable.
runnable_ref.Reset(env, runnable);
- reinterpret_cast<base::MessageLoop*>(runLoopID)->PostDelayedTask(
- FROM_HERE, base::Bind(&RunJavaRunnable, runnable_ref),
- base::TimeDelta::FromMicroseconds(delay));
+ reinterpret_cast<base::MessageLoop*>(runLoopID)
+ ->task_runner()
+ ->PostDelayedTask(FROM_HERE, base::Bind(&RunJavaRunnable, runnable_ref),
+ base::TimeDelta::FromMicroseconds(delay));
}
static void DeleteMessageLoop(JNIEnv* env,
@@ -78,4 +80,3 @@ bool RegisterBaseRunLoop(JNIEnv* env) {
} // namespace android
} // namespace mojo
-
diff --git a/mojo/android/system/core_impl.cc b/mojo/android/system/core_impl.cc
index 526c050..5cbd754 100644
--- a/mojo/android/system/core_impl.cc
+++ b/mojo/android/system/core_impl.cc
@@ -7,56 +7,20 @@
#include <stddef.h>
#include <stdint.h>
-#include <memory>
-
#include "base/android/base_jni_registrar.h"
#include "base/android/jni_android.h"
#include "base/android/jni_registrar.h"
#include "base/android/library_loader/library_loader_hooks.h"
#include "base/android/scoped_java_ref.h"
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "jni/CoreImpl_jni.h"
-#include "mojo/message_pump/handle_watcher.h"
#include "mojo/public/c/system/core.h"
-namespace {
-
-using MojoAsyncWaitID = uintptr_t;
-const MojoAsyncWaitID kInvalidHandleCancelID = 0;
-
-struct AsyncWaitCallbackData {
- base::android::ScopedJavaGlobalRef<jobject> core_impl;
- base::android::ScopedJavaGlobalRef<jobject> callback;
- base::android::ScopedJavaGlobalRef<jobject> cancellable;
-
- AsyncWaitCallbackData(JNIEnv* env, jobject core_impl, jobject callback) {
- this->core_impl.Reset(env, core_impl);
- this->callback.Reset(env, callback);
- }
-};
-
-void AsyncWaitCallback(mojo::common::HandleWatcher* watcher,
- void* data,
- MojoResult result) {
- delete watcher;
- std::unique_ptr<AsyncWaitCallbackData> callback_data(
- static_cast<AsyncWaitCallbackData*>(data));
- mojo::android::Java_CoreImpl_onAsyncWaitResult(
- base::android::AttachCurrentThread(),
- callback_data->core_impl.obj(),
- result,
- callback_data->callback.obj(),
- callback_data->cancellable.obj());
-}
-
-} // namespace
-
namespace mojo {
namespace android {
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
static jlong GetTimeTicksNow(JNIEnv* env,
const JavaParamRef<jobject>& jcaller) {
return MojoGetTimeTicksNow();
@@ -365,51 +329,6 @@ static int Unmap(JNIEnv* env,
return MojoUnmapBuffer(buffer_start);
}
-static ScopedJavaLocalRef<jobject> AsyncWait(
- JNIEnv* env,
- const JavaParamRef<jobject>& jcaller,
- jint mojo_handle,
- jint signals,
- jlong deadline,
- const JavaParamRef<jobject>& callback) {
- AsyncWaitCallbackData* callback_data =
- new AsyncWaitCallbackData(env, jcaller, callback);
- MojoAsyncWaitID cancel_id;
- if (static_cast<MojoHandle>(mojo_handle) != MOJO_HANDLE_INVALID) {
- common::HandleWatcher* watcher = new common::HandleWatcher();
- cancel_id = reinterpret_cast<MojoAsyncWaitID>(watcher);
- watcher->Start(Handle(static_cast<MojoHandle>(mojo_handle)), signals,
- deadline,
- base::Bind(&AsyncWaitCallback, watcher, callback_data));
- } else {
- cancel_id = kInvalidHandleCancelID;
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&AsyncWaitCallback, nullptr, callback_data,
- MOJO_RESULT_INVALID_ARGUMENT));
- }
- base::android::ScopedJavaLocalRef<jobject> cancellable =
- Java_CoreImpl_newAsyncWaiterCancellableImpl(
- env, jcaller, cancel_id, reinterpret_cast<intptr_t>(callback_data));
- callback_data->cancellable.Reset(env, cancellable.obj());
- return cancellable;
-}
-
-static void CancelAsyncWait(JNIEnv* env,
- const JavaParamRef<jobject>& jcaller,
- jlong id,
- jlong data_ptr) {
- if (id == 0) {
- // If |id| is |kInvalidHandleCancelID|, the async wait was done on an
- // invalid handle, so the AsyncWaitCallback will be called and will clear
- // the data_ptr.
- return;
- }
- std::unique_ptr<AsyncWaitCallbackData> deleter(
- reinterpret_cast<AsyncWaitCallbackData*>(data_ptr));
- delete reinterpret_cast<common::HandleWatcher*>(
- static_cast<MojoAsyncWaitID>(id));
-}
-
static jint GetNativeBufferOffset(JNIEnv* env,
const JavaParamRef<jobject>& jcaller,
const JavaParamRef<jobject>& buffer,
diff --git a/mojo/android/system/src/org/chromium/mojo/system/impl/BaseRunLoop.java b/mojo/android/system/src/org/chromium/mojo/system/impl/BaseRunLoop.java
index dfe92ef..3db6670 100644
--- a/mojo/android/system/src/org/chromium/mojo/system/impl/BaseRunLoop.java
+++ b/mojo/android/system/src/org/chromium/mojo/system/impl/BaseRunLoop.java
@@ -27,13 +27,13 @@ class BaseRunLoop implements RunLoop {
@Override
public void run() {
assert mRunLoopID != 0 : "The run loop cannot run once closed";
- nativeRun(mRunLoopID);
+ nativeRun();
}
@Override
public void runUntilIdle() {
assert mRunLoopID != 0 : "The run loop cannot run once closed";
- nativeRunUntilIdle(mRunLoopID);
+ nativeRunUntilIdle();
}
@Override
@@ -66,8 +66,8 @@ class BaseRunLoop implements RunLoop {
}
private native long nativeCreateBaseRunLoop();
- private native void nativeRun(long runLoopID);
- private native void nativeRunUntilIdle(long runLoopID);
+ private native void nativeRun();
+ private native void nativeRunUntilIdle();
private native void nativeQuit(long runLoopID);
private native void nativePostDelayedTask(long runLoopID, Runnable runnable, long delay);
private native void nativeDeleteMessageLoop(long runLoopID);
diff --git a/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java b/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java
index a20ea0a..8330586 100644
--- a/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java
+++ b/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java
@@ -7,7 +7,6 @@ package org.chromium.mojo.system.impl;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.MainDex;
-import org.chromium.mojo.system.AsyncWaiter;
import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.DataPipe;
import org.chromium.mojo.system.DataPipe.ConsumerHandle;
@@ -23,6 +22,7 @@ import org.chromium.mojo.system.SharedBufferHandle;
import org.chromium.mojo.system.SharedBufferHandle.DuplicateOptions;
import org.chromium.mojo.system.SharedBufferHandle.MapFlags;
import org.chromium.mojo.system.UntypedHandle;
+import org.chromium.mojo.system.Watcher;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -35,7 +35,7 @@ import java.util.List;
*/
@JNINamespace("mojo::android")
@MainDex
-public class CoreImpl implements Core, AsyncWaiter {
+public class CoreImpl implements Core {
/**
* Discard flag for the |MojoReadData| operation.
*/
@@ -216,11 +216,11 @@ public class CoreImpl implements Core, AsyncWaiter {
}
/**
- * @see Core#getDefaultAsyncWaiter()
+ * @see Core#getWatcher()
*/
@Override
- public AsyncWaiter getDefaultAsyncWaiter() {
- return this;
+ public Watcher getWatcher() {
+ return new WatcherImpl();
}
/**
@@ -251,15 +251,6 @@ public class CoreImpl implements Core, AsyncWaiter {
mCurrentRunLoop.remove();
}
- /**
- * @see AsyncWaiter#asyncWait(Handle, Core.HandleSignals, long, Callback)
- */
- @Override
- public Cancellable asyncWait(
- Handle handle, HandleSignals signals, long deadline, Callback callback) {
- return nativeAsyncWait(getMojoHandle(handle), signals.getFlags(), deadline, callback);
- }
-
int closeWithResult(int mojoHandle) {
return nativeClose(mojoHandle);
}
@@ -497,59 +488,6 @@ public class CoreImpl implements Core, AsyncWaiter {
return buffer.order(ByteOrder.nativeOrder());
}
- /**
- * Implementation of {@link org.chromium.mojo.system.AsyncWaiter.Cancellable}.
- */
- private class AsyncWaiterCancellableImpl implements AsyncWaiter.Cancellable {
- private final long mId;
- private final long mDataPtr;
- private boolean mActive = true;
-
- private AsyncWaiterCancellableImpl(long id, long dataPtr) {
- this.mId = id;
- this.mDataPtr = dataPtr;
- }
-
- /**
- * @see org.chromium.mojo.system.AsyncWaiter.Cancellable#cancel()
- */
- @Override
- public void cancel() {
- if (mActive) {
- mActive = false;
- nativeCancelAsyncWait(mId, mDataPtr);
- }
- }
-
- private boolean isActive() {
- return mActive;
- }
-
- private void deactivate() {
- mActive = false;
- }
- }
-
- @CalledByNative
- private AsyncWaiterCancellableImpl newAsyncWaiterCancellableImpl(long id, long dataPtr) {
- return new AsyncWaiterCancellableImpl(id, dataPtr);
- }
-
- @CalledByNative
- private void onAsyncWaitResult(
- int mojoResult, AsyncWaiter.Callback callback, AsyncWaiterCancellableImpl cancellable) {
- if (!cancellable.isActive()) {
- // If cancellable is not active, the user cancelled the wait.
- return;
- }
- cancellable.deactivate();
- if (isUnrecoverableError(mojoResult)) {
- callback.onError(new MojoException(mojoResult));
- return;
- }
- callback.onResult(mojoResult);
- }
-
@CalledByNative
private static ResultAnd<ByteBuffer> newResultAndBuffer(int mojoResult, ByteBuffer buffer) {
return new ResultAnd<>(mojoResult, buffer);
@@ -629,10 +567,5 @@ public class CoreImpl implements Core, AsyncWaiter {
private native int nativeUnmap(ByteBuffer buffer);
- private native AsyncWaiterCancellableImpl nativeAsyncWait(
- int mojoHandle, int signals, long deadline, AsyncWaiter.Callback callback);
-
- private native void nativeCancelAsyncWait(long mId, long dataPtr);
-
private native int nativeGetNativeBufferOffset(ByteBuffer buffer, int alignment);
}
diff --git a/mojo/android/system/src/org/chromium/mojo/system/impl/WatcherImpl.java b/mojo/android/system/src/org/chromium/mojo/system/impl/WatcherImpl.java
new file mode 100644
index 0000000..094ad90
--- /dev/null
+++ b/mojo/android/system/src/org/chromium/mojo/system/impl/WatcherImpl.java
@@ -0,0 +1,63 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.mojo.system.impl;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.mojo.system.Core;
+import org.chromium.mojo.system.Handle;
+import org.chromium.mojo.system.MojoResult;
+import org.chromium.mojo.system.Watcher;
+
+@JNINamespace("mojo::android")
+class WatcherImpl implements Watcher {
+ private long mImplPtr = nativeCreateWatcher();
+ private Callback mCallback;
+
+ @Override
+ public int start(Handle handle, Core.HandleSignals signals, Callback callback) {
+ if (mImplPtr == 0) {
+ return MojoResult.INVALID_ARGUMENT;
+ }
+ if (!(handle instanceof HandleBase)) {
+ return MojoResult.INVALID_ARGUMENT;
+ }
+ int result =
+ nativeStart(mImplPtr, ((HandleBase) handle).getMojoHandle(), signals.getFlags());
+ if (result == MojoResult.OK) mCallback = callback;
+ return result;
+ }
+
+ @Override
+ public void cancel() {
+ if (mImplPtr == 0) {
+ return;
+ }
+ mCallback = null;
+ nativeCancel(mImplPtr);
+ }
+
+ @Override
+ public void destroy() {
+ if (mImplPtr == 0) {
+ return;
+ }
+ nativeDelete(mImplPtr);
+ mImplPtr = 0;
+ }
+
+ @CalledByNative
+ private void onHandleReady(int result) {
+ mCallback.onResult(result);
+ }
+
+ private native long nativeCreateWatcher();
+
+ private native int nativeStart(long implPtr, int mojoHandle, int flags);
+
+ private native void nativeCancel(long implPtr);
+
+ private native void nativeDelete(long implPtr);
+}
diff --git a/mojo/android/system/watcher_impl.cc b/mojo/android/system/watcher_impl.cc
new file mode 100644
index 0000000..28d8c9f
--- /dev/null
+++ b/mojo/android/system/watcher_impl.cc
@@ -0,0 +1,109 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/android/system/watcher_impl.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/android/base_jni_registrar.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_registrar.h"
+#include "base/android/library_loader/library_loader_hooks.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/bind.h"
+#include "jni/WatcherImpl_jni.h"
+#include "mojo/public/cpp/system/handle.h"
+#include "mojo/public/cpp/system/watcher.h"
+
+namespace mojo {
+namespace android {
+
+using base::android::JavaParamRef;
+
+namespace {
+
+class WatcherImpl {
+ public:
+ WatcherImpl() : watcher_(FROM_HERE) {}
+
+ ~WatcherImpl() = default;
+
+ jint Start(JNIEnv* env,
+ const JavaParamRef<jobject>& jcaller,
+ jint mojo_handle,
+ jint signals) {
+ java_watcher_.Reset(env, jcaller);
+
+ auto ready_callback =
+ base::Bind(&WatcherImpl::OnHandleReady, base::Unretained(this));
+
+ MojoResult result =
+ watcher_.Start(mojo::Handle(static_cast<MojoHandle>(mojo_handle)),
+ static_cast<MojoHandleSignals>(signals), ready_callback);
+
+ if (result != MOJO_RESULT_OK)
+ java_watcher_.Reset();
+
+ return result;
+ }
+
+ void Cancel() {
+ java_watcher_.Reset();
+ watcher_.Cancel();
+ }
+
+ private:
+ void OnHandleReady(MojoResult result) {
+ DCHECK(!java_watcher_.is_null());
+
+ base::android::ScopedJavaGlobalRef<jobject> java_watcher_preserver;
+ if (result == MOJO_RESULT_CANCELLED)
+ java_watcher_preserver = std::move(java_watcher_);
+
+ Java_WatcherImpl_onHandleReady(
+ base::android::AttachCurrentThread(),
+ java_watcher_.is_null() ? java_watcher_preserver : java_watcher_,
+ result);
+ }
+
+ Watcher watcher_;
+ base::android::ScopedJavaGlobalRef<jobject> java_watcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(WatcherImpl);
+};
+
+} // namespace
+
+static jlong CreateWatcher(JNIEnv* env, const JavaParamRef<jobject>& jcaller) {
+ return reinterpret_cast<jlong>(new WatcherImpl);
+}
+
+static jint Start(JNIEnv* env,
+ const JavaParamRef<jobject>& jcaller,
+ jlong watcher_ptr,
+ jint mojo_handle,
+ jint signals) {
+ auto* watcher = reinterpret_cast<WatcherImpl*>(watcher_ptr);
+ return watcher->Start(env, jcaller, mojo_handle, signals);
+}
+
+static void Cancel(JNIEnv* env,
+ const JavaParamRef<jobject>& jcaller,
+ jlong watcher_ptr) {
+ reinterpret_cast<WatcherImpl*>(watcher_ptr)->Cancel();
+}
+
+static void Delete(JNIEnv* env,
+ const JavaParamRef<jobject>& jcaller,
+ jlong watcher_ptr) {
+ delete reinterpret_cast<WatcherImpl*>(watcher_ptr);
+}
+
+bool RegisterWatcherImpl(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace android
+} // namespace mojo
diff --git a/mojo/android/system/watcher_impl.h b/mojo/android/system/watcher_impl.h
new file mode 100644
index 0000000..784f007
--- /dev/null
+++ b/mojo/android/system/watcher_impl.h
@@ -0,0 +1,20 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_ANDROID_SYSTEM_WATCHER_IMPL_H_
+#define MOJO_ANDROID_SYSTEM_WATCHER_IMPL_H_
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+
+namespace mojo {
+namespace android {
+
+JNI_EXPORT bool RegisterWatcherImpl(JNIEnv* env);
+
+} // namespace android
+} // namespace mojo
+
+#endif // MOJO_ANDROID_SYSTEM_WATCHER_IMPL_H_
diff --git a/mojo/common/BUILD.gn b/mojo/common/BUILD.gn
index 6dfed8e..9e74e58 100644
--- a/mojo/common/BUILD.gn
+++ b/mojo/common/BUILD.gn
@@ -12,29 +12,27 @@ group("common") {
]
}
-# GYP version: mojo/mojo_base.gyp:mojo_common_custom_types
mojom("common_custom_types") {
sources = [
- "common_custom_types.mojom",
+ "file.mojom",
+ "file_path.mojom",
"string16.mojom",
+ "text_direction.mojom",
"time.mojom",
+ "unguessable_token.mojom",
+ "values.mojom",
+ "version.mojom",
]
}
-# GYP version: mojo/mojo_base.gyp:mojo_common_lib
component("common_base") {
output_name = "mojo_common_lib"
sources = [
- "common_type_converters.cc",
- "common_type_converters.h",
"data_pipe_drainer.cc",
"data_pipe_drainer.h",
- "data_pipe_file_utils.cc",
"data_pipe_utils.cc",
"data_pipe_utils.h",
- "user_agent.cc",
- "user_agent.h",
]
defines = [ "MOJO_COMMON_IMPLEMENTATION" ]
@@ -46,21 +44,21 @@ component("common_base") {
]
}
-# GYP version: mojo/mojo_base.gyp:mojo_test_common_custom_types
mojom("test_common_custom_types") {
sources = [
"test_common_custom_types.mojom",
+ "traits_test_service.mojom",
]
public_deps = [
":common_custom_types",
]
}
-# GYP version: mojo/mojo_base.gyp:mojo_common_unittests
test("mojo_common_unittests") {
deps = [
":common",
":common_custom_types",
+ ":struct_traits",
":test_common_custom_types",
"//base",
"//base:message_loop_tests",
@@ -75,16 +73,21 @@ test("mojo_common_unittests") {
sources = [
"common_custom_types_unittest.cc",
- "common_type_converters_unittest.cc",
+ "struct_traits_unittest.cc",
]
}
-test("mojo_common_perftests") {
+source_set("struct_traits") {
+ sources = [
+ "common_custom_types_struct_traits.cc",
+ "common_custom_types_struct_traits.h",
+ ]
deps = [
- ":common",
- "//base",
- "//mojo/edk/test:run_all_perftests",
- "//mojo/public/cpp/test_support:test_utils",
- "//testing/gtest",
+ ":common_custom_types_shared_cpp_sources",
+ "//base:base",
+ "//mojo/public/cpp/system",
+ ]
+ public_deps = [
+ "//base:i18n",
]
}
diff --git a/mojo/common/DEPS b/mojo/common/DEPS
index 588c68d..e8ac428 100644
--- a/mojo/common/DEPS
+++ b/mojo/common/DEPS
@@ -1,16 +1,6 @@
include_rules = [
# common must not depend on embedder.
"-mojo",
- "+services/shell/public/cpp",
"+mojo/common",
"+mojo/public",
]
-
-specific_include_rules = {
- "trace_controller_impl\.h": [
- "+services/tracing/public/interfaces/tracing.mojom.h"
- ],
- "tracing_impl\.h": [
- "+services/tracing/public/interfaces/tracing.mojom.h"
- ],
-}
diff --git a/mojo/common/common_custom_types.typemap b/mojo/common/common_custom_types.typemap
deleted file mode 100644
index 0b63f38..0000000
--- a/mojo/common/common_custom_types.typemap
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//mojo/common/common_custom_types.mojom"
-public_headers = [
- "//base/files/file_path.h",
- "//base/values.h",
- "//base/time/time.h",
-]
-traits_headers = [ "//ipc/ipc_message_utils.h" ]
-public_deps = [
- "//ipc",
-]
-
-type_mappings = [
- "mojo.common.mojom.FilePath=base::FilePath",
- "mojo.common.mojom.DictionaryValue=base::DictionaryValue",
- "mojo.common.mojom.ListValue=base::ListValue",
- "mojo.common.mojom.String16=base::string16",
- "mojo.common.mojom.Time=base::Time",
- "mojo.common.mojom.TimeDelta=base::TimeDelta",
- "mojo.common.mojom.TimeTicks=base::TimeTicks",
-]
diff --git a/mojo/common/common_custom_types_struct_traits.cc b/mojo/common/common_custom_types_struct_traits.cc
index 3f9f7d9..6289504 100644
--- a/mojo/common/common_custom_types_struct_traits.cc
+++ b/mojo/common/common_custom_types_struct_traits.cc
@@ -1,18 +1,108 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "mojo/common/common_custom_types_struct_traits.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+
namespace mojo {
// static
-bool StructTraits<common::mojom::String16, base::string16>::Read(
- common::mojom::String16DataView data, base::string16* out) {
- std::vector<uint16_t> view;
- data.ReadData(&view);
+bool StructTraits<common::mojom::String16DataView, base::string16>::Read(
+ common::mojom::String16DataView data,
+ base::string16* out) {
+ ArrayDataView<uint16_t> view;
+ data.GetDataDataView(&view);
out->assign(reinterpret_cast<const base::char16*>(view.data()), view.size());
return true;
}
-} // mojo
+// static
+const std::vector<uint32_t>&
+StructTraits<common::mojom::VersionDataView, base::Version>::components(
+ const base::Version& version) {
+ return version.components();
+}
+
+// static
+bool StructTraits<common::mojom::VersionDataView, base::Version>::Read(
+ common::mojom::VersionDataView data,
+ base::Version* out) {
+ std::vector<uint32_t> components;
+ if (!data.ReadComponents(&components))
+ return false;
+
+ *out = base::Version(base::Version(std::move(components)));
+ return out->IsValid();
+}
+
+// static
+bool StructTraits<
+ common::mojom::UnguessableTokenDataView,
+ base::UnguessableToken>::Read(common::mojom::UnguessableTokenDataView data,
+ base::UnguessableToken* out) {
+ uint64_t high = data.high();
+ uint64_t low = data.low();
+
+ // Receiving a zeroed UnguessableToken is a security issue.
+ if (high == 0 && low == 0)
+ return false;
+
+ *out = base::UnguessableToken::Deserialize(high, low);
+ return true;
+}
+
+mojo::ScopedHandle StructTraits<common::mojom::FileDataView, base::File>::fd(
+ base::File& file) {
+ DCHECK(file.IsValid());
+ return mojo::WrapPlatformFile(file.TakePlatformFile());
+}
+
+bool StructTraits<common::mojom::FileDataView, base::File>::Read(
+ common::mojom::FileDataView data,
+ base::File* file) {
+ base::PlatformFile platform_handle = base::kInvalidPlatformFile;
+ if (mojo::UnwrapPlatformFile(data.TakeFd(), &platform_handle) !=
+ MOJO_RESULT_OK) {
+ return false;
+ }
+ *file = base::File(platform_handle);
+ return true;
+}
+
+// static
+common::mojom::TextDirection
+EnumTraits<common::mojom::TextDirection, base::i18n::TextDirection>::ToMojom(
+ base::i18n::TextDirection text_direction) {
+ switch (text_direction) {
+ case base::i18n::UNKNOWN_DIRECTION:
+ return common::mojom::TextDirection::UNKNOWN_DIRECTION;
+ case base::i18n::RIGHT_TO_LEFT:
+ return common::mojom::TextDirection::RIGHT_TO_LEFT;
+ case base::i18n::LEFT_TO_RIGHT:
+ return common::mojom::TextDirection::LEFT_TO_RIGHT;
+ }
+ NOTREACHED();
+ return common::mojom::TextDirection::UNKNOWN_DIRECTION;
+}
+
+// static
+bool EnumTraits<common::mojom::TextDirection, base::i18n::TextDirection>::
+ FromMojom(common::mojom::TextDirection input,
+ base::i18n::TextDirection* out) {
+ switch (input) {
+ case common::mojom::TextDirection::UNKNOWN_DIRECTION:
+ *out = base::i18n::UNKNOWN_DIRECTION;
+ return true;
+ case common::mojom::TextDirection::RIGHT_TO_LEFT:
+ *out = base::i18n::RIGHT_TO_LEFT;
+ return true;
+ case common::mojom::TextDirection::LEFT_TO_RIGHT:
+ *out = base::i18n::LEFT_TO_RIGHT;
+ return true;
+ }
+ return false;
+}
+
+} // namespace mojo
diff --git a/mojo/common/common_custom_types_struct_traits.h b/mojo/common/common_custom_types_struct_traits.h
index 4cbb3f9..b20c795 100644
--- a/mojo/common/common_custom_types_struct_traits.h
+++ b/mojo/common/common_custom_types_struct_traits.h
@@ -1,45 +1,69 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_COMMON_COMMON_CUSTOM_TYPES_STRUCT_TRAITS_H_
#define MOJO_COMMON_COMMON_CUSTOM_TYPES_STRUCT_TRAITS_H_
-#include <stdint.h>
-#include <vector>
-
-#include "base/strings/string16.h"
-#include "base/time/time.h"
-#include "mojo/common/string16.mojom.h"
-#include "mojo/common/time.mojom.h"
-#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "base/files/file.h"
+#include "base/i18n/rtl.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/unguessable_token.h"
+#include "base/version.h"
+#include "mojo/common/file.mojom-shared.h"
+#include "mojo/common/mojo_common_export.h"
+#include "mojo/common/string16.mojom-shared.h"
+#include "mojo/common/text_direction.mojom-shared.h"
+#include "mojo/common/time.mojom-shared.h"
+#include "mojo/common/unguessable_token.mojom-shared.h"
+#include "mojo/common/version.mojom-shared.h"
namespace mojo {
template <>
-struct StructTraits<common::mojom::String16, base::string16> {
- static std::vector<uint16_t> data(const base::string16& str) {
- const uint16_t* base = str.data();
- return std::vector<uint16_t>(base, base + str.size());
+struct StructTraits<common::mojom::String16DataView, base::string16> {
+ static ConstCArray<uint16_t> data(const base::string16& str) {
+ return ConstCArray<uint16_t>(str.size(),
+ reinterpret_cast<const uint16_t*>(str.data()));
}
- static bool Read(common::mojom::String16DataView data, base::string16* output);
+
+ static bool Read(common::mojom::String16DataView data, base::string16* out);
};
template <>
-struct StructTraits<common::mojom::Time, base::Time> {
- static int64_t internal_value(const base::Time& time) {
- return time.ToInternalValue();
+struct StructTraits<common::mojom::VersionDataView, base::Version> {
+ static bool IsNull(const base::Version& version) {
+ return !version.IsValid();
+ }
+ static void SetToNull(base::Version* out) {
+ *out = base::Version(std::string());
}
+ static const std::vector<uint32_t>& components(const base::Version& version);
+ static bool Read(common::mojom::VersionDataView data, base::Version* out);
+};
- static bool Read(common::mojom::TimeDataView data, base::Time* time) {
- *time =
- base::Time() + base::TimeDelta::FromMicroseconds(data.internal_value());
- return true;
+// If base::UnguessableToken is no longer 128 bits, the logic below and the
+// mojom::UnguessableToken type should be updated.
+static_assert(sizeof(base::UnguessableToken) == 2 * sizeof(uint64_t),
+ "base::UnguessableToken should be of size 2 * sizeof(uint64_t).");
+
+template <>
+struct StructTraits<common::mojom::UnguessableTokenDataView,
+ base::UnguessableToken> {
+ static uint64_t high(const base::UnguessableToken& token) {
+ return token.GetHighForSerialization();
+ }
+
+ static uint64_t low(const base::UnguessableToken& token) {
+ return token.GetLowForSerialization();
}
+
+ static bool Read(common::mojom::UnguessableTokenDataView data,
+ base::UnguessableToken* out);
};
template <>
-struct StructTraits<common::mojom::TimeDelta, base::TimeDelta> {
+struct StructTraits<common::mojom::TimeDeltaDataView, base::TimeDelta> {
static int64_t microseconds(const base::TimeDelta& delta) {
return delta.InMicroseconds();
}
@@ -52,19 +76,23 @@ struct StructTraits<common::mojom::TimeDelta, base::TimeDelta> {
};
template <>
-struct StructTraits<common::mojom::TimeTicks, base::TimeTicks> {
- static int64_t internal_value(const base::TimeTicks& time) {
- return time.ToInternalValue();
- }
+struct StructTraits<common::mojom::FileDataView, base::File> {
+ static bool IsNull(const base::File& file) { return !file.IsValid(); }
- static bool Read(common::mojom::TimeTicksDataView data,
- base::TimeTicks* time) {
- *time = base::TimeTicks() +
- base::TimeDelta::FromMicroseconds(data.internal_value());
- return true;
- }
+ static void SetToNull(base::File* file) { *file = base::File(); }
+
+ static mojo::ScopedHandle fd(base::File& file);
+ static bool Read(common::mojom::FileDataView data, base::File* file);
+};
+
+template <>
+struct EnumTraits<common::mojom::TextDirection, base::i18n::TextDirection> {
+ static common::mojom::TextDirection ToMojom(
+ base::i18n::TextDirection text_direction);
+ static bool FromMojom(common::mojom::TextDirection input,
+ base::i18n::TextDirection* out);
};
-} // mojo
+} // namespace mojo
#endif // MOJO_COMMON_COMMON_CUSTOM_TYPES_STRUCT_TRAITS_H_
diff --git a/mojo/common/common_custom_types_unittest.cc b/mojo/common/common_custom_types_unittest.cc
index fe6bb5d..e3571d9 100644
--- a/mojo/common/common_custom_types_unittest.cc
+++ b/mojo/common/common_custom_types_unittest.cc
@@ -3,10 +3,13 @@
// found in the LICENSE file.
#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
+#include "base/numerics/safe_math.h"
#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
-#include "mojo/common/common_custom_types.mojom.h"
#include "mojo/common/test_common_custom_types.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,33 +26,38 @@ struct BounceTestTraits {
}
};
+template <typename T>
+struct PassTraits {
+ using Type = const T&;
+};
+
template <>
-struct BounceTestTraits<base::DictionaryValue> {
- static void ExpectEquality(const base::DictionaryValue& a,
- const base::DictionaryValue& b) {
- EXPECT_TRUE(a.Equals(&b));
- }
+struct PassTraits<base::Time> {
+ using Type = base::Time;
};
template <>
-struct BounceTestTraits<base::ListValue> {
- static void ExpectEquality(const base::ListValue& a,
- const base::ListValue& b) {
- EXPECT_TRUE(a.Equals(&b));
- }
+struct PassTraits<base::TimeDelta> {
+ using Type = base::TimeDelta;
+};
+
+template <>
+struct PassTraits<base::TimeTicks> {
+ using Type = base::TimeTicks;
};
template <typename T>
void DoExpectResponse(T* expected_value,
const base::Closure& closure,
- const T& value) {
+ typename PassTraits<T>::Type value) {
BounceTestTraits<T>::ExpectEquality(*expected_value, value);
closure.Run();
}
template <typename T>
-base::Callback<void(const T&)> ExpectResponse(T* expected_value,
- const base::Closure& closure) {
+base::Callback<void(typename PassTraits<T>::Type)> ExpectResponse(
+ T* expected_value,
+ const base::Closure& closure) {
return base::Bind(&DoExpectResponse<T>, expected_value, closure);
}
@@ -68,24 +76,38 @@ class TestFilePathImpl : public TestFilePath {
mojo::Binding<TestFilePath> binding_;
};
+class TestUnguessableTokenImpl : public TestUnguessableToken {
+ public:
+ explicit TestUnguessableTokenImpl(TestUnguessableTokenRequest request)
+ : binding_(this, std::move(request)) {}
+
+ // TestUnguessableToken implementation:
+ void BounceNonce(const base::UnguessableToken& in,
+ const BounceNonceCallback& callback) override {
+ callback.Run(in);
+ }
+
+ private:
+ mojo::Binding<TestUnguessableToken> binding_;
+};
+
class TestTimeImpl : public TestTime {
public:
explicit TestTimeImpl(TestTimeRequest request)
: binding_(this, std::move(request)) {}
// TestTime implementation:
- void BounceTime(const base::Time& in,
- const BounceTimeCallback& callback) override {
+ void BounceTime(base::Time in, const BounceTimeCallback& callback) override {
callback.Run(in);
}
- void BounceTimeDelta(const base::TimeDelta& in,
- const BounceTimeDeltaCallback& callback) override {
+ void BounceTimeDelta(base::TimeDelta in,
+ const BounceTimeDeltaCallback& callback) override {
callback.Run(in);
}
- void BounceTimeTicks(const base::TimeTicks& in,
- const BounceTimeTicksCallback& callback) override {
+ void BounceTimeTicks(base::TimeTicks in,
+ const BounceTimeTicksCallback& callback) override {
callback.Run(in);
}
@@ -100,19 +122,70 @@ class TestValueImpl : public TestValue {
// TestValue implementation:
void BounceDictionaryValue(
- const base::DictionaryValue& in,
+ std::unique_ptr<base::DictionaryValue> in,
const BounceDictionaryValueCallback& callback) override {
- callback.Run(in);
+ callback.Run(std::move(in));
}
- void BounceListValue(const base::ListValue& in,
+
+ void BounceListValue(std::unique_ptr<base::ListValue> in,
const BounceListValueCallback& callback) override {
- callback.Run(in);
+ callback.Run(std::move(in));
+ }
+
+ void BounceValue(std::unique_ptr<base::Value> in,
+ const BounceValueCallback& callback) override {
+ callback.Run(std::move(in));
}
private:
mojo::Binding<TestValue> binding_;
};
+class TestString16Impl : public TestString16 {
+ public:
+ explicit TestString16Impl(TestString16Request request)
+ : binding_(this, std::move(request)) {}
+
+ // TestString16 implementation:
+ void BounceString16(const base::string16& in,
+ const BounceString16Callback& callback) override {
+ callback.Run(in);
+ }
+
+ private:
+ mojo::Binding<TestString16> binding_;
+};
+
+class TestFileImpl : public TestFile {
+ public:
+ explicit TestFileImpl(TestFileRequest request)
+ : binding_(this, std::move(request)) {}
+
+ // TestFile implementation:
+ void BounceFile(base::File in, const BounceFileCallback& callback) override {
+ callback.Run(std::move(in));
+ }
+
+ private:
+ mojo::Binding<TestFile> binding_;
+};
+
+class TestTextDirectionImpl : public TestTextDirection {
+ public:
+ explicit TestTextDirectionImpl(TestTextDirectionRequest request)
+ : binding_(this, std::move(request)) {}
+
+ // TestTextDirection:
+ void BounceTextDirection(
+ base::i18n::TextDirection in,
+ const BounceTextDirectionCallback& callback) override {
+ callback.Run(in);
+ }
+
+ private:
+ mojo::Binding<TestTextDirection> binding_;
+};
+
class CommonCustomTypesTest : public testing::Test {
protected:
CommonCustomTypesTest() {}
@@ -130,7 +203,7 @@ TEST_F(CommonCustomTypesTest, FilePath) {
base::RunLoop run_loop;
TestFilePathPtr ptr;
- TestFilePathImpl impl(GetProxy(&ptr));
+ TestFilePathImpl impl(MakeRequest(&ptr));
base::FilePath dir(FILE_PATH_LITERAL("hello"));
base::FilePath file = dir.Append(FILE_PATH_LITERAL("world"));
@@ -140,11 +213,24 @@ TEST_F(CommonCustomTypesTest, FilePath) {
run_loop.Run();
}
+TEST_F(CommonCustomTypesTest, UnguessableToken) {
+ base::RunLoop run_loop;
+
+ TestUnguessableTokenPtr ptr;
+ TestUnguessableTokenImpl impl(MakeRequest(&ptr));
+
+ base::UnguessableToken token = base::UnguessableToken::Create();
+
+ ptr->BounceNonce(token, ExpectResponse(&token, run_loop.QuitClosure()));
+
+ run_loop.Run();
+}
+
TEST_F(CommonCustomTypesTest, Time) {
base::RunLoop run_loop;
TestTimePtr ptr;
- TestTimeImpl impl(GetProxy(&ptr));
+ TestTimeImpl impl(MakeRequest(&ptr));
base::Time t = base::Time::Now();
@@ -157,7 +243,7 @@ TEST_F(CommonCustomTypesTest, TimeDelta) {
base::RunLoop run_loop;
TestTimePtr ptr;
- TestTimeImpl impl(GetProxy(&ptr));
+ TestTimeImpl impl(MakeRequest(&ptr));
base::TimeDelta t = base::TimeDelta::FromDays(123);
@@ -170,7 +256,7 @@ TEST_F(CommonCustomTypesTest, TimeTicks) {
base::RunLoop run_loop;
TestTimePtr ptr;
- TestTimeImpl impl(GetProxy(&ptr));
+ TestTimeImpl impl(MakeRequest(&ptr));
base::TimeTicks t = base::TimeTicks::Now();
@@ -181,43 +267,164 @@ TEST_F(CommonCustomTypesTest, TimeTicks) {
TEST_F(CommonCustomTypesTest, Value) {
TestValuePtr ptr;
- TestValueImpl impl(GetProxy(&ptr));
-
- base::DictionaryValue dict;
- dict.SetBoolean("bool", false);
- dict.SetInteger("int", 2);
- dict.SetString("string", "some string");
- dict.SetBoolean("nested.bool", true);
- dict.SetInteger("nested.int", 9);
- dict.Set("some_binary", base::BinaryValue::CreateWithCopiedBuffer("mojo", 4));
+ TestValueImpl impl(MakeRequest(&ptr));
+
+ std::unique_ptr<base::Value> output;
+
+ ASSERT_TRUE(ptr->BounceValue(nullptr, &output));
+ EXPECT_FALSE(output);
+
+ std::unique_ptr<base::Value> input = base::Value::CreateNullValue();
+ ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output));
+ EXPECT_TRUE(base::Value::Equals(input.get(), output.get()));
+
+ input = base::MakeUnique<base::Value>(123);
+ ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output));
+ EXPECT_TRUE(base::Value::Equals(input.get(), output.get()));
+
+ input = base::MakeUnique<base::Value>(1.23);
+ ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output));
+ EXPECT_TRUE(base::Value::Equals(input.get(), output.get()));
+
+ input = base::MakeUnique<base::Value>(false);
+ ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output));
+ EXPECT_TRUE(base::Value::Equals(input.get(), output.get()));
+
+ input = base::MakeUnique<base::Value>("test string");
+ ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output));
+ EXPECT_TRUE(base::Value::Equals(input.get(), output.get()));
+
+ input = base::BinaryValue::CreateWithCopiedBuffer("mojo", 4);
+ ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output));
+ EXPECT_TRUE(base::Value::Equals(input.get(), output.get()));
+
+ auto dict = base::MakeUnique<base::DictionaryValue>();
+ dict->SetBoolean("bool", false);
+ dict->SetInteger("int", 2);
+ dict->SetString("string", "some string");
+ dict->SetBoolean("nested.bool", true);
+ dict->SetInteger("nested.int", 9);
+ dict->Set("some_binary",
+ base::BinaryValue::CreateWithCopiedBuffer("mojo", 4));
+ dict->Set("null_value", base::Value::CreateNullValue());
+ dict->SetIntegerWithoutPathExpansion("non_nested.int", 10);
{
std::unique_ptr<base::ListValue> dict_list(new base::ListValue());
dict_list->AppendString("string");
dict_list->AppendBoolean(true);
- dict.Set("list", std::move(dict_list));
- }
- {
- base::RunLoop run_loop;
- ptr->BounceDictionaryValue(
- dict, ExpectResponse(&dict, run_loop.QuitClosure()));
- run_loop.Run();
+ dict->Set("list", std::move(dict_list));
}
- base::ListValue list;
- list.AppendString("string");
- list.AppendDouble(42.1);
- list.AppendBoolean(true);
- list.Append(base::BinaryValue::CreateWithCopiedBuffer("mojo", 4));
+ std::unique_ptr<base::DictionaryValue> dict_output;
+ ASSERT_TRUE(ptr->BounceDictionaryValue(dict->CreateDeepCopy(), &dict_output));
+ EXPECT_TRUE(base::Value::Equals(dict.get(), dict_output.get()));
+
+ input = std::move(dict);
+ ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output));
+ EXPECT_TRUE(base::Value::Equals(input.get(), output.get()));
+
+ auto list = base::MakeUnique<base::ListValue>();
+ list->AppendString("string");
+ list->AppendDouble(42.1);
+ list->AppendBoolean(true);
+ list->Append(base::BinaryValue::CreateWithCopiedBuffer("mojo", 4));
+ list->Append(base::Value::CreateNullValue());
{
std::unique_ptr<base::DictionaryValue> list_dict(
new base::DictionaryValue());
list_dict->SetString("string", "str");
- list.Append(std::move(list_dict));
+ list->Append(std::move(list_dict));
}
- {
- base::RunLoop run_loop;
- ptr->BounceListValue(list, ExpectResponse(&list, run_loop.QuitClosure()));
- run_loop.Run();
+ std::unique_ptr<base::ListValue> list_output;
+ ASSERT_TRUE(ptr->BounceListValue(list->CreateDeepCopy(), &list_output));
+ EXPECT_TRUE(base::Value::Equals(list.get(), list_output.get()));
+
+ input = std::move(list);
+ ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output));
+ ASSERT_TRUE(base::Value::Equals(input.get(), output.get()));
+}
+
+TEST_F(CommonCustomTypesTest, String16) {
+ base::RunLoop run_loop;
+
+ TestString16Ptr ptr;
+ TestString16Impl impl(MakeRequest(&ptr));
+
+ base::string16 str16 = base::ASCIIToUTF16("hello world");
+
+ ptr->BounceString16(str16, ExpectResponse(&str16, run_loop.QuitClosure()));
+
+ run_loop.Run();
+}
+
+TEST_F(CommonCustomTypesTest, EmptyString16) {
+ base::RunLoop run_loop;
+
+ TestString16Ptr ptr;
+ TestString16Impl impl(MakeRequest(&ptr));
+
+ base::string16 str16;
+
+ ptr->BounceString16(str16, ExpectResponse(&str16, run_loop.QuitClosure()));
+
+ run_loop.Run();
+}
+
+TEST_F(CommonCustomTypesTest, File) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+ TestFilePtr ptr;
+ TestFileImpl impl(MakeRequest(&ptr));
+
+ base::File file(
+ temp_dir.GetPath().AppendASCII("test_file.txt"),
+ base::File::FLAG_CREATE | base::File::FLAG_WRITE | base::File::FLAG_READ);
+ const base::StringPiece test_content =
+ "A test string to be stored in a test file";
+ file.WriteAtCurrentPos(
+ test_content.data(),
+ base::CheckedNumeric<int>(test_content.size()).ValueOrDie());
+
+ base::File file_out;
+ ASSERT_TRUE(ptr->BounceFile(std::move(file), &file_out));
+ std::vector<char> content(test_content.size());
+ ASSERT_TRUE(file_out.IsValid());
+ ASSERT_EQ(static_cast<int>(test_content.size()),
+ file_out.Read(
+ 0, content.data(),
+ base::CheckedNumeric<int>(test_content.size()).ValueOrDie()));
+ EXPECT_EQ(test_content,
+ base::StringPiece(content.data(), test_content.size()));
+}
+
+TEST_F(CommonCustomTypesTest, InvalidFile) {
+ TestFilePtr ptr;
+ TestFileImpl impl(MakeRequest(&ptr));
+
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ // Test that |file_out| is set to an invalid file.
+ base::File file_out(
+ temp_dir.GetPath().AppendASCII("test_file.txt"),
+ base::File::FLAG_CREATE | base::File::FLAG_WRITE | base::File::FLAG_READ);
+
+ ASSERT_TRUE(ptr->BounceFile(base::File(), &file_out));
+ EXPECT_FALSE(file_out.IsValid());
+}
+
+TEST_F(CommonCustomTypesTest, TextDirection) {
+ base::i18n::TextDirection kTestDirections[] = {base::i18n::LEFT_TO_RIGHT,
+ base::i18n::RIGHT_TO_LEFT,
+ base::i18n::UNKNOWN_DIRECTION};
+
+ TestTextDirectionPtr ptr;
+ TestTextDirectionImpl impl(MakeRequest(&ptr));
+
+ for (size_t i = 0; i < arraysize(kTestDirections); i++) {
+ base::i18n::TextDirection direction_out;
+ ASSERT_TRUE(ptr->BounceTextDirection(kTestDirections[i], &direction_out));
+ EXPECT_EQ(kTestDirections[i], direction_out);
}
}
diff --git a/mojo/common/common_type_converters.cc b/mojo/common/common_type_converters.cc
deleted file mode 100644
index 92ae3e2..0000000
--- a/mojo/common/common_type_converters.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/common/common_type_converters.h"
-
-#include <stdint.h>
-
-#include <string>
-
-#include "base/strings/utf_string_conversions.h"
-
-namespace mojo {
-
-// static
-String TypeConverter<String, base::StringPiece>::Convert(
- const base::StringPiece& input) {
- if (input.empty()) {
- char c = 0;
- return String(&c, 0);
- }
- return String(input.data(), input.size());
-}
-// static
-base::StringPiece TypeConverter<base::StringPiece, String>::Convert(
- const String& input) {
- return input.get();
-}
-
-// static
-String TypeConverter<String, base::string16>::Convert(
- const base::string16& input) {
- return TypeConverter<String, base::StringPiece>::Convert(
- base::UTF16ToUTF8(input));
-}
-// static
-base::string16 TypeConverter<base::string16, String>::Convert(
- const String& input) {
- return base::UTF8ToUTF16(input.To<base::StringPiece>());
-}
-
-std::string TypeConverter<std::string, Array<uint8_t>>::Convert(
- const Array<uint8_t>& input) {
- if (input.is_null() || input.empty())
- return std::string();
-
- return std::string(reinterpret_cast<const char*>(&input.front()),
- input.size());
-}
-
-Array<uint8_t> TypeConverter<Array<uint8_t>, std::string>::Convert(
- const std::string& input) {
- Array<uint8_t> result(input.size());
- if (!input.empty())
- memcpy(&result.front(), input.c_str(), input.size());
- return result;
-}
-
-Array<uint8_t> TypeConverter<Array<uint8_t>, base::StringPiece>::Convert(
- const base::StringPiece& input) {
- Array<uint8_t> result(input.size());
- if (!input.empty())
- memcpy(&result.front(), input.data(), input.size());
- return result;
-}
-
-base::string16 TypeConverter<base::string16, Array<uint8_t>>::Convert(
- const Array<uint8_t>& input) {
- if (input.is_null() || input.empty())
- return base::string16();
-
- return base::string16(reinterpret_cast<const base::char16*>(&input.front()),
- input.size() / sizeof(base::char16));
-}
-
-Array<uint8_t> TypeConverter<Array<uint8_t>, base::string16>::Convert(
- const base::string16& input) {
- Array<uint8_t> result(input.size() * sizeof(base::char16));
- if (!input.empty())
- memcpy(&result.front(), input.c_str(), input.size() * sizeof(base::char16));
- return result;
-}
-
-} // namespace mojo
diff --git a/mojo/common/common_type_converters.h b/mojo/common/common_type_converters.h
deleted file mode 100644
index a065f05..0000000
--- a/mojo/common/common_type_converters.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_COMMON_COMMON_TYPE_CONVERTERS_H_
-#define MOJO_COMMON_COMMON_TYPE_CONVERTERS_H_
-
-#include <stdint.h>
-
-#include "base/strings/string16.h"
-#include "base/strings/string_piece.h"
-#include "mojo/common/mojo_common_export.h"
-#include "mojo/public/cpp/bindings/array.h"
-#include "mojo/public/cpp/bindings/string.h"
-#include "mojo/public/cpp/bindings/type_converter.h"
-
-namespace mojo {
-
-template <>
-struct MOJO_COMMON_EXPORT TypeConverter<String, base::StringPiece> {
- static String Convert(const base::StringPiece& input);
-};
-
-template <>
-struct MOJO_COMMON_EXPORT TypeConverter<base::StringPiece, String> {
- static base::StringPiece Convert(const String& input);
-};
-
-template <>
-struct MOJO_COMMON_EXPORT TypeConverter<String, base::string16> {
- static String Convert(const base::string16& input);
-};
-
-template <>
-struct MOJO_COMMON_EXPORT TypeConverter<base::string16, String> {
- static base::string16 Convert(const String& input);
-};
-
-template <>
-struct MOJO_COMMON_EXPORT TypeConverter<std::string, Array<uint8_t>> {
- static std::string Convert(const Array<uint8_t>& input);
-};
-
-template <>
-struct MOJO_COMMON_EXPORT TypeConverter<Array<uint8_t>, std::string> {
- static Array<uint8_t> Convert(const std::string& input);
-};
-
-template <>
-struct MOJO_COMMON_EXPORT TypeConverter<Array<uint8_t>, base::StringPiece> {
- static Array<uint8_t> Convert(const base::StringPiece& input);
-};
-
-template <>
-struct MOJO_COMMON_EXPORT TypeConverter<base::string16, Array<uint8_t>> {
- static base::string16 Convert(const Array<uint8_t>& input);
-};
-
-template <>
-struct MOJO_COMMON_EXPORT TypeConverter<Array<uint8_t>, base::string16> {
- static Array<uint8_t> Convert(const base::string16& input);
-};
-
-} // namespace mojo
-
-#endif // MOJO_COMMON_COMMON_TYPE_CONVERTERS_H_
diff --git a/mojo/common/common_type_converters_unittest.cc b/mojo/common/common_type_converters_unittest.cc
deleted file mode 100644
index 1740d06..0000000
--- a/mojo/common/common_type_converters_unittest.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/common/common_type_converters.h"
-
-#include <stdint.h>
-
-#include "base/strings/utf_string_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace mojo {
-namespace common {
-namespace test {
-namespace {
-
-void ExpectEqualsStringPiece(const std::string& expected,
- const base::StringPiece& str) {
- EXPECT_EQ(expected, str.as_string());
-}
-
-void ExpectEqualsMojoString(const std::string& expected,
- const String& str) {
- EXPECT_EQ(expected, str.get());
-}
-
-void ExpectEqualsString16(const base::string16& expected,
- const base::string16& actual) {
- EXPECT_EQ(expected, actual);
-}
-
-void ExpectEqualsMojoString(const base::string16& expected,
- const String& str) {
- EXPECT_EQ(expected, str.To<base::string16>());
-}
-
-} // namespace
-
-TEST(CommonTypeConvertersTest, StringPiece) {
- std::string kText("hello world");
-
- base::StringPiece string_piece(kText);
- String mojo_string(String::From(string_piece));
-
- ExpectEqualsMojoString(kText, mojo_string);
- ExpectEqualsStringPiece(kText, mojo_string.To<base::StringPiece>());
-
- // Test implicit construction and conversion:
- ExpectEqualsMojoString(kText, String::From(string_piece));
- ExpectEqualsStringPiece(kText, mojo_string.To<base::StringPiece>());
-
- // Test null String:
- base::StringPiece empty_string_piece = String().To<base::StringPiece>();
- EXPECT_TRUE(empty_string_piece.empty());
-}
-
-TEST(CommonTypeConvertersTest, String16) {
- const base::string16 string16(base::ASCIIToUTF16("hello world"));
- const String mojo_string(String::From(string16));
-
- ExpectEqualsMojoString(string16, mojo_string);
- EXPECT_EQ(string16, mojo_string.To<base::string16>());
-
- // Test implicit construction and conversion:
- ExpectEqualsMojoString(string16, String::From(string16));
- ExpectEqualsString16(string16, mojo_string.To<base::string16>());
-
- // Test empty string conversion.
- ExpectEqualsMojoString(base::string16(), String::From(base::string16()));
-}
-
-TEST(CommonTypeConvertersTest, ArrayUint8ToStdString) {
- Array<uint8_t> data(4);
- data[0] = 'd';
- data[1] = 'a';
- data[2] = 't';
- data[3] = 'a';
-
- EXPECT_EQ("data", data.To<std::string>());
-}
-
-TEST(CommonTypeConvertersTest, StdStringToArrayUint8) {
- std::string input("data");
- Array<uint8_t> data = Array<uint8_t>::From(input);
-
- ASSERT_EQ(4ul, data.size());
- EXPECT_EQ('d', data[0]);
- EXPECT_EQ('a', data[1]);
- EXPECT_EQ('t', data[2]);
- EXPECT_EQ('a', data[3]);
-}
-
-TEST(CommonTypeConvertersTest, ArrayUint8ToString16) {
- Array<uint8_t> data(8);
- data[0] = 'd';
- data[2] = 'a';
- data[4] = 't';
- data[6] = 'a';
-
- EXPECT_EQ(base::ASCIIToUTF16("data"), data.To<base::string16>());
-}
-
-TEST(CommonTypeConvertersTest, String16ToArrayUint8) {
- base::string16 input(base::ASCIIToUTF16("data"));
- Array<uint8_t> data = Array<uint8_t>::From(input);
-
- ASSERT_EQ(8ul, data.size());
- EXPECT_EQ('d', data[0]);
- EXPECT_EQ('a', data[2]);
- EXPECT_EQ('t', data[4]);
- EXPECT_EQ('a', data[6]);
-}
-
-TEST(CommonTypeConvertersTest, String16ToArrayUint8AndBack) {
- base::string16 input(base::ASCIIToUTF16("data"));
- Array<uint8_t> data = Array<uint8_t>::From(input);
- EXPECT_EQ(input, data.To<base::string16>());
-}
-
-TEST(CommonTypeConvertersTest, EmptyStringToArrayUint8) {
- Array<uint8_t> data = Array<uint8_t>::From(std::string());
-
- ASSERT_EQ(0ul, data.size());
- EXPECT_FALSE(data.is_null());
-}
-
-} // namespace test
-} // namespace common
-} // namespace mojo
diff --git a/mojo/common/data_pipe_drainer.cc b/mojo/common/data_pipe_drainer.cc
index 1133e11..27bd893 100644
--- a/mojo/common/data_pipe_drainer.cc
+++ b/mojo/common/data_pipe_drainer.cc
@@ -15,7 +15,10 @@ namespace common {
DataPipeDrainer::DataPipeDrainer(Client* client,
mojo::ScopedDataPipeConsumerHandle source)
- : client_(client), source_(std::move(source)), weak_factory_(this) {
+ : client_(client),
+ source_(std::move(source)),
+ handle_watcher_(FROM_HERE),
+ weak_factory_(this) {
DCHECK(client_);
handle_watcher_.Start(
source_.get(), MOJO_HANDLE_SIGNAL_READABLE,
diff --git a/mojo/common/data_pipe_file_utils.cc b/mojo/common/data_pipe_file_utils.cc
deleted file mode 100644
index 841dfde..0000000
--- a/mojo/common/data_pipe_file_utils.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/common/data_pipe_utils.h"
-
-#include <stdint.h>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
-#include "base/location.h"
-#include "base/task_runner_util.h"
-
-namespace mojo {
-namespace common {
-namespace {
-
-bool BlockingCopyFromFile(const base::FilePath& source,
- ScopedDataPipeProducerHandle destination,
- uint32_t skip) {
- base::File file(source, base::File::FLAG_OPEN | base::File::FLAG_READ);
- if (!file.IsValid())
- return false;
- if (file.Seek(base::File::FROM_BEGIN, skip) != skip) {
- LOG(ERROR) << "Seek of " << skip << " in " << source.value() << " failed";
- return false;
- }
- for (;;) {
- void* buffer = nullptr;
- uint32_t buffer_num_bytes = 0;
- MojoResult result =
- BeginWriteDataRaw(destination.get(), &buffer, &buffer_num_bytes,
- MOJO_WRITE_DATA_FLAG_NONE);
- if (result == MOJO_RESULT_OK) {
- int bytes_read =
- file.ReadAtCurrentPos(static_cast<char*>(buffer), buffer_num_bytes);
- if (bytes_read >= 0) {
- EndWriteDataRaw(destination.get(), bytes_read);
- if (bytes_read == 0) {
- // eof
- return true;
- }
- } else {
- // error
- EndWriteDataRaw(destination.get(), 0);
- return false;
- }
- } else if (result == MOJO_RESULT_SHOULD_WAIT) {
- result = Wait(destination.get(), MOJO_HANDLE_SIGNAL_WRITABLE,
- MOJO_DEADLINE_INDEFINITE, nullptr);
- if (result != MOJO_RESULT_OK) {
- // If the consumer handle was closed, then treat as EOF.
- return result == MOJO_RESULT_FAILED_PRECONDITION;
- }
- } else {
- // If the consumer handle was closed, then treat as EOF.
- return result == MOJO_RESULT_FAILED_PRECONDITION;
- }
- }
-#if !defined(OS_WIN)
- NOTREACHED();
- return false;
-#endif
-}
-
-} // namespace
-
-void CopyFromFile(const base::FilePath& source,
- ScopedDataPipeProducerHandle destination,
- uint32_t skip,
- base::TaskRunner* task_runner,
- const base::Callback<void(bool)>& callback) {
- base::PostTaskAndReplyWithResult(task_runner, FROM_HERE,
- base::Bind(&BlockingCopyFromFile, source,
- base::Passed(&destination), skip),
- callback);
-}
-
-} // namespace common
-} // namespace mojo
diff --git a/mojo/common/data_pipe_utils.cc b/mojo/common/data_pipe_utils.cc
index 8540ac6..bed5e85 100644
--- a/mojo/common/data_pipe_utils.cc
+++ b/mojo/common/data_pipe_utils.cc
@@ -4,16 +4,9 @@
#include "mojo/common/data_pipe_utils.h"
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
#include <utility>
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
-#include "base/message_loop/message_loop.h"
-#include "base/task_runner_util.h"
+#include "base/bind.h"
namespace mojo {
namespace common {
@@ -58,12 +51,7 @@ size_t CopyToStringHelper(
return num_bytes;
}
-size_t CopyToFileHelper(FILE* fp, const void* buffer, uint32_t num_bytes) {
- return fwrite(buffer, 1, num_bytes, fp);
-}
-
-} // namespace
-
+} // namespace
// TODO(hansmuller): Add a max_size parameter.
bool BlockingCopyToString(ScopedDataPipeConsumerHandle source,
@@ -107,25 +95,5 @@ bool MOJO_COMMON_EXPORT BlockingCopyFromString(
}
}
-bool BlockingCopyToFile(ScopedDataPipeConsumerHandle source,
- const base::FilePath& destination) {
- base::ScopedFILE fp(base::OpenFile(destination, "wb"));
- if (!fp)
- return false;
- return BlockingCopyHelper(std::move(source),
- base::Bind(&CopyToFileHelper, fp.get()));
-}
-
-void CopyToFile(ScopedDataPipeConsumerHandle source,
- const base::FilePath& destination,
- base::TaskRunner* task_runner,
- const base::Callback<void(bool)>& callback) {
- base::PostTaskAndReplyWithResult(
- task_runner,
- FROM_HERE,
- base::Bind(&BlockingCopyToFile, base::Passed(&source), destination),
- callback);
-}
-
} // namespace common
} // namespace mojo
diff --git a/mojo/common/data_pipe_utils.h b/mojo/common/data_pipe_utils.h
index 426912c..a3f7c09 100644
--- a/mojo/common/data_pipe_utils.h
+++ b/mojo/common/data_pipe_utils.h
@@ -2,41 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef MOJO_SHELL_DATA_PIPE_UTILS_H_
-#define MOJO_SHELL_DATA_PIPE_UTILS_H_
+#ifndef MOJO_COMMON_DATA_PIPE_UTILS_H_
+#define MOJO_COMMON_DATA_PIPE_UTILS_H_
#include <stdint.h>
#include <string>
-#include "base/callback_forward.h"
#include "mojo/common/mojo_common_export.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace base {
-class FilePath;
-class TaskRunner;
-}
+#include "mojo/public/cpp/system/data_pipe.h"
namespace mojo {
namespace common {
-// Asynchronously copies data from source to the destination file. The given
-// |callback| is run upon completion. File writes will be scheduled to the
-// given |task_runner|.
-void MOJO_COMMON_EXPORT CopyToFile(
- ScopedDataPipeConsumerHandle source,
- const base::FilePath& destination,
- base::TaskRunner* task_runner,
- const base::Callback<void(bool /*success*/)>& callback);
-
-void MOJO_COMMON_EXPORT
-CopyFromFile(const base::FilePath& source,
- ScopedDataPipeProducerHandle destination,
- uint32_t skip,
- base::TaskRunner* task_runner,
- const base::Callback<void(bool /*success*/)>& callback);
-
// Copies the data from |source| into |contents| and returns true on success and
// false on error. In case of I/O error, |contents| holds the data that could
// be read from source before the error occurred.
@@ -48,13 +26,7 @@ bool MOJO_COMMON_EXPORT BlockingCopyFromString(
const std::string& source,
const ScopedDataPipeProducerHandle& destination);
-// Synchronously copies data from source to the destination file returning true
-// on success and false on error. In case of an error, |destination| holds the
-// data that could be read from the source before the error occured.
-bool MOJO_COMMON_EXPORT BlockingCopyToFile(ScopedDataPipeConsumerHandle source,
- const base::FilePath& destination);
-
} // namespace common
} // namespace mojo
-#endif // MOJO_SHELL_DATA_PIPE_UTILS_H_
+#endif // MOJO_COMMON_DATA_PIPE_UTILS_H_
diff --git a/mojo/common/common_custom_types.mojom b/mojo/common/file.mojom
index 4a04dbc..fe22473 100644
--- a/mojo/common/common_custom_types.mojom
+++ b/mojo/common/file.mojom
@@ -4,11 +4,7 @@
module mojo.common.mojom;
-[Native]
-struct FilePath;
-
-[Native]
-struct ListValue;
-
-[Native]
-struct DictionaryValue;
+// Corresponds to |base::File| in base/files/file.h
+struct File {
+ handle fd;
+};
diff --git a/mojo/common/file.typemap b/mojo/common/file.typemap
new file mode 100644
index 0000000..26d4941
--- /dev/null
+++ b/mojo/common/file.typemap
@@ -0,0 +1,13 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//mojo/common/file.mojom"
+public_headers = [ "//base/files/file.h" ]
+traits_headers = [ "//mojo/common/common_custom_types_struct_traits.h" ]
+public_deps = [
+ "//mojo/common:struct_traits",
+]
+
+type_mappings =
+ [ "mojo.common.mojom.File=base::File[move_only,nullable_is_same_type]" ]
diff --git a/mojo/common/string16.mojom b/mojo/common/string16.mojom
index eb1ace2..173c867 100644
--- a/mojo/common/string16.mojom
+++ b/mojo/common/string16.mojom
@@ -10,4 +10,3 @@ module mojo.common.mojom;
struct String16 {
array<uint16> data;
};
-
diff --git a/mojo/common/string16.typemap b/mojo/common/string16.typemap
new file mode 100644
index 0000000..223de29
--- /dev/null
+++ b/mojo/common/string16.typemap
@@ -0,0 +1,12 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//mojo/common/string16.mojom"
+public_headers = [ "//base/strings/string16.h" ]
+traits_headers = [ "//mojo/common/common_custom_types_struct_traits.h" ]
+public_deps = [
+ "//mojo/common:struct_traits",
+]
+
+type_mappings = [ "mojo.common.mojom.String16=base::string16" ]
diff --git a/mojo/common/test_common_custom_types.mojom b/mojo/common/test_common_custom_types.mojom
index db91a4f..0f13680 100644
--- a/mojo/common/test_common_custom_types.mojom
+++ b/mojo/common/test_common_custom_types.mojom
@@ -4,13 +4,24 @@
module mojo.common.test;
-import "mojo/common/common_custom_types.mojom";
+import "mojo/common/file.mojom";
+import "mojo/common/file_path.mojom";
+import "mojo/common/string16.mojom";
+import "mojo/common/text_direction.mojom";
+import "mojo/common/time.mojom";
+import "mojo/common/unguessable_token.mojom";
+import "mojo/common/values.mojom";
interface TestFilePath {
BounceFilePath(mojo.common.mojom.FilePath in)
=> (mojo.common.mojom.FilePath out);
};
+interface TestUnguessableToken {
+ BounceNonce(mojo.common.mojom.UnguessableToken in)
+ => (mojo.common.mojom.UnguessableToken out);
+};
+
interface TestTime {
BounceTime(mojo.common.mojom.Time time) => (mojo.common.mojom.Time time);
BounceTimeDelta(mojo.common.mojom.TimeDelta time_delta)
@@ -20,8 +31,31 @@ interface TestTime {
};
interface TestValue {
+ [Sync]
BounceDictionaryValue(mojo.common.mojom.DictionaryValue in)
=> (mojo.common.mojom.DictionaryValue out);
+ [Sync]
BounceListValue(mojo.common.mojom.ListValue in)
=> (mojo.common.mojom.ListValue out);
+ [Sync]
+ BounceValue(mojo.common.mojom.Value? in)
+ => (mojo.common.mojom.Value? out);
+};
+
+interface TestString16 {
+ [Sync]
+ BounceString16(mojo.common.mojom.String16 in)
+ => (mojo.common.mojom.String16 out);
+};
+
+interface TestFile {
+ [Sync]
+ BounceFile(mojo.common.mojom.File? in)
+ => (mojo.common.mojom.File? out);
+};
+
+interface TestTextDirection {
+ [Sync]
+ BounceTextDirection(mojo.common.mojom.TextDirection in)
+ => (mojo.common.mojom.TextDirection out);
};
diff --git a/mojo/common/text_direction.mojom b/mojo/common/text_direction.mojom
new file mode 100644
index 0000000..7d65124
--- /dev/null
+++ b/mojo/common/text_direction.mojom
@@ -0,0 +1,12 @@
+// 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.
+
+module mojo.common.mojom;
+
+// Corresponds to |base::i18n::TextDirection| in base/i18n/rtl.h
+enum TextDirection {
+ UNKNOWN_DIRECTION,
+ RIGHT_TO_LEFT,
+ LEFT_TO_RIGHT
+};
diff --git a/mojo/common/text_direction.typemap b/mojo/common/text_direction.typemap
new file mode 100644
index 0000000..1f5be8e
--- /dev/null
+++ b/mojo/common/text_direction.typemap
@@ -0,0 +1,12 @@
+# 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.
+
+mojom = "//mojo/common/text_direction.mojom"
+public_headers = [ "//base/i18n/rtl.h" ]
+traits_headers = [ "//mojo/common/common_custom_types_struct_traits.h" ]
+public_deps = [
+ "//base:i18n",
+ "//mojo/common:struct_traits",
+]
+type_mappings = [ "mojo.common.mojom.TextDirection=base::i18n::TextDirection" ]
diff --git a/mojo/common/time.mojom b/mojo/common/time.mojom
index b403bca..43dfcc8 100644
--- a/mojo/common/time.mojom
+++ b/mojo/common/time.mojom
@@ -4,18 +4,12 @@
module mojo.common.mojom;
-struct Time {
- // The internal value is expressed in terms of microseconds since a fixed but
- // intentionally unspecified epoch.
- int64 internal_value;
-};
+[Native]
+struct Time;
struct TimeDelta {
int64 microseconds;
};
-struct TimeTicks {
- // The internal value is expressed in terms of microseconds since a fixed but
- // intentionally unspecified epoch.
- int64 internal_value;
-};
+[Native]
+struct TimeTicks;
diff --git a/mojo/common/time.typemap b/mojo/common/time.typemap
index 20661f6..99e9e3a 100644
--- a/mojo/common/time.typemap
+++ b/mojo/common/time.typemap
@@ -4,9 +4,12 @@
mojom = "//mojo/common/time.mojom"
public_headers = [ "//base/time/time.h" ]
-traits_headers = [ "//mojo/common/time_struct_traits.h" ]
+traits_headers = [
+ "//ipc/ipc_message_utils.h",
+ "//mojo/common/common_custom_types_struct_traits.h",
+]
public_deps = [
- "//base",
+ "//ipc",
"//mojo/common:struct_traits",
]
diff --git a/mojo/common/unguessable_token.mojom b/mojo/common/unguessable_token.mojom
new file mode 100644
index 0000000..3279717
--- /dev/null
+++ b/mojo/common/unguessable_token.mojom
@@ -0,0 +1,11 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module mojo.common.mojom;
+
+// Corresponds to |base::UnguessableToken| in base/unguessable_token.h
+struct UnguessableToken {
+ uint64 high;
+ uint64 low;
+};
diff --git a/mojo/common/unguessable_token.typemap b/mojo/common/unguessable_token.typemap
new file mode 100644
index 0000000..ec7b194
--- /dev/null
+++ b/mojo/common/unguessable_token.typemap
@@ -0,0 +1,12 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//mojo/common/unguessable_token.mojom"
+public_headers = [ "//base/unguessable_token.h" ]
+traits_headers = [ "//mojo/common/common_custom_types_struct_traits.h" ]
+public_deps = [
+ "//mojo/common:struct_traits",
+]
+
+type_mappings = [ "mojo.common.mojom.UnguessableToken=base::UnguessableToken" ]
diff --git a/mojo/common/user_agent.cc b/mojo/common/user_agent.cc
deleted file mode 100644
index 6055cbe..0000000
--- a/mojo/common/user_agent.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/common/user_agent.h"
-
-#include "build/build_config.h"
-
-namespace mojo {
-namespace common {
-
-std::string GetUserAgent() {
- // TODO(jam): change depending on OS
-#if defined(OS_ANDROID)
- return "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 7 Build/LMY48G) "
- "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.68 "
- "Safari/537.36";
-#else
- return "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like "
- "Gecko) Chrome/42.0.2311.68 Safari/537.36";
-#endif
-}
-
-} // namespace common
-} // namespace mojo
diff --git a/mojo/common/user_agent.h b/mojo/common/user_agent.h
deleted file mode 100644
index 031b102..0000000
--- a/mojo/common/user_agent.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_COMMON_USER_AGENT_H_
-#define MOJO_COMMON_USER_AGENT_H_
-
-#include <string>
-
-#include "mojo/common/mojo_common_export.h"
-
-namespace mojo {
-namespace common {
-
-std::string MOJO_COMMON_EXPORT GetUserAgent();
-
-} // namespace common
-} // namespace mojo
-
-#endif // MOJO_COMMON_USER_AGENT_H_
diff --git a/mojo/common/version.mojom b/mojo/common/version.mojom
new file mode 100644
index 0000000..6ddf6e6
--- /dev/null
+++ b/mojo/common/version.mojom
@@ -0,0 +1,10 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module mojo.common.mojom;
+
+// Corresponds to |base::Version| in base/version.h
+struct Version {
+ array<uint32> components;
+};
diff --git a/mojo/common/version.typemap b/mojo/common/version.typemap
new file mode 100644
index 0000000..fa7fed9
--- /dev/null
+++ b/mojo/common/version.typemap
@@ -0,0 +1,12 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//mojo/common/version.mojom"
+public_headers = [ "//base/version.h" ]
+traits_headers = [ "//mojo/common/common_custom_types_struct_traits.h" ]
+public_deps = [
+ "//mojo/common:struct_traits",
+]
+
+type_mappings = [ "mojo.common.mojom.Version=base::Version" ]
diff --git a/mojo/converters/blink/BUILD.gn b/mojo/converters/blink/BUILD.gn
deleted file mode 100644
index 0bb9295..0000000
--- a/mojo/converters/blink/BUILD.gn
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//testing/test.gni")
-
-component("blink") {
- output_name = "mojo_blink_lib"
-
- sources = [
- "blink_input_events_type_converters.cc",
- "blink_input_events_type_converters.h",
- "mojo_blink_export.h",
- ]
-
- defines = [ "MOJO_CONVERTERS_BLINK_IMPLEMENTATION" ]
-
- public_deps = [
- "//mojo/public/cpp/bindings",
- ]
-
- deps = [
- "//base",
- "//third_party/WebKit/public:blink",
- "//ui/events",
- "//ui/events:dom_keycode_converter",
- ]
-}
-
-test("blink_converters_unittests") {
- sources = [
- "blink_input_events_type_converters_unittest.cc",
- ]
- deps = [
- ":blink",
- "//base:message_loop_tests",
- "//base/test:run_all_unittests",
- "//base/test:test_support",
- "//mojo/public/cpp/bindings:bindings",
- "//testing/gtest",
- "//third_party/WebKit/public:blink",
- "//ui/events",
- ]
-}
diff --git a/mojo/converters/blink/DEPS b/mojo/converters/blink/DEPS
deleted file mode 100644
index 6678b7c..0000000
--- a/mojo/converters/blink/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-include_rules = [
- "+base",
- "+third_party/WebKit/public",
- "+ui/events"
-]
diff --git a/mojo/converters/blink/blink_input_events_type_converters.cc b/mojo/converters/blink/blink_input_events_type_converters.cc
deleted file mode 100644
index 1114a5f..0000000
--- a/mojo/converters/blink/blink_input_events_type_converters.cc
+++ /dev/null
@@ -1,246 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/converters/blink/blink_input_events_type_converters.h"
-
-#include <utility>
-
-#include "base/logging.h"
-#include "base/time/time.h"
-#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/events/base_event_utils.h"
-#include "ui/events/event.h"
-#include "ui/events/keycodes/dom/keycode_converter.h"
-
-namespace mojo {
-namespace {
-
-// TODO(majidvp): remove this and directly use ui::EventFlagsToWebEventModifiers
-int EventFlagsToWebEventModifiers(int flags) {
- int modifiers = 0;
-
- if (flags & ui::EF_SHIFT_DOWN)
- modifiers |= blink::WebInputEvent::ShiftKey;
- if (flags & ui::EF_CONTROL_DOWN)
- modifiers |= blink::WebInputEvent::ControlKey;
- if (flags & ui::EF_ALT_DOWN)
- modifiers |= blink::WebInputEvent::AltKey;
- // TODO(beng): MetaKey/META_MASK
- if (flags & ui::EF_LEFT_MOUSE_BUTTON)
- modifiers |= blink::WebInputEvent::LeftButtonDown;
- if (flags & ui::EF_MIDDLE_MOUSE_BUTTON)
- modifiers |= blink::WebInputEvent::MiddleButtonDown;
- if (flags & ui::EF_RIGHT_MOUSE_BUTTON)
- modifiers |= blink::WebInputEvent::RightButtonDown;
- if (flags & ui::EF_CAPS_LOCK_ON)
- modifiers |= blink::WebInputEvent::CapsLockOn;
- return modifiers;
-}
-
-// TODO(majidvp): remove this and directly use ui::EventFlagsToWebEventModifiers
-int EventFlagsToWebInputEventModifiers(int flags) {
- return (flags & ui::EF_SHIFT_DOWN ? blink::WebInputEvent::ShiftKey : 0) |
- (flags & ui::EF_CONTROL_DOWN ? blink::WebInputEvent::ControlKey : 0) |
- (flags & ui::EF_CAPS_LOCK_ON ? blink::WebInputEvent::CapsLockOn : 0) |
- (flags & ui::EF_ALT_DOWN ? blink::WebInputEvent::AltKey : 0);
-}
-
-int GetClickCount(int flags) {
- if (flags & ui::EF_IS_TRIPLE_CLICK)
- return 3;
- else if (flags & ui::EF_IS_DOUBLE_CLICK)
- return 2;
-
- return 1;
-}
-
-void SetWebMouseEventLocation(const ui::LocatedEvent& located_event,
- blink::WebMouseEvent* web_event) {
- web_event->x = static_cast<int>(located_event.x());
- web_event->y = static_cast<int>(located_event.y());
- web_event->globalX = static_cast<int>(located_event.root_location_f().x());
- web_event->globalY = static_cast<int>(located_event.root_location_f().y());
-}
-
-std::unique_ptr<blink::WebInputEvent> BuildWebMouseEventFrom(
- const ui::PointerEvent& event) {
- std::unique_ptr<blink::WebMouseEvent> web_event(new blink::WebMouseEvent);
-
- web_event->pointerType = blink::WebPointerProperties::PointerType::Mouse;
- SetWebMouseEventLocation(event, web_event.get());
-
- web_event->modifiers = EventFlagsToWebEventModifiers(event.flags());
- web_event->timeStampSeconds = ui::EventTimeStampToSeconds(event.time_stamp());
-
- web_event->button = blink::WebMouseEvent::ButtonNone;
- if (event.flags() & ui::EF_LEFT_MOUSE_BUTTON)
- web_event->button = blink::WebMouseEvent::ButtonLeft;
- if (event.flags() & ui::EF_MIDDLE_MOUSE_BUTTON)
- web_event->button = blink::WebMouseEvent::ButtonMiddle;
- if (event.flags() & ui::EF_RIGHT_MOUSE_BUTTON)
- web_event->button = blink::WebMouseEvent::ButtonRight;
-
- switch (event.type()) {
- case ui::ET_POINTER_DOWN:
- web_event->type = blink::WebInputEvent::MouseDown;
- break;
- case ui::ET_POINTER_UP:
- web_event->type = blink::WebInputEvent::MouseUp;
- break;
- case ui::ET_POINTER_MOVED:
- web_event->type = blink::WebInputEvent::MouseMove;
- break;
- case ui::ET_MOUSE_EXITED:
- web_event->type = blink::WebInputEvent::MouseLeave;
- break;
- default:
- NOTIMPLEMENTED() << "Received unexpected event: " << event.type();
- break;
- }
-
- web_event->clickCount = GetClickCount(event.flags());
-
- return std::move(web_event);
-}
-
-std::unique_ptr<blink::WebInputEvent> BuildWebKeyboardEvent(
- const ui::KeyEvent& event) {
- std::unique_ptr<blink::WebKeyboardEvent> web_event(
- new blink::WebKeyboardEvent);
-
- web_event->modifiers = EventFlagsToWebInputEventModifiers(event.flags());
- web_event->timeStampSeconds = ui::EventTimeStampToSeconds(event.time_stamp());
-
- switch (event.type()) {
- case ui::ET_KEY_PRESSED:
- web_event->type = event.is_char() ? blink::WebInputEvent::Char
- : blink::WebInputEvent::RawKeyDown;
- break;
- case ui::ET_KEY_RELEASED:
- web_event->type = blink::WebInputEvent::KeyUp;
- break;
- default:
- NOTREACHED();
- }
-
- if (web_event->modifiers & blink::WebInputEvent::AltKey)
- web_event->isSystemKey = true;
-
- web_event->windowsKeyCode = event.GetLocatedWindowsKeyboardCode();
- web_event->nativeKeyCode =
- ui::KeycodeConverter::DomCodeToNativeKeycode(event.code());
- web_event->text[0] = event.GetText();
- web_event->unmodifiedText[0] = event.GetUnmodifiedText();
- return std::move(web_event);
-}
-
-std::unique_ptr<blink::WebInputEvent> BuildWebMouseWheelEventFrom(
- const ui::MouseWheelEvent& event) {
- std::unique_ptr<blink::WebMouseWheelEvent> web_event(
- new blink::WebMouseWheelEvent);
- web_event->type = blink::WebInputEvent::MouseWheel;
- web_event->button = blink::WebMouseEvent::ButtonNone;
- web_event->modifiers = EventFlagsToWebEventModifiers(event.flags());
- web_event->timeStampSeconds = ui::EventTimeStampToSeconds(event.time_stamp());
-
- SetWebMouseEventLocation(event, web_event.get());
-
- // TODO(rjkroege): Update the following code once Blink supports
- // DOM Level 3 wheel events
- // (http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents)
- web_event->deltaX = event.x_offset();
- web_event->deltaY = event.y_offset();
-
- web_event->wheelTicksX = web_event->deltaX / ui::MouseWheelEvent::kWheelDelta;
- web_event->wheelTicksY = web_event->deltaY / ui::MouseWheelEvent::kWheelDelta;
-
- // TODO(moshayedi): ui::WheelEvent currently only supports WHEEL_MODE_LINE.
- // Add support for other wheel modes once ui::WheelEvent has support for them.
- web_event->hasPreciseScrollingDeltas = false;
- web_event->scrollByPage = false;
-
- return std::move(web_event);
-}
-
-void SetWebTouchEventLocation(const ui::PointerEvent& event,
- blink::WebTouchPoint* touch) {
- touch->position.x = event.x();
- touch->position.y = event.y();
- touch->screenPosition.x = event.root_location_f().x();
- touch->screenPosition.y = event.root_location_f().y();
-}
-
-std::unique_ptr<blink::WebInputEvent> BuildWebTouchEvent(
- const ui::PointerEvent& event) {
- std::unique_ptr<blink::WebTouchEvent> web_event(new blink::WebTouchEvent);
- blink::WebTouchPoint* touch = &web_event->touches[event.pointer_id()];
-
- // TODO(jonross): we will need to buffer input events, as blink expects all
- // active touch points to be in each WebInputEvent (crbug.com/578160)
- SetWebTouchEventLocation(event, touch);
- touch->pointerType = blink::WebPointerProperties::PointerType::Touch;
- touch->radiusX = event.pointer_details().radius_x;
- touch->radiusY = event.pointer_details().radius_y;
-
- web_event->modifiers = EventFlagsToWebEventModifiers(event.flags());
- web_event->timeStampSeconds = ui::EventTimeStampToSeconds(event.time_stamp());
- web_event->uniqueTouchEventId = ui::GetNextTouchEventId();
-
- switch (event.type()) {
- case ui::ET_POINTER_DOWN:
- web_event->type = blink::WebInputEvent::TouchStart;
- touch->state = blink::WebTouchPoint::StatePressed;
- break;
- case ui::ET_POINTER_UP:
- web_event->type = blink::WebInputEvent::TouchEnd;
- touch->state = blink::WebTouchPoint::StateReleased;
- break;
- case ui::ET_POINTER_MOVED:
- web_event->type = blink::WebInputEvent::TouchMove;
- touch->state = blink::WebTouchPoint::StateMoved;
- break;
- case ui::ET_POINTER_CANCELLED:
- web_event->type = blink::WebInputEvent::TouchCancel;
- touch->state = blink::WebTouchPoint::StateCancelled;
- break;
- default:
- NOTIMPLEMENTED() << "Received non touch pointer event action: "
- << event.type();
- break;
- }
-
- return std::move(web_event);
-}
-
-} // namespace
-
-// static
-std::unique_ptr<blink::WebInputEvent>
-TypeConverter<std::unique_ptr<blink::WebInputEvent>, ui::Event>::Convert(
- const ui::Event& event) {
- DCHECK(event.IsKeyEvent() || event.IsPointerEvent() ||
- event.IsMouseWheelEvent());
- switch (event.type()) {
- case ui::ET_POINTER_DOWN:
- case ui::ET_POINTER_UP:
- case ui::ET_POINTER_CANCELLED:
- case ui::ET_POINTER_MOVED:
- case ui::ET_POINTER_EXITED:
- if (event.IsMousePointerEvent())
- return BuildWebMouseEventFrom(*event.AsPointerEvent());
- else if (event.IsTouchPointerEvent())
- return BuildWebTouchEvent(*event.AsPointerEvent());
- else
- return nullptr;
- case ui::ET_MOUSEWHEEL:
- return BuildWebMouseWheelEventFrom(*event.AsMouseWheelEvent());
- case ui::ET_KEY_PRESSED:
- case ui::ET_KEY_RELEASED:
- return BuildWebKeyboardEvent(*event.AsKeyEvent());
- default:
- return nullptr;
- }
-}
-
-} // namespace mojo
diff --git a/mojo/converters/blink/blink_input_events_type_converters.h b/mojo/converters/blink/blink_input_events_type_converters.h
deleted file mode 100644
index 3231eab..0000000
--- a/mojo/converters/blink/blink_input_events_type_converters.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_CONVERTERS_BLINK_BLINK_INPUT_EVENTS_TYPE_CONVERTERS_H_
-#define MOJO_CONVERTERS_BLINK_BLINK_INPUT_EVENTS_TYPE_CONVERTERS_H_
-
-#include <memory>
-
-#include "mojo/converters/blink/mojo_blink_export.h"
-#include "mojo/public/cpp/bindings/type_converter.h"
-
-namespace blink {
-class WebInputEvent;
-}
-
-namespace ui {
-class Event;
-}
-
-namespace mojo {
-
-template <>
-struct MOJO_BLINK_EXPORT
- TypeConverter<std::unique_ptr<blink::WebInputEvent>, ui::Event> {
- static std::unique_ptr<blink::WebInputEvent> Convert(const ui::Event& input);
-};
-
-} // namespace mojo
-
-#endif // MOJO_CONVERTERS_BLINK_BLINK_INPUT_EVENTS_TYPE_CONVERTERS_H_
diff --git a/mojo/converters/blink/mojo_blink_export.h b/mojo/converters/blink/mojo_blink_export.h
deleted file mode 100644
index 1a77184..0000000
--- a/mojo/converters/blink/mojo_blink_export.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_CONVERTERS_BLINK_MOJO_BLINK_EXPORT_H_
-#define MOJO_CONVERTERS_BLINK_MOJO_BLINK_EXPORT_H_
-
-#if defined(COMPONENT_BUILD)
-
-#if defined(WIN32)
-
-#if defined(MOJO_CONVERTERS_BLINK_IMPLEMENTATION)
-#define MOJO_BLINK_EXPORT __declspec(dllexport)
-#else
-#define MOJO_BLINK_EXPORT __declspec(dllimport)
-#endif
-
-#else // !defined(WIN32)
-
-#if defined(MOJO_CONVERTERS_BLINK_IMPLEMENTATION)
-#define MOJO_BLINK_EXPORT __attribute__((visibility("default")))
-#else
-#define MOJO_BLINK_EXPORT
-#endif
-
-#endif // defined(WIN32)
-
-#else // !defined(COMPONENT_BUILD)
-#define MOJO_BLINK_EXPORT
-#endif
-
-#endif // MOJO_CONVERTERS_BLINK_MOJO_BLINK_EXPORT_H_
diff --git a/mojo/edk/embedder/BUILD.gn b/mojo/edk/embedder/BUILD.gn
index f20fd40..8105bed 100644
--- a/mojo/edk/embedder/BUILD.gn
+++ b/mojo/edk/embedder/BUILD.gn
@@ -7,13 +7,16 @@ import("//build/config/nacl/config.gni")
source_set("headers") {
sources = [
"configuration.h",
+ "connection_params.h",
"embedder.h",
"embedder_internal.h",
"named_platform_channel_pair.h",
+ "named_platform_handle.h",
+ "named_platform_handle_utils.h",
+ "pending_process_connection.h",
"platform_channel_pair.h",
"platform_handle.h",
"platform_handle_utils.h",
- "process_delegate.h",
"scoped_platform_handle.h",
]
@@ -33,11 +36,14 @@ source_set("embedder") {
sources = [
"configuration.h",
+ "connection_params.cc",
+ "connection_params.h",
"embedder.cc",
"embedder.h",
"embedder_internal.h",
"entrypoints.cc",
"entrypoints.h",
+ "pending_process_connection.cc",
"scoped_ipc_support.cc",
"scoped_ipc_support.h",
@@ -52,7 +58,6 @@ source_set("embedder") {
defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
public_deps = [
- ":delegates",
":headers",
":platform",
"//base",
@@ -77,6 +82,9 @@ source_set("platform") {
sources = [
"named_platform_channel_pair.h",
"named_platform_channel_pair_win.cc",
+ "named_platform_handle.h",
+ "named_platform_handle_utils.h",
+ "named_platform_handle_utils_win.cc",
"platform_channel_pair.cc",
"platform_channel_pair.h",
"platform_channel_pair_posix.cc",
@@ -93,6 +101,9 @@ source_set("platform") {
"platform_shared_buffer.h",
"scoped_platform_handle.h",
]
+ if (!is_nacl) {
+ sources += [ "named_platform_handle_utils_posix.cc" ]
+ }
defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
@@ -113,25 +124,6 @@ source_set("platform") {
}
}
-source_set("delegates") {
- # This isn't really a standalone target; it must be linked into the
- # mojo_system_impl component.
- visibility = [
- ":embedder",
- "//mojo/edk/system",
- ]
-
- sources = [
- "process_delegate.h",
- ]
-
- defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
-
- public_deps = [
- "//mojo/public/cpp/system",
- ]
-}
-
source_set("embedder_unittests") {
testonly = true
diff --git a/mojo/edk/embedder/README.md b/mojo/edk/embedder/README.md
index f976fcb..6def874 100644
--- a/mojo/edk/embedder/README.md
+++ b/mojo/edk/embedder/README.md
@@ -1,13 +1,327 @@
-Mojo Embedder API
-=================
-
-The Mojo Embedder API is an unstable, internal API to the Mojo system
-implementation. It should be used by code running on top of the system-level
-APIs to set up the Mojo environment (instead of directly instantiating things
-from src/mojo/edk/system).
-
-Example uses: Mojo shell, to set up the Mojo environment for Mojo apps; Chromium
-code, to set up the Mojo IPC system for use between processes. Note that most
-code should use the Mojo Public API (under src/mojo/public) instead. The
-Embedder API should only be used to initialize the environment, set up the
-initial MessagePipe between two processes, etc.
+# Mojo Embedder Development Kit (EDK)
+
+The Mojo EDK is a (binary-unstable) API which enables a process to use Mojo both
+internally and for IPC to other Mojo-embedding processes.
+
+Using any of the API surface in `//mojo/edk/embedder` requires (somewhat
+confusingly) a direct dependency on the GN `//mojo/edk/system` target. Despite
+this fact, you should never reference any of the headers in `mojo/edk/system`
+directly, as everything there is considered to be an internal detail of the EDK.
+
+## Basic Initialization
+
+In order to use Mojo in a given process, it's necessary to call
+`mojo::edk::Init` exactly once:
+
+```
+#include "mojo/edk/embedder/embedder.h"
+
+int main(int argc, char** argv) {
+ mojo::edk::Init();
+
+ // Now you can create message pipes, write messages, etc
+
+ return 0;
+}
+```
+
+As it happens though, Mojo is less useful without some kind of IPC support as
+well, and that's a second initialization step.
+
+## IPC Initialization
+
+You also need to provide the system with a background TaskRunner on which it can
+watch for inbound I/O from any of the various other processes you will later
+connect to it.
+
+Here we'll just create a new background thread for IPC and let Mojo use that.
+Note that in Chromium, we use the existing "IO thread" in the browser process
+and content child processes.
+
+```
+#include "base/threading/thread.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/scoped_ipc_support.h"
+
+int main(int argc, char** argv) {
+ mojo::edk::Init();
+
+ base::Thread ipc_thread("ipc!");
+ ipc_thread.StartWithOptions(
+ base::Thread::Options(base::MessageLoop::TYPE_IO));
+
+ // As long as this object is alive, all EDK API surface relevant to IPC
+ // connections is usable and message pipes which span a process boundary will
+ // continue to function.
+ mojo::edk::ScopedIPCSupport ipc_support(
+ ipc_thread.task_runner(),
+ mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
+
+ return 0;
+}
+```
+
+This process is now fully prepared to use Mojo IPC!
+
+Note that all existing process types in Chromium already perform this setup
+very early during startup.
+
+## Connecting Two Processes
+
+Now suppose you're running a process which has initialized Mojo IPC, and you
+want to launch another process which you know will also initialize Mojo IPC.
+You want to be able to connect Mojo interfaces between these two processes.
+Rejoice, because this section was written just for you.
+
+NOTE: For legacy reasons, some API terminology may refer to concepts of "parent"
+and "child" as a relationship between processes being connected by Mojo. This
+relationship is today completely orthogonal to any notion of process hierarchy
+in the OS, and so use of these APIs is not constrained by an adherence to any
+such hierarchy.
+
+Mojo requires you to bring your own OS pipe to the party, and it will do the
+rest. It also provides a convenient mechanism for creating such pipes, known as
+a `PlatformChannelPair`.
+
+You provide one end of this pipe to the EDK in the local process via
+`PendingProcessConnection` - which can also be used to create cross-process
+message pipes (see the next section) - and you're responsible for getting the
+other end into the remote process.
+
+```
+#include "base/process/process_handle.h"
+#include "base/threading/thread.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/pending_process_connection.h"
+#include "mojo/edk/embedder/platform_channel_pair.h"
+#include "mojo/edk/embedder/scoped_ipc_support.h"
+
+// You write this. It launches a new process, passing the pipe handle
+// encapsulated by |channel| by any means possible (e.g. on Windows or POSIX
+// you may inhert the file descriptor/HANDLE at launch and pass a commandline
+// argument to indicate its numeric value). Returns the handle of the new
+// process.
+base::ProcessHandle LaunchCoolChildProcess(
+ mojo::edk::ScopedPlatformHandle channel);
+
+int main(int argc, char** argv) {
+ mojo::edk::Init();
+
+ base::Thread ipc_thread("ipc!");
+ ipc_thread.StartWithOptions(
+ base::Thread::Options(base::MessageLoop::TYPE_IO));
+
+ mojo::edk::ScopedIPCSupport ipc_support(
+ ipc_thread.task_runner(),
+ mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
+
+ // This is essentially always an OS pipe (domain socket pair, Windows named
+ // pipe, etc.)
+ mojo::edk::PlatformChannelPair channel;
+
+ // This is a scoper which encapsulates the intent to connect to another
+ // process. It exists because process connection is inherently asynchronous,
+ // things may go wrong, and the lifetime of any associated resources is bound
+ // by the lifetime of this object regardless of success or failure.
+ mojo::edk::PendingProcessConnection child;
+
+ base::ProcessHandle child_handle =
+ LaunchCoolChildProcess(channel.PassClientHandle());
+
+ // At this point it's safe for |child| to go out of scope and nothing will
+ // break.
+ child.Connect(child_handle, channel.PassServerHandle());
+
+ return 0;
+}
+```
+
+The launched process code uses `SetParentPipeHandle` to get connected, and might
+look something like:
+
+```
+#include "base/threading/thread.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/scoped_ipc_support.h"
+
+// You write this. It acquires the ScopedPlatformHandle that was passed by
+// whomever launched this process (i.e. LaunchCoolChildProcess above).
+mojo::edk::ScopedPlatformHandle GetChannelHandle();
+
+int main(int argc, char** argv) {
+ mojo::edk::Init();
+
+ base::Thread ipc_thread("ipc!");
+ ipc_thread.StartWithOptions(
+ base::Thread::Options(base::MessageLoop::TYPE_IO));
+
+ mojo::edk::ScopedIPCSupport ipc_support(
+ ipc_thread.task_runner(),
+ mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
+
+ mojo::edk::SetParentPipeHandle(GetChannelHandle());
+
+ return 0;
+}
+```
+
+Now you have IPC initialized between two processes. For some practical examples
+of how this is done, you can dig into the various multiprocess tests in the
+`mojo_system_unittests` test suite.
+
+## Bootstrapping Cross-Process Message Pipes
+
+Having internal Mojo IPC support initialized is pretty useless if you don't have
+any message pipes spanning the process boundary. Fortunately, this is made
+trivial by the EDK: `PendingProcessConnection` has a
+`CreateMessagePipe` method which synthesizes a new solitary message pipe
+endpoint for your immediate use, while also generating a magic token string that
+can be exchanged for the other end of the pipe via
+`mojo::edk::CreateChildMessagePipe`.
+
+The token exchange can be done by the same process (which is sometimes useful),
+or by the process that is eventually connected via `Connect()` on that
+`PendingProcessConnection`. This means that you can effectively pass message
+pipes on the commandline by passing a token string.
+
+We can modify our existing sample code as follows:
+
+```
+#include "base/command_line.h"
+#include "base/process/process_handle.h"
+#include "base/threading/thread.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/pending_process_connection.h"
+#include "mojo/edk/embedder/platform_channel_pair.h"
+#include "mojo/edk/embedder/scoped_ipc_support.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "local/foo.mojom.h" // You provide this
+
+base::ProcessHandle LaunchCoolChildProcess(
+ const base::CommandLine& command_line,
+ mojo::edk::ScopedPlatformHandle channel);
+
+int main(int argc, char** argv) {
+ mojo::edk::Init();
+
+ base::Thread ipc_thread("ipc!");
+ ipc_thread.StartWithOptions(
+ base::Thread::Options(base::MessageLoop::TYPE_IO));
+
+ mojo::edk::ScopedIPCSupport ipc_support(
+ ipc_thread.task_runner(),
+ mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
+
+ mojo::edk::PlatformChannelPair channel;
+
+ mojo::edk::PendingProcessConnection child;
+
+ base::CommandLine command_line; // Assume this is appropriately initialized
+
+ // Create a new message pipe with one end being retrievable in the new
+ // process. Note that it doesn't matter whether we call CreateMessagePipe()
+ // before or after Connect(), and we can create as many different pipes as
+ // we like.
+ std::string pipe_token;
+ mojo::ScopedMessagePipeHandle my_pipe = child.CreateMessagePipe(&pipe_token);
+ command_line.AppendSwitchASCII("primordial-pipe", pipe_token);
+
+ base::ProcessHandle child_handle =
+ LaunchCoolChildProcess(command_line, channel.PassClientHandle());
+
+ child.Connect(child_handle, channel.PassServerHandle());
+
+ // We can start using our end of the pipe immediately. Here we assume the
+ // other end will eventually be bound to a local::mojom::Foo implementation,
+ // so we can start making calls on that interface.
+ //
+ // Note that this could even be done before the child process is launched and
+ // it would still work as expected.
+ local::mojom::FooPtr foo;
+ foo.Bind(local::mojom::FooPtrInfo(std::move(my_pipe), 0));
+ foo->DoSomeStuff(42);
+
+ return 0;
+}
+```
+
+and for the launched process:
+
+
+```
+#include "base/command_line.h"
+#include "base/run_loop/run_loop.h"
+#include "base/threading/thread.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/scoped_ipc_support.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "local/foo.mojom.h" // You provide this
+
+mojo::edk::ScopedPlatformHandle GetChannelHandle();
+
+class FooImpl : local::mojom::Foo {
+ public:
+ explicit FooImpl(local::mojom::FooRequest request)
+ : binding_(this, std::move(request)) {}
+ ~FooImpl() override {}
+
+ void DoSomeStuff(int32_t n) override {
+ // ...
+ }
+
+ private:
+ mojo::Binding<local::mojom::Foo> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(FooImpl);
+};
+
+int main(int argc, char** argv) {
+ base::CommandLine::Init(argc, argv);
+
+ mojo::edk::Init();
+
+ base::Thread ipc_thread("ipc!");
+ ipc_thread.StartWithOptions(
+ base::Thread::Options(base::MessageLoop::TYPE_IO));
+
+ mojo::edk::ScopedIPCSupport ipc_support(
+ ipc_thread.task_runner(),
+ mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
+
+ mojo::edk::SetParentPipeHandle(GetChannelHandle());
+
+ mojo::ScopedMessagePipeHandle my_pipe = mojo::edk::CreateChildMessagePipe(
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ "primordial-pipe"));
+
+ local::mojom::FooRequest foo_request;
+ foo_request.Bind(std::move(my_pipe));
+ FooImpl impl(std::move(foo_request));
+
+ // Run forever!
+ base::RunLoop().Run();
+
+ return 0;
+}
+```
+
+Note that the above samples assume an interface definition in
+`//local/test.mojom` which would look something like:
+
+```
+module local.mojom;
+
+interface Foo {
+ DoSomeStuff(int32 n);
+};
+```
+
+Once you've bootstrapped your process connection with a real mojom interface,
+you can avoid any further mucking around with EDK APIs or raw message pipe
+handles, as everything beyond this point - including the passing of other
+interface pipes - can be handled eloquently using public bindings APIs.
+
+See [additional Mojo documentation](
+ https://www.chromium.org/developers/design-documents/mojo) for more
+information.
diff --git a/mojo/edk/embedder/connection_params.cc b/mojo/edk/embedder/connection_params.cc
new file mode 100644
index 0000000..9b7ec54
--- /dev/null
+++ b/mojo/edk/embedder/connection_params.cc
@@ -0,0 +1,28 @@
+// 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.
+
+#include "mojo/edk/embedder/connection_params.h"
+
+#include <utility>
+
+namespace mojo {
+namespace edk {
+
+ConnectionParams::ConnectionParams(ScopedPlatformHandle channel)
+ : channel_(std::move(channel)) {}
+
+ConnectionParams::ConnectionParams(ConnectionParams&& param)
+ : channel_(std::move(param.channel_)) {}
+
+ConnectionParams& ConnectionParams::operator=(ConnectionParams&& param) {
+ channel_ = std::move(param.channel_);
+ return *this;
+}
+
+ScopedPlatformHandle ConnectionParams::TakeChannelHandle() {
+ return std::move(channel_);
+}
+
+} // namespace edk
+} // namespace mojo
diff --git a/mojo/edk/embedder/connection_params.h b/mojo/edk/embedder/connection_params.h
new file mode 100644
index 0000000..25ffdde
--- /dev/null
+++ b/mojo/edk/embedder/connection_params.h
@@ -0,0 +1,34 @@
+// 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_EDK_EMBEDDER_CONNECTION_PARAMS_H_
+#define MOJO_EDK_EMBEDDER_CONNECTION_PARAMS_H_
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "mojo/edk/embedder/scoped_platform_handle.h"
+#include "mojo/edk/system/system_impl_export.h"
+
+namespace mojo {
+namespace edk {
+
+class MOJO_SYSTEM_IMPL_EXPORT ConnectionParams {
+ public:
+ explicit ConnectionParams(ScopedPlatformHandle channel);
+
+ ConnectionParams(ConnectionParams&& param);
+ ConnectionParams& operator=(ConnectionParams&& param);
+
+ ScopedPlatformHandle TakeChannelHandle();
+
+ private:
+ ScopedPlatformHandle channel_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConnectionParams);
+};
+
+} // namespace edk
+} // namespace mojo
+
+#endif // MOJO_EDK_EMBEDDER_CONNECTION_PARAMS_H_
diff --git a/mojo/edk/embedder/embedder.cc b/mojo/edk/embedder/embedder.cc
index c90acbd..0fdda5c 100644
--- a/mojo/edk/embedder/embedder.cc
+++ b/mojo/edk/embedder/embedder.cc
@@ -5,6 +5,7 @@
#include "mojo/edk/embedder/embedder.h"
#include <stdint.h>
+#include <utility>
#include "base/bind.h"
#include "base/location.h"
@@ -17,8 +18,8 @@
#include "mojo/edk/embedder/embedder_internal.h"
#include "mojo/edk/embedder/entrypoints.h"
#include "mojo/edk/embedder/platform_channel_pair.h"
-#include "mojo/edk/embedder/process_delegate.h"
#include "mojo/edk/system/core.h"
+#include "mojo/edk/system/node_controller.h"
#if !defined(OS_NACL)
#include "crypto/random.h"
@@ -33,7 +34,6 @@ class PlatformSupport;
namespace internal {
Core* g_core;
-ProcessDelegate* g_process_delegate;
Core* GetCore() { return g_core; }
@@ -42,30 +42,9 @@ Core* GetCore() { return g_core; }
void SetMaxMessageSize(size_t bytes) {
}
-void ChildProcessLaunched(base::ProcessHandle child_process,
- ScopedPlatformHandle server_pipe,
- const std::string& child_token) {
- ChildProcessLaunched(child_process, std::move(server_pipe),
- child_token, ProcessErrorCallback());
-}
-
-void ChildProcessLaunched(base::ProcessHandle child_process,
- ScopedPlatformHandle server_pipe,
- const std::string& child_token,
- const ProcessErrorCallback& process_error_callback) {
- CHECK(internal::g_core);
- internal::g_core->AddChild(child_process, std::move(server_pipe),
- child_token, process_error_callback);
-}
-
-void ChildProcessLaunchFailed(const std::string& child_token) {
- CHECK(internal::g_core);
- internal::g_core->ChildLaunchFailed(child_token);
-}
-
void SetParentPipeHandle(ScopedPlatformHandle pipe) {
CHECK(internal::g_core);
- internal::g_core->InitChild(std::move(pipe));
+ internal::g_core->InitChild(ConnectionParams(std::move(pipe)));
}
void SetParentPipeHandleFromCommandLine() {
@@ -76,6 +55,21 @@ void SetParentPipeHandleFromCommandLine() {
SetParentPipeHandle(std::move(platform_channel));
}
+ScopedMessagePipeHandle ConnectToPeerProcess(ScopedPlatformHandle pipe) {
+ return ConnectToPeerProcess(std::move(pipe), GenerateRandomToken());
+}
+
+ScopedMessagePipeHandle ConnectToPeerProcess(ScopedPlatformHandle pipe,
+ const std::string& peer_token) {
+ DCHECK(pipe.is_valid());
+ DCHECK(!peer_token.empty());
+ return internal::g_core->ConnectToPeerProcess(std::move(pipe), peer_token);
+}
+
+void ClosePeerConnection(const std::string& peer_token) {
+ return internal::g_core->ClosePeerConnection(peer_token);
+}
+
void Init() {
MojoSystemThunks thunks = MakeSystemThunks();
size_t expected_size = MojoEmbedderSetSystemThunks(&thunks);
@@ -84,6 +78,10 @@ void Init() {
internal::g_core = new Core();
}
+void SetDefaultProcessErrorCallback(const ProcessErrorCallback& callback) {
+ internal::g_core->SetDefaultProcessErrorCallback(callback);
+}
+
MojoResult CreatePlatformHandleWrapper(
ScopedPlatformHandle platform_handle,
MojoHandle* platform_handle_wrapper_handle) {
@@ -115,19 +113,18 @@ MojoResult PassSharedMemoryHandle(
mojo_handle, shared_memory_handle, num_bytes, read_only);
}
-void InitIPCSupport(ProcessDelegate* process_delegate,
- scoped_refptr<base::TaskRunner> io_thread_task_runner) {
+void InitIPCSupport(scoped_refptr<base::TaskRunner> io_thread_task_runner) {
CHECK(internal::g_core);
internal::g_core->SetIOTaskRunner(io_thread_task_runner);
- internal::g_process_delegate = process_delegate;
}
-void ShutdownIPCSupport() {
- CHECK(internal::g_process_delegate);
+scoped_refptr<base::TaskRunner> GetIOTaskRunner() {
+ return internal::g_core->GetNodeController()->io_task_runner();
+}
+
+void ShutdownIPCSupport(const base::Closure& callback) {
CHECK(internal::g_core);
- internal::g_core->RequestShutdown(
- base::Bind(&ProcessDelegate::OnShutdownComplete,
- base::Unretained(internal::g_process_delegate)));
+ internal::g_core->RequestShutdown(callback);
}
#if defined(OS_MACOSX) && !defined(OS_IOS)
@@ -137,14 +134,7 @@ void SetMachPortProvider(base::PortProvider* port_provider) {
}
#endif
-ScopedMessagePipeHandle CreateParentMessagePipe(
- const std::string& token, const std::string& child_token) {
- CHECK(internal::g_process_delegate);
- return internal::g_core->CreateParentMessagePipe(token, child_token);
-}
-
ScopedMessagePipeHandle CreateChildMessagePipe(const std::string& token) {
- CHECK(internal::g_process_delegate);
return internal::g_core->CreateChildMessagePipe(token);
}
diff --git a/mojo/edk/embedder/embedder.h b/mojo/edk/embedder/embedder.h
index 9e83bbe..97258e5 100644
--- a/mojo/edk/embedder/embedder.h
+++ b/mojo/edk/embedder/embedder.h
@@ -16,6 +16,7 @@
#include "base/memory/shared_memory_handle.h"
#include "base/process/process_handle.h"
#include "base/task_runner.h"
+#include "mojo/edk/embedder/pending_process_connection.h"
#include "mojo/edk/embedder/scoped_platform_handle.h"
#include "mojo/edk/system/system_impl_export.h"
#include "mojo/public/cpp/system/message_pipe.h"
@@ -27,10 +28,6 @@ class PortProvider;
namespace mojo {
namespace edk {
-class ProcessDelegate;
-
-using ProcessErrorCallback = base::Callback<void(const std::string& error)>;
-
// Basic configuration/initialization ------------------------------------------
// |Init()| sets up the basic Mojo system environment, making the |Mojo...()|
@@ -40,40 +37,43 @@ using ProcessErrorCallback = base::Callback<void(const std::string& error)>;
// Allows changing the default max message size. Must be called before Init.
MOJO_SYSTEM_IMPL_EXPORT void SetMaxMessageSize(size_t bytes);
-// Called in the parent process for each child process that is launched.
-MOJO_SYSTEM_IMPL_EXPORT void ChildProcessLaunched(
- base::ProcessHandle child_process,
- ScopedPlatformHandle server_pipe,
- const std::string& child_token);
-
-// Called in the parent process for each child process that is launched.
-// |process_error_callback| is called if the system becomes aware of some
-// internal error related to this process, e.g., if the system is notified of a
-// bad message from this process via the |MojoNotifyBadMessage()| API.
-MOJO_SYSTEM_IMPL_EXPORT void ChildProcessLaunched(
- base::ProcessHandle child_process,
- ScopedPlatformHandle server_pipe,
- const std::string& child_token,
- const ProcessErrorCallback& error_callback);
-
-// Called in the parent process when a child process fails to launch.
-// Exactly one of ChildProcessLaunched() or ChildProcessLaunchFailed() must be
-// called per child process launch attempt.
-MOJO_SYSTEM_IMPL_EXPORT void ChildProcessLaunchFailed(
- const std::string& child_token);
-
-// Should be called as early as possible in the child process with the handle
-// that the parent received from ChildProcessLaunched.
+// Should be called as early as possible in a child process with a handle to the
+// other end of a pipe provided in the parent to
+// PendingProcessConnection::Connect.
MOJO_SYSTEM_IMPL_EXPORT void SetParentPipeHandle(ScopedPlatformHandle pipe);
// Same as above but extracts the pipe handle from the command line. See
// PlatformChannelPair for details.
MOJO_SYSTEM_IMPL_EXPORT void SetParentPipeHandleFromCommandLine();
+// Called to connect to a peer process. This should be called only if there
+// is no common ancestor for the processes involved within this mojo system.
+// Both processes must call this function, each passing one end of a platform
+// channel. This returns one end of a message pipe to each process.
+MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
+ConnectToPeerProcess(ScopedPlatformHandle pipe);
+
+// Called to connect to a peer process. This should be called only if there
+// is no common ancestor for the processes involved within this mojo system.
+// Both processes must call this function, each passing one end of a platform
+// channel. This returns one end of a message pipe to each process. |peer_token|
+// may be passed to ClosePeerConnection() to close the connection.
+MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
+ConnectToPeerProcess(ScopedPlatformHandle pipe, const std::string& peer_token);
+
+// Closes a connection to a peer process created by ConnectToPeerProcess()
+// where the same |peer_token| was used.
+MOJO_SYSTEM_IMPL_EXPORT void ClosePeerConnection(const std::string& peer_token);
+
// Must be called first, or just after setting configuration parameters, to
// initialize the (global, singleton) system.
MOJO_SYSTEM_IMPL_EXPORT void Init();
+// Sets a default callback to invoke when an internal error is reported but
+// cannot be associated with a specific child process.
+MOJO_SYSTEM_IMPL_EXPORT void SetDefaultProcessErrorCallback(
+ const ProcessErrorCallback& callback);
+
// Basic functions -------------------------------------------------------------
// The functions in this section are available once |Init()| has been called.
@@ -126,22 +126,20 @@ PassSharedMemoryHandle(MojoHandle mojo_handle,
//
// This subsystem may be shut down using |ShutdownIPCSupport()|. None of the IPC
// functions may be called after this is called.
-
-// Initializes a process of the given type; to be called after |Init()|.
-// - |process_delegate| must be a process delegate of the appropriate type
-// corresponding to |process_type|; its methods will be called on the same
-// thread as Shutdown.
-// - |process_delegate|, and |io_thread_task_runner| should live at least
-// until |ShutdownIPCSupport()|'s callback has been run.
+//
+// |io_thread_task_runner| should live at least until |ShutdownIPCSupport()|'s
+// callback has been run.
MOJO_SYSTEM_IMPL_EXPORT void InitIPCSupport(
- ProcessDelegate* process_delegate,
scoped_refptr<base::TaskRunner> io_thread_task_runner);
+// Retrieves the TaskRunner used for IPC I/O, as set by InitIPCSupport.
+MOJO_SYSTEM_IMPL_EXPORT scoped_refptr<base::TaskRunner> GetIOTaskRunner();
+
// Shuts down the subsystem initialized by |InitIPCSupport()|. It be called from
// any thread and will attempt to complete shutdown on the I/O thread with which
-// the system was initialized. Upon completion the ProcessDelegate's
-// |OnShutdownComplete()| method is invoked.
-MOJO_SYSTEM_IMPL_EXPORT void ShutdownIPCSupport();
+// the system was initialized. Upon completion, |callback| is invoked on an
+// arbitrary thread.
+MOJO_SYSTEM_IMPL_EXPORT void ShutdownIPCSupport(const base::Closure& callback);
#if defined(OS_MACOSX) && !defined(OS_IOS)
// Set the |base::PortProvider| for this process. Can be called on any thread,
@@ -150,25 +148,14 @@ MOJO_SYSTEM_IMPL_EXPORT void SetMachPortProvider(
base::PortProvider* port_provider);
#endif
-// Creates a message pipe from a token. A child embedder must also have this
-// token and call CreateChildMessagePipe() with it in order for the pipe to get
-// connected. |child_token| identifies the child process and should be the same
-// as the token passed into ChildProcessLaunched(). If they are different, the
-// returned message pipe will not be signaled of peer closure if the child
-// process dies before establishing connection to the pipe.
-MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
-CreateParentMessagePipe(const std::string& token,
- const std::string& child_token);
-
-// Creates a message pipe from a token in a child process. The parent must also
-// have this token and call CreateParentMessagePipe() with it in order for the
-// pipe to get connected.
+// Creates a message pipe from a token in a child process. This token must have
+// been acquired by a corresponding call to
+// PendingProcessConnection::CreateMessagePipe.
MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
CreateChildMessagePipe(const std::string& token);
-// Generates a random ASCII token string for use with CreateParentMessagePipe()
-// and CreateChildMessagePipe() above. The generated token is suitably random so
-// as to not have to worry about collisions with other generated tokens.
+// Generates a random ASCII token string for use with various APIs that expect
+// a globally unique token string.
MOJO_SYSTEM_IMPL_EXPORT std::string GenerateRandomToken();
// Sets system properties that can be read by the MojoGetProperty() API. See the
diff --git a/mojo/edk/embedder/embedder_unittest.cc b/mojo/edk/embedder/embedder_unittest.cc
index 127a74f..d5a87e5 100644
--- a/mojo/edk/embedder/embedder_unittest.cc
+++ b/mojo/edk/embedder/embedder_unittest.cc
@@ -10,16 +10,24 @@
#include <utility>
+#include "base/base_paths.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/shared_memory.h"
#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
#include "base/process/process_handle.h"
+#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/test_timeouts.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/named_platform_handle.h"
+#include "mojo/edk/embedder/named_platform_handle_utils.h"
+#include "mojo/edk/embedder/pending_process_connection.h"
#include "mojo/edk/embedder/platform_channel_pair.h"
#include "mojo/edk/embedder/test_embedder.h"
#include "mojo/edk/system/test_utils.h"
@@ -183,13 +191,12 @@ TEST_F(EmbedderTest, ChannelsHandlePassing) {
}
TEST_F(EmbedderTest, PipeSetup) {
- std::string child_token = GenerateRandomToken();
- std::string pipe_token = GenerateRandomToken();
-
- ScopedMessagePipeHandle parent_mp =
- CreateParentMessagePipe(pipe_token, child_token);
- ScopedMessagePipeHandle child_mp =
- CreateChildMessagePipe(pipe_token);
+ // Ensures that a pending process connection's message pipe can be claimed by
+ // the host process itself.
+ PendingProcessConnection process;
+ std::string pipe_token;
+ ScopedMessagePipeHandle parent_mp = process.CreateMessagePipe(&pipe_token);
+ ScopedMessagePipeHandle child_mp = CreateChildMessagePipe(pipe_token);
const std::string kHello = "hello";
WriteMessage(parent_mp.get().value(), kHello);
@@ -200,13 +207,11 @@ TEST_F(EmbedderTest, PipeSetup) {
TEST_F(EmbedderTest, PipeSetup_LaunchDeath) {
PlatformChannelPair pair;
- std::string child_token = GenerateRandomToken();
- std::string pipe_token = GenerateRandomToken();
-
- ScopedMessagePipeHandle parent_mp =
- CreateParentMessagePipe(pipe_token, child_token);
- ChildProcessLaunched(base::GetCurrentProcessHandle(), pair.PassServerHandle(),
- child_token);
+ PendingProcessConnection process;
+ std::string pipe_token;
+ ScopedMessagePipeHandle parent_mp = process.CreateMessagePipe(&pipe_token);
+ process.Connect(base::GetCurrentProcessHandle(),
+ ConnectionParams(pair.PassServerHandle()));
// Close the remote end, simulating child death before the child connects to
// the reserved port.
@@ -221,13 +226,14 @@ TEST_F(EmbedderTest, PipeSetup_LaunchDeath) {
TEST_F(EmbedderTest, PipeSetup_LaunchFailure) {
PlatformChannelPair pair;
- std::string child_token = GenerateRandomToken();
- std::string pipe_token = GenerateRandomToken();
+ auto process = base::MakeUnique<PendingProcessConnection>();
+ std::string pipe_token;
+ ScopedMessagePipeHandle parent_mp = process->CreateMessagePipe(&pipe_token);
- ScopedMessagePipeHandle parent_mp =
- CreateParentMessagePipe(pipe_token, child_token);
+ // Ensure that if a PendingProcessConnection goes away before Connect() is
+ // called, any message pipes associated with it detect peer closure.
+ process.reset();
- ChildProcessLaunchFailed(child_token);
EXPECT_EQ(MOJO_RESULT_OK, MojoWait(parent_mp.get().value(),
MOJO_HANDLE_SIGNAL_PEER_CLOSED,
MOJO_DEADLINE_INDEFINITE,
@@ -557,6 +563,100 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessMixMachAndFdsClient, EmbedderTest,
#endif // !defined(OS_IOS)
+NamedPlatformHandle GenerateChannelName() {
+#if defined(OS_POSIX)
+ base::FilePath temp_dir;
+ CHECK(base::PathService::Get(base::DIR_TEMP, &temp_dir));
+ return NamedPlatformHandle(
+ temp_dir.AppendASCII(GenerateRandomToken()).value());
+#else
+ return NamedPlatformHandle(GenerateRandomToken());
+#endif
+}
+
+void CreateClientHandleOnIoThread(const NamedPlatformHandle& named_handle,
+ ScopedPlatformHandle* output) {
+ *output = CreateClientHandle(named_handle);
+}
+
+TEST_F(EmbedderTest, ClosePendingPeerConnection) {
+ NamedPlatformHandle named_handle = GenerateChannelName();
+ std::string peer_token = GenerateRandomToken();
+ ScopedMessagePipeHandle server_pipe =
+ ConnectToPeerProcess(CreateServerHandle(named_handle), peer_token);
+ ClosePeerConnection(peer_token);
+ EXPECT_EQ(MOJO_RESULT_OK,
+ Wait(server_pipe.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_DEADLINE_INDEFINITE, nullptr));
+ base::MessageLoop message_loop;
+ base::RunLoop run_loop;
+ ScopedPlatformHandle client_handle;
+ // Closing the channel involves posting a task to the IO thread to do the
+ // work. By the time the local message pipe has been observerd as closed,
+ // that task will have been posted. Therefore, a task to create the client
+ // connection should be handled after the channel is closed.
+ GetIOTaskRunner()->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&CreateClientHandleOnIoThread, named_handle, &client_handle),
+ run_loop.QuitClosure());
+ run_loop.Run();
+ EXPECT_FALSE(client_handle.is_valid());
+}
+
+#if !defined(OS_IOS)
+
+TEST_F(EmbedderTest, ClosePipeToConnectedPeer) {
+ set_launch_type(LaunchType::PEER);
+ auto& controller = StartClient("ClosePipeToConnectedPeerClient");
+ MojoHandle server_mp = controller.pipe();
+ // 1. Write a message to |server_mp| (attaching nothing).
+ WriteMessage(server_mp, "hello");
+
+ // 2. Read a message from |server_mp|.
+ EXPECT_EQ("world!", ReadMessage(server_mp));
+
+ controller.ClosePeerConnection();
+
+ EXPECT_EQ(MOJO_RESULT_OK, MojoWait(server_mp, MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_DEADLINE_INDEFINITE, nullptr));
+
+ EXPECT_EQ(0, controller.WaitForShutdown());
+}
+
+DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ClosePipeToConnectedPeerClient, EmbedderTest,
+ client_mp) {
+ // 1. Read the first message from |client_mp|.
+ EXPECT_EQ("hello", ReadMessage(client_mp));
+
+ // 2. Write a message to |client_mp| (attaching nothing).
+ WriteMessage(client_mp, "world!");
+
+ ASSERT_EQ(MOJO_RESULT_OK,
+ MojoWait(client_mp, MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_DEADLINE_INDEFINITE, nullptr));
+}
+
+TEST_F(EmbedderTest, ClosePipeToConnectingPeer) {
+ set_launch_type(LaunchType::PEER);
+ auto& controller = StartClient("ClosePipeToConnectingPeerClient");
+ controller.ClosePeerConnection();
+
+ MojoHandle server_mp = controller.pipe();
+
+ EXPECT_EQ(MOJO_RESULT_OK, MojoWait(server_mp, MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_DEADLINE_INDEFINITE, nullptr));
+
+ EXPECT_EQ(0, controller.WaitForShutdown());
+}
+
+DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ClosePipeToConnectingPeerClient, EmbedderTest,
+ client_mp) {
+ ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_DEADLINE_INDEFINITE, nullptr));
+}
+
+#endif // !defined(OS_IOS)
+
} // namespace
} // namespace edk
} // namespace mojo
diff --git a/mojo/edk/embedder/named_platform_channel_pair.h b/mojo/edk/embedder/named_platform_channel_pair.h
new file mode 100644
index 0000000..5a83ae3
--- /dev/null
+++ b/mojo/edk/embedder/named_platform_channel_pair.h
@@ -0,0 +1,73 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_EDK_EMBEDDER_NAMED_PLATFORM_CHANNEL_PAIR_H_
+#define MOJO_EDK_EMBEDDER_NAMED_PLATFORM_CHANNEL_PAIR_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+#include "mojo/edk/embedder/named_platform_handle.h"
+#include "mojo/edk/embedder/scoped_platform_handle.h"
+#include "mojo/edk/system/system_impl_export.h"
+
+namespace base {
+class CommandLine;
+}
+
+namespace mojo {
+namespace edk {
+
+// This is used to create a named bidirectional pipe to connect new child
+// processes. The resulting server handle should be passed to the EDK, and the
+// child end passed as a pipe name on the command line to the child process. The
+// child process can then retrieve the pipe name from the command line and
+// resolve it into a client handle.
+class MOJO_SYSTEM_IMPL_EXPORT NamedPlatformChannelPair {
+ public:
+ struct Options {
+#if defined(OS_WIN)
+ // If non-empty, a security descriptor to use when creating the pipe. If
+ // empty, a default security descriptor will be used. See
+ // kDefaultSecurityDescriptor in named_platform_handle_utils_win.cc.
+ base::string16 security_descriptor;
+#endif
+ };
+
+ NamedPlatformChannelPair(const Options& options = {});
+ ~NamedPlatformChannelPair();
+
+ // Note: It is NOT acceptable to use this handle as a generic pipe channel. It
+ // MUST be passed to PendingProcessConnection::Connect() only.
+ ScopedPlatformHandle PassServerHandle();
+
+ // To be called in the child process, after the parent process called
+ // |PrepareToPassClientHandleToChildProcess()| and launched the child (using
+ // the provided data), to create a client handle connected to the server
+ // handle (in the parent process).
+ static ScopedPlatformHandle PassClientHandleFromParentProcess(
+ const base::CommandLine& command_line);
+
+ // Prepares to pass the client channel to a new child process, to be launched
+ // using |LaunchProcess()| (from base/launch.h). Modifies |*command_line| and
+ // |*handle_passing_info| as needed.
+ // Note: For Windows, this method only works on Vista and later.
+ void PrepareToPassClientHandleToChildProcess(
+ base::CommandLine* command_line) const;
+
+ const NamedPlatformHandle& handle() const { return pipe_handle_; }
+
+ private:
+ NamedPlatformHandle pipe_handle_;
+ ScopedPlatformHandle server_handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(NamedPlatformChannelPair);
+};
+
+} // namespace edk
+} // namespace mojo
+
+#endif // MOJO_EDK_EMBEDDER_NAMED_PLATFORM_CHANNEL_PAIR_H_
diff --git a/mojo/edk/embedder/named_platform_handle.h b/mojo/edk/embedder/named_platform_handle.h
new file mode 100644
index 0000000..15ca656
--- /dev/null
+++ b/mojo/edk/embedder/named_platform_handle.h
@@ -0,0 +1,51 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_EDK_EMBEDDER_NAMED_PLATFORM_HANDLE_H_
+#define MOJO_EDK_EMBEDDER_NAMED_PLATFORM_HANDLE_H_
+
+#include <string>
+
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "mojo/edk/system/system_impl_export.h"
+
+namespace mojo {
+namespace edk {
+
+#if defined(OS_POSIX)
+struct MOJO_SYSTEM_IMPL_EXPORT NamedPlatformHandle {
+ NamedPlatformHandle() {}
+ explicit NamedPlatformHandle(const base::StringPiece& name)
+ : name(name.as_string()) {}
+
+ bool is_valid() const { return !name.empty(); }
+
+ std::string name;
+};
+#elif defined(OS_WIN)
+struct MOJO_SYSTEM_IMPL_EXPORT NamedPlatformHandle {
+ NamedPlatformHandle() {}
+ explicit NamedPlatformHandle(const base::StringPiece& name)
+ : name(base::UTF8ToUTF16(name)) {}
+
+ explicit NamedPlatformHandle(const base::StringPiece16& name)
+ : name(name.as_string()) {}
+
+ bool is_valid() const { return !name.empty(); }
+
+ base::string16 pipe_name() const { return L"\\\\.\\pipe\\mojo." + name; }
+
+ base::string16 name;
+};
+#else
+#error "Platform not yet supported."
+#endif
+
+} // namespace edk
+} // namespace mojo
+
+#endif // MOJO_EDK_EMBEDDER_NAMED_PLATFORM_HANDLE_H_
diff --git a/mojo/edk/embedder/pending_process_connection.cc b/mojo/edk/embedder/pending_process_connection.cc
new file mode 100644
index 0000000..d6be76e
--- /dev/null
+++ b/mojo/edk/embedder/pending_process_connection.cc
@@ -0,0 +1,50 @@
+// 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.
+
+#include "mojo/edk/embedder/pending_process_connection.h"
+
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/embedder_internal.h"
+#include "mojo/edk/system/core.h"
+
+namespace mojo {
+namespace edk {
+
+PendingProcessConnection::PendingProcessConnection()
+ : process_token_(GenerateRandomToken()) {
+ DCHECK(internal::g_core);
+}
+
+PendingProcessConnection::~PendingProcessConnection() {
+ if (has_message_pipes_ && !connected_) {
+ DCHECK(internal::g_core);
+ internal::g_core->ChildLaunchFailed(process_token_);
+ }
+}
+
+ScopedMessagePipeHandle PendingProcessConnection::CreateMessagePipe(
+ std::string* token) {
+ has_message_pipes_ = true;
+ DCHECK(internal::g_core);
+ *token = GenerateRandomToken();
+ return internal::g_core->CreateParentMessagePipe(*token, process_token_);
+}
+
+void PendingProcessConnection::Connect(
+ base::ProcessHandle process,
+ ConnectionParams connection_params,
+ const ProcessErrorCallback& error_callback) {
+ // It's now safe to avoid cleanup in the destructor, as the lifetime of any
+ // associated resources is effectively bound to the |channel| passed to
+ // AddChild() below.
+ DCHECK(!connected_);
+ connected_ = true;
+
+ DCHECK(internal::g_core);
+ internal::g_core->AddChild(process, std::move(connection_params),
+ process_token_, error_callback);
+}
+
+} // namespace edk
+} // namespace mojo
diff --git a/mojo/edk/embedder/pending_process_connection.h b/mojo/edk/embedder/pending_process_connection.h
new file mode 100644
index 0000000..ca18227
--- /dev/null
+++ b/mojo/edk/embedder/pending_process_connection.h
@@ -0,0 +1,124 @@
+// 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_EDK_EMBEDDER_PENDING_PROCESS_CONNECTION_H_
+#define MOJO_EDK_EMBEDDER_PENDING_PROCESS_CONNECTION_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/process/process_handle.h"
+#include "mojo/edk/embedder/connection_params.h"
+#include "mojo/edk/embedder/scoped_platform_handle.h"
+#include "mojo/edk/system/system_impl_export.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace mojo {
+namespace edk {
+
+using ProcessErrorCallback = base::Callback<void(const std::string& error)>;
+
+// Represents a potential connection to an external process. Use this object
+// to make other processes reachable from this one via Mojo IPC. Typical usage
+// might look something like:
+//
+// PendingProcessConnection connection;
+//
+// std::string pipe_token;
+// ScopedMessagePipeHandle pipe = connection.CreateMessagePipe(&pipe_token);
+//
+// // New pipes to the process are fully functional and can be used right
+// // away, even if the process doesn't exist yet.
+// GoDoSomethingInteresting(std::move(pipe));
+//
+// ScopedPlatformChannelPair channel;
+//
+// // Give the pipe token to the child process via command-line.
+// child_command_line.AppendSwitchASCII("yer-pipe", pipe_token);
+//
+// // Magic child process launcher which gives one end of the pipe to the
+// // new process.
+// LaunchProcess(child_command_line, channel.PassClientHandle());
+//
+// // Some time later...
+// connection.Connect(new_process, channel.PassServerHandle());
+//
+// If at any point during the above process, |connection| is destroyed before
+// Connect() can be called, |pipe| will imminently behave as if its peer has
+// been closed.
+//
+// Otherwise, if the remote process in this example eventually calls:
+//
+// mojo::edk::SetParentPipeHandle(std::move(client_channel_handle));
+//
+// std::string token = command_line.GetSwitchValueASCII("yer-pipe");
+// ScopedMessagePipeHandle pipe = mojo::edk::CreateChildMessagePipe(token);
+//
+// it will be connected to this process, and its |pipe| will be connected to
+// this process's |pipe|.
+//
+// If the remote process exits or otherwise closes its client channel handle
+// before calling CreateChildMessagePipe for a given message pipe token,
+// this process's end of the corresponding message pipe will imminently behave
+// as if its peer has been closed.
+//
+class MOJO_SYSTEM_IMPL_EXPORT PendingProcessConnection {
+ public:
+ PendingProcessConnection();
+ ~PendingProcessConnection();
+
+ // Creates a message pipe associated with a new globally unique string value
+ // which will be placed in |*token|.
+ //
+ // The other end of the new pipe is obtainable in the remote process (or in
+ // this process, to facilitate "single-process mode" in some applications) by
+ // passing the new |*token| value to mojo::edk::CreateChildMessagePipe. It's
+ // the caller's responsibility to communicate the value of |*token| to the
+ // remote process by any means available, e.g. a command-line argument on
+ // process launch, or some other out-of-band communication channel for an
+ // existing process.
+ //
+ // NOTES: This may be called any number of times to create multiple message
+ // pipes to the same remote process. This call ALWAYS succeeds, returning
+ // a valid message pipe handle and populating |*token| with a new unique
+ // string value.
+ ScopedMessagePipeHandle CreateMessagePipe(std::string* token);
+
+ // Connects to the process. This must be called at most once, with the process
+ // handle in |process|.
+ //
+ // |connection_param| contains the platform handle of an OS pipe which can be
+ // used to communicate with the connected process. The other end of that pipe
+ // must ultimately be passed to mojo::edk::SetParentPipeHandle in the remote
+ // process, and getting that end of the pipe into the other process is the
+ // embedder's responsibility.
+ //
+ // If this method is not called by the time the PendingProcessConnection is
+ // destroyed, it's assumed that the process is unavailable (e.g. process
+ // launch failed or the process has otherwise been terminated early), and
+ // any associated resources, such as remote endpoints of messages pipes
+ // created by CreateMessagePipe above) will be cleaned up at that time.
+ void Connect(
+ base::ProcessHandle process,
+ ConnectionParams connection_params,
+ const ProcessErrorCallback& error_callback = ProcessErrorCallback());
+
+ private:
+ // A GUID representing a potential new process to be connected to this one.
+ const std::string process_token_;
+
+ // Indicates whether this object has been used to create new message pipes.
+ bool has_message_pipes_ = false;
+
+ // Indicates whether Connect() has been called yet.
+ bool connected_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(PendingProcessConnection);
+};
+
+} // namespace edk
+} // namespace mojo
+
+#endif // MOJO_EDK_EMBEDDER_PENDING_PROCESS_CONNECTION_H_
diff --git a/mojo/edk/embedder/platform_channel_pair.h b/mojo/edk/embedder/platform_channel_pair.h
index f80de89..9c93f76 100644
--- a/mojo/edk/embedder/platform_channel_pair.h
+++ b/mojo/edk/embedder/platform_channel_pair.h
@@ -69,6 +69,7 @@ class MOJO_SYSTEM_IMPL_EXPORT PlatformChannelPair {
// |PrepareToPassClientHandleToChildProcess()| and launched the child (using
// the provided data), to create a client handle connected to the server
// handle (in the parent process).
+ // TODO(jcivelli): remove the command_line param. http://crbug.com/670106
static ScopedPlatformHandle PassClientHandleFromParentProcess(
const base::CommandLine& command_line);
diff --git a/mojo/edk/embedder/platform_channel_pair_posix.cc b/mojo/edk/embedder/platform_channel_pair_posix.cc
index 55f3ae2..4760e95 100644
--- a/mojo/edk/embedder/platform_channel_pair_posix.cc
+++ b/mojo/edk/embedder/platform_channel_pair_posix.cc
@@ -35,6 +35,15 @@ namespace edk {
namespace {
+#if defined(OS_ANDROID)
+enum {
+ // Leave room for any other descriptors defined in content for example.
+ // TODO(jcivelli): consider changing base::GlobalDescriptors to generate a
+ // key when setting the file descriptor (http://crbug.com/676442).
+ kAndroidClientHandleDescriptor =
+ base::GlobalDescriptors::kBaseDescriptor + 10000,
+};
+#else
bool IsTargetDescriptorUsed(
const base::FileHandleMappingVector& file_handle_mapping,
int target_fd) {
@@ -44,6 +53,7 @@ bool IsTargetDescriptorUsed(
}
return false;
}
+#endif
} // namespace
@@ -92,13 +102,21 @@ ScopedPlatformHandle
PlatformChannelPair::PassClientHandleFromParentProcessFromString(
const std::string& value) {
int client_fd = -1;
+#if defined(OS_ANDROID)
+ base::GlobalDescriptors::Key key = -1;
+ if (value.empty() || !base::StringToUint(value, &key)) {
+ LOG(ERROR) << "Missing or invalid --" << kMojoPlatformChannelHandleSwitch;
+ return ScopedPlatformHandle();
+ }
+ client_fd = base::GlobalDescriptors::GetInstance()->Get(key);
+#else
if (value.empty() ||
!base::StringToInt(value, &client_fd) ||
client_fd < base::GlobalDescriptors::kBaseDescriptor) {
LOG(ERROR) << "Missing or invalid --" << kMojoPlatformChannelHandleSwitch;
return ScopedPlatformHandle();
}
-
+#endif
return ScopedPlatformHandle(PlatformHandle(client_fd));
}
@@ -124,6 +142,12 @@ void PlatformChannelPair::PrepareToPassClientHandleToChildProcess(
std::string
PlatformChannelPair::PrepareToPassClientHandleToChildProcessAsString(
HandlePassingInformation* handle_passing_info) const {
+#if defined(OS_ANDROID)
+ int fd = client_handle_.get().handle;
+ handle_passing_info->push_back(
+ std::pair<int, int>(fd, kAndroidClientHandleDescriptor));
+ return base::UintToString(kAndroidClientHandleDescriptor);
+#else
DCHECK(handle_passing_info);
// This is an arbitrary sanity check. (Note that this guarantees that the loop
// below will terminate sanely.)
@@ -141,6 +165,7 @@ PlatformChannelPair::PrepareToPassClientHandleToChildProcessAsString(
handle_passing_info->push_back(
std::pair<int, int>(client_handle_.get().handle, target_fd));
return base::IntToString(target_fd);
+#endif
}
} // namespace edk
diff --git a/mojo/edk/embedder/platform_channel_pair_posix_unittest.cc b/mojo/edk/embedder/platform_channel_pair_posix_unittest.cc
index e05cd79..a3fd275 100644
--- a/mojo/edk/embedder/platform_channel_pair_posix_unittest.cc
+++ b/mojo/edk/embedder/platform_channel_pair_posix_unittest.cc
@@ -153,7 +153,7 @@ TEST_F(PlatformChannelPairPosixTest, SendReceiveFDs) {
for (size_t j = 1; j <= i; j++) {
base::FilePath unused;
base::ScopedFILE fp(
- base::CreateAndOpenTemporaryFileInDir(temp_dir.path(), &unused));
+ base::CreateAndOpenTemporaryFileInDir(temp_dir.GetPath(), &unused));
ASSERT_TRUE(fp);
ASSERT_EQ(j, fwrite(std::string(j, c).data(), 1, j, fp.get()));
platform_handles->push_back(
@@ -209,7 +209,7 @@ TEST_F(PlatformChannelPairPosixTest, AppendReceivedFDs) {
{
base::FilePath unused;
base::ScopedFILE fp(
- base::CreateAndOpenTemporaryFileInDir(temp_dir.path(), &unused));
+ base::CreateAndOpenTemporaryFileInDir(temp_dir.GetPath(), &unused));
ASSERT_TRUE(fp);
ASSERT_EQ(file_contents.size(),
fwrite(file_contents.data(), 1, file_contents.size(), fp.get()));
diff --git a/mojo/edk/embedder/platform_channel_utils_posix.cc b/mojo/edk/embedder/platform_channel_utils_posix.cc
index 3171844..689b6ee 100644
--- a/mojo/edk/embedder/platform_channel_utils_posix.cc
+++ b/mojo/edk/embedder/platform_channel_utils_posix.cc
@@ -8,9 +8,13 @@
#include <sys/socket.h>
#include <unistd.h>
+#include <utility>
+
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "build/build_config.h"
+#include "mojo/edk/embedder/scoped_platform_handle.h"
#if !defined(OS_NACL)
#include <sys/uio.h>
@@ -22,6 +26,55 @@
namespace mojo {
namespace edk {
+namespace {
+
+#if !defined(OS_NACL)
+bool IsRecoverableError() {
+ return errno == ECONNABORTED || errno == EMFILE || errno == ENFILE ||
+ errno == ENOMEM || errno == ENOBUFS;
+}
+
+bool GetPeerEuid(PlatformHandle handle, uid_t* peer_euid) {
+ DCHECK(peer_euid);
+#if defined(OS_MACOSX) || defined(OS_OPENBSD) || defined(OS_FREEBSD)
+ uid_t socket_euid;
+ gid_t socket_gid;
+ if (getpeereid(handle.handle, &socket_euid, &socket_gid) < 0) {
+ PLOG(ERROR) << "getpeereid " << handle.handle;
+ return false;
+ }
+ *peer_euid = socket_euid;
+ return true;
+#else
+ struct ucred cred;
+ socklen_t cred_len = sizeof(cred);
+ if (getsockopt(handle.handle, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) <
+ 0) {
+ PLOG(ERROR) << "getsockopt " << handle.handle;
+ return false;
+ }
+ if (static_cast<unsigned>(cred_len) < sizeof(cred)) {
+ NOTREACHED() << "Truncated ucred from SO_PEERCRED?";
+ return false;
+ }
+ *peer_euid = cred.uid;
+ return true;
+#endif
+}
+
+bool IsPeerAuthorized(PlatformHandle peer_handle) {
+ uid_t peer_euid;
+ if (!GetPeerEuid(peer_handle, &peer_euid))
+ return false;
+ if (peer_euid != geteuid()) {
+ DLOG(ERROR) << "Client euid is not authorised";
+ return false;
+ }
+ return true;
+}
+#endif // !defined(OS_NACL)
+
+} // namespace
// On Linux, |SIGPIPE| is suppressed by passing |MSG_NOSIGNAL| to
// |send()|/|sendmsg()|. (There is no way of suppressing |SIGPIPE| on
@@ -193,5 +246,37 @@ ssize_t PlatformChannelRecvmsg(PlatformHandle h,
return result;
}
+bool ServerAcceptConnection(PlatformHandle server_handle,
+ ScopedPlatformHandle* connection_handle,
+ bool check_peer_user) {
+ DCHECK(server_handle.is_valid());
+ connection_handle->reset();
+#if defined(OS_NACL)
+ NOTREACHED();
+ return false;
+#else
+ ScopedPlatformHandle accept_handle(
+ PlatformHandle(HANDLE_EINTR(accept(server_handle.handle, NULL, 0))));
+ if (!accept_handle.is_valid())
+ return IsRecoverableError();
+
+ // Verify that the IPC channel peer is running as the same user.
+ if (check_peer_user && !IsPeerAuthorized(accept_handle.get())) {
+ return true;
+ }
+
+ if (!base::SetNonBlocking(accept_handle.get().handle)) {
+ PLOG(ERROR) << "base::SetNonBlocking() failed "
+ << accept_handle.get().handle;
+ // It's safe to keep listening on |server_handle| even if the attempt to set
+ // O_NONBLOCK failed on the client fd.
+ return true;
+ }
+
+ *connection_handle = std::move(accept_handle);
+ return true;
+#endif // defined(OS_NACL)
+}
+
} // namespace edk
} // namespace mojo
diff --git a/mojo/edk/embedder/platform_channel_utils_posix.h b/mojo/edk/embedder/platform_channel_utils_posix.h
index 8b24bd0..23cfa92 100644
--- a/mojo/edk/embedder/platform_channel_utils_posix.h
+++ b/mojo/edk/embedder/platform_channel_utils_posix.h
@@ -18,6 +18,7 @@ struct iovec; // Declared in <sys/uio.h>.
namespace mojo {
namespace edk {
+class ScopedPlatformHandle;
// The maximum number of handles that can be sent "at once" using
// |PlatformChannelSendmsgWithHandles()|. This must be less than the Linux
@@ -70,6 +71,16 @@ PlatformChannelRecvmsg(PlatformHandle h,
std::deque<PlatformHandle>* platform_handles,
bool block = false);
+// Returns false if |server_handle| encounters an unrecoverable error.
+// Returns true if it's valid to keep listening on |server_handle|. In this
+// case, it's possible that a connection wasn't successfully established; then,
+// |connection_handle| will be invalid. If |check_peer_user| is True, the
+// connection will be rejected if the peer is running as a different user.
+MOJO_SYSTEM_IMPL_EXPORT bool ServerAcceptConnection(
+ PlatformHandle server_handle,
+ ScopedPlatformHandle* connection_handle,
+ bool check_peer_user = true);
+
} // namespace edk
} // namespace mojo
diff --git a/mojo/edk/embedder/platform_handle.h b/mojo/edk/embedder/platform_handle.h
index 4f76009..4866e75 100644
--- a/mojo/edk/embedder/platform_handle.h
+++ b/mojo/edk/embedder/platform_handle.h
@@ -53,6 +53,9 @@ struct MOJO_SYSTEM_IMPL_EXPORT PlatformHandle {
int handle = -1;
+ // A POSIX handle may be a listen handle that can accept a connection.
+ bool needs_connection = false;
+
#if defined(OS_MACOSX) && !defined(OS_IOS)
mach_port_t port = MACH_PORT_NULL;
#endif
diff --git a/mojo/edk/embedder/platform_handle_utils_posix.cc b/mojo/edk/embedder/platform_handle_utils_posix.cc
index fc2a0db..5604f96 100644
--- a/mojo/edk/embedder/platform_handle_utils_posix.cc
+++ b/mojo/edk/embedder/platform_handle_utils_posix.cc
@@ -15,7 +15,9 @@ ScopedPlatformHandle DuplicatePlatformHandle(PlatformHandle platform_handle) {
DCHECK(platform_handle.is_valid());
// Note that |dup()| returns -1 on error (which is exactly the value we use
// for invalid |PlatformHandle| FDs).
- return ScopedPlatformHandle(PlatformHandle(dup(platform_handle.handle)));
+ PlatformHandle duped(dup(platform_handle.handle));
+ duped.needs_connection = platform_handle.needs_connection;
+ return ScopedPlatformHandle(duped);
}
} // namespace edk
diff --git a/mojo/edk/embedder/platform_shared_buffer.cc b/mojo/edk/embedder/platform_shared_buffer.cc
index 53d8edc..58af44d 100644
--- a/mojo/edk/embedder/platform_shared_buffer.cc
+++ b/mojo/edk/embedder/platform_shared_buffer.cc
@@ -253,21 +253,28 @@ bool PlatformSharedBuffer::InitFromPlatformHandle(
bool PlatformSharedBuffer::InitFromPlatformHandlePair(
ScopedPlatformHandle rw_platform_handle,
ScopedPlatformHandle ro_platform_handle) {
-#if defined(OS_WIN) || defined(OS_MACOSX)
+#if defined(OS_MACOSX)
NOTREACHED();
return false;
-#else
- DCHECK(!shared_memory_);
+#else // defined(OS_MACOSX)
+#if defined(OS_WIN)
+ base::SharedMemoryHandle handle(rw_platform_handle.release().handle,
+ base::GetCurrentProcId());
+ base::SharedMemoryHandle ro_handle(ro_platform_handle.release().handle,
+ base::GetCurrentProcId());
+#else // defined(OS_WIN)
base::SharedMemoryHandle handle(rw_platform_handle.release().handle, false);
- shared_memory_.reset(new base::SharedMemory(handle, false));
-
base::SharedMemoryHandle ro_handle(ro_platform_handle.release().handle,
false);
- ro_shared_memory_.reset(new base::SharedMemory(ro_handle, true));
+#endif // defined(OS_WIN)
+ DCHECK(!shared_memory_);
+ shared_memory_.reset(new base::SharedMemory(handle, false));
+ ro_shared_memory_.reset(new base::SharedMemory(ro_handle, true));
return true;
-#endif
+
+#endif // defined(OS_MACOSX)
}
void PlatformSharedBuffer::InitFromSharedMemoryHandle(
diff --git a/mojo/edk/embedder/process_delegate.h b/mojo/edk/embedder/process_delegate.h
deleted file mode 100644
index 144f4a3..0000000
--- a/mojo/edk/embedder/process_delegate.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_EMBEDDER_PROCESS_DELEGATE_H_
-#define MOJO_EDK_EMBEDDER_PROCESS_DELEGATE_H_
-
-#include "base/macros.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace mojo {
-namespace edk {
-
-// An interface for process delegates.
-class MOJO_SYSTEM_IMPL_EXPORT ProcessDelegate {
- public:
- // Called when |ShutdownIPCSupport()| has completed work on the I/O thread.
- virtual void OnShutdownComplete() = 0;
-
- protected:
- ProcessDelegate() {}
- virtual ~ProcessDelegate() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ProcessDelegate);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_PROCESS_DELEGATE_H_
diff --git a/mojo/edk/js/test/BUILD.gn b/mojo/edk/js/test/BUILD.gn
deleted file mode 100644
index c5a78c3..0000000
--- a/mojo/edk/js/test/BUILD.gn
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//testing/test.gni")
-
-test("js_unittests") {
- output_name = "mojo_js_unittests"
-
- deps = [
- "//base",
- "//gin:gin_test",
- "//mojo/edk/js",
- "//mojo/edk/test:run_all_unittests",
- "//mojo/edk/test:test_support",
- "//mojo/public/cpp/system",
- "//mojo/public/interfaces/bindings/tests:test_interfaces",
- "//mojo/public/interfaces/bindings/tests:test_interfaces_experimental",
- "//mojo/public/js:tests",
- ]
-
- sources = [
- "//mojo/edk/js/handle_unittest.cc",
- "run_js_tests.cc",
- ]
-}
-
-test("js_integration_tests") {
- output_name = "mojo_js_integration_tests"
-
- deps = [
- "//base",
- "//gin:gin_test",
- "//mojo/edk/js",
- "//mojo/edk/js/tests:js_to_cpp_tests",
- "//mojo/edk/test:run_all_unittests",
- "//mojo/edk/test:test_support",
- "//mojo/public/cpp/bindings",
- "//mojo/public/interfaces/bindings/tests:test_interfaces",
- "//mojo/public/js:bindings",
- ]
-
- sources = [
- "run_js_integration_tests.cc",
- ]
-}
diff --git a/mojo/edk/js/test/hexdump.js b/mojo/edk/js/test/hexdump.js
deleted file mode 100644
index b36c47f..0000000
--- a/mojo/edk/js/test/hexdump.js
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define(function() {
- function hexify(value, length) {
- var hex = value.toString(16);
- while (hex.length < length)
- hex = "0" + hex;
- return hex;
- }
-
- function dumpArray(bytes) {
- var dumped = "";
- for (var i = 0; i < bytes.length; ++i) {
- dumped += hexify(bytes[i], 2);
-
- if (i % 16 == 15) {
- dumped += "\n";
- continue;
- }
-
- if (i % 2 == 1)
- dumped += " ";
- if (i % 8 == 7)
- dumped += " ";
- }
- return dumped;
- }
-
- var exports = {};
- exports.dumpArray = dumpArray;
- return exports;
-});
diff --git a/mojo/edk/js/test/run_js_integration_tests.cc b/mojo/edk/js/test/run_js_integration_tests.cc
deleted file mode 100644
index 00d3e96..0000000
--- a/mojo/edk/js/test/run_js_integration_tests.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/path_service.h"
-#include "gin/modules/console.h"
-#include "gin/modules/module_registry.h"
-#include "gin/modules/timer.h"
-#include "gin/test/file_runner.h"
-#include "gin/test/gtest.h"
-#include "mojo/edk/js/core.h"
-#include "mojo/edk/js/support.h"
-#include "mojo/edk/js/threading.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-namespace {
-
-class TestRunnerDelegate : public gin::FileRunnerDelegate {
- public:
- TestRunnerDelegate() {
- AddBuiltinModule(gin::Console::kModuleName, gin::Console::GetModule);
- AddBuiltinModule(Core::kModuleName, Core::GetModule);
- AddBuiltinModule(gin::TimerModule::kName, gin::TimerModule::GetModule);
- AddBuiltinModule(Threading::kModuleName, Threading::GetModule);
- AddBuiltinModule(Support::kModuleName, Support::GetModule);
- }
- private:
- DISALLOW_COPY_AND_ASSIGN(TestRunnerDelegate);
-};
-
-void RunTest(std::string test) {
- base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
- path = path.AppendASCII("mojo")
- .AppendASCII("edk")
- .AppendASCII("js")
- .AppendASCII("tests")
- .AppendASCII(test);
- TestRunnerDelegate delegate;
- gin::RunTestFromFile(path, &delegate, false);
-}
-
-TEST(JSTest, connection) {
- RunTest("connection_tests.js");
-}
-
-TEST(JSTest, sample_service) {
- RunTest("sample_service_tests.js");
-}
-
-} // namespace
-} // namespace js
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/js/test/run_js_tests.cc b/mojo/edk/js/test/run_js_tests.cc
deleted file mode 100644
index d0e8edc..0000000
--- a/mojo/edk/js/test/run_js_tests.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/path_service.h"
-#include "gin/modules/console.h"
-#include "gin/modules/module_registry.h"
-#include "gin/test/file_runner.h"
-#include "gin/test/gtest.h"
-#include "mojo/edk/js/core.h"
-#include "mojo/edk/js/support.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-namespace {
-
-class TestRunnerDelegate : public gin::FileRunnerDelegate {
- public:
- TestRunnerDelegate() {
- AddBuiltinModule(gin::Console::kModuleName, gin::Console::GetModule);
- AddBuiltinModule(Core::kModuleName, Core::GetModule);
- AddBuiltinModule(Support::kModuleName, Support::GetModule);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestRunnerDelegate);
-};
-
-void RunTest(std::string test, bool run_until_idle) {
- base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
- path = path.AppendASCII("mojo")
- .AppendASCII("public")
- .AppendASCII("js")
- .AppendASCII(test);
- TestRunnerDelegate delegate;
- gin::RunTestFromFile(path, &delegate, run_until_idle);
-}
-
-// TODO(abarth): Should we autogenerate these stubs from GYP?
-TEST(JSTest, core) {
- RunTest("core_unittests.js", true);
-}
-
-TEST(JSTest, codec) {
- RunTest("codec_unittests.js", true);
-}
-
-TEST(JSTest, struct) {
- RunTest("struct_unittests.js", true);
-}
-
-TEST(JSTest, union) {
- RunTest("union_unittests.js", true);
-}
-
-TEST(JSTest, validation) {
- RunTest("validation_unittests.js", true);
-}
-
-} // namespace
-} // namespace js
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/js/tests/BUILD.gn b/mojo/edk/js/tests/BUILD.gn
index b21cdbc..41850d7 100644
--- a/mojo/edk/js/tests/BUILD.gn
+++ b/mojo/edk/js/tests/BUILD.gn
@@ -2,21 +2,34 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("../../../../mojo/public/tools/bindings/mojom.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
+import("//testing/test.gni")
-source_set("js_to_cpp_tests") {
+# TODO(hansmuller): The organization of tests in this directory is weird:
+# * Really, js_unittests tests public stuff, so that should live in public
+# and be reworked as some sort of apptest.
+# * Both js_unittests and js_integration_tests should auto-generate their
+# tests somehow. The .cc files are just test runner stubs, including
+# explicit lists of .js files.
+
+group("tests") {
testonly = true
+ deps = [
+ ":mojo_js_integration_tests",
+ ":mojo_js_unittests",
+ ]
+}
+test("mojo_js_integration_tests") {
deps = [
":js_to_cpp_bindings",
"//gin:gin_test",
"//mojo/common",
"//mojo/edk/js",
- "//mojo/edk/test:test_support",
+ "//mojo/edk/test:run_all_unittests",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
- "//mojo/public/interfaces/bindings/tests:test_interfaces",
- "//mojo/public/interfaces/bindings/tests:test_interfaces_experimental",
+ "//mojo/public/js:bindings",
]
sources = [
@@ -24,9 +37,7 @@ source_set("js_to_cpp_tests") {
]
data = [
- "connection_tests.js",
"js_to_cpp_tests.js",
- "sample_service_tests.js",
]
configs += [ "//v8:external_startup_data" ]
@@ -37,3 +48,22 @@ mojom("js_to_cpp_bindings") {
"js_to_cpp.mojom",
]
}
+
+test("mojo_js_unittests") {
+ deps = [
+ "//base",
+ "//gin:gin_test",
+ "//mojo/edk/js",
+ "//mojo/edk/test:run_all_unittests",
+ "//mojo/edk/test:test_support",
+ "//mojo/public/cpp/system",
+ "//mojo/public/interfaces/bindings/tests:test_interfaces",
+ "//mojo/public/interfaces/bindings/tests:test_interfaces_experimental",
+ "//mojo/public/js:tests",
+ ]
+
+ sources = [
+ "//mojo/edk/js/handle_unittest.cc",
+ "run_js_unittests.cc",
+ ]
+}
diff --git a/mojo/edk/js/tests/connection_tests.js b/mojo/edk/js/tests/connection_tests.js
deleted file mode 100644
index 0b4b213..0000000
--- a/mojo/edk/js/tests/connection_tests.js
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define([
- "gin/test/expect",
- "mojo/public/js/connection",
- "mojo/public/js/core",
- "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom",
- "mojo/public/interfaces/bindings/tests/sample_service.mojom",
- "mojo/public/js/threading",
- "gc",
-], function(expect,
- connection,
- core,
- sample_interfaces,
- sample_service,
- threading,
- gc) {
- testClientServer()
- .then(testWriteToClosedPipe)
- .then(testRequestResponse)
- .then(function() {
- this.result = "PASS";
- gc.collectGarbage(); // should not crash
- threading.quit();
- }.bind(this)).catch(function(e) {
- this.result = "FAIL: " + (e.stack || e);
- threading.quit();
- }.bind(this));
-
- function testClientServer() {
- // ServiceImpl ------------------------------------------------------------
-
- function ServiceImpl() {
- }
-
- ServiceImpl.prototype = Object.create(
- sample_service.Service.stubClass.prototype);
-
- ServiceImpl.prototype.frobinate = function(foo, baz, port) {
- expect(foo.name).toBe("Example name");
- expect(baz).toBe(sample_service.Service.BazOptions.REGULAR);
- expect(core.close(port)).toBe(core.RESULT_OK);
-
- return Promise.resolve({result: 42});
- };
-
- var pipe = core.createMessagePipe();
- var anotherPipe = core.createMessagePipe();
- var sourcePipe = core.createMessagePipe();
-
- var connection0 = new connection.Connection(pipe.handle0, ServiceImpl);
-
- var connection1 = new connection.Connection(
- pipe.handle1, undefined, sample_service.Service.proxyClass);
-
- var foo = new sample_service.Foo();
- foo.bar = new sample_service.Bar();
- foo.name = "Example name";
- foo.source = sourcePipe.handle0;
- var promise = connection1.remote.frobinate(
- foo, sample_service.Service.BazOptions.REGULAR, anotherPipe.handle0)
- .then(function(response) {
- expect(response.result).toBe(42);
-
- connection0.close();
- connection1.close();
-
- return Promise.resolve();
- });
-
- // sourcePipe.handle1 hasn't been closed yet.
- expect(core.close(sourcePipe.handle1)).toBe(core.RESULT_OK);
-
- // anotherPipe.handle1 hasn't been closed yet.
- expect(core.close(anotherPipe.handle1)).toBe(core.RESULT_OK);
-
- return promise;
- }
-
- function testWriteToClosedPipe() {
- var pipe = core.createMessagePipe();
- var anotherPipe = core.createMessagePipe();
-
- var connection1 = new connection.Connection(
- pipe.handle1, function() {}, sample_service.Service.proxyClass);
-
- // Close the other end of the pipe.
- core.close(pipe.handle0);
-
- // Not observed yet because we haven't pumped events yet.
- expect(connection1.encounteredError()).toBeFalsy();
-
- var promise = connection1.remote.frobinate(
- null, sample_service.Service.BazOptions.REGULAR, anotherPipe.handle0)
- .then(function(response) {
- return Promise.reject("Unexpected response");
- }).catch(function(e) {
- // We should observe the closed pipe.
- expect(connection1.encounteredError()).toBeTruthy();
- return Promise.resolve();
- });
-
- // Write failures are not reported.
- expect(connection1.encounteredError()).toBeFalsy();
-
- return promise;
- }
-
- function testRequestResponse() {
- // ProviderImpl ------------------------------------------------------------
-
- function ProviderImpl() {
- }
-
- ProviderImpl.prototype =
- Object.create(sample_interfaces.Provider.stubClass.prototype);
-
- ProviderImpl.prototype.echoString = function(a) {
- return Promise.resolve({a: a});
- };
-
- ProviderImpl.prototype.echoStrings = function(a, b) {
- return Promise.resolve({a: a, b: b});
- };
-
- var pipe = core.createMessagePipe();
-
- var connection0 = new connection.Connection(pipe.handle0, ProviderImpl);
-
- var connection1 = new connection.Connection(
- pipe.handle1, undefined, sample_interfaces.Provider.proxyClass);
-
- var promise = connection1.remote.echoString("hello")
- .then(function(response) {
- expect(response.a).toBe("hello");
- return connection1.remote.echoStrings("hello", "world");
- }).then(function(response) {
- expect(response.a).toBe("hello");
- expect(response.b).toBe("world");
- // Mock a read failure, expect it to fail.
- core.readMessage = function() {
- return { result: core.RESULT_UNKNOWN };
- };
- return connection1.remote.echoString("goodbye");
- }).then(function() {
- throw Error("Expected echoString to fail.");
- }, function(error) {
- expect(error.message).toBe("Connection error: " + core.RESULT_UNKNOWN);
-
- return Promise.resolve();
- });
-
- return promise;
- }
-});
diff --git a/mojo/edk/js/tests/js_to_cpp_tests.cc b/mojo/edk/js/tests/js_to_cpp_tests.cc
index 6d3426d..e5e6bd1 100644
--- a/mojo/edk/js/tests/js_to_cpp_tests.cc
+++ b/mojo/edk/js/tests/js_to_cpp_tests.cc
@@ -15,14 +15,15 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "gin/array_buffer.h"
#include "gin/public/isolate_holder.h"
#include "gin/v8_initializer.h"
#include "mojo/common/data_pipe_utils.h"
#include "mojo/edk/js/mojo_runner_delegate.h"
#include "mojo/edk/js/tests/js_to_cpp.mojom.h"
-#include "mojo/edk/test/test_utils.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/lib/validation_errors.h"
#include "mojo/public/cpp/system/core.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -104,12 +105,11 @@ js_to_cpp::EchoArgsPtr BuildSampleEchoArgs() {
args->double_val = kExpectedDoubleVal;
args->double_inf = kExpectedDoubleInf;
args->double_nan = kExpectedDoubleNan;
- args->name = "coming";
- Array<String> string_array(3);
- string_array[0] = "one";
- string_array[1] = "two";
- string_array[2] = "three";
- args->string_array = std::move(string_array);
+ args->name.emplace("coming");
+ args->string_array.emplace(3);
+ (*args->string_array)[0] = "one";
+ (*args->string_array)[1] = "two";
+ (*args->string_array)[2] = "three";
return args;
}
@@ -128,10 +128,10 @@ void CheckSampleEchoArgs(js_to_cpp::EchoArgsPtr arg) {
EXPECT_EQ(kExpectedDoubleVal, arg->double_val);
EXPECT_EQ(kExpectedDoubleInf, arg->double_inf);
EXPECT_NAN(arg->double_nan);
- EXPECT_EQ(std::string("coming"), arg->name.get());
- EXPECT_EQ(std::string("one"), arg->string_array[0].get());
- EXPECT_EQ(std::string("two"), arg->string_array[1].get());
- EXPECT_EQ(std::string("three"), arg->string_array[2].get());
+ EXPECT_EQ(std::string("coming"), *arg->name);
+ EXPECT_EQ(std::string("one"), (*arg->string_array)[0]);
+ EXPECT_EQ(std::string("two"), (*arg->string_array)[1]);
+ EXPECT_EQ(std::string("three"), (*arg->string_array)[2]);
CheckDataPipe(std::move(arg->data_handle));
CheckMessagePipe(arg->message_handle.get());
}
@@ -146,18 +146,23 @@ void CheckSampleEchoArgsList(const js_to_cpp::EchoArgsListPtr& list) {
// More forgiving checks are needed in the face of potentially corrupt
// messages. The values don't matter so long as all accesses are within
// bounds.
-void CheckCorruptedString(const String& arg) {
- if (arg.is_null())
- return;
+void CheckCorruptedString(const std::string& arg) {
for (size_t i = 0; i < arg.size(); ++i)
g_waste_accumulator += arg[i];
}
-void CheckCorruptedStringArray(const Array<String>& string_array) {
- if (string_array.is_null())
+void CheckCorruptedString(const base::Optional<std::string>& arg) {
+ if (!arg)
return;
- for (size_t i = 0; i < string_array.size(); ++i)
- CheckCorruptedString(string_array[i]);
+ CheckCorruptedString(*arg);
+}
+
+void CheckCorruptedStringArray(
+ const base::Optional<std::vector<std::string>>& string_array) {
+ if (!string_array)
+ return;
+ for (size_t i = 0; i < string_array->size(); ++i)
+ CheckCorruptedString((*string_array)[i]);
}
void CheckCorruptedDataPipe(MojoHandle data_pipe_handle) {
@@ -297,7 +302,7 @@ class EchoCppSideConnection : public CppSideConnection {
EXPECT_EQ(-1, special_arg->si32);
EXPECT_EQ(-1, special_arg->si16);
EXPECT_EQ(-1, special_arg->si8);
- EXPECT_EQ(std::string("going"), special_arg->name.To<std::string>());
+ EXPECT_EQ(std::string("going"), *special_arg->name);
CheckSampleEchoArgsList(list->next);
}
@@ -383,11 +388,11 @@ class JsToCppTest : public testing::Test {
cpp_side->set_run_loop(&run_loop_);
js_to_cpp::JsSidePtr js_side;
- auto js_side_proxy = GetProxy(&js_side);
+ auto js_side_proxy = MakeRequest(&js_side);
cpp_side->set_js_side(js_side.get());
js_to_cpp::CppSidePtr cpp_side_ptr;
- cpp_side->Bind(GetProxy(&cpp_side_ptr));
+ cpp_side->Bind(MakeRequest(&cpp_side_ptr));
js_side->SetCppSide(std::move(cpp_side_ptr));
@@ -399,7 +404,7 @@ class JsToCppTest : public testing::Test {
gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
gin::IsolateHolder::kStableV8Extras,
gin::ArrayBufferAllocator::SharedInstance());
- gin::IsolateHolder instance;
+ gin::IsolateHolder instance(base::ThreadTaskRunnerHandle::Get());
MojoRunnerDelegate delegate;
gin::ShellRunner runner(&delegate, instance.isolate());
delegate.Start(&runner, js_side_proxy.PassMessagePipe().release().value(),
@@ -429,12 +434,18 @@ TEST_F(JsToCppTest, Echo) {
}
TEST_F(JsToCppTest, BitFlip) {
+ // These tests generate a lot of expected validation errors. Suppress logging.
+ mojo::internal::ScopedSuppressValidationErrorLoggingForTests log_suppression;
+
BitFlipCppSideConnection cpp_side_connection;
RunTest("mojo/edk/js/tests/js_to_cpp_tests", &cpp_side_connection);
EXPECT_TRUE(cpp_side_connection.DidSucceed());
}
TEST_F(JsToCppTest, BackPointer) {
+ // These tests generate a lot of expected validation errors. Suppress logging.
+ mojo::internal::ScopedSuppressValidationErrorLoggingForTests log_suppression;
+
BackPointerCppSideConnection cpp_side_connection;
RunTest("mojo/edk/js/tests/js_to_cpp_tests", &cpp_side_connection);
EXPECT_TRUE(cpp_side_connection.DidSucceed());
diff --git a/mojo/edk/js/tests/js_to_cpp_tests.js b/mojo/edk/js/tests/js_to_cpp_tests.js
index ddecc4b..6b69fca 100644
--- a/mojo/edk/js/tests/js_to_cpp_tests.js
+++ b/mojo/edk/js/tests/js_to_cpp_tests.js
@@ -6,10 +6,9 @@ define('mojo/edk/js/tests/js_to_cpp_tests', [
'console',
'mojo/edk/js/tests/js_to_cpp.mojom',
'mojo/public/js/bindings',
- 'mojo/public/js/connection',
'mojo/public/js/connector',
'mojo/public/js/core',
-], function (console, jsToCpp, bindings, connection, connector, core) {
+], function (console, jsToCpp, bindings, connector, core) {
var retainedJsSide;
var retainedJsSideStub;
var sampleData;
@@ -22,11 +21,9 @@ define('mojo/edk/js/tests/js_to_cpp_tests', [
};
function JsSideConnection() {
+ this.binding = new bindings.Binding(jsToCpp.JsSide, this);
}
- JsSideConnection.prototype =
- Object.create(jsToCpp.JsSide.stubClass.prototype);
-
JsSideConnection.prototype.setCppSide = function(cppSide) {
this.cppSide_ = cppSide;
this.cppSide_.startTest();
@@ -220,9 +217,7 @@ define('mojo/edk/js/tests/js_to_cpp_tests', [
for (i = 0; i < sampleMessage.length; ++i) {
sampleMessage[i] = 255 - i;
}
- retainedJsSideStub =
- connection.bindHandleToStub(jsSideRequestHandle, jsToCpp.JsSide);
retainedJsSide = new JsSideConnection;
- bindings.StubBindings(retainedJsSideStub).delegate = retainedJsSide;
+ retainedJsSide.binding.bind(jsSideRequestHandle);
};
});
diff --git a/mojo/edk/js/tests/sample_service_tests.js b/mojo/edk/js/tests/sample_service_tests.js
deleted file mode 100644
index 2b065a8..0000000
--- a/mojo/edk/js/tests/sample_service_tests.js
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define([
- "gin/test/expect",
- "mojo/public/interfaces/bindings/tests/sample_service.mojom",
- "mojo/public/interfaces/bindings/tests/sample_import.mojom",
- "mojo/public/interfaces/bindings/tests/sample_import2.mojom",
- "mojo/public/js/connection",
- "mojo/public/js/core",
- "mojo/public/js/threading",
- ], function(expect, sample, imported, imported2, connection, core,
- threading) {
- testDefaultValues()
- .then(testSampleService)
- .then(function() {
- this.result = "PASS";
- threading.quit();
- }.bind(this)).catch(function(e) {
- this.result = "FAIL: " + (e.stack || e);
- threading.quit();
- }.bind(this));
-
- // Checks that values are set to the defaults if we don't override them.
- function testDefaultValues() {
- var bar = new sample.Bar();
- expect(bar.alpha).toBe(255);
- expect(bar.type).toBe(sample.Bar.Type.VERTICAL);
-
- var foo = new sample.Foo();
- expect(foo.name).toBe("Fooby");
- expect(foo.a).toBeTruthy();
- expect(foo.data).toBeNull();
-
- var defaults = new sample.DefaultsTest();
- expect(defaults.a0).toBe(-12);
- expect(defaults.a1).toBe(sample.kTwelve);
- expect(defaults.a2).toBe(1234);
- expect(defaults.a3).toBe(34567);
- expect(defaults.a4).toBe(123456);
- expect(defaults.a5).toBe(3456789012);
- expect(defaults.a6).toBe(-111111111111);
- // JS doesn't have a 64 bit integer type so this is just checking that the
- // expected and actual values have the same closest double value.
- expect(defaults.a7).toBe(9999999999999999999);
- expect(defaults.a8).toBe(0x12345);
- expect(defaults.a9).toBe(-0x12345);
- expect(defaults.a10).toBe(1234);
- expect(defaults.a11).toBe(true);
- expect(defaults.a12).toBe(false);
- expect(defaults.a13).toBe(123.25);
- expect(defaults.a14).toBe(1234567890.123);
- expect(defaults.a15).toBe(1E10);
- expect(defaults.a16).toBe(-1.2E+20);
- expect(defaults.a17).toBe(1.23E-20);
- expect(defaults.a20).toBe(sample.Bar.Type.BOTH);
- expect(defaults.a21).toBeNull();
- expect(defaults.a22).toBeTruthy();
- expect(defaults.a22.shape).toBe(imported.Shape.RECTANGLE);
- expect(defaults.a22.color).toBe(imported2.Color.BLACK);
- expect(defaults.a21).toBeNull();
- expect(defaults.a23).toBe(0xFFFFFFFFFFFFFFFF);
- expect(defaults.a24).toBe(0x123456789);
- expect(defaults.a25).toBe(-0x123456789);
-
- return Promise.resolve();
- }
-
- function testSampleService() {
- function ServiceImpl() {
- }
-
- ServiceImpl.prototype = Object.create(sample.Service.stubClass.prototype);
-
- ServiceImpl.prototype.frobinate = function(foo, baz, port) {
- checkFoo(foo);
- expect(baz).toBe(sample.Service.BazOptions.EXTRA);
- expect(core.isHandle(port)).toBeTruthy();
- return Promise.resolve({result: 1234});
- };
-
- var foo = makeFoo();
- checkFoo(foo);
-
- var sampleServicePipe = core.createMessagePipe();
- var connection0 = new connection.Connection(sampleServicePipe.handle0,
- ServiceImpl);
- var connection1 = new connection.Connection(
- sampleServicePipe.handle1, undefined, sample.Service.proxyClass);
-
- var pipe = core.createMessagePipe();
- var promise = connection1.remote.frobinate(
- foo, sample.Service.BazOptions.EXTRA, pipe.handle0)
- .then(function(response) {
- expect(response.result).toBe(1234);
-
- return Promise.resolve();
- });
-
- return promise;
- }
-
- function makeFoo() {
- var bar = new sample.Bar();
- bar.alpha = 20;
- bar.beta = 40;
- bar.gamma = 60;
- bar.type = sample.Bar.Type.VERTICAL;
-
- var extra_bars = new Array(3);
- for (var i = 0; i < extra_bars.length; ++i) {
- var base = i * 100;
- var type = i % 2 ?
- sample.Bar.Type.VERTICAL : sample.Bar.Type.HORIZONTAL;
- extra_bars[i] = new sample.Bar();
- extra_bars[i].alpha = base;
- extra_bars[i].beta = base + 20;
- extra_bars[i].gamma = base + 40;
- extra_bars[i].type = type;
- }
-
- var data = new Array(10);
- for (var i = 0; i < data.length; ++i) {
- data[i] = data.length - i;
- }
-
- var foo = new sample.Foo();
- foo.name = "foopy";
- foo.x = 1;
- foo.y = 2;
- foo.a = false;
- foo.b = true;
- foo.c = false;
- foo.bar = bar;
- foo.extra_bars = extra_bars;
- foo.data = data;
-
- // TODO(yzshen): currently setting it to null will cause connection error,
- // even if the field is defined as nullable. crbug.com/575753
- foo.source = core.createMessagePipe().handle0;
-
- return foo;
- }
-
- // Checks that the given |Foo| is identical to the one made by |makeFoo()|.
- function checkFoo(foo) {
- expect(foo.name).toBe("foopy");
- expect(foo.x).toBe(1);
- expect(foo.y).toBe(2);
- expect(foo.a).toBeFalsy();
- expect(foo.b).toBeTruthy();
- expect(foo.c).toBeFalsy();
- expect(foo.bar.alpha).toBe(20);
- expect(foo.bar.beta).toBe(40);
- expect(foo.bar.gamma).toBe(60);
- expect(foo.bar.type).toBe(sample.Bar.Type.VERTICAL);
-
- expect(foo.extra_bars.length).toBe(3);
- for (var i = 0; i < foo.extra_bars.length; ++i) {
- var base = i * 100;
- var type = i % 2 ?
- sample.Bar.Type.VERTICAL : sample.Bar.Type.HORIZONTAL;
- expect(foo.extra_bars[i].alpha).toBe(base);
- expect(foo.extra_bars[i].beta).toBe(base + 20);
- expect(foo.extra_bars[i].gamma).toBe(base + 40);
- expect(foo.extra_bars[i].type).toBe(type);
- }
-
- expect(foo.data.length).toBe(10);
- for (var i = 0; i < foo.data.length; ++i)
- expect(foo.data[i]).toBe(foo.data.length - i);
-
- expect(core.isHandle(foo.source)).toBeTruthy();
- }
-});
diff --git a/mojo/edk/system/BUILD.gn b/mojo/edk/system/BUILD.gn
index 84f1f30..b0acf23 100644
--- a/mojo/edk/system/BUILD.gn
+++ b/mojo/edk/system/BUILD.gn
@@ -20,9 +20,10 @@ component("system") {
"awakable_list.cc",
"awakable_list.h",
"broker.h",
+ "broker_host.cc",
"broker_host.h",
- "broker_host_posix.cc",
"broker_posix.cc",
+ "broker_win.cc",
"channel.cc",
"channel.h",
"channel_posix.cc",
@@ -75,7 +76,6 @@ component("system") {
public_deps = [
"//mojo/edk/embedder",
- "//mojo/edk/embedder:delegates",
"//mojo/edk/embedder:platform",
"//mojo/edk/system/ports",
"//mojo/public/c/system",
@@ -104,7 +104,7 @@ component("system") {
if (is_nacl && !is_nacl_nonsfi) {
sources -= [
- "broker_host_posix.cc",
+ "broker_host.cc",
"broker_posix.cc",
"channel_posix.cc",
]
@@ -154,6 +154,7 @@ source_set("test_utils") {
test("mojo_system_unittests") {
sources = [
"awakable_list_unittest.cc",
+ "channel_unittest.cc",
"core_test_base.cc",
"core_test_base.h",
"core_unittest.cc",
@@ -186,6 +187,7 @@ test("mojo_system_unittests") {
"//mojo/edk/system/ports:tests",
"//mojo/edk/test:run_all_unittests",
"//mojo/edk/test:test_support",
+ "//testing/gmock",
"//testing/gtest",
]
diff --git a/mojo/edk/system/broker_host_posix.cc b/mojo/edk/system/broker_host.cc
index ed8e213..6096034 100644
--- a/mojo/edk/system/broker_host_posix.cc
+++ b/mojo/edk/system/broker_host.cc
@@ -4,17 +4,14 @@
#include "mojo/edk/system/broker_host.h"
-#include <fcntl.h>
-#include <unistd.h>
-
#include <utility>
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/embedder/platform_channel_utils_posix.h"
+#include "mojo/edk/embedder/named_platform_channel_pair.h"
+#include "mojo/edk/embedder/named_platform_handle.h"
#include "mojo/edk/embedder/platform_handle_vector.h"
#include "mojo/edk/embedder/platform_shared_buffer.h"
#include "mojo/edk/system/broker_messages.h"
@@ -22,18 +19,17 @@
namespace mojo {
namespace edk {
-namespace {
-// To prevent abuse, limit the maximum size of shared memory buffers.
-// TODO(amistry): Re-consider this limit, or do something smarter.
-const size_t kMaxSharedBufferSize = 16 * 1024 * 1024;
-}
-
-BrokerHost::BrokerHost(ScopedPlatformHandle platform_handle) {
+BrokerHost::BrokerHost(base::ProcessHandle client_process,
+ ScopedPlatformHandle platform_handle)
+#if defined(OS_WIN)
+ : client_process_(client_process)
+#endif
+{
CHECK(platform_handle.is_valid());
base::MessageLoop::current()->AddDestructionObserver(this);
- channel_ = Channel::Create(this, std::move(platform_handle),
+ channel_ = Channel::Create(this, ConnectionParams(std::move(platform_handle)),
base::ThreadTaskRunnerHandle::Get());
channel_->Start();
}
@@ -46,32 +42,70 @@ BrokerHost::~BrokerHost() {
channel_->ShutDown();
}
-void BrokerHost::SendChannel(ScopedPlatformHandle handle) {
+bool BrokerHost::PrepareHandlesForClient(PlatformHandleVector* handles) {
+#if defined(OS_WIN)
+ if (!Channel::Message::RewriteHandles(
+ base::GetCurrentProcessHandle(), client_process_, handles)) {
+ // NOTE: We only log an error here. We do not signal a logical error or
+ // prevent any message from being sent. The client should handle unexpected
+ // invalid handles appropriately.
+ DLOG(ERROR) << "Failed to rewrite one or more handles to broker client.";
+ return false;
+ }
+#endif
+ return true;
+}
+
+bool BrokerHost::SendChannel(ScopedPlatformHandle handle) {
CHECK(handle.is_valid());
CHECK(channel_);
+#if defined(OS_WIN)
+ InitData* data;
+ Channel::MessagePtr message =
+ CreateBrokerMessage(BrokerMessageType::INIT, 1, 0, &data);
+ data->pipe_name_length = 0;
+#else
Channel::MessagePtr message =
CreateBrokerMessage(BrokerMessageType::INIT, 1, nullptr);
+#endif
ScopedPlatformHandleVectorPtr handles;
handles.reset(new PlatformHandleVector(1));
handles->at(0) = handle.release();
- message->SetHandles(std::move(handles));
+ // This may legitimately fail on Windows if the client process is in another
+ // session, e.g., is an elevated process.
+ if (!PrepareHandlesForClient(handles.get()))
+ return false;
+
+ message->SetHandles(std::move(handles));
channel_->Write(std::move(message));
+ return true;
}
-void BrokerHost::OnBufferRequest(size_t num_bytes) {
- scoped_refptr<PlatformSharedBuffer> buffer;
+#if defined(OS_WIN)
+
+void BrokerHost::SendNamedChannel(const base::StringPiece16& pipe_name) {
+ InitData* data;
+ base::char16* name_data;
+ Channel::MessagePtr message = CreateBrokerMessage(
+ BrokerMessageType::INIT, 0, sizeof(*name_data) * pipe_name.length(),
+ &data, reinterpret_cast<void**>(&name_data));
+ data->pipe_name_length = static_cast<uint32_t>(pipe_name.length());
+ std::copy(pipe_name.begin(), pipe_name.end(), name_data);
+ channel_->Write(std::move(message));
+}
+
+#endif // defined(OS_WIN)
+
+void BrokerHost::OnBufferRequest(uint32_t num_bytes) {
scoped_refptr<PlatformSharedBuffer> read_only_buffer;
- if (num_bytes <= kMaxSharedBufferSize) {
- buffer = PlatformSharedBuffer::Create(num_bytes);
- if (buffer)
- read_only_buffer = buffer->CreateReadOnlyDuplicate();
- if (!read_only_buffer)
- buffer = nullptr;
- } else {
- LOG(ERROR) << "Shared buffer request too large: " << num_bytes;
- }
+ scoped_refptr<PlatformSharedBuffer> buffer =
+ PlatformSharedBuffer::Create(num_bytes);
+ if (buffer)
+ read_only_buffer = buffer->CreateReadOnlyDuplicate();
+ if (!read_only_buffer)
+ buffer = nullptr;
Channel::MessagePtr message = CreateBrokerMessage(
BrokerMessageType::BUFFER_RESPONSE, buffer ? 2 : 0, nullptr);
@@ -80,6 +114,7 @@ void BrokerHost::OnBufferRequest(size_t num_bytes) {
handles.reset(new PlatformHandleVector(2));
handles->at(0) = buffer->PassPlatformHandle().release();
handles->at(1) = read_only_buffer->PassPlatformHandle().release();
+ PrepareHandlesForClient(handles.get());
message->SetHandles(std::move(handles));
}
@@ -101,29 +136,18 @@ void BrokerHost::OnChannelMessage(const void* payload,
const BufferRequestData* request =
reinterpret_cast<const BufferRequestData*>(header + 1);
OnBufferRequest(request->size);
- return;
}
break;
default:
+ LOG(ERROR) << "Unexpected broker message type: " << header->type;
break;
}
-
- LOG(ERROR) << "Unexpected broker message type: " << header->type;
}
-void BrokerHost::OnChannelError() {
- if (channel_) {
- channel_->ShutDown();
- channel_ = nullptr;
- }
+void BrokerHost::OnChannelError() { delete this; }
- delete this;
-}
-
-void BrokerHost::WillDestroyCurrentMessageLoop() {
- delete this;
-}
+void BrokerHost::WillDestroyCurrentMessageLoop() { delete this; }
} // namespace edk
} // namespace mojo
diff --git a/mojo/edk/system/broker_host.h b/mojo/edk/system/broker_host.h
index b8f68c4..a7995d2 100644
--- a/mojo/edk/system/broker_host.h
+++ b/mojo/edk/system/broker_host.h
@@ -5,8 +5,13 @@
#ifndef MOJO_EDK_SYSTEM_BROKER_HOST_H_
#define MOJO_EDK_SYSTEM_BROKER_HOST_H_
+#include <stdint.h>
+
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "base/process/process_handle.h"
+#include "base/strings/string_piece.h"
+#include "mojo/edk/embedder/platform_handle_vector.h"
#include "mojo/edk/embedder/scoped_platform_handle.h"
#include "mojo/edk/system/channel.h"
@@ -18,14 +23,21 @@ namespace edk {
class BrokerHost : public Channel::Delegate,
public base::MessageLoop::DestructionObserver {
public:
- explicit BrokerHost(ScopedPlatformHandle platform_handle);
+ BrokerHost(base::ProcessHandle client_process, ScopedPlatformHandle handle);
// Send |handle| to the child, to be used to establish a NodeChannel to us.
- void SendChannel(ScopedPlatformHandle handle);
+ bool SendChannel(ScopedPlatformHandle handle);
+
+#if defined(OS_WIN)
+ // Sends a named channel to the child. Like above, but for named pipes.
+ void SendNamedChannel(const base::StringPiece16& pipe_name);
+#endif
private:
~BrokerHost() override;
+ bool PrepareHandlesForClient(PlatformHandleVector* handles);
+
// Channel::Delegate:
void OnChannelMessage(const void* payload,
size_t payload_size,
@@ -35,7 +47,11 @@ class BrokerHost : public Channel::Delegate,
// base::MessageLoop::DestructionObserver:
void WillDestroyCurrentMessageLoop() override;
- void OnBufferRequest(size_t num_bytes);
+ void OnBufferRequest(uint32_t num_bytes);
+
+#if defined(OS_WIN)
+ base::ProcessHandle client_process_;
+#endif
scoped_refptr<Channel> channel_;
diff --git a/mojo/edk/system/broker_messages.h b/mojo/edk/system/broker_messages.h
index a67be15..0f0dd9d 100644
--- a/mojo/edk/system/broker_messages.h
+++ b/mojo/edk/system/broker_messages.h
@@ -23,26 +23,41 @@ struct BrokerMessageHeader {
uint32_t padding;
};
-static_assert(sizeof(BrokerMessageHeader) % kChannelMessageAlignment == 0,
+static_assert(IsAlignedForChannelMessage(sizeof(BrokerMessageHeader)),
"Invalid header size.");
struct BufferRequestData {
uint32_t size;
};
+#if defined(OS_WIN)
+struct InitData {
+ // NOTE: InitData in the payload is followed by string16 data with exactly
+ // |pipe_name_length| wide characters (i.e., |pipe_name_length|*2 bytes.)
+ // This applies to Windows only.
+ uint32_t pipe_name_length;
+};
+#endif
+
#pragma pack(pop)
template <typename T>
-inline Channel::MessagePtr CreateBrokerMessage(BrokerMessageType type,
- size_t num_handles,
- T** out_message_data) {
- const size_t message_size = sizeof(BrokerMessageHeader) + sizeof(T);
+inline Channel::MessagePtr CreateBrokerMessage(
+ BrokerMessageType type,
+ size_t num_handles,
+ size_t extra_data_size,
+ T** out_message_data,
+ void** out_extra_data = nullptr) {
+ const size_t message_size = sizeof(BrokerMessageHeader) +
+ sizeof(**out_message_data) + extra_data_size;
Channel::MessagePtr message(new Channel::Message(message_size, num_handles));
BrokerMessageHeader* header =
reinterpret_cast<BrokerMessageHeader*>(message->mutable_payload());
header->type = type;
header->padding = 0;
*out_message_data = reinterpret_cast<T*>(header + 1);
+ if (out_extra_data)
+ *out_extra_data = *out_message_data + 1;
return message;
}
diff --git a/mojo/edk/system/broker_posix.cc b/mojo/edk/system/broker_posix.cc
index 62b37b3..8742f70 100644
--- a/mojo/edk/system/broker_posix.cc
+++ b/mojo/edk/system/broker_posix.cc
@@ -38,7 +38,7 @@ bool WaitForBrokerMessage(PlatformHandle platform_handle,
PLOG(ERROR) << "Recvmsg error";
error = true;
} else if (static_cast<size_t>(read_result) != message->data_num_bytes()) {
- LOG(ERROR) << "Invalid node channel message. Expected " << message->data_num_bytes() << " got " << read_result;
+ LOG(ERROR) << "Invalid node channel message";
error = true;
} else if (incoming_platform_handles.size() != expected_num_handles) {
LOG(ERROR) << "Received unexpected number of handles";
@@ -94,7 +94,7 @@ scoped_refptr<PlatformSharedBuffer> Broker::GetSharedBuffer(size_t num_bytes) {
BufferRequestData* buffer_request;
Channel::MessagePtr out_message = CreateBrokerMessage(
- BrokerMessageType::BUFFER_REQUEST, 0, &buffer_request);
+ BrokerMessageType::BUFFER_REQUEST, 0, 0, &buffer_request);
buffer_request->size = num_bytes;
ssize_t write_result = PlatformChannelWrite(
sync_channel_.get(), out_message->data(), out_message->data_num_bytes());
diff --git a/mojo/edk/system/channel.cc b/mojo/edk/system/channel.cc
index 56509b5..8a44d36 100644
--- a/mojo/edk/system/channel.cc
+++ b/mojo/edk/system/channel.cc
@@ -4,6 +4,7 @@
#include "mojo/edk/system/channel.h"
+#include <stddef.h>
#include <string.h>
#include <algorithm>
@@ -26,27 +27,47 @@ namespace edk {
namespace {
-static_assert(sizeof(Channel::Message::Header) % kChannelMessageAlignment == 0,
- "Invalid Header size.");
+static_assert(
+ IsAlignedForChannelMessage(sizeof(Channel::Message::LegacyHeader)),
+ "Invalid LegacyHeader size.");
-#if defined(MOJO_EDK_LEGACY_PROTOCOL)
-static_assert(sizeof(Channel::Message::Header) == 8,
- "Header must be 8 bytes on ChromeOS and Android");
-#endif
+static_assert(IsAlignedForChannelMessage(sizeof(Channel::Message::Header)),
+ "Invalid Header size.");
+
+static_assert(sizeof(Channel::Message::LegacyHeader) == 8,
+ "LegacyHeader must be 8 bytes on ChromeOS and Android");
+
+static_assert(offsetof(Channel::Message::LegacyHeader, num_bytes) ==
+ offsetof(Channel::Message::Header, num_bytes),
+ "num_bytes should be at the same offset in both Header structs.");
+static_assert(offsetof(Channel::Message::LegacyHeader, message_type) ==
+ offsetof(Channel::Message::Header, message_type),
+ "message_type should be at the same offset in both Header "
+ "structs.");
} // namespace
const size_t kReadBufferSize = 4096;
-const size_t kMaxUnusedReadBufferCapacity = 64 * 1024;
+const size_t kMaxUnusedReadBufferCapacity = 4096;
const size_t kMaxChannelMessageSize = 256 * 1024 * 1024;
const size_t kMaxAttachedHandles = 128;
+Channel::Message::Message(size_t payload_size, size_t max_handles)
+#if defined(MOJO_EDK_LEGACY_PROTOCOL)
+ : Message(payload_size, max_handles, MessageType::NORMAL_LEGACY) {
+}
+#else
+ : Message(payload_size, max_handles, MessageType::NORMAL) {
+}
+#endif
+
Channel::Message::Message(size_t payload_size,
size_t max_handles,
- Header::MessageType message_type)
+ MessageType message_type)
: max_handles_(max_handles) {
DCHECK_LE(max_handles_, kMaxAttachedHandles);
+ const bool is_legacy_message = (message_type == MessageType::NORMAL_LEGACY);
size_t extra_header_size = 0;
#if defined(OS_WIN)
// On Windows we serialize HANDLEs into the extra header space.
@@ -62,16 +83,16 @@ Channel::Message::Message(size_t payload_size,
}
#endif
// Pad extra header data to be aliged to |kChannelMessageAlignment| bytes.
- if (extra_header_size % kChannelMessageAlignment) {
+ if (!IsAlignedForChannelMessage(extra_header_size)) {
extra_header_size += kChannelMessageAlignment -
(extra_header_size % kChannelMessageAlignment);
}
- DCHECK_EQ(0u, extra_header_size % kChannelMessageAlignment);
-#if defined(MOJO_EDK_LEGACY_PROTOCOL)
- DCHECK_EQ(0u, extra_header_size);
-#endif
+ DCHECK(IsAlignedForChannelMessage(extra_header_size));
+ const size_t header_size =
+ is_legacy_message ? sizeof(LegacyHeader) : sizeof(Header);
+ DCHECK(extra_header_size == 0 || !is_legacy_message);
- size_ = sizeof(Header) + extra_header_size + payload_size;
+ size_ = header_size + extra_header_size + payload_size;
data_ = static_cast<char*>(base::AlignedAlloc(size_,
kChannelMessageAlignment));
// Only zero out the header and not the payload. Since the payload is going to
@@ -79,21 +100,21 @@ Channel::Message::Message(size_t payload_size,
// performance issue when dealing with large messages. Any sanitizer errors
// complaining about an uninitialized read in the payload area should be
// treated as an error and fixed.
- memset(data_, 0, sizeof(Header) + extra_header_size);
- header_ = reinterpret_cast<Header*>(data_);
+ memset(data_, 0, header_size + extra_header_size);
DCHECK_LE(size_, std::numeric_limits<uint32_t>::max());
- header_->num_bytes = static_cast<uint32_t>(size_);
+ legacy_header()->num_bytes = static_cast<uint32_t>(size_);
- DCHECK_LE(sizeof(Header) + extra_header_size,
+ DCHECK_LE(header_size + extra_header_size,
std::numeric_limits<uint16_t>::max());
- header_->message_type = message_type;
-#if defined(MOJO_EDK_LEGACY_PROTOCOL)
- header_->num_handles = static_cast<uint16_t>(max_handles);
-#else
- header_->num_header_bytes =
- static_cast<uint16_t>(sizeof(Header) + extra_header_size);
-#endif
+ legacy_header()->message_type = message_type;
+
+ if (is_legacy_message) {
+ legacy_header()->num_handles = static_cast<uint16_t>(max_handles);
+ } else {
+ header()->num_header_bytes =
+ static_cast<uint16_t>(header_size + extra_header_size);
+ }
if (max_handles_ > 0) {
#if defined(OS_WIN)
@@ -121,79 +142,93 @@ Channel::Message::~Message() {
// static
Channel::MessagePtr Channel::Message::Deserialize(const void* data,
size_t data_num_bytes) {
- if (data_num_bytes < sizeof(Header))
+ if (data_num_bytes < sizeof(LegacyHeader))
return nullptr;
- const Header* header = reinterpret_cast<const Header*>(data);
- if (header->num_bytes != data_num_bytes) {
- DLOG(ERROR) << "Decoding invalid message: " << header->num_bytes
+ const LegacyHeader* legacy_header =
+ reinterpret_cast<const LegacyHeader*>(data);
+ if (legacy_header->num_bytes != data_num_bytes) {
+ DLOG(ERROR) << "Decoding invalid message: " << legacy_header->num_bytes
<< " != " << data_num_bytes;
return nullptr;
}
-#if defined(MOJO_EDK_LEGACY_PROTOCOL)
- size_t payload_size = data_num_bytes - sizeof(Header);
- const char* payload = static_cast<const char*>(data) + sizeof(Header);
-#else
- if (header->num_bytes < header->num_header_bytes ||
- header->num_header_bytes < sizeof(Header)) {
- DLOG(ERROR) << "Decoding invalid message: " << header->num_bytes << " < "
- << header->num_header_bytes;
- return nullptr;
+ const Header* header = nullptr;
+ if (legacy_header->message_type == MessageType::NORMAL)
+ header = reinterpret_cast<const Header*>(data);
+
+ uint32_t extra_header_size = 0;
+ size_t payload_size = 0;
+ const char* payload = nullptr;
+ if (!header) {
+ payload_size = data_num_bytes - sizeof(LegacyHeader);
+ payload = static_cast<const char*>(data) + sizeof(LegacyHeader);
+ } else {
+ if (header->num_bytes < header->num_header_bytes ||
+ header->num_header_bytes < sizeof(Header)) {
+ DLOG(ERROR) << "Decoding invalid message: " << header->num_bytes << " < "
+ << header->num_header_bytes;
+ return nullptr;
+ }
+ extra_header_size = header->num_header_bytes - sizeof(Header);
+ payload_size = data_num_bytes - header->num_header_bytes;
+ payload = static_cast<const char*>(data) + header->num_header_bytes;
}
- uint32_t extra_header_size = header->num_header_bytes - sizeof(Header);
- size_t payload_size = data_num_bytes - header->num_header_bytes;
- const char* payload =
- static_cast<const char*>(data) + header->num_header_bytes;
-#endif // defined(MOJO_EDK_LEGACY_PROTOCOL)
-
#if defined(OS_WIN)
uint32_t max_handles = extra_header_size / sizeof(HandleEntry);
#elif defined(OS_MACOSX) && !defined(OS_IOS)
- if (extra_header_size < sizeof(MachPortsExtraHeader)) {
+ if (extra_header_size > 0 &&
+ extra_header_size < sizeof(MachPortsExtraHeader)) {
DLOG(ERROR) << "Decoding invalid message: " << extra_header_size << " < "
<< sizeof(MachPortsExtraHeader);
return nullptr;
}
- uint32_t max_handles = (extra_header_size - sizeof(MachPortsExtraHeader)) /
- sizeof(MachPortsEntry);
+ uint32_t max_handles =
+ extra_header_size == 0
+ ? 0
+ : (extra_header_size - sizeof(MachPortsExtraHeader)) /
+ sizeof(MachPortsEntry);
#else
const uint32_t max_handles = 0;
#endif // defined(OS_WIN)
- if (header->num_handles > max_handles || max_handles > kMaxAttachedHandles) {
- DLOG(ERROR) << "Decoding invalid message:" << header->num_handles
- << " > " << max_handles;
+ const uint16_t num_handles =
+ header ? header->num_handles : legacy_header->num_handles;
+ if (num_handles > max_handles || max_handles > kMaxAttachedHandles) {
+ DLOG(ERROR) << "Decoding invalid message: " << num_handles << " > "
+ << max_handles;
return nullptr;
}
- MessagePtr message(new Message(payload_size, max_handles));
+ MessagePtr message(
+ new Message(payload_size, max_handles, legacy_header->message_type));
DCHECK_EQ(message->data_num_bytes(), data_num_bytes);
// Copy all payload bytes.
if (payload_size)
memcpy(message->mutable_payload(), payload, payload_size);
-#if !defined(MOJO_EDK_LEGACY_PROTOCOL)
- DCHECK_EQ(message->extra_header_size(), extra_header_size);
- DCHECK_EQ(message->header_->num_header_bytes, header->num_header_bytes);
+ if (header) {
+ DCHECK_EQ(message->extra_header_size(), extra_header_size);
+ DCHECK_EQ(message->header()->num_header_bytes, header->num_header_bytes);
- if (message->extra_header_size()) {
- // Copy extra header bytes.
- memcpy(message->mutable_extra_header(),
- static_cast<const char*>(data) + sizeof(Header),
- message->extra_header_size());
+ if (message->extra_header_size()) {
+ // Copy extra header bytes.
+ memcpy(message->mutable_extra_header(),
+ static_cast<const char*>(data) + sizeof(Header),
+ message->extra_header_size());
+ }
+ message->header()->num_handles = header->num_handles;
+ } else {
+ message->legacy_header()->num_handles = legacy_header->num_handles;
}
-#endif
- message->header_->num_handles = header->num_handles;
#if defined(OS_WIN)
- ScopedPlatformHandleVectorPtr handles(
- new PlatformHandleVector(header->num_handles));
- for (size_t i = 0; i < header->num_handles; i++) {
- (*handles)[i].handle = reinterpret_cast<HANDLE>(
- static_cast<uintptr_t>(message->handles_[i].handle));
+ ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector(num_handles));
+ for (size_t i = 0; i < num_handles; i++) {
+ (*handles)[i].handle =
+ base::win::Uint32ToHandle(message->handles_[i].handle);
}
message->SetHandles(std::move(handles));
#endif
@@ -201,12 +236,46 @@ Channel::MessagePtr Channel::Message::Deserialize(const void* data,
return message;
}
+const void* Channel::Message::extra_header() const {
+ DCHECK(!is_legacy_message());
+ return data_ + sizeof(Header);
+}
+
+void* Channel::Message::mutable_extra_header() {
+ DCHECK(!is_legacy_message());
+ return data_ + sizeof(Header);
+}
+
+size_t Channel::Message::extra_header_size() const {
+ return header()->num_header_bytes - sizeof(Header);
+}
+
+void* Channel::Message::mutable_payload() {
+ if (is_legacy_message())
+ return static_cast<void*>(legacy_header() + 1);
+ return data_ + header()->num_header_bytes;
+}
+
+const void* Channel::Message::payload() const {
+ if (is_legacy_message())
+ return static_cast<const void*>(legacy_header() + 1);
+ return data_ + header()->num_header_bytes;
+}
+
size_t Channel::Message::payload_size() const {
-#if defined(MOJO_EDK_LEGACY_PROTOCOL)
- return header_->num_bytes - sizeof(Header);
-#else
- return size_ - header_->num_header_bytes;
-#endif
+ if (is_legacy_message())
+ return legacy_header()->num_bytes - sizeof(LegacyHeader);
+ return size_ - header()->num_header_bytes;
+}
+
+size_t Channel::Message::num_handles() const {
+ return is_legacy_message() ? legacy_header()->num_handles
+ : header()->num_handles;
+}
+
+bool Channel::Message::has_handles() const {
+ return (is_legacy_message() ? legacy_header()->num_handles
+ : header()->num_handles) > 0;
}
#if defined(OS_MACOSX) && !defined(OS_IOS)
@@ -224,31 +293,44 @@ bool Channel::Message::has_mach_ports() const {
}
#endif
+bool Channel::Message::is_legacy_message() const {
+ return legacy_header()->message_type == MessageType::NORMAL_LEGACY;
+}
+
+Channel::Message::LegacyHeader* Channel::Message::legacy_header() const {
+ return reinterpret_cast<LegacyHeader*>(data_);
+}
+
+Channel::Message::Header* Channel::Message::header() const {
+ DCHECK(!is_legacy_message());
+ return reinterpret_cast<Header*>(data_);
+}
+
void Channel::Message::SetHandles(ScopedPlatformHandleVectorPtr new_handles) {
-#if defined(MOJO_EDK_LEGACY_PROTOCOL)
- // Old semantics for ChromeOS and Android
- if (header_->num_handles == 0) {
- CHECK(!new_handles || new_handles->size() == 0);
+ if (is_legacy_message()) {
+ // Old semantics for ChromeOS and Android
+ if (legacy_header()->num_handles == 0) {
+ CHECK(!new_handles || new_handles->size() == 0);
+ return;
+ }
+ CHECK(new_handles && new_handles->size() == legacy_header()->num_handles);
+ std::swap(handle_vector_, new_handles);
return;
}
- CHECK(new_handles && new_handles->size() == header_->num_handles);
- std::swap(handle_vector_, new_handles);
-#else
if (max_handles_ == 0) {
CHECK(!new_handles || new_handles->size() == 0);
return;
}
CHECK(new_handles && new_handles->size() <= max_handles_);
- header_->num_handles = static_cast<uint16_t>(new_handles->size());
+ header()->num_handles = static_cast<uint16_t>(new_handles->size());
std::swap(handle_vector_, new_handles);
#if defined(OS_WIN)
memset(handles_, 0, extra_header_size());
for (size_t i = 0; i < handle_vector_->size(); i++)
handles_[i].handle = base::win::HandleToUint32((*handle_vector_)[i].handle);
#endif // defined(OS_WIN)
-#endif // defined(MOJO_EDK_LEGACY_PROTOCOL)
#if defined(OS_MACOSX) && !defined(OS_IOS)
size_t mach_port_index = 0;
@@ -280,12 +362,12 @@ ScopedPlatformHandleVectorPtr Channel::Message::TakeHandles() {
}
mach_ports_header_->num_ports = 0;
}
- header_->num_handles = 0;
- return std::move(handle_vector_);
-#else
- header_->num_handles = 0;
- return std::move(handle_vector_);
#endif
+ if (is_legacy_message())
+ legacy_header()->num_handles = 0;
+ else
+ header()->num_handles = 0;
+ return std::move(handle_vector_);
}
ScopedPlatformHandleVectorPtr Channel::Message::TakeHandlesForTransport() {
@@ -491,58 +573,71 @@ char* Channel::GetReadBuffer(size_t *buffer_capacity) {
bool Channel::OnReadComplete(size_t bytes_read, size_t *next_read_size_hint) {
bool did_dispatch_message = false;
read_buffer_->Claim(bytes_read);
- while (read_buffer_->num_occupied_bytes() >= sizeof(Message::Header)) {
+ while (read_buffer_->num_occupied_bytes() >= sizeof(Message::LegacyHeader)) {
// Ensure the occupied data is properly aligned. If it isn't, a SIGBUS could
// happen on architectures that don't allow misaligned words access (i.e.
// anything other than x86). Only re-align when necessary to avoid copies.
- if (reinterpret_cast<uintptr_t>(read_buffer_->occupied_bytes()) %
- kChannelMessageAlignment != 0)
+ if (!IsAlignedForChannelMessage(
+ reinterpret_cast<uintptr_t>(read_buffer_->occupied_bytes()))) {
read_buffer_->Realign();
+ }
+
+ // We have at least enough data available for a LegacyHeader.
+ const Message::LegacyHeader* legacy_header =
+ reinterpret_cast<const Message::LegacyHeader*>(
+ read_buffer_->occupied_bytes());
- // We have at least enough data available for a MessageHeader.
- const Message::Header* header = reinterpret_cast<const Message::Header*>(
- read_buffer_->occupied_bytes());
- if (header->num_bytes < sizeof(Message::Header) ||
- header->num_bytes > kMaxChannelMessageSize) {
- LOG(ERROR) << "Invalid message size: " << header->num_bytes;
+ if (legacy_header->num_bytes < sizeof(Message::LegacyHeader) ||
+ legacy_header->num_bytes > kMaxChannelMessageSize) {
+ LOG(ERROR) << "Invalid message size: " << legacy_header->num_bytes;
return false;
}
- if (read_buffer_->num_occupied_bytes() < header->num_bytes) {
+ if (read_buffer_->num_occupied_bytes() < legacy_header->num_bytes) {
// Not enough data available to read the full message. Hint to the
// implementation that it should try reading the full size of the message.
*next_read_size_hint =
- header->num_bytes - read_buffer_->num_occupied_bytes();
+ legacy_header->num_bytes - read_buffer_->num_occupied_bytes();
return true;
}
-#if defined(MOJO_EDK_LEGACY_PROTOCOL)
+ const Message::Header* header = nullptr;
+ if (legacy_header->message_type != Message::MessageType::NORMAL_LEGACY) {
+ header = reinterpret_cast<const Message::Header*>(legacy_header);
+ }
+
size_t extra_header_size = 0;
const void* extra_header = nullptr;
- size_t payload_size = header->num_bytes - sizeof(Message::Header);
- void* payload = payload_size ? const_cast<Message::Header*>(&header[1])
- : nullptr;
-#else
- if (header->num_header_bytes < sizeof(Message::Header) ||
- header->num_header_bytes > header->num_bytes) {
- LOG(ERROR) << "Invalid message header size: " << header->num_header_bytes;
- return false;
+ size_t payload_size = 0;
+ void* payload = nullptr;
+ if (header) {
+ if (header->num_header_bytes < sizeof(Message::Header) ||
+ header->num_header_bytes > header->num_bytes) {
+ LOG(ERROR) << "Invalid message header size: "
+ << header->num_header_bytes;
+ return false;
+ }
+ extra_header_size = header->num_header_bytes - sizeof(Message::Header);
+ extra_header = extra_header_size ? header + 1 : nullptr;
+ payload_size = header->num_bytes - header->num_header_bytes;
+ payload = payload_size
+ ? reinterpret_cast<Message::Header*>(
+ const_cast<char*>(read_buffer_->occupied_bytes()) +
+ header->num_header_bytes)
+ : nullptr;
+ } else {
+ payload_size = legacy_header->num_bytes - sizeof(Message::LegacyHeader);
+ payload = payload_size
+ ? const_cast<Message::LegacyHeader*>(&legacy_header[1])
+ : nullptr;
}
- size_t extra_header_size =
- header->num_header_bytes - sizeof(Message::Header);
- const void* extra_header = extra_header_size ? header + 1 : nullptr;
- size_t payload_size = header->num_bytes - header->num_header_bytes;
- void* payload =
- payload_size ? reinterpret_cast<Message::Header*>(
- const_cast<char*>(read_buffer_->occupied_bytes()) +
- header->num_header_bytes)
- : nullptr;
-#endif // defined(MOJO_EDK_LEGACY_PROTOCOL)
+ const uint16_t num_handles =
+ header ? header->num_handles : legacy_header->num_handles;
ScopedPlatformHandleVectorPtr handles;
- if (header->num_handles > 0) {
- if (!GetReadPlatformHandles(header->num_handles, extra_header,
- extra_header_size, &handles)) {
+ if (num_handles > 0) {
+ if (!GetReadPlatformHandles(num_handles, extra_header, extra_header_size,
+ &handles)) {
return false;
}
@@ -553,8 +648,9 @@ bool Channel::OnReadComplete(size_t bytes_read, size_t *next_read_size_hint) {
}
// We've got a complete message! Dispatch it and try another.
- if (header->message_type != Message::Header::MessageType::NORMAL) {
- if (!OnControlMessage(header->message_type, payload, payload_size,
+ if (legacy_header->message_type != Message::MessageType::NORMAL_LEGACY &&
+ legacy_header->message_type != Message::MessageType::NORMAL) {
+ if (!OnControlMessage(legacy_header->message_type, payload, payload_size,
std::move(handles))) {
return false;
}
@@ -564,7 +660,7 @@ bool Channel::OnReadComplete(size_t bytes_read, size_t *next_read_size_hint) {
did_dispatch_message = true;
}
- read_buffer_->Discard(header->num_bytes);
+ read_buffer_->Discard(legacy_header->num_bytes);
}
*next_read_size_hint = did_dispatch_message ? 0 : kReadBufferSize;
@@ -576,7 +672,7 @@ void Channel::OnError() {
delegate_->OnChannelError();
}
-bool Channel::OnControlMessage(Message::Header::MessageType message_type,
+bool Channel::OnControlMessage(Message::MessageType message_type,
const void* payload,
size_t payload_size,
ScopedPlatformHandleVectorPtr handles) {
diff --git a/mojo/edk/system/channel.h b/mojo/edk/system/channel.h
index aa6d70c..33a510c 100644
--- a/mojo/edk/system/channel.h
+++ b/mojo/edk/system/channel.h
@@ -10,6 +10,7 @@
#include "base/memory/ref_counted.h"
#include "base/process/process_handle.h"
#include "base/task_runner.h"
+#include "mojo/edk/embedder/connection_params.h"
#include "mojo/edk/embedder/platform_handle_vector.h"
#include "mojo/edk/embedder/scoped_platform_handle.h"
@@ -18,53 +19,70 @@ namespace edk {
const size_t kChannelMessageAlignment = 8;
+constexpr bool IsAlignedForChannelMessage(size_t n) {
+ return n % kChannelMessageAlignment == 0;
+}
+
// Channel provides a thread-safe interface to read and write arbitrary
// delimited messages over an underlying I/O channel, optionally transferring
// one or more platform handles in the process.
-class Channel : public base::RefCountedThreadSafe<Channel> {
+class MOJO_SYSTEM_IMPL_EXPORT Channel
+ : public base::RefCountedThreadSafe<Channel> {
public:
struct Message;
using MessagePtr = std::unique_ptr<Message>;
// A message to be written to a channel.
- struct Message {
-#pragma pack(push, 1)
- struct Header {
- enum class MessageType : uint16_t {
- // A normal message.
- NORMAL = 0,
+ struct MOJO_SYSTEM_IMPL_EXPORT Message {
+ enum class MessageType : uint16_t {
+ // An old format normal message, that uses the LegacyHeader.
+ // Only used on Android and ChromeOS.
+ // TODO(jcivelli): remove legacy support when Arc++ has updated to Mojo
+ // with normal versioned messages. crbug.com/695645
+ NORMAL_LEGACY = 0,
#if defined(OS_MACOSX)
- // A control message containing handles to echo back.
- HANDLES_SENT,
- // A control message containing handles that can now be closed.
- HANDLES_SENT_ACK,
+ // A control message containing handles to echo back.
+ HANDLES_SENT,
+ // A control message containing handles that can now be closed.
+ HANDLES_SENT_ACK,
#endif
- };
+ // A normal message that uses Header and can contain extra header values.
+ NORMAL,
+ };
+#pragma pack(push, 1)
+ // Old message wire format for ChromeOS and Android, used by NORMAL_LEGACY
+ // messages.
+ struct LegacyHeader {
// Message size in bytes, including the header.
uint32_t num_bytes;
-#if defined(MOJO_EDK_LEGACY_PROTOCOL)
- // Old message wire format for ChromeOS and Android.
// Number of attached handles.
uint16_t num_handles;
MessageType message_type;
-#else
+ };
+
+ // Header used by NORMAL messages.
+ // To preserve backward compatibility with LegacyHeader, the num_bytes and
+ // message_type field must be at the same offset as in LegacyHeader.
+ struct Header {
+ // Message size in bytes, including the header.
+ uint32_t num_bytes;
+
// Total size of header, including extra header data (i.e. HANDLEs on
// windows).
uint16_t num_header_bytes;
+ MessageType message_type;
+
// Number of attached handles. May be less than the reserved handle
// storage size in this message on platforms that serialise handles as
// data (i.e. HANDLEs on Windows, Mach ports on OSX).
uint16_t num_handles;
- MessageType message_type;
-
char padding[6];
-#endif // defined(MOJO_EDK_LEGACY_PROTOCOL)
};
#if defined(OS_MACOSX) && !defined(OS_IOS)
@@ -85,7 +103,7 @@ class Channel : public base::RefCountedThreadSafe<Channel> {
// Actual number of Mach ports encoded in the extra header.
uint16_t num_ports;
- // Array of encoded Mach ports. If |num_ports| > 0, |entires[0]| through
+ // Array of encoded Mach ports. If |num_ports| > 0, |entries[0]| through
// to |entries[num_ports-1]| inclusive are valid.
MachPortsEntry entries[0];
};
@@ -104,10 +122,8 @@ class Channel : public base::RefCountedThreadSafe<Channel> {
// Allocates and owns a buffer for message data with enough capacity for
// |payload_size| bytes plus a header, plus |max_handles| platform handles.
- Message(size_t payload_size,
- size_t max_handles,
- Header::MessageType message_type = Header::MessageType::NORMAL);
-
+ Message(size_t payload_size, size_t max_handles);
+ Message(size_t payload_size, size_t max_handles, MessageType message_type);
~Message();
// Constructs a Message from serialized message data.
@@ -116,30 +132,24 @@ class Channel : public base::RefCountedThreadSafe<Channel> {
const void* data() const { return data_; }
size_t data_num_bytes() const { return size_; }
-#if defined(MOJO_EDK_LEGACY_PROTOCOL)
- void* mutable_payload() { return static_cast<void*>(header_ + 1); }
- const void* payload() const {
- return static_cast<const void*>(header_ + 1);
- }
- size_t payload_size() const;
-#else
- const void* extra_header() const { return data_ + sizeof(Header); }
- void* mutable_extra_header() { return data_ + sizeof(Header); }
- size_t extra_header_size() const {
- return header_->num_header_bytes - sizeof(Header);
- }
-
- void* mutable_payload() { return data_ + header_->num_header_bytes; }
- const void* payload() const { return data_ + header_->num_header_bytes; }
+ const void* extra_header() const;
+ void* mutable_extra_header();
+ size_t extra_header_size() const;
+
+ void* mutable_payload();
+ const void* payload() const;
size_t payload_size() const;
-#endif // defined(MOJO_EDK_LEGACY_PROTOCOL)
- size_t num_handles() const { return header_->num_handles; }
- bool has_handles() const { return header_->num_handles > 0; }
+ size_t num_handles() const;
+ bool has_handles() const;
#if defined(OS_MACOSX) && !defined(OS_IOS)
bool has_mach_ports() const;
#endif
+ bool is_legacy_message() const;
+ LegacyHeader* legacy_header() const;
+ Header* header() const;
+
// Note: SetHandles() and TakeHandles() invalidate any previous value of
// handles().
void SetHandles(ScopedPlatformHandleVectorPtr new_handles);
@@ -161,11 +171,12 @@ class Channel : public base::RefCountedThreadSafe<Channel> {
PlatformHandleVector* handles);
#endif
+ void SetVersionForTest(uint16_t version_number);
+
private:
- size_t size_;
- size_t max_handles_;
- char* data_;
- Header* header_;
+ size_t size_ = 0;
+ size_t max_handles_ = 0;
+ char* data_ = nullptr;
ScopedPlatformHandleVectorPtr handle_vector_;
@@ -203,7 +214,7 @@ class Channel : public base::RefCountedThreadSafe<Channel> {
// |delegate| is destroyed.
static scoped_refptr<Channel> Create(
Delegate* delegate,
- ScopedPlatformHandle platform_handle,
+ ConnectionParams connection_params,
scoped_refptr<base::TaskRunner> io_task_runner);
// Request that the channel be shut down. This should always be called before
@@ -270,7 +281,7 @@ class Channel : public base::RefCountedThreadSafe<Channel> {
// Handles a received control message. Returns |true| if the message is
// accepted, or |false| otherwise.
- virtual bool OnControlMessage(Message::Header::MessageType message_type,
+ virtual bool OnControlMessage(Message::MessageType message_type,
const void* payload,
size_t payload_size,
ScopedPlatformHandleVectorPtr handles);
diff --git a/mojo/edk/system/channel_posix.cc b/mojo/edk/system/channel_posix.cc
index 16a9304..8b4ca7f 100644
--- a/mojo/edk/system/channel_posix.cc
+++ b/mojo/edk/system/channel_posix.cc
@@ -88,17 +88,18 @@ class ChannelPosix : public Channel,
public base::MessageLoopForIO::Watcher {
public:
ChannelPosix(Delegate* delegate,
- ScopedPlatformHandle handle,
+ ConnectionParams connection_params,
scoped_refptr<base::TaskRunner> io_task_runner)
: Channel(delegate),
self_(this),
- handle_(std::move(handle)),
+ handle_(connection_params.TakeChannelHandle()),
io_task_runner_(io_task_runner)
#if defined(OS_MACOSX)
,
handles_to_close_(new PlatformHandleVector)
#endif
{
+ CHECK(handle_.is_valid());
}
void Start() override {
@@ -210,12 +211,22 @@ class ChannelPosix : public Channel,
void StartOnIOThread() {
DCHECK(!read_watcher_);
DCHECK(!write_watcher_);
- read_watcher_.reset(new base::MessageLoopForIO::FileDescriptorWatcher);
- write_watcher_.reset(new base::MessageLoopForIO::FileDescriptorWatcher);
- base::MessageLoopForIO::current()->WatchFileDescriptor(
- handle_.get().handle, true /* persistent */,
- base::MessageLoopForIO::WATCH_READ, read_watcher_.get(), this);
+ read_watcher_.reset(
+ new base::MessageLoopForIO::FileDescriptorWatcher(FROM_HERE));
base::MessageLoop::current()->AddDestructionObserver(this);
+ if (handle_.get().needs_connection) {
+ base::MessageLoopForIO::current()->WatchFileDescriptor(
+ handle_.get().handle, false /* persistent */,
+ base::MessageLoopForIO::WATCH_READ, read_watcher_.get(), this);
+ } else {
+ write_watcher_.reset(
+ new base::MessageLoopForIO::FileDescriptorWatcher(FROM_HERE));
+ base::MessageLoopForIO::current()->WatchFileDescriptor(
+ handle_.get().handle, true /* persistent */,
+ base::MessageLoopForIO::WATCH_READ, read_watcher_.get(), this);
+ base::AutoLock lock(write_lock_);
+ FlushOutgoingMessagesNoLock();
+ }
}
void WaitForWriteOnIOThread() {
@@ -265,6 +276,24 @@ class ChannelPosix : public Channel,
// base::MessageLoopForIO::Watcher:
void OnFileCanReadWithoutBlocking(int fd) override {
CHECK_EQ(fd, handle_.get().handle);
+ if (handle_.get().needs_connection) {
+#if !defined(OS_NACL)
+ read_watcher_.reset();
+ base::MessageLoop::current()->RemoveDestructionObserver(this);
+
+ ScopedPlatformHandle accept_fd;
+ ServerAcceptConnection(handle_.get(), &accept_fd);
+ if (!accept_fd.is_valid()) {
+ OnError();
+ return;
+ }
+ handle_ = std::move(accept_fd);
+ StartOnIOThread();
+#else
+ NOTREACHED();
+#endif
+ return;
+ }
bool read_error = false;
size_t next_read_size = 0;
@@ -321,6 +350,10 @@ class ChannelPosix : public Channel,
// cannot be written, it's queued and a wait is initiated to write the message
// ASAP on the I/O thread.
bool WriteNoLock(MessageView message_view) {
+ if (handle_.get().needs_connection) {
+ outgoing_messages_.emplace_front(std::move(message_view));
+ return true;
+ }
size_t bytes_written = 0;
do {
message_view.advance_data_offset(bytes_written);
@@ -355,7 +388,7 @@ class ChannelPosix : public Channel,
}
MessagePtr fds_message(
new Channel::Message(sizeof(fds[0]) * fds.size(), 0,
- Message::Header::MessageType::HANDLES_SENT));
+ Message::MessageType::HANDLES_SENT));
memcpy(fds_message->mutable_payload(), fds.data(),
sizeof(fds[0]) * fds.size());
outgoing_messages_.emplace_back(std::move(fds_message), 0);
@@ -370,8 +403,26 @@ class ChannelPosix : public Channel,
}
if (result < 0) {
- if (errno != EAGAIN && errno != EWOULDBLOCK)
+ if (errno != EAGAIN && errno != EWOULDBLOCK
+#if defined(OS_MACOSX)
+ // On OS X if sendmsg() is trying to send fds between processes and
+ // there isn't enough room in the output buffer to send the fd
+ // structure over atomically then EMSGSIZE is returned.
+ //
+ // EMSGSIZE presents a problem since the system APIs can only call
+ // us when there's room in the socket buffer and not when there is
+ // "enough" room.
+ //
+ // The current behavior is to return to the event loop when EMSGSIZE
+ // is received and hopefull service another FD. This is however
+ // still technically a busy wait since the event loop will call us
+ // right back until the receiver has read enough data to allow
+ // passing the FD over atomically.
+ && errno != EMSGSIZE
+#endif
+ ) {
return false;
+ }
message_view.SetHandles(std::move(handles));
outgoing_messages_.emplace_front(std::move(message_view));
WaitForWriteOnIOThreadNoLock();
@@ -412,22 +463,22 @@ class ChannelPosix : public Channel,
}
#if defined(OS_MACOSX)
- bool OnControlMessage(Message::Header::MessageType message_type,
+ bool OnControlMessage(Message::MessageType message_type,
const void* payload,
size_t payload_size,
ScopedPlatformHandleVectorPtr handles) override {
switch (message_type) {
- case Message::Header::MessageType::HANDLES_SENT: {
+ case Message::MessageType::HANDLES_SENT: {
if (payload_size == 0)
break;
MessagePtr message(new Channel::Message(
- payload_size, 0, Message::Header::MessageType::HANDLES_SENT_ACK));
+ payload_size, 0, Message::MessageType::HANDLES_SENT_ACK));
memcpy(message->mutable_payload(), payload, payload_size);
Write(std::move(message));
return true;
}
- case Message::Header::MessageType::HANDLES_SENT_ACK: {
+ case Message::MessageType::HANDLES_SENT_ACK: {
size_t num_fds = payload_size / sizeof(int);
if (num_fds == 0 || payload_size % sizeof(int) != 0)
break;
@@ -511,9 +562,10 @@ class ChannelPosix : public Channel,
// static
scoped_refptr<Channel> Channel::Create(
Delegate* delegate,
- ScopedPlatformHandle platform_handle,
+ ConnectionParams connection_params,
scoped_refptr<base::TaskRunner> io_task_runner) {
- return new ChannelPosix(delegate, std::move(platform_handle), io_task_runner);
+ return new ChannelPosix(delegate, std::move(connection_params),
+ io_task_runner);
}
} // namespace edk
diff --git a/mojo/edk/system/channel_win.cc b/mojo/edk/system/channel_win.cc
index c989344..c15df16 100644
--- a/mojo/edk/system/channel_win.cc
+++ b/mojo/edk/system/channel_win.cc
@@ -19,6 +19,7 @@
#include "base/message_loop/message_loop.h"
#include "base/synchronization/lock.h"
#include "base/task_runner.h"
+#include "base/win/win_util.h"
#include "mojo/edk/embedder/platform_handle_vector.h"
namespace mojo {
@@ -137,8 +138,8 @@ class ChannelWin : public Channel,
const HandleEntry* extra_header_handles =
reinterpret_cast<const HandleEntry*>(extra_header);
for (size_t i = 0; i < num_handles; i++) {
- (*handles)->at(i).handle = reinterpret_cast<HANDLE>(
- static_cast<uintptr_t>(extra_header_handles[i].handle));
+ (*handles)->at(i).handle =
+ base::win::Uint32ToHandle(extra_header_handles[i].handle);
}
return true;
}
@@ -349,9 +350,10 @@ class ChannelWin : public Channel,
// static
scoped_refptr<Channel> Channel::Create(
Delegate* delegate,
- ScopedPlatformHandle platform_handle,
+ ConnectionParams connection_params,
scoped_refptr<base::TaskRunner> io_task_runner) {
- return new ChannelWin(delegate, std::move(platform_handle), io_task_runner);
+ return new ChannelWin(delegate, connection_params.TakeChannelHandle(),
+ io_task_runner);
}
} // namespace edk
diff --git a/mojo/edk/system/core.cc b/mojo/edk/system/core.cc
index ada3753..1e0bf4e 100644
--- a/mojo/edk/system/core.cc
+++ b/mojo/edk/system/core.cc
@@ -44,8 +44,8 @@ namespace {
// This is an unnecessarily large limit that is relatively easy to enforce.
const uint32_t kMaxHandlesPerMessage = 1024 * 1024;
-// TODO: Maybe we could negotiate a debugging pipe ID for cross-process pipes
-// too; for now we just use a constant. This only affects bootstrap pipes.
+// TODO(rockot): Maybe we could negotiate a debugging pipe ID for cross-process
+// pipes too; for now we just use a constant. This only affects bootstrap pipes.
const uint64_t kUnknownPipeIdForDebug = 0x7f7f7f7f7f7f7f7fUL;
void CallWatchCallback(MojoWatchCallback callback,
@@ -166,13 +166,17 @@ scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) {
return handles_.GetDispatcher(handle);
}
+void Core::SetDefaultProcessErrorCallback(
+ const ProcessErrorCallback& callback) {
+ default_process_error_callback_ = callback;
+}
+
void Core::AddChild(base::ProcessHandle process_handle,
- ScopedPlatformHandle platform_handle,
+ ConnectionParams connection_params,
const std::string& child_token,
const ProcessErrorCallback& process_error_callback) {
GetNodeController()->ConnectToChild(process_handle,
- std::move(platform_handle),
- child_token,
+ std::move(connection_params), child_token,
process_error_callback);
}
@@ -181,8 +185,26 @@ void Core::ChildLaunchFailed(const std::string& child_token) {
GetNodeController()->CloseChildPorts(child_token);
}
-void Core::InitChild(ScopedPlatformHandle platform_handle) {
- GetNodeController()->ConnectToParent(std::move(platform_handle));
+ScopedMessagePipeHandle Core::ConnectToPeerProcess(
+ ScopedPlatformHandle pipe_handle,
+ const std::string& peer_token) {
+ RequestContext request_context;
+ ports::PortRef port0, port1;
+ GetNodeController()->node()->CreatePortPair(&port0, &port1);
+ MojoHandle handle = AddDispatcher(new MessagePipeDispatcher(
+ GetNodeController(), port0, kUnknownPipeIdForDebug, 0));
+ ConnectionParams connection_params(std::move(pipe_handle));
+ GetNodeController()->ConnectToPeer(std::move(connection_params), port1,
+ peer_token);
+ return ScopedMessagePipeHandle(MessagePipeHandle(handle));
+}
+
+void Core::ClosePeerConnection(const std::string& peer_token) {
+ GetNodeController()->ClosePeerConnection(peer_token);
+}
+
+void Core::InitChild(ConnectionParams connection_params) {
+ GetNodeController()->ConnectToParent(std::move(connection_params));
}
void Core::SetMachPortProvider(base::PortProvider* port_provider) {
@@ -310,15 +332,7 @@ MojoResult Core::PassSharedMemoryHandle(
}
void Core::RequestShutdown(const base::Closure& callback) {
- base::Closure on_shutdown;
- if (base::ThreadTaskRunnerHandle::IsSet()) {
- on_shutdown = base::Bind(base::IgnoreResult(&base::TaskRunner::PostTask),
- base::ThreadTaskRunnerHandle::Get(),
- FROM_HERE, callback);
- } else {
- on_shutdown = callback;
- }
- GetNodeController()->RequestShutdown(on_shutdown);
+ GetNodeController()->RequestShutdown(callback);
}
ScopedMessagePipeHandle Core::CreateParentMessagePipe(
@@ -754,6 +768,8 @@ MojoResult Core::NotifyBadMessage(MojoMessageHandle message,
reinterpret_cast<MessageForTransit*>(message)->ports_message();
if (ports_message.source_node() == ports::kInvalidNodeName) {
DVLOG(1) << "Received invalid message from unknown node.";
+ if (!default_process_error_callback_.is_null())
+ default_process_error_callback_.Run(std::string(error, error_num_bytes));
return MOJO_RESULT_OK;
}
@@ -774,12 +790,12 @@ MojoResult Core::CreateDataPipe(
create_options.struct_size = sizeof(MojoCreateDataPipeOptions);
create_options.flags = options ? options->flags : 0;
create_options.element_num_bytes = options ? options->element_num_bytes : 1;
- // TODO: Use Configuration to get default data pipe capacity.
+ // TODO(rockot): Use Configuration to get default data pipe capacity.
create_options.capacity_num_bytes =
options && options->capacity_num_bytes ? options->capacity_num_bytes
: 64 * 1024;
- // TODO: Broker through the parent when necessary.
+ // TODO(rockot): Broker through the parent when necessary.
scoped_refptr<PlatformSharedBuffer> ring_buffer =
GetNodeController()->CreateSharedBuffer(
create_options.capacity_num_bytes);
@@ -1085,7 +1101,7 @@ MojoResult Core::WaitManyInternal(const MojoHandle* handles,
const MojoHandleSignals* signals,
uint32_t num_handles,
MojoDeadline deadline,
- uint32_t *result_index,
+ uint32_t* result_index,
HandleSignalsState* signals_states) {
CHECK(handles);
CHECK(signals);
diff --git a/mojo/edk/system/core.h b/mojo/edk/system/core.h
index 64298f9..1e20a87 100644
--- a/mojo/edk/system/core.h
+++ b/mojo/edk/system/core.h
@@ -6,6 +6,7 @@
#define MOJO_EDK_SYSTEM_CORE_H_
#include <memory>
+#include <string>
#include <vector>
#include "base/callback.h"
@@ -39,7 +40,7 @@ namespace edk {
// are thread-safe.
class MOJO_SYSTEM_IMPL_EXPORT Core {
public:
- explicit Core();
+ Core();
virtual ~Core();
// Called exactly once, shortly after construction, and before any other
@@ -51,17 +52,27 @@ class MOJO_SYSTEM_IMPL_EXPORT Core {
scoped_refptr<Dispatcher> GetDispatcher(MojoHandle handle);
+ void SetDefaultProcessErrorCallback(const ProcessErrorCallback& callback);
+
// Called in the parent process any time a new child is launched.
void AddChild(base::ProcessHandle process_handle,
- ScopedPlatformHandle platform_handle,
+ ConnectionParams connection_params,
const std::string& child_token,
const ProcessErrorCallback& process_error_callback);
// Called in the parent process when a child process fails to launch.
void ChildLaunchFailed(const std::string& child_token);
+ // Called to connect to a peer process. This should be called only if there
+ // is no common ancestor for the processes involved within this mojo system.
+ // Both processes must call this function, each passing one end of a platform
+ // channel. This returns one end of a message pipe to each process.
+ ScopedMessagePipeHandle ConnectToPeerProcess(ScopedPlatformHandle pipe_handle,
+ const std::string& peer_token);
+ void ClosePeerConnection(const std::string& peer_token);
+
// Called in a child process exactly once during early initialization.
- void InitChild(ScopedPlatformHandle platform_handle);
+ void InitChild(ConnectionParams connection_params);
// Creates a message pipe endpoint associated with |token|, which a child
// holding the token can later locate and connect to.
@@ -262,7 +273,7 @@ class MOJO_SYSTEM_IMPL_EXPORT Core {
const MojoHandleSignals* signals,
uint32_t num_handles,
MojoDeadline deadline,
- uint32_t *result_index,
+ uint32_t* result_index,
HandleSignalsState* signals_states);
// Used to pass ownership of our NodeController over to the IO thread in the
@@ -284,6 +295,10 @@ class MOJO_SYSTEM_IMPL_EXPORT Core {
// to access it.
std::unique_ptr<NodeController> node_controller_;
+ // The default callback to invoke, if any, when a process error is reported
+ // but cannot be associated with a specific process.
+ ProcessErrorCallback default_process_error_callback_;
+
base::Lock handles_lock_;
HandleTable handles_;
diff --git a/mojo/edk/system/core_unittest.cc b/mojo/edk/system/core_unittest.cc
index 33a7068..814ce4b 100644
--- a/mojo/edk/system/core_unittest.cc
+++ b/mojo/edk/system/core_unittest.cc
@@ -846,14 +846,16 @@ TEST_F(CoreTest, DataPipe) {
MOJO_RESULT_FAILED_PRECONDITION,
core()->Wait(ch, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss));
ASSERT_EQ(0u, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
hss = kFullMojoHandleSignalsState;
ASSERT_EQ(
MOJO_RESULT_DEADLINE_EXCEEDED,
core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss));
ASSERT_EQ(0u, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Write.
@@ -872,8 +874,10 @@ TEST_F(CoreTest, DataPipe) {
hss = kEmptyMojoHandleSignalsState;
ASSERT_EQ(MOJO_RESULT_OK, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0,
&hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Peek one character.
@@ -994,8 +998,9 @@ TEST_F(CoreTest, DataPipe) {
ASSERT_EQ(
MOJO_RESULT_DEADLINE_EXCEEDED,
core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss));
- ASSERT_EQ(0u, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(0u, hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// TODO(vtl): More.
@@ -1081,8 +1086,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
ASSERT_EQ(MOJO_RESULT_OK,
core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000,
&hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
num_bytes = kBufferSize;
ASSERT_EQ(MOJO_RESULT_OK,
@@ -1133,8 +1140,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
ASSERT_EQ(MOJO_RESULT_OK,
core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000,
&hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
num_bytes = kBufferSize;
ASSERT_EQ(MOJO_RESULT_OK,
@@ -1187,8 +1196,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
hss = kEmptyMojoHandleSignalsState;
ASSERT_EQ(MOJO_RESULT_OK, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE,
1000000000, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Make sure that |ch| can't be sent if it's in a two-phase read.
diff --git a/mojo/edk/system/data_pipe_consumer_dispatcher.cc b/mojo/edk/system/data_pipe_consumer_dispatcher.cc
index 23cb2e0..c908e3a 100644
--- a/mojo/edk/system/data_pipe_consumer_dispatcher.cc
+++ b/mojo/edk/system/data_pipe_consumer_dispatcher.cc
@@ -124,6 +124,8 @@ MojoResult DataPipeConsumerDispatcher::ReadData(void* elements,
uint32_t* num_bytes,
MojoReadDataFlags flags) {
base::AutoLock lock(lock_);
+ new_data_available_ = false;
+
if (!shared_ring_buffer_ || in_transit_)
return MOJO_RESULT_INVALID_ARGUMENT;
@@ -204,6 +206,7 @@ MojoResult DataPipeConsumerDispatcher::BeginReadData(const void** buffer,
uint32_t* buffer_num_bytes,
MojoReadDataFlags flags) {
base::AutoLock lock(lock_);
+ new_data_available_ = false;
if (!shared_ring_buffer_ || in_transit_)
return MOJO_RESULT_INVALID_ARGUMENT;
@@ -419,8 +422,10 @@ DataPipeConsumerDispatcher::Deserialize(const void* data,
base::AutoLock lock(dispatcher->lock_);
dispatcher->read_offset_ = state->read_offset;
dispatcher->bytes_available_ = state->bytes_available;
+ dispatcher->new_data_available_ = state->bytes_available > 0;
dispatcher->peer_closed_ = state->flags & kFlagPeerClosed;
dispatcher->InitializeNoLock();
+ dispatcher->UpdateSignalsStateNoLock();
}
return dispatcher;
@@ -473,16 +478,25 @@ DataPipeConsumerDispatcher::GetHandleSignalsStateNoLock() const {
HandleSignalsState rv;
if (shared_ring_buffer_ && bytes_available_) {
- if (!in_two_phase_read_)
+ if (!in_two_phase_read_) {
rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_READABLE;
+ if (new_data_available_)
+ rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE;
+ }
rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE;
} else if (!peer_closed_ && shared_ring_buffer_) {
rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE;
}
+ if (shared_ring_buffer_) {
+ if (new_data_available_ || !peer_closed_)
+ rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE;
+ }
+
if (peer_closed_)
rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
+
return rv;
}
@@ -526,8 +540,8 @@ void DataPipeConsumerDispatcher::UpdateSignalsStateNoLock() {
} else if (rv == ports::OK && port_status.has_messages && !in_transit_) {
ports::ScopedMessage message;
do {
- int rv = node_controller_->node()->GetMessageIf(control_port_, nullptr,
- &message);
+ int rv = node_controller_->node()->GetMessage(
+ control_port_, &message, nullptr);
if (rv != ports::OK)
peer_closed_ = true;
if (message) {
@@ -562,8 +576,11 @@ void DataPipeConsumerDispatcher::UpdateSignalsStateNoLock() {
} while (message);
}
- if (peer_closed_ != was_peer_closed ||
- bytes_available_ != previous_bytes_available) {
+ bool has_new_data = bytes_available_ != previous_bytes_available;
+ if (has_new_data)
+ new_data_available_ = true;
+
+ if (peer_closed_ != was_peer_closed || has_new_data) {
awakable_list_.AwakeForStateChange(GetHandleSignalsStateNoLock());
}
}
diff --git a/mojo/edk/system/data_pipe_consumer_dispatcher.h b/mojo/edk/system/data_pipe_consumer_dispatcher.h
index 6a7fb1c..b323c16 100644
--- a/mojo/edk/system/data_pipe_consumer_dispatcher.h
+++ b/mojo/edk/system/data_pipe_consumer_dispatcher.h
@@ -24,7 +24,6 @@
namespace mojo {
namespace edk {
-struct DataPipeControlMessage;
class NodeController;
// This is the Dispatcher implementation for the consumer handle for data
@@ -118,6 +117,9 @@ class MOJO_SYSTEM_IMPL_EXPORT DataPipeConsumerDispatcher final
uint32_t read_offset_ = 0;
uint32_t bytes_available_ = 0;
+ // Indicates whether any new data is available since the last read attempt.
+ bool new_data_available_ = false;
+
DISALLOW_COPY_AND_ASSIGN(DataPipeConsumerDispatcher);
};
diff --git a/mojo/edk/system/data_pipe_control_message.h b/mojo/edk/system/data_pipe_control_message.h
index 82ee594..ec84ea3 100644
--- a/mojo/edk/system/data_pipe_control_message.h
+++ b/mojo/edk/system/data_pipe_control_message.h
@@ -17,7 +17,6 @@ namespace mojo {
namespace edk {
class NodeController;
-class PortsMessage;
enum DataPipeCommand : uint32_t {
// Signal to the consumer that new data is available.
diff --git a/mojo/edk/system/data_pipe_producer_dispatcher.cc b/mojo/edk/system/data_pipe_producer_dispatcher.cc
index d056e7d..8c1993a 100644
--- a/mojo/edk/system/data_pipe_producer_dispatcher.cc
+++ b/mojo/edk/system/data_pipe_producer_dispatcher.cc
@@ -137,9 +137,8 @@ MojoResult DataPipeProducerDispatcher::WriteData(const void* elements,
if (*num_bytes == 0)
return MOJO_RESULT_OK; // Nothing to do.
- bool all_or_none = flags & MOJO_WRITE_DATA_FLAG_ALL_OR_NONE;
- uint32_t min_num_bytes_to_write = all_or_none ? *num_bytes : 0;
- if (min_num_bytes_to_write > options_.capacity_num_bytes) {
+ if ((flags & MOJO_WRITE_DATA_FLAG_ALL_OR_NONE) &&
+ (*num_bytes > available_capacity_)) {
// Don't return "should wait" since you can't wait for a specified amount of
// data.
return MOJO_RESULT_OUT_OF_RANGE;
@@ -403,6 +402,7 @@ DataPipeProducerDispatcher::Deserialize(const void* data,
dispatcher->available_capacity_ = state->available_capacity;
dispatcher->peer_closed_ = state->flags & kFlagPeerClosed;
dispatcher->InitializeNoLock();
+ dispatcher->UpdateSignalsStateNoLock();
}
return dispatcher;
@@ -504,8 +504,8 @@ void DataPipeProducerDispatcher::UpdateSignalsStateNoLock() {
} else if (rv == ports::OK && port_status.has_messages && !in_transit_) {
ports::ScopedMessage message;
do {
- int rv = node_controller_->node()->GetMessageIf(control_port_, nullptr,
- &message);
+ int rv = node_controller_->node()->GetMessage(
+ control_port_, &message, nullptr);
if (rv != ports::OK)
peer_closed_ = true;
if (message) {
diff --git a/mojo/edk/system/data_pipe_unittest.cc b/mojo/edk/system/data_pipe_unittest.cc
index 526444c..610aeac 100644
--- a/mojo/edk/system/data_pipe_unittest.cc
+++ b/mojo/edk/system/data_pipe_unittest.cc
@@ -12,6 +12,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "mojo/edk/embedder/embedder.h"
#include "mojo/edk/embedder/platform_channel_pair.h"
#include "mojo/edk/system/test_utils.h"
@@ -20,6 +21,7 @@
#include "mojo/public/c/system/data_pipe.h"
#include "mojo/public/c/system/functions.h"
#include "mojo/public/c/system/message_pipe.h"
+#include "mojo/public/cpp/system/watcher.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
@@ -40,6 +42,9 @@ const size_t kMultiprocessCapacity = 37;
const char kMultiprocessTestData[] = "hello i'm a string that is 36 bytes";
const int kMultiprocessMaxIter = 5;
+// TODO(rockot): There are many uses of ASSERT where EXPECT would be more
+// appropriate. Fix this.
+
class DataPipeTest : public test::MojoTestBase {
public:
DataPipeTest() : producer_(MOJO_HANDLE_INVALID),
@@ -159,7 +164,8 @@ TEST_F(DataPipeTest, Basic) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &state));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, state.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ state.satisfied_signals);
elements[0] = -1;
elements[1] = -1;
@@ -245,8 +251,10 @@ TEST_F(DataPipeTest, SimpleReadWrite) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Query.
@@ -352,8 +360,10 @@ TEST_F(DataPipeTest, BasicProducerWaiting) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Peek one element.
@@ -477,8 +487,9 @@ TEST_F(DataPipeTest, BasicConsumerWaiting) {
ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_WRITABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(0u, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(0u, hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Write two elements.
@@ -491,8 +502,10 @@ TEST_F(DataPipeTest, BasicConsumerWaiting) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Discard one element.
@@ -505,8 +518,9 @@ TEST_F(DataPipeTest, BasicConsumerWaiting) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Peek one element.
@@ -522,8 +536,9 @@ TEST_F(DataPipeTest, BasicConsumerWaiting) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Read one element.
@@ -546,8 +561,10 @@ TEST_F(DataPipeTest, BasicConsumerWaiting) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Close the producer.
@@ -558,8 +575,10 @@ TEST_F(DataPipeTest, BasicConsumerWaiting) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE) != 0);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_TRUE(hss.satisfied_signals & (MOJO_HANDLE_SIGNAL_READABLE |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE));
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Wait for the peer closed signal.
@@ -567,8 +586,11 @@ TEST_F(DataPipeTest, BasicConsumerWaiting) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_PEER_CLOSED) != 0);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE |
+ MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Read one element.
@@ -589,6 +611,64 @@ TEST_F(DataPipeTest, BasicConsumerWaiting) {
ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
}
+TEST_F(DataPipeTest, ConsumerNewDataReadable) {
+ const MojoCreateDataPipeOptions options = {
+ kSizeOfOptions, // |struct_size|.
+ MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
+ static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
+ 1000 * sizeof(int32_t) // |capacity_num_bytes|.
+ };
+ EXPECT_EQ(MOJO_RESULT_OK, Create(&options));
+
+ int32_t elements[2] = {123, 456};
+ uint32_t num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0]));
+ EXPECT_EQ(MOJO_RESULT_OK, WriteData(elements, &num_bytes, true));
+
+ // The consumer handle should appear to be readable and have new data.
+ EXPECT_EQ(MOJO_RESULT_OK, MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
+ MOJO_DEADLINE_INDEFINITE, nullptr));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoWait(consumer_, MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ MOJO_DEADLINE_INDEFINITE, nullptr));
+
+ // Now try to read a minimum of 6 elements.
+ int32_t read_elements[6];
+ uint32_t num_read_bytes = sizeof(read_elements);
+ EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE,
+ MojoReadData(consumer_, read_elements, &num_read_bytes,
+ MOJO_READ_DATA_FLAG_ALL_OR_NONE));
+
+ // The consumer should still appear to be readable, but not with new data.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE, 0, nullptr));
+ EXPECT_EQ(
+ MOJO_RESULT_DEADLINE_EXCEEDED,
+ MojoWait(consumer_, MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE, 0, nullptr));
+
+ // Write four more elements.
+ EXPECT_EQ(MOJO_RESULT_OK, WriteData(elements, &num_bytes, true));
+ EXPECT_EQ(MOJO_RESULT_OK, WriteData(elements, &num_bytes, true));
+
+ // The consumer handle should once again appear to be readable with new data.
+ EXPECT_EQ(MOJO_RESULT_OK, MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
+ MOJO_DEADLINE_INDEFINITE, nullptr));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoWait(consumer_, MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ MOJO_DEADLINE_INDEFINITE, nullptr));
+
+ // Read should succeed this time.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoReadData(consumer_, read_elements, &num_read_bytes,
+ MOJO_READ_DATA_FLAG_ALL_OR_NONE));
+
+ // And once again the consumer is unreadable.
+ EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
+ MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE, 0, nullptr));
+ EXPECT_EQ(
+ MOJO_RESULT_DEADLINE_EXCEEDED,
+ MojoWait(consumer_, MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE, 0, nullptr));
+}
+
// Test with two-phase APIs and also closing the producer with an active
// consumer waiter.
TEST_F(DataPipeTest, ConsumerWaitingTwoPhase) {
@@ -606,7 +686,7 @@ TEST_F(DataPipeTest, ConsumerWaitingTwoPhase) {
void* buffer = nullptr;
// Request room for three (but we'll only write two).
uint32_t num_bytes = static_cast<uint32_t>(3u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, BeginWriteData(&buffer, &num_bytes, true));
+ ASSERT_EQ(MOJO_RESULT_OK, BeginWriteData(&buffer, &num_bytes, false));
EXPECT_TRUE(buffer);
EXPECT_GE(num_bytes, static_cast<uint32_t>(3u * sizeof(elements[0])));
elements = static_cast<int32_t*>(buffer);
@@ -619,8 +699,10 @@ TEST_F(DataPipeTest, ConsumerWaitingTwoPhase) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Read one element.
@@ -639,8 +721,9 @@ TEST_F(DataPipeTest, ConsumerWaitingTwoPhase) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Read one element.
@@ -704,7 +787,8 @@ TEST_F(DataPipeTest, BasicTwoPhaseWaiting) {
ASSERT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss));
ASSERT_EQ(0u, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
static_cast<int32_t*>(write_ptr)[0] = 123;
@@ -723,8 +807,10 @@ TEST_F(DataPipeTest, BasicTwoPhaseWaiting) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Start another two-phase write and check that it's readable even in the
@@ -740,8 +826,10 @@ TEST_F(DataPipeTest, BasicTwoPhaseWaiting) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// End the two-phase write without writing anything.
@@ -767,7 +855,8 @@ TEST_F(DataPipeTest, BasicTwoPhaseWaiting) {
ASSERT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss));
ASSERT_EQ(0u, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// End the two-phase read without reading anything.
@@ -778,7 +867,8 @@ TEST_F(DataPipeTest, BasicTwoPhaseWaiting) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss));
ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
}
@@ -797,7 +887,7 @@ TEST_F(DataPipeTest, AllOrNone) {
ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
MojoHandleSignalsState hss;
- // Try writing way too much.
+ // Try writing more than the total capacity of the pipe.
uint32_t num_bytes = 20u * sizeof(int32_t);
int32_t buffer[100];
Seq(0, arraysize(buffer), buffer);
@@ -823,8 +913,10 @@ TEST_F(DataPipeTest, AllOrNone) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE |
+ MOJO_HANDLE_SIGNAL_PEER_CLOSED,
hss.satisfiable_signals);
// Half full.
@@ -832,12 +924,11 @@ TEST_F(DataPipeTest, AllOrNone) {
ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
ASSERT_EQ(5u * sizeof(int32_t), num_bytes);
- /* TODO(jam): enable if we end up observing max capacity
- // Too much.
+ // Try writing more than the available capacity of the pipe, but less than the
+ // total capacity.
num_bytes = 6u * sizeof(int32_t);
Seq(200, arraysize(buffer), buffer);
ASSERT_EQ(MOJO_RESULT_OUT_OF_RANGE, WriteData(buffer, &num_bytes, true));
- */
// Try reading too much.
num_bytes = 11u * sizeof(int32_t);
@@ -913,9 +1004,9 @@ TEST_F(DataPipeTest, AllOrNone) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
hss.satisfiable_signals);
// Try reading too much; "failed precondition" since the producer is closed.
@@ -978,8 +1069,9 @@ TEST_F(DataPipeTest, WrapAround) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE) != 0);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_TRUE(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Read 10 bytes.
@@ -1141,8 +1233,10 @@ TEST_F(DataPipeTest, TwoPhaseWriteReadCloseConsumer) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Start two-phase read.
@@ -1231,9 +1325,11 @@ TEST_F(DataPipeTest, WriteCloseProducerReadNoData) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Peek that data.
@@ -1290,8 +1386,10 @@ TEST_F(DataPipeTest, TwoPhaseReadMemoryStable) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Begin a two-phase read.
@@ -1315,8 +1413,9 @@ TEST_F(DataPipeTest, TwoPhaseReadMemoryStable) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Read the two phase memory to check it's still valid.
@@ -1402,8 +1501,10 @@ TEST_F(DataPipeTest, TwoPhaseMoreInvalidArguments) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// One element available.
@@ -1470,8 +1571,10 @@ TEST_F(DataPipeTest, SendProducer) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Check the data.
@@ -1511,8 +1614,10 @@ TEST_F(DataPipeTest, SendProducer) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ hss.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
hss.satisfiable_signals);
// Check the second write.
@@ -1550,9 +1655,11 @@ TEST_F(DataPipeTest, ConsumerWithClosedProducerSent) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED,
MOJO_DEADLINE_INDEFINITE, &state));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
state.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
state.satisfiable_signals);
// Now send the consumer over a MP so that it's serialized.
@@ -1575,9 +1682,11 @@ TEST_F(DataPipeTest, ConsumerWithClosedProducerSent) {
ASSERT_EQ(MOJO_RESULT_OK,
MojoWait(consumer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED,
MOJO_DEADLINE_INDEFINITE, &state));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
state.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
state.satisfiable_signals);
int32_t read_data;
@@ -1649,8 +1758,8 @@ bool ReadAllData(MojoHandle consumer,
MOJO_DEADLINE_INDEFINITE, &hss));
// Peer could have become closed while we're still waiting for data.
EXPECT_TRUE(MOJO_HANDLE_SIGNAL_READABLE & hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfiable_signals);
+ EXPECT_TRUE(hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE);
+ EXPECT_TRUE(hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_PEER_CLOSED);
}
return num_bytes == 0;
@@ -1898,6 +2007,90 @@ TEST_F(DataPipeTest, CreateInChild) {
END_CHILD()
}
+DEFINE_TEST_CLIENT_TEST_WITH_PIPE(DataPipeStatusChangeInTransitClient,
+ DataPipeTest, parent) {
+ // This test verifies that peer closure is detectable through various
+ // mechanisms when it races with handle transfer.
+
+ MojoHandle handles[6];
+ EXPECT_EQ("o_O", ReadMessageWithHandles(parent, handles, 6));
+ MojoHandle* producers = &handles[0];
+ MojoHandle* consumers = &handles[3];
+
+ // Wait on producer 0 using MojoWait.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoWait(producers[0], MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_DEADLINE_INDEFINITE, nullptr));
+
+ // Wait on consumer 0 using MojoWait.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoWait(consumers[0], MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_DEADLINE_INDEFINITE, nullptr));
+
+ base::MessageLoop message_loop;
+
+ // Wait on producer 1 and consumer 1 using Watchers.
+ {
+ base::RunLoop run_loop;
+ int count = 0;
+ auto callback = base::Bind(
+ [] (base::RunLoop* loop, int* count, MojoResult result) {
+ EXPECT_EQ(MOJO_RESULT_OK, result);
+ if (++*count == 2)
+ loop->Quit();
+ },
+ &run_loop, &count);
+ Watcher producer_watcher(FROM_HERE), consumer_watcher(FROM_HERE);
+ producer_watcher.Start(
+ Handle(producers[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED, callback);
+ consumer_watcher.Start(
+ Handle(consumers[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED, callback);
+ run_loop.Run();
+ }
+
+ // Wait on producer 2 by polling with MojoWriteData.
+ MojoResult result;
+ do {
+ uint32_t num_bytes = 0;
+ result = MojoWriteData(
+ producers[2], nullptr, &num_bytes, MOJO_WRITE_DATA_FLAG_NONE);
+ } while (result == MOJO_RESULT_OK);
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
+
+ // Wait on consumer 2 by polling with MojoReadData.
+ do {
+ char byte;
+ uint32_t num_bytes = 1;
+ result = MojoReadData(
+ consumers[2], &byte, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
+ } while (result == MOJO_RESULT_SHOULD_WAIT);
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
+
+ for (size_t i = 0; i < 6; ++i)
+ CloseHandle(handles[i]);
+}
+
+TEST_F(DataPipeTest, StatusChangeInTransit) {
+ MojoHandle producers[6];
+ MojoHandle consumers[6];
+ for (size_t i = 0; i < 6; ++i)
+ CreateDataPipe(&producers[i], &consumers[i], 1);
+
+ RUN_CHILD_ON_PIPE(DataPipeStatusChangeInTransitClient, child)
+ MojoHandle handles[] = { producers[0], producers[1], producers[2],
+ consumers[3], consumers[4], consumers[5] };
+
+ // Send 3 producers and 3 consumers, and let their transfer race with their
+ // peers' closure.
+ WriteMessageWithHandles(child, "o_O", handles, 6);
+
+ for (size_t i = 0; i < 3; ++i)
+ CloseHandle(consumers[i]);
+ for (size_t i = 3; i < 6; ++i)
+ CloseHandle(producers[i]);
+ END_CHILD()
+}
+
#endif // !defined(OS_IOS)
} // namespace
diff --git a/mojo/edk/system/handle_table.cc b/mojo/edk/system/handle_table.cc
index e41817d..b570793 100644
--- a/mojo/edk/system/handle_table.cc
+++ b/mojo/edk/system/handle_table.cc
@@ -21,7 +21,8 @@ MojoHandle HandleTable::AddDispatcher(scoped_refptr<Dispatcher> dispatcher) {
return MOJO_HANDLE_INVALID;
MojoHandle handle = next_available_handle_++;
- auto result = handles_.insert(std::make_pair(handle, Entry(dispatcher)));
+ auto result =
+ handles_.insert(std::make_pair(handle, Entry(std::move(dispatcher))));
DCHECK(result.second);
return handle;
@@ -66,7 +67,7 @@ MojoResult HandleTable::GetAndRemoveDispatcher(
if (it->second.busy)
return MOJO_RESULT_BUSY;
- *dispatcher = it->second.dispatcher;
+ *dispatcher = std::move(it->second.dispatcher);
handles_.erase(it);
return MOJO_RESULT_OK;
}
@@ -124,7 +125,7 @@ void HandleTable::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) {
HandleTable::Entry::Entry() {}
HandleTable::Entry::Entry(scoped_refptr<Dispatcher> dispatcher)
- : dispatcher(dispatcher) {}
+ : dispatcher(std::move(dispatcher)) {}
HandleTable::Entry::Entry(const Entry& other) = default;
diff --git a/mojo/edk/system/message_pipe_dispatcher.cc b/mojo/edk/system/message_pipe_dispatcher.cc
index f06054d..f27336b 100644
--- a/mojo/edk/system/message_pipe_dispatcher.cc
+++ b/mojo/edk/system/message_pipe_dispatcher.cc
@@ -14,6 +14,7 @@
#include "mojo/edk/system/core.h"
#include "mojo/edk/system/message_for_transit.h"
#include "mojo/edk/system/node_controller.h"
+#include "mojo/edk/system/ports/message_filter.h"
#include "mojo/edk/system/ports_message.h"
#include "mojo/edk/system/request_context.h"
@@ -59,6 +60,103 @@ class MessagePipeDispatcher::PortObserverThunk
DISALLOW_COPY_AND_ASSIGN(PortObserverThunk);
};
+// A MessageFilter used by ReadMessage to determine whether a message should
+// actually be consumed yet.
+class ReadMessageFilter : public ports::MessageFilter {
+ public:
+ // Creates a new ReadMessageFilter which captures and potentially modifies
+ // various (unowned) local state within MessagePipeDispatcher::ReadMessage.
+ ReadMessageFilter(bool read_any_size,
+ bool may_discard,
+ uint32_t* num_bytes,
+ uint32_t* num_handles,
+ bool* no_space,
+ bool* invalid_message)
+ : read_any_size_(read_any_size),
+ may_discard_(may_discard),
+ num_bytes_(num_bytes),
+ num_handles_(num_handles),
+ no_space_(no_space),
+ invalid_message_(invalid_message) {}
+
+ ~ReadMessageFilter() override {}
+
+ // ports::MessageFilter:
+ bool Match(const ports::Message& m) override {
+ const PortsMessage& message = static_cast<const PortsMessage&>(m);
+ if (message.num_payload_bytes() < sizeof(MessageHeader)) {
+ *invalid_message_ = true;
+ return true;
+ }
+
+ const MessageHeader* header =
+ static_cast<const MessageHeader*>(message.payload_bytes());
+ if (header->header_size > message.num_payload_bytes()) {
+ *invalid_message_ = true;
+ return true;
+ }
+
+ uint32_t bytes_to_read = 0;
+ uint32_t bytes_available =
+ static_cast<uint32_t>(message.num_payload_bytes()) -
+ header->header_size;
+ if (num_bytes_) {
+ bytes_to_read = std::min(*num_bytes_, bytes_available);
+ *num_bytes_ = bytes_available;
+ }
+
+ uint32_t handles_to_read = 0;
+ uint32_t handles_available = header->num_dispatchers;
+ if (num_handles_) {
+ handles_to_read = std::min(*num_handles_, handles_available);
+ *num_handles_ = handles_available;
+ }
+
+ if (handles_to_read < handles_available ||
+ (!read_any_size_ && bytes_to_read < bytes_available)) {
+ *no_space_ = true;
+ return may_discard_;
+ }
+
+ return true;
+ }
+
+ private:
+ const bool read_any_size_;
+ const bool may_discard_;
+ uint32_t* const num_bytes_;
+ uint32_t* const num_handles_;
+ bool* const no_space_;
+ bool* const invalid_message_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReadMessageFilter);
+};
+
+#if DCHECK_IS_ON()
+
+// A MessageFilter which never matches a message. Used to peek at the size of
+// the next available message on a port, for debug logging only.
+class PeekSizeMessageFilter : public ports::MessageFilter {
+ public:
+ PeekSizeMessageFilter() {}
+ ~PeekSizeMessageFilter() override {}
+
+ // ports::MessageFilter:
+ bool Match(const ports::Message& message) override {
+ message_size_ = message.num_payload_bytes();
+ return false;
+ }
+
+ size_t message_size() const { return message_size_; }
+
+ private:
+ size_t message_size_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(PeekSizeMessageFilter);
+};
+
+#endif // DCHECK_IS_ON()
+
MessagePipeDispatcher::MessagePipeDispatcher(NodeController* node_controller,
const ports::PortRef& port,
uint64_t pipe_id,
@@ -141,7 +239,7 @@ MojoResult MessagePipeDispatcher::WriteMessage(
size_t num_bytes = message->num_bytes();
int rv = node_controller_->SendMessage(port_, message->TakePortsMessage());
- DVLOG(2) << "Sent message on pipe " << pipe_id_ << " endpoint " << endpoint_
+ DVLOG(4) << "Sent message on pipe " << pipe_id_ << " endpoint " << endpoint_
<< " [port=" << port_.name() << "; rv=" << rv
<< "; num_bytes=" << num_bytes << "]";
@@ -151,8 +249,6 @@ MojoResult MessagePipeDispatcher::WriteMessage(
rv == ports::ERROR_PORT_CANNOT_SEND_PEER) {
return MOJO_RESULT_INVALID_ARGUMENT;
} else if (rv == ports::ERROR_PORT_PEER_CLOSED) {
- base::AutoLock lock(signal_lock_);
- awakables_.AwakeForStateChange(GetHandleSignalsStateNoLock());
return MOJO_RESULT_FAILED_PRECONDITION;
}
@@ -186,50 +282,9 @@ MojoResult MessagePipeDispatcher::ReadMessage(
// This flag exists to support both new and old API behavior.
ports::ScopedMessage ports_message;
- int rv = node_controller_->node()->GetMessageIf(
- port_,
- [read_any_size, num_bytes, num_handles, &no_space, &may_discard,
- &invalid_message](
- const ports::Message& next_message) {
- const PortsMessage& message =
- static_cast<const PortsMessage&>(next_message);
- if (message.num_payload_bytes() < sizeof(MessageHeader)) {
- invalid_message = true;
- return true;
- }
-
- const MessageHeader* header =
- static_cast<const MessageHeader*>(message.payload_bytes());
- if (header->header_size > message.num_payload_bytes()) {
- invalid_message = true;
- return true;
- }
-
- uint32_t bytes_to_read = 0;
- uint32_t bytes_available =
- static_cast<uint32_t>(message.num_payload_bytes()) -
- header->header_size;
- if (num_bytes) {
- bytes_to_read = std::min(*num_bytes, bytes_available);
- *num_bytes = bytes_available;
- }
-
- uint32_t handles_to_read = 0;
- uint32_t handles_available = header->num_dispatchers;
- if (num_handles) {
- handles_to_read = std::min(*num_handles, handles_available);
- *num_handles = handles_available;
- }
-
- if (handles_to_read < handles_available ||
- (!read_any_size && bytes_to_read < bytes_available)) {
- no_space = true;
- return may_discard;
- }
-
- return true;
- },
- &ports_message);
+ ReadMessageFilter filter(read_any_size, may_discard, num_bytes, num_handles,
+ &no_space, &invalid_message);
+ int rv = node_controller_->node()->GetMessage(port_, &ports_message, &filter);
if (invalid_message)
return MOJO_RESULT_UNKNOWN;
@@ -258,8 +313,6 @@ MojoResult MessagePipeDispatcher::ReadMessage(
// Peer is closed and there are no more messages to read.
DCHECK_EQ(rv, ports::ERROR_PORT_PEER_CLOSED);
- base::AutoLock lock(signal_lock_);
- awakables_.AwakeForStateChange(GetHandleSignalsStateNoLock());
return MOJO_RESULT_FAILED_PRECONDITION;
}
@@ -530,15 +583,11 @@ void MessagePipeDispatcher::OnPortStatusChanged() {
if (node_controller_->node()->GetStatus(port_, &port_status) == ports::OK) {
if (port_status.has_messages) {
ports::ScopedMessage unused;
- size_t message_size = 0;
- node_controller_->node()->GetMessageIf(
- port_, [&message_size](const ports::Message& message) {
- message_size = message.num_payload_bytes();
- return false;
- }, &unused);
- DVLOG(2) << "New message detected on message pipe " << pipe_id_
+ PeekSizeMessageFilter filter;
+ node_controller_->node()->GetMessage(port_, &unused, &filter);
+ DVLOG(4) << "New message detected on message pipe " << pipe_id_
<< " endpoint " << endpoint_ << " [port=" << port_.name()
- << "; size=" << message_size << "]";
+ << "; size=" << filter.message_size() << "]";
}
if (port_status.peer_closed) {
DVLOG(2) << "Peer closure detected on message pipe " << pipe_id_
diff --git a/mojo/edk/system/message_pipe_dispatcher.h b/mojo/edk/system/message_pipe_dispatcher.h
index fddd0fd..6743222 100644
--- a/mojo/edk/system/message_pipe_dispatcher.h
+++ b/mojo/edk/system/message_pipe_dispatcher.h
@@ -21,7 +21,6 @@ namespace mojo {
namespace edk {
class NodeController;
-class PortsMessage;
class MessagePipeDispatcher : public Dispatcher {
public:
diff --git a/mojo/edk/system/message_pipe_unittest.cc b/mojo/edk/system/message_pipe_unittest.cc
index fcfaeca..8f48950 100644
--- a/mojo/edk/system/message_pipe_unittest.cc
+++ b/mojo/edk/system/message_pipe_unittest.cc
@@ -706,6 +706,17 @@ TEST_F(FuseMessagePipeTest, FuseAfterPeerWriteAndClosure) {
EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
}
+TEST_F(MessagePipeTest, ClosePipesStressTest) {
+ // Stress test to exercise https://crbug.com/665869.
+ const size_t kNumPipes = 100000;
+ for (size_t i = 0; i < kNumPipes; ++i) {
+ MojoHandle a, b;
+ CreateMessagePipe(&a, &b);
+ MojoClose(a);
+ MojoClose(b);
+ }
+}
+
} // namespace
} // namespace edk
} // namespace mojo
diff --git a/mojo/edk/system/multiprocess_message_pipe_unittest.cc b/mojo/edk/system/multiprocess_message_pipe_unittest.cc
index 6e2c6f1..498980c 100644
--- a/mojo/edk/system/multiprocess_message_pipe_unittest.cc
+++ b/mojo/edk/system/multiprocess_message_pipe_unittest.cc
@@ -18,6 +18,8 @@
#include "base/files/scoped_file.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/strings/string_split.h"
#include "build/build_config.h"
#include "mojo/edk/embedder/platform_channel_pair.h"
@@ -29,6 +31,7 @@
#include "mojo/public/c/system/buffer.h"
#include "mojo/public/c/system/functions.h"
#include "mojo/public/c/system/types.h"
+#include "mojo/public/cpp/system/watcher.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -68,6 +71,16 @@ class MultiprocessMessagePipeTest : public test::MojoTestBase {
};
};
+class MultiprocessMessagePipeTestWithPeerSupport
+ : public MultiprocessMessagePipeTest,
+ public testing::WithParamInterface<test::MojoTestBase::LaunchType> {
+ protected:
+ void SetUp() override {
+ test::MojoTestBase::SetUp();
+ set_launch_type(GetParam());
+ }
+};
+
// For each message received, sends a reply message with the same contents
// repeated twice, until the other end is closed or it receives "quitquitquit"
// (which it doesn't reply to). It'll return the number of messages received,
@@ -116,7 +129,7 @@ DEFINE_TEST_CLIENT_WITH_PIPE(EchoEcho, MultiprocessMessagePipeTest, h) {
return rv;
}
-TEST_F(MultiprocessMessagePipeTest, Basic) {
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport, Basic) {
RUN_CHILD_ON_PIPE(EchoEcho, h)
std::string hello("hello");
ASSERT_EQ(MOJO_RESULT_OK,
@@ -152,7 +165,7 @@ TEST_F(MultiprocessMessagePipeTest, Basic) {
END_CHILD_AND_EXPECT_EXIT_CODE(1 % 100);
}
-TEST_F(MultiprocessMessagePipeTest, QueueMessages) {
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport, QueueMessages) {
static const size_t kNumMessages = 1001;
RUN_CHILD_ON_PIPE(EchoEcho, h)
for (size_t i = 0; i < kNumMessages; i++) {
@@ -415,7 +428,7 @@ TEST_P(MultiprocessMessagePipeTestWithPipeCount, PlatformHandlePassing) {
for (size_t i = 0; i < pipe_count; ++i) {
base::FilePath unused;
base::ScopedFILE fp(
- CreateAndOpenTemporaryFileInDir(temp_dir.path(), &unused));
+ CreateAndOpenTemporaryFileInDir(temp_dir.GetPath(), &unused));
const std::string world("world");
CHECK_EQ(fwrite(&world[0], 1, world.size(), fp.get()), world.size());
fflush(fp.get());
@@ -430,7 +443,8 @@ TEST_P(MultiprocessMessagePipeTestWithPipeCount, PlatformHandlePassing) {
}
char message[128];
- sprintf(message, "hello %d", static_cast<int>(pipe_count));
+ snprintf(message, sizeof(message), "hello %d",
+ static_cast<int>(pipe_count));
ASSERT_EQ(MOJO_RESULT_OK,
MojoWriteMessage(h, message,
static_cast<uint32_t>(strlen(message)),
@@ -452,9 +466,9 @@ TEST_P(MultiprocessMessagePipeTestWithPipeCount, PlatformHandlePassing) {
#if !defined(OS_ANDROID)
INSTANTIATE_TEST_CASE_P(PipeCount,
MultiprocessMessagePipeTestWithPipeCount,
- // TODO: Re-enable the 140-pipe case when ChannelPosix
- // has support for sending lots of handles.
- testing::Values(1u, 128u/*, 140u*/));
+ // TODO(rockot): Re-enable the 140-pipe case when
+ // ChannelPosix has support for sending lots of handles.
+ testing::Values(1u, 128u /*, 140u*/));
#endif
DEFINE_TEST_CLIENT_WITH_PIPE(CheckMessagePipe, MultiprocessMessagePipeTest, h) {
@@ -509,7 +523,7 @@ DEFINE_TEST_CLIENT_WITH_PIPE(CheckMessagePipe, MultiprocessMessagePipeTest, h) {
return 0;
}
-TEST_F(MultiprocessMessagePipeTest, MessagePipePassing) {
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport, MessagePipePassing) {
RUN_CHILD_ON_PIPE(CheckMessagePipe, h)
MojoCreateSharedBufferOptions options;
options.struct_size = sizeof(options);
@@ -551,7 +565,7 @@ TEST_F(MultiprocessMessagePipeTest, MessagePipePassing) {
END_CHILD()
}
-TEST_F(MultiprocessMessagePipeTest, MessagePipeTwoPassing) {
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport, MessagePipeTwoPassing) {
RUN_CHILD_ON_PIPE(CheckMessagePipe, h)
MojoHandle mp1, mp2;
ASSERT_EQ(MOJO_RESULT_OK,
@@ -681,11 +695,9 @@ TEST_F(MultiprocessMessagePipeTest, DataPipeConsumer) {
END_CHILD();
}
-TEST_F(MultiprocessMessagePipeTest, CreateMessagePipe) {
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport, CreateMessagePipe) {
MojoHandle p0, p1;
CreateMessagePipe(&p0, &p1);
- VerifyTransmission(p0, p1, "hey man");
- VerifyTransmission(p1, p0, "slow down");
VerifyTransmission(p0, p1, std::string(10 * 1024 * 1024, 'a'));
VerifyTransmission(p1, p0, std::string(10 * 1024 * 1024, 'e'));
@@ -693,7 +705,7 @@ TEST_F(MultiprocessMessagePipeTest, CreateMessagePipe) {
CloseHandle(p1);
}
-TEST_F(MultiprocessMessagePipeTest, PassMessagePipeLocal) {
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport, PassMessagePipeLocal) {
MojoHandle p0, p1;
CreateMessagePipe(&p0, &p1);
VerifyTransmission(p0, p1, "testing testing");
@@ -733,7 +745,7 @@ DEFINE_TEST_CLIENT_WITH_PIPE(ChannelEchoClient, MultiprocessMessagePipeTest,
return 0;
}
-TEST_F(MultiprocessMessagePipeTest, MultiprocessChannelPipe) {
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport, MultiprocessChannelPipe) {
RUN_CHILD_ON_PIPE(ChannelEchoClient, h)
VerifyEcho(h, "in an interstellar burst");
VerifyEcho(h, "i am back to save the universe");
@@ -758,7 +770,8 @@ DEFINE_TEST_CLIENT_WITH_PIPE(EchoServiceClient, MultiprocessMessagePipeTest,
return 0;
}
-TEST_F(MultiprocessMessagePipeTest, PassMessagePipeCrossProcess) {
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport,
+ PassMessagePipeCrossProcess) {
MojoHandle p0, p1;
CreateMessagePipe(&p0, &p1);
RUN_CHILD_ON_PIPE(EchoServiceClient, h)
@@ -815,7 +828,8 @@ DEFINE_TEST_CLIENT_WITH_PIPE(EchoServiceFactoryClient,
return 0;
}
-TEST_F(MultiprocessMessagePipeTest, PassMoarMessagePipesCrossProcess) {
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport,
+ PassMoarMessagePipesCrossProcess) {
MojoHandle echo_factory_proxy, echo_factory_request;
CreateMessagePipe(&echo_factory_proxy, &echo_factory_request);
@@ -860,7 +874,8 @@ TEST_F(MultiprocessMessagePipeTest, PassMoarMessagePipesCrossProcess) {
CloseHandle(echo_proxy_c);
}
-TEST_F(MultiprocessMessagePipeTest, ChannelPipesWithMultipleChildren) {
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport,
+ ChannelPipesWithMultipleChildren) {
RUN_CHILD_ON_PIPE(ChannelEchoClient, a)
RUN_CHILD_ON_PIPE(ChannelEchoClient, b)
VerifyEcho(a, "hello child 0");
@@ -890,7 +905,7 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(PingPongPipeClient,
EXPECT_EQ("quit", ReadMessage(h));
}
-TEST_F(MultiprocessMessagePipeTest, PingPongPipe) {
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport, PingPongPipe) {
MojoHandle p0, p1;
CreateMessagePipe(&p0, &p1);
@@ -983,7 +998,7 @@ DEFINE_TEST_CLIENT_WITH_PIPE(CommandDrivenClient, MultiprocessMessagePipeTest,
}
}
- for (auto& pipe: named_pipes)
+ for (auto& pipe : named_pipes)
CloseHandle(pipe.second);
return 0;
@@ -1002,8 +1017,8 @@ TEST_F(MultiprocessMessagePipeTest, ChildToChildPipes) {
b.SendHandle("y", p1);
// Make sure they can talk.
- a.Send("say:x:hello sir");
- b.Send("hear:y:hello sir");
+ a.Send("say:x:hello");
+ b.Send("hear:y:hello");
b.Send("say:y:i love multiprocess pipes!");
a.Send("hear:x:i love multiprocess pipes!");
@@ -1096,11 +1111,12 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceivePipeWithClosedPeer,
MojoHandle p;
EXPECT_EQ("foo", ReadMessageWithHandles(h, &p, 1));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWait(p, MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- MOJO_DEADLINE_INDEFINITE, nullptr));
+ auto result = MojoWait(p, MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_DEADLINE_INDEFINITE, nullptr);
+ EXPECT_EQ(MOJO_RESULT_OK, result);
}
-TEST_F(MultiprocessMessagePipeTest, SendPipeThenClosePeer) {
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport, SendPipeThenClosePeer) {
RUN_CHILD_ON_PIPE(ReceivePipeWithClosedPeer, h)
MojoHandle a, b;
CreateMessagePipe(&a, &b);
@@ -1176,8 +1192,7 @@ TEST_F(MultiprocessMessagePipeTest,
END_CHILD()
}
-
-TEST_F(MultiprocessMessagePipeTest, SendClosePeerSend) {
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport, SendClosePeerSend) {
MojoHandle a, b;
CreateMessagePipe(&a, &b);
@@ -1220,7 +1235,7 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(WriteCloseSendPeerClient,
EXPECT_EQ("quit", ReadMessage(h));
}
-TEST_F(MultiprocessMessagePipeTest, WriteCloseSendPeer) {
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport, WriteCloseSendPeer) {
MojoHandle pipe[2];
CreateMessagePipe(&pipe[0], &pipe[1]);
@@ -1243,41 +1258,61 @@ TEST_F(MultiprocessMessagePipeTest, WriteCloseSendPeer) {
END_CHILD()
}
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(BootstrapMessagePipeAsyncClient,
+DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MessagePipeStatusChangeInTransitClient,
MultiprocessMessagePipeTest, parent) {
- // Receive one end of a platform channel from the parent.
- MojoHandle channel_handle;
- EXPECT_EQ("hi", ReadMessageWithHandles(parent, &channel_handle, 1));
- ScopedPlatformHandle channel;
- EXPECT_EQ(MOJO_RESULT_OK,
- edk::PassWrappedPlatformHandle(channel_handle, &channel));
- ASSERT_TRUE(channel.is_valid());
+ // This test verifies that peer closure is detectable through various
+ // mechanisms when it races with handle transfer.
+ MojoHandle handles[4];
+ EXPECT_EQ("o_O", ReadMessageWithHandles(parent, handles, 4));
+
+ // Wait on handle 0 using MojoWait.
+ EXPECT_EQ(MOJO_RESULT_OK, MojoWait(handles[0], MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_DEADLINE_INDEFINITE, nullptr));
- // Create a new pipe using our end of the channel.
- ScopedMessagePipeHandle pipe = edk::CreateMessagePipe(std::move(channel));
+ base::MessageLoop message_loop;
+
+ // Wait on handle 1 using a Watcher.
+ {
+ base::RunLoop run_loop;
+ Watcher watcher(FROM_HERE);
+ watcher.Start(Handle(handles[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ base::Bind([] (base::RunLoop* loop, MojoResult result) {
+ EXPECT_EQ(MOJO_RESULT_OK, result);
+ loop->Quit();
+ }, &run_loop));
+ run_loop.Run();
+ }
- // Ensure that we can read and write on the new pipe.
- VerifyEcho(pipe.get().value(), "goodbye");
+ // Wait on handle 2 by polling with MojoReadMessage.
+ MojoResult result;
+ do {
+ result = MojoReadMessage(handles[2], nullptr, nullptr, nullptr, nullptr,
+ MOJO_READ_MESSAGE_FLAG_NONE);
+ } while (result == MOJO_RESULT_SHOULD_WAIT);
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
+
+ // Wait on handle 3 by polling with MojoWriteMessage.
+ do {
+ result = MojoWriteMessage(handles[3], nullptr, 0, nullptr, 0,
+ MOJO_WRITE_MESSAGE_FLAG_NONE);
+ } while (result == MOJO_RESULT_OK);
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
+
+ for (size_t i = 0; i < 4; ++i)
+ CloseHandle(handles[i]);
}
-TEST_F(MultiprocessMessagePipeTest, BootstrapMessagePipeAsync) {
- // Tests that new cross-process message pipes can be created synchronously
- // using asynchronous negotiation over an arbitrary platform channel.
- RUN_CHILD_ON_PIPE(BootstrapMessagePipeAsyncClient, child)
- // Pass one end of a platform channel to the child.
- PlatformChannelPair platform_channel;
- MojoHandle client_channel_handle;
- EXPECT_EQ(MOJO_RESULT_OK,
- CreatePlatformHandleWrapper(platform_channel.PassClientHandle(),
- &client_channel_handle));
- WriteMessageWithHandles(child, "hi", &client_channel_handle, 1);
-
- // Create a new pipe using our end of the channel.
- ScopedMessagePipeHandle pipe =
- edk::CreateMessagePipe(platform_channel.PassServerHandle());
-
- // Ensure that we can read and write on the new pipe.
- VerifyEcho(pipe.get().value(), "goodbye");
+TEST_F(MultiprocessMessagePipeTest, MessagePipeStatusChangeInTransit) {
+ MojoHandle local_handles[4];
+ MojoHandle sent_handles[4];
+ for (size_t i = 0; i < 4; ++i)
+ CreateMessagePipe(&local_handles[i], &sent_handles[i]);
+
+ RUN_CHILD_ON_PIPE(MessagePipeStatusChangeInTransitClient, child)
+ // Send 4 handles and let their transfer race with their peers' closure.
+ WriteMessageWithHandles(child, "o_O", sent_handles, 4);
+ for (size_t i = 0; i < 4; ++i)
+ CloseHandle(local_handles[i]);
END_CHILD()
}
@@ -1345,7 +1380,13 @@ TEST_F(MultiprocessMessagePipeTest, NotifyBadMessage) {
EXPECT_NE(std::string::npos, first_process_error.find(kFirstErrorMessage));
EXPECT_NE(std::string::npos, second_process_error.find(kSecondErrorMessage));
}
-
+INSTANTIATE_TEST_CASE_P(
+ ,
+ MultiprocessMessagePipeTestWithPeerSupport,
+ testing::Values(test::MojoTestBase::LaunchType::CHILD,
+ test::MojoTestBase::LaunchType::PEER,
+ test::MojoTestBase::LaunchType::NAMED_CHILD,
+ test::MojoTestBase::LaunchType::NAMED_PEER));
} // namespace
} // namespace edk
} // namespace mojo
diff --git a/mojo/edk/system/node_channel.cc b/mojo/edk/system/node_channel.cc
index ce094c1..b0f770d 100644
--- a/mojo/edk/system/node_channel.cc
+++ b/mojo/edk/system/node_channel.cc
@@ -47,6 +47,7 @@ enum class MessageType : uint32_t {
#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
PORTS_MESSAGE_FROM_RELAY,
#endif
+ ACCEPT_PEER,
};
struct Header {
@@ -54,8 +55,8 @@ struct Header {
uint32_t padding;
};
-static_assert(sizeof(Header) % kChannelMessageAlignment == 0,
- "Invalid header size.");
+static_assert(IsAlignedForChannelMessage(sizeof(Header)),
+ "Invalid header size.");
struct AcceptChildData {
ports::NodeName parent_name;
@@ -67,6 +68,12 @@ struct AcceptParentData {
ports::NodeName child_name;
};
+struct AcceptPeerData {
+ ports::NodeName token;
+ ports::NodeName peer_name;
+ ports::PortName port_name;
+};
+
// This message may include a process handle on plaforms that require it.
struct AddBrokerClientData {
ports::NodeName client_name;
@@ -153,14 +160,14 @@ bool GetMessagePayload(const void* bytes,
// static
scoped_refptr<NodeChannel> NodeChannel::Create(
Delegate* delegate,
- ScopedPlatformHandle platform_handle,
+ ConnectionParams connection_params,
scoped_refptr<base::TaskRunner> io_task_runner,
const ProcessErrorCallback& process_error_callback) {
#if defined(OS_NACL_SFI)
LOG(FATAL) << "Multi-process not yet supported on NaCl-SFI";
return nullptr;
#else
- return new NodeChannel(delegate, std::move(platform_handle), io_task_runner,
+ return new NodeChannel(delegate, std::move(connection_params), io_task_runner,
process_error_callback);
#endif
}
@@ -282,6 +289,18 @@ void NodeChannel::AcceptParent(const ports::NodeName& token,
WriteChannelMessage(std::move(message));
}
+void NodeChannel::AcceptPeer(const ports::NodeName& sender_name,
+ const ports::NodeName& token,
+ const ports::PortName& port_name) {
+ AcceptPeerData* data;
+ Channel::MessagePtr message =
+ CreateMessage(MessageType::ACCEPT_PEER, sizeof(AcceptPeerData), 0, &data);
+ data->token = token;
+ data->peer_name = sender_name;
+ data->port_name = port_name;
+ WriteChannelMessage(std::move(message));
+}
+
void NodeChannel::AddBrokerClient(const ports::NodeName& client_name,
base::ProcessHandle process_handle) {
AddBrokerClientData* data;
@@ -435,17 +454,18 @@ void NodeChannel::PortsMessageFromRelay(const ports::NodeName& source,
#endif // defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
NodeChannel::NodeChannel(Delegate* delegate,
- ScopedPlatformHandle platform_handle,
+ ConnectionParams connection_params,
scoped_refptr<base::TaskRunner> io_task_runner,
const ProcessErrorCallback& process_error_callback)
: delegate_(delegate),
io_task_runner_(io_task_runner),
process_error_callback_(process_error_callback)
#if !defined(OS_NACL_SFI)
- , channel_(
- Channel::Create(this, std::move(platform_handle), io_task_runner_))
+ ,
+ channel_(
+ Channel::Create(this, std::move(connection_params), io_task_runner_))
#endif
- {
+{
}
NodeChannel::~NodeChannel() {
@@ -728,6 +748,16 @@ void NodeChannel::OnChannelMessage(const void* payload,
#endif // defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+ case MessageType::ACCEPT_PEER: {
+ const AcceptPeerData* data;
+ if (GetMessagePayload(payload, payload_size, &data)) {
+ delegate_->OnAcceptPeer(remote_node_name_, data->token, data->peer_name,
+ data->port_name);
+ return;
+ }
+ break;
+ }
+
default:
break;
}
@@ -771,7 +801,6 @@ void NodeChannel::ProcessPendingMessagesWithMachPorts() {
pending_writes.swap(pending_write_messages_);
pending_relays.swap(pending_relay_messages_);
}
- DCHECK(pending_writes.empty() && pending_relays.empty());
while (!pending_writes.empty()) {
Channel::MessagePtr message = std::move(pending_writes.front());
diff --git a/mojo/edk/system/node_channel.h b/mojo/edk/system/node_channel.h
index 5a5fc8a..95dc341 100644
--- a/mojo/edk/system/node_channel.h
+++ b/mojo/edk/system/node_channel.h
@@ -16,6 +16,7 @@
#include "base/synchronization/lock.h"
#include "base/task_runner.h"
#include "build/build_config.h"
+#include "mojo/edk/embedder/connection_params.h"
#include "mojo/edk/embedder/embedder.h"
#include "mojo/edk/embedder/platform_handle_vector.h"
#include "mojo/edk/embedder/scoped_platform_handle.h"
@@ -76,7 +77,10 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
const ports::NodeName& source_node,
Channel::MessagePtr message) = 0;
#endif
-
+ virtual void OnAcceptPeer(const ports::NodeName& from_node,
+ const ports::NodeName& token,
+ const ports::NodeName& peer_name,
+ const ports::PortName& port_name) = 0;
virtual void OnChannelError(const ports::NodeName& node,
NodeChannel* channel) = 0;
@@ -87,7 +91,7 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
static scoped_refptr<NodeChannel> Create(
Delegate* delegate,
- ScopedPlatformHandle platform_handle,
+ ConnectionParams connection_params,
scoped_refptr<base::TaskRunner> io_task_runner,
const ProcessErrorCallback& process_error_callback);
@@ -124,6 +128,9 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
const ports::NodeName& token);
void AcceptParent(const ports::NodeName& token,
const ports::NodeName& child_name);
+ void AcceptPeer(const ports::NodeName& sender_name,
+ const ports::NodeName& token,
+ const ports::PortName& port_name);
void AddBrokerClient(const ports::NodeName& client_name,
base::ProcessHandle process_handle);
void BrokerClientAdded(const ports::NodeName& client_name,
@@ -161,7 +168,7 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
std::queue<std::pair<ports::NodeName, Channel::MessagePtr>>;
NodeChannel(Delegate* delegate,
- ScopedPlatformHandle platform_handle,
+ ConnectionParams connection_params,
scoped_refptr<base::TaskRunner> io_task_runner,
const ProcessErrorCallback& process_error_callback);
~NodeChannel() override;
diff --git a/mojo/edk/system/node_controller.cc b/mojo/edk/system/node_controller.cc
index 63291a5..7bdb571 100644
--- a/mojo/edk/system/node_controller.cc
+++ b/mojo/edk/system/node_controller.cc
@@ -18,6 +18,8 @@
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "mojo/edk/embedder/embedder_internal.h"
+#include "mojo/edk/embedder/named_platform_channel_pair.h"
+#include "mojo/edk/embedder/named_platform_handle.h"
#include "mojo/edk/embedder/platform_channel_pair.h"
#include "mojo/edk/system/broker.h"
#include "mojo/edk/system/broker_host.h"
@@ -58,7 +60,7 @@ void RecordPeerCount(size_t count) {
// 8k is the maximum number of file descriptors allowed in Chrome.
UMA_HISTOGRAM_CUSTOM_COUNTS("Mojo.System.Node.ConnectedPeers",
static_cast<int32_t>(count),
- 0 /* min */,
+ 1 /* min */,
8000 /* max */,
50 /* bucket count */);
}
@@ -69,7 +71,7 @@ void RecordPendingChildCount(size_t count) {
// 8k is the maximum number of file descriptors allowed in Chrome.
UMA_HISTOGRAM_CUSTOM_COUNTS("Mojo.System.Node.PendingChildren",
static_cast<int32_t>(count),
- 0 /* min */,
+ 1 /* min */,
8000 /* max */,
50 /* bucket count */);
}
@@ -163,7 +165,7 @@ void NodeController::SetIOTaskRunner(
void NodeController::ConnectToChild(
base::ProcessHandle process_handle,
- ScopedPlatformHandle platform_handle,
+ ConnectionParams connection_params,
const std::string& child_token,
const ProcessErrorCallback& process_error_callback) {
// Generate the temporary remote node name here so that it can be associated
@@ -194,13 +196,10 @@ void NodeController::ConnectToChild(
#endif
io_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&NodeController::ConnectToChildOnIOThread,
- base::Unretained(this),
- process_handle,
- base::Passed(&platform_handle),
- node_name,
- process_error_callback));
+ FROM_HERE, base::Bind(&NodeController::ConnectToChildOnIOThread,
+ base::Unretained(this), process_handle,
+ base::Passed(&connection_params), node_name,
+ process_error_callback));
}
void NodeController::CloseChildPorts(const std::string& child_token) {
@@ -227,14 +226,19 @@ void NodeController::CloseChildPorts(const std::string& child_token) {
AcceptIncomingMessages();
}
-void NodeController::ConnectToParent(ScopedPlatformHandle platform_handle) {
-// TODO(amistry): Consider the need for a broker on Windows.
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_NACL_SFI)
- // On posix, use the bootstrap channel for the broker and receive the node's
- // channel synchronously as the first message from the broker.
+void NodeController::ClosePeerConnection(const std::string& peer_token) {
+ io_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&NodeController::ClosePeerConnectionOnIOThread,
+ base::Unretained(this), peer_token));
+}
+
+void NodeController::ConnectToParent(ConnectionParams connection_params) {
+#if !defined(OS_MACOSX) && !defined(OS_NACL_SFI)
+ // Use the bootstrap channel for the broker and receive the node's channel
+ // synchronously as the first message from the broker.
base::ElapsedTimer timer;
- broker_.reset(new Broker(std::move(platform_handle)));
- platform_handle = broker_->GetParentPlatformHandle();
+ broker_.reset(new Broker(connection_params.TakeChannelHandle()));
+ ScopedPlatformHandle platform_handle = broker_->GetParentPlatformHandle();
UMA_HISTOGRAM_TIMES("Mojo.System.GetParentPlatformHandleSyncTime",
timer.Elapsed());
@@ -243,21 +247,33 @@ void NodeController::ConnectToParent(ScopedPlatformHandle platform_handle) {
// the broker was unable to negotiate a NodeChannel pipe. In this case we
// can cancel parent connection.
DVLOG(1) << "Cannot connect to invalid parent channel.";
+ CancelPendingPortMerges();
return;
}
+ connection_params = ConnectionParams(std::move(platform_handle));
#endif
io_task_runner_->PostTask(
FROM_HERE,
base::Bind(&NodeController::ConnectToParentOnIOThread,
- base::Unretained(this),
- base::Passed(&platform_handle)));
+ base::Unretained(this), base::Passed(&connection_params)));
}
-void NodeController::SetPortObserver(
- const ports::PortRef& port,
- const scoped_refptr<PortObserver>& observer) {
- node_->SetUserData(port, observer);
+void NodeController::ConnectToPeer(ConnectionParams connection_params,
+ const ports::PortRef& port,
+ const std::string& peer_token) {
+ ports::NodeName node_name;
+ GenerateRandomName(&node_name);
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&NodeController::ConnectToPeerOnIOThread,
+ base::Unretained(this), base::Passed(&connection_params),
+ node_name, port, peer_token));
+}
+
+void NodeController::SetPortObserver(const ports::PortRef& port,
+ scoped_refptr<PortObserver> observer) {
+ node_->SetUserData(port, std::move(observer));
}
void NodeController::ClosePort(const ports::PortRef& port) {
@@ -345,7 +361,7 @@ int NodeController::MergeLocalPorts(const ports::PortRef& port0,
scoped_refptr<PlatformSharedBuffer> NodeController::CreateSharedBuffer(
size_t num_bytes) {
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_NACL_SFI)
+#if !defined(OS_MACOSX) && !defined(OS_NACL_SFI)
// Shared buffer creation failure is fatal, so always use the broker when we
// have one. This does mean that a non-root process that has children will use
// the broker for shared buffer creation even though that process is
@@ -376,24 +392,40 @@ void NodeController::NotifyBadMessageFrom(const ports::NodeName& source_node,
void NodeController::ConnectToChildOnIOThread(
base::ProcessHandle process_handle,
- ScopedPlatformHandle platform_handle,
+ ConnectionParams connection_params,
ports::NodeName token,
const ProcessErrorCallback& process_error_callback) {
DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_NACL)
+#if !defined(OS_MACOSX) && !defined(OS_NACL)
PlatformChannelPair node_channel;
+ ScopedPlatformHandle server_handle = node_channel.PassServerHandle();
// BrokerHost owns itself.
- BrokerHost* broker_host = new BrokerHost(std::move(platform_handle));
- broker_host->SendChannel(node_channel.PassClientHandle());
- scoped_refptr<NodeChannel> channel = NodeChannel::Create(
- this, node_channel.PassServerHandle(), io_task_runner_,
- process_error_callback);
+ BrokerHost* broker_host =
+ new BrokerHost(process_handle, connection_params.TakeChannelHandle());
+ bool channel_ok = broker_host->SendChannel(node_channel.PassClientHandle());
+
+#if defined(OS_WIN)
+ if (!channel_ok) {
+ // On Windows the above operation may fail if the channel is crossing a
+ // session boundary. In that case we fall back to a named pipe.
+ NamedPlatformChannelPair named_channel;
+ server_handle = named_channel.PassServerHandle();
+ broker_host->SendNamedChannel(named_channel.handle().name);
+ }
#else
+ CHECK(channel_ok);
+#endif // defined(OS_WIN)
+
scoped_refptr<NodeChannel> channel =
- NodeChannel::Create(this, std::move(platform_handle), io_task_runner_,
+ NodeChannel::Create(this, ConnectionParams(std::move(server_handle)),
+ io_task_runner_, process_error_callback);
+
+#else // !defined(OS_MACOSX) && !defined(OS_NACL)
+ scoped_refptr<NodeChannel> channel =
+ NodeChannel::Create(this, std::move(connection_params), io_task_runner_,
process_error_callback);
-#endif
+#endif // !defined(OS_MACOSX) && !defined(OS_NACL)
// We set up the child channel with a temporary name so it can be identified
// as a pending child if it writes any messages to the channel. We may start
@@ -411,7 +443,7 @@ void NodeController::ConnectToChildOnIOThread(
}
void NodeController::ConnectToParentOnIOThread(
- ScopedPlatformHandle platform_handle) {
+ ConnectionParams connection_params) {
DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
{
@@ -422,7 +454,7 @@ void NodeController::ConnectToParentOnIOThread(
// into our |peers_| map. That will happen as soon as we receive an
// AcceptChild message from them.
bootstrap_parent_channel_ =
- NodeChannel::Create(this, std::move(platform_handle), io_task_runner_,
+ NodeChannel::Create(this, std::move(connection_params), io_task_runner_,
ProcessErrorCallback());
// Prevent the parent pipe handle from being closed on shutdown. Pipe
// closure is used by the parent to detect the child process has exited.
@@ -434,6 +466,37 @@ void NodeController::ConnectToParentOnIOThread(
bootstrap_parent_channel_->Start();
}
+void NodeController::ConnectToPeerOnIOThread(ConnectionParams connection_params,
+ ports::NodeName token,
+ ports::PortRef port,
+ const std::string& peer_token) {
+ DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
+
+ scoped_refptr<NodeChannel> channel = NodeChannel::Create(
+ this, std::move(connection_params), io_task_runner_, {});
+ peer_connections_.insert(
+ {token, PeerConnection{channel, port, peer_token}});
+ peers_by_token_.insert({peer_token, token});
+
+ channel->SetRemoteNodeName(token);
+ channel->Start();
+
+ channel->AcceptPeer(name_, token, port.name());
+}
+
+void NodeController::ClosePeerConnectionOnIOThread(
+ const std::string& peer_token) {
+ RequestContext request_context(RequestContext::Source::SYSTEM);
+ auto peer = peers_by_token_.find(peer_token);
+ // The connection may already be closed.
+ if (peer == peers_by_token_.end())
+ return;
+
+ // |peer| may be removed so make a copy of |name|.
+ ports::NodeName name = peer->second;
+ DropPeer(name, nullptr);
+}
+
scoped_refptr<NodeChannel> NodeController::GetPeerChannel(
const ports::NodeName& name) {
base::AutoLock lock(peers_lock_);
@@ -559,16 +622,18 @@ void NodeController::DropPeer(const ports::NodeName& name,
base::AutoLock lock(parent_lock_);
is_parent = (name == parent_name_ || channel == bootstrap_parent_channel_);
}
+
// If the error comes from the parent channel, we also need to cancel any
// port merge requests, so that errors can be propagated to the message
// pipes.
- if (is_parent) {
- base::AutoLock lock(pending_port_merges_lock_);
- reject_pending_merges_ = true;
+ if (is_parent)
+ CancelPendingPortMerges();
- for (const auto& port : pending_port_merges_)
- ports_to_close.push_back(port.second);
- pending_port_merges_.clear();
+ auto peer = peer_connections_.find(name);
+ if (peer != peer_connections_.end()) {
+ peers_by_token_.erase(peer->second.peer_token);
+ ports_to_close.push_back(peer->second.local_port);
+ peer_connections_.erase(peer);
}
for (const auto& port : ports_to_close)
@@ -652,20 +717,50 @@ void NodeController::SendPeerMessage(const ports::NodeName& name,
}
void NodeController::AcceptIncomingMessages() {
- {
- base::AutoLock lock(messages_lock_);
- if (!incoming_messages_.empty()) {
- // libstdc++'s deque creates an internal buffer on construction, even when
- // the size is 0. So avoid creating it until it is necessary.
- std::queue<ports::ScopedMessage> messages;
- std::swap(messages, incoming_messages_);
- base::AutoUnlock unlock(messages_lock_);
-
- while (!messages.empty()) {
- node_->AcceptMessage(std::move(messages.front()));
- messages.pop();
- }
+ // This is an impactically large value which should never be reached in
+ // practice. See the CHECK below for usage.
+ constexpr size_t kMaxAcceptedMessages = 1000000;
+
+ size_t num_messages_accepted = 0;
+ while (incoming_messages_flag_) {
+ // TODO: We may need to be more careful to avoid starving the rest of the
+ // thread here. Revisit this if it turns out to be a problem. One
+ // alternative would be to schedule a task to continue pumping messages
+ // after flushing once.
+
+ messages_lock_.Acquire();
+ if (incoming_messages_.empty()) {
+ messages_lock_.Release();
+ break;
}
+
+ // libstdc++'s deque creates an internal buffer on construction, even when
+ // the size is 0. So avoid creating it until it is necessary.
+ std::queue<ports::ScopedMessage> messages;
+ std::swap(messages, incoming_messages_);
+ incoming_messages_flag_.Set(false);
+ messages_lock_.Release();
+
+ num_messages_accepted += messages.size();
+ while (!messages.empty()) {
+ node_->AcceptMessage(std::move(messages.front()));
+ messages.pop();
+ }
+
+ // This is effectively a safeguard against potential bugs which might lead
+ // to runaway message cycles. If any such cycles arise, we'll start seeing
+ // crash reports from this location.
+ CHECK_LE(num_messages_accepted, kMaxAcceptedMessages);
+ }
+
+ if (num_messages_accepted >= 4) {
+ // Note: We avoid logging this histogram for the vast majority of cases.
+ // See https://crbug.com/685763 for more context.
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Mojo.System.MessagesAcceptedPerEvent",
+ static_cast<int32_t>(num_messages_accepted),
+ 1 /* min */,
+ 500 /* max */,
+ 50 /* bucket count */);
}
AttemptShutdownIfRequested();
@@ -712,6 +807,7 @@ void NodeController::DropAllPeers() {
peers_.clear();
pending_children_.clear();
pending_peer_messages_.clear();
+ peer_connections_.clear();
}
for (const auto& peer : all_peers)
@@ -746,6 +842,7 @@ void NodeController::ForwardMessage(const ports::NodeName& node,
!incoming_messages_task_posted_;
incoming_messages_task_posted_ |= schedule_pump_task;
incoming_messages_.emplace(std::move(message));
+ incoming_messages_flag_.Set(true);
} else {
SendPeerMessage(node, std::move(message));
}
@@ -896,9 +993,10 @@ void NodeController::OnAddBrokerClient(const ports::NodeName& from_node,
}
PlatformChannelPair broker_channel;
- scoped_refptr<NodeChannel> client = NodeChannel::Create(
- this, broker_channel.PassServerHandle(), io_task_runner_,
- ProcessErrorCallback());
+ ConnectionParams connection_params(broker_channel.PassServerHandle());
+ scoped_refptr<NodeChannel> client =
+ NodeChannel::Create(this, std::move(connection_params), io_task_runner_,
+ ProcessErrorCallback());
#if defined(OS_WIN)
// The broker must have a working handle to the client process in order to
@@ -974,8 +1072,9 @@ void NodeController::OnAcceptBrokerClient(const ports::NodeName& from_node,
broker = parent;
} else {
DCHECK(broker_channel.is_valid());
- broker = NodeChannel::Create(this, std::move(broker_channel),
- io_task_runner_, ProcessErrorCallback());
+ broker =
+ NodeChannel::Create(this, ConnectionParams(std::move(broker_channel)),
+ io_task_runner_, ProcessErrorCallback());
AddPeer(broker_name, broker, true /* start_channel */);
}
@@ -1096,15 +1195,15 @@ void NodeController::OnIntroduce(const ports::NodeName& from_node,
if (!channel_handle.is_valid()) {
node_->LostConnectionToNode(name);
- DLOG(ERROR) << "Could not be introduced to peer " << name;
+ DVLOG(1) << "Could not be introduced to peer " << name;
base::AutoLock lock(peers_lock_);
pending_peer_messages_.erase(name);
return;
}
scoped_refptr<NodeChannel> channel =
- NodeChannel::Create(this, std::move(channel_handle), io_task_runner_,
- ProcessErrorCallback());
+ NodeChannel::Create(this, ConnectionParams(std::move(channel_handle)),
+ io_task_runner_, ProcessErrorCallback());
DVLOG(1) << "Adding new peer " << name << " via parent introduction.";
AddPeer(name, channel, true /* start_channel */);
@@ -1219,6 +1318,46 @@ void NodeController::OnPortsMessageFromRelay(const ports::NodeName& from_node,
}
#endif
+void NodeController::OnAcceptPeer(const ports::NodeName& from_node,
+ const ports::NodeName& token,
+ const ports::NodeName& peer_name,
+ const ports::PortName& port_name) {
+ DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
+
+ auto it = peer_connections_.find(from_node);
+ if (it == peer_connections_.end()) {
+ DLOG(ERROR) << "Received unexpected AcceptPeer message from " << from_node;
+ DropPeer(from_node, nullptr);
+ return;
+ }
+
+ scoped_refptr<NodeChannel> channel = std::move(it->second.channel);
+ ports::PortRef local_port = it->second.local_port;
+ std::string peer_token = std::move(it->second.peer_token);
+ peer_connections_.erase(it);
+ DCHECK(channel);
+
+ // If the peer connection is a self connection (which is used in tests),
+ // drop the channel to it and skip straight to merging the ports.
+ if (name_ == peer_name) {
+ peers_by_token_.erase(peer_token);
+ } else {
+ peers_by_token_[peer_token] = peer_name;
+ peer_connections_.insert(
+ {peer_name, PeerConnection{nullptr, local_port, peer_token}});
+ DVLOG(1) << "Node " << name_ << " accepted peer " << peer_name;
+
+ AddPeer(peer_name, channel, false /* start_channel */);
+ }
+
+ // We need to choose one side to initiate the port merge. It doesn't matter
+ // who does it as long as they don't both try. Simple solution: pick the one
+ // with the "smaller" port name.
+ if (local_port.name() < port_name) {
+ node()->MergePorts(local_port, peer_name, port_name);
+ }
+}
+
void NodeController::OnChannelError(const ports::NodeName& from_node,
NodeChannel* channel) {
if (io_task_runner_->RunsTasksOnCurrentThread()) {
@@ -1248,6 +1387,21 @@ MachPortRelay* NodeController::GetMachPortRelay() {
}
#endif
+void NodeController::CancelPendingPortMerges() {
+ std::vector<ports::PortRef> ports_to_close;
+
+ {
+ base::AutoLock lock(pending_port_merges_lock_);
+ reject_pending_merges_ = true;
+ for (const auto& port : pending_port_merges_)
+ ports_to_close.push_back(port.second);
+ pending_port_merges_.clear();
+ }
+
+ for (const auto& port : ports_to_close)
+ node_->ClosePort(port);
+}
+
void NodeController::DestroyOnIOThreadShutdown() {
destroy_on_io_thread_shutdown_ = true;
}
@@ -1261,7 +1415,8 @@ void NodeController::AttemptShutdownIfRequested() {
base::AutoLock lock(shutdown_lock_);
if (shutdown_callback_.is_null())
return;
- if (!node_->CanShutdownCleanly(true /* allow_local_ports */)) {
+ if (!node_->CanShutdownCleanly(
+ ports::Node::ShutdownPolicy::ALLOW_LOCAL_PORTS)) {
DVLOG(2) << "Unable to cleanly shut down node " << name_;
return;
}
@@ -1276,5 +1431,29 @@ void NodeController::AttemptShutdownIfRequested() {
callback.Run();
}
+NodeController::PeerConnection::PeerConnection() = default;
+
+NodeController::PeerConnection::PeerConnection(
+ const PeerConnection& other) = default;
+
+NodeController::PeerConnection::PeerConnection(
+ PeerConnection&& other) = default;
+
+NodeController::PeerConnection::PeerConnection(
+ scoped_refptr<NodeChannel> channel,
+ const ports::PortRef& local_port,
+ const std::string& peer_token)
+ : channel(std::move(channel)),
+ local_port(local_port),
+ peer_token(peer_token) {}
+
+NodeController::PeerConnection::~PeerConnection() = default;
+
+NodeController::PeerConnection& NodeController::PeerConnection::
+operator=(const PeerConnection& other) = default;
+
+NodeController::PeerConnection& NodeController::PeerConnection::
+operator=(PeerConnection&& other) = default;
+
} // namespace edk
} // namespace mojo
diff --git a/mojo/edk/system/node_controller.h b/mojo/edk/system/node_controller.h
index 11d5f19..46a2d61 100644
--- a/mojo/edk/system/node_controller.h
+++ b/mojo/edk/system/node_controller.h
@@ -73,7 +73,7 @@ class NodeController : public ports::NodeDelegate,
// Connects this node to a child node. This node will initiate a handshake.
void ConnectToChild(base::ProcessHandle process_handle,
- ScopedPlatformHandle platform_handle,
+ ConnectionParams connection_params,
const std::string& child_token,
const ProcessErrorCallback& process_error_callback);
@@ -81,14 +81,23 @@ class NodeController : public ports::NodeDelegate,
// |child_token|.
void CloseChildPorts(const std::string& child_token);
+ // Close a connection to a peer associated with |peer_token|.
+ void ClosePeerConnection(const std::string& peer_token);
+
// Connects this node to a parent node. The parent node will initiate a
// handshake.
- void ConnectToParent(ScopedPlatformHandle platform_handle);
+ void ConnectToParent(ConnectionParams connection_params);
+
+ // Connects this node to a peer node. On success, |port| will be merged with
+ // the corresponding port in the peer node.
+ void ConnectToPeer(ConnectionParams connection_params,
+ const ports::PortRef& port,
+ const std::string& peer_token);
// Sets a port's observer. If |observer| is null the port's current observer
// is removed.
void SetPortObserver(const ports::PortRef& port,
- const scoped_refptr<PortObserver>& observer);
+ scoped_refptr<PortObserver> observer);
// Closes a port. Use this in lieu of calling Node::ClosePort() directly, as
// it ensures the port's observer has also been removed.
@@ -139,12 +148,36 @@ class NodeController : public ports::NodeDelegate,
const std::string child_token;
};
+ struct PeerConnection {
+ PeerConnection();
+ PeerConnection(const PeerConnection& other);
+ PeerConnection(PeerConnection&& other);
+ PeerConnection(scoped_refptr<NodeChannel> channel,
+ const ports::PortRef& local_port,
+ const std::string& peer_token);
+ ~PeerConnection();
+
+ PeerConnection& operator=(const PeerConnection& other);
+ PeerConnection& operator=(PeerConnection&& other);
+
+
+ scoped_refptr<NodeChannel> channel;
+ ports::PortRef local_port;
+ std::string peer_token;
+ };
+
void ConnectToChildOnIOThread(
base::ProcessHandle process_handle,
- ScopedPlatformHandle platform_handle,
+ ConnectionParams connection_params,
ports::NodeName token,
const ProcessErrorCallback& process_error_callback);
- void ConnectToParentOnIOThread(ScopedPlatformHandle platform_handle);
+ void ConnectToParentOnIOThread(ConnectionParams connection_params);
+
+ void ConnectToPeerOnIOThread(ConnectionParams connection_params,
+ ports::NodeName token,
+ ports::PortRef port,
+ const std::string& peer_token);
+ void ClosePeerConnectionOnIOThread(const std::string& node_name);
scoped_refptr<NodeChannel> GetPeerChannel(const ports::NodeName& name);
scoped_refptr<NodeChannel> GetParentChannel();
@@ -206,12 +239,21 @@ class NodeController : public ports::NodeDelegate,
const ports::NodeName& source_node,
Channel::MessagePtr message) override;
#endif
+ void OnAcceptPeer(const ports::NodeName& from_node,
+ const ports::NodeName& token,
+ const ports::NodeName& peer_name,
+ const ports::PortName& port_name) override;
void OnChannelError(const ports::NodeName& from_node,
NodeChannel* channel) override;
#if defined(OS_MACOSX) && !defined(OS_IOS)
MachPortRelay* GetMachPortRelay() override;
#endif
+ // Cancels all pending port merges. These are merges which are supposed to
+ // be requested from the parent ASAP, and they may be cancelled if the
+ // connection to the parent is broken or never established.
+ void CancelPendingPortMerges();
+
// Marks this NodeController for destruction when the IO thread shuts down.
// This is used in case Core is torn down before the IO thread. Must only be
// called on the IO thread.
@@ -286,6 +328,8 @@ class NodeController : public ports::NodeDelegate,
// Ensures that there is only one incoming messages task posted to the IO
// thread.
bool incoming_messages_task_posted_ = false;
+ // Flag to fast-path checking |incoming_messages_|.
+ AtomicFlag incoming_messages_flag_;
// Guards |shutdown_callback_|.
base::Lock shutdown_lock_;
@@ -303,12 +347,19 @@ class NodeController : public ports::NodeDelegate,
// Channels to children during handshake.
NodeMap pending_children_;
+ using PeerNodeMap =
+ std::unordered_map<ports::NodeName, PeerConnection>;
+ PeerNodeMap peer_connections_;
+
+ // Maps from peer token to node name, pending or not.
+ std::unordered_map<std::string, ports::NodeName> peers_by_token_;
+
// Indicates whether this object should delete itself on IO thread shutdown.
// Must only be accessed from the IO thread.
bool destroy_on_io_thread_shutdown_ = false;
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_NACL_SFI)
- // Broker for sync shared buffer creation (non-Mac posix-only) in children.
+#if !defined(OS_MACOSX) && !defined(OS_NACL_SFI)
+ // Broker for sync shared buffer creation in children.
std::unique_ptr<Broker> broker_;
#endif
diff --git a/mojo/edk/system/platform_handle_dispatcher_unittest.cc b/mojo/edk/system/platform_handle_dispatcher_unittest.cc
index ad6dc38..7a94262 100644
--- a/mojo/edk/system/platform_handle_dispatcher_unittest.cc
+++ b/mojo/edk/system/platform_handle_dispatcher_unittest.cc
@@ -28,7 +28,7 @@ TEST(PlatformHandleDispatcherTest, Basic) {
base::FilePath unused;
base::ScopedFILE fp(
- CreateAndOpenTemporaryFileInDir(temp_dir.path(), &unused));
+ CreateAndOpenTemporaryFileInDir(temp_dir.GetPath(), &unused));
ASSERT_TRUE(fp);
EXPECT_EQ(sizeof(kHelloWorld),
fwrite(kHelloWorld, 1, sizeof(kHelloWorld), fp.get()));
@@ -70,7 +70,7 @@ TEST(PlatformHandleDispatcherTest, Serialization) {
base::FilePath unused;
base::ScopedFILE fp(
- CreateAndOpenTemporaryFileInDir(temp_dir.path(), &unused));
+ CreateAndOpenTemporaryFileInDir(temp_dir.GetPath(), &unused));
EXPECT_EQ(sizeof(kFooBar), fwrite(kFooBar, 1, sizeof(kFooBar), fp.get()));
scoped_refptr<PlatformHandleDispatcher> dispatcher =
diff --git a/mojo/edk/system/ports/BUILD.gn b/mojo/edk/system/ports/BUILD.gn
index 239b3a4..37b2548 100644
--- a/mojo/edk/system/ports/BUILD.gn
+++ b/mojo/edk/system/ports/BUILD.gn
@@ -10,6 +10,7 @@ source_set("ports") {
"event.h",
"message.cc",
"message.h",
+ "message_filter.h",
"message_queue.cc",
"message_queue.h",
"name.cc",
diff --git a/mojo/edk/system/ports/message_filter.h b/mojo/edk/system/ports/message_filter.h
new file mode 100644
index 0000000..bf8fa21
--- /dev/null
+++ b/mojo/edk/system/ports/message_filter.h
@@ -0,0 +1,29 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_EDK_SYSTEM_PORTS_MESSAGE_FILTER_H_
+#define MOJO_EDK_SYSTEM_PORTS_MESSAGE_FILTER_H_
+
+namespace mojo {
+namespace edk {
+namespace ports {
+
+class Message;
+
+// An interface which can be implemented to filter port messages according to
+// arbitrary policy.
+class MessageFilter {
+ public:
+ virtual ~MessageFilter() {}
+
+ // Returns true of |message| should be accepted by whomever is applying this
+ // filter. See MessageQueue::GetNextMessage(), for example.
+ virtual bool Match(const Message& message) = 0;
+};
+
+} // namespace ports
+} // namespace edk
+} // namespace mojo
+
+#endif // MOJO_EDK_SYSTEM_PORTS_MESSAGE_FILTER_H_
diff --git a/mojo/edk/system/ports/message_queue.cc b/mojo/edk/system/ports/message_queue.cc
index ef2e940..defb1b6 100644
--- a/mojo/edk/system/ports/message_queue.cc
+++ b/mojo/edk/system/ports/message_queue.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "mojo/edk/system/ports/event.h"
+#include "mojo/edk/system/ports/message_filter.h"
namespace mojo {
namespace edk {
@@ -44,10 +45,9 @@ bool MessageQueue::HasNextMessage() const {
return !heap_.empty() && GetSequenceNum(heap_[0]) == next_sequence_num_;
}
-void MessageQueue::GetNextMessageIf(
- std::function<bool(const Message&)> selector,
- ScopedMessage* message) {
- if (!HasNextMessage() || (selector && !selector(*heap_[0].get()))) {
+void MessageQueue::GetNextMessage(ScopedMessage* message,
+ MessageFilter* filter) {
+ if (!HasNextMessage() || (filter && !filter->Match(*heap_[0].get()))) {
message->reset();
return;
}
diff --git a/mojo/edk/system/ports/message_queue.h b/mojo/edk/system/ports/message_queue.h
index d90ac1a..d9a47ed 100644
--- a/mojo/edk/system/ports/message_queue.h
+++ b/mojo/edk/system/ports/message_queue.h
@@ -22,6 +22,8 @@ namespace ports {
const uint64_t kInitialSequenceNum = 1;
const uint64_t kInvalidSequenceNum = std::numeric_limits<uint64_t>::max();
+class MessageFilter;
+
// An incoming message queue for a port. MessageQueue keeps track of the highest
// known sequence number and can indicate whether the next sequential message is
// available. Thus the queue enforces message ordering for the consumer without
@@ -38,9 +40,9 @@ class MessageQueue {
bool HasNextMessage() const;
- // Gives ownership of the message. The selector may be null.
- void GetNextMessageIf(std::function<bool(const Message&)> selector,
- ScopedMessage* message);
+ // Gives ownership of the message. If |filter| is non-null, the next message
+ // will only be retrieved if the filter successfully matches it.
+ void GetNextMessage(ScopedMessage* message, MessageFilter* filter);
// Takes ownership of the message. Note: Messages are ordered, so while we
// have added a message to the queue, we may still be waiting on a message
diff --git a/mojo/edk/system/ports/name.cc b/mojo/edk/system/ports/name.cc
index 7088cbf..ea17698 100644
--- a/mojo/edk/system/ports/name.cc
+++ b/mojo/edk/system/ports/name.cc
@@ -8,6 +8,10 @@ namespace mojo {
namespace edk {
namespace ports {
+extern const PortName kInvalidPortName = {0, 0};
+
+extern const NodeName kInvalidNodeName = {0, 0};
+
std::ostream& operator<<(std::ostream& stream, const Name& name) {
std::ios::fmtflags flags(stream.flags());
stream << std::hex << std::uppercase << name.v1;
diff --git a/mojo/edk/system/ports/name.h b/mojo/edk/system/ports/name.h
index 1082719..72e41b9 100644
--- a/mojo/edk/system/ports/name.h
+++ b/mojo/edk/system/ports/name.h
@@ -40,14 +40,14 @@ struct PortName : Name {
PortName(uint64_t v1, uint64_t v2) : Name(v1, v2) {}
};
-const PortName kInvalidPortName = {0, 0};
+extern const PortName kInvalidPortName;
struct NodeName : Name {
NodeName() : Name(0, 0) {}
NodeName(uint64_t v1, uint64_t v2) : Name(v1, v2) {}
};
-const NodeName kInvalidNodeName = {0, 0};
+extern const NodeName kInvalidNodeName;
} // namespace ports
} // namespace edk
diff --git a/mojo/edk/system/ports/node.cc b/mojo/edk/system/ports/node.cc
index 128ecdf..9c6f1fd 100644
--- a/mojo/edk/system/ports/node.cc
+++ b/mojo/edk/system/ports/node.cc
@@ -8,6 +8,7 @@
#include <utility>
+#include "base/atomicops.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
@@ -64,10 +65,10 @@ Node::~Node() {
DLOG(WARNING) << "Unclean shutdown for node " << name_;
}
-bool Node::CanShutdownCleanly(bool allow_local_ports) {
+bool Node::CanShutdownCleanly(ShutdownPolicy policy) {
base::AutoLock ports_lock(ports_lock_);
- if (!allow_local_ports) {
+ if (policy == ShutdownPolicy::DONT_ALLOW_LOCAL_PORTS) {
#if DCHECK_IS_ON()
for (auto entry : ports_) {
DVLOG(2) << "Port " << entry.first << " referencing node "
@@ -78,6 +79,8 @@ bool Node::CanShutdownCleanly(bool allow_local_ports) {
return ports_.empty();
}
+ DCHECK_EQ(policy, ShutdownPolicy::ALLOW_LOCAL_PORTS);
+
// NOTE: This is not efficient, though it probably doesn't need to be since
// relatively few ports should be open during shutdown and shutdown doesn't
// need to be blazingly fast.
@@ -114,8 +117,7 @@ int Node::CreateUninitializedPort(PortRef* port_ref) {
PortName port_name;
delegate_->GenerateRandomPortName(&port_name);
- scoped_refptr<Port> port = make_scoped_refptr(new Port(kInitialSequenceNum,
- kInitialSequenceNum));
+ scoped_refptr<Port> port(new Port(kInitialSequenceNum, kInitialSequenceNum));
int rv = AddPortWithName(port_name, port);
if (rv != OK)
return rv;
@@ -167,7 +169,7 @@ int Node::CreatePortPair(PortRef* port0_ref, PortRef* port1_ref) {
}
int Node::SetUserData(const PortRef& port_ref,
- const scoped_refptr<UserData>& user_data) {
+ scoped_refptr<UserData> user_data) {
Port* port = port_ref.port();
base::AutoLock lock(port->lock);
@@ -261,16 +263,12 @@ int Node::GetStatus(const PortRef& port_ref, PortStatus* port_status) {
return OK;
}
-int Node::GetMessage(const PortRef& port_ref, ScopedMessage* message) {
- return GetMessageIf(port_ref, nullptr, message);
-}
-
-int Node::GetMessageIf(const PortRef& port_ref,
- std::function<bool(const Message&)> selector,
- ScopedMessage* message) {
+int Node::GetMessage(const PortRef& port_ref,
+ ScopedMessage* message,
+ MessageFilter* filter) {
*message = nullptr;
- DVLOG(2) << "GetMessageIf for " << port_ref.name() << "@" << name_;
+ DVLOG(4) << "GetMessage for " << port_ref.name() << "@" << name_;
Port* port = port_ref.port();
{
@@ -286,7 +284,7 @@ int Node::GetMessageIf(const PortRef& port_ref,
if (!CanAcceptMoreMessages(port))
return ERROR_PORT_PEER_CLOSED;
- port->message_queue.GetNextMessageIf(std::move(selector), message);
+ port->message_queue.GetNextMessage(message, filter);
}
// Allow referenced ports to trigger PortStatusChanged calls.
@@ -426,7 +424,7 @@ int Node::OnUserMessage(ScopedMessage message) {
ports_buf << message->ports()[i];
}
- DVLOG(2) << "AcceptMessage " << event->sequence_num
+ DVLOG(4) << "AcceptMessage " << event->sequence_num
<< " [ports=" << ports_buf.str() << "] at "
<< port_name << "@" << name_;
#endif
@@ -506,7 +504,7 @@ int Node::OnPortAccepted(const PortName& port_name) {
<< " pointing to "
<< port->peer_port_name << "@" << port->peer_node_name;
- return BeginProxying(PortRef(port_name, port));
+ return BeginProxying(PortRef(port_name, std::move(port)));
}
int Node::OnObserveProxy(const PortName& port_name,
@@ -531,17 +529,6 @@ int Node::OnObserveProxy(const PortName& port_name,
scoped_refptr<Port> port = GetPort(port_name);
if (!port) {
DVLOG(1) << "ObserveProxy: " << port_name << "@" << name_ << " not found";
-
- if (port_name != event.proxy_port_name &&
- port_name != event.proxy_to_port_name) {
- // The receiving port may have been removed while this message was in
- // transit. In this case, we restart the ObserveProxy circulation from
- // the referenced proxy port to avoid leaking the proxy.
- delegate_->ForwardMessage(
- event.proxy_node_name,
- NewInternalMessage(
- event.proxy_port_name, EventType::kObserveProxy, event));
- }
return OK;
}
@@ -632,7 +619,7 @@ int Node::OnObserveProxyAck(const PortName& port_name,
port->remove_proxy_on_last_message = true;
port->last_sequence_num_to_receive = last_sequence_num;
}
- TryRemoveProxy(PortRef(port_name, port));
+ TryRemoveProxy(PortRef(port_name, std::move(port)));
return OK;
}
@@ -709,7 +696,7 @@ int Node::OnObserveClosure(const PortName& port_name,
forwarded_data));
if (notify_delegate) {
- PortRef port_ref(port_name, port);
+ PortRef port_ref(port_name, std::move(port));
delegate_->PortStatusChanged(port_ref);
}
return OK;
@@ -784,11 +771,10 @@ int Node::OnMergePort(const PortName& port_name,
return ERROR_PORT_STATE_UNEXPECTED;
}
-int Node::AddPortWithName(const PortName& port_name,
- const scoped_refptr<Port>& port) {
+int Node::AddPortWithName(const PortName& port_name, scoped_refptr<Port> port) {
base::AutoLock lock(ports_lock_);
- if (!ports_.insert(std::make_pair(port_name, port)).second)
+ if (!ports_.insert(std::make_pair(port_name, std::move(port))).second)
return OOPS(ERROR_PORT_EXISTS); // Suggests a bad UUID generator.
DVLOG(2) << "Created port " << port_name << "@" << name_;
@@ -817,6 +803,11 @@ scoped_refptr<Port> Node::GetPort_Locked(const PortName& port_name) {
if (iter == ports_.end())
return nullptr;
+#if defined(OS_ANDROID) && defined(ARCH_CPU_ARM64)
+ // Workaround for https://crbug.com/665869.
+ base::subtle::MemoryBarrier();
+#endif
+
return iter->second;
}
@@ -1003,10 +994,10 @@ int Node::AcceptPort(const PortName& port_name,
<< port->last_sequence_num_to_receive << "]";
// A newly accepted port is not signalable until the message referencing the
- // new port finds its way to the consumer (see GetMessageIf).
+ // new port finds its way to the consumer (see GetMessage).
port->message_queue.set_signalable(false);
- int rv = AddPortWithName(port_name, port);
+ int rv = AddPortWithName(port_name, std::move(port));
if (rv != OK)
return rv;
@@ -1087,7 +1078,7 @@ int Node::WillSendMessage_Locked(const LockedPort& port,
}
#if DCHECK_IS_ON()
- DVLOG(2) << "Sending message "
+ DVLOG(4) << "Sending message "
<< GetEventData<UserEventData>(*message)->sequence_num
<< " [ports=" << ports_buf.str() << "]"
<< " from " << port_name << "@" << name_
@@ -1185,7 +1176,7 @@ int Node::ForwardMessages_Locked(const LockedPort& port,
for (;;) {
ScopedMessage message;
- port->message_queue.GetNextMessageIf(nullptr, &message);
+ port->message_queue.GetNextMessage(&message, nullptr);
if (!message)
break;
diff --git a/mojo/edk/system/ports/node.h b/mojo/edk/system/ports/node.h
index 3aeadca..55b8d27 100644
--- a/mojo/edk/system/ports/node.h
+++ b/mojo/edk/system/ports/node.h
@@ -44,10 +44,16 @@ struct PortStatus {
bool peer_closed;
};
+class MessageFilter;
class NodeDelegate;
class Node {
public:
+ enum class ShutdownPolicy {
+ DONT_ALLOW_LOCAL_PORTS,
+ ALLOW_LOCAL_PORTS,
+ };
+
// Does not take ownership of the delegate.
Node(const NodeName& name, NodeDelegate* delegate);
~Node();
@@ -59,9 +65,11 @@ class Node {
// method may be called again after AcceptMessage to check if the Node is now
// ready to be destroyed.
//
- // If |allow_local_ports| is |true|, this will only return |false| when there
- // are transient ports referring to other nodes.
- bool CanShutdownCleanly(bool allow_local_ports);
+ // If |policy| is set to |ShutdownPolicy::ALLOW_LOCAL_PORTS|, this will return
+ // |true| even if some ports remain alive, as long as none of them are proxies
+ // to another node.
+ bool CanShutdownCleanly(
+ ShutdownPolicy policy = ShutdownPolicy::DONT_ALLOW_LOCAL_PORTS);
// Lookup the named port.
int GetPort(const PortName& port_name, PortRef* port_ref);
@@ -82,8 +90,7 @@ class Node {
int CreatePortPair(PortRef* port0_ref, PortRef* port1_ref);
// User data associated with the port.
- int SetUserData(const PortRef& port_ref,
- const scoped_refptr<UserData>& user_data);
+ int SetUserData(const PortRef& port_ref, scoped_refptr<UserData> user_data);
int GetUserData(const PortRef& port_ref,
scoped_refptr<UserData>* user_data);
@@ -100,15 +107,15 @@ class Node {
// indicate that this port's peer has closed. In such cases GetMessage may
// be called until it yields a null message, indicating that no more messages
// may be read from the port.
- int GetMessage(const PortRef& port_ref, ScopedMessage* message);
-
- // Like GetMessage, but the caller may optionally supply a selector function
- // that decides whether or not to return the message. If |selector| is a
- // nullptr, then GetMessageIf acts just like GetMessage. The |selector| may
- // not call any Node methods.
- int GetMessageIf(const PortRef& port_ref,
- std::function<bool(const Message&)> selector,
- ScopedMessage* message);
+ //
+ // If |filter| is non-null, the next available message is returned only if it
+ // is matched by the filter. If the provided filter does not match the next
+ // available message, GetMessage() behaves as if there is no message
+ // available. Ownership of |filter| is not taken, and it must outlive the
+ // extent of this call.
+ int GetMessage(const PortRef& port_ref,
+ ScopedMessage* message,
+ MessageFilter* filter);
// Sends a message from the specified port to its peer. Note that the message
// notification may arrive synchronously (via PortStatusChanged() on the
@@ -156,8 +163,7 @@ class Node {
int OnObserveClosure(const PortName& port_name, uint64_t last_sequence_num);
int OnMergePort(const PortName& port_name, const MergePortEventData& event);
- int AddPortWithName(const PortName& port_name,
- const scoped_refptr<Port>& port);
+ int AddPortWithName(const PortName& port_name, scoped_refptr<Port> port);
void ErasePort(const PortName& port_name);
void ErasePort_Locked(const PortName& port_name);
scoped_refptr<Port> GetPort(const PortName& port_name);
diff --git a/mojo/edk/system/ports/port_ref.cc b/mojo/edk/system/ports/port_ref.cc
index bd59629..675754d 100644
--- a/mojo/edk/system/ports/port_ref.cc
+++ b/mojo/edk/system/ports/port_ref.cc
@@ -16,9 +16,8 @@ PortRef::~PortRef() {
PortRef::PortRef() {
}
-PortRef::PortRef(const PortName& name, const scoped_refptr<Port>& port)
- : name_(name), port_(port) {
-}
+PortRef::PortRef(const PortName& name, scoped_refptr<Port> port)
+ : name_(name), port_(std::move(port)) {}
PortRef::PortRef(const PortRef& other)
: name_(other.name_), port_(other.port_) {
diff --git a/mojo/edk/system/ports/port_ref.h b/mojo/edk/system/ports/port_ref.h
index 9af4a8d..59036c3 100644
--- a/mojo/edk/system/ports/port_ref.h
+++ b/mojo/edk/system/ports/port_ref.h
@@ -19,7 +19,7 @@ class PortRef {
public:
~PortRef();
PortRef();
- PortRef(const PortName& name, const scoped_refptr<Port>& port);
+ PortRef(const PortName& name, scoped_refptr<Port> port);
PortRef(const PortRef& other);
PortRef& operator=(const PortRef& other);
diff --git a/mojo/edk/system/ports/ports_unittest.cc b/mojo/edk/system/ports/ports_unittest.cc
index 200e72b..cb48b3e 100644
--- a/mojo/edk/system/ports/ports_unittest.cc
+++ b/mojo/edk/system/ports/ports_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -9,9 +10,18 @@
#include <map>
#include <queue>
#include <sstream>
+#include <utility>
+#include "base/bind.h"
+#include "base/callback.h"
#include "base/logging.h"
+#include "base/memory/ref_counted.h"
#include "base/rand_util.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
#include "mojo/edk/system/ports/event.h"
#include "mojo/edk/system/ports/node.h"
#include "mojo/edk/system/ports/node_delegate.h"
@@ -24,24 +34,8 @@ namespace test {
namespace {
-void LogMessage(const Message* message) {
- std::stringstream ports;
- for (size_t i = 0; i < message->num_ports(); ++i) {
- if (i > 0)
- ports << ",";
- ports << message->ports()[i];
- }
- DVLOG(1) << "message: \""
- << static_cast<const char*>(message->payload_bytes())
- << "\" ports=[" << ports.str() << "]";
-}
-
-void ClosePortsInMessage(Node* node, Message* message) {
- for (size_t i = 0; i < message->num_ports(); ++i) {
- PortRef port;
- ASSERT_EQ(OK, node->GetPort(message->ports()[i], &port));
- EXPECT_EQ(OK, node->ClosePort(port));
- }
+bool MessageEquals(const ScopedMessage& message, const base::StringPiece& s) {
+ return !strcmp(static_cast<const char*>(message->payload_bytes()), s.data());
}
class TestMessage : public Message {
@@ -71,132 +65,140 @@ class TestMessage : public Message {
}
};
-struct Task {
- Task(NodeName node_name, ScopedMessage message)
- : node_name(node_name),
- message(std::move(message)),
- priority(base::RandUint64()) {
- }
+class TestNode;
- NodeName node_name;
- ScopedMessage message;
- uint64_t priority;
+class MessageRouter {
+ public:
+ virtual ~MessageRouter() {}
+
+ virtual void GeneratePortName(PortName* name) = 0;
+ virtual void ForwardMessage(TestNode* from_node,
+ const NodeName& node_name,
+ ScopedMessage message) = 0;
+ virtual void BroadcastMessage(TestNode* from_node, ScopedMessage message) = 0;
};
-struct TaskComparator {
- bool operator()(const Task* a, const Task* b) {
- return a->priority < b->priority;
+class TestNode : public NodeDelegate {
+ public:
+ explicit TestNode(uint64_t id)
+ : node_name_(id, 1),
+ node_(node_name_, this),
+ node_thread_(base::StringPrintf("Node %" PRIu64 " thread", id)),
+ messages_available_event_(
+ base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED),
+ idle_event_(
+ base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::SIGNALED) {
}
-};
-const size_t kMaxNodes = 3;
+ ~TestNode() override {
+ StopWhenIdle();
+ node_thread_.Stop();
+ }
-std::priority_queue<Task*, std::vector<Task*>, TaskComparator> task_queue;
-Node* node_map[kMaxNodes];
+ const NodeName& name() const { return node_name_; }
-Node* GetNode(const NodeName& name) {
- return node_map[name.v1];
-}
+ // NOTE: Node is thread-safe.
+ Node& node() { return node_; }
-void SetNode(const NodeName& name, Node* node) {
- node_map[name.v1] = node;
-}
-
-void PumpTasks() {
- while (!task_queue.empty()) {
- Task* task = task_queue.top();
- task_queue.pop();
+ base::WaitableEvent& idle_event() { return idle_event_; }
- Node* node = GetNode(task->node_name);
- if (node)
- node->AcceptMessage(std::move(task->message));
+ bool IsIdle() {
+ base::AutoLock lock(lock_);
+ return started_ && !dispatching_ &&
+ (incoming_messages_.empty() || (block_on_event_ && blocked_));
+ }
- delete task;
+ void BlockOnEvent(EventType type) {
+ base::AutoLock lock(lock_);
+ blocked_event_type_ = type;
+ block_on_event_ = true;
}
-}
-void PumpUntilTask(EventType type) {
- while (!task_queue.empty()) {
- Task* task = task_queue.top();
+ void Unblock() {
+ base::AutoLock lock(lock_);
+ block_on_event_ = false;
+ messages_available_event_.Signal();
+ }
- const EventHeader* header = GetEventHeader(*task->message);
- if (header->type == type)
- return;
+ void Start(MessageRouter* router) {
+ router_ = router;
+ node_thread_.Start();
+ node_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&TestNode::ProcessMessages, base::Unretained(this)));
+ }
- task_queue.pop();
+ void StopWhenIdle() {
+ base::AutoLock lock(lock_);
+ should_quit_ = true;
+ messages_available_event_.Signal();
+ }
- Node* node = GetNode(task->node_name);
- if (node)
- node->AcceptMessage(std::move(task->message));
+ void WakeUp() { messages_available_event_.Signal(); }
- delete task;
+ int SendStringMessage(const PortRef& port, const std::string& s) {
+ size_t size = s.size() + 1;
+ ScopedMessage message = TestMessage::NewUserMessage(size, 0);
+ memcpy(message->mutable_payload_bytes(), s.data(), size);
+ return node_.SendMessage(port, std::move(message));
}
-}
-void DiscardPendingTasks() {
- while (!task_queue.empty()) {
- Task* task = task_queue.top();
- task_queue.pop();
- delete task;
+ int SendStringMessageWithPort(const PortRef& port,
+ const std::string& s,
+ const PortName& sent_port_name) {
+ size_t size = s.size() + 1;
+ ScopedMessage message = TestMessage::NewUserMessage(size, 1);
+ memcpy(message->mutable_payload_bytes(), s.data(), size);
+ message->mutable_ports()[0] = sent_port_name;
+ return node_.SendMessage(port, std::move(message));
}
-}
-
-int SendStringMessage(Node* node, const PortRef& port, const std::string& s) {
- size_t size = s.size() + 1;
- ScopedMessage message = TestMessage::NewUserMessage(size, 0);
- memcpy(message->mutable_payload_bytes(), s.data(), size);
- return node->SendMessage(port, std::move(message));
-}
-
-int SendStringMessageWithPort(Node* node,
- const PortRef& port,
- const std::string& s,
- const PortName& sent_port_name) {
- size_t size = s.size() + 1;
- ScopedMessage message = TestMessage::NewUserMessage(size, 1);
- memcpy(message->mutable_payload_bytes(), s.data(), size);
- message->mutable_ports()[0] = sent_port_name;
- return node->SendMessage(port, std::move(message));
-}
-int SendStringMessageWithPort(Node* node,
- const PortRef& port,
- const std::string& s,
- const PortRef& sent_port) {
- return SendStringMessageWithPort(node, port, s, sent_port.name());
-}
+ int SendStringMessageWithPort(const PortRef& port,
+ const std::string& s,
+ const PortRef& sent_port) {
+ return SendStringMessageWithPort(port, s, sent_port.name());
+ }
-const char* ToString(const ScopedMessage& message) {
- return static_cast<const char*>(message->payload_bytes());
-}
+ void set_drop_messages(bool value) {
+ base::AutoLock lock(lock_);
+ drop_messages_ = value;
+ }
-class TestNodeDelegate : public NodeDelegate {
- public:
- explicit TestNodeDelegate(const NodeName& node_name)
- : node_name_(node_name),
- drop_messages_(false),
- read_messages_(true),
- save_messages_(false) {
+ void set_save_messages(bool value) {
+ base::AutoLock lock(lock_);
+ save_messages_ = value;
}
- void set_drop_messages(bool value) { drop_messages_ = value; }
- void set_read_messages(bool value) { read_messages_ = value; }
- void set_save_messages(bool value) { save_messages_ = value; }
+ bool ReadMessage(const PortRef& port, ScopedMessage* message) {
+ return node_.GetMessage(port, message, nullptr) == OK && *message;
+ }
bool GetSavedMessage(ScopedMessage* message) {
+ base::AutoLock lock(lock_);
if (saved_messages_.empty()) {
message->reset();
return false;
}
- *message = std::move(saved_messages_.front());
+ std::swap(*message, saved_messages_.front());
saved_messages_.pop();
return true;
}
+ void EnqueueMessage(ScopedMessage message) {
+ idle_event_.Reset();
+
+ // NOTE: This may be called from ForwardMessage and thus must not reenter
+ // |node_|.
+ base::AutoLock lock(lock_);
+ incoming_messages_.emplace(std::move(message));
+ messages_available_event_.Signal();
+ }
+
void GenerateRandomPortName(PortName* port_name) override {
- static uint64_t next_port_name = 1;
- port_name->v1 = next_port_name++;
- port_name->v2 = 0;
+ DCHECK(router_);
+ router_->GeneratePortName(port_name);
}
void AllocMessage(size_t num_header_bytes, ScopedMessage* message) override {
@@ -205,489 +207,570 @@ class TestNodeDelegate : public NodeDelegate {
void ForwardMessage(const NodeName& node_name,
ScopedMessage message) override {
- if (drop_messages_) {
- DVLOG(1) << "Dropping ForwardMessage from node "
- << node_name_ << " to " << node_name;
- ClosePortsInMessage(GetNode(node_name), message.get());
- return;
+ {
+ base::AutoLock lock(lock_);
+ if (drop_messages_) {
+ DVLOG(1) << "Dropping ForwardMessage from node "
+ << node_name_ << " to " << node_name;
+
+ base::AutoUnlock unlock(lock_);
+ ClosePortsInMessage(message.get());
+ return;
+ }
}
+
+ DCHECK(router_);
DVLOG(1) << "ForwardMessage from node "
<< node_name_ << " to " << node_name;
- task_queue.push(new Task(node_name, std::move(message)));
+ router_->ForwardMessage(this, node_name, std::move(message));
}
void BroadcastMessage(ScopedMessage message) override {
- for (size_t i = 0; i < kMaxNodes; ++i) {
- Node* node = node_map[i];
- // Broadcast doesn't deliver to the local node.
- if (node && node != GetNode(node_name_)) {
- // NOTE: We only need to support broadcast of events, which have no
- // payload or ports bytes.
- ScopedMessage new_message(
- new TestMessage(message->num_header_bytes(), 0, 0));
- memcpy(new_message->mutable_header_bytes(), message->header_bytes(),
- message->num_header_bytes());
- node->AcceptMessage(std::move(new_message));
- }
- }
+ router_->BroadcastMessage(this, std::move(message));
}
void PortStatusChanged(const PortRef& port) override {
- DVLOG(1) << "PortStatusChanged for " << port.name() << "@" << node_name_;
- if (!read_messages_)
+ // The port may be closed, in which case we ignore the notification.
+ base::AutoLock lock(lock_);
+ if (!save_messages_)
return;
- Node* node = GetNode(node_name_);
+
for (;;) {
ScopedMessage message;
- int rv = node->GetMessage(port, &message);
- EXPECT_TRUE(rv == OK || rv == ERROR_PORT_PEER_CLOSED);
- if (rv == ERROR_PORT_PEER_CLOSED || !message)
- break;
- if (save_messages_) {
- SaveMessage(std::move(message));
- } else {
- LogMessage(message.get());
- for (size_t i = 0; i < message->num_ports(); ++i) {
- std::stringstream buf;
- buf << "got port: " << message->ports()[i];
-
- PortRef received_port;
- node->GetPort(message->ports()[i], &received_port);
+ {
+ base::AutoUnlock unlock(lock_);
+ if (!ReadMessage(port, &message))
+ break;
+ }
- SendStringMessage(node, received_port, buf.str());
+ saved_messages_.emplace(std::move(message));
+ }
+ }
- // Avoid leaking these ports.
- node->ClosePort(received_port);
- }
- }
+ void ClosePortsInMessage(Message* message) {
+ for (size_t i = 0; i < message->num_ports(); ++i) {
+ PortRef port;
+ ASSERT_EQ(OK, node_.GetPort(message->ports()[i], &port));
+ EXPECT_EQ(OK, node_.ClosePort(port));
}
}
private:
- void SaveMessage(ScopedMessage message) {
- saved_messages_.emplace(std::move(message));
+ void ProcessMessages() {
+ for (;;) {
+ messages_available_event_.Wait();
+
+ base::AutoLock lock(lock_);
+
+ if (should_quit_)
+ return;
+
+ dispatching_ = true;
+ while (!incoming_messages_.empty()) {
+ if (block_on_event_ &&
+ GetEventHeader(*incoming_messages_.front())->type ==
+ blocked_event_type_) {
+ blocked_ = true;
+ // Go idle if we hit a blocked event type.
+ break;
+ } else {
+ blocked_ = false;
+ }
+ ScopedMessage message = std::move(incoming_messages_.front());
+ incoming_messages_.pop();
+
+ // NOTE: AcceptMessage() can re-enter this object to call any of the
+ // NodeDelegate interface methods.
+ base::AutoUnlock unlock(lock_);
+ node_.AcceptMessage(std::move(message));
+ }
+
+ dispatching_ = false;
+ started_ = true;
+ idle_event_.Signal();
+ };
}
+ const NodeName node_name_;
+ Node node_;
+ MessageRouter* router_ = nullptr;
+
+ base::Thread node_thread_;
+ base::WaitableEvent messages_available_event_;
+ base::WaitableEvent idle_event_;
+
+ // Guards fields below.
+ base::Lock lock_;
+ bool started_ = false;
+ bool dispatching_ = false;
+ bool should_quit_ = false;
+ bool drop_messages_ = false;
+ bool save_messages_ = false;
+ bool blocked_ = false;
+ bool block_on_event_ = false;
+ EventType blocked_event_type_;
+ std::queue<ScopedMessage> incoming_messages_;
std::queue<ScopedMessage> saved_messages_;
- NodeName node_name_;
- bool drop_messages_;
- bool read_messages_;
- bool save_messages_;
};
-class PortsTest : public testing::Test {
+class PortsTest : public testing::Test, public MessageRouter {
public:
- void SetUp() override {
- DiscardPendingTasks();
- SetNode(NodeName(0, 1), nullptr);
- SetNode(NodeName(1, 1), nullptr);
- SetNode(NodeName(2, 1), nullptr);
+ void AddNode(TestNode* node) {
+ {
+ base::AutoLock lock(lock_);
+ nodes_[node->name()] = node;
+ }
+ node->Start(this);
+ }
+
+ void RemoveNode(TestNode* node) {
+ {
+ base::AutoLock lock(lock_);
+ nodes_.erase(node->name());
+ }
+
+ for (const auto& entry : nodes_)
+ entry.second->node().LostConnectionToNode(node->name());
+ }
+
+ // Waits until all known Nodes are idle. Message forwarding and processing
+ // is handled in such a way that idleness is a stable state: once all nodes in
+ // the system are idle, they will remain idle until the test explicitly
+ // initiates some further event (e.g. sending a message, closing a port, or
+ // removing a Node).
+ void WaitForIdle() {
+ for (;;) {
+ base::AutoLock global_lock(global_lock_);
+ bool all_nodes_idle = true;
+ for (const auto& entry : nodes_) {
+ if (!entry.second->IsIdle())
+ all_nodes_idle = false;
+ entry.second->WakeUp();
+ }
+ if (all_nodes_idle)
+ return;
+
+ // Wait for any Node to signal that it's idle.
+ base::AutoUnlock global_unlock(global_lock_);
+ std::vector<base::WaitableEvent*> events;
+ for (const auto& entry : nodes_)
+ events.push_back(&entry.second->idle_event());
+ base::WaitableEvent::WaitMany(events.data(), events.size());
+ }
}
+
+ void CreatePortPair(TestNode* node0,
+ PortRef* port0,
+ TestNode* node1,
+ PortRef* port1) {
+ if (node0 == node1) {
+ EXPECT_EQ(OK, node0->node().CreatePortPair(port0, port1));
+ } else {
+ EXPECT_EQ(OK, node0->node().CreateUninitializedPort(port0));
+ EXPECT_EQ(OK, node1->node().CreateUninitializedPort(port1));
+ EXPECT_EQ(OK, node0->node().InitializePort(*port0, node1->name(),
+ port1->name()));
+ EXPECT_EQ(OK, node1->node().InitializePort(*port1, node0->name(),
+ port0->name()));
+ }
+ }
+
+ private:
+ // MessageRouter:
+ void GeneratePortName(PortName* name) override {
+ base::AutoLock lock(lock_);
+ name->v1 = next_port_id_++;
+ name->v2 = 0;
+ }
+
+ void ForwardMessage(TestNode* from_node,
+ const NodeName& node_name,
+ ScopedMessage message) override {
+ base::AutoLock global_lock(global_lock_);
+ base::AutoLock lock(lock_);
+ // Drop messages from nodes that have been removed.
+ if (nodes_.find(from_node->name()) == nodes_.end()) {
+ from_node->ClosePortsInMessage(message.get());
+ return;
+ }
+
+ auto it = nodes_.find(node_name);
+ if (it == nodes_.end()) {
+ DVLOG(1) << "Node not found: " << node_name;
+ return;
+ }
+
+ it->second->EnqueueMessage(std::move(message));
+ }
+
+ void BroadcastMessage(TestNode* from_node, ScopedMessage message) override {
+ base::AutoLock global_lock(global_lock_);
+ base::AutoLock lock(lock_);
+
+ // Drop messages from nodes that have been removed.
+ if (nodes_.find(from_node->name()) == nodes_.end())
+ return;
+
+ for (const auto& entry : nodes_) {
+ TestNode* node = entry.second;
+ // Broadcast doesn't deliver to the local node.
+ if (node == from_node)
+ continue;
+
+ // NOTE: We only need to support broadcast of events. Events have no
+ // payload or ports bytes.
+ ScopedMessage new_message(
+ new TestMessage(message->num_header_bytes(), 0, 0));
+ memcpy(new_message->mutable_header_bytes(), message->header_bytes(),
+ message->num_header_bytes());
+ node->EnqueueMessage(std::move(new_message));
+ }
+ }
+
+ base::MessageLoop message_loop_;
+
+ // Acquired before any operation which makes a Node busy, and before testing
+ // if all nodes are idle.
+ base::Lock global_lock_;
+
+ base::Lock lock_;
+ uint64_t next_port_id_ = 1;
+ std::map<NodeName, TestNode*> nodes_;
};
} // namespace
TEST_F(PortsTest, Basic1) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- SetNode(node0_name, &node0);
+ TestNode node0(0);
+ AddNode(&node0);
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- SetNode(node1_name, &node1);
+ TestNode node1(1);
+ AddNode(&node1);
- // Setup pipe between node0 and node1.
PortRef x0, x1;
- EXPECT_EQ(OK, node0.CreateUninitializedPort(&x0));
- EXPECT_EQ(OK, node1.CreateUninitializedPort(&x1));
- EXPECT_EQ(OK, node0.InitializePort(x0, node1_name, x1.name()));
- EXPECT_EQ(OK, node1.InitializePort(x1, node0_name, x0.name()));
+ CreatePortPair(&node0, &x0, &node1, &x1);
- // Transfer a port from node0 to node1.
PortRef a0, a1;
- EXPECT_EQ(OK, node0.CreatePortPair(&a0, &a1));
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, x0, "hello", a1));
-
- EXPECT_EQ(OK, node0.ClosePort(a0));
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&a0, &a1));
+ EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "hello", a1));
+ EXPECT_EQ(OK, node0.node().ClosePort(a0));
- EXPECT_EQ(OK, node0.ClosePort(x0));
- EXPECT_EQ(OK, node1.ClosePort(x1));
+ EXPECT_EQ(OK, node0.node().ClosePort(x0));
+ EXPECT_EQ(OK, node1.node().ClosePort(x1));
- PumpTasks();
+ WaitForIdle();
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
TEST_F(PortsTest, Basic2) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- SetNode(node0_name, &node0);
+ TestNode node0(0);
+ AddNode(&node0);
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- SetNode(node1_name, &node1);
+ TestNode node1(1);
+ AddNode(&node1);
- // Setup pipe between node0 and node1.
PortRef x0, x1;
- EXPECT_EQ(OK, node0.CreateUninitializedPort(&x0));
- EXPECT_EQ(OK, node1.CreateUninitializedPort(&x1));
- EXPECT_EQ(OK, node0.InitializePort(x0, node1_name, x1.name()));
- EXPECT_EQ(OK, node1.InitializePort(x1, node0_name, x0.name()));
+ CreatePortPair(&node0, &x0, &node1, &x1);
PortRef b0, b1;
- EXPECT_EQ(OK, node0.CreatePortPair(&b0, &b1));
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, x0, "hello", b1));
- EXPECT_EQ(OK, SendStringMessage(&node0, b0, "hello again"));
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&b0, &b1));
+ EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "hello", b1));
+ EXPECT_EQ(OK, node0.SendStringMessage(b0, "hello again"));
- // This may cause a SendMessage(b1) failure.
- EXPECT_EQ(OK, node0.ClosePort(b0));
+ EXPECT_EQ(OK, node0.node().ClosePort(b0));
- EXPECT_EQ(OK, node0.ClosePort(x0));
- EXPECT_EQ(OK, node1.ClosePort(x1));
+ EXPECT_EQ(OK, node0.node().ClosePort(x0));
+ EXPECT_EQ(OK, node1.node().ClosePort(x1));
- PumpTasks();
+ WaitForIdle();
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
TEST_F(PortsTest, Basic3) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- SetNode(node0_name, &node0);
+ TestNode node0(0);
+ AddNode(&node0);
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- SetNode(node1_name, &node1);
+ TestNode node1(1);
+ AddNode(&node1);
- // Setup pipe between node0 and node1.
PortRef x0, x1;
- EXPECT_EQ(OK, node0.CreateUninitializedPort(&x0));
- EXPECT_EQ(OK, node1.CreateUninitializedPort(&x1));
- EXPECT_EQ(OK, node0.InitializePort(x0, node1_name, x1.name()));
- EXPECT_EQ(OK, node1.InitializePort(x1, node0_name, x0.name()));
+ CreatePortPair(&node0, &x0, &node1, &x1);
- // Transfer a port from node0 to node1.
PortRef a0, a1;
- EXPECT_EQ(OK, node0.CreatePortPair(&a0, &a1));
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, x0, "hello", a1));
- EXPECT_EQ(OK, SendStringMessage(&node0, a0, "hello again"));
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&a0, &a1));
- // Transfer a0 as well.
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, x0, "foo", a0));
+ EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "hello", a1));
+ EXPECT_EQ(OK, node0.SendStringMessage(a0, "hello again"));
+
+ EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "foo", a0));
PortRef b0, b1;
- EXPECT_EQ(OK, node0.CreatePortPair(&b0, &b1));
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, x0, "bar", b1));
- EXPECT_EQ(OK, SendStringMessage(&node0, b0, "baz"));
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&b0, &b1));
+ EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "bar", b1));
+ EXPECT_EQ(OK, node0.SendStringMessage(b0, "baz"));
- // This may cause a SendMessage(b1) failure.
- EXPECT_EQ(OK, node0.ClosePort(b0));
+ EXPECT_EQ(OK, node0.node().ClosePort(b0));
- EXPECT_EQ(OK, node0.ClosePort(x0));
- EXPECT_EQ(OK, node1.ClosePort(x1));
+ EXPECT_EQ(OK, node0.node().ClosePort(x0));
+ EXPECT_EQ(OK, node1.node().ClosePort(x1));
- PumpTasks();
+ WaitForIdle();
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
TEST_F(PortsTest, LostConnectionToNode1) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- SetNode(node0_name, &node0);
+ TestNode node0(0);
+ AddNode(&node0);
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- SetNode(node1_name, &node1);
+ TestNode node1(1);
+ AddNode(&node1);
+ node1.set_drop_messages(true);
- // Setup pipe between node0 and node1.
PortRef x0, x1;
- EXPECT_EQ(OK, node0.CreateUninitializedPort(&x0));
- EXPECT_EQ(OK, node1.CreateUninitializedPort(&x1));
- EXPECT_EQ(OK, node0.InitializePort(x0, node1_name, x1.name()));
- EXPECT_EQ(OK, node1.InitializePort(x1, node0_name, x0.name()));
-
- // Transfer port to node1 and simulate a lost connection to node1. Dropping
- // events from node1 is how we simulate the lost connection.
+ CreatePortPair(&node0, &x0, &node1, &x1);
- node1_delegate.set_drop_messages(true);
+ // Transfer a port to node1 and simulate a lost connection to node1.
PortRef a0, a1;
- EXPECT_EQ(OK, node0.CreatePortPair(&a0, &a1));
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, x0, "foo", a1));
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&a0, &a1));
+ EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "foo", a1));
- PumpTasks();
+ WaitForIdle();
- EXPECT_EQ(OK, node0.LostConnectionToNode(node1_name));
+ RemoveNode(&node1);
- PumpTasks();
+ WaitForIdle();
- EXPECT_EQ(OK, node0.ClosePort(a0));
- EXPECT_EQ(OK, node0.ClosePort(x0));
- EXPECT_EQ(OK, node1.ClosePort(x1));
+ EXPECT_EQ(OK, node0.node().ClosePort(a0));
+ EXPECT_EQ(OK, node0.node().ClosePort(x0));
+ EXPECT_EQ(OK, node1.node().ClosePort(x1));
- PumpTasks();
+ WaitForIdle();
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
TEST_F(PortsTest, LostConnectionToNode2) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
+ TestNode node0(0);
+ AddNode(&node0);
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- node_map[1] = &node1;
+ TestNode node1(1);
+ AddNode(&node1);
- // Setup pipe between node0 and node1.
PortRef x0, x1;
- EXPECT_EQ(OK, node0.CreateUninitializedPort(&x0));
- EXPECT_EQ(OK, node1.CreateUninitializedPort(&x1));
- EXPECT_EQ(OK, node0.InitializePort(x0, node1_name, x1.name()));
- EXPECT_EQ(OK, node1.InitializePort(x1, node0_name, x0.name()));
-
- node1_delegate.set_read_messages(false);
+ CreatePortPair(&node0, &x0, &node1, &x1);
PortRef a0, a1;
- EXPECT_EQ(OK, node0.CreatePortPair(&a0, &a1));
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, x0, "take a1", a1));
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&a0, &a1));
+ EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "take a1", a1));
- PumpTasks();
+ WaitForIdle();
- node1_delegate.set_drop_messages(true);
+ node1.set_drop_messages(true);
- EXPECT_EQ(OK, node0.LostConnectionToNode(node1_name));
+ RemoveNode(&node1);
- PumpTasks();
+ WaitForIdle();
+ // a0 should have eventually detected peer closure after node loss.
ScopedMessage message;
- EXPECT_EQ(ERROR_PORT_PEER_CLOSED, node0.GetMessage(a0, &message));
+ EXPECT_EQ(ERROR_PORT_PEER_CLOSED,
+ node0.node().GetMessage(a0, &message, nullptr));
EXPECT_FALSE(message);
- EXPECT_EQ(OK, node0.ClosePort(a0));
+ EXPECT_EQ(OK, node0.node().ClosePort(a0));
- EXPECT_EQ(OK, node0.ClosePort(x0));
+ EXPECT_EQ(OK, node0.node().ClosePort(x0));
- EXPECT_EQ(OK, node1.GetMessage(x1, &message));
+ EXPECT_EQ(OK, node1.node().GetMessage(x1, &message, nullptr));
EXPECT_TRUE(message);
- ClosePortsInMessage(&node1, message.get());
+ node1.ClosePortsInMessage(message.get());
- EXPECT_EQ(OK, node1.ClosePort(x1));
+ EXPECT_EQ(OK, node1.node().ClosePort(x1));
- PumpTasks();
+ WaitForIdle();
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
TEST_F(PortsTest, LostConnectionToNodeWithSecondaryProxy) {
// Tests that a proxy gets cleaned up when its indirect peer lives on a lost
// node.
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
+ TestNode node0(0);
+ AddNode(&node0);
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- node_map[1] = &node1;
+ TestNode node1(1);
+ AddNode(&node1);
- NodeName node2_name(2, 1);
- TestNodeDelegate node2_delegate(node2_name);
- Node node2(node2_name, &node2_delegate);
- node_map[2] = &node2;
-
- node1_delegate.set_save_messages(true);
+ TestNode node2(2);
+ AddNode(&node2);
// Create A-B spanning nodes 0 and 1 and C-D spanning 1 and 2.
PortRef A, B, C, D;
- EXPECT_EQ(OK, node0.CreateUninitializedPort(&A));
- EXPECT_EQ(OK, node1.CreateUninitializedPort(&B));
- EXPECT_EQ(OK, node0.InitializePort(A, node1_name, B.name()));
- EXPECT_EQ(OK, node1.InitializePort(B, node0_name, A.name()));
- EXPECT_EQ(OK, node1.CreateUninitializedPort(&C));
- EXPECT_EQ(OK, node2.CreateUninitializedPort(&D));
- EXPECT_EQ(OK, node1.InitializePort(C, node2_name, D.name()));
- EXPECT_EQ(OK, node2.InitializePort(D, node1_name, C.name()));
+ CreatePortPair(&node0, &A, &node1, &B);
+ CreatePortPair(&node1, &C, &node2, &D);
// Create E-F and send F over A to node 1.
PortRef E, F;
- EXPECT_EQ(OK, node0.CreatePortPair(&E, &F));
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, A, ".", F));
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&E, &F));
+ EXPECT_EQ(OK, node0.SendStringMessageWithPort(A, ".", F));
- PumpTasks();
+ WaitForIdle();
ScopedMessage message;
- ASSERT_TRUE(node1_delegate.GetSavedMessage(&message));
+ ASSERT_TRUE(node1.ReadMessage(B, &message));
ASSERT_EQ(1u, message->num_ports());
- EXPECT_EQ(OK, node1.GetPort(message->ports()[0], &F));
+ EXPECT_EQ(OK, node1.node().GetPort(message->ports()[0], &F));
// Send F over C to node 2 and then simulate node 2 loss from node 1. Node 1
// will trivially become aware of the loss, and this test verifies that the
// port A on node 0 will eventually also become aware of it.
- EXPECT_EQ(OK, SendStringMessageWithPort(&node1, C, ".", F));
+ // Make sure node2 stops processing events when it encounters an ObserveProxy.
+ node2.BlockOnEvent(EventType::kObserveProxy);
+
+ EXPECT_EQ(OK, node1.SendStringMessageWithPort(C, ".", F));
+ WaitForIdle();
- node_map[2] = nullptr;
- EXPECT_EQ(OK, node1.LostConnectionToNode(node2_name));
+ // Simulate node 1 and 2 disconnecting.
+ EXPECT_EQ(OK, node1.node().LostConnectionToNode(node2.name()));
- PumpTasks();
+ // Let node2 continue processing events and wait for everyone to go idle.
+ node2.Unblock();
+ WaitForIdle();
// Port F should be gone.
- EXPECT_EQ(ERROR_PORT_UNKNOWN, node1.GetPort(F.name(), &F));
+ EXPECT_EQ(ERROR_PORT_UNKNOWN, node1.node().GetPort(F.name(), &F));
// Port E should have detected peer closure despite the fact that there is
// no longer a continuous route from F to E over which the event could travel.
PortStatus status;
- EXPECT_EQ(OK, node0.GetStatus(E, &status));
+ EXPECT_EQ(OK, node0.node().GetStatus(E, &status));
EXPECT_TRUE(status.peer_closed);
- EXPECT_EQ(OK, node0.ClosePort(A));
- EXPECT_EQ(OK, node1.ClosePort(B));
- EXPECT_EQ(OK, node1.ClosePort(C));
- EXPECT_EQ(OK, node0.ClosePort(E));
+ EXPECT_EQ(OK, node0.node().ClosePort(A));
+ EXPECT_EQ(OK, node1.node().ClosePort(B));
+ EXPECT_EQ(OK, node1.node().ClosePort(C));
+ EXPECT_EQ(OK, node0.node().ClosePort(E));
+
+ WaitForIdle();
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
TEST_F(PortsTest, LostConnectionToNodeWithLocalProxy) {
// Tests that a proxy gets cleaned up when its direct peer lives on a lost
// node and it's predecessor lives on the same node.
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
+ TestNode node0(0);
+ AddNode(&node0);
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- node_map[1] = &node1;
+ TestNode node1(1);
+ AddNode(&node1);
- node1_delegate.set_save_messages(true);
-
- // Create A-B spanning nodes 0 and 1.
PortRef A, B;
- EXPECT_EQ(OK, node0.CreateUninitializedPort(&A));
- EXPECT_EQ(OK, node1.CreateUninitializedPort(&B));
- EXPECT_EQ(OK, node0.InitializePort(A, node1_name, B.name()));
- EXPECT_EQ(OK, node1.InitializePort(B, node0_name, A.name()));
+ CreatePortPair(&node0, &A, &node1, &B);
- // Create C-D and send D over A to node 1.
PortRef C, D;
- EXPECT_EQ(OK, node0.CreatePortPair(&C, &D));
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, A, ".", D));
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&C, &D));
+
+ // Send D but block node0 on an ObserveProxy event.
+ node0.BlockOnEvent(EventType::kObserveProxy);
+ EXPECT_EQ(OK, node0.SendStringMessageWithPort(A, ".", D));
- // Pump tasks until the start of port collapse for port D, which should become
- // a proxy.
- PumpUntilTask(EventType::kObserveProxy);
+ // node0 won't collapse the proxy but node1 will receive the message before
+ // going idle.
+ WaitForIdle();
ScopedMessage message;
- ASSERT_TRUE(node1_delegate.GetSavedMessage(&message));
+ ASSERT_TRUE(node1.ReadMessage(B, &message));
ASSERT_EQ(1u, message->num_ports());
-
PortRef E;
- EXPECT_EQ(OK, node1.GetPort(message->ports()[0], &E));
+ EXPECT_EQ(OK, node1.node().GetPort(message->ports()[0], &E));
- EXPECT_EQ(OK, node0.LostConnectionToNode(node1_name));
- PumpTasks();
+ RemoveNode(&node1);
+
+ node0.Unblock();
+ WaitForIdle();
// Port C should have detected peer closure.
PortStatus status;
- EXPECT_EQ(OK, node0.GetStatus(C, &status));
+ EXPECT_EQ(OK, node0.node().GetStatus(C, &status));
EXPECT_TRUE(status.peer_closed);
- EXPECT_EQ(OK, node0.ClosePort(A));
- EXPECT_EQ(OK, node1.ClosePort(B));
- EXPECT_EQ(OK, node0.ClosePort(C));
- EXPECT_EQ(OK, node1.ClosePort(E));
+ EXPECT_EQ(OK, node0.node().ClosePort(A));
+ EXPECT_EQ(OK, node1.node().ClosePort(B));
+ EXPECT_EQ(OK, node0.node().ClosePort(C));
+ EXPECT_EQ(OK, node1.node().ClosePort(E));
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
TEST_F(PortsTest, GetMessage1) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
+ TestNode node(0);
+ AddNode(&node);
PortRef a0, a1;
- EXPECT_EQ(OK, node0.CreatePortPair(&a0, &a1));
+ EXPECT_EQ(OK, node.node().CreatePortPair(&a0, &a1));
ScopedMessage message;
- EXPECT_EQ(OK, node0.GetMessage(a0, &message));
+ EXPECT_EQ(OK, node.node().GetMessage(a0, &message, nullptr));
EXPECT_FALSE(message);
- EXPECT_EQ(OK, node0.ClosePort(a1));
-
- EXPECT_EQ(OK, node0.GetMessage(a0, &message));
- EXPECT_FALSE(message);
+ EXPECT_EQ(OK, node.node().ClosePort(a1));
- PumpTasks();
+ WaitForIdle();
- EXPECT_EQ(ERROR_PORT_PEER_CLOSED, node0.GetMessage(a0, &message));
+ EXPECT_EQ(ERROR_PORT_PEER_CLOSED,
+ node.node().GetMessage(a0, &message, nullptr));
EXPECT_FALSE(message);
- EXPECT_EQ(OK, node0.ClosePort(a0));
+ EXPECT_EQ(OK, node.node().ClosePort(a0));
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
+ WaitForIdle();
+
+ EXPECT_TRUE(node.node().CanShutdownCleanly());
}
TEST_F(PortsTest, GetMessage2) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
-
- node0_delegate.set_read_messages(false);
+ TestNode node(0);
+ AddNode(&node);
PortRef a0, a1;
- EXPECT_EQ(OK, node0.CreatePortPair(&a0, &a1));
+ EXPECT_EQ(OK, node.node().CreatePortPair(&a0, &a1));
- EXPECT_EQ(OK, SendStringMessage(&node0, a1, "1"));
+ EXPECT_EQ(OK, node.SendStringMessage(a1, "1"));
ScopedMessage message;
- EXPECT_EQ(OK, node0.GetMessage(a0, &message));
+ EXPECT_EQ(OK, node.node().GetMessage(a0, &message, nullptr));
ASSERT_TRUE(message);
- EXPECT_EQ(0, strcmp("1", ToString(message)));
+ EXPECT_TRUE(MessageEquals(message, "1"));
- EXPECT_EQ(OK, node0.ClosePort(a0));
- EXPECT_EQ(OK, node0.ClosePort(a1));
+ EXPECT_EQ(OK, node.node().ClosePort(a0));
+ EXPECT_EQ(OK, node.node().ClosePort(a1));
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
+ EXPECT_TRUE(node.node().CanShutdownCleanly());
}
TEST_F(PortsTest, GetMessage3) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
-
- node0_delegate.set_read_messages(false);
+ TestNode node(0);
+ AddNode(&node);
PortRef a0, a1;
- EXPECT_EQ(OK, node0.CreatePortPair(&a0, &a1));
+ EXPECT_EQ(OK, node.node().CreatePortPair(&a0, &a1));
const char* kStrings[] = {
"1",
@@ -696,371 +779,305 @@ TEST_F(PortsTest, GetMessage3) {
};
for (size_t i = 0; i < sizeof(kStrings)/sizeof(kStrings[0]); ++i)
- EXPECT_EQ(OK, SendStringMessage(&node0, a1, kStrings[i]));
+ EXPECT_EQ(OK, node.SendStringMessage(a1, kStrings[i]));
ScopedMessage message;
for (size_t i = 0; i < sizeof(kStrings)/sizeof(kStrings[0]); ++i) {
- EXPECT_EQ(OK, node0.GetMessage(a0, &message));
+ EXPECT_EQ(OK, node.node().GetMessage(a0, &message, nullptr));
ASSERT_TRUE(message);
- EXPECT_EQ(0, strcmp(kStrings[i], ToString(message)));
- DVLOG(1) << "got " << kStrings[i];
+ EXPECT_TRUE(MessageEquals(message, kStrings[i]));
}
- EXPECT_EQ(OK, node0.ClosePort(a0));
- EXPECT_EQ(OK, node0.ClosePort(a1));
+ EXPECT_EQ(OK, node.node().ClosePort(a0));
+ EXPECT_EQ(OK, node.node().ClosePort(a1));
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
+ EXPECT_TRUE(node.node().CanShutdownCleanly());
}
TEST_F(PortsTest, Delegation1) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- SetNode(node0_name, &node0);
+ TestNode node0(0);
+ AddNode(&node0);
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- node_map[1] = &node1;
+ TestNode node1(1);
+ AddNode(&node1);
- node0_delegate.set_save_messages(true);
- node1_delegate.set_save_messages(true);
-
- // Setup pipe between node0 and node1.
PortRef x0, x1;
- EXPECT_EQ(OK, node0.CreateUninitializedPort(&x0));
- EXPECT_EQ(OK, node1.CreateUninitializedPort(&x1));
- EXPECT_EQ(OK, node0.InitializePort(x0, node1_name, x1.name()));
- EXPECT_EQ(OK, node1.InitializePort(x1, node0_name, x0.name()));
+ CreatePortPair(&node0, &x0, &node1, &x1);
// In this test, we send a message to a port that has been moved.
PortRef a0, a1;
- EXPECT_EQ(OK, node0.CreatePortPair(&a0, &a1));
-
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, x0, "a1", a1));
-
- PumpTasks();
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&a0, &a1));
+ EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "a1", a1));
+ WaitForIdle();
ScopedMessage message;
- ASSERT_TRUE(node1_delegate.GetSavedMessage(&message));
-
+ ASSERT_TRUE(node1.ReadMessage(x1, &message));
ASSERT_EQ(1u, message->num_ports());
+ EXPECT_TRUE(MessageEquals(message, "a1"));
// This is "a1" from the point of view of node1.
PortName a2_name = message->ports()[0];
+ EXPECT_EQ(OK, node1.SendStringMessageWithPort(x1, "a2", a2_name));
+ EXPECT_EQ(OK, node0.SendStringMessage(a0, "hello"));
- EXPECT_EQ(OK, SendStringMessageWithPort(&node1, x1, "a2", a2_name));
-
- PumpTasks();
-
- EXPECT_EQ(OK, SendStringMessage(&node0, a0, "hello"));
-
- PumpTasks();
-
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
+ WaitForIdle();
+ ASSERT_TRUE(node0.ReadMessage(x0, &message));
ASSERT_EQ(1u, message->num_ports());
+ EXPECT_TRUE(MessageEquals(message, "a2"));
// This is "a2" from the point of view of node1.
PortName a3_name = message->ports()[0];
PortRef a3;
- EXPECT_EQ(OK, node0.GetPort(a3_name, &a3));
-
- EXPECT_EQ(0, strcmp("a2", ToString(message)));
-
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
+ EXPECT_EQ(OK, node0.node().GetPort(a3_name, &a3));
+ ASSERT_TRUE(node0.ReadMessage(a3, &message));
EXPECT_EQ(0u, message->num_ports());
- EXPECT_EQ(0, strcmp("hello", ToString(message)));
+ EXPECT_TRUE(MessageEquals(message, "hello"));
- EXPECT_EQ(OK, node0.ClosePort(a0));
- EXPECT_EQ(OK, node0.ClosePort(a3));
+ EXPECT_EQ(OK, node0.node().ClosePort(a0));
+ EXPECT_EQ(OK, node0.node().ClosePort(a3));
- EXPECT_EQ(OK, node0.ClosePort(x0));
- EXPECT_EQ(OK, node1.ClosePort(x1));
+ EXPECT_EQ(OK, node0.node().ClosePort(x0));
+ EXPECT_EQ(OK, node1.node().ClosePort(x1));
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
TEST_F(PortsTest, Delegation2) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- SetNode(node0_name, &node0);
-
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- node_map[1] = &node1;
+ TestNode node0(0);
+ AddNode(&node0);
- node0_delegate.set_save_messages(true);
- node1_delegate.set_save_messages(true);
+ TestNode node1(1);
+ AddNode(&node1);
- for (int i = 0; i < 10; ++i) {
+ for (int i = 0; i < 100; ++i) {
// Setup pipe a<->b between node0 and node1.
PortRef A, B;
- EXPECT_EQ(OK, node0.CreateUninitializedPort(&A));
- EXPECT_EQ(OK, node1.CreateUninitializedPort(&B));
- EXPECT_EQ(OK, node0.InitializePort(A, node1_name, B.name()));
- EXPECT_EQ(OK, node1.InitializePort(B, node0_name, A.name()));
+ CreatePortPair(&node0, &A, &node1, &B);
PortRef C, D;
- EXPECT_EQ(OK, node0.CreatePortPair(&C, &D));
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&C, &D));
PortRef E, F;
- EXPECT_EQ(OK, node0.CreatePortPair(&E, &F));
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&E, &F));
+
+ node1.set_save_messages(true);
// Pass D over A to B.
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, A, "1", D));
+ EXPECT_EQ(OK, node0.SendStringMessageWithPort(A, "1", D));
// Pass F over C to D.
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, C, "1", F));
+ EXPECT_EQ(OK, node0.SendStringMessageWithPort(C, "1", F));
// This message should find its way to node1.
- EXPECT_EQ(OK, SendStringMessage(&node0, E, "hello"));
+ EXPECT_EQ(OK, node0.SendStringMessage(E, "hello"));
- PumpTasks();
+ WaitForIdle();
- EXPECT_EQ(OK, node0.ClosePort(C));
- EXPECT_EQ(OK, node0.ClosePort(E));
+ EXPECT_EQ(OK, node0.node().ClosePort(C));
+ EXPECT_EQ(OK, node0.node().ClosePort(E));
- EXPECT_EQ(OK, node0.ClosePort(A));
- EXPECT_EQ(OK, node1.ClosePort(B));
+ EXPECT_EQ(OK, node0.node().ClosePort(A));
+ EXPECT_EQ(OK, node1.node().ClosePort(B));
- for (;;) {
- ScopedMessage message;
- if (node1_delegate.GetSavedMessage(&message)) {
- ClosePortsInMessage(&node1, message.get());
- if (strcmp("hello", ToString(message)) == 0)
- break;
- } else {
- ASSERT_TRUE(false); // "hello" message not delivered!
+ bool got_hello = false;
+ ScopedMessage message;
+ while (node1.GetSavedMessage(&message)) {
+ node1.ClosePortsInMessage(message.get());
+ if (MessageEquals(message, "hello")) {
+ got_hello = true;
break;
}
}
- PumpTasks(); // Because ClosePort may have generated tasks.
+ EXPECT_TRUE(got_hello);
+
+ WaitForIdle(); // Because closing ports may have generated tasks.
}
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
TEST_F(PortsTest, SendUninitialized) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
+ TestNode node(0);
+ AddNode(&node);
PortRef x0;
- EXPECT_EQ(OK, node0.CreateUninitializedPort(&x0));
- EXPECT_EQ(ERROR_PORT_STATE_UNEXPECTED,
- SendStringMessage(&node0, x0, "oops"));
- EXPECT_EQ(OK, node0.ClosePort(x0));
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
+ EXPECT_EQ(OK, node.node().CreateUninitializedPort(&x0));
+ EXPECT_EQ(ERROR_PORT_STATE_UNEXPECTED, node.SendStringMessage(x0, "oops"));
+ EXPECT_EQ(OK, node.node().ClosePort(x0));
+ EXPECT_TRUE(node.node().CanShutdownCleanly());
}
TEST_F(PortsTest, SendFailure) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
+ TestNode node(0);
+ AddNode(&node);
- node0_delegate.set_save_messages(true);
+ node.set_save_messages(true);
PortRef A, B;
- EXPECT_EQ(OK, node0.CreatePortPair(&A, &B));
+ EXPECT_EQ(OK, node.node().CreatePortPair(&A, &B));
// Try to send A over itself.
EXPECT_EQ(ERROR_PORT_CANNOT_SEND_SELF,
- SendStringMessageWithPort(&node0, A, "oops", A));
+ node.SendStringMessageWithPort(A, "oops", A));
// Try to send B over A.
EXPECT_EQ(ERROR_PORT_CANNOT_SEND_PEER,
- SendStringMessageWithPort(&node0, A, "nope", B));
+ node.SendStringMessageWithPort(A, "nope", B));
// B should be closed immediately.
- EXPECT_EQ(ERROR_PORT_UNKNOWN, node0.GetPort(B.name(), &B));
+ EXPECT_EQ(ERROR_PORT_UNKNOWN, node.node().GetPort(B.name(), &B));
- PumpTasks();
+ WaitForIdle();
// There should have been no messages accepted.
ScopedMessage message;
- EXPECT_FALSE(node0_delegate.GetSavedMessage(&message));
+ EXPECT_FALSE(node.GetSavedMessage(&message));
- EXPECT_EQ(OK, node0.ClosePort(A));
+ EXPECT_EQ(OK, node.node().ClosePort(A));
- PumpTasks();
+ WaitForIdle();
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
+ EXPECT_TRUE(node.node().CanShutdownCleanly());
}
TEST_F(PortsTest, DontLeakUnreceivedPorts) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
-
- node0_delegate.set_read_messages(false);
+ TestNode node(0);
+ AddNode(&node);
- PortRef A, B;
- EXPECT_EQ(OK, node0.CreatePortPair(&A, &B));
-
- PortRef C, D;
- EXPECT_EQ(OK, node0.CreatePortPair(&C, &D));
-
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, A, "foo", D));
-
- PumpTasks();
+ PortRef A, B, C, D;
+ EXPECT_EQ(OK, node.node().CreatePortPair(&A, &B));
+ EXPECT_EQ(OK, node.node().CreatePortPair(&C, &D));
- EXPECT_EQ(OK, node0.ClosePort(C));
+ EXPECT_EQ(OK, node.SendStringMessageWithPort(A, "foo", D));
- EXPECT_EQ(OK, node0.ClosePort(A));
- EXPECT_EQ(OK, node0.ClosePort(B));
+ EXPECT_EQ(OK, node.node().ClosePort(C));
+ EXPECT_EQ(OK, node.node().ClosePort(A));
+ EXPECT_EQ(OK, node.node().ClosePort(B));
- PumpTasks();
+ WaitForIdle();
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
+ EXPECT_TRUE(node.node().CanShutdownCleanly());
}
TEST_F(PortsTest, AllowShutdownWithLocalPortsOpen) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
+ TestNode node(0);
+ AddNode(&node);
- node0_delegate.set_save_messages(true);
-
- PortRef A, B;
- EXPECT_EQ(OK, node0.CreatePortPair(&A, &B));
-
- PortRef C, D;
- EXPECT_EQ(OK, node0.CreatePortPair(&C, &D));
+ PortRef A, B, C, D;
+ EXPECT_EQ(OK, node.node().CreatePortPair(&A, &B));
+ EXPECT_EQ(OK, node.node().CreatePortPair(&C, &D));
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, A, "foo", D));
+ EXPECT_EQ(OK, node.SendStringMessageWithPort(A, "foo", D));
ScopedMessage message;
- EXPECT_TRUE(node0_delegate.GetSavedMessage(&message));
+ EXPECT_TRUE(node.ReadMessage(B, &message));
ASSERT_EQ(1u, message->num_ports());
-
+ EXPECT_TRUE(MessageEquals(message, "foo"));
PortRef E;
- ASSERT_EQ(OK, node0.GetPort(message->ports()[0], &E));
+ ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &E));
- EXPECT_TRUE(node0.CanShutdownCleanly(true));
+ EXPECT_TRUE(
+ node.node().CanShutdownCleanly(Node::ShutdownPolicy::ALLOW_LOCAL_PORTS));
- PumpTasks();
+ WaitForIdle();
- EXPECT_TRUE(node0.CanShutdownCleanly(true));
- EXPECT_FALSE(node0.CanShutdownCleanly(false));
+ EXPECT_TRUE(
+ node.node().CanShutdownCleanly(Node::ShutdownPolicy::ALLOW_LOCAL_PORTS));
+ EXPECT_FALSE(node.node().CanShutdownCleanly());
- EXPECT_EQ(OK, node0.ClosePort(A));
- EXPECT_EQ(OK, node0.ClosePort(B));
- EXPECT_EQ(OK, node0.ClosePort(C));
- EXPECT_EQ(OK, node0.ClosePort(E));
+ EXPECT_EQ(OK, node.node().ClosePort(A));
+ EXPECT_EQ(OK, node.node().ClosePort(B));
+ EXPECT_EQ(OK, node.node().ClosePort(C));
+ EXPECT_EQ(OK, node.node().ClosePort(E));
- PumpTasks();
+ WaitForIdle();
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
+ EXPECT_TRUE(node.node().CanShutdownCleanly());
}
TEST_F(PortsTest, ProxyCollapse1) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
-
- node0_delegate.set_save_messages(true);
+ TestNode node(0);
+ AddNode(&node);
PortRef A, B;
- EXPECT_EQ(OK, node0.CreatePortPair(&A, &B));
+ EXPECT_EQ(OK, node.node().CreatePortPair(&A, &B));
PortRef X, Y;
- EXPECT_EQ(OK, node0.CreatePortPair(&X, &Y));
+ EXPECT_EQ(OK, node.node().CreatePortPair(&X, &Y));
ScopedMessage message;
// Send B and receive it as C.
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, X, "foo", B));
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
+ EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", B));
+ ASSERT_TRUE(node.ReadMessage(Y, &message));
ASSERT_EQ(1u, message->num_ports());
PortRef C;
- ASSERT_EQ(OK, node0.GetPort(message->ports()[0], &C));
+ ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &C));
// Send C and receive it as D.
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, X, "foo", C));
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
+ EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", C));
+ ASSERT_TRUE(node.ReadMessage(Y, &message));
ASSERT_EQ(1u, message->num_ports());
PortRef D;
- ASSERT_EQ(OK, node0.GetPort(message->ports()[0], &D));
+ ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &D));
// Send D and receive it as E.
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, X, "foo", D));
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
+ EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", D));
+ ASSERT_TRUE(node.ReadMessage(Y, &message));
ASSERT_EQ(1u, message->num_ports());
PortRef E;
- ASSERT_EQ(OK, node0.GetPort(message->ports()[0], &E));
+ ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &E));
- EXPECT_EQ(OK, node0.ClosePort(X));
- EXPECT_EQ(OK, node0.ClosePort(Y));
+ EXPECT_EQ(OK, node.node().ClosePort(X));
+ EXPECT_EQ(OK, node.node().ClosePort(Y));
- EXPECT_EQ(OK, node0.ClosePort(A));
- EXPECT_EQ(OK, node0.ClosePort(E));
+ EXPECT_EQ(OK, node.node().ClosePort(A));
+ EXPECT_EQ(OK, node.node().ClosePort(E));
- PumpTasks();
+ // The node should not idle until all proxies are collapsed.
+ WaitForIdle();
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
+ EXPECT_TRUE(node.node().CanShutdownCleanly());
}
TEST_F(PortsTest, ProxyCollapse2) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
-
- node0_delegate.set_save_messages(true);
+ TestNode node(0);
+ AddNode(&node);
PortRef A, B;
- EXPECT_EQ(OK, node0.CreatePortPair(&A, &B));
+ EXPECT_EQ(OK, node.node().CreatePortPair(&A, &B));
PortRef X, Y;
- EXPECT_EQ(OK, node0.CreatePortPair(&X, &Y));
+ EXPECT_EQ(OK, node.node().CreatePortPair(&X, &Y));
ScopedMessage message;
- // Send B and receive it as C.
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, X, "foo", B));
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
- ASSERT_EQ(1u, message->num_ports());
- PortRef C;
- ASSERT_EQ(OK, node0.GetPort(message->ports()[0], &C));
+ // Send B and A to create proxies in each direction.
+ EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", B));
+ EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", A));
- // Send A and receive it as D.
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, X, "foo", A));
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
- ASSERT_EQ(1u, message->num_ports());
- PortRef D;
- ASSERT_EQ(OK, node0.GetPort(message->ports()[0], &D));
+ EXPECT_EQ(OK, node.node().ClosePort(X));
+ EXPECT_EQ(OK, node.node().ClosePort(Y));
// At this point we have a scenario with:
//
// D -> [B] -> C -> [A]
//
- // Ensure that the proxies can collapse.
-
- EXPECT_EQ(OK, node0.ClosePort(X));
- EXPECT_EQ(OK, node0.ClosePort(Y));
+ // Ensure that the proxies can collapse. The sent ports will be closed
+ // eventually as a result of Y's closure.
- EXPECT_EQ(OK, node0.ClosePort(C));
- EXPECT_EQ(OK, node0.ClosePort(D));
+ WaitForIdle();
- PumpTasks();
-
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
+ EXPECT_TRUE(node.node().CanShutdownCleanly());
}
TEST_F(PortsTest, SendWithClosedPeer) {
@@ -1068,56 +1085,47 @@ TEST_F(PortsTest, SendWithClosedPeer) {
// closed, the newly created port will be aware of that peer closure, and the
// proxy will eventually collapse.
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
-
- node0_delegate.set_read_messages(false);
+ TestNode node(0);
+ AddNode(&node);
// Send a message from A to B, then close A.
PortRef A, B;
- EXPECT_EQ(OK, node0.CreatePortPair(&A, &B));
- EXPECT_EQ(OK, SendStringMessage(&node0, A, "hey"));
- EXPECT_EQ(OK, node0.ClosePort(A));
-
- PumpTasks();
+ EXPECT_EQ(OK, node.node().CreatePortPair(&A, &B));
+ EXPECT_EQ(OK, node.SendStringMessage(A, "hey"));
+ EXPECT_EQ(OK, node.node().ClosePort(A));
// Now send B over X-Y as new port C.
PortRef X, Y;
- EXPECT_EQ(OK, node0.CreatePortPair(&X, &Y));
-
- node0_delegate.set_read_messages(true);
- node0_delegate.set_save_messages(true);
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, X, "foo", B));
-
- EXPECT_EQ(OK, node0.ClosePort(X));
- EXPECT_EQ(OK, node0.ClosePort(Y));
-
+ EXPECT_EQ(OK, node.node().CreatePortPair(&X, &Y));
+ EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", B));
ScopedMessage message;
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
+ ASSERT_TRUE(node.ReadMessage(Y, &message));
ASSERT_EQ(1u, message->num_ports());
-
PortRef C;
- ASSERT_EQ(OK, node0.GetPort(message->ports()[0], &C));
+ ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &C));
+
+ EXPECT_EQ(OK, node.node().ClosePort(X));
+ EXPECT_EQ(OK, node.node().ClosePort(Y));
- PumpTasks();
+ WaitForIdle();
- // C should receive the message originally sent to B, and it should also be
- // aware of A's closure.
+ // C should have received the message originally sent to B, and it should also
+ // be aware of A's closure.
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
- EXPECT_EQ(0, strcmp("hey", ToString(message)));
+ ASSERT_TRUE(node.ReadMessage(C, &message));
+ EXPECT_TRUE(MessageEquals(message, "hey"));
PortStatus status;
- EXPECT_EQ(OK, node0.GetStatus(C, &status));
+ EXPECT_EQ(OK, node.node().GetStatus(C, &status));
EXPECT_FALSE(status.receiving_messages);
EXPECT_FALSE(status.has_messages);
EXPECT_TRUE(status.peer_closed);
- node0.ClosePort(C);
+ node.node().ClosePort(C);
+
+ WaitForIdle();
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
+ EXPECT_TRUE(node.node().CanShutdownCleanly());
}
TEST_F(PortsTest, SendWithClosedPeerSent) {
@@ -1126,391 +1134,342 @@ TEST_F(PortsTest, SendWithClosedPeerSent) {
// eventually notified of the closure, and the dead-end proxies will
// eventually be removed.
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
-
- node0_delegate.set_save_messages(true);
+ TestNode node(0);
+ AddNode(&node);
PortRef X, Y;
- EXPECT_EQ(OK, node0.CreatePortPair(&X, &Y));
+ EXPECT_EQ(OK, node.node().CreatePortPair(&X, &Y));
PortRef A, B;
- EXPECT_EQ(OK, node0.CreatePortPair(&A, &B));
+ EXPECT_EQ(OK, node.node().CreatePortPair(&A, &B));
ScopedMessage message;
// Send A as new port C.
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, X, "foo", A));
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
+ EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", A));
+
+ ASSERT_TRUE(node.ReadMessage(Y, &message));
ASSERT_EQ(1u, message->num_ports());
PortRef C;
- ASSERT_EQ(OK, node0.GetPort(message->ports()[0], &C));
+ ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &C));
// Send C as new port D.
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, X, "foo", C));
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
+ EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", C));
+
+ ASSERT_TRUE(node.ReadMessage(Y, &message));
ASSERT_EQ(1u, message->num_ports());
PortRef D;
- ASSERT_EQ(OK, node0.GetPort(message->ports()[0], &D));
-
- node0_delegate.set_read_messages(false);
+ ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &D));
// Send a message to B through D, then close D.
- EXPECT_EQ(OK, SendStringMessage(&node0, D, "hey"));
- EXPECT_EQ(OK, node0.ClosePort(D));
-
- PumpTasks();
+ EXPECT_EQ(OK, node.SendStringMessage(D, "hey"));
+ EXPECT_EQ(OK, node.node().ClosePort(D));
// Now send B as new port E.
- node0_delegate.set_read_messages(true);
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, X, "foo", B));
+ EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", B));
+ EXPECT_EQ(OK, node.node().ClosePort(X));
- EXPECT_EQ(OK, node0.ClosePort(X));
- EXPECT_EQ(OK, node0.ClosePort(Y));
-
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
+ ASSERT_TRUE(node.ReadMessage(Y, &message));
ASSERT_EQ(1u, message->num_ports());
-
PortRef E;
- ASSERT_EQ(OK, node0.GetPort(message->ports()[0], &E));
+ ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &E));
+
+ EXPECT_EQ(OK, node.node().ClosePort(Y));
- PumpTasks();
+ WaitForIdle();
// E should receive the message originally sent to B, and it should also be
// aware of D's closure.
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
- EXPECT_EQ(0, strcmp("hey", ToString(message)));
+ ASSERT_TRUE(node.ReadMessage(E, &message));
+ EXPECT_TRUE(MessageEquals(message, "hey"));
PortStatus status;
- EXPECT_EQ(OK, node0.GetStatus(E, &status));
+ EXPECT_EQ(OK, node.node().GetStatus(E, &status));
EXPECT_FALSE(status.receiving_messages);
EXPECT_FALSE(status.has_messages);
EXPECT_TRUE(status.peer_closed);
- node0.ClosePort(E);
+ EXPECT_EQ(OK, node.node().ClosePort(E));
- PumpTasks();
+ WaitForIdle();
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
+ EXPECT_TRUE(node.node().CanShutdownCleanly());
}
TEST_F(PortsTest, MergePorts) {
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
+ TestNode node0(0);
+ AddNode(&node0);
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- node_map[1] = &node1;
+ TestNode node1(1);
+ AddNode(&node1);
// Setup two independent port pairs, A-B on node0 and C-D on node1.
PortRef A, B, C, D;
- EXPECT_EQ(OK, node0.CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node1.CreatePortPair(&C, &D));
-
- node0_delegate.set_read_messages(false);
- node1_delegate.set_save_messages(true);
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&A, &B));
+ EXPECT_EQ(OK, node1.node().CreatePortPair(&C, &D));
// Write a message on A.
- EXPECT_EQ(OK, SendStringMessage(&node0, A, "hey"));
-
- PumpTasks();
+ EXPECT_EQ(OK, node0.SendStringMessage(A, "hey"));
// Initiate a merge between B and C.
- EXPECT_EQ(OK, node0.MergePorts(B, node1_name, C.name()));
+ EXPECT_EQ(OK, node0.node().MergePorts(B, node1.name(), C.name()));
- PumpTasks();
+ WaitForIdle();
- // Expect only two receiving ports to be left after pumping tasks.
- EXPECT_TRUE(node0.CanShutdownCleanly(true));
- EXPECT_TRUE(node1.CanShutdownCleanly(true));
+ // Expect all proxies to be gone once idle.
+ EXPECT_TRUE(
+ node0.node().CanShutdownCleanly(Node::ShutdownPolicy::ALLOW_LOCAL_PORTS));
+ EXPECT_TRUE(
+ node1.node().CanShutdownCleanly(Node::ShutdownPolicy::ALLOW_LOCAL_PORTS));
// Expect D to have received the message sent on A.
ScopedMessage message;
- ASSERT_TRUE(node1_delegate.GetSavedMessage(&message));
- EXPECT_EQ(0, strcmp("hey", ToString(message)));
+ ASSERT_TRUE(node1.ReadMessage(D, &message));
+ EXPECT_TRUE(MessageEquals(message, "hey"));
- EXPECT_EQ(OK, node0.ClosePort(A));
- EXPECT_EQ(OK, node1.ClosePort(D));
+ EXPECT_EQ(OK, node0.node().ClosePort(A));
+ EXPECT_EQ(OK, node1.node().ClosePort(D));
// No more ports should be open.
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
TEST_F(PortsTest, MergePortWithClosedPeer1) {
// This tests that the right thing happens when initiating a merge on a port
// whose peer has already been closed.
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
+ TestNode node0(0);
+ AddNode(&node0);
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- node_map[1] = &node1;
+ TestNode node1(1);
+ AddNode(&node1);
// Setup two independent port pairs, A-B on node0 and C-D on node1.
PortRef A, B, C, D;
- EXPECT_EQ(OK, node0.CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node1.CreatePortPair(&C, &D));
-
- node0_delegate.set_read_messages(false);
- node1_delegate.set_save_messages(true);
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&A, &B));
+ EXPECT_EQ(OK, node1.node().CreatePortPair(&C, &D));
// Write a message on A.
- EXPECT_EQ(OK, SendStringMessage(&node0, A, "hey"));
-
- PumpTasks();
+ EXPECT_EQ(OK, node0.SendStringMessage(A, "hey"));
// Close A.
- EXPECT_EQ(OK, node0.ClosePort(A));
+ EXPECT_EQ(OK, node0.node().ClosePort(A));
// Initiate a merge between B and C.
- EXPECT_EQ(OK, node0.MergePorts(B, node1_name, C.name()));
+ EXPECT_EQ(OK, node0.node().MergePorts(B, node1.name(), C.name()));
- PumpTasks();
+ WaitForIdle();
- // Expect only one receiving port to be left after pumping tasks.
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(true));
+ // Expect all proxies to be gone once idle. node0 should have no ports since
+ // A was explicitly closed.
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(
+ node1.node().CanShutdownCleanly(Node::ShutdownPolicy::ALLOW_LOCAL_PORTS));
// Expect D to have received the message sent on A.
ScopedMessage message;
- ASSERT_TRUE(node1_delegate.GetSavedMessage(&message));
- EXPECT_EQ(0, strcmp("hey", ToString(message)));
+ ASSERT_TRUE(node1.ReadMessage(D, &message));
+ EXPECT_TRUE(MessageEquals(message, "hey"));
- EXPECT_EQ(OK, node1.ClosePort(D));
+ EXPECT_EQ(OK, node1.node().ClosePort(D));
// No more ports should be open.
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
TEST_F(PortsTest, MergePortWithClosedPeer2) {
// This tests that the right thing happens when merging into a port whose peer
// has already been closed.
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
+ TestNode node0(0);
+ AddNode(&node0);
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- node_map[1] = &node1;
+ TestNode node1(1);
+ AddNode(&node1);
// Setup two independent port pairs, A-B on node0 and C-D on node1.
PortRef A, B, C, D;
- EXPECT_EQ(OK, node0.CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node1.CreatePortPair(&C, &D));
-
- node0_delegate.set_save_messages(true);
- node1_delegate.set_read_messages(false);
-
- // Write a message on D.
- EXPECT_EQ(OK, SendStringMessage(&node0, D, "hey"));
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&A, &B));
+ EXPECT_EQ(OK, node1.node().CreatePortPair(&C, &D));
- PumpTasks();
-
- // Close D.
- EXPECT_EQ(OK, node1.ClosePort(D));
+ // Write a message on D and close it.
+ EXPECT_EQ(OK, node0.SendStringMessage(D, "hey"));
+ EXPECT_EQ(OK, node1.node().ClosePort(D));
// Initiate a merge between B and C.
- EXPECT_EQ(OK, node0.MergePorts(B, node1_name, C.name()));
+ EXPECT_EQ(OK, node0.node().MergePorts(B, node1.name(), C.name()));
- PumpTasks();
+ WaitForIdle();
- // Expect only one receiving port to be left after pumping tasks.
- EXPECT_TRUE(node0.CanShutdownCleanly(true));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ // Expect all proxies to be gone once idle. node1 should have no ports since
+ // D was explicitly closed.
+ EXPECT_TRUE(
+ node0.node().CanShutdownCleanly(Node::ShutdownPolicy::ALLOW_LOCAL_PORTS));
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
// Expect A to have received the message sent on D.
ScopedMessage message;
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
- EXPECT_EQ(0, strcmp("hey", ToString(message)));
+ ASSERT_TRUE(node0.ReadMessage(A, &message));
+ EXPECT_TRUE(MessageEquals(message, "hey"));
- EXPECT_EQ(OK, node0.ClosePort(A));
+ EXPECT_EQ(OK, node0.node().ClosePort(A));
// No more ports should be open.
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
TEST_F(PortsTest, MergePortsWithClosedPeers) {
// This tests that no residual ports are left behind if two ports are merged
// when both of their peers have been closed.
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
+ TestNode node0(0);
+ AddNode(&node0);
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- node_map[1] = &node1;
+ TestNode node1(1);
+ AddNode(&node1);
// Setup two independent port pairs, A-B on node0 and C-D on node1.
PortRef A, B, C, D;
- EXPECT_EQ(OK, node0.CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node1.CreatePortPair(&C, &D));
-
- node0_delegate.set_save_messages(true);
- node1_delegate.set_read_messages(false);
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&A, &B));
+ EXPECT_EQ(OK, node1.node().CreatePortPair(&C, &D));
// Close A and D.
- EXPECT_EQ(OK, node0.ClosePort(A));
- EXPECT_EQ(OK, node1.ClosePort(D));
+ EXPECT_EQ(OK, node0.node().ClosePort(A));
+ EXPECT_EQ(OK, node1.node().ClosePort(D));
- PumpTasks();
+ WaitForIdle();
// Initiate a merge between B and C.
- EXPECT_EQ(OK, node0.MergePorts(B, node1_name, C.name()));
+ EXPECT_EQ(OK, node0.node().MergePorts(B, node1.name(), C.name()));
- PumpTasks();
+ WaitForIdle();
// Expect everything to have gone away.
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
TEST_F(PortsTest, MergePortsWithMovedPeers) {
- // This tests that no ports can be merged successfully even if their peers
- // are moved around.
+ // This tests that ports can be merged successfully even if their peers are
+ // moved around.
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
+ TestNode node0(0);
+ AddNode(&node0);
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- node_map[1] = &node1;
-
- node0_delegate.set_save_messages(true);
- node1_delegate.set_read_messages(false);
+ TestNode node1(1);
+ AddNode(&node1);
// Setup two independent port pairs, A-B on node0 and C-D on node1.
PortRef A, B, C, D;
- EXPECT_EQ(OK, node0.CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node1.CreatePortPair(&C, &D));
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&A, &B));
+ EXPECT_EQ(OK, node1.node().CreatePortPair(&C, &D));
// Set up another pair X-Y for moving ports on node0.
PortRef X, Y;
- EXPECT_EQ(OK, node0.CreatePortPair(&X, &Y));
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&X, &Y));
ScopedMessage message;
// Move A to new port E.
- EXPECT_EQ(OK, SendStringMessageWithPort(&node0, X, "foo", A));
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
+ EXPECT_EQ(OK, node0.SendStringMessageWithPort(X, "foo", A));
+ ASSERT_TRUE(node0.ReadMessage(Y, &message));
ASSERT_EQ(1u, message->num_ports());
PortRef E;
- ASSERT_EQ(OK, node0.GetPort(message->ports()[0], &E));
-
- EXPECT_EQ(OK, node0.ClosePort(X));
- EXPECT_EQ(OK, node0.ClosePort(Y));
+ ASSERT_EQ(OK, node0.node().GetPort(message->ports()[0], &E));
- node0_delegate.set_read_messages(false);
+ EXPECT_EQ(OK, node0.node().ClosePort(X));
+ EXPECT_EQ(OK, node0.node().ClosePort(Y));
// Write messages on E and D.
- EXPECT_EQ(OK, SendStringMessage(&node0, E, "hey"));
- EXPECT_EQ(OK, SendStringMessage(&node1, D, "hi"));
+ EXPECT_EQ(OK, node0.SendStringMessage(E, "hey"));
+ EXPECT_EQ(OK, node1.SendStringMessage(D, "hi"));
// Initiate a merge between B and C.
- EXPECT_EQ(OK, node0.MergePorts(B, node1_name, C.name()));
-
- node0_delegate.set_read_messages(true);
- node1_delegate.set_read_messages(true);
- node1_delegate.set_save_messages(true);
+ EXPECT_EQ(OK, node0.node().MergePorts(B, node1.name(), C.name()));
- PumpTasks();
+ WaitForIdle();
// Expect to receive D's message on E and E's message on D.
- ASSERT_TRUE(node0_delegate.GetSavedMessage(&message));
- EXPECT_EQ(0, strcmp("hi", ToString(message)));
- ASSERT_TRUE(node1_delegate.GetSavedMessage(&message));
- EXPECT_EQ(0, strcmp("hey", ToString(message)));
+ ASSERT_TRUE(node0.ReadMessage(E, &message));
+ EXPECT_TRUE(MessageEquals(message, "hi"));
+ ASSERT_TRUE(node1.ReadMessage(D, &message));
+ EXPECT_TRUE(MessageEquals(message, "hey"));
// Close E and D.
- EXPECT_EQ(OK, node0.ClosePort(E));
- EXPECT_EQ(OK, node1.ClosePort(D));
+ EXPECT_EQ(OK, node0.node().ClosePort(E));
+ EXPECT_EQ(OK, node1.node().ClosePort(D));
- PumpTasks();
+ WaitForIdle();
// Expect everything to have gone away.
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
TEST_F(PortsTest, MergePortsFailsGracefully) {
// This tests that the system remains in a well-defined state if something
// goes wrong during port merge.
- NodeName node0_name(0, 1);
- TestNodeDelegate node0_delegate(node0_name);
- Node node0(node0_name, &node0_delegate);
- node_map[0] = &node0;
+ TestNode node0(0);
+ AddNode(&node0);
- NodeName node1_name(1, 1);
- TestNodeDelegate node1_delegate(node1_name);
- Node node1(node1_name, &node1_delegate);
- node_map[1] = &node1;
+ TestNode node1(1);
+ AddNode(&node1);
// Setup two independent port pairs, A-B on node0 and C-D on node1.
PortRef A, B, C, D;
- EXPECT_EQ(OK, node0.CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node1.CreatePortPair(&C, &D));
-
- PumpTasks();
-
- // Initiate a merge between B and C.
- EXPECT_EQ(OK, node0.MergePorts(B, node1_name, C.name()));
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&A, &B));
+ EXPECT_EQ(OK, node1.node().CreatePortPair(&C, &D));
- // Move C to a new port E. This is dumb and nobody should do it, but it's
- // possible. MergePorts will fail as a result because C won't be in a
- // receiving state when the event arrives at node1, so B should be closed.
ScopedMessage message;
PortRef X, Y;
- EXPECT_EQ(OK, node1.CreatePortPair(&X, &Y));
- node1_delegate.set_save_messages(true);
- EXPECT_EQ(OK, SendStringMessageWithPort(&node1, X, "foo", C));
- ASSERT_TRUE(node1_delegate.GetSavedMessage(&message));
+ EXPECT_EQ(OK, node1.node().CreatePortPair(&X, &Y));
+
+ // Block the merge from proceeding until we can do something stupid with port
+ // C. This avoids the test logic racing with async merge logic.
+ node1.BlockOnEvent(EventType::kMergePort);
+
+ // Initiate the merge between B and C.
+ EXPECT_EQ(OK, node0.node().MergePorts(B, node1.name(), C.name()));
+
+ // Move C to a new port E. This is not a sane use of Node's public API but
+ // is still hypothetically possible. It allows us to force a merge failure
+ // because C will be in an invalid state by the term the merge is processed.
+ // As a result, B should be closed.
+ EXPECT_EQ(OK, node1.SendStringMessageWithPort(X, "foo", C));
+
+ node1.Unblock();
+
+ ASSERT_TRUE(node1.ReadMessage(Y, &message));
ASSERT_EQ(1u, message->num_ports());
PortRef E;
- ASSERT_EQ(OK, node1.GetPort(message->ports()[0], &E));
- EXPECT_EQ(OK, node1.ClosePort(X));
- EXPECT_EQ(OK, node1.ClosePort(Y));
+ ASSERT_EQ(OK, node1.node().GetPort(message->ports()[0], &E));
- // C goes away as a result of normal proxy removal.
- PumpTasks();
+ EXPECT_EQ(OK, node1.node().ClosePort(X));
+ EXPECT_EQ(OK, node1.node().ClosePort(Y));
- EXPECT_EQ(ERROR_PORT_UNKNOWN, node1.GetPort(C.name(), &C));
+ WaitForIdle();
- // B should have been closed cleanly.
- EXPECT_EQ(ERROR_PORT_UNKNOWN, node0.GetPort(B.name(), &B));
+ // C goes away as a result of normal proxy removal. B should have been closed
+ // cleanly by the failed MergePorts.
+ EXPECT_EQ(ERROR_PORT_UNKNOWN, node1.node().GetPort(C.name(), &C));
+ EXPECT_EQ(ERROR_PORT_UNKNOWN, node0.node().GetPort(B.name(), &B));
// Close A, D, and E.
- EXPECT_EQ(OK, node0.ClosePort(A));
- EXPECT_EQ(OK, node1.ClosePort(D));
- EXPECT_EQ(OK, node1.ClosePort(E));
+ EXPECT_EQ(OK, node0.node().ClosePort(A));
+ EXPECT_EQ(OK, node1.node().ClosePort(D));
+ EXPECT_EQ(OK, node1.node().ClosePort(E));
- PumpTasks();
+ WaitForIdle();
// Expect everything to have gone away.
- EXPECT_TRUE(node0.CanShutdownCleanly(false));
- EXPECT_TRUE(node1.CanShutdownCleanly(false));
+ EXPECT_TRUE(node0.node().CanShutdownCleanly());
+ EXPECT_TRUE(node1.node().CanShutdownCleanly());
}
} // namespace test
diff --git a/mojo/edk/system/request_context.cc b/mojo/edk/system/request_context.cc
index 276e39f..6370ab1 100644
--- a/mojo/edk/system/request_context.cc
+++ b/mojo/edk/system/request_context.cc
@@ -77,12 +77,12 @@ void RequestContext::AddWatchNotifyFinalizer(
const HandleSignalsState& state) {
DCHECK(IsCurrent());
watch_notify_finalizers_->push_back(
- WatchNotifyFinalizer(watcher, result, state));
+ WatchNotifyFinalizer(std::move(watcher), result, state));
}
void RequestContext::AddWatchCancelFinalizer(scoped_refptr<Watcher> watcher) {
DCHECK(IsCurrent());
- watch_cancel_finalizers_->push_back(watcher);
+ watch_cancel_finalizers_->push_back(std::move(watcher));
}
bool RequestContext::IsCurrent() const {
@@ -93,8 +93,7 @@ RequestContext::WatchNotifyFinalizer::WatchNotifyFinalizer(
scoped_refptr<Watcher> watcher,
MojoResult result,
const HandleSignalsState& state)
- : watcher(watcher), result(result), state(state) {
-}
+ : watcher(std::move(watcher)), result(result), state(state) {}
RequestContext::WatchNotifyFinalizer::WatchNotifyFinalizer(
const WatchNotifyFinalizer& other) = default;
diff --git a/mojo/edk/system/shared_buffer_dispatcher.h b/mojo/edk/system/shared_buffer_dispatcher.h
index 1648dd2..6015595 100644
--- a/mojo/edk/system/shared_buffer_dispatcher.h
+++ b/mojo/edk/system/shared_buffer_dispatcher.h
@@ -21,7 +21,6 @@ namespace mojo {
namespace edk {
class NodeController;
-class PlatformSupport;
class MOJO_SYSTEM_IMPL_EXPORT SharedBufferDispatcher final : public Dispatcher {
public:
diff --git a/mojo/edk/test/BUILD.gn b/mojo/edk/test/BUILD.gn
index ebacc64..a15456a 100644
--- a/mojo/edk/test/BUILD.gn
+++ b/mojo/edk/test/BUILD.gn
@@ -9,8 +9,6 @@ static_library("test_support") {
sources = [
"mojo_test_base.cc",
"mojo_test_base.h",
- "scoped_ipc_support.cc",
- "scoped_ipc_support.h",
"test_utils.h",
"test_utils_posix.cc",
"test_utils_win.cc",
diff --git a/mojo/edk/test/mojo_test_base.cc b/mojo/edk/test/mojo_test_base.cc
index 5d77a11..f1032d7 100644
--- a/mojo/edk/test/mojo_test_base.cc
+++ b/mojo/edk/test/mojo_test_base.cc
@@ -44,14 +44,15 @@ MojoTestBase::~MojoTestBase() {}
MojoTestBase::ClientController& MojoTestBase::StartClient(
const std::string& client_name) {
clients_.push_back(base::MakeUnique<ClientController>(
- client_name, this, process_error_callback_));
+ client_name, this, process_error_callback_, launch_type_));
return *clients_.back();
}
MojoTestBase::ClientController::ClientController(
const std::string& client_name,
MojoTestBase* test,
- const ProcessErrorCallback& process_error_callback) {
+ const ProcessErrorCallback& process_error_callback,
+ LaunchType launch_type) {
#if !defined(OS_IOS)
#if defined(OS_MACOSX)
// This lock needs to be held while launching the child because the Mach port
@@ -63,7 +64,7 @@ MojoTestBase::ClientController::ClientController(
base::AutoLock lock(g_mach_broker->GetLock());
#endif
helper_.set_process_error_callback(process_error_callback);
- pipe_ = helper_.StartChild(client_name);
+ pipe_ = helper_.StartChild(client_name, launch_type);
#if defined(OS_MACOSX)
g_mach_broker->AddPlaceholderForPid(helper_.test_child().Handle());
#endif
@@ -75,6 +76,12 @@ MojoTestBase::ClientController::~ClientController() {
<< "Test clients should be waited on explicitly with WaitForShutdown().";
}
+void MojoTestBase::ClientController::ClosePeerConnection() {
+#if !defined(OS_IOS)
+ helper_.ClosePeerConnection();
+#endif
+}
+
int MojoTestBase::ClientController::WaitForShutdown() {
was_shutdown_ = true;
#if !defined(OS_IOS)
diff --git a/mojo/edk/test/mojo_test_base.h b/mojo/edk/test/mojo_test_base.h
index 4f55145..fa5b64c 100644
--- a/mojo/edk/test/mojo_test_base.h
+++ b/mojo/edk/test/mojo_test_base.h
@@ -29,6 +29,8 @@ class MojoTestBase : public testing::Test {
MojoTestBase();
~MojoTestBase() override;
+ using LaunchType = MultiprocessTestHelper::LaunchType;
+
protected:
using HandlerCallback = base::Callback<void(ScopedMessagePipeHandle)>;
@@ -36,11 +38,13 @@ class MojoTestBase : public testing::Test {
public:
ClientController(const std::string& client_name,
MojoTestBase* test,
- const ProcessErrorCallback& process_error_callback_);
+ const ProcessErrorCallback& process_error_callback,
+ LaunchType launch_type);
~ClientController();
MojoHandle pipe() const { return pipe_.get().value(); }
+ void ClosePeerConnection();
int WaitForShutdown();
private:
@@ -148,6 +152,8 @@ class MojoTestBase : public testing::Test {
// Reads data from a data pipe.
static std::string ReadData(MojoHandle consumer, size_t size);
+ void set_launch_type(LaunchType launch_type) { launch_type_ = launch_type; }
+
private:
friend class ClientController;
@@ -155,6 +161,8 @@ class MojoTestBase : public testing::Test {
ProcessErrorCallback process_error_callback_;
+ LaunchType launch_type_ = LaunchType::CHILD;
+
DISALLOW_COPY_AND_ASSIGN(MojoTestBase);
};
diff --git a/mojo/edk/test/multiprocess_test_helper.cc b/mojo/edk/test/multiprocess_test_helper.cc
index 82a82c8..de6e2d9 100644
--- a/mojo/edk/test/multiprocess_test_helper.cc
+++ b/mojo/edk/test/multiprocess_test_helper.cc
@@ -8,12 +8,14 @@
#include <set>
#include <utility>
+#include "base/base_paths.h"
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
+#include "base/path_service.h"
#include "base/process/kill.h"
#include "base/process/process_handle.h"
#include "base/run_loop.h"
@@ -22,6 +24,9 @@
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/named_platform_handle.h"
+#include "mojo/edk/embedder/named_platform_handle_utils.h"
+#include "mojo/edk/embedder/pending_process_connection.h"
#include "mojo/edk/embedder/platform_channel_pair.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -38,11 +43,13 @@ namespace test {
namespace {
const char kMojoPrimordialPipeToken[] = "mojo-primordial-pipe-token";
+const char kMojoNamedPipeName[] = "mojo-named-pipe-name";
-int RunClientFunction(std::function<int(MojoHandle)> handler) {
- CHECK(!MultiprocessTestHelper::primordial_pipe_token.empty());
- ScopedMessagePipeHandle pipe = CreateChildMessagePipe(
- MultiprocessTestHelper::primordial_pipe_token);
+template <typename Func>
+int RunClientFunction(Func handler) {
+ CHECK(MultiprocessTestHelper::primordial_pipe.is_valid());
+ ScopedMessagePipeHandle pipe =
+ std::move(MultiprocessTestHelper::primordial_pipe);
return handler(pipe.get().value());
}
@@ -55,15 +62,17 @@ MultiprocessTestHelper::~MultiprocessTestHelper() {
}
ScopedMessagePipeHandle MultiprocessTestHelper::StartChild(
- const std::string& test_child_name) {
- return StartChildWithExtraSwitch(
- test_child_name, std::string(), std::string());
+ const std::string& test_child_name,
+ LaunchType launch_type) {
+ return StartChildWithExtraSwitch(test_child_name, std::string(),
+ std::string(), launch_type);
}
ScopedMessagePipeHandle MultiprocessTestHelper::StartChildWithExtraSwitch(
const std::string& test_child_name,
const std::string& switch_string,
- const std::string& switch_value) {
+ const std::string& switch_value,
+ LaunchType launch_type) {
CHECK(!test_child_name.empty());
CHECK(!test_child_.IsValid());
@@ -88,12 +97,23 @@ ScopedMessagePipeHandle MultiprocessTestHelper::StartChildWithExtraSwitch(
}
PlatformChannelPair channel;
+ NamedPlatformHandle named_pipe;
HandlePassingInformation handle_passing_info;
- channel.PrepareToPassClientHandleToChildProcess(&command_line,
- &handle_passing_info);
-
- std::string pipe_token = mojo::edk::GenerateRandomToken();
- command_line.AppendSwitchASCII(kMojoPrimordialPipeToken, pipe_token);
+ if (launch_type == LaunchType::CHILD || launch_type == LaunchType::PEER) {
+ channel.PrepareToPassClientHandleToChildProcess(&command_line,
+ &handle_passing_info);
+ } else if (launch_type == LaunchType::NAMED_CHILD ||
+ launch_type == LaunchType::NAMED_PEER) {
+#if defined(OS_POSIX)
+ base::FilePath temp_dir;
+ CHECK(base::PathService::Get(base::DIR_TEMP, &temp_dir));
+ named_pipe = NamedPlatformHandle(
+ temp_dir.AppendASCII(GenerateRandomToken()).value());
+#else
+ named_pipe = NamedPlatformHandle(GenerateRandomToken());
+#endif
+ command_line.AppendSwitchNative(kMojoNamedPipeName, named_pipe.name);
+ }
if (!switch_string.empty()) {
CHECK(!command_line.HasSwitch(switch_string));
@@ -116,18 +136,44 @@ ScopedMessagePipeHandle MultiprocessTestHelper::StartChildWithExtraSwitch(
#error "Not supported yet."
#endif
- std::string child_token = mojo::edk::GenerateRandomToken();
- ScopedMessagePipeHandle pipe = CreateParentMessagePipe(pipe_token,
- child_token);
+ // NOTE: In the case of named pipes, it's important that the server handle be
+ // created before the child process is launched; otherwise the server binding
+ // the pipe path can race with child's connection to the pipe.
+ ScopedPlatformHandle server_handle;
+ if (launch_type == LaunchType::CHILD || launch_type == LaunchType::PEER) {
+ server_handle = channel.PassServerHandle();
+ } else if (launch_type == LaunchType::NAMED_CHILD ||
+ launch_type == LaunchType::NAMED_PEER) {
+ server_handle = CreateServerHandle(named_pipe);
+ }
+
+ PendingProcessConnection process;
+ ScopedMessagePipeHandle pipe;
+ if (launch_type == LaunchType::CHILD ||
+ launch_type == LaunchType::NAMED_CHILD) {
+ std::string pipe_token;
+ pipe = process.CreateMessagePipe(&pipe_token);
+ command_line.AppendSwitchASCII(kMojoPrimordialPipeToken, pipe_token);
+ } else if (launch_type == LaunchType::PEER ||
+ launch_type == LaunchType::NAMED_PEER) {
+ peer_token_ = mojo::edk::GenerateRandomToken();
+ pipe = ConnectToPeerProcess(std::move(server_handle), peer_token_);
+ }
test_child_ =
base::SpawnMultiProcessTestChild(test_child_main, command_line, options);
- channel.ChildProcessLaunched();
+ if (launch_type == LaunchType::CHILD || launch_type == LaunchType::PEER)
+ channel.ChildProcessLaunched();
+
+ if (launch_type == LaunchType::CHILD ||
+ launch_type == LaunchType::NAMED_CHILD) {
+ DCHECK(server_handle.is_valid());
+ process.Connect(test_child_.Handle(),
+ ConnectionParams(std::move(server_handle)),
+ process_error_callback_);
+ }
- ChildProcessLaunched(test_child_.Handle(), channel.PassServerHandle(),
- child_token, process_error_callback_);
CHECK(test_child_.IsValid());
-
return pipe;
}
@@ -135,18 +181,18 @@ int MultiprocessTestHelper::WaitForChildShutdown() {
CHECK(test_child_.IsValid());
int rv = -1;
-#if defined(OS_ANDROID)
- // On Android, we need to use a special function to wait for the child.
- CHECK(AndroidWaitForChildExitWithTimeout(
- test_child_, TestTimeouts::action_timeout(), &rv));
-#else
- CHECK(
- test_child_.WaitForExitWithTimeout(TestTimeouts::action_timeout(), &rv));
-#endif
+ WaitForMultiprocessTestChildExit(test_child_, TestTimeouts::action_timeout(),
+ &rv);
test_child_.Close();
return rv;
}
+void MultiprocessTestHelper::ClosePeerConnection() {
+ DCHECK(!peer_token_.empty());
+ ::mojo::edk::ClosePeerConnection(peer_token_);
+ peer_token_.clear();
+}
+
bool MultiprocessTestHelper::WaitForChildTestShutdown() {
return WaitForChildShutdown() == 0;
}
@@ -155,17 +201,33 @@ bool MultiprocessTestHelper::WaitForChildTestShutdown() {
void MultiprocessTestHelper::ChildSetup() {
CHECK(base::CommandLine::InitializedForCurrentProcess());
- primordial_pipe_token = base::CommandLine::ForCurrentProcess()
- ->GetSwitchValueASCII(kMojoPrimordialPipeToken);
- CHECK(!primordial_pipe_token.empty());
-
+ std::string primordial_pipe_token =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ kMojoPrimordialPipeToken);
+ NamedPlatformHandle named_pipe(
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
+ kMojoNamedPipeName));
+ if (!primordial_pipe_token.empty()) {
+ primordial_pipe = CreateChildMessagePipe(primordial_pipe_token);
#if defined(OS_MACOSX) && !defined(OS_IOS)
- CHECK(base::MachPortBroker::ChildSendTaskPortToParent("mojo_test"));
+ CHECK(base::MachPortBroker::ChildSendTaskPortToParent("mojo_test"));
#endif
-
- SetParentPipeHandle(
- PlatformChannelPair::PassClientHandleFromParentProcess(
- *base::CommandLine::ForCurrentProcess()));
+ if (named_pipe.is_valid()) {
+ SetParentPipeHandle(CreateClientHandle(named_pipe));
+ } else {
+ SetParentPipeHandle(
+ PlatformChannelPair::PassClientHandleFromParentProcess(
+ *base::CommandLine::ForCurrentProcess()));
+ }
+ } else {
+ if (named_pipe.is_valid()) {
+ primordial_pipe = ConnectToPeerProcess(CreateClientHandle(named_pipe));
+ } else {
+ primordial_pipe = ConnectToPeerProcess(
+ PlatformChannelPair::PassClientHandleFromParentProcess(
+ *base::CommandLine::ForCurrentProcess()));
+ }
+ }
}
// static
@@ -187,7 +249,7 @@ int MultiprocessTestHelper::RunClientTestMain(
}
// static
-std::string MultiprocessTestHelper::primordial_pipe_token;
+mojo::ScopedMessagePipeHandle MultiprocessTestHelper::primordial_pipe;
} // namespace test
} // namespace edk
diff --git a/mojo/edk/test/multiprocess_test_helper.h b/mojo/edk/test/multiprocess_test_helper.h
index 203eb11..dd9bd6a 100644
--- a/mojo/edk/test/multiprocess_test_helper.h
+++ b/mojo/edk/test/multiprocess_test_helper.h
@@ -19,7 +19,6 @@
namespace mojo {
namespace edk {
-class PlatformChannelPair;
namespace test {
@@ -27,13 +26,31 @@ class MultiprocessTestHelper {
public:
using HandlerCallback = base::Callback<void(ScopedMessagePipeHandle)>;
+ enum class LaunchType {
+ // Launch the child process as a child in the mojo system.
+ CHILD,
+
+ // Launch the child process as an unrelated peer process in the mojo system.
+ PEER,
+
+ // Launch the child process as a child in the mojo system, using a named
+ // pipe.
+ NAMED_CHILD,
+
+ // Launch the child process as an unrelated peer process in the mojo
+ // system, using a named pipe.
+ NAMED_PEER,
+ };
+
MultiprocessTestHelper();
~MultiprocessTestHelper();
// Start a child process and run the "main" function "named" |test_child_name|
// declared using |MOJO_MULTIPROCESS_TEST_CHILD_MAIN()| or
// |MOJO_MULTIPROCESS_TEST_CHILD_TEST()| (below).
- ScopedMessagePipeHandle StartChild(const std::string& test_child_name);
+ ScopedMessagePipeHandle StartChild(
+ const std::string& test_child_name,
+ LaunchType launch_type = LaunchType::CHILD);
// Like |StartChild()|, but appends an extra switch (with ASCII value) to the
// command line. (The switch must not already be present in the default
@@ -41,12 +58,15 @@ class MultiprocessTestHelper {
ScopedMessagePipeHandle StartChildWithExtraSwitch(
const std::string& test_child_name,
const std::string& switch_string,
- const std::string& switch_value);
+ const std::string& switch_value,
+ LaunchType launch_type);
void set_process_error_callback(const ProcessErrorCallback& callback) {
process_error_callback_ = callback;
}
+ void ClosePeerConnection();
+
// Wait for the child process to terminate.
// Returns the exit code of the child process. Note that, though it's declared
// to be an |int|, the exit code is subject to mangling by the OS. E.g., we
@@ -69,7 +89,7 @@ class MultiprocessTestHelper {
static int RunClientTestMain(const base::Callback<void(MojoHandle)>& main);
// For use (and only valid) in the child process:
- static std::string primordial_pipe_token;
+ static mojo::ScopedMessagePipeHandle primordial_pipe;
private:
// Valid after |StartChild()| and before |WaitForChildShutdown()|.
@@ -77,6 +97,8 @@ class MultiprocessTestHelper {
ProcessErrorCallback process_error_callback_;
+ std::string peer_token_;
+
DISALLOW_COPY_AND_ASSIGN(MultiprocessTestHelper);
};
diff --git a/mojo/edk/test/run_all_perftests.cc b/mojo/edk/test/run_all_perftests.cc
index 50c41d7..3ce3b47 100644
--- a/mojo/edk/test/run_all_perftests.cc
+++ b/mojo/edk/test/run_all_perftests.cc
@@ -7,24 +7,19 @@
#include "base/test/perf_test_suite.h"
#include "base/test/test_io_thread.h"
#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/scoped_ipc_support.h"
#include "mojo/edk/test/multiprocess_test_helper.h"
-#include "mojo/edk/test/scoped_ipc_support.h"
#include "mojo/edk/test/test_support_impl.h"
#include "mojo/public/tests/test_support_private.h"
int main(int argc, char** argv) {
-#if defined(OS_ANDROID)
- base::InitAndroidMultiProcessTestHelper(main);
-#endif
-
base::PerfTestSuite test(argc, argv);
mojo::edk::Init();
base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
- // Leak this because its destructor calls mojo::edk::ShutdownIPCSupport which
- // really does nothing in the new EDK but does depend on the current message
- // loop, which is destructed inside base::LaunchUnitTests.
- new mojo::edk::test::ScopedIPCSupport(test_io_thread.task_runner());
+ mojo::edk::ScopedIPCSupport ipc_support(
+ test_io_thread.task_runner(),
+ mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
mojo::test::TestSupport::Init(new mojo::edk::test::TestSupportImpl());
return test.Run();
diff --git a/mojo/edk/test/run_all_unittests.cc b/mojo/edk/test/run_all_unittests.cc
index 05aed91..a057825 100644
--- a/mojo/edk/test/run_all_unittests.cc
+++ b/mojo/edk/test/run_all_unittests.cc
@@ -11,8 +11,8 @@
#include "base/test/test_io_thread.h"
#include "base/test/test_suite.h"
#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/scoped_ipc_support.h"
#include "mojo/edk/test/multiprocess_test_helper.h"
-#include "mojo/edk/test/scoped_ipc_support.h"
#include "mojo/edk/test/test_support_impl.h"
#include "mojo/public/tests/test_support_private.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -26,10 +26,6 @@ int main(int argc, char** argv) {
testing::GTEST_FLAG(death_test_style) = "threadsafe";
#endif
#if defined(OS_ANDROID)
- // Enable the alternate test child implementation. This is needed because Mojo
- // tests need to spawn test children after initialising the Mojo system.
- base::InitAndroidMultiProcessTestHelper(main);
-
// On android, the test framework has a signal handler that will print a
// [ CRASH ] line when the application crashes. This breaks death test has the
// test runner will consider the death of the child process a test failure.
@@ -43,11 +39,10 @@ int main(int argc, char** argv) {
mojo::test::TestSupport::Init(new mojo::edk::test::TestSupportImpl());
base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
- // Leak this because its destructor calls mojo::edk::ShutdownIPCSupport which
- // really does nothing in the new EDK but does depend on the current message
- // loop, which is destructed inside base::LaunchUnitTests.
- new mojo::edk::test::ScopedIPCSupport(test_io_thread.task_runner());
+ mojo::edk::ScopedIPCSupport ipc_support(
+ test_io_thread.task_runner(),
+ mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
return base::LaunchUnitTests(
argc, argv,
base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
diff --git a/mojo/edk/test/scoped_ipc_support.cc b/mojo/edk/test/scoped_ipc_support.cc
deleted file mode 100644
index 7dc7c99..0000000
--- a/mojo/edk/test/scoped_ipc_support.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/test/scoped_ipc_support.h"
-
-#include <utility>
-
-#include "base/message_loop/message_loop.h"
-#include "mojo/edk/embedder/embedder.h"
-
-namespace mojo {
-namespace edk {
-namespace test {
-
-namespace {
-base::TaskRunner* g_io_task_runner = nullptr;
-}
-
-base::TaskRunner* GetIoTaskRunner() {
- return g_io_task_runner;
-}
-
-namespace internal {
-
-ScopedIPCSupportHelper::ScopedIPCSupportHelper() {
-}
-
-ScopedIPCSupportHelper::~ScopedIPCSupportHelper() {
- ShutdownIPCSupport();
- run_loop_.Run();
-}
-
-void ScopedIPCSupportHelper::Init(
- ProcessDelegate* process_delegate,
- scoped_refptr<base::TaskRunner> io_thread_task_runner) {
- io_thread_task_runner_ = io_thread_task_runner;
- InitIPCSupport(process_delegate, io_thread_task_runner_);
-}
-
-void ScopedIPCSupportHelper::OnShutdownCompleteImpl() {
- run_loop_.Quit();
-}
-
-} // namespace internal
-
-ScopedIPCSupport::ScopedIPCSupport(
- scoped_refptr<base::TaskRunner> io_thread_task_runner) {
- g_io_task_runner = io_thread_task_runner.get();
- helper_.Init(this, std::move(io_thread_task_runner));
-}
-
-ScopedIPCSupport::~ScopedIPCSupport() {
-}
-
-void ScopedIPCSupport::OnShutdownComplete() {
- helper_.OnShutdownCompleteImpl();
-}
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/test/scoped_ipc_support.h b/mojo/edk/test/scoped_ipc_support.h
deleted file mode 100644
index 04173d3..0000000
--- a/mojo/edk/test/scoped_ipc_support.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_TEST_SCOPED_IPC_SUPPORT_H_
-#define MOJO_EDK_TEST_SCOPED_IPC_SUPPORT_H_
-
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/run_loop.h"
-#include "base/task_runner.h"
-#include "mojo/edk/embedder/process_delegate.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-
-namespace mojo {
-namespace edk {
-namespace test {
-
-base::TaskRunner* GetIoTaskRunner();
-
-namespace internal {
-
-class ScopedIPCSupportHelper {
- public:
- ScopedIPCSupportHelper();
- ~ScopedIPCSupportHelper();
-
- void Init(ProcessDelegate* process_delegate,
- scoped_refptr<base::TaskRunner> io_thread_task_runner);
-
- void OnShutdownCompleteImpl();
-
- private:
- scoped_refptr<base::TaskRunner> io_thread_task_runner_;
-
- base::RunLoop run_loop_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedIPCSupportHelper);
-};
-
-} // namespace internal
-
-// A simple class that calls |InitIPCSupport()| on construction and
-// |ShutdownIPCSupport()| on destruction.
-class ScopedIPCSupport : public ProcessDelegate {
- public:
- explicit ScopedIPCSupport(
- scoped_refptr<base::TaskRunner> io_thread_task_runner);
- ~ScopedIPCSupport() override;
-
- private:
- // |ProcessDelegate| implementation:
- // Note: Executed on the I/O thread.
- void OnShutdownComplete() override;
-
- internal::ScopedIPCSupportHelper helper_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedIPCSupport);
-};
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_TEST_SCOPED_IPC_SUPPORT_H_
diff --git a/mojo/gpu/BUILD.gn b/mojo/gpu/BUILD.gn
deleted file mode 100644
index ad37238..0000000
--- a/mojo/gpu/BUILD.gn
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("mojo_gles2_implementation") {
- sources = [
- "mojo_gles2_impl_autogen.cc",
- "mojo_gles2_impl_autogen.h",
- ]
-
- configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
- deps = [
- "//base",
- "//gpu/command_buffer/client:gles2_interface",
- "//mojo/public/c/gles2",
- ]
-}
diff --git a/mojo/gpu/DEPS b/mojo/gpu/DEPS
deleted file mode 100644
index 241389e..0000000
--- a/mojo/gpu/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "+gpu/command_buffer/client",
- "+third_party/khronos/GLES2",
-]
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.cc b/mojo/gpu/mojo_gles2_impl_autogen.cc
deleted file mode 100644
index 93377a5..0000000
--- a/mojo/gpu/mojo_gles2_impl_autogen.cc
+++ /dev/null
@@ -1,1899 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file is auto-generated from
-// gpu/command_buffer/build_gles2_cmd_buffer.py
-// It's formatted by clang-format using chromium coding style:
-// clang-format -i -style=chromium filename
-// DO NOT EDIT!
-
-#include "mojo/gpu/mojo_gles2_impl_autogen.h"
-
-#include "base/logging.h"
-#include "mojo/public/c/gles2/chromium_extension.h"
-#include "mojo/public/c/gles2/gles2.h"
-
-namespace mojo {
-
-void MojoGLES2Impl::ActiveTexture(GLenum texture) {
- MojoGLES2MakeCurrent(context_);
- glActiveTexture(texture);
-}
-void MojoGLES2Impl::AttachShader(GLuint program, GLuint shader) {
- MojoGLES2MakeCurrent(context_);
- glAttachShader(program, shader);
-}
-void MojoGLES2Impl::BindAttribLocation(GLuint program,
- GLuint index,
- const char* name) {
- MojoGLES2MakeCurrent(context_);
- glBindAttribLocation(program, index, name);
-}
-void MojoGLES2Impl::BindBuffer(GLenum target, GLuint buffer) {
- MojoGLES2MakeCurrent(context_);
- glBindBuffer(target, buffer);
-}
-void MojoGLES2Impl::BindBufferBase(GLenum target, GLuint index, GLuint buffer) {
- NOTREACHED() << "Unimplemented BindBufferBase.";
-}
-void MojoGLES2Impl::BindBufferRange(GLenum target,
- GLuint index,
- GLuint buffer,
- GLintptr offset,
- GLsizeiptr size) {
- NOTREACHED() << "Unimplemented BindBufferRange.";
-}
-void MojoGLES2Impl::BindFramebuffer(GLenum target, GLuint framebuffer) {
- MojoGLES2MakeCurrent(context_);
- glBindFramebuffer(target, framebuffer);
-}
-void MojoGLES2Impl::BindRenderbuffer(GLenum target, GLuint renderbuffer) {
- MojoGLES2MakeCurrent(context_);
- glBindRenderbuffer(target, renderbuffer);
-}
-void MojoGLES2Impl::BindSampler(GLuint unit, GLuint sampler) {
- NOTREACHED() << "Unimplemented BindSampler.";
-}
-void MojoGLES2Impl::BindTexture(GLenum target, GLuint texture) {
- MojoGLES2MakeCurrent(context_);
- glBindTexture(target, texture);
-}
-void MojoGLES2Impl::BindTransformFeedback(GLenum target,
- GLuint transformfeedback) {
- NOTREACHED() << "Unimplemented BindTransformFeedback.";
-}
-void MojoGLES2Impl::BlendColor(GLclampf red,
- GLclampf green,
- GLclampf blue,
- GLclampf alpha) {
- MojoGLES2MakeCurrent(context_);
- glBlendColor(red, green, blue, alpha);
-}
-void MojoGLES2Impl::BlendEquation(GLenum mode) {
- MojoGLES2MakeCurrent(context_);
- glBlendEquation(mode);
-}
-void MojoGLES2Impl::BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {
- MojoGLES2MakeCurrent(context_);
- glBlendEquationSeparate(modeRGB, modeAlpha);
-}
-void MojoGLES2Impl::BlendFunc(GLenum sfactor, GLenum dfactor) {
- MojoGLES2MakeCurrent(context_);
- glBlendFunc(sfactor, dfactor);
-}
-void MojoGLES2Impl::BlendFuncSeparate(GLenum srcRGB,
- GLenum dstRGB,
- GLenum srcAlpha,
- GLenum dstAlpha) {
- MojoGLES2MakeCurrent(context_);
- glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
-}
-void MojoGLES2Impl::BufferData(GLenum target,
- GLsizeiptr size,
- const void* data,
- GLenum usage) {
- MojoGLES2MakeCurrent(context_);
- glBufferData(target, size, data, usage);
-}
-void MojoGLES2Impl::BufferSubData(GLenum target,
- GLintptr offset,
- GLsizeiptr size,
- const void* data) {
- MojoGLES2MakeCurrent(context_);
- glBufferSubData(target, offset, size, data);
-}
-GLenum MojoGLES2Impl::CheckFramebufferStatus(GLenum target) {
- MojoGLES2MakeCurrent(context_);
- return glCheckFramebufferStatus(target);
-}
-void MojoGLES2Impl::Clear(GLbitfield mask) {
- MojoGLES2MakeCurrent(context_);
- glClear(mask);
-}
-void MojoGLES2Impl::ClearBufferfi(GLenum buffer,
- GLint drawbuffers,
- GLfloat depth,
- GLint stencil) {
- NOTREACHED() << "Unimplemented ClearBufferfi.";
-}
-void MojoGLES2Impl::ClearBufferfv(GLenum buffer,
- GLint drawbuffers,
- const GLfloat* value) {
- NOTREACHED() << "Unimplemented ClearBufferfv.";
-}
-void MojoGLES2Impl::ClearBufferiv(GLenum buffer,
- GLint drawbuffers,
- const GLint* value) {
- NOTREACHED() << "Unimplemented ClearBufferiv.";
-}
-void MojoGLES2Impl::ClearBufferuiv(GLenum buffer,
- GLint drawbuffers,
- const GLuint* value) {
- NOTREACHED() << "Unimplemented ClearBufferuiv.";
-}
-void MojoGLES2Impl::ClearColor(GLclampf red,
- GLclampf green,
- GLclampf blue,
- GLclampf alpha) {
- MojoGLES2MakeCurrent(context_);
- glClearColor(red, green, blue, alpha);
-}
-void MojoGLES2Impl::ClearDepthf(GLclampf depth) {
- MojoGLES2MakeCurrent(context_);
- glClearDepthf(depth);
-}
-void MojoGLES2Impl::ClearStencil(GLint s) {
- MojoGLES2MakeCurrent(context_);
- glClearStencil(s);
-}
-GLenum MojoGLES2Impl::ClientWaitSync(GLsync sync,
- GLbitfield flags,
- GLuint64 timeout) {
- NOTREACHED() << "Unimplemented ClientWaitSync.";
- return 0;
-}
-void MojoGLES2Impl::ColorMask(GLboolean red,
- GLboolean green,
- GLboolean blue,
- GLboolean alpha) {
- MojoGLES2MakeCurrent(context_);
- glColorMask(red, green, blue, alpha);
-}
-void MojoGLES2Impl::CompileShader(GLuint shader) {
- MojoGLES2MakeCurrent(context_);
- glCompileShader(shader);
-}
-void MojoGLES2Impl::CompressedTexImage2D(GLenum target,
- GLint level,
- GLenum internalformat,
- GLsizei width,
- GLsizei height,
- GLint border,
- GLsizei imageSize,
- const void* data) {
- MojoGLES2MakeCurrent(context_);
- glCompressedTexImage2D(target, level, internalformat, width, height, border,
- imageSize, data);
-}
-void MojoGLES2Impl::CompressedTexSubImage2D(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLsizei imageSize,
- const void* data) {
- MojoGLES2MakeCurrent(context_);
- glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height,
- format, imageSize, data);
-}
-void MojoGLES2Impl::CompressedTexImage3D(GLenum target,
- GLint level,
- GLenum internalformat,
- GLsizei width,
- GLsizei height,
- GLsizei depth,
- GLint border,
- GLsizei imageSize,
- const void* data) {
- NOTREACHED() << "Unimplemented CompressedTexImage3D.";
-}
-void MojoGLES2Impl::CompressedTexSubImage3D(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLint zoffset,
- GLsizei width,
- GLsizei height,
- GLsizei depth,
- GLenum format,
- GLsizei imageSize,
- const void* data) {
- NOTREACHED() << "Unimplemented CompressedTexSubImage3D.";
-}
-void MojoGLES2Impl::CopyBufferSubData(GLenum readtarget,
- GLenum writetarget,
- GLintptr readoffset,
- GLintptr writeoffset,
- GLsizeiptr size) {
- NOTREACHED() << "Unimplemented CopyBufferSubData.";
-}
-void MojoGLES2Impl::CopyTexImage2D(GLenum target,
- GLint level,
- GLenum internalformat,
- GLint x,
- GLint y,
- GLsizei width,
- GLsizei height,
- GLint border) {
- MojoGLES2MakeCurrent(context_);
- glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
-}
-void MojoGLES2Impl::CopyTexSubImage2D(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLint x,
- GLint y,
- GLsizei width,
- GLsizei height) {
- MojoGLES2MakeCurrent(context_);
- glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
-}
-void MojoGLES2Impl::CopyTexSubImage3D(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLint zoffset,
- GLint x,
- GLint y,
- GLsizei width,
- GLsizei height) {
- NOTREACHED() << "Unimplemented CopyTexSubImage3D.";
-}
-GLuint MojoGLES2Impl::CreateProgram() {
- MojoGLES2MakeCurrent(context_);
- return glCreateProgram();
-}
-GLuint MojoGLES2Impl::CreateShader(GLenum type) {
- MojoGLES2MakeCurrent(context_);
- return glCreateShader(type);
-}
-void MojoGLES2Impl::CullFace(GLenum mode) {
- MojoGLES2MakeCurrent(context_);
- glCullFace(mode);
-}
-void MojoGLES2Impl::DeleteBuffers(GLsizei n, const GLuint* buffers) {
- MojoGLES2MakeCurrent(context_);
- glDeleteBuffers(n, buffers);
-}
-void MojoGLES2Impl::DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) {
- MojoGLES2MakeCurrent(context_);
- glDeleteFramebuffers(n, framebuffers);
-}
-void MojoGLES2Impl::DeleteProgram(GLuint program) {
- MojoGLES2MakeCurrent(context_);
- glDeleteProgram(program);
-}
-void MojoGLES2Impl::DeleteRenderbuffers(GLsizei n,
- const GLuint* renderbuffers) {
- MojoGLES2MakeCurrent(context_);
- glDeleteRenderbuffers(n, renderbuffers);
-}
-void MojoGLES2Impl::DeleteSamplers(GLsizei n, const GLuint* samplers) {
- NOTREACHED() << "Unimplemented DeleteSamplers.";
-}
-void MojoGLES2Impl::DeleteSync(GLsync sync) {
- NOTREACHED() << "Unimplemented DeleteSync.";
-}
-void MojoGLES2Impl::DeleteShader(GLuint shader) {
- MojoGLES2MakeCurrent(context_);
- glDeleteShader(shader);
-}
-void MojoGLES2Impl::DeleteTextures(GLsizei n, const GLuint* textures) {
- MojoGLES2MakeCurrent(context_);
- glDeleteTextures(n, textures);
-}
-void MojoGLES2Impl::DeleteTransformFeedbacks(GLsizei n, const GLuint* ids) {
- NOTREACHED() << "Unimplemented DeleteTransformFeedbacks.";
-}
-void MojoGLES2Impl::DepthFunc(GLenum func) {
- MojoGLES2MakeCurrent(context_);
- glDepthFunc(func);
-}
-void MojoGLES2Impl::DepthMask(GLboolean flag) {
- MojoGLES2MakeCurrent(context_);
- glDepthMask(flag);
-}
-void MojoGLES2Impl::DepthRangef(GLclampf zNear, GLclampf zFar) {
- MojoGLES2MakeCurrent(context_);
- glDepthRangef(zNear, zFar);
-}
-void MojoGLES2Impl::DetachShader(GLuint program, GLuint shader) {
- MojoGLES2MakeCurrent(context_);
- glDetachShader(program, shader);
-}
-void MojoGLES2Impl::Disable(GLenum cap) {
- MojoGLES2MakeCurrent(context_);
- glDisable(cap);
-}
-void MojoGLES2Impl::DisableVertexAttribArray(GLuint index) {
- MojoGLES2MakeCurrent(context_);
- glDisableVertexAttribArray(index);
-}
-void MojoGLES2Impl::DrawArrays(GLenum mode, GLint first, GLsizei count) {
- MojoGLES2MakeCurrent(context_);
- glDrawArrays(mode, first, count);
-}
-void MojoGLES2Impl::DrawElements(GLenum mode,
- GLsizei count,
- GLenum type,
- const void* indices) {
- MojoGLES2MakeCurrent(context_);
- glDrawElements(mode, count, type, indices);
-}
-void MojoGLES2Impl::DrawRangeElements(GLenum mode,
- GLuint start,
- GLuint end,
- GLsizei count,
- GLenum type,
- const void* indices) {
- NOTREACHED() << "Unimplemented DrawRangeElements.";
-}
-void MojoGLES2Impl::Enable(GLenum cap) {
- MojoGLES2MakeCurrent(context_);
- glEnable(cap);
-}
-void MojoGLES2Impl::EnableVertexAttribArray(GLuint index) {
- MojoGLES2MakeCurrent(context_);
- glEnableVertexAttribArray(index);
-}
-GLsync MojoGLES2Impl::FenceSync(GLenum condition, GLbitfield flags) {
- NOTREACHED() << "Unimplemented FenceSync.";
- return 0;
-}
-void MojoGLES2Impl::Finish() {
- MojoGLES2MakeCurrent(context_);
- glFinish();
-}
-void MojoGLES2Impl::Flush() {
- MojoGLES2MakeCurrent(context_);
- glFlush();
-}
-void MojoGLES2Impl::FramebufferRenderbuffer(GLenum target,
- GLenum attachment,
- GLenum renderbuffertarget,
- GLuint renderbuffer) {
- MojoGLES2MakeCurrent(context_);
- glFramebufferRenderbuffer(target, attachment, renderbuffertarget,
- renderbuffer);
-}
-void MojoGLES2Impl::FramebufferTexture2D(GLenum target,
- GLenum attachment,
- GLenum textarget,
- GLuint texture,
- GLint level) {
- MojoGLES2MakeCurrent(context_);
- glFramebufferTexture2D(target, attachment, textarget, texture, level);
-}
-void MojoGLES2Impl::FramebufferTextureLayer(GLenum target,
- GLenum attachment,
- GLuint texture,
- GLint level,
- GLint layer) {
- NOTREACHED() << "Unimplemented FramebufferTextureLayer.";
-}
-void MojoGLES2Impl::FrontFace(GLenum mode) {
- MojoGLES2MakeCurrent(context_);
- glFrontFace(mode);
-}
-void MojoGLES2Impl::GenBuffers(GLsizei n, GLuint* buffers) {
- MojoGLES2MakeCurrent(context_);
- glGenBuffers(n, buffers);
-}
-void MojoGLES2Impl::GenerateMipmap(GLenum target) {
- MojoGLES2MakeCurrent(context_);
- glGenerateMipmap(target);
-}
-void MojoGLES2Impl::GenFramebuffers(GLsizei n, GLuint* framebuffers) {
- MojoGLES2MakeCurrent(context_);
- glGenFramebuffers(n, framebuffers);
-}
-void MojoGLES2Impl::GenRenderbuffers(GLsizei n, GLuint* renderbuffers) {
- MojoGLES2MakeCurrent(context_);
- glGenRenderbuffers(n, renderbuffers);
-}
-void MojoGLES2Impl::GenSamplers(GLsizei n, GLuint* samplers) {
- NOTREACHED() << "Unimplemented GenSamplers.";
-}
-void MojoGLES2Impl::GenTextures(GLsizei n, GLuint* textures) {
- MojoGLES2MakeCurrent(context_);
- glGenTextures(n, textures);
-}
-void MojoGLES2Impl::GenTransformFeedbacks(GLsizei n, GLuint* ids) {
- NOTREACHED() << "Unimplemented GenTransformFeedbacks.";
-}
-void MojoGLES2Impl::GetActiveAttrib(GLuint program,
- GLuint index,
- GLsizei bufsize,
- GLsizei* length,
- GLint* size,
- GLenum* type,
- char* name) {
- MojoGLES2MakeCurrent(context_);
- glGetActiveAttrib(program, index, bufsize, length, size, type, name);
-}
-void MojoGLES2Impl::GetActiveUniform(GLuint program,
- GLuint index,
- GLsizei bufsize,
- GLsizei* length,
- GLint* size,
- GLenum* type,
- char* name) {
- MojoGLES2MakeCurrent(context_);
- glGetActiveUniform(program, index, bufsize, length, size, type, name);
-}
-void MojoGLES2Impl::GetActiveUniformBlockiv(GLuint program,
- GLuint index,
- GLenum pname,
- GLint* params) {
- NOTREACHED() << "Unimplemented GetActiveUniformBlockiv.";
-}
-void MojoGLES2Impl::GetActiveUniformBlockName(GLuint program,
- GLuint index,
- GLsizei bufsize,
- GLsizei* length,
- char* name) {
- NOTREACHED() << "Unimplemented GetActiveUniformBlockName.";
-}
-void MojoGLES2Impl::GetActiveUniformsiv(GLuint program,
- GLsizei count,
- const GLuint* indices,
- GLenum pname,
- GLint* params) {
- NOTREACHED() << "Unimplemented GetActiveUniformsiv.";
-}
-void MojoGLES2Impl::GetAttachedShaders(GLuint program,
- GLsizei maxcount,
- GLsizei* count,
- GLuint* shaders) {
- MojoGLES2MakeCurrent(context_);
- glGetAttachedShaders(program, maxcount, count, shaders);
-}
-GLint MojoGLES2Impl::GetAttribLocation(GLuint program, const char* name) {
- MojoGLES2MakeCurrent(context_);
- return glGetAttribLocation(program, name);
-}
-void MojoGLES2Impl::GetBooleanv(GLenum pname, GLboolean* params) {
- MojoGLES2MakeCurrent(context_);
- glGetBooleanv(pname, params);
-}
-void MojoGLES2Impl::GetBufferParameteri64v(GLenum target,
- GLenum pname,
- GLint64* params) {
- NOTREACHED() << "Unimplemented GetBufferParameteri64v.";
-}
-void MojoGLES2Impl::GetBufferParameteriv(GLenum target,
- GLenum pname,
- GLint* params) {
- MojoGLES2MakeCurrent(context_);
- glGetBufferParameteriv(target, pname, params);
-}
-GLenum MojoGLES2Impl::GetError() {
- MojoGLES2MakeCurrent(context_);
- return glGetError();
-}
-void MojoGLES2Impl::GetFloatv(GLenum pname, GLfloat* params) {
- MojoGLES2MakeCurrent(context_);
- glGetFloatv(pname, params);
-}
-GLint MojoGLES2Impl::GetFragDataLocation(GLuint program, const char* name) {
- NOTREACHED() << "Unimplemented GetFragDataLocation.";
- return 0;
-}
-void MojoGLES2Impl::GetFramebufferAttachmentParameteriv(GLenum target,
- GLenum attachment,
- GLenum pname,
- GLint* params) {
- MojoGLES2MakeCurrent(context_);
- glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
-}
-void MojoGLES2Impl::GetInteger64v(GLenum pname, GLint64* params) {
- NOTREACHED() << "Unimplemented GetInteger64v.";
-}
-void MojoGLES2Impl::GetIntegeri_v(GLenum pname, GLuint index, GLint* data) {
- NOTREACHED() << "Unimplemented GetIntegeri_v.";
-}
-void MojoGLES2Impl::GetInteger64i_v(GLenum pname, GLuint index, GLint64* data) {
- NOTREACHED() << "Unimplemented GetInteger64i_v.";
-}
-void MojoGLES2Impl::GetIntegerv(GLenum pname, GLint* params) {
- MojoGLES2MakeCurrent(context_);
- glGetIntegerv(pname, params);
-}
-void MojoGLES2Impl::GetInternalformativ(GLenum target,
- GLenum format,
- GLenum pname,
- GLsizei bufSize,
- GLint* params) {
- NOTREACHED() << "Unimplemented GetInternalformativ.";
-}
-void MojoGLES2Impl::GetProgramiv(GLuint program, GLenum pname, GLint* params) {
- MojoGLES2MakeCurrent(context_);
- glGetProgramiv(program, pname, params);
-}
-void MojoGLES2Impl::GetProgramInfoLog(GLuint program,
- GLsizei bufsize,
- GLsizei* length,
- char* infolog) {
- MojoGLES2MakeCurrent(context_);
- glGetProgramInfoLog(program, bufsize, length, infolog);
-}
-void MojoGLES2Impl::GetRenderbufferParameteriv(GLenum target,
- GLenum pname,
- GLint* params) {
- MojoGLES2MakeCurrent(context_);
- glGetRenderbufferParameteriv(target, pname, params);
-}
-void MojoGLES2Impl::GetSamplerParameterfv(GLuint sampler,
- GLenum pname,
- GLfloat* params) {
- NOTREACHED() << "Unimplemented GetSamplerParameterfv.";
-}
-void MojoGLES2Impl::GetSamplerParameteriv(GLuint sampler,
- GLenum pname,
- GLint* params) {
- NOTREACHED() << "Unimplemented GetSamplerParameteriv.";
-}
-void MojoGLES2Impl::GetShaderiv(GLuint shader, GLenum pname, GLint* params) {
- MojoGLES2MakeCurrent(context_);
- glGetShaderiv(shader, pname, params);
-}
-void MojoGLES2Impl::GetShaderInfoLog(GLuint shader,
- GLsizei bufsize,
- GLsizei* length,
- char* infolog) {
- MojoGLES2MakeCurrent(context_);
- glGetShaderInfoLog(shader, bufsize, length, infolog);
-}
-void MojoGLES2Impl::GetShaderPrecisionFormat(GLenum shadertype,
- GLenum precisiontype,
- GLint* range,
- GLint* precision) {
- MojoGLES2MakeCurrent(context_);
- glGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
-}
-void MojoGLES2Impl::GetShaderSource(GLuint shader,
- GLsizei bufsize,
- GLsizei* length,
- char* source) {
- MojoGLES2MakeCurrent(context_);
- glGetShaderSource(shader, bufsize, length, source);
-}
-const GLubyte* MojoGLES2Impl::GetString(GLenum name) {
- MojoGLES2MakeCurrent(context_);
- return glGetString(name);
-}
-const GLubyte* MojoGLES2Impl::GetStringi(GLenum name, GLuint index) {
- NOTREACHED() << "Unimplemented GetStringi.";
- return 0;
-}
-void MojoGLES2Impl::GetSynciv(GLsync sync,
- GLenum pname,
- GLsizei bufsize,
- GLsizei* length,
- GLint* values) {
- NOTREACHED() << "Unimplemented GetSynciv.";
-}
-void MojoGLES2Impl::GetTexParameterfv(GLenum target,
- GLenum pname,
- GLfloat* params) {
- MojoGLES2MakeCurrent(context_);
- glGetTexParameterfv(target, pname, params);
-}
-void MojoGLES2Impl::GetTexParameteriv(GLenum target,
- GLenum pname,
- GLint* params) {
- MojoGLES2MakeCurrent(context_);
- glGetTexParameteriv(target, pname, params);
-}
-void MojoGLES2Impl::GetTransformFeedbackVarying(GLuint program,
- GLuint index,
- GLsizei bufsize,
- GLsizei* length,
- GLsizei* size,
- GLenum* type,
- char* name) {
- NOTREACHED() << "Unimplemented GetTransformFeedbackVarying.";
-}
-GLuint MojoGLES2Impl::GetUniformBlockIndex(GLuint program, const char* name) {
- NOTREACHED() << "Unimplemented GetUniformBlockIndex.";
- return 0;
-}
-void MojoGLES2Impl::GetUniformfv(GLuint program,
- GLint location,
- GLfloat* params) {
- MojoGLES2MakeCurrent(context_);
- glGetUniformfv(program, location, params);
-}
-void MojoGLES2Impl::GetUniformiv(GLuint program,
- GLint location,
- GLint* params) {
- MojoGLES2MakeCurrent(context_);
- glGetUniformiv(program, location, params);
-}
-void MojoGLES2Impl::GetUniformuiv(GLuint program,
- GLint location,
- GLuint* params) {
- NOTREACHED() << "Unimplemented GetUniformuiv.";
-}
-void MojoGLES2Impl::GetUniformIndices(GLuint program,
- GLsizei count,
- const char* const* names,
- GLuint* indices) {
- NOTREACHED() << "Unimplemented GetUniformIndices.";
-}
-GLint MojoGLES2Impl::GetUniformLocation(GLuint program, const char* name) {
- MojoGLES2MakeCurrent(context_);
- return glGetUniformLocation(program, name);
-}
-void MojoGLES2Impl::GetVertexAttribfv(GLuint index,
- GLenum pname,
- GLfloat* params) {
- MojoGLES2MakeCurrent(context_);
- glGetVertexAttribfv(index, pname, params);
-}
-void MojoGLES2Impl::GetVertexAttribiv(GLuint index,
- GLenum pname,
- GLint* params) {
- MojoGLES2MakeCurrent(context_);
- glGetVertexAttribiv(index, pname, params);
-}
-void MojoGLES2Impl::GetVertexAttribIiv(GLuint index,
- GLenum pname,
- GLint* params) {
- NOTREACHED() << "Unimplemented GetVertexAttribIiv.";
-}
-void MojoGLES2Impl::GetVertexAttribIuiv(GLuint index,
- GLenum pname,
- GLuint* params) {
- NOTREACHED() << "Unimplemented GetVertexAttribIuiv.";
-}
-void MojoGLES2Impl::GetVertexAttribPointerv(GLuint index,
- GLenum pname,
- void** pointer) {
- MojoGLES2MakeCurrent(context_);
- glGetVertexAttribPointerv(index, pname, pointer);
-}
-void MojoGLES2Impl::Hint(GLenum target, GLenum mode) {
- MojoGLES2MakeCurrent(context_);
- glHint(target, mode);
-}
-void MojoGLES2Impl::InvalidateFramebuffer(GLenum target,
- GLsizei count,
- const GLenum* attachments) {
- NOTREACHED() << "Unimplemented InvalidateFramebuffer.";
-}
-void MojoGLES2Impl::InvalidateSubFramebuffer(GLenum target,
- GLsizei count,
- const GLenum* attachments,
- GLint x,
- GLint y,
- GLsizei width,
- GLsizei height) {
- NOTREACHED() << "Unimplemented InvalidateSubFramebuffer.";
-}
-GLboolean MojoGLES2Impl::IsBuffer(GLuint buffer) {
- MojoGLES2MakeCurrent(context_);
- return glIsBuffer(buffer);
-}
-GLboolean MojoGLES2Impl::IsEnabled(GLenum cap) {
- MojoGLES2MakeCurrent(context_);
- return glIsEnabled(cap);
-}
-GLboolean MojoGLES2Impl::IsFramebuffer(GLuint framebuffer) {
- MojoGLES2MakeCurrent(context_);
- return glIsFramebuffer(framebuffer);
-}
-GLboolean MojoGLES2Impl::IsProgram(GLuint program) {
- MojoGLES2MakeCurrent(context_);
- return glIsProgram(program);
-}
-GLboolean MojoGLES2Impl::IsRenderbuffer(GLuint renderbuffer) {
- MojoGLES2MakeCurrent(context_);
- return glIsRenderbuffer(renderbuffer);
-}
-GLboolean MojoGLES2Impl::IsSampler(GLuint sampler) {
- NOTREACHED() << "Unimplemented IsSampler.";
- return 0;
-}
-GLboolean MojoGLES2Impl::IsShader(GLuint shader) {
- MojoGLES2MakeCurrent(context_);
- return glIsShader(shader);
-}
-GLboolean MojoGLES2Impl::IsSync(GLsync sync) {
- NOTREACHED() << "Unimplemented IsSync.";
- return 0;
-}
-GLboolean MojoGLES2Impl::IsTexture(GLuint texture) {
- MojoGLES2MakeCurrent(context_);
- return glIsTexture(texture);
-}
-GLboolean MojoGLES2Impl::IsTransformFeedback(GLuint transformfeedback) {
- NOTREACHED() << "Unimplemented IsTransformFeedback.";
- return 0;
-}
-void MojoGLES2Impl::LineWidth(GLfloat width) {
- MojoGLES2MakeCurrent(context_);
- glLineWidth(width);
-}
-void MojoGLES2Impl::LinkProgram(GLuint program) {
- MojoGLES2MakeCurrent(context_);
- glLinkProgram(program);
-}
-void MojoGLES2Impl::PauseTransformFeedback() {
- NOTREACHED() << "Unimplemented PauseTransformFeedback.";
-}
-void MojoGLES2Impl::PixelStorei(GLenum pname, GLint param) {
- MojoGLES2MakeCurrent(context_);
- glPixelStorei(pname, param);
-}
-void MojoGLES2Impl::PolygonOffset(GLfloat factor, GLfloat units) {
- MojoGLES2MakeCurrent(context_);
- glPolygonOffset(factor, units);
-}
-void MojoGLES2Impl::ReadBuffer(GLenum src) {
- NOTREACHED() << "Unimplemented ReadBuffer.";
-}
-void MojoGLES2Impl::ReadPixels(GLint x,
- GLint y,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLenum type,
- void* pixels) {
- MojoGLES2MakeCurrent(context_);
- glReadPixels(x, y, width, height, format, type, pixels);
-}
-void MojoGLES2Impl::ReleaseShaderCompiler() {
- MojoGLES2MakeCurrent(context_);
- glReleaseShaderCompiler();
-}
-void MojoGLES2Impl::RenderbufferStorage(GLenum target,
- GLenum internalformat,
- GLsizei width,
- GLsizei height) {
- MojoGLES2MakeCurrent(context_);
- glRenderbufferStorage(target, internalformat, width, height);
-}
-void MojoGLES2Impl::ResumeTransformFeedback() {
- NOTREACHED() << "Unimplemented ResumeTransformFeedback.";
-}
-void MojoGLES2Impl::SampleCoverage(GLclampf value, GLboolean invert) {
- MojoGLES2MakeCurrent(context_);
- glSampleCoverage(value, invert);
-}
-void MojoGLES2Impl::SamplerParameterf(GLuint sampler,
- GLenum pname,
- GLfloat param) {
- NOTREACHED() << "Unimplemented SamplerParameterf.";
-}
-void MojoGLES2Impl::SamplerParameterfv(GLuint sampler,
- GLenum pname,
- const GLfloat* params) {
- NOTREACHED() << "Unimplemented SamplerParameterfv.";
-}
-void MojoGLES2Impl::SamplerParameteri(GLuint sampler,
- GLenum pname,
- GLint param) {
- NOTREACHED() << "Unimplemented SamplerParameteri.";
-}
-void MojoGLES2Impl::SamplerParameteriv(GLuint sampler,
- GLenum pname,
- const GLint* params) {
- NOTREACHED() << "Unimplemented SamplerParameteriv.";
-}
-void MojoGLES2Impl::Scissor(GLint x, GLint y, GLsizei width, GLsizei height) {
- MojoGLES2MakeCurrent(context_);
- glScissor(x, y, width, height);
-}
-void MojoGLES2Impl::ShaderBinary(GLsizei n,
- const GLuint* shaders,
- GLenum binaryformat,
- const void* binary,
- GLsizei length) {
- MojoGLES2MakeCurrent(context_);
- glShaderBinary(n, shaders, binaryformat, binary, length);
-}
-void MojoGLES2Impl::ShaderSource(GLuint shader,
- GLsizei count,
- const GLchar* const* str,
- const GLint* length) {
- MojoGLES2MakeCurrent(context_);
- glShaderSource(shader, count, str, length);
-}
-void MojoGLES2Impl::ShallowFinishCHROMIUM() {
- MojoGLES2MakeCurrent(context_);
- glShallowFinishCHROMIUM();
-}
-void MojoGLES2Impl::ShallowFlushCHROMIUM() {
- MojoGLES2MakeCurrent(context_);
- glShallowFlushCHROMIUM();
-}
-void MojoGLES2Impl::OrderingBarrierCHROMIUM() {
- MojoGLES2MakeCurrent(context_);
- glOrderingBarrierCHROMIUM();
-}
-void MojoGLES2Impl::StencilFunc(GLenum func, GLint ref, GLuint mask) {
- MojoGLES2MakeCurrent(context_);
- glStencilFunc(func, ref, mask);
-}
-void MojoGLES2Impl::StencilFuncSeparate(GLenum face,
- GLenum func,
- GLint ref,
- GLuint mask) {
- MojoGLES2MakeCurrent(context_);
- glStencilFuncSeparate(face, func, ref, mask);
-}
-void MojoGLES2Impl::StencilMask(GLuint mask) {
- MojoGLES2MakeCurrent(context_);
- glStencilMask(mask);
-}
-void MojoGLES2Impl::StencilMaskSeparate(GLenum face, GLuint mask) {
- MojoGLES2MakeCurrent(context_);
- glStencilMaskSeparate(face, mask);
-}
-void MojoGLES2Impl::StencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
- MojoGLES2MakeCurrent(context_);
- glStencilOp(fail, zfail, zpass);
-}
-void MojoGLES2Impl::StencilOpSeparate(GLenum face,
- GLenum fail,
- GLenum zfail,
- GLenum zpass) {
- MojoGLES2MakeCurrent(context_);
- glStencilOpSeparate(face, fail, zfail, zpass);
-}
-void MojoGLES2Impl::TexImage2D(GLenum target,
- GLint level,
- GLint internalformat,
- GLsizei width,
- GLsizei height,
- GLint border,
- GLenum format,
- GLenum type,
- const void* pixels) {
- MojoGLES2MakeCurrent(context_);
- glTexImage2D(target, level, internalformat, width, height, border, format,
- type, pixels);
-}
-void MojoGLES2Impl::TexImage3D(GLenum target,
- GLint level,
- GLint internalformat,
- GLsizei width,
- GLsizei height,
- GLsizei depth,
- GLint border,
- GLenum format,
- GLenum type,
- const void* pixels) {
- NOTREACHED() << "Unimplemented TexImage3D.";
-}
-void MojoGLES2Impl::TexParameterf(GLenum target, GLenum pname, GLfloat param) {
- MojoGLES2MakeCurrent(context_);
- glTexParameterf(target, pname, param);
-}
-void MojoGLES2Impl::TexParameterfv(GLenum target,
- GLenum pname,
- const GLfloat* params) {
- MojoGLES2MakeCurrent(context_);
- glTexParameterfv(target, pname, params);
-}
-void MojoGLES2Impl::TexParameteri(GLenum target, GLenum pname, GLint param) {
- MojoGLES2MakeCurrent(context_);
- glTexParameteri(target, pname, param);
-}
-void MojoGLES2Impl::TexParameteriv(GLenum target,
- GLenum pname,
- const GLint* params) {
- MojoGLES2MakeCurrent(context_);
- glTexParameteriv(target, pname, params);
-}
-void MojoGLES2Impl::TexStorage3D(GLenum target,
- GLsizei levels,
- GLenum internalFormat,
- GLsizei width,
- GLsizei height,
- GLsizei depth) {
- NOTREACHED() << "Unimplemented TexStorage3D.";
-}
-void MojoGLES2Impl::TexSubImage2D(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLenum type,
- const void* pixels) {
- MojoGLES2MakeCurrent(context_);
- glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type,
- pixels);
-}
-void MojoGLES2Impl::TexSubImage3D(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLint zoffset,
- GLsizei width,
- GLsizei height,
- GLsizei depth,
- GLenum format,
- GLenum type,
- const void* pixels) {
- NOTREACHED() << "Unimplemented TexSubImage3D.";
-}
-void MojoGLES2Impl::TransformFeedbackVaryings(GLuint program,
- GLsizei count,
- const char* const* varyings,
- GLenum buffermode) {
- NOTREACHED() << "Unimplemented TransformFeedbackVaryings.";
-}
-void MojoGLES2Impl::Uniform1f(GLint location, GLfloat x) {
- MojoGLES2MakeCurrent(context_);
- glUniform1f(location, x);
-}
-void MojoGLES2Impl::Uniform1fv(GLint location,
- GLsizei count,
- const GLfloat* v) {
- MojoGLES2MakeCurrent(context_);
- glUniform1fv(location, count, v);
-}
-void MojoGLES2Impl::Uniform1i(GLint location, GLint x) {
- MojoGLES2MakeCurrent(context_);
- glUniform1i(location, x);
-}
-void MojoGLES2Impl::Uniform1iv(GLint location, GLsizei count, const GLint* v) {
- MojoGLES2MakeCurrent(context_);
- glUniform1iv(location, count, v);
-}
-void MojoGLES2Impl::Uniform1ui(GLint location, GLuint x) {
- NOTREACHED() << "Unimplemented Uniform1ui.";
-}
-void MojoGLES2Impl::Uniform1uiv(GLint location,
- GLsizei count,
- const GLuint* v) {
- NOTREACHED() << "Unimplemented Uniform1uiv.";
-}
-void MojoGLES2Impl::Uniform2f(GLint location, GLfloat x, GLfloat y) {
- MojoGLES2MakeCurrent(context_);
- glUniform2f(location, x, y);
-}
-void MojoGLES2Impl::Uniform2fv(GLint location,
- GLsizei count,
- const GLfloat* v) {
- MojoGLES2MakeCurrent(context_);
- glUniform2fv(location, count, v);
-}
-void MojoGLES2Impl::Uniform2i(GLint location, GLint x, GLint y) {
- MojoGLES2MakeCurrent(context_);
- glUniform2i(location, x, y);
-}
-void MojoGLES2Impl::Uniform2iv(GLint location, GLsizei count, const GLint* v) {
- MojoGLES2MakeCurrent(context_);
- glUniform2iv(location, count, v);
-}
-void MojoGLES2Impl::Uniform2ui(GLint location, GLuint x, GLuint y) {
- NOTREACHED() << "Unimplemented Uniform2ui.";
-}
-void MojoGLES2Impl::Uniform2uiv(GLint location,
- GLsizei count,
- const GLuint* v) {
- NOTREACHED() << "Unimplemented Uniform2uiv.";
-}
-void MojoGLES2Impl::Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) {
- MojoGLES2MakeCurrent(context_);
- glUniform3f(location, x, y, z);
-}
-void MojoGLES2Impl::Uniform3fv(GLint location,
- GLsizei count,
- const GLfloat* v) {
- MojoGLES2MakeCurrent(context_);
- glUniform3fv(location, count, v);
-}
-void MojoGLES2Impl::Uniform3i(GLint location, GLint x, GLint y, GLint z) {
- MojoGLES2MakeCurrent(context_);
- glUniform3i(location, x, y, z);
-}
-void MojoGLES2Impl::Uniform3iv(GLint location, GLsizei count, const GLint* v) {
- MojoGLES2MakeCurrent(context_);
- glUniform3iv(location, count, v);
-}
-void MojoGLES2Impl::Uniform3ui(GLint location, GLuint x, GLuint y, GLuint z) {
- NOTREACHED() << "Unimplemented Uniform3ui.";
-}
-void MojoGLES2Impl::Uniform3uiv(GLint location,
- GLsizei count,
- const GLuint* v) {
- NOTREACHED() << "Unimplemented Uniform3uiv.";
-}
-void MojoGLES2Impl::Uniform4f(GLint location,
- GLfloat x,
- GLfloat y,
- GLfloat z,
- GLfloat w) {
- MojoGLES2MakeCurrent(context_);
- glUniform4f(location, x, y, z, w);
-}
-void MojoGLES2Impl::Uniform4fv(GLint location,
- GLsizei count,
- const GLfloat* v) {
- MojoGLES2MakeCurrent(context_);
- glUniform4fv(location, count, v);
-}
-void MojoGLES2Impl::Uniform4i(GLint location,
- GLint x,
- GLint y,
- GLint z,
- GLint w) {
- MojoGLES2MakeCurrent(context_);
- glUniform4i(location, x, y, z, w);
-}
-void MojoGLES2Impl::Uniform4iv(GLint location, GLsizei count, const GLint* v) {
- MojoGLES2MakeCurrent(context_);
- glUniform4iv(location, count, v);
-}
-void MojoGLES2Impl::Uniform4ui(GLint location,
- GLuint x,
- GLuint y,
- GLuint z,
- GLuint w) {
- NOTREACHED() << "Unimplemented Uniform4ui.";
-}
-void MojoGLES2Impl::Uniform4uiv(GLint location,
- GLsizei count,
- const GLuint* v) {
- NOTREACHED() << "Unimplemented Uniform4uiv.";
-}
-void MojoGLES2Impl::UniformBlockBinding(GLuint program,
- GLuint index,
- GLuint binding) {
- NOTREACHED() << "Unimplemented UniformBlockBinding.";
-}
-void MojoGLES2Impl::UniformMatrix2fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) {
- MojoGLES2MakeCurrent(context_);
- glUniformMatrix2fv(location, count, transpose, value);
-}
-void MojoGLES2Impl::UniformMatrix2x3fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) {
- NOTREACHED() << "Unimplemented UniformMatrix2x3fv.";
-}
-void MojoGLES2Impl::UniformMatrix2x4fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) {
- NOTREACHED() << "Unimplemented UniformMatrix2x4fv.";
-}
-void MojoGLES2Impl::UniformMatrix3fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) {
- MojoGLES2MakeCurrent(context_);
- glUniformMatrix3fv(location, count, transpose, value);
-}
-void MojoGLES2Impl::UniformMatrix3x2fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) {
- NOTREACHED() << "Unimplemented UniformMatrix3x2fv.";
-}
-void MojoGLES2Impl::UniformMatrix3x4fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) {
- NOTREACHED() << "Unimplemented UniformMatrix3x4fv.";
-}
-void MojoGLES2Impl::UniformMatrix4fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) {
- MojoGLES2MakeCurrent(context_);
- glUniformMatrix4fv(location, count, transpose, value);
-}
-void MojoGLES2Impl::UniformMatrix4x2fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) {
- NOTREACHED() << "Unimplemented UniformMatrix4x2fv.";
-}
-void MojoGLES2Impl::UniformMatrix4x3fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) {
- NOTREACHED() << "Unimplemented UniformMatrix4x3fv.";
-}
-void MojoGLES2Impl::UseProgram(GLuint program) {
- MojoGLES2MakeCurrent(context_);
- glUseProgram(program);
-}
-void MojoGLES2Impl::ValidateProgram(GLuint program) {
- MojoGLES2MakeCurrent(context_);
- glValidateProgram(program);
-}
-void MojoGLES2Impl::VertexAttrib1f(GLuint indx, GLfloat x) {
- MojoGLES2MakeCurrent(context_);
- glVertexAttrib1f(indx, x);
-}
-void MojoGLES2Impl::VertexAttrib1fv(GLuint indx, const GLfloat* values) {
- MojoGLES2MakeCurrent(context_);
- glVertexAttrib1fv(indx, values);
-}
-void MojoGLES2Impl::VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) {
- MojoGLES2MakeCurrent(context_);
- glVertexAttrib2f(indx, x, y);
-}
-void MojoGLES2Impl::VertexAttrib2fv(GLuint indx, const GLfloat* values) {
- MojoGLES2MakeCurrent(context_);
- glVertexAttrib2fv(indx, values);
-}
-void MojoGLES2Impl::VertexAttrib3f(GLuint indx,
- GLfloat x,
- GLfloat y,
- GLfloat z) {
- MojoGLES2MakeCurrent(context_);
- glVertexAttrib3f(indx, x, y, z);
-}
-void MojoGLES2Impl::VertexAttrib3fv(GLuint indx, const GLfloat* values) {
- MojoGLES2MakeCurrent(context_);
- glVertexAttrib3fv(indx, values);
-}
-void MojoGLES2Impl::VertexAttrib4f(GLuint indx,
- GLfloat x,
- GLfloat y,
- GLfloat z,
- GLfloat w) {
- MojoGLES2MakeCurrent(context_);
- glVertexAttrib4f(indx, x, y, z, w);
-}
-void MojoGLES2Impl::VertexAttrib4fv(GLuint indx, const GLfloat* values) {
- MojoGLES2MakeCurrent(context_);
- glVertexAttrib4fv(indx, values);
-}
-void MojoGLES2Impl::VertexAttribI4i(GLuint indx,
- GLint x,
- GLint y,
- GLint z,
- GLint w) {
- NOTREACHED() << "Unimplemented VertexAttribI4i.";
-}
-void MojoGLES2Impl::VertexAttribI4iv(GLuint indx, const GLint* values) {
- NOTREACHED() << "Unimplemented VertexAttribI4iv.";
-}
-void MojoGLES2Impl::VertexAttribI4ui(GLuint indx,
- GLuint x,
- GLuint y,
- GLuint z,
- GLuint w) {
- NOTREACHED() << "Unimplemented VertexAttribI4ui.";
-}
-void MojoGLES2Impl::VertexAttribI4uiv(GLuint indx, const GLuint* values) {
- NOTREACHED() << "Unimplemented VertexAttribI4uiv.";
-}
-void MojoGLES2Impl::VertexAttribIPointer(GLuint indx,
- GLint size,
- GLenum type,
- GLsizei stride,
- const void* ptr) {
- NOTREACHED() << "Unimplemented VertexAttribIPointer.";
-}
-void MojoGLES2Impl::VertexAttribPointer(GLuint indx,
- GLint size,
- GLenum type,
- GLboolean normalized,
- GLsizei stride,
- const void* ptr) {
- MojoGLES2MakeCurrent(context_);
- glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
-}
-void MojoGLES2Impl::Viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
- MojoGLES2MakeCurrent(context_);
- glViewport(x, y, width, height);
-}
-void MojoGLES2Impl::WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
- NOTREACHED() << "Unimplemented WaitSync.";
-}
-void MojoGLES2Impl::BlitFramebufferCHROMIUM(GLint srcX0,
- GLint srcY0,
- GLint srcX1,
- GLint srcY1,
- GLint dstX0,
- GLint dstY0,
- GLint dstX1,
- GLint dstY1,
- GLbitfield mask,
- GLenum filter) {
- MojoGLES2MakeCurrent(context_);
- glBlitFramebufferCHROMIUM(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1,
- dstY1, mask, filter);
-}
-void MojoGLES2Impl::RenderbufferStorageMultisampleCHROMIUM(
- GLenum target,
- GLsizei samples,
- GLenum internalformat,
- GLsizei width,
- GLsizei height) {
- MojoGLES2MakeCurrent(context_);
- glRenderbufferStorageMultisampleCHROMIUM(target, samples, internalformat,
- width, height);
-}
-void MojoGLES2Impl::RenderbufferStorageMultisampleEXT(GLenum target,
- GLsizei samples,
- GLenum internalformat,
- GLsizei width,
- GLsizei height) {
- MojoGLES2MakeCurrent(context_);
- glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width,
- height);
-}
-void MojoGLES2Impl::FramebufferTexture2DMultisampleEXT(GLenum target,
- GLenum attachment,
- GLenum textarget,
- GLuint texture,
- GLint level,
- GLsizei samples) {
- MojoGLES2MakeCurrent(context_);
- glFramebufferTexture2DMultisampleEXT(target, attachment, textarget, texture,
- level, samples);
-}
-void MojoGLES2Impl::TexStorage2DEXT(GLenum target,
- GLsizei levels,
- GLenum internalFormat,
- GLsizei width,
- GLsizei height) {
- MojoGLES2MakeCurrent(context_);
- glTexStorage2DEXT(target, levels, internalFormat, width, height);
-}
-void MojoGLES2Impl::GenQueriesEXT(GLsizei n, GLuint* queries) {
- MojoGLES2MakeCurrent(context_);
- glGenQueriesEXT(n, queries);
-}
-void MojoGLES2Impl::DeleteQueriesEXT(GLsizei n, const GLuint* queries) {
- MojoGLES2MakeCurrent(context_);
- glDeleteQueriesEXT(n, queries);
-}
-void MojoGLES2Impl::QueryCounterEXT(GLuint id, GLenum target) {
- MojoGLES2MakeCurrent(context_);
- glQueryCounterEXT(id, target);
-}
-GLboolean MojoGLES2Impl::IsQueryEXT(GLuint id) {
- MojoGLES2MakeCurrent(context_);
- return glIsQueryEXT(id);
-}
-void MojoGLES2Impl::BeginQueryEXT(GLenum target, GLuint id) {
- MojoGLES2MakeCurrent(context_);
- glBeginQueryEXT(target, id);
-}
-void MojoGLES2Impl::BeginTransformFeedback(GLenum primitivemode) {
- NOTREACHED() << "Unimplemented BeginTransformFeedback.";
-}
-void MojoGLES2Impl::EndQueryEXT(GLenum target) {
- MojoGLES2MakeCurrent(context_);
- glEndQueryEXT(target);
-}
-void MojoGLES2Impl::EndTransformFeedback() {
- NOTREACHED() << "Unimplemented EndTransformFeedback.";
-}
-void MojoGLES2Impl::GetQueryivEXT(GLenum target, GLenum pname, GLint* params) {
- MojoGLES2MakeCurrent(context_);
- glGetQueryivEXT(target, pname, params);
-}
-void MojoGLES2Impl::GetQueryObjectivEXT(GLuint id,
- GLenum pname,
- GLint* params) {
- MojoGLES2MakeCurrent(context_);
- glGetQueryObjectivEXT(id, pname, params);
-}
-void MojoGLES2Impl::GetQueryObjectuivEXT(GLuint id,
- GLenum pname,
- GLuint* params) {
- MojoGLES2MakeCurrent(context_);
- glGetQueryObjectuivEXT(id, pname, params);
-}
-void MojoGLES2Impl::GetQueryObjecti64vEXT(GLuint id,
- GLenum pname,
- GLint64* params) {
- MojoGLES2MakeCurrent(context_);
- glGetQueryObjecti64vEXT(id, pname, params);
-}
-void MojoGLES2Impl::GetQueryObjectui64vEXT(GLuint id,
- GLenum pname,
- GLuint64* params) {
- MojoGLES2MakeCurrent(context_);
- glGetQueryObjectui64vEXT(id, pname, params);
-}
-void MojoGLES2Impl::SetDisjointValueSyncCHROMIUM() {
- MojoGLES2MakeCurrent(context_);
- glSetDisjointValueSyncCHROMIUM();
-}
-void MojoGLES2Impl::InsertEventMarkerEXT(GLsizei length, const GLchar* marker) {
- MojoGLES2MakeCurrent(context_);
- glInsertEventMarkerEXT(length, marker);
-}
-void MojoGLES2Impl::PushGroupMarkerEXT(GLsizei length, const GLchar* marker) {
- MojoGLES2MakeCurrent(context_);
- glPushGroupMarkerEXT(length, marker);
-}
-void MojoGLES2Impl::PopGroupMarkerEXT() {
- MojoGLES2MakeCurrent(context_);
- glPopGroupMarkerEXT();
-}
-void MojoGLES2Impl::GenVertexArraysOES(GLsizei n, GLuint* arrays) {
- MojoGLES2MakeCurrent(context_);
- glGenVertexArraysOES(n, arrays);
-}
-void MojoGLES2Impl::DeleteVertexArraysOES(GLsizei n, const GLuint* arrays) {
- MojoGLES2MakeCurrent(context_);
- glDeleteVertexArraysOES(n, arrays);
-}
-GLboolean MojoGLES2Impl::IsVertexArrayOES(GLuint array) {
- MojoGLES2MakeCurrent(context_);
- return glIsVertexArrayOES(array);
-}
-void MojoGLES2Impl::BindVertexArrayOES(GLuint array) {
- MojoGLES2MakeCurrent(context_);
- glBindVertexArrayOES(array);
-}
-void MojoGLES2Impl::SwapBuffers() {
- MojoGLES2MakeCurrent(context_);
- glSwapBuffers();
-}
-GLuint MojoGLES2Impl::GetMaxValueInBufferCHROMIUM(GLuint buffer_id,
- GLsizei count,
- GLenum type,
- GLuint offset) {
- MojoGLES2MakeCurrent(context_);
- return glGetMaxValueInBufferCHROMIUM(buffer_id, count, type, offset);
-}
-GLboolean MojoGLES2Impl::EnableFeatureCHROMIUM(const char* feature) {
- MojoGLES2MakeCurrent(context_);
- return glEnableFeatureCHROMIUM(feature);
-}
-void* MojoGLES2Impl::MapBufferCHROMIUM(GLuint target, GLenum access) {
- MojoGLES2MakeCurrent(context_);
- return glMapBufferCHROMIUM(target, access);
-}
-GLboolean MojoGLES2Impl::UnmapBufferCHROMIUM(GLuint target) {
- MojoGLES2MakeCurrent(context_);
- return glUnmapBufferCHROMIUM(target);
-}
-void* MojoGLES2Impl::MapBufferSubDataCHROMIUM(GLuint target,
- GLintptr offset,
- GLsizeiptr size,
- GLenum access) {
- MojoGLES2MakeCurrent(context_);
- return glMapBufferSubDataCHROMIUM(target, offset, size, access);
-}
-void MojoGLES2Impl::UnmapBufferSubDataCHROMIUM(const void* mem) {
- MojoGLES2MakeCurrent(context_);
- glUnmapBufferSubDataCHROMIUM(mem);
-}
-void* MojoGLES2Impl::MapBufferRange(GLenum target,
- GLintptr offset,
- GLsizeiptr size,
- GLbitfield access) {
- NOTREACHED() << "Unimplemented MapBufferRange.";
- return 0;
-}
-GLboolean MojoGLES2Impl::UnmapBuffer(GLenum target) {
- NOTREACHED() << "Unimplemented UnmapBuffer.";
- return 0;
-}
-void* MojoGLES2Impl::MapTexSubImage2DCHROMIUM(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLenum type,
- GLenum access) {
- MojoGLES2MakeCurrent(context_);
- return glMapTexSubImage2DCHROMIUM(target, level, xoffset, yoffset, width,
- height, format, type, access);
-}
-void MojoGLES2Impl::UnmapTexSubImage2DCHROMIUM(const void* mem) {
- MojoGLES2MakeCurrent(context_);
- glUnmapTexSubImage2DCHROMIUM(mem);
-}
-void MojoGLES2Impl::ResizeCHROMIUM(GLuint width,
- GLuint height,
- GLfloat scale_factor,
- GLboolean alpha) {
- MojoGLES2MakeCurrent(context_);
- glResizeCHROMIUM(width, height, scale_factor, alpha);
-}
-const GLchar* MojoGLES2Impl::GetRequestableExtensionsCHROMIUM() {
- MojoGLES2MakeCurrent(context_);
- return glGetRequestableExtensionsCHROMIUM();
-}
-void MojoGLES2Impl::RequestExtensionCHROMIUM(const char* extension) {
- MojoGLES2MakeCurrent(context_);
- glRequestExtensionCHROMIUM(extension);
-}
-void MojoGLES2Impl::GetProgramInfoCHROMIUM(GLuint program,
- GLsizei bufsize,
- GLsizei* size,
- void* info) {
- MojoGLES2MakeCurrent(context_);
- glGetProgramInfoCHROMIUM(program, bufsize, size, info);
-}
-void MojoGLES2Impl::GetUniformBlocksCHROMIUM(GLuint program,
- GLsizei bufsize,
- GLsizei* size,
- void* info) {
- NOTREACHED() << "Unimplemented GetUniformBlocksCHROMIUM.";
-}
-void MojoGLES2Impl::GetTransformFeedbackVaryingsCHROMIUM(GLuint program,
- GLsizei bufsize,
- GLsizei* size,
- void* info) {
- NOTREACHED() << "Unimplemented GetTransformFeedbackVaryingsCHROMIUM.";
-}
-void MojoGLES2Impl::GetUniformsES3CHROMIUM(GLuint program,
- GLsizei bufsize,
- GLsizei* size,
- void* info) {
- NOTREACHED() << "Unimplemented GetUniformsES3CHROMIUM.";
-}
-GLuint MojoGLES2Impl::CreateImageCHROMIUM(ClientBuffer buffer,
- GLsizei width,
- GLsizei height,
- GLenum internalformat) {
- MojoGLES2MakeCurrent(context_);
- return glCreateImageCHROMIUM(buffer, width, height, internalformat);
-}
-void MojoGLES2Impl::DestroyImageCHROMIUM(GLuint image_id) {
- MojoGLES2MakeCurrent(context_);
- glDestroyImageCHROMIUM(image_id);
-}
-GLuint MojoGLES2Impl::CreateGpuMemoryBufferImageCHROMIUM(GLsizei width,
- GLsizei height,
- GLenum internalformat,
- GLenum usage) {
- MojoGLES2MakeCurrent(context_);
- return glCreateGpuMemoryBufferImageCHROMIUM(width, height, internalformat,
- usage);
-}
-void MojoGLES2Impl::GetTranslatedShaderSourceANGLE(GLuint shader,
- GLsizei bufsize,
- GLsizei* length,
- char* source) {
- MojoGLES2MakeCurrent(context_);
- glGetTranslatedShaderSourceANGLE(shader, bufsize, length, source);
-}
-void MojoGLES2Impl::PostSubBufferCHROMIUM(GLint x,
- GLint y,
- GLint width,
- GLint height) {
- MojoGLES2MakeCurrent(context_);
- glPostSubBufferCHROMIUM(x, y, width, height);
-}
-void MojoGLES2Impl::CopyTextureCHROMIUM(GLenum source_id,
- GLenum dest_id,
- GLint internalformat,
- GLenum dest_type,
- GLboolean unpack_flip_y,
- GLboolean unpack_premultiply_alpha,
- GLboolean unpack_unmultiply_alpha) {
- MojoGLES2MakeCurrent(context_);
- glCopyTextureCHROMIUM(source_id, dest_id, internalformat, dest_type,
- unpack_flip_y, unpack_premultiply_alpha,
- unpack_unmultiply_alpha);
-}
-void MojoGLES2Impl::CopySubTextureCHROMIUM(GLenum source_id,
- GLenum dest_id,
- GLint xoffset,
- GLint yoffset,
- GLint x,
- GLint y,
- GLsizei width,
- GLsizei height,
- GLboolean unpack_flip_y,
- GLboolean unpack_premultiply_alpha,
- GLboolean unpack_unmultiply_alpha) {
- MojoGLES2MakeCurrent(context_);
- glCopySubTextureCHROMIUM(source_id, dest_id, xoffset, yoffset, x, y, width,
- height, unpack_flip_y, unpack_premultiply_alpha,
- unpack_unmultiply_alpha);
-}
-void MojoGLES2Impl::CompressedCopyTextureCHROMIUM(GLenum source_id,
- GLenum dest_id) {
- MojoGLES2MakeCurrent(context_);
- glCompressedCopyTextureCHROMIUM(source_id, dest_id);
-}
-void MojoGLES2Impl::DrawArraysInstancedANGLE(GLenum mode,
- GLint first,
- GLsizei count,
- GLsizei primcount) {
- MojoGLES2MakeCurrent(context_);
- glDrawArraysInstancedANGLE(mode, first, count, primcount);
-}
-void MojoGLES2Impl::DrawElementsInstancedANGLE(GLenum mode,
- GLsizei count,
- GLenum type,
- const void* indices,
- GLsizei primcount) {
- MojoGLES2MakeCurrent(context_);
- glDrawElementsInstancedANGLE(mode, count, type, indices, primcount);
-}
-void MojoGLES2Impl::VertexAttribDivisorANGLE(GLuint index, GLuint divisor) {
- MojoGLES2MakeCurrent(context_);
- glVertexAttribDivisorANGLE(index, divisor);
-}
-void MojoGLES2Impl::GenMailboxCHROMIUM(GLbyte* mailbox) {
- MojoGLES2MakeCurrent(context_);
- glGenMailboxCHROMIUM(mailbox);
-}
-void MojoGLES2Impl::ProduceTextureCHROMIUM(GLenum target,
- const GLbyte* mailbox) {
- MojoGLES2MakeCurrent(context_);
- glProduceTextureCHROMIUM(target, mailbox);
-}
-void MojoGLES2Impl::ProduceTextureDirectCHROMIUM(GLuint texture,
- GLenum target,
- const GLbyte* mailbox) {
- MojoGLES2MakeCurrent(context_);
- glProduceTextureDirectCHROMIUM(texture, target, mailbox);
-}
-void MojoGLES2Impl::ConsumeTextureCHROMIUM(GLenum target,
- const GLbyte* mailbox) {
- MojoGLES2MakeCurrent(context_);
- glConsumeTextureCHROMIUM(target, mailbox);
-}
-GLuint MojoGLES2Impl::CreateAndConsumeTextureCHROMIUM(GLenum target,
- const GLbyte* mailbox) {
- MojoGLES2MakeCurrent(context_);
- return glCreateAndConsumeTextureCHROMIUM(target, mailbox);
-}
-void MojoGLES2Impl::BindUniformLocationCHROMIUM(GLuint program,
- GLint location,
- const char* name) {
- MojoGLES2MakeCurrent(context_);
- glBindUniformLocationCHROMIUM(program, location, name);
-}
-void MojoGLES2Impl::BindTexImage2DCHROMIUM(GLenum target, GLint imageId) {
- MojoGLES2MakeCurrent(context_);
- glBindTexImage2DCHROMIUM(target, imageId);
-}
-void MojoGLES2Impl::ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) {
- MojoGLES2MakeCurrent(context_);
- glReleaseTexImage2DCHROMIUM(target, imageId);
-}
-void MojoGLES2Impl::TraceBeginCHROMIUM(const char* category_name,
- const char* trace_name) {
- MojoGLES2MakeCurrent(context_);
- glTraceBeginCHROMIUM(category_name, trace_name);
-}
-void MojoGLES2Impl::TraceEndCHROMIUM() {
- MojoGLES2MakeCurrent(context_);
- glTraceEndCHROMIUM();
-}
-void MojoGLES2Impl::DiscardFramebufferEXT(GLenum target,
- GLsizei count,
- const GLenum* attachments) {
- MojoGLES2MakeCurrent(context_);
- glDiscardFramebufferEXT(target, count, attachments);
-}
-void MojoGLES2Impl::LoseContextCHROMIUM(GLenum current, GLenum other) {
- MojoGLES2MakeCurrent(context_);
- glLoseContextCHROMIUM(current, other);
-}
-GLuint64 MojoGLES2Impl::InsertFenceSyncCHROMIUM() {
- MojoGLES2MakeCurrent(context_);
- return glInsertFenceSyncCHROMIUM();
-}
-void MojoGLES2Impl::GenSyncTokenCHROMIUM(GLuint64 fence_sync,
- GLbyte* sync_token) {
- MojoGLES2MakeCurrent(context_);
- glGenSyncTokenCHROMIUM(fence_sync, sync_token);
-}
-void MojoGLES2Impl::GenUnverifiedSyncTokenCHROMIUM(GLuint64 fence_sync,
- GLbyte* sync_token) {
- MojoGLES2MakeCurrent(context_);
- glGenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token);
-}
-void MojoGLES2Impl::VerifySyncTokensCHROMIUM(GLbyte** sync_tokens,
- GLsizei count) {
- MojoGLES2MakeCurrent(context_);
- glVerifySyncTokensCHROMIUM(sync_tokens, count);
-}
-void MojoGLES2Impl::WaitSyncTokenCHROMIUM(const GLbyte* sync_token) {
- MojoGLES2MakeCurrent(context_);
- glWaitSyncTokenCHROMIUM(sync_token);
-}
-void MojoGLES2Impl::DrawBuffersEXT(GLsizei count, const GLenum* bufs) {
- MojoGLES2MakeCurrent(context_);
- glDrawBuffersEXT(count, bufs);
-}
-void MojoGLES2Impl::DiscardBackbufferCHROMIUM() {
- MojoGLES2MakeCurrent(context_);
- glDiscardBackbufferCHROMIUM();
-}
-void MojoGLES2Impl::ScheduleOverlayPlaneCHROMIUM(GLint plane_z_order,
- GLenum plane_transform,
- GLuint overlay_texture_id,
- GLint bounds_x,
- GLint bounds_y,
- GLint bounds_width,
- GLint bounds_height,
- GLfloat uv_x,
- GLfloat uv_y,
- GLfloat uv_width,
- GLfloat uv_height) {
- MojoGLES2MakeCurrent(context_);
- glScheduleOverlayPlaneCHROMIUM(
- plane_z_order, plane_transform, overlay_texture_id, bounds_x, bounds_y,
- bounds_width, bounds_height, uv_x, uv_y, uv_width, uv_height);
-}
-void MojoGLES2Impl::ScheduleCALayerCHROMIUM(GLuint contents_texture_id,
- const GLfloat* contents_rect,
- GLfloat opacity,
- GLuint background_color,
- GLuint edge_aa_mask,
- const GLfloat* bounds_rect,
- GLboolean is_clipped,
- const GLfloat* clip_rect,
- GLint sorting_context_id,
- const GLfloat* transform,
- GLuint filter) {
- MojoGLES2MakeCurrent(context_);
- glScheduleCALayerCHROMIUM(contents_texture_id, contents_rect, opacity,
- background_color, edge_aa_mask, bounds_rect,
- is_clipped, clip_rect, sorting_context_id,
- transform, filter);
-}
-void MojoGLES2Impl::CommitOverlayPlanesCHROMIUM() {
- MojoGLES2MakeCurrent(context_);
- glCommitOverlayPlanesCHROMIUM();
-}
-void MojoGLES2Impl::SwapInterval(GLint interval) {
- MojoGLES2MakeCurrent(context_);
- glSwapInterval(interval);
-}
-void MojoGLES2Impl::FlushDriverCachesCHROMIUM() {
- MojoGLES2MakeCurrent(context_);
- glFlushDriverCachesCHROMIUM();
-}
-GLuint MojoGLES2Impl::GetLastFlushIdCHROMIUM() {
- MojoGLES2MakeCurrent(context_);
- return glGetLastFlushIdCHROMIUM();
-}
-void MojoGLES2Impl::MatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat* m) {
- MojoGLES2MakeCurrent(context_);
- glMatrixLoadfCHROMIUM(matrixMode, m);
-}
-void MojoGLES2Impl::MatrixLoadIdentityCHROMIUM(GLenum matrixMode) {
- MojoGLES2MakeCurrent(context_);
- glMatrixLoadIdentityCHROMIUM(matrixMode);
-}
-GLuint MojoGLES2Impl::GenPathsCHROMIUM(GLsizei range) {
- MojoGLES2MakeCurrent(context_);
- return glGenPathsCHROMIUM(range);
-}
-void MojoGLES2Impl::DeletePathsCHROMIUM(GLuint path, GLsizei range) {
- MojoGLES2MakeCurrent(context_);
- glDeletePathsCHROMIUM(path, range);
-}
-GLboolean MojoGLES2Impl::IsPathCHROMIUM(GLuint path) {
- MojoGLES2MakeCurrent(context_);
- return glIsPathCHROMIUM(path);
-}
-void MojoGLES2Impl::PathCommandsCHROMIUM(GLuint path,
- GLsizei numCommands,
- const GLubyte* commands,
- GLsizei numCoords,
- GLenum coordType,
- const GLvoid* coords) {
- MojoGLES2MakeCurrent(context_);
- glPathCommandsCHROMIUM(path, numCommands, commands, numCoords, coordType,
- coords);
-}
-void MojoGLES2Impl::PathParameterfCHROMIUM(GLuint path,
- GLenum pname,
- GLfloat value) {
- MojoGLES2MakeCurrent(context_);
- glPathParameterfCHROMIUM(path, pname, value);
-}
-void MojoGLES2Impl::PathParameteriCHROMIUM(GLuint path,
- GLenum pname,
- GLint value) {
- MojoGLES2MakeCurrent(context_);
- glPathParameteriCHROMIUM(path, pname, value);
-}
-void MojoGLES2Impl::PathStencilFuncCHROMIUM(GLenum func,
- GLint ref,
- GLuint mask) {
- MojoGLES2MakeCurrent(context_);
- glPathStencilFuncCHROMIUM(func, ref, mask);
-}
-void MojoGLES2Impl::StencilFillPathCHROMIUM(GLuint path,
- GLenum fillMode,
- GLuint mask) {
- MojoGLES2MakeCurrent(context_);
- glStencilFillPathCHROMIUM(path, fillMode, mask);
-}
-void MojoGLES2Impl::StencilStrokePathCHROMIUM(GLuint path,
- GLint reference,
- GLuint mask) {
- MojoGLES2MakeCurrent(context_);
- glStencilStrokePathCHROMIUM(path, reference, mask);
-}
-void MojoGLES2Impl::CoverFillPathCHROMIUM(GLuint path, GLenum coverMode) {
- MojoGLES2MakeCurrent(context_);
- glCoverFillPathCHROMIUM(path, coverMode);
-}
-void MojoGLES2Impl::CoverStrokePathCHROMIUM(GLuint path, GLenum coverMode) {
- MojoGLES2MakeCurrent(context_);
- glCoverStrokePathCHROMIUM(path, coverMode);
-}
-void MojoGLES2Impl::StencilThenCoverFillPathCHROMIUM(GLuint path,
- GLenum fillMode,
- GLuint mask,
- GLenum coverMode) {
- MojoGLES2MakeCurrent(context_);
- glStencilThenCoverFillPathCHROMIUM(path, fillMode, mask, coverMode);
-}
-void MojoGLES2Impl::StencilThenCoverStrokePathCHROMIUM(GLuint path,
- GLint reference,
- GLuint mask,
- GLenum coverMode) {
- MojoGLES2MakeCurrent(context_);
- glStencilThenCoverStrokePathCHROMIUM(path, reference, mask, coverMode);
-}
-void MojoGLES2Impl::StencilFillPathInstancedCHROMIUM(
- GLsizei numPaths,
- GLenum pathNameType,
- const GLvoid* paths,
- GLuint pathBase,
- GLenum fillMode,
- GLuint mask,
- GLenum transformType,
- const GLfloat* transformValues) {
- MojoGLES2MakeCurrent(context_);
- glStencilFillPathInstancedCHROMIUM(numPaths, pathNameType, paths, pathBase,
- fillMode, mask, transformType,
- transformValues);
-}
-void MojoGLES2Impl::StencilStrokePathInstancedCHROMIUM(
- GLsizei numPaths,
- GLenum pathNameType,
- const GLvoid* paths,
- GLuint pathBase,
- GLint reference,
- GLuint mask,
- GLenum transformType,
- const GLfloat* transformValues) {
- MojoGLES2MakeCurrent(context_);
- glStencilStrokePathInstancedCHROMIUM(numPaths, pathNameType, paths, pathBase,
- reference, mask, transformType,
- transformValues);
-}
-void MojoGLES2Impl::CoverFillPathInstancedCHROMIUM(
- GLsizei numPaths,
- GLenum pathNameType,
- const GLvoid* paths,
- GLuint pathBase,
- GLenum coverMode,
- GLenum transformType,
- const GLfloat* transformValues) {
- MojoGLES2MakeCurrent(context_);
- glCoverFillPathInstancedCHROMIUM(numPaths, pathNameType, paths, pathBase,
- coverMode, transformType, transformValues);
-}
-void MojoGLES2Impl::CoverStrokePathInstancedCHROMIUM(
- GLsizei numPaths,
- GLenum pathNameType,
- const GLvoid* paths,
- GLuint pathBase,
- GLenum coverMode,
- GLenum transformType,
- const GLfloat* transformValues) {
- MojoGLES2MakeCurrent(context_);
- glCoverStrokePathInstancedCHROMIUM(numPaths, pathNameType, paths, pathBase,
- coverMode, transformType, transformValues);
-}
-void MojoGLES2Impl::StencilThenCoverFillPathInstancedCHROMIUM(
- GLsizei numPaths,
- GLenum pathNameType,
- const GLvoid* paths,
- GLuint pathBase,
- GLenum fillMode,
- GLuint mask,
- GLenum coverMode,
- GLenum transformType,
- const GLfloat* transformValues) {
- MojoGLES2MakeCurrent(context_);
- glStencilThenCoverFillPathInstancedCHROMIUM(
- numPaths, pathNameType, paths, pathBase, fillMode, mask, coverMode,
- transformType, transformValues);
-}
-void MojoGLES2Impl::StencilThenCoverStrokePathInstancedCHROMIUM(
- GLsizei numPaths,
- GLenum pathNameType,
- const GLvoid* paths,
- GLuint pathBase,
- GLint reference,
- GLuint mask,
- GLenum coverMode,
- GLenum transformType,
- const GLfloat* transformValues) {
- MojoGLES2MakeCurrent(context_);
- glStencilThenCoverStrokePathInstancedCHROMIUM(
- numPaths, pathNameType, paths, pathBase, reference, mask, coverMode,
- transformType, transformValues);
-}
-void MojoGLES2Impl::BindFragmentInputLocationCHROMIUM(GLuint program,
- GLint location,
- const char* name) {
- MojoGLES2MakeCurrent(context_);
- glBindFragmentInputLocationCHROMIUM(program, location, name);
-}
-void MojoGLES2Impl::ProgramPathFragmentInputGenCHROMIUM(GLuint program,
- GLint location,
- GLenum genMode,
- GLint components,
- const GLfloat* coeffs) {
- MojoGLES2MakeCurrent(context_);
- glProgramPathFragmentInputGenCHROMIUM(program, location, genMode, components,
- coeffs);
-}
-void MojoGLES2Impl::CoverageModulationCHROMIUM(GLenum components) {
- MojoGLES2MakeCurrent(context_);
- glCoverageModulationCHROMIUM(components);
-}
-GLenum MojoGLES2Impl::GetGraphicsResetStatusKHR() {
- MojoGLES2MakeCurrent(context_);
- return glGetGraphicsResetStatusKHR();
-}
-void MojoGLES2Impl::BlendBarrierKHR() {
- MojoGLES2MakeCurrent(context_);
- glBlendBarrierKHR();
-}
-void MojoGLES2Impl::ApplyScreenSpaceAntialiasingCHROMIUM() {
- MojoGLES2MakeCurrent(context_);
- glApplyScreenSpaceAntialiasingCHROMIUM();
-}
-void MojoGLES2Impl::BindFragDataLocationIndexedEXT(GLuint program,
- GLuint colorNumber,
- GLuint index,
- const char* name) {
- MojoGLES2MakeCurrent(context_);
- glBindFragDataLocationIndexedEXT(program, colorNumber, index, name);
-}
-void MojoGLES2Impl::BindFragDataLocationEXT(GLuint program,
- GLuint colorNumber,
- const char* name) {
- MojoGLES2MakeCurrent(context_);
- glBindFragDataLocationEXT(program, colorNumber, name);
-}
-GLint MojoGLES2Impl::GetFragDataIndexEXT(GLuint program, const char* name) {
- MojoGLES2MakeCurrent(context_);
- return glGetFragDataIndexEXT(program, name);
-}
-void MojoGLES2Impl::UniformMatrix4fvStreamTextureMatrixCHROMIUM(
- GLint location,
- GLboolean transpose,
- const GLfloat* default_value) {
- MojoGLES2MakeCurrent(context_);
- glUniformMatrix4fvStreamTextureMatrixCHROMIUM(location, transpose,
- default_value);
-}
-
-} // namespace mojo
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.h b/mojo/gpu/mojo_gles2_impl_autogen.h
deleted file mode 100644
index fd0e5bd..0000000
--- a/mojo/gpu/mojo_gles2_impl_autogen.h
+++ /dev/null
@@ -1,890 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file is auto-generated from
-// gpu/command_buffer/build_gles2_cmd_buffer.py
-// It's formatted by clang-format using chromium coding style:
-// clang-format -i -style=chromium filename
-// DO NOT EDIT!
-
-// This file is included by gles2_interface.h to declare the
-// GL api functions.
-#ifndef MOJO_GPU_MOJO_GLES2_IMPL_AUTOGEN_H_
-#define MOJO_GPU_MOJO_GLES2_IMPL_AUTOGEN_H_
-
-#include <memory>
-
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "mojo/public/c/gles2/gles2.h"
-
-namespace mojo {
-
-class MojoGLES2Impl : public gpu::gles2::GLES2Interface {
- public:
- explicit MojoGLES2Impl(MojoGLES2Context context) { context_ = context; }
- ~MojoGLES2Impl() override {}
- void ActiveTexture(GLenum texture) override;
- void AttachShader(GLuint program, GLuint shader) override;
- void BindAttribLocation(GLuint program,
- GLuint index,
- const char* name) override;
- void BindBuffer(GLenum target, GLuint buffer) override;
- void BindBufferBase(GLenum target, GLuint index, GLuint buffer) override;
- void BindBufferRange(GLenum target,
- GLuint index,
- GLuint buffer,
- GLintptr offset,
- GLsizeiptr size) override;
- void BindFramebuffer(GLenum target, GLuint framebuffer) override;
- void BindRenderbuffer(GLenum target, GLuint renderbuffer) override;
- void BindSampler(GLuint unit, GLuint sampler) override;
- void BindTexture(GLenum target, GLuint texture) override;
- void BindTransformFeedback(GLenum target, GLuint transformfeedback) override;
- void BlendColor(GLclampf red,
- GLclampf green,
- GLclampf blue,
- GLclampf alpha) override;
- void BlendEquation(GLenum mode) override;
- void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) override;
- void BlendFunc(GLenum sfactor, GLenum dfactor) override;
- void BlendFuncSeparate(GLenum srcRGB,
- GLenum dstRGB,
- GLenum srcAlpha,
- GLenum dstAlpha) override;
- void BufferData(GLenum target,
- GLsizeiptr size,
- const void* data,
- GLenum usage) override;
- void BufferSubData(GLenum target,
- GLintptr offset,
- GLsizeiptr size,
- const void* data) override;
- GLenum CheckFramebufferStatus(GLenum target) override;
- void Clear(GLbitfield mask) override;
- void ClearBufferfi(GLenum buffer,
- GLint drawbuffers,
- GLfloat depth,
- GLint stencil) override;
- void ClearBufferfv(GLenum buffer,
- GLint drawbuffers,
- const GLfloat* value) override;
- void ClearBufferiv(GLenum buffer,
- GLint drawbuffers,
- const GLint* value) override;
- void ClearBufferuiv(GLenum buffer,
- GLint drawbuffers,
- const GLuint* value) override;
- void ClearColor(GLclampf red,
- GLclampf green,
- GLclampf blue,
- GLclampf alpha) override;
- void ClearDepthf(GLclampf depth) override;
- void ClearStencil(GLint s) override;
- GLenum ClientWaitSync(GLsync sync,
- GLbitfield flags,
- GLuint64 timeout) override;
- void ColorMask(GLboolean red,
- GLboolean green,
- GLboolean blue,
- GLboolean alpha) override;
- void CompileShader(GLuint shader) override;
- void CompressedTexImage2D(GLenum target,
- GLint level,
- GLenum internalformat,
- GLsizei width,
- GLsizei height,
- GLint border,
- GLsizei imageSize,
- const void* data) override;
- void CompressedTexSubImage2D(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLsizei imageSize,
- const void* data) override;
- void CompressedTexImage3D(GLenum target,
- GLint level,
- GLenum internalformat,
- GLsizei width,
- GLsizei height,
- GLsizei depth,
- GLint border,
- GLsizei imageSize,
- const void* data) override;
- void CompressedTexSubImage3D(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLint zoffset,
- GLsizei width,
- GLsizei height,
- GLsizei depth,
- GLenum format,
- GLsizei imageSize,
- const void* data) override;
- void CopyBufferSubData(GLenum readtarget,
- GLenum writetarget,
- GLintptr readoffset,
- GLintptr writeoffset,
- GLsizeiptr size) override;
- void CopyTexImage2D(GLenum target,
- GLint level,
- GLenum internalformat,
- GLint x,
- GLint y,
- GLsizei width,
- GLsizei height,
- GLint border) override;
- void CopyTexSubImage2D(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLint x,
- GLint y,
- GLsizei width,
- GLsizei height) override;
- void CopyTexSubImage3D(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLint zoffset,
- GLint x,
- GLint y,
- GLsizei width,
- GLsizei height) override;
- GLuint CreateProgram() override;
- GLuint CreateShader(GLenum type) override;
- void CullFace(GLenum mode) override;
- void DeleteBuffers(GLsizei n, const GLuint* buffers) override;
- void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) override;
- void DeleteProgram(GLuint program) override;
- void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) override;
- void DeleteSamplers(GLsizei n, const GLuint* samplers) override;
- void DeleteSync(GLsync sync) override;
- void DeleteShader(GLuint shader) override;
- void DeleteTextures(GLsizei n, const GLuint* textures) override;
- void DeleteTransformFeedbacks(GLsizei n, const GLuint* ids) override;
- void DepthFunc(GLenum func) override;
- void DepthMask(GLboolean flag) override;
- void DepthRangef(GLclampf zNear, GLclampf zFar) override;
- void DetachShader(GLuint program, GLuint shader) override;
- void Disable(GLenum cap) override;
- void DisableVertexAttribArray(GLuint index) override;
- void DrawArrays(GLenum mode, GLint first, GLsizei count) override;
- void DrawElements(GLenum mode,
- GLsizei count,
- GLenum type,
- const void* indices) override;
- void DrawRangeElements(GLenum mode,
- GLuint start,
- GLuint end,
- GLsizei count,
- GLenum type,
- const void* indices) override;
- void Enable(GLenum cap) override;
- void EnableVertexAttribArray(GLuint index) override;
- GLsync FenceSync(GLenum condition, GLbitfield flags) override;
- void Finish() override;
- void Flush() override;
- void FramebufferRenderbuffer(GLenum target,
- GLenum attachment,
- GLenum renderbuffertarget,
- GLuint renderbuffer) override;
- void FramebufferTexture2D(GLenum target,
- GLenum attachment,
- GLenum textarget,
- GLuint texture,
- GLint level) override;
- void FramebufferTextureLayer(GLenum target,
- GLenum attachment,
- GLuint texture,
- GLint level,
- GLint layer) override;
- void FrontFace(GLenum mode) override;
- void GenBuffers(GLsizei n, GLuint* buffers) override;
- void GenerateMipmap(GLenum target) override;
- void GenFramebuffers(GLsizei n, GLuint* framebuffers) override;
- void GenRenderbuffers(GLsizei n, GLuint* renderbuffers) override;
- void GenSamplers(GLsizei n, GLuint* samplers) override;
- void GenTextures(GLsizei n, GLuint* textures) override;
- void GenTransformFeedbacks(GLsizei n, GLuint* ids) override;
- void GetActiveAttrib(GLuint program,
- GLuint index,
- GLsizei bufsize,
- GLsizei* length,
- GLint* size,
- GLenum* type,
- char* name) override;
- void GetActiveUniform(GLuint program,
- GLuint index,
- GLsizei bufsize,
- GLsizei* length,
- GLint* size,
- GLenum* type,
- char* name) override;
- void GetActiveUniformBlockiv(GLuint program,
- GLuint index,
- GLenum pname,
- GLint* params) override;
- void GetActiveUniformBlockName(GLuint program,
- GLuint index,
- GLsizei bufsize,
- GLsizei* length,
- char* name) override;
- void GetActiveUniformsiv(GLuint program,
- GLsizei count,
- const GLuint* indices,
- GLenum pname,
- GLint* params) override;
- void GetAttachedShaders(GLuint program,
- GLsizei maxcount,
- GLsizei* count,
- GLuint* shaders) override;
- GLint GetAttribLocation(GLuint program, const char* name) override;
- void GetBooleanv(GLenum pname, GLboolean* params) override;
- void GetBufferParameteri64v(GLenum target,
- GLenum pname,
- GLint64* params) override;
- void GetBufferParameteriv(GLenum target,
- GLenum pname,
- GLint* params) override;
- GLenum GetError() override;
- void GetFloatv(GLenum pname, GLfloat* params) override;
- GLint GetFragDataLocation(GLuint program, const char* name) override;
- void GetFramebufferAttachmentParameteriv(GLenum target,
- GLenum attachment,
- GLenum pname,
- GLint* params) override;
- void GetInteger64v(GLenum pname, GLint64* params) override;
- void GetIntegeri_v(GLenum pname, GLuint index, GLint* data) override;
- void GetInteger64i_v(GLenum pname, GLuint index, GLint64* data) override;
- void GetIntegerv(GLenum pname, GLint* params) override;
- void GetInternalformativ(GLenum target,
- GLenum format,
- GLenum pname,
- GLsizei bufSize,
- GLint* params) override;
- void GetProgramiv(GLuint program, GLenum pname, GLint* params) override;
- void GetProgramInfoLog(GLuint program,
- GLsizei bufsize,
- GLsizei* length,
- char* infolog) override;
- void GetRenderbufferParameteriv(GLenum target,
- GLenum pname,
- GLint* params) override;
- void GetSamplerParameterfv(GLuint sampler,
- GLenum pname,
- GLfloat* params) override;
- void GetSamplerParameteriv(GLuint sampler,
- GLenum pname,
- GLint* params) override;
- void GetShaderiv(GLuint shader, GLenum pname, GLint* params) override;
- void GetShaderInfoLog(GLuint shader,
- GLsizei bufsize,
- GLsizei* length,
- char* infolog) override;
- void GetShaderPrecisionFormat(GLenum shadertype,
- GLenum precisiontype,
- GLint* range,
- GLint* precision) override;
- void GetShaderSource(GLuint shader,
- GLsizei bufsize,
- GLsizei* length,
- char* source) override;
- const GLubyte* GetString(GLenum name) override;
- const GLubyte* GetStringi(GLenum name, GLuint index) override;
- void GetSynciv(GLsync sync,
- GLenum pname,
- GLsizei bufsize,
- GLsizei* length,
- GLint* values) override;
- void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) override;
- void GetTexParameteriv(GLenum target, GLenum pname, GLint* params) override;
- void GetTransformFeedbackVarying(GLuint program,
- GLuint index,
- GLsizei bufsize,
- GLsizei* length,
- GLsizei* size,
- GLenum* type,
- char* name) override;
- GLuint GetUniformBlockIndex(GLuint program, const char* name) override;
- void GetUniformfv(GLuint program, GLint location, GLfloat* params) override;
- void GetUniformiv(GLuint program, GLint location, GLint* params) override;
- void GetUniformuiv(GLuint program, GLint location, GLuint* params) override;
- void GetUniformIndices(GLuint program,
- GLsizei count,
- const char* const* names,
- GLuint* indices) override;
- GLint GetUniformLocation(GLuint program, const char* name) override;
- void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) override;
- void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params) override;
- void GetVertexAttribIiv(GLuint index, GLenum pname, GLint* params) override;
- void GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params) override;
- void GetVertexAttribPointerv(GLuint index,
- GLenum pname,
- void** pointer) override;
- void Hint(GLenum target, GLenum mode) override;
- void InvalidateFramebuffer(GLenum target,
- GLsizei count,
- const GLenum* attachments) override;
- void InvalidateSubFramebuffer(GLenum target,
- GLsizei count,
- const GLenum* attachments,
- GLint x,
- GLint y,
- GLsizei width,
- GLsizei height) override;
- GLboolean IsBuffer(GLuint buffer) override;
- GLboolean IsEnabled(GLenum cap) override;
- GLboolean IsFramebuffer(GLuint framebuffer) override;
- GLboolean IsProgram(GLuint program) override;
- GLboolean IsRenderbuffer(GLuint renderbuffer) override;
- GLboolean IsSampler(GLuint sampler) override;
- GLboolean IsShader(GLuint shader) override;
- GLboolean IsSync(GLsync sync) override;
- GLboolean IsTexture(GLuint texture) override;
- GLboolean IsTransformFeedback(GLuint transformfeedback) override;
- void LineWidth(GLfloat width) override;
- void LinkProgram(GLuint program) override;
- void PauseTransformFeedback() override;
- void PixelStorei(GLenum pname, GLint param) override;
- void PolygonOffset(GLfloat factor, GLfloat units) override;
- void ReadBuffer(GLenum src) override;
- void ReadPixels(GLint x,
- GLint y,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLenum type,
- void* pixels) override;
- void ReleaseShaderCompiler() override;
- void RenderbufferStorage(GLenum target,
- GLenum internalformat,
- GLsizei width,
- GLsizei height) override;
- void ResumeTransformFeedback() override;
- void SampleCoverage(GLclampf value, GLboolean invert) override;
- void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) override;
- void SamplerParameterfv(GLuint sampler,
- GLenum pname,
- const GLfloat* params) override;
- void SamplerParameteri(GLuint sampler, GLenum pname, GLint param) override;
- void SamplerParameteriv(GLuint sampler,
- GLenum pname,
- const GLint* params) override;
- void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) override;
- void ShaderBinary(GLsizei n,
- const GLuint* shaders,
- GLenum binaryformat,
- const void* binary,
- GLsizei length) override;
- void ShaderSource(GLuint shader,
- GLsizei count,
- const GLchar* const* str,
- const GLint* length) override;
- void ShallowFinishCHROMIUM() override;
- void ShallowFlushCHROMIUM() override;
- void OrderingBarrierCHROMIUM() override;
- void StencilFunc(GLenum func, GLint ref, GLuint mask) override;
- void StencilFuncSeparate(GLenum face,
- GLenum func,
- GLint ref,
- GLuint mask) override;
- void StencilMask(GLuint mask) override;
- void StencilMaskSeparate(GLenum face, GLuint mask) override;
- void StencilOp(GLenum fail, GLenum zfail, GLenum zpass) override;
- void StencilOpSeparate(GLenum face,
- GLenum fail,
- GLenum zfail,
- GLenum zpass) override;
- void TexImage2D(GLenum target,
- GLint level,
- GLint internalformat,
- GLsizei width,
- GLsizei height,
- GLint border,
- GLenum format,
- GLenum type,
- const void* pixels) override;
- void TexImage3D(GLenum target,
- GLint level,
- GLint internalformat,
- GLsizei width,
- GLsizei height,
- GLsizei depth,
- GLint border,
- GLenum format,
- GLenum type,
- const void* pixels) override;
- void TexParameterf(GLenum target, GLenum pname, GLfloat param) override;
- void TexParameterfv(GLenum target,
- GLenum pname,
- const GLfloat* params) override;
- void TexParameteri(GLenum target, GLenum pname, GLint param) override;
- void TexParameteriv(GLenum target,
- GLenum pname,
- const GLint* params) override;
- void TexStorage3D(GLenum target,
- GLsizei levels,
- GLenum internalFormat,
- GLsizei width,
- GLsizei height,
- GLsizei depth) override;
- void TexSubImage2D(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLenum type,
- const void* pixels) override;
- void TexSubImage3D(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLint zoffset,
- GLsizei width,
- GLsizei height,
- GLsizei depth,
- GLenum format,
- GLenum type,
- const void* pixels) override;
- void TransformFeedbackVaryings(GLuint program,
- GLsizei count,
- const char* const* varyings,
- GLenum buffermode) override;
- void Uniform1f(GLint location, GLfloat x) override;
- void Uniform1fv(GLint location, GLsizei count, const GLfloat* v) override;
- void Uniform1i(GLint location, GLint x) override;
- void Uniform1iv(GLint location, GLsizei count, const GLint* v) override;
- void Uniform1ui(GLint location, GLuint x) override;
- void Uniform1uiv(GLint location, GLsizei count, const GLuint* v) override;
- void Uniform2f(GLint location, GLfloat x, GLfloat y) override;
- void Uniform2fv(GLint location, GLsizei count, const GLfloat* v) override;
- void Uniform2i(GLint location, GLint x, GLint y) override;
- void Uniform2iv(GLint location, GLsizei count, const GLint* v) override;
- void Uniform2ui(GLint location, GLuint x, GLuint y) override;
- void Uniform2uiv(GLint location, GLsizei count, const GLuint* v) override;
- void Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) override;
- void Uniform3fv(GLint location, GLsizei count, const GLfloat* v) override;
- void Uniform3i(GLint location, GLint x, GLint y, GLint z) override;
- void Uniform3iv(GLint location, GLsizei count, const GLint* v) override;
- void Uniform3ui(GLint location, GLuint x, GLuint y, GLuint z) override;
- void Uniform3uiv(GLint location, GLsizei count, const GLuint* v) override;
- void Uniform4f(GLint location,
- GLfloat x,
- GLfloat y,
- GLfloat z,
- GLfloat w) override;
- void Uniform4fv(GLint location, GLsizei count, const GLfloat* v) override;
- void Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) override;
- void Uniform4iv(GLint location, GLsizei count, const GLint* v) override;
- void Uniform4ui(GLint location,
- GLuint x,
- GLuint y,
- GLuint z,
- GLuint w) override;
- void Uniform4uiv(GLint location, GLsizei count, const GLuint* v) override;
- void UniformBlockBinding(GLuint program,
- GLuint index,
- GLuint binding) override;
- void UniformMatrix2fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) override;
- void UniformMatrix2x3fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) override;
- void UniformMatrix2x4fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) override;
- void UniformMatrix3fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) override;
- void UniformMatrix3x2fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) override;
- void UniformMatrix3x4fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) override;
- void UniformMatrix4fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) override;
- void UniformMatrix4x2fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) override;
- void UniformMatrix4x3fv(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value) override;
- void UseProgram(GLuint program) override;
- void ValidateProgram(GLuint program) override;
- void VertexAttrib1f(GLuint indx, GLfloat x) override;
- void VertexAttrib1fv(GLuint indx, const GLfloat* values) override;
- void VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) override;
- void VertexAttrib2fv(GLuint indx, const GLfloat* values) override;
- void VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) override;
- void VertexAttrib3fv(GLuint indx, const GLfloat* values) override;
- void VertexAttrib4f(GLuint indx,
- GLfloat x,
- GLfloat y,
- GLfloat z,
- GLfloat w) override;
- void VertexAttrib4fv(GLuint indx, const GLfloat* values) override;
- void VertexAttribI4i(GLuint indx,
- GLint x,
- GLint y,
- GLint z,
- GLint w) override;
- void VertexAttribI4iv(GLuint indx, const GLint* values) override;
- void VertexAttribI4ui(GLuint indx,
- GLuint x,
- GLuint y,
- GLuint z,
- GLuint w) override;
- void VertexAttribI4uiv(GLuint indx, const GLuint* values) override;
- void VertexAttribIPointer(GLuint indx,
- GLint size,
- GLenum type,
- GLsizei stride,
- const void* ptr) override;
- void VertexAttribPointer(GLuint indx,
- GLint size,
- GLenum type,
- GLboolean normalized,
- GLsizei stride,
- const void* ptr) override;
- void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) override;
- void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) override;
- void BlitFramebufferCHROMIUM(GLint srcX0,
- GLint srcY0,
- GLint srcX1,
- GLint srcY1,
- GLint dstX0,
- GLint dstY0,
- GLint dstX1,
- GLint dstY1,
- GLbitfield mask,
- GLenum filter) override;
- void RenderbufferStorageMultisampleCHROMIUM(GLenum target,
- GLsizei samples,
- GLenum internalformat,
- GLsizei width,
- GLsizei height) override;
- void RenderbufferStorageMultisampleEXT(GLenum target,
- GLsizei samples,
- GLenum internalformat,
- GLsizei width,
- GLsizei height) override;
- void FramebufferTexture2DMultisampleEXT(GLenum target,
- GLenum attachment,
- GLenum textarget,
- GLuint texture,
- GLint level,
- GLsizei samples) override;
- void TexStorage2DEXT(GLenum target,
- GLsizei levels,
- GLenum internalFormat,
- GLsizei width,
- GLsizei height) override;
- void GenQueriesEXT(GLsizei n, GLuint* queries) override;
- void DeleteQueriesEXT(GLsizei n, const GLuint* queries) override;
- void QueryCounterEXT(GLuint id, GLenum target) override;
- GLboolean IsQueryEXT(GLuint id) override;
- void BeginQueryEXT(GLenum target, GLuint id) override;
- void BeginTransformFeedback(GLenum primitivemode) override;
- void EndQueryEXT(GLenum target) override;
- void EndTransformFeedback() override;
- void GetQueryivEXT(GLenum target, GLenum pname, GLint* params) override;
- void GetQueryObjectivEXT(GLuint id, GLenum pname, GLint* params) override;
- void GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* params) override;
- void GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64* params) override;
- void GetQueryObjectui64vEXT(GLuint id,
- GLenum pname,
- GLuint64* params) override;
- void SetDisjointValueSyncCHROMIUM() override;
- void InsertEventMarkerEXT(GLsizei length, const GLchar* marker) override;
- void PushGroupMarkerEXT(GLsizei length, const GLchar* marker) override;
- void PopGroupMarkerEXT() override;
- void GenVertexArraysOES(GLsizei n, GLuint* arrays) override;
- void DeleteVertexArraysOES(GLsizei n, const GLuint* arrays) override;
- GLboolean IsVertexArrayOES(GLuint array) override;
- void BindVertexArrayOES(GLuint array) override;
- void SwapBuffers() override;
- GLuint GetMaxValueInBufferCHROMIUM(GLuint buffer_id,
- GLsizei count,
- GLenum type,
- GLuint offset) override;
- GLboolean EnableFeatureCHROMIUM(const char* feature) override;
- void* MapBufferCHROMIUM(GLuint target, GLenum access) override;
- GLboolean UnmapBufferCHROMIUM(GLuint target) override;
- void* MapBufferSubDataCHROMIUM(GLuint target,
- GLintptr offset,
- GLsizeiptr size,
- GLenum access) override;
- void UnmapBufferSubDataCHROMIUM(const void* mem) override;
- void* MapBufferRange(GLenum target,
- GLintptr offset,
- GLsizeiptr size,
- GLbitfield access) override;
- GLboolean UnmapBuffer(GLenum target) override;
- void* MapTexSubImage2DCHROMIUM(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLenum type,
- GLenum access) override;
- void UnmapTexSubImage2DCHROMIUM(const void* mem) override;
- void ResizeCHROMIUM(GLuint width,
- GLuint height,
- GLfloat scale_factor,
- GLboolean alpha) override;
- const GLchar* GetRequestableExtensionsCHROMIUM() override;
- void RequestExtensionCHROMIUM(const char* extension) override;
- void GetProgramInfoCHROMIUM(GLuint program,
- GLsizei bufsize,
- GLsizei* size,
- void* info) override;
- void GetUniformBlocksCHROMIUM(GLuint program,
- GLsizei bufsize,
- GLsizei* size,
- void* info) override;
- void GetTransformFeedbackVaryingsCHROMIUM(GLuint program,
- GLsizei bufsize,
- GLsizei* size,
- void* info) override;
- void GetUniformsES3CHROMIUM(GLuint program,
- GLsizei bufsize,
- GLsizei* size,
- void* info) override;
- GLuint CreateImageCHROMIUM(ClientBuffer buffer,
- GLsizei width,
- GLsizei height,
- GLenum internalformat) override;
- void DestroyImageCHROMIUM(GLuint image_id) override;
- GLuint CreateGpuMemoryBufferImageCHROMIUM(GLsizei width,
- GLsizei height,
- GLenum internalformat,
- GLenum usage) override;
- void GetTranslatedShaderSourceANGLE(GLuint shader,
- GLsizei bufsize,
- GLsizei* length,
- char* source) override;
- void PostSubBufferCHROMIUM(GLint x,
- GLint y,
- GLint width,
- GLint height) override;
- void CopyTextureCHROMIUM(GLenum source_id,
- GLenum dest_id,
- GLint internalformat,
- GLenum dest_type,
- GLboolean unpack_flip_y,
- GLboolean unpack_premultiply_alpha,
- GLboolean unpack_unmultiply_alpha) override;
- void CopySubTextureCHROMIUM(GLenum source_id,
- GLenum dest_id,
- GLint xoffset,
- GLint yoffset,
- GLint x,
- GLint y,
- GLsizei width,
- GLsizei height,
- GLboolean unpack_flip_y,
- GLboolean unpack_premultiply_alpha,
- GLboolean unpack_unmultiply_alpha) override;
- void CompressedCopyTextureCHROMIUM(GLenum source_id, GLenum dest_id) override;
- void DrawArraysInstancedANGLE(GLenum mode,
- GLint first,
- GLsizei count,
- GLsizei primcount) override;
- void DrawElementsInstancedANGLE(GLenum mode,
- GLsizei count,
- GLenum type,
- const void* indices,
- GLsizei primcount) override;
- void VertexAttribDivisorANGLE(GLuint index, GLuint divisor) override;
- void GenMailboxCHROMIUM(GLbyte* mailbox) override;
- void ProduceTextureCHROMIUM(GLenum target, const GLbyte* mailbox) override;
- void ProduceTextureDirectCHROMIUM(GLuint texture,
- GLenum target,
- const GLbyte* mailbox) override;
- void ConsumeTextureCHROMIUM(GLenum target, const GLbyte* mailbox) override;
- GLuint CreateAndConsumeTextureCHROMIUM(GLenum target,
- const GLbyte* mailbox) override;
- void BindUniformLocationCHROMIUM(GLuint program,
- GLint location,
- const char* name) override;
- void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
- void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
- void TraceBeginCHROMIUM(const char* category_name,
- const char* trace_name) override;
- void TraceEndCHROMIUM() override;
- void DiscardFramebufferEXT(GLenum target,
- GLsizei count,
- const GLenum* attachments) override;
- void LoseContextCHROMIUM(GLenum current, GLenum other) override;
- GLuint64 InsertFenceSyncCHROMIUM() override;
- void GenSyncTokenCHROMIUM(GLuint64 fence_sync, GLbyte* sync_token) override;
- void GenUnverifiedSyncTokenCHROMIUM(GLuint64 fence_sync,
- GLbyte* sync_token) override;
- void VerifySyncTokensCHROMIUM(GLbyte** sync_tokens, GLsizei count) override;
- void WaitSyncTokenCHROMIUM(const GLbyte* sync_token) override;
- void DrawBuffersEXT(GLsizei count, const GLenum* bufs) override;
- void DiscardBackbufferCHROMIUM() override;
- void ScheduleOverlayPlaneCHROMIUM(GLint plane_z_order,
- GLenum plane_transform,
- GLuint overlay_texture_id,
- GLint bounds_x,
- GLint bounds_y,
- GLint bounds_width,
- GLint bounds_height,
- GLfloat uv_x,
- GLfloat uv_y,
- GLfloat uv_width,
- GLfloat uv_height) override;
- void ScheduleCALayerCHROMIUM(GLuint contents_texture_id,
- const GLfloat* contents_rect,
- GLfloat opacity,
- GLuint background_color,
- GLuint edge_aa_mask,
- const GLfloat* bounds_rect,
- GLboolean is_clipped,
- const GLfloat* clip_rect,
- GLint sorting_context_id,
- const GLfloat* transform,
- GLuint filter) override;
- void CommitOverlayPlanesCHROMIUM() override;
- void SwapInterval(GLint interval) override;
- void FlushDriverCachesCHROMIUM() override;
- GLuint GetLastFlushIdCHROMIUM() override;
- void MatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat* m) override;
- void MatrixLoadIdentityCHROMIUM(GLenum matrixMode) override;
- GLuint GenPathsCHROMIUM(GLsizei range) override;
- void DeletePathsCHROMIUM(GLuint path, GLsizei range) override;
- GLboolean IsPathCHROMIUM(GLuint path) override;
- void PathCommandsCHROMIUM(GLuint path,
- GLsizei numCommands,
- const GLubyte* commands,
- GLsizei numCoords,
- GLenum coordType,
- const GLvoid* coords) override;
- void PathParameterfCHROMIUM(GLuint path,
- GLenum pname,
- GLfloat value) override;
- void PathParameteriCHROMIUM(GLuint path, GLenum pname, GLint value) override;
- void PathStencilFuncCHROMIUM(GLenum func, GLint ref, GLuint mask) override;
- void StencilFillPathCHROMIUM(GLuint path,
- GLenum fillMode,
- GLuint mask) override;
- void StencilStrokePathCHROMIUM(GLuint path,
- GLint reference,
- GLuint mask) override;
- void CoverFillPathCHROMIUM(GLuint path, GLenum coverMode) override;
- void CoverStrokePathCHROMIUM(GLuint path, GLenum coverMode) override;
- void StencilThenCoverFillPathCHROMIUM(GLuint path,
- GLenum fillMode,
- GLuint mask,
- GLenum coverMode) override;
- void StencilThenCoverStrokePathCHROMIUM(GLuint path,
- GLint reference,
- GLuint mask,
- GLenum coverMode) override;
- void StencilFillPathInstancedCHROMIUM(
- GLsizei numPaths,
- GLenum pathNameType,
- const GLvoid* paths,
- GLuint pathBase,
- GLenum fillMode,
- GLuint mask,
- GLenum transformType,
- const GLfloat* transformValues) override;
- void StencilStrokePathInstancedCHROMIUM(
- GLsizei numPaths,
- GLenum pathNameType,
- const GLvoid* paths,
- GLuint pathBase,
- GLint reference,
- GLuint mask,
- GLenum transformType,
- const GLfloat* transformValues) override;
- void CoverFillPathInstancedCHROMIUM(GLsizei numPaths,
- GLenum pathNameType,
- const GLvoid* paths,
- GLuint pathBase,
- GLenum coverMode,
- GLenum transformType,
- const GLfloat* transformValues) override;
- void CoverStrokePathInstancedCHROMIUM(
- GLsizei numPaths,
- GLenum pathNameType,
- const GLvoid* paths,
- GLuint pathBase,
- GLenum coverMode,
- GLenum transformType,
- const GLfloat* transformValues) override;
- void StencilThenCoverFillPathInstancedCHROMIUM(
- GLsizei numPaths,
- GLenum pathNameType,
- const GLvoid* paths,
- GLuint pathBase,
- GLenum fillMode,
- GLuint mask,
- GLenum coverMode,
- GLenum transformType,
- const GLfloat* transformValues) override;
- void StencilThenCoverStrokePathInstancedCHROMIUM(
- GLsizei numPaths,
- GLenum pathNameType,
- const GLvoid* paths,
- GLuint pathBase,
- GLint reference,
- GLuint mask,
- GLenum coverMode,
- GLenum transformType,
- const GLfloat* transformValues) override;
- void BindFragmentInputLocationCHROMIUM(GLuint program,
- GLint location,
- const char* name) override;
- void ProgramPathFragmentInputGenCHROMIUM(GLuint program,
- GLint location,
- GLenum genMode,
- GLint components,
- const GLfloat* coeffs) override;
- void CoverageModulationCHROMIUM(GLenum components) override;
- GLenum GetGraphicsResetStatusKHR() override;
- void BlendBarrierKHR() override;
- void ApplyScreenSpaceAntialiasingCHROMIUM() override;
- void BindFragDataLocationIndexedEXT(GLuint program,
- GLuint colorNumber,
- GLuint index,
- const char* name) override;
- void BindFragDataLocationEXT(GLuint program,
- GLuint colorNumber,
- const char* name) override;
- GLint GetFragDataIndexEXT(GLuint program, const char* name) override;
- void UniformMatrix4fvStreamTextureMatrixCHROMIUM(
- GLint location,
- GLboolean transpose,
- const GLfloat* default_value) override;
-
- private:
- MojoGLES2Context context_;
-};
-
-} // namespace mojo
-#endif // MOJO_GPU_MOJO_GLES2_IMPL_AUTOGEN_H_
diff --git a/mojo/message_pump/BUILD.gn b/mojo/message_pump/BUILD.gn
deleted file mode 100644
index e1ae4af..0000000
--- a/mojo/message_pump/BUILD.gn
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//testing/test.gni")
-
-component("message_pump") {
- sources = [
- "handle_watcher.cc",
- "handle_watcher.h",
- "message_pump_mojo.cc",
- "message_pump_mojo.h",
- "message_pump_mojo_handler.h",
- "time_helper.cc",
- "time_helper.h",
- ]
-
- defines = [ "MOJO_MESSAGE_PUMP_IMPLEMENTATION" ]
-
- public_deps = [
- "//base",
- "//mojo/public/cpp/system",
- ]
-}
diff --git a/mojo/message_pump/handle_watcher.cc b/mojo/message_pump/handle_watcher.cc
deleted file mode 100644
index 7f6f561..0000000
--- a/mojo/message_pump/handle_watcher.cc
+++ /dev/null
@@ -1,480 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/message_pump/handle_watcher.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
-
-#include "base/atomic_sequence_num.h"
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "mojo/message_pump/message_pump_mojo.h"
-#include "mojo/message_pump/message_pump_mojo_handler.h"
-#include "mojo/message_pump/time_helper.h"
-#include "mojo/public/c/system/message_pipe.h"
-
-namespace mojo {
-namespace common {
-
-typedef int WatcherID;
-
-namespace {
-
-const char kWatcherThreadName[] = "handle-watcher-thread";
-
-base::TimeTicks MojoDeadlineToTimeTicks(MojoDeadline deadline) {
- return deadline == MOJO_DEADLINE_INDEFINITE ? base::TimeTicks() :
- internal::NowTicks() + base::TimeDelta::FromMicroseconds(deadline);
-}
-
-// Tracks the data for a single call to Start().
-struct WatchData {
- WatchData()
- : id(0), handle_signals(MOJO_HANDLE_SIGNAL_NONE), task_runner(NULL) {}
-
- WatcherID id;
- Handle handle;
- MojoHandleSignals handle_signals;
- base::TimeTicks deadline;
- base::Callback<void(MojoResult)> callback;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner;
-};
-
-// WatcherBackend --------------------------------------------------------------
-
-// WatcherBackend is responsible for managing the requests and interacting with
-// MessagePumpMojo. All access (outside of creation/destruction) is done on the
-// thread WatcherThreadManager creates.
-class WatcherBackend : public MessagePumpMojoHandler {
- public:
- WatcherBackend();
- ~WatcherBackend() override;
-
- void StartWatching(const WatchData& data);
- void StopWatching(WatcherID watcher_id);
-
- private:
- typedef std::map<Handle, WatchData> HandleToWatchDataMap;
-
- // Invoked when a handle needs to be removed and notified.
- void RemoveAndNotify(const Handle& handle, MojoResult result);
-
- // Searches through |handle_to_data_| for |watcher_id|. Returns true if found
- // and sets |handle| to the Handle. Returns false if not a known id.
- bool GetMojoHandleByWatcherID(WatcherID watcher_id, Handle* handle) const;
-
- // MessagePumpMojoHandler overrides:
- void OnHandleReady(const Handle& handle) override;
- void OnHandleError(const Handle& handle, MojoResult result) override;
-
- // Maps from assigned id to WatchData.
- HandleToWatchDataMap handle_to_data_;
-
- DISALLOW_COPY_AND_ASSIGN(WatcherBackend);
-};
-
-WatcherBackend::WatcherBackend() {
-}
-
-WatcherBackend::~WatcherBackend() {
-}
-
-void WatcherBackend::StartWatching(const WatchData& data) {
- RemoveAndNotify(data.handle, MOJO_RESULT_CANCELLED);
-
- DCHECK_EQ(0u, handle_to_data_.count(data.handle));
-
- handle_to_data_[data.handle] = data;
- MessagePumpMojo::current()->AddHandler(this, data.handle,
- data.handle_signals,
- data.deadline);
-}
-
-void WatcherBackend::StopWatching(WatcherID watcher_id) {
- // Because of the thread hop it is entirely possible to get here and not
- // have a valid handle registered for |watcher_id|.
- Handle handle;
- if (!GetMojoHandleByWatcherID(watcher_id, &handle))
- return;
-
- handle_to_data_.erase(handle);
- MessagePumpMojo::current()->RemoveHandler(handle);
-}
-
-void WatcherBackend::RemoveAndNotify(const Handle& handle,
- MojoResult result) {
- if (handle_to_data_.count(handle) == 0)
- return;
-
- const WatchData data(handle_to_data_[handle]);
- handle_to_data_.erase(handle);
- MessagePumpMojo::current()->RemoveHandler(handle);
-
- data.task_runner->PostTask(FROM_HERE, base::Bind(data.callback, result));
-}
-
-bool WatcherBackend::GetMojoHandleByWatcherID(WatcherID watcher_id,
- Handle* handle) const {
- for (HandleToWatchDataMap::const_iterator i = handle_to_data_.begin();
- i != handle_to_data_.end(); ++i) {
- if (i->second.id == watcher_id) {
- *handle = i->second.handle;
- return true;
- }
- }
- return false;
-}
-
-void WatcherBackend::OnHandleReady(const Handle& handle) {
- RemoveAndNotify(handle, MOJO_RESULT_OK);
-}
-
-void WatcherBackend::OnHandleError(const Handle& handle, MojoResult result) {
- RemoveAndNotify(handle, result);
-}
-
-// WatcherThreadManager --------------------------------------------------------
-
-// WatcherThreadManager manages the background thread that listens for handles
-// to be ready. All requests are handled by WatcherBackend.
-class WatcherThreadManager {
- public:
- ~WatcherThreadManager();
-
- // Returns the shared instance.
- static WatcherThreadManager* GetInstance();
-
- // Starts watching the requested handle. Returns a unique ID that is used to
- // stop watching the handle. When the handle is ready |callback| is notified
- // on the thread StartWatching() was invoked on.
- // This may be invoked on any thread.
- WatcherID StartWatching(const Handle& handle,
- MojoHandleSignals handle_signals,
- base::TimeTicks deadline,
- const base::Callback<void(MojoResult)>& callback);
-
- // Stops watching a handle.
- // This may be invoked on any thread.
- void StopWatching(WatcherID watcher_id);
-
- private:
- enum RequestType {
- REQUEST_START,
- REQUEST_STOP,
- };
-
- // See description of |requests_| for details.
- struct RequestData {
- RequestData() : type(REQUEST_START), stop_id(0) {}
-
- RequestType type;
- WatchData start_data;
- WatcherID stop_id;
- };
-
- typedef std::vector<RequestData> Requests;
-
- friend struct base::DefaultSingletonTraits<WatcherThreadManager>;
-
- WatcherThreadManager();
-
- // Schedules a request on the background thread. See |requests_| for details.
- void AddRequest(const RequestData& data);
-
- // Processes requests added to |requests_|. This is invoked on the backend
- // thread.
- void ProcessRequestsOnBackendThread();
-
- base::Thread thread_;
-
- base::AtomicSequenceNumber watcher_id_generator_;
-
- WatcherBackend backend_;
-
- // Protects |requests_|.
- base::Lock lock_;
-
- // Start/Stop result in adding a RequestData to |requests_| (protected by
- // |lock_|). When the background thread wakes up it processes the requests.
- Requests requests_;
-
- DISALLOW_COPY_AND_ASSIGN(WatcherThreadManager);
-};
-
-WatcherThreadManager::~WatcherThreadManager() {
- thread_.Stop();
-}
-
-WatcherThreadManager* WatcherThreadManager::GetInstance() {
- return base::Singleton<WatcherThreadManager>::get();
-}
-
-WatcherID WatcherThreadManager::StartWatching(
- const Handle& handle,
- MojoHandleSignals handle_signals,
- base::TimeTicks deadline,
- const base::Callback<void(MojoResult)>& callback) {
- RequestData request_data;
- request_data.type = REQUEST_START;
- request_data.start_data.id = watcher_id_generator_.GetNext();
- request_data.start_data.handle = handle;
- request_data.start_data.callback = callback;
- request_data.start_data.handle_signals = handle_signals;
- request_data.start_data.deadline = deadline;
- request_data.start_data.task_runner = base::ThreadTaskRunnerHandle::Get();
- AddRequest(request_data);
- return request_data.start_data.id;
-}
-
-void WatcherThreadManager::StopWatching(WatcherID watcher_id) {
- // Handle the case of StartWatching() followed by StopWatching() before
- // |thread_| woke up.
- {
- base::AutoLock auto_lock(lock_);
- for (Requests::iterator i = requests_.begin(); i != requests_.end(); ++i) {
- if (i->type == REQUEST_START && i->start_data.id == watcher_id) {
- // Watcher ids are not reused, so if we find it we can stop.
- requests_.erase(i);
- return;
- }
- }
- }
-
- RequestData request_data;
- request_data.type = REQUEST_STOP;
- request_data.stop_id = watcher_id;
- AddRequest(request_data);
-}
-
-void WatcherThreadManager::AddRequest(const RequestData& data) {
- {
- base::AutoLock auto_lock(lock_);
- const bool was_empty = requests_.empty();
- requests_.push_back(data);
- if (!was_empty)
- return;
- }
-
- // We outlive |thread_|, so it's safe to use Unretained() here.
- thread_.task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&WatcherThreadManager::ProcessRequestsOnBackendThread,
- base::Unretained(this)));
-}
-
-void WatcherThreadManager::ProcessRequestsOnBackendThread() {
- DCHECK(thread_.task_runner()->BelongsToCurrentThread());
-
- Requests requests;
- {
- base::AutoLock auto_lock(lock_);
- requests_.swap(requests);
- }
- for (size_t i = 0; i < requests.size(); ++i) {
- if (requests[i].type == REQUEST_START) {
- backend_.StartWatching(requests[i].start_data);
- } else {
- backend_.StopWatching(requests[i].stop_id);
- }
- }
-}
-
-WatcherThreadManager::WatcherThreadManager()
- : thread_(kWatcherThreadName) {
- base::Thread::Options thread_options;
- thread_options.message_pump_factory = base::Bind(&MessagePumpMojo::Create);
- thread_.StartWithOptions(thread_options);
-}
-
-} // namespace
-
-// HandleWatcher::StateBase and subclasses -------------------------------------
-
-// The base class of HandleWatcher's state. Owns the user's callback and
-// monitors the current thread's MessageLoop to know when to force the callback
-// to run (with an error) even though the pipe hasn't been signaled yet.
-class HandleWatcher::StateBase : public base::MessageLoop::DestructionObserver {
- public:
- StateBase(HandleWatcher* watcher,
- const base::Callback<void(MojoResult)>& callback)
- : watcher_(watcher),
- callback_(callback),
- got_ready_(false) {
- base::MessageLoop::current()->AddDestructionObserver(this);
- }
-
- ~StateBase() override {
- base::MessageLoop::current()->RemoveDestructionObserver(this);
- }
-
- protected:
- void NotifyHandleReady(MojoResult result) {
- got_ready_ = true;
- NotifyAndDestroy(result);
- }
-
- bool got_ready() const { return got_ready_; }
-
- private:
- void WillDestroyCurrentMessageLoop() override {
- // The current thread is exiting. Simulate a watch error.
- NotifyAndDestroy(MOJO_RESULT_ABORTED);
- }
-
- void NotifyAndDestroy(MojoResult result) {
- base::Callback<void(MojoResult)> callback = callback_;
- watcher_->Stop(); // Destroys |this|.
-
- callback.Run(result);
- }
-
- HandleWatcher* watcher_;
- base::Callback<void(MojoResult)> callback_;
-
- // Have we been notified that the handle is ready?
- bool got_ready_;
-
- DISALLOW_COPY_AND_ASSIGN(StateBase);
-};
-
-// If the thread on which HandleWatcher is used runs MessagePumpMojo,
-// SameThreadWatchingState is used to directly watch the handle on the same
-// thread.
-class HandleWatcher::SameThreadWatchingState : public StateBase,
- public MessagePumpMojoHandler {
- public:
- SameThreadWatchingState(HandleWatcher* watcher,
- const Handle& handle,
- MojoHandleSignals handle_signals,
- MojoDeadline deadline,
- const base::Callback<void(MojoResult)>& callback)
- : StateBase(watcher, callback),
- handle_(handle) {
- DCHECK(MessagePumpMojo::IsCurrent());
-
- MessagePumpMojo::current()->AddHandler(
- this, handle, handle_signals, MojoDeadlineToTimeTicks(deadline));
- }
-
- ~SameThreadWatchingState() override {
- if (!got_ready())
- MessagePumpMojo::current()->RemoveHandler(handle_);
- }
-
- private:
- // MessagePumpMojoHandler overrides:
- void OnHandleReady(const Handle& handle) override {
- StopWatchingAndNotifyReady(handle, MOJO_RESULT_OK);
- }
-
- void OnHandleError(const Handle& handle, MojoResult result) override {
- StopWatchingAndNotifyReady(handle, result);
- }
-
- void StopWatchingAndNotifyReady(const Handle& handle, MojoResult result) {
- DCHECK_EQ(handle.value(), handle_.value());
- MessagePumpMojo::current()->RemoveHandler(handle_);
- NotifyHandleReady(result);
- }
-
- Handle handle_;
-
- DISALLOW_COPY_AND_ASSIGN(SameThreadWatchingState);
-};
-
-// If the thread on which HandleWatcher is used runs a message pump different
-// from MessagePumpMojo, SecondaryThreadWatchingState is used to watch the
-// handle on the handle watcher thread.
-class HandleWatcher::SecondaryThreadWatchingState : public StateBase {
- public:
- SecondaryThreadWatchingState(HandleWatcher* watcher,
- const Handle& handle,
- MojoHandleSignals handle_signals,
- MojoDeadline deadline,
- const base::Callback<void(MojoResult)>& callback)
- : StateBase(watcher, callback),
- weak_factory_(this) {
- watcher_id_ = WatcherThreadManager::GetInstance()->StartWatching(
- handle,
- handle_signals,
- MojoDeadlineToTimeTicks(deadline),
- base::Bind(&SecondaryThreadWatchingState::NotifyHandleReady,
- weak_factory_.GetWeakPtr()));
- }
-
- ~SecondaryThreadWatchingState() override {
- // If we've been notified the handle is ready (|got_ready()| is true) then
- // the watch has been implicitly removed by
- // WatcherThreadManager/MessagePumpMojo and we don't have to call
- // StopWatching(). To do so would needlessly entail posting a task and
- // blocking until the background thread services it.
- if (!got_ready())
- WatcherThreadManager::GetInstance()->StopWatching(watcher_id_);
- }
-
- private:
- WatcherID watcher_id_;
-
- // Used to weakly bind |this| to the WatcherThreadManager.
- base::WeakPtrFactory<SecondaryThreadWatchingState> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(SecondaryThreadWatchingState);
-};
-
-// HandleWatcher ---------------------------------------------------------------
-
-HandleWatcher::HandleWatcher() {
-}
-
-HandleWatcher::~HandleWatcher() {
-}
-
-void HandleWatcher::Start(const Handle& handle,
- MojoHandleSignals handle_signals,
- MojoDeadline deadline,
- const base::Callback<void(MojoResult)>& callback) {
- DCHECK(handle.is_valid());
- DCHECK_NE(MOJO_HANDLE_SIGNAL_NONE, handle_signals);
-
- // Need to clear the state before creating a new one.
- state_.reset();
- if (MessagePumpMojo::IsCurrent()) {
- state_.reset(new SameThreadWatchingState(
- this, handle, handle_signals, deadline, callback));
- } else {
-#if !defined(OFFICIAL_BUILD)
- // Just for making debugging non-transferable message pipes easier. Since
- // they can't be sent after they're read/written/listened to,
- // MessagePipeDispatcher saves the callstack of when it's "bound" to a
- // pipe id. Triggering a read here, instead of later in the PostTask, means
- // we have a callstack that is useful to check if the pipe is erronously
- // attempted to be sent.
- uint32_t temp = 0;
- MojoReadMessage(handle.value(), nullptr, &temp, nullptr, nullptr,
- MOJO_READ_MESSAGE_FLAG_NONE);
-#endif
- state_.reset(new SecondaryThreadWatchingState(
- this, handle, handle_signals, deadline, callback));
- }
-}
-
-void HandleWatcher::Stop() {
- state_.reset();
-}
-
-} // namespace common
-} // namespace mojo
diff --git a/mojo/message_pump/handle_watcher.h b/mojo/message_pump/handle_watcher.h
deleted file mode 100644
index 10056b1..0000000
--- a/mojo/message_pump/handle_watcher.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_MESSAGE_PUMP_HANDLE_WATCHER_H_
-#define MOJO_MESSAGE_PUMP_HANDLE_WATCHER_H_
-
-#include <memory>
-
-#include "base/callback_forward.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "mojo/message_pump/mojo_message_pump_export.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace base {
-class Thread;
-}
-
-namespace mojo {
-namespace common {
-namespace test {
-class HandleWatcherTest;
-}
-
-// HandleWatcher is used to asynchronously wait on a handle and notify a Closure
-// when the handle is ready, or the deadline has expired.
-class MOJO_MESSAGE_PUMP_EXPORT HandleWatcher {
- public:
- HandleWatcher();
-
- ~HandleWatcher();
-
- // Starts listening for |handle|. This implicitly invokes Stop(). In other
- // words, Start() performs one asynchronous watch at a time. It is ok to call
- // Start() multiple times, but it cancels any existing watches. |callback| is
- // notified when the handle is ready, invalid or deadline has passed and is
- // notified on the thread Start() was invoked on. If the current thread exits
- // before the handle is ready, then |callback| is invoked with a result of
- // MOJO_RESULT_ABORTED.
- void Start(const Handle& handle,
- MojoHandleSignals handle_signals,
- MojoDeadline deadline,
- const base::Callback<void(MojoResult)>& callback);
-
- // Stops listening. Does nothing if not in the process of listening.
- void Stop();
-
- bool is_watching() const { return !!state_; }
-
- private:
- class StateBase;
- class SameThreadWatchingState;
- class SecondaryThreadWatchingState;
-
- // If non-NULL Start() has been invoked.
- std::unique_ptr<StateBase> state_;
-
- DISALLOW_COPY_AND_ASSIGN(HandleWatcher);
-};
-
-} // namespace common
-} // namespace mojo
-
-#endif // MOJO_MESSAGE_PUMP_HANDLE_WATCHER_H_
diff --git a/mojo/message_pump/handle_watcher_perftest.cc b/mojo/message_pump/handle_watcher_perftest.cc
deleted file mode 100644
index 96c8495..0000000
--- a/mojo/message_pump/handle_watcher_perftest.cc
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stdint.h>
-
-#include <string>
-#include <utility>
-
-#include "base/auto_reset.h"
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/memory/scoped_vector.h"
-#include "base/run_loop.h"
-#include "base/time/time.h"
-#include "mojo/message_pump/handle_watcher.h"
-#include "mojo/message_pump/message_pump_mojo.h"
-#include "mojo/public/cpp/test_support/test_support.h"
-#include "mojo/public/cpp/test_support/test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace common {
-namespace test {
-
-enum MessageLoopConfig {
- MESSAGE_LOOP_CONFIG_DEFAULT = 0,
- MESSAGE_LOOP_CONFIG_MOJO = 1
-};
-
-std::unique_ptr<base::MessageLoop> CreateMessageLoop(MessageLoopConfig config) {
- std::unique_ptr<base::MessageLoop> loop;
- if (config == MESSAGE_LOOP_CONFIG_DEFAULT)
- loop.reset(new base::MessageLoop());
- else
- loop.reset(new base::MessageLoop(MessagePumpMojo::Create()));
- return loop;
-}
-
-void OnWatcherSignaled(const base::Closure& callback, MojoResult /* result */) {
- callback.Run();
-}
-
-class ScopedPerfTimer {
- public:
- ScopedPerfTimer(const std::string& test_name,
- const std::string& sub_test_name,
- uint64_t iterations)
- : test_name_(test_name),
- sub_test_name_(sub_test_name),
- iterations_(iterations),
- start_time_(base::TimeTicks::Now()) {}
- ~ScopedPerfTimer() {
- base::TimeTicks end_time = base::TimeTicks::Now();
- mojo::test::LogPerfResult(
- test_name_.c_str(), sub_test_name_.c_str(),
- iterations_ / (end_time - start_time_).InSecondsF(),
- "iterations/second");
- }
-
- private:
- const std::string test_name_;
- const std::string sub_test_name_;
- const uint64_t iterations_;
- base::TimeTicks start_time_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedPerfTimer);
-};
-
-class HandleWatcherPerftest : public testing::TestWithParam<MessageLoopConfig> {
- public:
- HandleWatcherPerftest() : message_loop_(CreateMessageLoop(GetParam())) {}
-
- protected:
- std::string GetMessageLoopName() const {
- return (GetParam() == MESSAGE_LOOP_CONFIG_DEFAULT) ? "DefaultMessageLoop"
- : "MojoMessageLoop";
- }
-
- private:
- std::unique_ptr<base::MessageLoop> message_loop_;
-
- DISALLOW_COPY_AND_ASSIGN(HandleWatcherPerftest);
-};
-
-INSTANTIATE_TEST_CASE_P(MultipleMessageLoopConfigs,
- HandleWatcherPerftest,
- testing::Values(MESSAGE_LOOP_CONFIG_DEFAULT,
- MESSAGE_LOOP_CONFIG_MOJO));
-
-void NeverReached(MojoResult result) {
- FAIL() << "Callback should never be invoked " << result;
-}
-
-TEST_P(HandleWatcherPerftest, StartStop) {
- const uint64_t kIterations = 100000;
- MessagePipe pipe;
- HandleWatcher watcher;
-
- ScopedPerfTimer timer("StartStop", GetMessageLoopName(), kIterations);
- for (uint64_t i = 0; i < kIterations; i++) {
- watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
- MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached));
- watcher.Stop();
- }
-}
-
-TEST_P(HandleWatcherPerftest, StartAllThenStop_1000Handles) {
- const uint64_t kIterations = 100;
- const uint64_t kHandles = 1000;
-
- struct TestData {
- MessagePipe pipe;
- HandleWatcher watcher;
- };
- ScopedVector<TestData> data_vector;
- // Create separately from the start/stop loops to avoid affecting the
- // benchmark.
- for (uint64_t i = 0; i < kHandles; i++) {
- std::unique_ptr<TestData> test_data(new TestData);
- ASSERT_TRUE(test_data->pipe.handle0.is_valid());
- data_vector.push_back(std::move(test_data));
- }
-
- ScopedPerfTimer timer("StartAllThenStop_1000Handles", GetMessageLoopName(),
- kIterations * kHandles);
- for (uint64_t iter = 0; iter < kIterations; iter++) {
- for (uint64_t i = 0; i < kHandles; i++) {
- TestData* test_data = data_vector[i];
- test_data->watcher.Start(
- test_data->pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
- MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached));
- }
- for (uint64_t i = 0; i < kHandles; i++) {
- TestData* test_data = data_vector[i];
- test_data->watcher.Stop();
- }
- }
-}
-
-TEST_P(HandleWatcherPerftest, StartAndSignal) {
- const uint64_t kIterations = 10000;
- const std::string kMessage = "hello";
- MessagePipe pipe;
- HandleWatcher watcher;
- std::string received_message;
-
- ScopedPerfTimer timer("StartAndSignal", GetMessageLoopName(), kIterations);
- for (uint64_t i = 0; i < kIterations; i++) {
- base::RunLoop run_loop;
- watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
- MOJO_DEADLINE_INDEFINITE,
- base::Bind(&OnWatcherSignaled, run_loop.QuitClosure()));
- ASSERT_TRUE(mojo::test::WriteTextMessage(pipe.handle1.get(), kMessage));
- run_loop.Run();
- watcher.Stop();
-
- ASSERT_TRUE(
- mojo::test::ReadTextMessage(pipe.handle0.get(), &received_message));
- EXPECT_EQ(kMessage, received_message);
- received_message.clear();
- }
-}
-
-TEST_P(HandleWatcherPerftest, StartAndSignal_1000Waiting) {
- const uint64_t kIterations = 10000;
- const uint64_t kWaitingHandles = 1000;
- const std::string kMessage = "hello";
- MessagePipe pipe;
- HandleWatcher watcher;
- std::string received_message;
-
- struct TestData {
- MessagePipe pipe;
- HandleWatcher watcher;
- };
- ScopedVector<TestData> data_vector;
- for (uint64_t i = 0; i < kWaitingHandles; i++) {
- std::unique_ptr<TestData> test_data(new TestData);
- ASSERT_TRUE(test_data->pipe.handle0.is_valid());
- test_data->watcher.Start(
- test_data->pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
- MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached));
- data_vector.push_back(std::move(test_data));
- }
-
- ScopedPerfTimer timer("StartAndSignal_1000Waiting", GetMessageLoopName(),
- kIterations);
- for (uint64_t i = 0; i < kIterations; i++) {
- base::RunLoop run_loop;
- watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
- MOJO_DEADLINE_INDEFINITE,
- base::Bind(&OnWatcherSignaled, run_loop.QuitClosure()));
- ASSERT_TRUE(mojo::test::WriteTextMessage(pipe.handle1.get(), kMessage));
- run_loop.Run();
- watcher.Stop();
-
- ASSERT_TRUE(
- mojo::test::ReadTextMessage(pipe.handle0.get(), &received_message));
- EXPECT_EQ(kMessage, received_message);
- received_message.clear();
- }
-}
-
-} // namespace test
-} // namespace common
-} // namespace mojo
diff --git a/mojo/message_pump/handle_watcher_unittest.cc b/mojo/message_pump/handle_watcher_unittest.cc
deleted file mode 100644
index fd1f49b..0000000
--- a/mojo/message_pump/handle_watcher_unittest.cc
+++ /dev/null
@@ -1,493 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/message_pump/handle_watcher.h"
-
-#include <memory>
-#include <string>
-
-#include "base/at_exit.h"
-#include "base/auto_reset.h"
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/memory/scoped_vector.h"
-#include "base/run_loop.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "base/threading/thread.h"
-#include "mojo/message_pump/message_pump_mojo.h"
-#include "mojo/message_pump/time_helper.h"
-#include "mojo/public/cpp/system/core.h"
-#include "mojo/public/cpp/test_support/test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace common {
-namespace test {
-
-enum MessageLoopConfig {
- MESSAGE_LOOP_CONFIG_DEFAULT = 0,
- MESSAGE_LOOP_CONFIG_MOJO = 1
-};
-
-void ObserveCallback(bool* was_signaled,
- MojoResult* result_observed,
- MojoResult result) {
- *was_signaled = true;
- *result_observed = result;
-}
-
-void RunUntilIdle() {
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
-}
-
-void DeleteWatcherAndForwardResult(
- HandleWatcher* watcher,
- base::Callback<void(MojoResult)> next_callback,
- MojoResult result) {
- delete watcher;
- next_callback.Run(result);
-}
-
-std::unique_ptr<base::MessageLoop> CreateMessageLoop(MessageLoopConfig config) {
- std::unique_ptr<base::MessageLoop> loop;
- if (config == MESSAGE_LOOP_CONFIG_DEFAULT)
- loop.reset(new base::MessageLoop());
- else
- loop.reset(new base::MessageLoop(MessagePumpMojo::Create()));
- return loop;
-}
-
-// Helper class to manage the callback and running the message loop waiting for
-// message to be received. Typical usage is something like:
-// Schedule callback returned from GetCallback().
-// RunUntilGotCallback();
-// EXPECT_TRUE(got_callback());
-// clear_callback();
-class CallbackHelper {
- public:
- CallbackHelper()
- : got_callback_(false),
- run_loop_(NULL),
- weak_factory_(this) {}
- ~CallbackHelper() {}
-
- // See description above |got_callback_|.
- bool got_callback() const { return got_callback_; }
- void clear_callback() { got_callback_ = false; }
-
- // Runs the current MessageLoop until the callback returned from GetCallback()
- // is notified.
- void RunUntilGotCallback() {
- ASSERT_TRUE(run_loop_ == NULL);
- base::RunLoop run_loop;
- base::AutoReset<base::RunLoop*> reseter(&run_loop_, &run_loop);
- run_loop.Run();
- }
-
- base::Callback<void(MojoResult)> GetCallback() {
- return base::Bind(&CallbackHelper::OnCallback, weak_factory_.GetWeakPtr());
- }
-
- void Start(HandleWatcher* watcher, const MessagePipeHandle& handle) {
- StartWithCallback(watcher, handle, GetCallback());
- }
-
- void StartWithCallback(HandleWatcher* watcher,
- const MessagePipeHandle& handle,
- const base::Callback<void(MojoResult)>& callback) {
- watcher->Start(handle, MOJO_HANDLE_SIGNAL_READABLE,
- MOJO_DEADLINE_INDEFINITE, callback);
- }
-
- private:
- void OnCallback(MojoResult result) {
- got_callback_ = true;
- if (run_loop_)
- run_loop_->Quit();
- }
-
- // Set to true when the callback is called.
- bool got_callback_;
-
- // If non-NULL we're in RunUntilGotCallback().
- base::RunLoop* run_loop_;
-
- base::WeakPtrFactory<CallbackHelper> weak_factory_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CallbackHelper);
-};
-
-class HandleWatcherTest : public testing::TestWithParam<MessageLoopConfig> {
- public:
- HandleWatcherTest()
- : at_exit_(new base::ShadowingAtExitManager),
- message_loop_(CreateMessageLoop(GetParam())) {}
- virtual ~HandleWatcherTest() {
- // By explicitly destroying |at_exit_| before resetting the tick clock, it
- // ensures that the handle watcher thread (if there is one) is shut down,
- // preventing a race with users of the tick clock in MessagePumpMojo.
- at_exit_.reset();
- test::SetTickClockForTest(NULL);
- }
-
- protected:
- void TearDownMessageLoop() {
- message_loop_.reset();
- }
-
- // This should be called at the beginning of any test that needs it, so that
- // it is installed before the handle watcher thread starts.
- void InstallTickClock() {
- test::SetTickClockForTest(&tick_clock_);
- }
-
- base::SimpleTestTickClock tick_clock_;
-
- private:
- std::unique_ptr<base::ShadowingAtExitManager> at_exit_;
- std::unique_ptr<base::MessageLoop> message_loop_;
-
- DISALLOW_COPY_AND_ASSIGN(HandleWatcherTest);
-};
-
-INSTANTIATE_TEST_CASE_P(
- MultipleMessageLoopConfigs, HandleWatcherTest,
- testing::Values(MESSAGE_LOOP_CONFIG_DEFAULT, MESSAGE_LOOP_CONFIG_MOJO));
-
-// Trivial test case with a single handle to watch.
-TEST_P(HandleWatcherTest, SingleHandler) {
- MessagePipe test_pipe;
- ASSERT_TRUE(test_pipe.handle0.is_valid());
- CallbackHelper callback_helper;
- HandleWatcher watcher;
- callback_helper.Start(&watcher, test_pipe.handle0.get());
- RunUntilIdle();
- EXPECT_FALSE(callback_helper.got_callback());
- EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe.handle1.get(),
- std::string()));
- callback_helper.RunUntilGotCallback();
- EXPECT_TRUE(callback_helper.got_callback());
-}
-
-// Creates three handles and notfies them in reverse order ensuring each one is
-// notified appropriately.
-TEST_P(HandleWatcherTest, ThreeHandles) {
- MessagePipe test_pipe1;
- MessagePipe test_pipe2;
- MessagePipe test_pipe3;
- CallbackHelper callback_helper1;
- CallbackHelper callback_helper2;
- CallbackHelper callback_helper3;
- ASSERT_TRUE(test_pipe1.handle0.is_valid());
- ASSERT_TRUE(test_pipe2.handle0.is_valid());
- ASSERT_TRUE(test_pipe3.handle0.is_valid());
-
- HandleWatcher watcher1;
- callback_helper1.Start(&watcher1, test_pipe1.handle0.get());
- RunUntilIdle();
- EXPECT_FALSE(callback_helper1.got_callback());
- EXPECT_FALSE(callback_helper2.got_callback());
- EXPECT_FALSE(callback_helper3.got_callback());
-
- HandleWatcher watcher2;
- callback_helper2.Start(&watcher2, test_pipe2.handle0.get());
- RunUntilIdle();
- EXPECT_FALSE(callback_helper1.got_callback());
- EXPECT_FALSE(callback_helper2.got_callback());
- EXPECT_FALSE(callback_helper3.got_callback());
-
- HandleWatcher watcher3;
- callback_helper3.Start(&watcher3, test_pipe3.handle0.get());
- RunUntilIdle();
- EXPECT_FALSE(callback_helper1.got_callback());
- EXPECT_FALSE(callback_helper2.got_callback());
- EXPECT_FALSE(callback_helper3.got_callback());
-
- // Write to 3 and make sure it's notified.
- EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe3.handle1.get(),
- std::string()));
- callback_helper3.RunUntilGotCallback();
- EXPECT_FALSE(callback_helper1.got_callback());
- EXPECT_FALSE(callback_helper2.got_callback());
- EXPECT_TRUE(callback_helper3.got_callback());
- callback_helper3.clear_callback();
-
- // Write to 1 and 3. Only 1 should be notified since 3 was is no longer
- // running.
- EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe1.handle1.get(),
- std::string()));
- EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe3.handle1.get(),
- std::string()));
- callback_helper1.RunUntilGotCallback();
- EXPECT_TRUE(callback_helper1.got_callback());
- EXPECT_FALSE(callback_helper2.got_callback());
- EXPECT_FALSE(callback_helper3.got_callback());
- callback_helper1.clear_callback();
-
- // Write to 1 and 2. Only 2 should be notified (since 1 was already notified).
- EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe1.handle1.get(),
- std::string()));
- EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe2.handle1.get(),
- std::string()));
- callback_helper2.RunUntilGotCallback();
- EXPECT_FALSE(callback_helper1.got_callback());
- EXPECT_TRUE(callback_helper2.got_callback());
- EXPECT_FALSE(callback_helper3.got_callback());
-}
-
-// Verifies Start() invoked a second time works.
-TEST_P(HandleWatcherTest, Restart) {
- MessagePipe test_pipe1;
- MessagePipe test_pipe2;
- CallbackHelper callback_helper1;
- CallbackHelper callback_helper2;
- ASSERT_TRUE(test_pipe1.handle0.is_valid());
- ASSERT_TRUE(test_pipe2.handle0.is_valid());
-
- HandleWatcher watcher1;
- callback_helper1.Start(&watcher1, test_pipe1.handle0.get());
- RunUntilIdle();
- EXPECT_FALSE(callback_helper1.got_callback());
- EXPECT_FALSE(callback_helper2.got_callback());
-
- HandleWatcher watcher2;
- callback_helper2.Start(&watcher2, test_pipe2.handle0.get());
- RunUntilIdle();
- EXPECT_FALSE(callback_helper1.got_callback());
- EXPECT_FALSE(callback_helper2.got_callback());
-
- // Write to 1 and make sure it's notified.
- EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe1.handle1.get(),
- std::string()));
- callback_helper1.RunUntilGotCallback();
- EXPECT_TRUE(callback_helper1.got_callback());
- EXPECT_FALSE(callback_helper2.got_callback());
- callback_helper1.clear_callback();
- EXPECT_TRUE(mojo::test::DiscardMessage(test_pipe1.handle0.get()));
-
- // Write to 2 and make sure it's notified.
- EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe2.handle1.get(),
- std::string()));
- callback_helper2.RunUntilGotCallback();
- EXPECT_FALSE(callback_helper1.got_callback());
- EXPECT_TRUE(callback_helper2.got_callback());
- callback_helper2.clear_callback();
-
- // Listen on 1 again.
- callback_helper1.Start(&watcher1, test_pipe1.handle0.get());
- RunUntilIdle();
- EXPECT_FALSE(callback_helper1.got_callback());
- EXPECT_FALSE(callback_helper2.got_callback());
-
- // Write to 1 and make sure it's notified.
- EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe1.handle1.get(),
- std::string()));
- callback_helper1.RunUntilGotCallback();
- EXPECT_TRUE(callback_helper1.got_callback());
- EXPECT_FALSE(callback_helper2.got_callback());
-}
-
-// Verifies Start() invoked a second time on the same handle works.
-TEST_P(HandleWatcherTest, RestartOnSameHandle) {
- MessagePipe test_pipe;
- CallbackHelper callback_helper;
- ASSERT_TRUE(test_pipe.handle0.is_valid());
-
- HandleWatcher watcher;
- callback_helper.Start(&watcher, test_pipe.handle0.get());
- RunUntilIdle();
- EXPECT_FALSE(callback_helper.got_callback());
-
- callback_helper.Start(&watcher, test_pipe.handle0.get());
- RunUntilIdle();
- EXPECT_FALSE(callback_helper.got_callback());
-}
-
-// Verifies deadline is honored.
-TEST_P(HandleWatcherTest, Deadline) {
- InstallTickClock();
-
- MessagePipe test_pipe1;
- MessagePipe test_pipe2;
- MessagePipe test_pipe3;
- CallbackHelper callback_helper1;
- CallbackHelper callback_helper2;
- CallbackHelper callback_helper3;
- ASSERT_TRUE(test_pipe1.handle0.is_valid());
- ASSERT_TRUE(test_pipe2.handle0.is_valid());
- ASSERT_TRUE(test_pipe3.handle0.is_valid());
-
- // Add a watcher with an infinite timeout.
- HandleWatcher watcher1;
- callback_helper1.Start(&watcher1, test_pipe1.handle0.get());
- RunUntilIdle();
- EXPECT_FALSE(callback_helper1.got_callback());
- EXPECT_FALSE(callback_helper2.got_callback());
- EXPECT_FALSE(callback_helper3.got_callback());
-
- // Add another watcher wth a timeout of 500 microseconds.
- HandleWatcher watcher2;
- watcher2.Start(test_pipe2.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE, 500,
- callback_helper2.GetCallback());
- RunUntilIdle();
- EXPECT_FALSE(callback_helper1.got_callback());
- EXPECT_FALSE(callback_helper2.got_callback());
- EXPECT_FALSE(callback_helper3.got_callback());
-
- // Advance the clock passed the deadline. We also have to start another
- // watcher to wake up the background thread.
- tick_clock_.Advance(base::TimeDelta::FromMicroseconds(501));
-
- HandleWatcher watcher3;
- callback_helper3.Start(&watcher3, test_pipe3.handle0.get());
-
- callback_helper2.RunUntilGotCallback();
- EXPECT_FALSE(callback_helper1.got_callback());
- EXPECT_TRUE(callback_helper2.got_callback());
- EXPECT_FALSE(callback_helper3.got_callback());
-}
-
-TEST_P(HandleWatcherTest, DeleteInCallback) {
- MessagePipe test_pipe;
- CallbackHelper callback_helper;
-
- HandleWatcher* watcher = new HandleWatcher();
- callback_helper.StartWithCallback(watcher, test_pipe.handle1.get(),
- base::Bind(&DeleteWatcherAndForwardResult,
- watcher,
- callback_helper.GetCallback()));
- EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe.handle0.get(),
- std::string()));
- callback_helper.RunUntilGotCallback();
- EXPECT_TRUE(callback_helper.got_callback());
-}
-
-TEST_P(HandleWatcherTest, AbortedOnMessageLoopDestruction) {
- bool was_signaled = false;
- MojoResult result = MOJO_RESULT_OK;
-
- MessagePipe pipe;
- HandleWatcher watcher;
- watcher.Start(pipe.handle0.get(),
- MOJO_HANDLE_SIGNAL_READABLE,
- MOJO_DEADLINE_INDEFINITE,
- base::Bind(&ObserveCallback, &was_signaled, &result));
-
- // Now, let the MessageLoop get torn down. We expect our callback to run.
- TearDownMessageLoop();
-
- EXPECT_TRUE(was_signaled);
- EXPECT_EQ(MOJO_RESULT_ABORTED, result);
-}
-
-void NeverReached(MojoResult result) {
- FAIL() << "Callback should never be invoked " << result;
-}
-
-// Called on the main thread when a thread is done. Decrements |active_count|
-// and if |active_count| is zero quits |run_loop|.
-void StressThreadDone(base::RunLoop* run_loop, int* active_count) {
- (*active_count)--;
- EXPECT_GE(*active_count, 0);
- if (*active_count == 0)
- run_loop->Quit();
-}
-
-// See description of StressTest. This is called on the background thread.
-// |count| is the number of HandleWatchers to create. |active_count| is the
-// number of outstanding threads, |task_runner| the task runner for the main
-// thread and |run_loop| the run loop that should be quit when there are no more
-// threads running. When done StressThreadDone() is invoked on the main thread.
-// |active_count| and |run_loop| should only be used on the main thread.
-void RunStressTest(int count,
- scoped_refptr<base::TaskRunner> task_runner,
- base::RunLoop* run_loop,
- int* active_count) {
- struct TestData {
- MessagePipe pipe;
- HandleWatcher watcher;
- };
- ScopedVector<TestData> data_vector;
- for (int i = 0; i < count; ++i) {
- if (i % 20 == 0) {
- // Every so often we wait. This results in some level of thread balancing
- // as well as making sure HandleWatcher has time to actually start some
- // watches.
- MessagePipe test_pipe;
- ASSERT_TRUE(test_pipe.handle0.is_valid());
- CallbackHelper callback_helper;
- HandleWatcher watcher;
- callback_helper.Start(&watcher, test_pipe.handle0.get());
- RunUntilIdle();
- EXPECT_FALSE(callback_helper.got_callback());
- EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe.handle1.get(),
- std::string()));
- base::MessageLoop::ScopedNestableTaskAllower scoper(
- base::MessageLoop::current());
- callback_helper.RunUntilGotCallback();
- EXPECT_TRUE(callback_helper.got_callback());
- } else {
- std::unique_ptr<TestData> test_data(new TestData);
- ASSERT_TRUE(test_data->pipe.handle0.is_valid());
- test_data->watcher.Start(test_data->pipe.handle0.get(),
- MOJO_HANDLE_SIGNAL_READABLE,
- MOJO_DEADLINE_INDEFINITE,
- base::Bind(&NeverReached));
- data_vector.push_back(test_data.release());
- }
- if (i % 15 == 0)
- data_vector.clear();
- }
- task_runner->PostTask(FROM_HERE,
- base::Bind(&StressThreadDone, run_loop,
- active_count));
-}
-
-// This test is meant to stress HandleWatcher. It uses from various threads
-// repeatedly starting and stopping watches. It spins up kThreadCount
-// threads. Each thread creates kWatchCount watches. Every so often each thread
-// writes to a pipe and waits for the response.
-TEST(HandleWatcherCleanEnvironmentTest, StressTest) {
-#if defined(NDEBUG)
- const int kThreadCount = 15;
- const int kWatchCount = 400;
-#else
- const int kThreadCount = 10;
- const int kWatchCount = 250;
-#endif
-
- base::ShadowingAtExitManager at_exit;
- base::MessageLoop message_loop;
- base::RunLoop run_loop;
- ScopedVector<base::Thread> threads;
- int threads_active_counter = kThreadCount;
- // Starts the threads first and then post the task in hopes of having more
- // threads running at once.
- for (int i = 0; i < kThreadCount; ++i) {
- std::unique_ptr<base::Thread> thread(new base::Thread("test thread"));
- if (i % 2) {
- base::Thread::Options thread_options;
- thread_options.message_pump_factory =
- base::Bind(&MessagePumpMojo::Create);
- thread->StartWithOptions(thread_options);
- } else {
- thread->Start();
- }
- threads.push_back(thread.release());
- }
- for (int i = 0; i < kThreadCount; ++i) {
- threads[i]->task_runner()->PostTask(
- FROM_HERE, base::Bind(&RunStressTest, kWatchCount,
- message_loop.task_runner(),
- &run_loop, &threads_active_counter));
- }
- run_loop.Run();
- ASSERT_EQ(0, threads_active_counter);
-}
-
-} // namespace test
-} // namespace common
-} // namespace mojo
diff --git a/mojo/message_pump/message_pump_mojo.cc b/mojo/message_pump/message_pump_mojo.cc
deleted file mode 100644
index b907ba3..0000000
--- a/mojo/message_pump/message_pump_mojo.cc
+++ /dev/null
@@ -1,448 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/message_pump/message_pump_mojo.h"
-
-#include <stdint.h>
-
-#include <algorithm>
-#include <map>
-#include <vector>
-
-#include "base/containers/small_map.h"
-#include "base/debug/alias.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/threading/thread_local.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/time/time.h"
-#include "mojo/message_pump/message_pump_mojo_handler.h"
-#include "mojo/message_pump/time_helper.h"
-#include "mojo/public/c/system/wait_set.h"
-
-namespace mojo {
-namespace common {
-namespace {
-
-base::LazyInstance<base::ThreadLocalPointer<MessagePumpMojo> >::Leaky
- g_tls_current_pump = LAZY_INSTANCE_INITIALIZER;
-
-MojoDeadline TimeTicksToMojoDeadline(base::TimeTicks time_ticks,
- base::TimeTicks now) {
- // The is_null() check matches that of HandleWatcher as well as how
- // |delayed_work_time| is used.
- if (time_ticks.is_null())
- return MOJO_DEADLINE_INDEFINITE;
- const int64_t delta = (time_ticks - now).InMicroseconds();
- return delta < 0 ? static_cast<MojoDeadline>(0) :
- static_cast<MojoDeadline>(delta);
-}
-
-} // namespace
-
-struct MessagePumpMojo::RunState {
- RunState() : should_quit(false) {}
-
- base::TimeTicks delayed_work_time;
-
- bool should_quit;
-};
-
-MessagePumpMojo::MessagePumpMojo()
- : run_state_(NULL),
- next_handler_id_(0),
- event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED) {
- DCHECK(!current())
- << "There is already a MessagePumpMojo instance on this thread.";
- g_tls_current_pump.Pointer()->Set(this);
-
- MojoResult result = CreateMessagePipe(nullptr, &read_handle_, &write_handle_);
- CHECK_EQ(result, MOJO_RESULT_OK);
- CHECK(read_handle_.is_valid());
- CHECK(write_handle_.is_valid());
-
- MojoHandle handle;
- result = MojoCreateWaitSet(&handle);
- CHECK_EQ(result, MOJO_RESULT_OK);
- wait_set_handle_.reset(Handle(handle));
- CHECK(wait_set_handle_.is_valid());
-
- result =
- MojoAddHandle(wait_set_handle_.get().value(), read_handle_.get().value(),
- MOJO_HANDLE_SIGNAL_READABLE);
- CHECK_EQ(result, MOJO_RESULT_OK);
-}
-
-MessagePumpMojo::~MessagePumpMojo() {
- DCHECK_EQ(this, current());
- g_tls_current_pump.Pointer()->Set(NULL);
-}
-
-// static
-std::unique_ptr<base::MessagePump> MessagePumpMojo::Create() {
- return std::unique_ptr<MessagePump>(new MessagePumpMojo());
-}
-
-// static
-MessagePumpMojo* MessagePumpMojo::current() {
- return g_tls_current_pump.Pointer()->Get();
-}
-
-void MessagePumpMojo::AddHandler(MessagePumpMojoHandler* handler,
- const Handle& handle,
- MojoHandleSignals wait_signals,
- base::TimeTicks deadline) {
- CHECK(handler);
- DCHECK(handle.is_valid());
- // Assume it's an error if someone tries to reregister an existing handle.
- CHECK_EQ(0u, handlers_.count(handle));
- Handler handler_data;
- handler_data.handler = handler;
- handler_data.wait_signals = wait_signals;
- handler_data.deadline = deadline;
- handler_data.id = next_handler_id_++;
- handlers_[handle] = handler_data;
- if (!deadline.is_null()) {
- bool inserted = deadline_handles_.insert(handle).second;
- DCHECK(inserted);
- }
-
- MojoResult result = MojoAddHandle(wait_set_handle_.get().value(),
- handle.value(), wait_signals);
- // Because stopping a HandleWatcher is now asynchronous, it's possible for the
- // handle to no longer be open at this point.
- CHECK(result == MOJO_RESULT_OK || result == MOJO_RESULT_INVALID_ARGUMENT);
-}
-
-void MessagePumpMojo::RemoveHandler(const Handle& handle) {
- MojoResult result =
- MojoRemoveHandle(wait_set_handle_.get().value(), handle.value());
- // At this point, it's possible that the handle has been closed, which would
- // cause MojoRemoveHandle() to return MOJO_RESULT_INVALID_ARGUMENT. It's also
- // possible for the handle to have already been removed, so all of the
- // possible error codes are valid here.
- CHECK(result == MOJO_RESULT_OK || result == MOJO_RESULT_NOT_FOUND ||
- result == MOJO_RESULT_INVALID_ARGUMENT);
-
- handlers_.erase(handle);
- deadline_handles_.erase(handle);
-}
-
-void MessagePumpMojo::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
-
-void MessagePumpMojo::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void MessagePumpMojo::Run(Delegate* delegate) {
- RunState run_state;
- RunState* old_state = NULL;
- {
- base::AutoLock auto_lock(run_state_lock_);
- old_state = run_state_;
- run_state_ = &run_state;
- }
- DoRunLoop(&run_state, delegate);
- {
- base::AutoLock auto_lock(run_state_lock_);
- run_state_ = old_state;
- }
-}
-
-void MessagePumpMojo::Quit() {
- base::AutoLock auto_lock(run_state_lock_);
- if (run_state_)
- run_state_->should_quit = true;
-}
-
-void MessagePumpMojo::ScheduleWork() {
- SignalControlPipe();
-}
-
-void MessagePumpMojo::ScheduleDelayedWork(
- const base::TimeTicks& delayed_work_time) {
- base::AutoLock auto_lock(run_state_lock_);
- if (!run_state_)
- return;
- run_state_->delayed_work_time = delayed_work_time;
-}
-
-void MessagePumpMojo::DoRunLoop(RunState* run_state, Delegate* delegate) {
- bool more_work_is_plausible = true;
- for (;;) {
- const bool block = !more_work_is_plausible;
- if (read_handle_.is_valid()) {
- more_work_is_plausible = DoInternalWork(*run_state, block);
- } else {
- more_work_is_plausible = DoNonMojoWork(*run_state, block);
- }
-
- if (run_state->should_quit)
- break;
-
- more_work_is_plausible |= delegate->DoWork();
- if (run_state->should_quit)
- break;
-
- more_work_is_plausible |= delegate->DoDelayedWork(
- &run_state->delayed_work_time);
- if (run_state->should_quit)
- break;
-
- if (more_work_is_plausible)
- continue;
-
- more_work_is_plausible = delegate->DoIdleWork();
- if (run_state->should_quit)
- break;
- }
-}
-
-bool MessagePumpMojo::DoInternalWork(const RunState& run_state, bool block) {
- bool did_work = block;
- if (block) {
- // If the wait isn't blocking (deadline == 0), there's no point in waiting.
- // Wait sets do not require a wait operation to be performed in order to
- // retreive any ready handles. Performing a wait with deadline == 0 is
- // unnecessary work.
- did_work = WaitForReadyHandles(run_state);
- }
-
- did_work |= ProcessReadyHandles();
- did_work |= RemoveExpiredHandles();
-
- return did_work;
-}
-
-bool MessagePumpMojo::DoNonMojoWork(const RunState& run_state, bool block) {
- bool did_work = block;
- if (block) {
- const MojoDeadline deadline = GetDeadlineForWait(run_state);
- // Stolen from base/message_loop/message_pump_default.cc
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- if (deadline == MOJO_DEADLINE_INDEFINITE) {
- event_.Wait();
- } else {
- if (deadline > 0) {
- event_.TimedWait(base::TimeDelta::FromMicroseconds(deadline));
- } else {
- did_work = false;
- }
- }
- // Since event_ is auto-reset, we don't need to do anything special here
- // other than service each delegate method.
- }
-
- did_work |= RemoveExpiredHandles();
-
- return did_work;
-}
-
-bool MessagePumpMojo::WaitForReadyHandles(const RunState& run_state) const {
- const MojoDeadline deadline = GetDeadlineForWait(run_state);
- const MojoResult wait_result = Wait(
- wait_set_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, deadline, nullptr);
- if (wait_result == MOJO_RESULT_OK) {
- // Handles may be ready. Or not since wake-ups can be spurious in certain
- // circumstances.
- return true;
- } else if (wait_result == MOJO_RESULT_DEADLINE_EXCEEDED) {
- return false;
- }
-
- base::debug::Alias(&wait_result);
- // Unexpected result is likely fatal, crash so we can determine cause.
- CHECK(false);
- return false;
-}
-
-bool MessagePumpMojo::ProcessReadyHandles() {
- // Maximum number of handles to retrieve and process. Experimentally, the 95th
- // percentile is 1 handle, and the long-term average is 1.1. However, this has
- // been seen to reach >10 under heavy load. 8 is a hand-wavy compromise.
- const uint32_t kMaxServiced = 8;
- uint32_t num_ready_handles = kMaxServiced;
- MojoHandle handles[kMaxServiced];
- MojoResult handle_results[kMaxServiced];
-
- const MojoResult get_result =
- MojoGetReadyHandles(wait_set_handle_.get().value(), &num_ready_handles,
- handles, handle_results, nullptr);
- CHECK(get_result == MOJO_RESULT_OK || get_result == MOJO_RESULT_SHOULD_WAIT);
- if (get_result != MOJO_RESULT_OK)
- return false;
-
- DCHECK(num_ready_handles);
- DCHECK_LE(num_ready_handles, kMaxServiced);
- // Do this in two steps, because notifying a handler may remove/add other
- // handles that may have also been woken up.
- // First, enumerate the IDs of the ready handles. Then, iterate over the
- // handles and only take action if the ID hasn't changed.
- // Since the size of this map is bounded by |kMaxServiced|, use a SmallMap to
- // avoid the per-element allocation.
- base::SmallMap<std::map<Handle, int>, kMaxServiced> ready_handles;
- for (uint32_t i = 0; i < num_ready_handles; i++) {
- const Handle handle = Handle(handles[i]);
- // Skip the control handle. It's special.
- if (handle.value() == read_handle_.get().value())
- continue;
- DCHECK(handle.is_valid());
- const auto it = handlers_.find(handle);
- // Skip handles that have been removed. This is possible because
- // RemoveHandler() can be called with a handle that has been closed. Because
- // the handle is closed, the MojoRemoveHandle() call in RemoveHandler()
- // would have failed, but the handle is still in the wait set. Once the
- // handle is retrieved using MojoGetReadyHandles(), it is implicitly removed
- // from the set. The result is either the pending result that existed when
- // the handle was closed, or |MOJO_RESULT_CANCELLED| to indicate that the
- // handle was closed.
- if (it == handlers_.end())
- continue;
- ready_handles[handle] = it->second.id;
- }
-
- for (uint32_t i = 0; i < num_ready_handles; i++) {
- const Handle handle = Handle(handles[i]);
-
- // If the handle has been removed, or it's ID has changed, skip over it.
- // If the handle's ID has changed, and it still satisfies its signals,
- // then it'll be caught in the next message pump iteration.
- const auto it = handlers_.find(handle);
- if ((handle.value() != read_handle_.get().value()) &&
- (it == handlers_.end() || it->second.id != ready_handles[handle])) {
- continue;
- }
-
- switch (handle_results[i]) {
- case MOJO_RESULT_CANCELLED:
- case MOJO_RESULT_FAILED_PRECONDITION:
- DVLOG(1) << "Error: " << handle_results[i]
- << " handle: " << handle.value();
- if (handle.value() == read_handle_.get().value()) {
- // The Mojo EDK is shutting down. We can't just quit the message pump
- // because that may cause the thread to quit, which causes the
- // thread's MessageLoop to be destroyed, which races with any use of
- // |Thread::task_runner()|. So instead, we enter a "dumb" mode which
- // bypasses Mojo and just acts like a trivial message pump. That way,
- // we can wait for the usual thread exiting mechanism to happen.
- // The dumb mode is indicated by releasing the control pipe's read
- // handle.
- read_handle_.reset();
- } else {
- SignalHandleError(handle, handle_results[i]);
- }
- break;
- case MOJO_RESULT_OK:
- if (handle.value() == read_handle_.get().value()) {
- DVLOG(1) << "Signaled control pipe";
- // Control pipe was written to.
- ReadMessageRaw(read_handle_.get(), nullptr, nullptr, nullptr, nullptr,
- MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
- } else {
- DVLOG(1) << "Handle ready: " << handle.value();
- SignalHandleReady(handle);
- }
- break;
- default:
- base::debug::Alias(&i);
- base::debug::Alias(&handle_results[i]);
- // Unexpected result is likely fatal, crash so we can determine cause.
- CHECK(false);
- }
- }
- return true;
-}
-
-bool MessagePumpMojo::RemoveExpiredHandles() {
- bool removed = false;
- // Notify and remove any handlers whose time has expired. First, iterate over
- // the set of handles that have a deadline, and add the expired handles to a
- // map of <Handle, id>. Then, iterate over those expired handles and remove
- // them. The two-step process is because a handler can add/remove new
- // handlers.
- std::map<Handle, int> expired_handles;
- const base::TimeTicks now(internal::NowTicks());
- for (const Handle handle : deadline_handles_) {
- const auto it = handlers_.find(handle);
- // Expect any handle in |deadline_handles_| to also be in |handlers_| since
- // the two are modified in lock-step.
- DCHECK(it != handlers_.end());
- if (!it->second.deadline.is_null() && it->second.deadline < now)
- expired_handles[handle] = it->second.id;
- }
- for (const auto& pair : expired_handles) {
- auto it = handlers_.find(pair.first);
- // Don't need to check deadline again since it can't change if id hasn't
- // changed.
- if (it != handlers_.end() && it->second.id == pair.second) {
- SignalHandleError(pair.first, MOJO_RESULT_DEADLINE_EXCEEDED);
- removed = true;
- }
- }
- return removed;
-}
-
-void MessagePumpMojo::SignalControlPipe() {
- const MojoResult result =
- WriteMessageRaw(write_handle_.get(), NULL, 0, NULL, 0,
- MOJO_WRITE_MESSAGE_FLAG_NONE);
- if (result == MOJO_RESULT_FAILED_PRECONDITION) {
- // Mojo EDK is shutting down.
- event_.Signal();
- return;
- }
-
- // If we can't write we likely won't wake up the thread and there is a strong
- // chance we'll deadlock.
- CHECK_EQ(MOJO_RESULT_OK, result);
-}
-
-MojoDeadline MessagePumpMojo::GetDeadlineForWait(
- const RunState& run_state) const {
- const base::TimeTicks now(internal::NowTicks());
- MojoDeadline deadline = TimeTicksToMojoDeadline(run_state.delayed_work_time,
- now);
- for (const Handle handle : deadline_handles_) {
- auto it = handlers_.find(handle);
- DCHECK(it != handlers_.end());
- deadline = std::min(
- TimeTicksToMojoDeadline(it->second.deadline, now), deadline);
- }
- return deadline;
-}
-
-void MessagePumpMojo::SignalHandleReady(Handle handle) {
- auto it = handlers_.find(handle);
- DCHECK(it != handlers_.end());
- MessagePumpMojoHandler* handler = it->second.handler;
-
- WillSignalHandler();
- handler->OnHandleReady(handle);
- DidSignalHandler();
-}
-
-void MessagePumpMojo::SignalHandleError(Handle handle, MojoResult result) {
- auto it = handlers_.find(handle);
- DCHECK(it != handlers_.end());
- MessagePumpMojoHandler* handler = it->second.handler;
-
- RemoveHandler(handle);
- WillSignalHandler();
- handler->OnHandleError(handle, result);
- DidSignalHandler();
-}
-
-void MessagePumpMojo::WillSignalHandler() {
- FOR_EACH_OBSERVER(Observer, observers_, WillSignalHandler());
-}
-
-void MessagePumpMojo::DidSignalHandler() {
- FOR_EACH_OBSERVER(Observer, observers_, DidSignalHandler());
-}
-
-} // namespace common
-} // namespace mojo
diff --git a/mojo/message_pump/message_pump_mojo.h b/mojo/message_pump/message_pump_mojo.h
deleted file mode 100644
index ef2f55a..0000000
--- a/mojo/message_pump/message_pump_mojo.h
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_MESSAGE_PUMP_MESSAGE_PUMP_MOJO_H_
-#define MOJO_MESSAGE_PUMP_MESSAGE_PUMP_MOJO_H_
-
-#include <stdint.h>
-
-#include <functional>
-#include <memory>
-#include <set>
-#include <unordered_map>
-
-#include "base/macros.h"
-#include "base/message_loop/message_pump.h"
-#include "base/observer_list.h"
-#include "base/synchronization/lock.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/time/time.h"
-#include "mojo/message_pump/mojo_message_pump_export.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace mojo {
-namespace common {
-
-class MessagePumpMojoHandler;
-
-// Mojo implementation of MessagePump.
-class MOJO_MESSAGE_PUMP_EXPORT MessagePumpMojo : public base::MessagePump {
- public:
- class MOJO_MESSAGE_PUMP_EXPORT Observer {
- public:
- Observer() {}
-
- virtual void WillSignalHandler() = 0;
- virtual void DidSignalHandler() = 0;
-
- protected:
- virtual ~Observer() {}
- };
-
- MessagePumpMojo();
- ~MessagePumpMojo() override;
-
- // Static factory function (for using with |base::Thread::Options|, wrapped
- // using |base::Bind()|).
- static std::unique_ptr<base::MessagePump> Create();
-
- // Returns the MessagePumpMojo instance of the current thread, if it exists.
- static MessagePumpMojo* current();
-
- static bool IsCurrent() { return !!current(); }
-
- // Registers a MessagePumpMojoHandler for the specified handle. Only one
- // handler can be registered for a specified handle.
- // NOTE: a value of 0 for |deadline| indicates an indefinite timeout.
- void AddHandler(MessagePumpMojoHandler* handler,
- const Handle& handle,
- MojoHandleSignals wait_signals,
- base::TimeTicks deadline);
-
- void RemoveHandler(const Handle& handle);
-
- void AddObserver(Observer*);
- void RemoveObserver(Observer*);
-
- // MessagePump:
- void Run(Delegate* delegate) override;
- void Quit() override;
- void ScheduleWork() override;
- void ScheduleDelayedWork(const base::TimeTicks& delayed_work_time) override;
-
- private:
- struct RunState;
-
- // Contains the data needed to track a request to AddHandler().
- struct Handler {
- Handler() : handler(NULL), wait_signals(MOJO_HANDLE_SIGNAL_NONE), id(0) {}
-
- MessagePumpMojoHandler* handler;
- MojoHandleSignals wait_signals;
- base::TimeTicks deadline;
- // See description of |MessagePumpMojo::next_handler_id_| for details.
- int id;
- };
-
- struct HandleHasher {
- size_t operator()(const Handle& handle) const {
- return std::hash<uint32_t>()(static_cast<uint32_t>(handle.value()));
- }
- };
-
- using HandleToHandler = std::unordered_map<Handle, Handler, HandleHasher>;
-
- // Implementation of Run().
- void DoRunLoop(RunState* run_state, Delegate* delegate);
-
- // Services the set of handles ready. If |block| is true this waits for a
- // handle to become ready, otherwise this does not block. Returns |true| if a
- // handle has become ready, |false| otherwise.
- bool DoInternalWork(const RunState& run_state, bool block);
-
- bool DoNonMojoWork(const RunState& run_state, bool block);
-
- // Waits for handles in the wait set to become ready. Returns |true| if ready
- // handles may be available, or |false| if the wait's deadline was exceeded.
- // Note, ready handles may be unavailable, even though |true| was returned.
- bool WaitForReadyHandles(const RunState& run_state) const;
-
- // Retrieves any 'ready' handles from the wait set, and runs the handler's
- // OnHandleReady() or OnHandleError() functions as necessary. Returns |true|
- // if any handles were ready and processed.
- bool ProcessReadyHandles();
-
- // Removes any handles that have expired their deadline. Runs the handler's
- // OnHandleError() function with |MOJO_RESULT_DEADLINE_EXCEEDED| as the
- // result. Returns |true| if any handles were removed.
- bool RemoveExpiredHandles();
-
- void SignalControlPipe();
-
- // Returns the deadline for the call to MojoWait().
- MojoDeadline GetDeadlineForWait(const RunState& run_state) const;
-
- // Run |OnHandleReady()| for the handler registered with |handle|. |handle|
- // must be registered.
- void SignalHandleReady(Handle handle);
-
- // Run |OnHandleError()| for the handler registered with |handle| and the
- // error code |result|. |handle| must be registered, and will be removed
- // before calling |OnHandleError()|.
- void SignalHandleError(Handle handle, MojoResult result);
-
- void WillSignalHandler();
- void DidSignalHandler();
-
- // If non-NULL we're running (inside Run()). Member is reference to value on
- // stack.
- RunState* run_state_;
-
- // Lock for accessing |run_state_|. In general the only method that we have to
- // worry about is ScheduleWork(). All other methods are invoked on the same
- // thread.
- base::Lock run_state_lock_;
-
- HandleToHandler handlers_;
- // Set of handles that have a deadline set. Avoids iterating over all elements
- // in |handles_| in the common case (no deadline set).
- // TODO(amistry): Make this better and avoid special-casing deadlines.
- std::set<Handle> deadline_handles_;
-
- // An ever increasing value assigned to each Handler::id. Used to detect
- // uniqueness while notifying. That is, while notifying expired timers we copy
- // |handlers_| and only notify handlers whose id match. If the id does not
- // match it means the handler was removed then added so that we shouldn't
- // notify it.
- int next_handler_id_;
-
- base::ObserverList<Observer> observers_;
-
- // Mojo handle for the wait set.
- ScopedHandle wait_set_handle_;
- // Used to wake up run loop from |SignalControlPipe()|.
- ScopedMessagePipeHandle read_handle_;
- ScopedMessagePipeHandle write_handle_;
-
- // Used to sleep until there is more work to do, when the Mojo EDK is shutting
- // down.
- base::WaitableEvent event_;
-
- DISALLOW_COPY_AND_ASSIGN(MessagePumpMojo);
-};
-
-} // namespace common
-} // namespace mojo
-
-#endif // MOJO_MESSAGE_PUMP_MESSAGE_PUMP_MOJO_H_
diff --git a/mojo/message_pump/message_pump_mojo_handler.h b/mojo/message_pump/message_pump_mojo_handler.h
deleted file mode 100644
index 8beb9ba..0000000
--- a/mojo/message_pump/message_pump_mojo_handler.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_MESSAGE_PUMP_MESSAGE_PUMP_MOJO_HANDLER_H_
-#define MOJO_MESSAGE_PUMP_MESSAGE_PUMP_MOJO_HANDLER_H_
-
-#include "mojo/message_pump/mojo_message_pump_export.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace mojo {
-namespace common {
-
-// Used by MessagePumpMojo to notify when a handle is either ready or has become
-// invalid. In case of error, the handler will be removed.
-class MOJO_MESSAGE_PUMP_EXPORT MessagePumpMojoHandler {
- public:
- virtual void OnHandleReady(const Handle& handle) = 0;
-
- virtual void OnHandleError(const Handle& handle, MojoResult result) = 0;
-
- protected:
- virtual ~MessagePumpMojoHandler() {}
-};
-
-} // namespace common
-} // namespace mojo
-
-#endif // MOJO_MESSAGE_PUMP_MESSAGE_PUMP_MOJO_HANDLER_H_
diff --git a/mojo/message_pump/message_pump_mojo_unittest.cc b/mojo/message_pump/message_pump_mojo_unittest.cc
deleted file mode 100644
index 1abb27c..0000000
--- a/mojo/message_pump/message_pump_mojo_unittest.cc
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/message_pump/message_pump_mojo.h"
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop_test.h"
-#include "base/run_loop.h"
-#include "mojo/message_pump/message_pump_mojo_handler.h"
-#include "mojo/public/cpp/system/core.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace common {
-namespace test {
-
-std::unique_ptr<base::MessagePump> CreateMojoMessagePump() {
- return std::unique_ptr<base::MessagePump>(new MessagePumpMojo());
-}
-
-RUN_MESSAGE_LOOP_TESTS(Mojo, &CreateMojoMessagePump);
-
-class CountingMojoHandler : public MessagePumpMojoHandler {
- public:
- CountingMojoHandler() : success_count_(0), error_count_(0) {}
-
- void OnHandleReady(const Handle& handle) override {
- ReadMessageRaw(static_cast<const MessagePipeHandle&>(handle),
- NULL,
- NULL,
- NULL,
- NULL,
- MOJO_READ_MESSAGE_FLAG_NONE);
- ++success_count_;
- if (success_count_ == success_callback_count_ &&
- !success_callback_.is_null()) {
- success_callback_.Run();
- success_callback_.Reset();
- }
- }
-
- void set_success_callback(const base::Closure& callback,
- int success_count) {
- success_callback_ = callback;
- success_callback_count_ = success_count;
- }
-
- void OnHandleError(const Handle& handle, MojoResult result) override {
- ++error_count_;
- if (!error_callback_.is_null()) {
- error_callback_.Run();
- error_callback_.Reset();
- }
- }
-
- void set_error_callback(const base::Closure& callback) {
- error_callback_ = callback;
- }
-
- int success_count() { return success_count_; }
- int error_count() { return error_count_; }
-
- private:
- int success_count_;
- int error_count_;
-
- base::Closure error_callback_;
- int success_callback_count_;
-
- base::Closure success_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(CountingMojoHandler);
-};
-
-class CountingObserver : public MessagePumpMojo::Observer {
- public:
- void WillSignalHandler() override { will_signal_handler_count++; }
- void DidSignalHandler() override { did_signal_handler_count++; }
-
- int will_signal_handler_count = 0;
- int did_signal_handler_count = 0;
-};
-
-TEST(MessagePumpMojo, RunUntilIdle) {
- base::MessageLoop message_loop(MessagePumpMojo::Create());
- CountingMojoHandler handler;
- base::RunLoop run_loop;
- handler.set_success_callback(run_loop.QuitClosure(), 2);
- MessagePipe handles;
- MessagePumpMojo::current()->AddHandler(&handler,
- handles.handle0.get(),
- MOJO_HANDLE_SIGNAL_READABLE,
- base::TimeTicks());
- WriteMessageRaw(
- handles.handle1.get(), NULL, 0, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
- WriteMessageRaw(
- handles.handle1.get(), NULL, 0, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
- MojoHandleSignalsState hss;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWait(handles.handle0.get().value(), MOJO_HANDLE_SIGNAL_READABLE,
- MOJO_DEADLINE_INDEFINITE, &hss));
- run_loop.Run();
- EXPECT_EQ(2, handler.success_count());
-}
-
-TEST(MessagePumpMojo, Observer) {
- base::MessageLoop message_loop(MessagePumpMojo::Create());
-
- CountingObserver observer;
- MessagePumpMojo::current()->AddObserver(&observer);
-
- CountingMojoHandler handler;
- base::RunLoop run_loop;
- handler.set_success_callback(run_loop.QuitClosure(), 1);
- MessagePipe handles;
- MessagePumpMojo::current()->AddHandler(&handler,
- handles.handle0.get(),
- MOJO_HANDLE_SIGNAL_READABLE,
- base::TimeTicks());
- WriteMessageRaw(
- handles.handle1.get(), NULL, 0, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
-
- MojoHandleSignalsState hss;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWait(handles.handle0.get().value(), MOJO_HANDLE_SIGNAL_READABLE,
- MOJO_DEADLINE_INDEFINITE, &hss));
- run_loop.Run();
- EXPECT_EQ(1, handler.success_count());
- EXPECT_EQ(1, observer.will_signal_handler_count);
- EXPECT_EQ(1, observer.did_signal_handler_count);
- MessagePumpMojo::current()->RemoveObserver(&observer);
-
- base::RunLoop run_loop2;
- handler.set_success_callback(run_loop2.QuitClosure(), 2);
- WriteMessageRaw(
- handles.handle1.get(), NULL, 0, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWait(handles.handle0.get().value(), MOJO_HANDLE_SIGNAL_READABLE,
- MOJO_DEADLINE_INDEFINITE, &hss));
- run_loop2.Run();
- EXPECT_EQ(2, handler.success_count());
- EXPECT_EQ(1, observer.will_signal_handler_count);
- EXPECT_EQ(1, observer.did_signal_handler_count);
-}
-
-TEST(MessagePumpMojo, UnregisterAfterDeadline) {
- base::MessageLoop message_loop(MessagePumpMojo::Create());
- CountingMojoHandler handler;
- base::RunLoop run_loop;
- handler.set_error_callback(run_loop.QuitClosure());
- MessagePipe handles;
- MessagePumpMojo::current()->AddHandler(
- &handler,
- handles.handle0.get(),
- MOJO_HANDLE_SIGNAL_READABLE,
- base::TimeTicks::Now() - base::TimeDelta::FromSeconds(1));
- run_loop.Run();
- EXPECT_EQ(1, handler.error_count());
-}
-
-TEST(MessagePumpMojo, AddClosedHandle) {
- base::MessageLoop message_loop(MessagePumpMojo::Create());
- CountingMojoHandler handler;
- MessagePipe handles;
- Handle closed_handle = handles.handle0.get();
- handles.handle0.reset();
- MessagePumpMojo::current()->AddHandler(
- &handler, closed_handle, MOJO_HANDLE_SIGNAL_READABLE, base::TimeTicks());
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- MessagePumpMojo::current()->RemoveHandler(closed_handle);
- EXPECT_EQ(0, handler.error_count());
- EXPECT_EQ(0, handler.success_count());
-}
-
-TEST(MessagePumpMojo, CloseAfterAdding) {
- base::MessageLoop message_loop(MessagePumpMojo::Create());
- CountingMojoHandler handler;
- MessagePipe handles;
- MessagePumpMojo::current()->AddHandler(&handler, handles.handle0.get(),
- MOJO_HANDLE_SIGNAL_READABLE,
- base::TimeTicks());
- handles.handle0.reset();
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- EXPECT_EQ(1, handler.error_count());
- EXPECT_EQ(0, handler.success_count());
-}
-
-} // namespace test
-} // namespace common
-} // namespace mojo
diff --git a/mojo/message_pump/mojo_message_pump_export.h b/mojo/message_pump/mojo_message_pump_export.h
deleted file mode 100644
index f8c1864..0000000
--- a/mojo/message_pump/mojo_message_pump_export.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_MESSAGE_PUMP_MOJO_MESSAGE_PUMP_EXPORT_H_
-#define MOJO_MESSAGE_PUMP_MOJO_MESSAGE_PUMP_EXPORT_H_
-
-#if defined(COMPONENT_BUILD)
-
-#if defined(WIN32)
-
-#if defined(MOJO_MESSAGE_PUMP_IMPLEMENTATION)
-#define MOJO_MESSAGE_PUMP_EXPORT __declspec(dllexport)
-#else
-#define MOJO_MESSAGE_PUMP_EXPORT __declspec(dllimport)
-#endif
-
-#else // !defined(WIN32)
-
-#if defined(MOJO_MESSAGE_PUMP_IMPLEMENTATION)
-#define MOJO_MESSAGE_PUMP_EXPORT __attribute__((visibility("default")))
-#else
-#define MOJO_MESSAGE_PUMP_EXPORT
-#endif
-
-#endif // defined(WIN32)
-
-#else // !defined(COMPONENT_BUILD)
-#define MOJO_MESSAGE_PUMP_EXPORT
-#endif
-
-#endif // MOJO_MESSAGE_PUMP_MOJO_MESSAGE_PUMP_EXPORT_H_
diff --git a/mojo/message_pump/time_helper.cc b/mojo/message_pump/time_helper.cc
deleted file mode 100644
index ffd667e..0000000
--- a/mojo/message_pump/time_helper.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/message_pump/time_helper.h"
-
-#include "base/time/tick_clock.h"
-
-namespace mojo {
-namespace common {
-
-namespace {
-
-base::TickClock* tick_clock = NULL;
-
-} // namespace
-
-namespace test {
-
-void SetTickClockForTest(base::TickClock* clock) {
- tick_clock = clock;
-}
-} // namespace test
-
-namespace internal {
-
-base::TimeTicks NowTicks() {
- return tick_clock ? tick_clock->NowTicks() : base::TimeTicks::Now();
-}
-
-} // namespace internal
-} // namespace common
-} // namespace mojo
diff --git a/mojo/message_pump/time_helper.h b/mojo/message_pump/time_helper.h
deleted file mode 100644
index 6079000..0000000
--- a/mojo/message_pump/time_helper.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_MESSAGE_PUMP_TIME_HELPER_H_
-#define MOJO_MESSAGE_PUMP_TIME_HELPER_H_
-
-#include "base/time/time.h"
-#include "mojo/message_pump/mojo_message_pump_export.h"
-
-namespace base {
-class TickClock;
-}
-
-namespace mojo {
-namespace common {
-namespace test {
-
-// Sets the TickClock used for getting TimeTicks::Now(). This is currently used
-// by both HandleWatcher and MessagePumpMojo.
-MOJO_MESSAGE_PUMP_EXPORT void SetTickClockForTest(base::TickClock* clock);
-
-} // namespace test
-
-namespace internal {
-
-// Returns now. Used internally; generally not useful.
-MOJO_MESSAGE_PUMP_EXPORT base::TimeTicks NowTicks();
-
-} // namespace internal
-} // namespace common
-} // namespace mojo
-
-#endif // MOJO_MESSAGE_PUMP_TIME_HELPER_H_
diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp
deleted file mode 100644
index 1ef0c4d..0000000
--- a/mojo/mojo.gyp
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'targets': [
- {
- # GN version: //mojo
- 'target_name': 'mojo',
- 'type': 'none',
- 'dependencies': [
- 'mojo_base.gyp:mojo_base',
- 'mojo_edk_tests.gyp:mojo_edk_tests',
- 'mojo_public.gyp:mojo_public',
- ],
- },
- ]
-}
diff --git a/mojo/mojo_base.gyp b/mojo/mojo_base.gyp
deleted file mode 100644
index a067353..0000000
--- a/mojo/mojo_base.gyp
+++ /dev/null
@@ -1,192 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Essential components (and their tests) that are needed to build
-# Chrome should be here. Other components that are useful only in
-# Mojo land like mojo_shell should be in mojo.gyp.
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'targets': [
- {
- 'target_name': 'mojo_base',
- 'type': 'none',
- 'dependencies': [
- # NOTE: If adding a new dependency here, please consider whether it
- # should also be added to the list of Mojo-related dependencies of
- # build/all.gyp:All on iOS, as All cannot depend on the mojo_base
- # target on iOS due to the presence of the js targets, which cause v8
- # to be built.
- 'mojo_common_lib',
- 'mojo_common_unittests',
- ],
- 'conditions': [
- ['OS == "android"', {
- 'dependencies': [
- 'mojo_public.gyp:mojo_bindings_java',
- 'mojo_public.gyp:mojo_public_java',
- ],
- }],
- ]
- },
- {
- 'target_name': 'mojo_none',
- 'type': 'none',
- },
- {
- # GN version: //mojo/common
- 'target_name': 'mojo_common_lib',
- 'type': '<(component)',
- 'defines': [
- 'MOJO_COMMON_IMPLEMENTATION',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../mojo/mojo_public.gyp:mojo_public_system',
- ],
- 'sources': [
- 'common/common_type_converters.cc',
- 'common/common_type_converters.h',
- 'common/data_pipe_file_utils.cc',
- 'common/data_pipe_utils.cc',
- 'common/data_pipe_utils.h',
- ],
- },
- {
- # GN version: //mojo/common:common_custom_types
- 'target_name': 'mojo_common_custom_types_mojom',
- 'type': 'none',
- 'variables': {
- 'mojom_files': [
- 'common/common_custom_types.mojom',
- ],
- 'mojom_typemaps': [
- 'common/common_custom_types.typemap',
- ],
- },
- 'dependencies': [
- '../ipc/ipc.gyp:ipc',
- ],
- 'includes': [ 'mojom_bindings_generator_explicit.gypi' ],
- },
- {
- # GN version: //mojo/common:test_common_custom_types
- 'target_name': 'mojo_test_common_custom_types',
- 'type': 'static_library',
- 'variables': {
- 'mojom_typemaps': [
- 'common/common_custom_types.typemap',
- ],
- },
- 'sources': [
- 'common/test_common_custom_types.mojom',
- ],
- 'dependencies': [
- 'mojo_common_custom_types_mojom',
- ],
- 'includes': [ 'mojom_bindings_generator.gypi' ],
- },
- {
- # GN version: //mojo/common:mojo_common_unittests
- 'target_name': 'mojo_common_unittests',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- '../base/base.gyp:base_message_loop_tests',
- '../testing/gtest.gyp:gtest',
- '../url/url.gyp:url_lib',
- 'mojo_common_custom_types_mojom',
- 'mojo_common_lib',
- 'mojo_test_common_custom_types',
- 'mojo_edk.gyp:mojo_system_impl',
- 'mojo_edk.gyp:mojo_common_test_support',
- 'mojo_edk.gyp:mojo_run_all_unittests',
- 'mojo_public.gyp:mojo_cpp_bindings',
- 'mojo_public.gyp:mojo_public_test_utils',
- ],
- 'sources': [
- 'common/common_custom_types_unittest.cc',
- 'common/common_type_converters_unittest.cc',
- ],
- },
- ],
- 'conditions': [
- ['OS=="android"', {
- 'targets': [
- {
- 'target_name': 'mojo_jni_headers',
- 'type': 'none',
- 'dependencies': [
- 'mojo_java_set_jni_headers',
- ],
- 'sources': [
- 'android/javatests/src/org/chromium/mojo/MojoTestCase.java',
- 'android/javatests/src/org/chromium/mojo/bindings/ValidationTestUtil.java',
- 'android/system/src/org/chromium/mojo/system/impl/CoreImpl.java',
- ],
- 'variables': {
- 'jni_gen_package': 'mojo',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- 'target_name': 'libmojo_system_java',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- 'mojo_common_lib',
- 'mojo_edk.gyp:mojo_system_impl',
- 'mojo_jni_headers',
- 'mojo_public.gyp:mojo_message_pump_lib',
- ],
- 'sources': [
- 'android/system/core_impl.cc',
- 'android/system/core_impl.h',
- ],
- },
- {
- 'target_name': 'mojo_java_set_jni_headers',
- 'type': 'none',
- 'variables': {
- 'jni_gen_package': 'mojo',
- 'input_java_class': 'java/util/HashSet.class',
- },
- 'includes': [ '../build/jar_file_jni_generator.gypi' ],
- },
- {
- 'target_name': 'mojo_system_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base_java',
- 'libmojo_system_java',
- 'mojo_public.gyp:mojo_public_java',
- ],
- 'variables': {
- 'java_in_dir': '<(DEPTH)/mojo/android/system',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- ],
- }],
- ['test_isolation_mode != "noop"', {
- 'targets': [
- {
- 'target_name': 'mojo_common_unittests_run',
- 'type': 'none',
- 'dependencies': [
- 'mojo_common_unittests',
- ],
- 'includes': [
- '../build/isolate.gypi',
- ],
- 'sources': [
- 'mojo_common_unittests.isolate',
- ],
- },
- ],
- }],
- ]
-}
diff --git a/mojo/mojo_common_unittests.isolate b/mojo/mojo_common_unittests.isolate
deleted file mode 100644
index a72311c..0000000
--- a/mojo/mojo_common_unittests.isolate
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-{
- 'includes': [
- '../base/base.isolate',
- ],
- 'conditions': [
- ['OS=="win" or OS=="mac" or OS=="linux"', {
- 'variables': {
- 'command': [
- '../testing/test_env.py',
- '<(PRODUCT_DIR)/mojo_common_unittests<(EXECUTABLE_SUFFIX)',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- ],
- 'files': [
- '../testing/test_env.py',
- ],
- },
- }],
- ],
-}
diff --git a/mojo/mojo_edk.gyp b/mojo/mojo_edk.gyp
deleted file mode 100644
index 5541839..0000000
--- a/mojo/mojo_edk.gyp
+++ /dev/null
@@ -1,233 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'includes': [
- 'mojo_edk.gypi',
- ],
- 'target_defaults' : {
- 'include_dirs': [
- '..',
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '..',
- ],
- },
- },
- 'targets': [
- {
- # GN version: //mojo/edk/system/ports
- 'target_name': 'mojo_system_ports',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../crypto/crypto.gyp:crypto',
- ],
- 'sources': [
- '<@(mojo_edk_ports_sources)',
- ],
- },
- {
- # GN version: //mojo/edk/system
- 'target_name': 'mojo_system_impl',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../crypto/crypto.gyp:crypto',
- 'mojo_public.gyp:mojo_public_system',
- 'mojo_system_ports',
- ],
- 'defines': [
- 'MOJO_SYSTEM_IMPL_IMPLEMENTATION',
- ],
- 'sources': [
- '<@(mojo_edk_system_impl_sources)',
- '<@(mojo_edk_system_impl_non_nacl_sources)',
- ],
- 'conditions': [
- ['OS=="android"', {
- 'dependencies': [
- '../third_party/ashmem/ashmem.gyp:ashmem',
- ],
- }],
- ['OS=="android" or chromeos==1', {
- 'defines': [
- 'MOJO_EDK_LEGACY_PROTOCOL',
- ],
- }],
- ['OS=="win"', {
- # Structure was padded due to __declspec(align()), which is
- # uninteresting.
- 'msvs_disabled_warnings': [ 4324 ],
- }],
- ['OS=="mac" and OS!="ios"', {
- 'sources': [
- 'edk/system/mach_port_relay.cc',
- 'edk/system/mach_port_relay.h',
- ],
- }],
- ],
- },
- {
- # GN version: //mojo/edk/js
- 'target_name': 'mojo_js_lib',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../gin/gin.gyp:gin',
- '../v8/src/v8.gyp:v8',
- ],
- 'export_dependent_settings': [
- '../base/base.gyp:base',
- '../gin/gin.gyp:gin',
- ],
- 'sources': [
- # Sources list duplicated in GN build.
- 'edk/js/core.cc',
- 'edk/js/core.h',
- 'edk/js/drain_data.cc',
- 'edk/js/drain_data.h',
- 'edk/js/handle.cc',
- 'edk/js/handle.h',
- 'edk/js/handle_close_observer.h',
- 'edk/js/mojo_runner_delegate.cc',
- 'edk/js/mojo_runner_delegate.h',
- 'edk/js/support.cc',
- 'edk/js/support.h',
- 'edk/js/threading.cc',
- 'edk/js/threading.h',
- 'edk/js/waiting_callback.cc',
- 'edk/js/waiting_callback.h',
- ],
- },
- {
- # GN version: //mojo/edk/test:test_support_impl
- 'target_name': 'mojo_test_support_impl',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'sources': [
- 'edk/test/test_support_impl.cc',
- 'edk/test/test_support_impl.h',
- ],
- },
- {
- # GN version: //mojo/edk/test:test_support
- 'target_name': 'mojo_common_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- '../testing/gtest.gyp:gtest',
- 'mojo_system_impl',
- ],
- 'sources': [
- 'edk/test/mojo_test_base.cc',
- 'edk/test/mojo_test_base.h',
- 'edk/test/multiprocess_test_helper.cc',
- 'edk/test/multiprocess_test_helper.h',
- 'edk/test/scoped_ipc_support.cc',
- 'edk/test/scoped_ipc_support.h',
- 'edk/test/test_utils.h',
- 'edk/test/test_utils_posix.cc',
- 'edk/test/test_utils_win.cc',
- ],
- 'conditions': [
- ['OS=="ios"', {
- 'sources!': [
- 'edk/test/multiprocess_test_helper.cc',
- ],
- }],
- ],
- },
- {
- # GN version: //mojo/edk/test:run_all_unittests
- 'target_name': 'mojo_run_all_unittests',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- '../testing/gtest.gyp:gtest',
- 'mojo_common_test_support',
- 'mojo_public.gyp:mojo_public_test_support',
- 'mojo_system_impl',
- 'mojo_test_support_impl',
- ],
- 'sources': [
- 'edk/test/run_all_unittests.cc',
- ],
- },
- {
- # GN version: //mojo/edk/test:run_all_perftests
- 'target_name': 'mojo_run_all_perftests',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- '../testing/gtest.gyp:gtest',
- 'mojo_common_test_support',
- 'mojo_public.gyp:mojo_public_test_support',
- 'mojo_system_impl',
- 'mojo_test_support_impl',
- ],
- 'sources': [
- 'edk/test/run_all_perftests.cc',
- ],
- },
- ],
- 'conditions': [
- ['OS == "win" and target_arch=="ia32"', {
- 'targets': [
- {
- # GN version: //mojo/edk/system/ports
- 'target_name': 'mojo_system_ports_win64',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base_win64',
- '../crypto/crypto.gyp:crypto_nacl_win64',
- ],
- 'sources': [
- '<@(mojo_edk_ports_sources)',
- ],
- 'configurations': {
- 'Common_Base': {
- 'msvs_target_platform': 'x64',
- },
- },
- },
- {
- # GN version: //mojo/edk/system
- 'target_name': 'mojo_system_impl_win64',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base_win64',
- '../crypto/crypto.gyp:crypto_nacl_win64',
- 'mojo_public.gyp:mojo_public_system_win64',
- 'mojo_system_ports_win64',
- ],
- 'defines': [
- 'MOJO_SYSTEM_IMPL_IMPLEMENTATION',
- ],
- 'sources': [
- '<@(mojo_edk_system_impl_sources)',
- '<@(mojo_edk_system_impl_non_nacl_sources)',
- ],
- # Structure was padded due to __declspec(align()), which is
- # uninteresting.
- 'msvs_disabled_warnings': [ 4324 ],
- 'configurations': {
- 'Common_Base': {
- 'msvs_target_platform': 'x64',
- },
- },
- },
- ],
- }],
- ]
-}
diff --git a/mojo/mojo_edk_tests.gyp b/mojo/mojo_edk_tests.gyp
deleted file mode 100644
index e192462..0000000
--- a/mojo/mojo_edk_tests.gyp
+++ /dev/null
@@ -1,397 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'targets': [
- {
- 'target_name': 'mojo_edk_tests',
- 'type': 'none',
- 'dependencies': [
- # NOTE: If adding a new dependency here, please consider whether it
- # should also be added to the list of Mojo-related dependencies of
- # build/all.gyp:All on iOS, as All cannot depend on the mojo_base
- # target on iOS due to the presence of the js targets, which cause v8
- # to be built.
- 'mojo_message_pipe_perftests',
- 'mojo_public_bindings_perftests',
- 'mojo_public_bindings_unittests',
- 'mojo_public_system_perftests',
- 'mojo_public_system_unittests',
- 'mojo_system_unittests',
- 'mojo_js_unittests',
- 'mojo_js_integration_tests',
- ],
- },
- {
- # GN version: //mojo/edk/test:mojo_public_bindings_unittests
- 'target_name': 'mojo_public_bindings_unittests',
- 'type': 'executable',
- 'dependencies': [
- '../testing/gtest.gyp:gtest',
- 'mojo_edk.gyp:mojo_run_all_unittests',
- 'mojo_public.gyp:mojo_cpp_bindings',
- 'mojo_public.gyp:mojo_public_bindings_test_utils',
- 'mojo_public.gyp:mojo_public_test_utils',
- 'mojo_public_tests.gyp:mojo_public_test_associated_interfaces',
- 'mojo_public_tests.gyp:mojo_public_test_interfaces',
- 'mojo_public_tests.gyp:mojo_public_test_interfaces_blink',
- 'mojo_public_tests.gyp:mojo_public_test_interfaces_struct_traits',
- ],
- 'variables': {
- 'clang_warning_flags_unset': [ '-Wglobal-constructors' ],
- },
- 'sources': [
- 'public/cpp/bindings/tests/array_common_test.h',
- 'public/cpp/bindings/tests/array_unittest.cc',
- 'public/cpp/bindings/tests/associated_interface_unittest.cc',
- 'public/cpp/bindings/tests/bind_task_runner_unittest.cc',
- 'public/cpp/bindings/tests/binding_callback_unittest.cc',
- 'public/cpp/bindings/tests/binding_unittest.cc',
- 'public/cpp/bindings/tests/buffer_unittest.cc',
- 'public/cpp/bindings/tests/connector_unittest.cc',
- 'public/cpp/bindings/tests/constant_unittest.cc',
- 'public/cpp/bindings/tests/container_test_util.cc',
- 'public/cpp/bindings/tests/container_test_util.h',
- 'public/cpp/bindings/tests/equals_unittest.cc',
- 'public/cpp/bindings/tests/handle_passing_unittest.cc',
- 'public/cpp/bindings/tests/interface_ptr_unittest.cc',
- 'public/cpp/bindings/tests/map_common_test.h',
- 'public/cpp/bindings/tests/map_unittest.cc',
- 'public/cpp/bindings/tests/message_queue.cc',
- 'public/cpp/bindings/tests/message_queue.h',
- 'public/cpp/bindings/tests/multiplex_router_unittest.cc',
- 'public/cpp/bindings/tests/pickle_unittest.cc',
- 'public/cpp/bindings/tests/pickled_types_blink.cc',
- 'public/cpp/bindings/tests/pickled_types_blink.h',
- 'public/cpp/bindings/tests/pickled_types_chromium.cc',
- 'public/cpp/bindings/tests/pickled_types_chromium.h',
- 'public/cpp/bindings/tests/rect_blink.h',
- 'public/cpp/bindings/tests/rect_blink_traits.h',
- 'public/cpp/bindings/tests/rect_chromium.h',
- 'public/cpp/bindings/tests/rect_chromium_traits.h',
- 'public/cpp/bindings/tests/request_response_unittest.cc',
- 'public/cpp/bindings/tests/router_test_util.cc',
- 'public/cpp/bindings/tests/router_test_util.h',
- 'public/cpp/bindings/tests/router_unittest.cc',
- 'public/cpp/bindings/tests/sample_service_unittest.cc',
- 'public/cpp/bindings/tests/serialization_warning_unittest.cc',
- 'public/cpp/bindings/tests/stl_converters_unittest.cc',
- 'public/cpp/bindings/tests/string_unittest.cc',
- 'public/cpp/bindings/tests/struct_traits_unittest.cc',
- 'public/cpp/bindings/tests/struct_unittest.cc',
- 'public/cpp/bindings/tests/struct_with_traits_impl.cc',
- 'public/cpp/bindings/tests/struct_with_traits_impl.h',
- 'public/cpp/bindings/tests/struct_with_traits_impl_traits.cc',
- 'public/cpp/bindings/tests/struct_with_traits_impl_traits.h',
- 'public/cpp/bindings/tests/sync_method_unittest.cc',
- 'public/cpp/bindings/tests/type_conversion_unittest.cc',
- 'public/cpp/bindings/tests/union_unittest.cc',
- 'public/cpp/bindings/tests/validation_context_unittest.cc',
- 'public/cpp/bindings/tests/validation_unittest.cc',
- 'public/cpp/bindings/tests/variant_test_util.h',
- ],
- 'conditions': [
- # TODO(yzshen): Blink-flavor bindings tests should be moved into
- # mojo_public_bindings_for_blink_tests (which should eventually be moved
- # into blink).
- ['OS=="ios"', {
- 'dependencies!': [
- 'mojo_public.gyp:mojo_public_test_interfaces_blink',
- ],
- 'sources!': [
- 'public/cpp/bindings/tests/pickle_unittest.cc',
- 'public/cpp/bindings/tests/pickled_types_blink.cc',
- 'public/cpp/bindings/tests/pickled_types_blink.h',
- 'public/cpp/bindings/tests/pickled_types_chromium.cc',
- 'public/cpp/bindings/tests/pickled_types_chromium.h',
- 'public/cpp/bindings/tests/rect_blink.h',
- 'public/cpp/bindings/tests/rect_blink_traits.h',
- 'public/cpp/bindings/tests/struct_traits_unittest.cc',
- ],
- }],
- ],
- },
- {
- # GN version: //mojo/public/cpp/bindings/tests:for_blink_tests
- 'target_name': 'mojo_public_bindings_for_blink_tests',
- 'type': 'static_library',
- 'dependencies': [
- '../testing/gtest.gyp:gtest',
- 'mojo_public.gyp:mojo_cpp_bindings',
- 'mojo_public_tests.gyp:mojo_public_test_interfaces',
- 'mojo_public_tests.gyp:mojo_public_test_wtf_types',
- 'mojo_public_tests.gyp:mojo_public_test_wtf_types_blink',
- ],
- 'variables': {
- 'clang_warning_flags_unset': [ '-Wglobal-constructors' ],
- },
- 'sources': [
- 'public/cpp/bindings/tests/array_common_test.h',
- 'public/cpp/bindings/tests/container_test_util.cc',
- 'public/cpp/bindings/tests/container_test_util.h',
- 'public/cpp/bindings/tests/map_common_test.h',
- 'public/cpp/bindings/tests/variant_test_util.h',
- 'public/cpp/bindings/tests/wtf_array_unittest.cc',
- 'public/cpp/bindings/tests/wtf_map_unittest.cc',
- 'public/cpp/bindings/tests/wtf_types_unittest.cc',
- ],
- },
- {
- # GN version: //mojo/edk/test:mojo_public_bindings_perftests
- 'target_name': 'mojo_public_bindings_perftests',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:test_support_base',
- '../testing/gtest.gyp:gtest',
- 'mojo_base.gyp:mojo_common_lib',
- 'mojo_edk.gyp:mojo_run_all_perftests',
- 'mojo_public.gyp:mojo_cpp_bindings',
- 'mojo_public.gyp:mojo_public_bindings_test_utils',
- 'mojo_public.gyp:mojo_public_test_utils',
- 'mojo_public_tests.gyp:mojo_public_test_interfaces',
- ],
- 'sources': [
- 'public/cpp/bindings/tests/bindings_perftest.cc',
- 'public/cpp/bindings/tests/e2e_perftest.cc',
- ],
- },
- {
- # GN version: //mojo/public/cpp/system/tests:mojo_public_system_unittests
- # and //mojo/public/c/system/tests
- 'target_name': 'mojo_public_system_unittests',
- 'type': 'executable',
- 'dependencies': [
- '../testing/gtest.gyp:gtest',
- 'mojo_edk.gyp:mojo_run_all_unittests',
- 'mojo_public.gyp:mojo_cpp_system',
- 'mojo_public.gyp:mojo_public_test_utils',
- ],
- 'sources': [
- '<(DEPTH)/mojo/public/c/system/tests/core_unittest.cc',
- '<(DEPTH)/mojo/public/c/system/tests/core_unittest_pure_c.c',
- '<(DEPTH)/mojo/public/c/system/tests/macros_unittest.cc',
- '<(DEPTH)/mojo/public/cpp/system/tests/core_unittest.cc',
- '<(DEPTH)/mojo/public/cpp/system/tests/watcher_unittest.cc',
- ],
- },
- {
- # GN version: //mojo/edk/test:mojo_public_system_perftests
- 'target_name': 'mojo_public_system_perftests',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- '../testing/gtest.gyp:gtest',
- 'mojo_edk.gyp:mojo_run_all_perftests',
- 'mojo_public.gyp:mojo_public_system',
- 'mojo_public.gyp:mojo_public_test_utils',
- ],
- 'sources': [
- 'public/c/system/tests/core_perftest.cc',
- ],
- },
- {
- # GN version: //mojo/edk/system:mojo_system_unittests
- 'target_name': 'mojo_system_unittests',
- 'type': '<(gtest_target_type)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../testing/gtest.gyp:gtest',
- 'mojo_edk.gyp:mojo_common_test_support',
- 'mojo_edk.gyp:mojo_run_all_unittests',
- 'mojo_edk.gyp:mojo_system_impl',
- 'mojo_edk.gyp:mojo_system_ports',
- 'mojo_public.gyp:mojo_public_system',
- ],
- 'sources': [
- 'edk/embedder/embedder_unittest.cc',
- 'edk/embedder/platform_channel_pair_posix_unittest.cc',
- 'edk/embedder/platform_shared_buffer_unittest.cc',
- 'edk/system/awakable_list_unittest.cc',
- 'edk/system/core_test_base.cc',
- 'edk/system/core_test_base.h',
- 'edk/system/core_unittest.cc',
- 'edk/system/message_pipe_unittest.cc',
- 'edk/system/multiprocess_message_pipe_unittest.cc',
- 'edk/system/options_validation_unittest.cc',
- 'edk/system/platform_handle_dispatcher_unittest.cc',
- 'edk/system/platform_wrapper_unittest.cc',
- 'edk/system/ports/ports_unittest.cc',
- 'edk/system/shared_buffer_dispatcher_unittest.cc',
- 'edk/system/shared_buffer_unittest.cc',
- 'edk/system/test_utils.cc',
- 'edk/system/test_utils.h',
- 'edk/system/wait_set_dispatcher_unittest.cc',
- 'edk/system/waiter_test_utils.cc',
- 'edk/system/waiter_test_utils.h',
- 'edk/system/waiter_unittest.cc',
- 'edk/system/watch_unittest.cc',
- ],
- 'conditions': [
- ['OS=="ios"', {
- 'sources!': [
- 'edk/system/multiprocess_message_pipe_unittest.cc',
- ],
- }],
- ['OS == "android"', {
- 'dependencies': [
- '../testing/android/native_test.gyp:native_test_native_code',
- ],
- }],
- ],
- },
- {
- # GN version: //mojo/edk/system:mojo_message_pipe_perftests
- 'target_name': 'mojo_message_pipe_perftests',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- '../testing/gtest.gyp:gtest',
- 'mojo_edk.gyp:mojo_common_test_support',
- 'mojo_edk.gyp:mojo_run_all_perftests',
- 'mojo_edk.gyp:mojo_system_impl',
- 'mojo_public.gyp:mojo_public_system',
- ],
- 'sources': [
- 'edk/system/message_pipe_perftest.cc',
- 'edk/system/test_utils.cc',
- 'edk/system/test_utils.h',
- ],
- },
- # TODO(yzshen): fix the following two targets.
- {
- # GN version: //mojo/edk/js/test:js_unittests
- 'target_name': 'mojo_js_unittests',
- 'type': 'executable',
- 'dependencies': [
- '../gin/gin.gyp:gin_test',
- 'mojo_edk.gyp:mojo_common_test_support',
- 'mojo_edk.gyp:mojo_run_all_unittests',
- 'mojo_edk.gyp:mojo_js_lib',
- 'mojo_public_tests.gyp:mojo_public_test_interfaces',
- ],
- 'sources': [
- 'edk/js/handle_unittest.cc',
- 'edk/js/test/run_js_tests.cc',
- ],
- },
- {
- # GN version: //mojo/edk/js/test:js_integration_tests
- 'target_name': 'mojo_js_integration_tests',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- '../gin/gin.gyp:gin_test',
- 'mojo_base.gyp:mojo_common_lib',
- 'mojo_edk.gyp:mojo_js_lib',
- 'mojo_edk.gyp:mojo_run_all_unittests',
- 'mojo_js_to_cpp_bindings',
- 'mojo_public_tests.gyp:mojo_public_test_interfaces',
- ],
- 'sources': [
- 'edk/js/test/run_js_integration_tests.cc',
- 'edk/js/tests/js_to_cpp_tests.cc',
- ],
- },
- {
- 'target_name': 'mojo_js_to_cpp_bindings',
- 'type': 'none',
- 'variables': {
- 'mojom_files': [
- 'edk/js/tests/js_to_cpp.mojom',
- ],
- },
- 'includes': [ 'mojom_bindings_generator_explicit.gypi' ],
- },
- ],
- 'conditions': [
- ['test_isolation_mode != "noop"', {
- 'targets': [
- {
- 'target_name': 'mojo_public_bindings_unittests_run',
- 'type': 'none',
- 'dependencies': [
- 'mojo_public_bindings_unittests',
- ],
- 'includes': [
- '../build/isolate.gypi',
- ],
- 'sources': [
- 'mojo_public_bindings_unittests.isolate',
- ],
- },
- {
- 'target_name': 'mojo_public_system_unittests_run',
- 'type': 'none',
- 'dependencies': [
- 'mojo_public_system_unittests',
- ],
- 'includes': [
- '../build/isolate.gypi',
- ],
- 'sources': [
- 'mojo_public_system_unittests.isolate',
- ],
- },
- {
- 'target_name': 'mojo_js_unittests_run',
- 'type': 'none',
- 'dependencies': [
- 'mojo_js_unittests',
- ],
- 'includes': [
- '../build/isolate.gypi',
- ],
- 'sources': [
- 'mojo_js_unittests.isolate',
- ],
- },
- {
- 'target_name': 'mojo_js_integration_tests_run',
- 'type': 'none',
- 'dependencies': [
- 'mojo_js_integration_tests',
- ],
- 'includes': [
- '../build/isolate.gypi',
- ],
- 'sources': [
- 'mojo_js_integration_tests.isolate',
- ],
- },
- {
- 'target_name': 'mojo_system_unittests_run',
- 'type': 'none',
- 'dependencies': [
- 'mojo_system_unittests',
- ],
- 'includes': [
- '../build/isolate.gypi',
- ],
- 'sources': [
- 'mojo_system_unittests.isolate',
- ],
- },
- ],
- }],
- ['OS == "android"', {
- 'targets': [
- {
- 'target_name': 'mojo_system_unittests_apk',
- 'type': 'none',
- 'dependencies': [
- 'mojo_system_unittests',
- ],
- 'variables': {
- 'test_suite_name': 'mojo_system_unittests',
- },
- 'includes': [ '../build/apk_test.gypi' ],
- },
- ],
- }],
- ],
-}
diff --git a/mojo/mojo_js_unittests.isolate b/mojo/mojo_js_unittests.isolate
deleted file mode 100644
index 81bae0b..0000000
--- a/mojo/mojo_js_unittests.isolate
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-{
- 'includes': [
- '../base/base.isolate',
- '../gin/v8.isolate',
- '../third_party/icu/icu.isolate',
- ],
- 'conditions': [
- ['OS=="win" or OS=="mac" or OS=="linux"', {
- 'variables': {
- 'command': [
- '../testing/test_env.py',
- '<(PRODUCT_DIR)/mojo_js_unittests<(EXECUTABLE_SUFFIX)',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- ],
- 'files': [
- '../gin/test/expect.js',
- '../testing/test_env.py',
- 'public/interfaces/bindings/tests/data/validation/',
- 'public/js/',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/math_calculator.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/no_module.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/ping_service.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/rect.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/regression_tests.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/sample_factory.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/sample_import.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/sample_import2.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/sample_service.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/scoping.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/serialization_test_structs.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/test_constants.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/test_native_types.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/test_structs.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/test_sync_methods.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/test_unions.mojom.js',
- '<(PRODUCT_DIR)/gen/mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom.js',
- ],
- },
- }],
- ],
-}
diff --git a/mojo/mojo_public.gyp b/mojo/mojo_public.gyp
deleted file mode 100644
index 005e012..0000000
--- a/mojo/mojo_public.gyp
+++ /dev/null
@@ -1,310 +0,0 @@
-# Copyright 2014 The Chroium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'includes': [
- 'mojo_public.gypi',
- ],
- 'variables': {
- 'chromium_code': 1,
- },
- 'target_defaults' : {
- 'include_dirs': [
- '..',
- ],
- },
- 'targets': [
- {
- 'target_name': 'mojo_public',
- 'type': 'none',
- 'dependencies': [
- 'mojo_js_bindings',
- 'mojo_public_system',
- ],
- },
- {
- # GN version: //mojo/public/c/system
- 'target_name': 'mojo_public_system',
- 'type': '<(component)',
- 'sources': [
- '<@(mojo_public_system_sources)',
- ],
- 'defines': [
- 'MOJO_SYSTEM_IMPLEMENTATION',
- ],
- },
- {
- # GN version: //mojo/public/cpp/system
- 'target_name': 'mojo_cpp_system',
- 'type': 'static_library',
- 'sources': [
- '<@(mojo_cpp_system_sources)',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- 'mojo_public_system',
- ],
- },
- {
- # GN version: //mojo/public/cpp/bindings
- 'target_name': 'mojo_cpp_bindings',
- 'type': 'static_library',
- 'include_dirs': [
- '..'
- ],
- 'sources': [
- '<@(mojo_cpp_bindings_sources)',
-
- # This comes from the mojo_interface_bindings_cpp_sources dependency.
- '>@(mojom_generated_sources)',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- 'mojo_cpp_system',
- 'mojo_interface_bindings_cpp_sources',
- ],
- },
- {
- # GN version: //mojo/message_pump
- 'target_name': 'mojo_message_pump_lib',
- 'type': '<(component)',
- 'defines': [
- 'MOJO_MESSAGE_PUMP_IMPLEMENTATION',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- 'mojo_cpp_system',
- ],
- 'sources': [
- 'message_pump/handle_watcher.cc',
- 'message_pump/handle_watcher.h',
- 'message_pump/message_pump_mojo.cc',
- 'message_pump/message_pump_mojo.h',
- 'message_pump/message_pump_mojo_handler.h',
- 'message_pump/time_helper.cc',
- 'message_pump/time_helper.h',
- ],
- },
- {
- # GN version: //mojo/public/js
- 'target_name': 'mojo_js_bindings',
- 'type': 'static_library',
- 'include_dirs': [
- '..'
- ],
- 'sources': [
- 'public/js/constants.cc',
- 'public/js/constants.h',
- ],
- },
- {
- 'target_name': 'mojo_interface_bindings_mojom',
- 'type': 'none',
- 'variables': {
- 'require_interface_bindings': 0,
- 'mojom_files': [
- 'public/interfaces/bindings/interface_control_messages.mojom',
- 'public/interfaces/bindings/pipe_control_messages.mojom',
- ],
- },
- 'includes': [ 'mojom_bindings_generator_explicit.gypi' ],
- },
- {
- 'target_name': 'mojo_interface_bindings_cpp_sources',
- 'type': 'none',
- 'dependencies': [
- 'mojo_interface_bindings_mojom',
- ],
- },
- {
- # This target can be used to introduce a dependency on interface bindings
- # generation without introducing any side-effects in the dependent
- # target's configuration.
- 'target_name': 'mojo_interface_bindings_generation',
- 'type': 'none',
- 'dependencies': [
- 'mojo_interface_bindings_cpp_sources',
- ],
- },
- {
- # GN version: //mojo/public/c/test_support
- 'target_name': 'mojo_public_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '..',
- ],
- },
- 'sources': [
- 'public/c/test_support/test_support.h',
- # TODO(vtl): Convert this to thunks http://crbug.com/386799
- 'public/tests/test_support_private.cc',
- 'public/tests/test_support_private.h',
- ],
- },
- {
- # GN version: //mojo/public/cpp/test_support:test_utils
- 'target_name': 'mojo_public_test_utils',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../testing/gtest.gyp:gtest',
- 'mojo_public_test_support',
- ],
- 'sources': [
- 'public/cpp/test_support/lib/test_support.cc',
- 'public/cpp/test_support/lib/test_utils.cc',
- 'public/cpp/test_support/test_utils.h',
- ],
- },
- {
- # GN version: //mojo/public/cpp/bindings/tests:mojo_public_bindings_test_utils
- 'target_name': 'mojo_public_bindings_test_utils',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'sources': [
- 'public/cpp/bindings/tests/validation_test_input_parser.cc',
- 'public/cpp/bindings/tests/validation_test_input_parser.h',
- ],
- },
- ],
- 'conditions': [
- ['OS == "android"', {
- 'targets': [
- {
- # GN version: //mojo/public/java:system
- 'target_name': 'mojo_public_java',
- 'type': 'none',
- 'variables': {
- 'chromium_code': 0,
- 'java_in_dir': 'public/java/system',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- 'target_name': 'mojo_interface_bindings_java_sources',
- 'type': 'none',
- 'dependencies': [
- 'mojo_interface_bindings_mojom',
- ],
- },
- {
- # GN version: //mojo/public/java:bindings
- 'target_name': 'mojo_bindings_java',
- 'type': 'none',
- 'variables': {
- 'chromium_code': 0,
- 'java_in_dir': 'public/java/bindings',
- },
- 'dependencies': [
- 'mojo_interface_bindings_java_sources',
- 'mojo_public_java',
- '<(DEPTH)/base/base.gyp:base_java',
- ],
- 'includes': [ '../build/java.gypi' ],
- },
- ],
- }],
- ['OS != "ios"', {
- 'targets': [
- {
- # TODO(yzshen): crbug.com/617718 Consider moving this into blink.
- # GN version: //mojo/public/cpp/bindings:wtf_support
- 'target_name': 'mojo_cpp_bindings_wtf_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..'
- ],
- 'sources': [
- 'public/cpp/bindings/array_traits_wtf.h',
- 'public/cpp/bindings/array_traits_wtf_vector.h',
- 'public/cpp/bindings/lib/string_traits_wtf.cc',
- 'public/cpp/bindings/lib/wtf_clone_equals_util.h',
- 'public/cpp/bindings/lib/wtf_serialization.h',
- 'public/cpp/bindings/map_traits_wtf.h',
- 'public/cpp/bindings/map_traits_wtf_hash_map.h',
- 'public/cpp/bindings/string_traits_wtf.h',
- 'public/cpp/bindings/wtf_array.h',
- 'public/cpp/bindings/wtf_map.h',
- ],
- 'dependencies': [
- 'mojo_cpp_bindings',
- '../third_party/WebKit/Source/config.gyp:config',
- '../third_party/WebKit/Source/wtf/wtf.gyp:wtf',
- ],
- 'export_dependent_settings': [
- 'mojo_cpp_bindings',
- '../third_party/WebKit/Source/config.gyp:config',
- ],
- },
- ],
- }],
- ['OS == "win" and target_arch=="ia32"', {
- 'targets': [
- {
- # GN version: //mojo/public/c/system
- 'target_name': 'mojo_public_system_win64',
- 'type': '<(component)',
- 'sources': [
- '<@(mojo_public_system_sources)',
- ],
- 'defines': [
- 'MOJO_SYSTEM_IMPLEMENTATION',
- ],
- 'configurations': {
- 'Common_Base': {
- 'msvs_target_platform': 'x64',
- },
- },
- },
- {
- # GN version: //mojo/public/cpp/system
- 'target_name': 'mojo_cpp_system_win64',
- 'type': 'static_library',
- 'sources': [
- '<@(mojo_cpp_system_sources)',
- ],
- 'dependencies': [
- '../base/base.gyp:base_win64',
- 'mojo_public_system_win64',
- ],
- 'configurations': {
- 'Common_Base': {
- 'msvs_target_platform': 'x64',
- },
- },
- },
- {
- # GN version: //mojo/public/cpp/bindings
- 'target_name': 'mojo_cpp_bindings_win64',
- 'type': 'static_library',
- 'include_dirs': [
- '..'
- ],
- 'sources': [
- '<@(mojo_cpp_bindings_sources)',
-
- # This comes from the mojo_interface_bindings_cpp_sources dependency.
- '>@(mojom_generated_sources)',
- ],
- 'dependencies': [
- '../base/base.gyp:base_win64',
- 'mojo_cpp_system_win64',
- 'mojo_interface_bindings_cpp_sources',
- ],
- 'configurations': {
- 'Common_Base': {
- 'msvs_target_platform': 'x64',
- },
- },
- },
- ],
- }],
- ],
-}
diff --git a/mojo/mojo_public_bindings_unittests.isolate b/mojo/mojo_public_bindings_unittests.isolate
deleted file mode 100644
index 846bf78..0000000
--- a/mojo/mojo_public_bindings_unittests.isolate
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-{
- 'includes': [
- '../base/base.isolate',
- ],
- 'conditions': [
- ['OS=="win" or OS=="mac" or OS=="linux"', {
- 'variables': {
- 'command': [
- '../testing/test_env.py',
- '<(PRODUCT_DIR)/mojo_public_bindings_unittests<(EXECUTABLE_SUFFIX)',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- ],
- 'files': [
- '../testing/test_env.py',
- 'public/interfaces/bindings/tests/data/validation/',
- ],
- },
- }],
- ],
-}
diff --git a/mojo/mojo_public_system_unittests.isolate b/mojo/mojo_public_system_unittests.isolate
deleted file mode 100644
index f761bf7..0000000
--- a/mojo/mojo_public_system_unittests.isolate
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-{
- 'includes': [
- '../base/base.isolate',
- ],
- 'conditions': [
- ['OS=="win" or OS=="mac" or OS=="linux"', {
- 'variables': {
- 'command': [
- '../testing/test_env.py',
- '<(PRODUCT_DIR)/mojo_public_system_unittests<(EXECUTABLE_SUFFIX)',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- ],
- 'files': [
- '../testing/test_env.py',
- ],
- },
- }],
- ],
-}
diff --git a/mojo/mojom_bindings_generator.gypi b/mojo/mojom_bindings_generator.gypi
deleted file mode 100644
index c8c5f15..0000000
--- a/mojo/mojom_bindings_generator.gypi
+++ /dev/null
@@ -1,178 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'includes': [
- 'mojom_bindings_generator_variables.gypi',
- ],
- 'variables': {
- 'variables': {
- 'variables': {
- 'for_blink%': 'false',
- 'use_new_wrapper_types%': 'false',
- },
- 'for_blink%': '<(for_blink)',
- 'use_new_wrapper_types%': '<(use_new_wrapper_types)',
- 'conditions': [
- ['for_blink=="true"', {
- 'mojom_output_languages%': 'c++',
- 'mojom_variant%': 'blink',
- 'mojom_generator_wtf_arg%': [
- '--for_blink',
- ],
- 'wtf_dependencies%': [
- '<(DEPTH)/mojo/mojo_public.gyp:mojo_cpp_bindings_wtf_support',
- '<(DEPTH)/third_party/WebKit/Source/wtf/wtf.gyp:wtf',
- ],
- }, {
- 'mojom_output_languages%': 'c++,javascript,java',
- 'mojom_variant%': 'none',
- 'mojom_generator_wtf_arg%': [],
- 'wtf_dependencies%': [],
- }],
- ['use_new_wrapper_types=="true"', {
- 'mojom_generator_new_wrappers_arg%': [
- '--use_new_wrapper_types',
- ],
- }, {
- 'mojom_generator_new_wrappers_arg%': [],
- }],
- ],
- },
- 'for_blink%': '<(for_blink)',
- 'use_new_wrapper_types%': '<(use_new_wrapper_types)',
- 'mojom_variant%': '<(mojom_variant)',
- 'mojom_generator_wtf_arg%': '<(mojom_generator_wtf_arg)',
- 'mojom_generator_new_wrappers_arg%': '<(mojom_generator_new_wrappers_arg)',
- 'wtf_dependencies%': '<(wtf_dependencies)',
- 'mojom_output_languages%': '<(mojom_output_languages)',
- 'mojom_typemaps%': [],
- 'mojom_base_output_dir':
- '<!(python <(DEPTH)/build/inverse_depth.py <(DEPTH))',
- 'mojom_generated_outputs': [
- '<!@(python <(DEPTH)/mojo/public/tools/bindings/mojom_list_outputs.py --basedir <(mojom_base_output_dir) --variant <(mojom_variant) <@(_sources))',
- ],
- 'generated_typemap_file': '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(_target_name)_type_mappings',
- },
- 'actions': [
- {
- 'variables': {
- 'java_out_dir': '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src',
- 'stamp_filename': '<(PRODUCT_DIR)/java_mojo/<(_target_name)/<(_target_name).stamp',
- },
- 'action_name': '<(_target_name)_mojom_bindings_stamp',
- # The java output directory is deleted to ensure that the java library
- # doesn't try to compile stale files.
- 'action': [
- 'python', '<(DEPTH)/build/rmdir_and_stamp.py',
- '<(java_out_dir)',
- '<(stamp_filename)',
- ],
- 'inputs': [ '<@(_sources)' ],
- 'outputs': [ '<(stamp_filename)' ],
- },
- {
- 'variables': {
- 'output': '<(generated_typemap_file)',
- },
- 'action_name': '<(_target_name)_type_mappings',
- 'action': [
- 'python', '<(DEPTH)/mojo/public/tools/bindings/generate_type_mappings.py',
- '--output',
- '<(output)',
- '<!@(python <(DEPTH)/mojo/public/tools/bindings/format_typemap_generator_args.py <@(mojom_typemaps))',
- ],
- 'inputs':[
- '<(DEPTH)/mojo/public/tools/bindings/generate_type_mappings.py',
- ],
- 'outputs': [ '<(output)' ],
- },
- ],
- 'rules': [
- {
- 'rule_name': '<(_target_name)_mojom_bindings_generator',
- 'extension': 'mojom',
- 'variables': {
- 'java_out_dir': '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src',
- 'mojom_import_args%': [
- '-I<(DEPTH)',
- '-I<(DEPTH)/mojo/services',
- ],
- 'stamp_filename': '<(PRODUCT_DIR)/java_mojo/<(_target_name)/<(_target_name).stamp',
- },
- 'inputs': [
- '<@(mojom_bindings_generator_sources)',
- '<(stamp_filename)',
- '<(generated_typemap_file)',
- '<(SHARED_INTERMEDIATE_DIR)/mojo/public/tools/bindings/cpp_templates.zip',
- '<(SHARED_INTERMEDIATE_DIR)/mojo/public/tools/bindings/java_templates.zip',
- '<(SHARED_INTERMEDIATE_DIR)/mojo/public/tools/bindings/js_templates.zip',
- ],
- 'conditions': [
- ['mojom_variant=="none"', {
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom.cc',
- '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom.h',
- '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom.js',
- '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom-internal.h',
- ]
- }, {
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom-<(mojom_variant).cc',
- '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom-<(mojom_variant).h',
- '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom-<(mojom_variant)-internal.h',
- ],
- }]
- ],
- 'action': [
- 'python', '<@(mojom_bindings_generator)',
- '--use_bundled_pylibs', 'generate',
- './<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom',
- '-d', '<(DEPTH)',
- '<@(mojom_import_args)',
- '-o', '<(SHARED_INTERMEDIATE_DIR)',
- '--java_output_directory=<(java_out_dir)',
- '--variant', '<(mojom_variant)',
- '-g', '<(mojom_output_languages)',
- '--typemap',
- '<(generated_typemap_file)',
- '<@(mojom_generator_wtf_arg)',
- '<@(mojom_generator_new_wrappers_arg)',
- '--bytecode_path',
- '<(SHARED_INTERMEDIATE_DIR)/mojo/public/tools/bindings',
- ],
- 'message': 'Generating Mojo bindings from <(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom',
- 'process_outputs_as_sources': 1,
- }
- ],
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/mojo/mojo_public.gyp:mojo_interface_bindings_generation',
- '<(DEPTH)/mojo/public/tools/bindings/bindings.gyp:precompile_mojom_bindings_generator_templates',
- '<@(wtf_dependencies)',
- ],
- 'export_dependent_settings': [
- '<@(wtf_dependencies)',
- ],
- 'include_dirs': [
- '<(DEPTH)',
- '<(SHARED_INTERMEDIATE_DIR)',
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(DEPTH)',
- '<(SHARED_INTERMEDIATE_DIR)',
- ],
- 'variables': {
- 'generated_src_dirs': [
- '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src',
- ],
- 'additional_input_paths': [
- '<@(mojom_bindings_generator_sources)',
- '<@(_sources)',
- ],
- },
- },
- 'hard_dependency': 1,
-}
diff --git a/mojo/mojom_bindings_generator_explicit.gypi b/mojo/mojom_bindings_generator_explicit.gypi
deleted file mode 100644
index 51676e9..0000000
--- a/mojo/mojom_bindings_generator_explicit.gypi
+++ /dev/null
@@ -1,195 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'includes': [
- 'mojom_bindings_generator_variables.gypi',
- ],
- 'variables': {
- 'variables': {
- 'variables': {
- 'for_blink%': 'false',
- 'use_new_wrapper_types%': 'false',
- },
- 'for_blink%': 'false',
- 'use_new_wrapper_types%': 'false',
- 'conditions': [
- ['for_blink=="true"', {
- 'mojom_output_languages%': 'c++',
- 'mojom_variant%': 'blink',
- 'mojom_generator_wtf_arg%': [
- '--for_blink',
- ],
- 'wtf_dependencies%': [
- '<(DEPTH)/mojo/mojo_public.gyp:mojo_cpp_bindings_wtf_support',
- '<(DEPTH)/third_party/WebKit/Source/wtf/wtf.gyp:wtf',
- ],
- }, {
- 'mojom_output_languages%': 'c++,javascript,java',
- 'mojom_variant%': 'none',
- 'mojom_generator_wtf_arg%': [],
- 'wtf_dependencies%': [],
- }],
- ['use_new_wrapper_types=="true"', {
- 'mojom_generator_new_wrappers_arg%': [
- '--use_new_wrapper_types',
- ],
- }, {
- 'mojom_generator_new_wrappers_arg%': [],
- }],
- ],
- },
- 'for_blink%': '<(for_blink)',
- 'use_new_wrapper_types%': '<(use_new_wrapper_types)',
- 'mojom_variant%': '<(mojom_variant)',
- 'mojom_generator_wtf_arg%': '<(mojom_generator_wtf_arg)',
- 'mojom_generator_new_wrappers_arg%': '<(mojom_generator_new_wrappers_arg)',
- 'wtf_dependencies%': '<(wtf_dependencies)',
- 'mojom_output_languages%': '<(mojom_output_languages)',
- 'mojom_typemaps%': [],
- 'mojom_base_output_dir':
- '<!(python <(DEPTH)/build/inverse_depth.py <(DEPTH))',
- 'mojom_generated_outputs': [
- '<!@(python <(DEPTH)/mojo/public/tools/bindings/mojom_list_outputs.py --basedir <(mojom_base_output_dir) --variant <(mojom_variant) <@(mojom_files))',
- ],
- 'generated_typemap_file': '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(_target_name)_type_mappings',
- 'mojom_include_path%': '<(DEPTH)',
- 'require_interface_bindings%': 1,
- },
- # Given mojom files as inputs, generate sources. These sources will be
- # exported to another target (via dependent_settings) to be compiled. This
- # keeps code generation separate from compilation, allowing the same sources
- # to be compiled with multiple toolchains - target, NaCl, etc.
- 'actions': [
- {
- 'variables': {
- 'java_out_dir': '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src',
- 'stamp_filename': '<(PRODUCT_DIR)/java_mojo/<(_target_name)/<(_target_name).stamp',
- },
- 'action_name': '<(_target_name)_mojom_bindings_stamp',
- # The java output directory is deleted to ensure that the java library
- # doesn't try to compile stale files.
- 'action': [
- 'python', '<(DEPTH)/build/rmdir_and_stamp.py',
- '<(java_out_dir)',
- '<(stamp_filename)',
- ],
- 'inputs': [
- '<@(mojom_files)',
- ],
- 'outputs': [ '<(stamp_filename)' ],
- },
- {
- 'variables': {
- 'output': '<(generated_typemap_file)',
- },
- 'action_name': '<(_target_name)_type_mappings',
- 'action': [
- 'python', '<(DEPTH)/mojo/public/tools/bindings/generate_type_mappings.py',
- '--output',
- '<(output)',
- '<!@(python <(DEPTH)/mojo/public/tools/bindings/format_typemap_generator_args.py <@(mojom_typemaps))',
- ],
- 'inputs':[
- '<(DEPTH)/mojo/public/tools/bindings/generate_type_mappings.py',
- ],
- 'outputs': [ '<(output)' ],
- },
- {
- 'action_name': '<(_target_name)_mojom_bindings_generator',
- 'variables': {
- 'java_out_dir': '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src',
- 'stamp_filename': '<(PRODUCT_DIR)/java_mojo/<(_target_name)/<(_target_name).stamp',
- 'mojom_import_args%': [
- '-I<(DEPTH)',
- '-I<(DEPTH)/mojo/services',
- '-I<(mojom_include_path)',
- ],
- },
- 'inputs': [
- '<@(mojom_bindings_generator_sources)',
- '<@(mojom_files)',
- '<(stamp_filename)',
- '<(generated_typemap_file)',
- '<(SHARED_INTERMEDIATE_DIR)/mojo/public/tools/bindings/cpp_templates.zip',
- '<(SHARED_INTERMEDIATE_DIR)/mojo/public/tools/bindings/java_templates.zip',
- '<(SHARED_INTERMEDIATE_DIR)/mojo/public/tools/bindings/js_templates.zip',
- ],
- 'outputs': [
- '<@(mojom_generated_outputs)',
- ],
- 'action': [
- 'python', '<@(mojom_bindings_generator)',
- '--use_bundled_pylibs', 'generate',
- '<@(mojom_files)',
- '-d', '<(DEPTH)',
- '<@(mojom_import_args)',
- '-o', '<(SHARED_INTERMEDIATE_DIR)',
- '--java_output_directory=<(java_out_dir)',
- '--variant', '<(mojom_variant)',
- '-g', '<(mojom_output_languages)',
- '--typemap',
- '<(generated_typemap_file)',
- '<@(mojom_generator_wtf_arg)',
- '<@(mojom_generator_new_wrappers_arg)',
- '--bytecode_path',
- '<(SHARED_INTERMEDIATE_DIR)/mojo/public/tools/bindings',
- ],
- 'message': 'Generating Mojo bindings from <@(mojom_files)',
- }
- ],
- 'conditions': [
- ['require_interface_bindings==1', {
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/mojo/mojo_public.gyp:mojo_interface_bindings_generation',
- ],
- }],
- ],
- 'dependencies': [
- '<(DEPTH)/mojo/public/tools/bindings/bindings.gyp:precompile_mojom_bindings_generator_templates',
- '<@(wtf_dependencies)',
- ],
- 'export_dependent_settings': [
- '<@(wtf_dependencies)',
- ],
- # Prevent the generated sources from being injected into the "all" target by
- # preventing the code generator from being directly depended on by the "all"
- # target.
- 'suppress_wildcard': '1',
- 'hard_dependency': '1',
- 'direct_dependent_settings': {
- # A target directly depending on this action will compile the generated
- # sources.
- 'sources': [
- '<@(mojom_generated_outputs)',
- ],
- # Include paths needed to compile the generated sources into a library.
- 'include_dirs': [
- '<(DEPTH)',
- '<(SHARED_INTERMEDIATE_DIR)',
- ],
- # Make sure the generated header files are available for any static library
- # that depends on a static library that depends on this generator.
- 'hard_dependency': 1,
- 'direct_dependent_settings': {
- # Include paths needed to find the generated header files and their
- # transitive dependancies when using the library.
- 'include_dirs': [
- '<(DEPTH)',
- '<(SHARED_INTERMEDIATE_DIR)',
- ],
- 'variables': {
- 'generated_src_dirs': [
- '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src',
- ],
- 'additional_input_paths': [
- '<@(mojom_bindings_generator_sources)',
- '<@(mojom_files)',
- ],
- 'mojom_generated_sources': [ '<@(mojom_generated_outputs)' ],
- },
- }
- },
-}
diff --git a/mojo/mojom_bindings_generator_variables.gypi b/mojo/mojom_bindings_generator_variables.gypi
deleted file mode 100644
index 9e3c400..0000000
--- a/mojo/mojom_bindings_generator_variables.gypi
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'variables': {
- 'mojom_bindings_generator':
- '<(DEPTH)/mojo/public/tools/bindings/mojom_bindings_generator.py',
- 'mojom_bindings_generator_sources': [
- '<(mojom_bindings_generator)',
- '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_cpp_generator.py',
- '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_java_generator.py',
- '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_js_generator.py',
- '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/__init__.py',
- '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/error.py',
- '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/__init__.py',
- '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/data.py',
- '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/generator.py',
- '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/module.py',
- '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/pack.py',
- '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py',
- '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/__init__.py',
- '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/ast.py',
- '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/lexer.py',
- '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/parser.py',
- '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/translate.py',
- ]
- }
-}
diff --git a/mojo/public/BUILD.gn b/mojo/public/BUILD.gn
index 9442479..3baf667 100644
--- a/mojo/public/BUILD.gn
+++ b/mojo/public/BUILD.gn
@@ -13,8 +13,8 @@ group("public") {
if (is_android) {
deps += [
- "java:bindings",
- "java:system",
+ "java:bindings_java",
+ "java:system_java",
]
}
}
@@ -23,7 +23,6 @@ group("sdk") {
deps = [
"c/system",
"cpp/bindings",
- "interfaces/bindings",
"js",
]
}
diff --git a/mojo/public/README.md b/mojo/public/README.md
index a31a8a8..dd91742 100644
--- a/mojo/public/README.md
+++ b/mojo/public/README.md
@@ -31,7 +31,7 @@ Platform
--------
The platform/ subdirectory contains any build-time requirements (e.g., static
-libraries) that may be needed to produce a Mojo application for certain
+libraries) that may be needed to produce a Service library for certain
platforms, such as a native shared library or as a NaCl binary.
Tools
diff --git a/mojo/public/c/system/BUILD.gn b/mojo/public/c/system/BUILD.gn
index 3ec12f6..c3b3d5f 100644
--- a/mojo/public/c/system/BUILD.gn
+++ b/mojo/public/c/system/BUILD.gn
@@ -25,7 +25,7 @@ component("system") {
# This should ONLY be depended upon directly by shared_library targets which
# need to export the MojoSetSystemThunks symbol, like targets generated by the
-# mojo_native_application template in //mojo/public/mojo_application.gni.
+# mojo_native_application template in //services/service_manager/public/cpp/service.gni.
source_set("set_thunks_for_app") {
sources = [
"set_thunks_for_app.cc",
diff --git a/mojo/public/c/system/core.h b/mojo/public/c/system/core.h
index 3775e90..77d452b 100644
--- a/mojo/public/c/system/core.h
+++ b/mojo/public/c/system/core.h
@@ -13,7 +13,6 @@
#include "mojo/public/c/system/data_pipe.h"
#include "mojo/public/c/system/functions.h"
#include "mojo/public/c/system/macros.h"
-#include "mojo/public/c/system/main.h"
#include "mojo/public/c/system/message_pipe.h"
#include "mojo/public/c/system/platform_handle.h"
#include "mojo/public/c/system/system_export.h"
diff --git a/mojo/public/c/system/main.h b/mojo/public/c/system/main.h
deleted file mode 100644
index 65d0837..0000000
--- a/mojo/public/c/system/main.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_C_SYSTEM_MAIN_H_
-#define MOJO_PUBLIC_C_SYSTEM_MAIN_H_
-
-#include "mojo/public/c/system/types.h"
-
-// Implement MojoMain directly as the entry point for an application.
-//
-// MojoResult MojoMain(MojoHandle application_request) {
-// ...
-// }
-//
-// TODO(davemoore): Establish this as part of our SDK for third party mojo
-// application writers.
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-#if defined(WIN32)
-__declspec(dllexport) MojoResult
- __cdecl MojoMain(MojoHandle application_request);
-#else // !defined(WIN32)
-__attribute__((visibility("default"))) MojoResult
- MojoMain(MojoHandle service_provider_handle);
-#endif // defined(WIN32)
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // MOJO_PUBLIC_C_SYSTEM_MAIN_H_
diff --git a/mojo/public/c/system/tests/core_unittest.cc b/mojo/public/c/system/tests/core_unittest.cc
index ef44a87..8a54380 100644
--- a/mojo/public/c/system/tests/core_unittest.cc
+++ b/mojo/public/c/system/tests/core_unittest.cc
@@ -192,7 +192,8 @@ TEST(CoreTest, BasicDataPipe) {
MojoWait(hc, MOJO_HANDLE_SIGNAL_READABLE, 0, &state));
EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, state.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
state.satisfiable_signals);
// The producer |hp| should be writable.
@@ -229,8 +230,10 @@ TEST(CoreTest, BasicDataPipe) {
&result_index, states));
EXPECT_EQ(0u, result_index);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, states[0].satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
+ states[0].satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
+ MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
states[0].satisfiable_signals);
// Do a two-phase write to |hp|.
diff --git a/mojo/public/c/system/tests/core_unittest_pure_c.c b/mojo/public/c/system/tests/core_unittest_pure_c.c
index a01e14b..fa3caa5 100644
--- a/mojo/public/c/system/tests/core_unittest_pure_c.c
+++ b/mojo/public/c/system/tests/core_unittest_pure_c.c
@@ -21,7 +21,7 @@
#define FAILURE(message) \
__FILE__ "(" STRINGIFY2(__LINE__) "): Failure: " message
-// Poor man's gtest.
+// Makeshift gtest.
#define EXPECT_EQ(a, b) \
do { \
if ((a) != (b)) \
diff --git a/mojo/public/c/system/types.h b/mojo/public/c/system/types.h
index 3482d4e..7e02eeb 100644
--- a/mojo/public/c/system/types.h
+++ b/mojo/public/c/system/types.h
@@ -149,6 +149,11 @@ const MojoDeadline MOJO_DEADLINE_INDEFINITE = static_cast<MojoDeadline>(-1);
// |MOJO_HANDLE_SIGNAL_READABLE| - Can read (e.g., a message) from the handle.
// |MOJO_HANDLE_SIGNAL_WRITABLE| - Can write (e.g., a message) to the handle.
// |MOJO_HANDLE_SIGNAL_PEER_CLOSED| - The peer handle is closed.
+// |MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE| - Can read data from a data pipe
+// consumer handle (implying MOJO_HANDLE_SIGNAL_READABLE is also set),
+// AND there is some nonzero quantity of new data available on the pipe
+// since the last |MojoReadData()| or |MojoBeginReadData()| call on the
+// handle.
typedef uint32_t MojoHandleSignals;
@@ -157,11 +162,13 @@ const MojoHandleSignals MOJO_HANDLE_SIGNAL_NONE = 0;
const MojoHandleSignals MOJO_HANDLE_SIGNAL_READABLE = 1 << 0;
const MojoHandleSignals MOJO_HANDLE_SIGNAL_WRITABLE = 1 << 1;
const MojoHandleSignals MOJO_HANDLE_SIGNAL_PEER_CLOSED = 1 << 2;
+const MojoHandleSignals MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE = 1 << 3;
#else
#define MOJO_HANDLE_SIGNAL_NONE ((MojoHandleSignals)0)
#define MOJO_HANDLE_SIGNAL_READABLE ((MojoHandleSignals)1 << 0)
#define MOJO_HANDLE_SIGNAL_WRITABLE ((MojoHandleSignals)1 << 1)
#define MOJO_HANDLE_SIGNAL_PEER_CLOSED ((MojoHandleSignals)1 << 2)
+#define MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE ((MojoHandleSignals)1 << 3);
#endif
// |MojoHandleSignalsState|: Returned by wait functions to indicate the
diff --git a/mojo/public/c/test_support/BUILD.gn b/mojo/public/c/test_support/BUILD.gn
index 75d9c13..e2abd58 100644
--- a/mojo/public/c/test_support/BUILD.gn
+++ b/mojo/public/c/test_support/BUILD.gn
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: mojo/mojo_public.gyp:mojo_test_support
static_library("test_support") {
output_name = "mojo_public_test_support"
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
index 3ec9824..5c41384 100644
--- a/mojo/public/cpp/bindings/BUILD.gn
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -2,14 +2,31 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-static_library("bindings") {
+interfaces_bindings_gen_dir = "$root_gen_dir/mojo/public/interfaces/bindings"
+
+component("bindings") {
sources = [
- "array.h",
+ # Normally, targets should depend on the source_sets generated by mojom
+ # targets. However, the generated source_sets use portions of the bindings
+ # library. In order to avoid linker warnings about locally-defined imports
+ # in Windows components build, this target depends on the generated C++
+ # files directly so that the EXPORT macro defintions match.
+ "$interfaces_bindings_gen_dir/interface_control_messages.mojom-shared-internal.h",
+ "$interfaces_bindings_gen_dir/interface_control_messages.mojom-shared.cc",
+ "$interfaces_bindings_gen_dir/interface_control_messages.mojom-shared.h",
+ "$interfaces_bindings_gen_dir/interface_control_messages.mojom.cc",
+ "$interfaces_bindings_gen_dir/interface_control_messages.mojom.h",
+ "$interfaces_bindings_gen_dir/pipe_control_messages.mojom-shared-internal.h",
+ "$interfaces_bindings_gen_dir/pipe_control_messages.mojom-shared.cc",
+ "$interfaces_bindings_gen_dir/pipe_control_messages.mojom-shared.h",
+ "$interfaces_bindings_gen_dir/pipe_control_messages.mojom.cc",
+ "$interfaces_bindings_gen_dir/pipe_control_messages.mojom.h",
+ "array_data_view.h",
"array_traits.h",
"array_traits_carray.h",
- "array_traits_standard.h",
"array_traits_stl.h",
"associated_binding.h",
+ "associated_binding_set.h",
"associated_group.h",
"associated_group_controller.h",
"associated_interface_ptr.h",
@@ -17,8 +34,13 @@ static_library("bindings") {
"associated_interface_request.h",
"binding.h",
"binding_set.h",
+ "bindings_export.h",
+ "clone_traits.h",
+ "connection_error_callback.h",
"connector.h",
- "enum_traits.h",
+ "disconnect_reason.h",
+ "filter_chain.h",
+ "interface_data_view.h",
"interface_endpoint_client.h",
"interface_endpoint_controller.h",
"interface_id.h",
@@ -29,34 +51,35 @@ static_library("bindings") {
"lib/array_internal.cc",
"lib/array_internal.h",
"lib/array_serialization.h",
+ "lib/associated_binding.cc",
"lib/associated_group.cc",
"lib/associated_group_controller.cc",
"lib/associated_interface_ptr_state.h",
+ "lib/binding_state.cc",
"lib/binding_state.h",
- "lib/bindings_internal.cc",
"lib/bindings_internal.h",
"lib/buffer.h",
- "lib/clone_equals_util.h",
"lib/connector.cc",
"lib/control_message_handler.cc",
"lib/control_message_handler.h",
"lib/control_message_proxy.cc",
"lib/control_message_proxy.h",
+ "lib/equals_traits.h",
"lib/filter_chain.cc",
- "lib/filter_chain.h",
"lib/fixed_buffer.cc",
"lib/fixed_buffer.h",
"lib/handle_interface_serialization.h",
+ "lib/hash_util.h",
"lib/interface_endpoint_client.cc",
"lib/interface_ptr_state.h",
"lib/map_data_internal.h",
"lib/map_serialization.h",
+ "lib/may_auto_lock.h",
"lib/message.cc",
"lib/message_buffer.cc",
"lib/message_buffer.h",
"lib/message_builder.cc",
"lib/message_builder.h",
- "lib/message_filter.cc",
"lib/message_header_validator.cc",
"lib/message_internal.h",
"lib/multiplex_router.cc",
@@ -68,11 +91,8 @@ static_library("bindings") {
"lib/native_struct_data.h",
"lib/native_struct_serialization.cc",
"lib/native_struct_serialization.h",
- "lib/no_interface.cc",
"lib/pipe_control_message_handler.cc",
"lib/pipe_control_message_proxy.cc",
- "lib/router.cc",
- "lib/router.h",
"lib/scoped_interface_endpoint_handle.cc",
"lib/serialization.h",
"lib/serialization_context.cc",
@@ -94,32 +114,35 @@ static_library("bindings") {
"lib/validation_util.cc",
"lib/validation_util.h",
"map.h",
+ "map_data_view.h",
"map_traits.h",
- "map_traits_standard.h",
"map_traits_stl.h",
"message.h",
- "message_filter.h",
"message_header_validator.h",
"native_enum.h",
"native_struct.h",
- "no_interface.h",
+ "native_struct_data_view.h",
"pipe_control_message_handler.h",
"pipe_control_message_handler_delegate.h",
"pipe_control_message_proxy.h",
+ "raw_ptr_impl_ref_traits.h",
"scoped_interface_endpoint_handle.h",
- "stl_converters.h",
- "string.h",
+ "string_data_view.h",
"string_traits.h",
- "string_traits_standard.h",
"string_traits_stl.h",
"string_traits_string16.h",
"string_traits_string_piece.h",
+ "strong_associated_binding.h",
"strong_binding.h",
+ "strong_binding_set.h",
"struct_ptr.h",
"sync_call_restrictions.h",
"sync_handle_registry.h",
"sync_handle_watcher.h",
+ "thread_safe_interface_ptr.h",
"type_converter.h",
+ "union_traits.h",
+ "unique_ptr_impl_ref_traits.h",
]
public_deps = [
@@ -131,12 +154,16 @@ static_library("bindings") {
deps = [
"//base",
- "//mojo/public/interfaces/bindings:bindings_cpp_sources",
+ "//mojo/public/interfaces/bindings:bindings__generator",
+ "//mojo/public/interfaces/bindings:bindings_shared__generator",
]
+
+ defines = [ "MOJO_CPP_BINDINGS_IMPLEMENTATION" ]
}
source_set("struct_traits") {
sources = [
+ "enum_traits.h",
"struct_traits.h",
]
}
@@ -145,16 +172,13 @@ if (!is_ios) {
# TODO(yzshen): crbug.com/617718 Consider moving this into blink.
source_set("wtf_support") {
sources = [
- "array_traits_wtf.h",
"array_traits_wtf_vector.h",
"lib/string_traits_wtf.cc",
"lib/wtf_clone_equals_util.h",
+ "lib/wtf_hash_util.h",
"lib/wtf_serialization.h",
- "map_traits_wtf.h",
"map_traits_wtf_hash_map.h",
"string_traits_wtf.h",
- "wtf_array.h",
- "wtf_map.h",
]
public_deps = [
diff --git a/mojo/public/cpp/bindings/array.h b/mojo/public/cpp/bindings/array.h
deleted file mode 100644
index a253da1..0000000
--- a/mojo/public/cpp/bindings/array.h
+++ /dev/null
@@ -1,279 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_
-
-#include <stddef.h>
-#include <string.h>
-#include <algorithm>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/lib/array_internal.h"
-#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
-#include "mojo/public/cpp/bindings/lib/clone_equals_util.h"
-#include "mojo/public/cpp/bindings/lib/template_util.h"
-#include "mojo/public/cpp/bindings/type_converter.h"
-
-namespace mojo {
-
-// Represents a moveable array with contents of type |T|. The array can be null,
-// meaning that no value has been assigned to it. Null is distinct from empty.
-template <typename T>
-class Array {
- public:
- using ConstRefType = typename std::vector<T>::const_reference;
- using RefType = typename std::vector<T>::reference;
-
- using Element = T;
-
- using iterator = typename std::vector<T>::iterator;
- using const_iterator = typename std::vector<T>::const_iterator;
-
- // Constructs an empty array.
- Array() : is_null_(false) {}
- // Constructs a null array.
- Array(std::nullptr_t null_pointer) : is_null_(true) {}
-
- // Constructs a new non-null array of the specified size. The elements will
- // be value-initialized (meaning that they will be initialized by their
- // default constructor, if any, or else zero-initialized).
- explicit Array(size_t size) : vec_(size), is_null_(false) {}
- ~Array() {}
-
- // Copies the contents of |other| into this array.
- Array(const std::vector<T>& other) : vec_(other), is_null_(false) {}
-
- // Moves the contents of |other| into this array.
- Array(std::vector<T>&& other) : vec_(std::move(other)), is_null_(false) {}
- Array(Array&& other) : is_null_(true) { Take(&other); }
-
- Array& operator=(std::vector<T>&& other) {
- vec_ = std::move(other);
- is_null_ = false;
- return *this;
- }
- Array& operator=(Array&& other) {
- Take(&other);
- return *this;
- }
-
- Array& operator=(std::nullptr_t null_pointer) {
- is_null_ = true;
- vec_.clear();
- return *this;
- }
-
- // Creates a non-null array of the specified size. The elements will be
- // value-initialized (meaning that they will be initialized by their default
- // constructor, if any, or else zero-initialized).
- static Array New(size_t size) { return Array(size); }
-
- // Creates a new array with a copy of the contents of |other|.
- template <typename U>
- static Array From(const U& other) {
- return TypeConverter<Array, U>::Convert(other);
- }
-
- // Copies the contents of this array to a new object of type |U|.
- template <typename U>
- U To() const {
- return TypeConverter<U, Array>::Convert(*this);
- }
-
- // Indicates whether the array is null (which is distinct from empty).
- bool is_null() const { return is_null_; }
-
- // Indicates whether the array is empty (which is distinct from null).
- bool empty() const { return vec_.empty() && !is_null_; }
-
- // Returns a reference to the first element of the array. Calling this on a
- // null or empty array causes undefined behavior.
- ConstRefType front() const { return vec_.front(); }
- RefType front() { return vec_.front(); }
-
- iterator begin() { return vec_.begin(); }
- const_iterator begin() const { return vec_.begin(); }
- iterator end() { return vec_.end(); }
- const_iterator end() const { return vec_.end(); }
-
- // Returns the size of the array, which will be zero if the array is null.
- size_t size() const { return vec_.size(); }
-
- // Returns a reference to the element at zero-based |offset|. Calling this on
- // an array with size less than |offset|+1 causes undefined behavior.
- ConstRefType at(size_t offset) const { return vec_.at(offset); }
- ConstRefType operator[](size_t offset) const { return at(offset); }
- RefType at(size_t offset) { return vec_.at(offset); }
- RefType operator[](size_t offset) { return at(offset); }
-
- // Pushes |value| onto the back of the array. If this array was null, it will
- // become non-null with a size of 1.
- void push_back(const T& value) {
- is_null_ = false;
- vec_.push_back(value);
- }
- void push_back(T&& value) {
- is_null_ = false;
- vec_.push_back(std::move(value));
- }
-
- // Resizes the array to |size| and makes it non-null. Otherwise, works just
- // like the resize method of |std::vector|.
- void resize(size_t size) {
- is_null_ = false;
- vec_.resize(size);
- }
-
- // Sets the array to empty (even if previously it was null.)
- void SetToEmpty() { resize(0); }
-
- // Returns a const reference to the |std::vector| managed by this class. If
- // the array is null, this will be an empty vector.
- const std::vector<T>& storage() const { return vec_; }
-
- // Passes the underlying storage and resets this array to null.
- std::vector<T> PassStorage() {
- is_null_ = true;
- return std::move(vec_);
- }
-
- operator const std::vector<T>&() const { return vec_; }
-
- void Swap(Array* other) {
- std::swap(is_null_, other->is_null_);
- vec_.swap(other->vec_);
- }
-
- // Swaps the contents of this array with the specified vector, making this
- // array non-null. Since the vector cannot represent null, it will just be
- // made empty if this array is null.
- void Swap(std::vector<T>* other) {
- is_null_ = false;
- vec_.swap(*other);
- }
-
- // Returns a copy of the array where each value of the new array has been
- // "cloned" from the corresponding value of this array. If the element type
- // defines a Clone() method, it will be used; otherwise copy
- // constructor/assignment will be used.
- //
- // Please note that calling this method will fail compilation if the element
- // type cannot be cloned (which usually means that it is a Mojo handle type or
- // a type containing Mojo handles).
- Array Clone() const {
- Array result;
- result.is_null_ = is_null_;
- result.vec_ = internal::Clone(vec_);
- return result;
- }
-
- // Indicates whether the contents of this array are equal to |other|. A null
- // array is only equal to another null array. If the element type defines an
- // Equals() method, it will be used; otherwise == operator will be used.
- bool Equals(const Array& other) const {
- if (is_null() != other.is_null())
- return false;
- return internal::Equals(vec_, other.vec_);
- }
-
- private:
- typedef std::vector<T> Array::*Testable;
-
- public:
- operator Testable() const { return is_null_ ? 0 : &Array::vec_; }
-
- private:
- // Forbid the == and != operators explicitly, otherwise Array will be
- // converted to Testable to do == or != comparison.
- template <typename U>
- bool operator==(const Array<U>& other) const = delete;
- template <typename U>
- bool operator!=(const Array<U>& other) const = delete;
-
- void Take(Array* other) {
- operator=(nullptr);
- Swap(other);
- }
-
- std::vector<T> vec_;
- bool is_null_;
-
- DISALLOW_COPY_AND_ASSIGN(Array);
-};
-
-// A |TypeConverter| that will create an |Array<T>| containing a copy of the
-// contents of an |std::vector<E>|, using |TypeConverter<T, E>| to copy each
-// element. The returned array will always be non-null.
-template <typename T, typename E>
-struct TypeConverter<Array<T>, std::vector<E>> {
- static Array<T> Convert(const std::vector<E>& input) {
- Array<T> result(input.size());
- for (size_t i = 0; i < input.size(); ++i)
- result[i] = TypeConverter<T, E>::Convert(input[i]);
- return std::move(result);
- }
-};
-
-// A |TypeConverter| that will create an |std::vector<E>| containing a copy of
-// the contents of an |Array<T>|, using |TypeConverter<E, T>| to copy each
-// element. If the input array is null, the output vector will be empty.
-template <typename E, typename T>
-struct TypeConverter<std::vector<E>, Array<T>> {
- static std::vector<E> Convert(const Array<T>& input) {
- std::vector<E> result;
- if (!input.is_null()) {
- result.resize(input.size());
- for (size_t i = 0; i < input.size(); ++i)
- result[i] = TypeConverter<E, T>::Convert(input[i]);
- }
- return result;
- }
-};
-
-// A |TypeConverter| that will create an |Array<T>| containing a copy of the
-// contents of an |std::set<E>|, using |TypeConverter<T, E>| to copy each
-// element. The returned array will always be non-null.
-template <typename T, typename E>
-struct TypeConverter<Array<T>, std::set<E>> {
- static Array<T> Convert(const std::set<E>& input) {
- Array<T> result;
- for (auto i : input)
- result.push_back(TypeConverter<T, E>::Convert(i));
- return std::move(result);
- }
-};
-
-// A |TypeConverter| that will create an |std::set<E>| containing a copy of
-// the contents of an |Array<T>|, using |TypeConverter<E, T>| to copy each
-// element. If the input array is null, the output set will be empty.
-template <typename E, typename T>
-struct TypeConverter<std::set<E>, Array<T>> {
- static std::set<E> Convert(const Array<T>& input) {
- std::set<E> result;
- if (!input.is_null()) {
- for (size_t i = 0; i < input.size(); ++i)
- result.insert(TypeConverter<E, T>::Convert(input[i]));
- }
- return result;
- }
-};
-
-// Less than operator to allow Arrays as keys in std maps and sets.
-template <typename T>
-inline bool operator<(const Array<T>& a, const Array<T>& b) {
- if (a.is_null())
- return !b.is_null();
- if (b.is_null())
- return false;
- return a.storage() < b.storage();
-}
-
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_
diff --git a/mojo/public/cpp/bindings/array_data_view.h b/mojo/public/cpp/bindings/array_data_view.h
new file mode 100644
index 0000000..d02a884
--- /dev/null
+++ b/mojo/public/cpp/bindings/array_data_view.h
@@ -0,0 +1,244 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_ARRAY_DATA_VIEW_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_DATA_VIEW_H_
+
+#include <type_traits>
+
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/serialization_context.h"
+#include "mojo/public/cpp/bindings/lib/serialization_forward.h"
+
+namespace mojo {
+namespace internal {
+
+template <typename T, typename EnableType = void>
+class ArrayDataViewImpl;
+
+template <typename T>
+class ArrayDataViewImpl<
+ T,
+ typename std::enable_if<
+ BelongsTo<T, MojomTypeCategory::POD>::value>::type> {
+ public:
+ using Data_ = typename MojomTypeTraits<ArrayDataView<T>>::Data;
+
+ ArrayDataViewImpl(Data_* data, SerializationContext* context)
+ : data_(data), context_(context) {}
+
+ T operator[](size_t index) const { return data_->at(index); }
+
+ const T* data() const { return data_->storage(); }
+
+ protected:
+ Data_* data_;
+ SerializationContext* context_;
+};
+
+template <typename T>
+class ArrayDataViewImpl<
+ T,
+ typename std::enable_if<
+ BelongsTo<T, MojomTypeCategory::BOOLEAN>::value>::type> {
+ public:
+ using Data_ = typename MojomTypeTraits<ArrayDataView<T>>::Data;
+
+ ArrayDataViewImpl(Data_* data, SerializationContext* context)
+ : data_(data), context_(context) {}
+
+ bool operator[](size_t index) const { return data_->at(index); }
+
+ protected:
+ Data_* data_;
+ SerializationContext* context_;
+};
+
+template <typename T>
+class ArrayDataViewImpl<
+ T,
+ typename std::enable_if<
+ BelongsTo<T, MojomTypeCategory::ENUM>::value>::type> {
+ public:
+ static_assert(sizeof(T) == sizeof(int32_t), "Unexpected enum size");
+
+ using Data_ = typename MojomTypeTraits<ArrayDataView<T>>::Data;
+
+ ArrayDataViewImpl(Data_* data, SerializationContext* context)
+ : data_(data), context_(context) {}
+
+ T operator[](size_t index) const { return static_cast<T>(data_->at(index)); }
+
+ const T* data() const { return reinterpret_cast<const T*>(data_->storage()); }
+
+ template <typename U>
+ bool Read(size_t index, U* output) {
+ return Deserialize<T>(data_->at(index), output);
+ }
+
+ protected:
+ Data_* data_;
+ SerializationContext* context_;
+};
+
+template <typename T>
+class ArrayDataViewImpl<
+ T,
+ typename std::enable_if<
+ BelongsTo<T,
+ MojomTypeCategory::ASSOCIATED_INTERFACE |
+ MojomTypeCategory::ASSOCIATED_INTERFACE_REQUEST |
+ MojomTypeCategory::INTERFACE |
+ MojomTypeCategory::INTERFACE_REQUEST>::value>::type> {
+ public:
+ using Data_ = typename MojomTypeTraits<ArrayDataView<T>>::Data;
+
+ ArrayDataViewImpl(Data_* data, SerializationContext* context)
+ : data_(data), context_(context) {}
+
+ template <typename U>
+ U Take(size_t index) {
+ U result;
+ bool ret = Deserialize<T>(&data_->at(index), &result, context_);
+ DCHECK(ret);
+ return result;
+ }
+
+ protected:
+ Data_* data_;
+ SerializationContext* context_;
+};
+
+template <typename T>
+class ArrayDataViewImpl<
+ T,
+ typename std::enable_if<
+ BelongsTo<T, MojomTypeCategory::HANDLE>::value>::type> {
+ public:
+ using Data_ = typename MojomTypeTraits<ArrayDataView<T>>::Data;
+
+ ArrayDataViewImpl(Data_* data, SerializationContext* context)
+ : data_(data), context_(context) {}
+
+ T Take(size_t index) {
+ T result;
+ bool ret = Deserialize<T>(&data_->at(index), &result, context_);
+ DCHECK(ret);
+ return result;
+ }
+
+ protected:
+ Data_* data_;
+ SerializationContext* context_;
+};
+
+template <typename T>
+class ArrayDataViewImpl<T,
+ typename std::enable_if<BelongsTo<
+ T,
+ MojomTypeCategory::ARRAY | MojomTypeCategory::MAP |
+ MojomTypeCategory::STRING |
+ MojomTypeCategory::STRUCT>::value>::type> {
+ public:
+ using Data_ = typename MojomTypeTraits<ArrayDataView<T>>::Data;
+
+ ArrayDataViewImpl(Data_* data, SerializationContext* context)
+ : data_(data), context_(context) {}
+
+ void GetDataView(size_t index, T* output) {
+ *output = T(data_->at(index).Get(), context_);
+ }
+
+ template <typename U>
+ bool Read(size_t index, U* output) {
+ return Deserialize<T>(data_->at(index).Get(), output, context_);
+ }
+
+ protected:
+ Data_* data_;
+ SerializationContext* context_;
+};
+
+template <typename T>
+class ArrayDataViewImpl<
+ T,
+ typename std::enable_if<
+ BelongsTo<T, MojomTypeCategory::UNION>::value>::type> {
+ public:
+ using Data_ = typename MojomTypeTraits<ArrayDataView<T>>::Data;
+
+ ArrayDataViewImpl(Data_* data, SerializationContext* context)
+ : data_(data), context_(context) {}
+
+ void GetDataView(size_t index, T* output) {
+ *output = T(&data_->at(index), context_);
+ }
+
+ template <typename U>
+ bool Read(size_t index, U* output) {
+ return Deserialize<T>(&data_->at(index), output, context_);
+ }
+
+ protected:
+ Data_* data_;
+ SerializationContext* context_;
+};
+
+} // namespace internal
+
+template <typename K, typename V>
+class MapDataView;
+
+template <typename T>
+class ArrayDataView : public internal::ArrayDataViewImpl<T> {
+ public:
+ using Element = T;
+ using Data_ = typename internal::ArrayDataViewImpl<T>::Data_;
+
+ ArrayDataView() : internal::ArrayDataViewImpl<T>(nullptr, nullptr) {}
+
+ ArrayDataView(Data_* data, internal::SerializationContext* context)
+ : internal::ArrayDataViewImpl<T>(data, context) {}
+
+ bool is_null() const { return !this->data_; }
+
+ size_t size() const { return this->data_->size(); }
+
+ // Methods to access elements are different for different element types. They
+ // are inherited from internal::ArrayDataViewImpl:
+
+ // POD types except boolean and enums:
+ // T operator[](size_t index) const;
+ // const T* data() const;
+
+ // Boolean:
+ // bool operator[](size_t index) const;
+
+ // Enums:
+ // T operator[](size_t index) const;
+ // const T* data() const;
+ // template <typename U>
+ // bool Read(size_t index, U* output);
+
+ // Handles:
+ // T Take(size_t index);
+
+ // Interfaces:
+ // template <typename U>
+ // U Take(size_t index);
+
+ // Object types:
+ // void GetDataView(size_t index, T* output);
+ // template <typename U>
+ // bool Read(size_t index, U* output);
+
+ private:
+ template <typename K, typename V>
+ friend class MapDataView;
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_DATA_VIEW_H_
diff --git a/mojo/public/cpp/bindings/array_traits.h b/mojo/public/cpp/bindings/array_traits.h
index 366573d..594b2e0 100644
--- a/mojo/public/cpp/bindings/array_traits.h
+++ b/mojo/public/cpp/bindings/array_traits.h
@@ -47,7 +47,9 @@ namespace mojo {
// static void AdvanceIterator(Iterator& iterator);
//
// // Returns a reference to the value at the current position of
-// // |iterator|.
+// // |iterator|. Optionally, the ConstIterator version of GetValue can
+// // return by value instead of by reference if it makes sense for the
+// // type.
// static const T& GetValue(ConstIterator& iterator);
// static T& GetValue(Iterator& iterator);
//
diff --git a/mojo/public/cpp/bindings/array_traits_carray.h b/mojo/public/cpp/bindings/array_traits_carray.h
index ffcf9d5..3ff694b 100644
--- a/mojo/public/cpp/bindings/array_traits_carray.h
+++ b/mojo/public/cpp/bindings/array_traits_carray.h
@@ -20,6 +20,14 @@ struct CArray {
};
template <typename T>
+struct ConstCArray {
+ ConstCArray() : size(0), data(nullptr) {}
+ ConstCArray(size_t size, const T* data) : size(size), data(data) {}
+ size_t size;
+ const T* data;
+};
+
+template <typename T>
struct ArrayTraits<CArray<T>> {
using Element = T;
@@ -48,6 +56,21 @@ struct ArrayTraits<CArray<T>> {
}
};
+template <typename T>
+struct ArrayTraits<ConstCArray<T>> {
+ using Element = T;
+
+ static bool IsNull(const ConstCArray<T>& input) { return !input.data; }
+
+ static size_t GetSize(const ConstCArray<T>& input) { return input.size; }
+
+ static const T* GetData(const ConstCArray<T>& input) { return input.data; }
+
+ static const T& GetAt(const ConstCArray<T>& input, size_t index) {
+ return input.data[index];
+ }
+};
+
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_CARRAY_H_
diff --git a/mojo/public/cpp/bindings/array_traits_standard.h b/mojo/public/cpp/bindings/array_traits_standard.h
deleted file mode 100644
index 862de6b..0000000
--- a/mojo/public/cpp/bindings/array_traits_standard.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STANDARD_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STANDARD_H_
-
-#include "mojo/public/cpp/bindings/array.h"
-#include "mojo/public/cpp/bindings/array_traits.h"
-
-namespace mojo {
-
-template <typename T>
-struct ArrayTraits<Array<T>> {
- using Element = T;
-
- static bool IsNull(const Array<T>& input) { return input.is_null(); }
- static void SetToNull(Array<T>* output) { *output = nullptr; }
-
- static size_t GetSize(const Array<T>& input) { return input.size(); }
-
- static T* GetData(Array<T>& input) { return &input.front(); }
-
- static const T* GetData(const Array<T>& input) { return &input.front(); }
-
- static typename Array<T>::RefType GetAt(Array<T>& input, size_t index) {
- return input[index];
- }
-
- static typename Array<T>::ConstRefType GetAt(const Array<T>& input,
- size_t index) {
- return input[index];
- }
-
- static bool Resize(Array<T>& input, size_t size) {
- input.resize(size);
- return true;
- }
-};
-
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STANDARD_H_
diff --git a/mojo/public/cpp/bindings/array_traits_stl.h b/mojo/public/cpp/bindings/array_traits_stl.h
index 9054a92..dec47bf 100644
--- a/mojo/public/cpp/bindings/array_traits_stl.h
+++ b/mojo/public/cpp/bindings/array_traits_stl.h
@@ -5,6 +5,8 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STL_H_
#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STL_H_
+#include <map>
+#include <set>
#include <vector>
#include "mojo/public/cpp/bindings/array_traits.h"
@@ -42,13 +44,17 @@ struct ArrayTraits<std::vector<T>> {
return input[index];
}
- static bool Resize(std::vector<T>& input, size_t size) {
+ static inline bool Resize(std::vector<T>& input, size_t size) {
+ // Instead of calling std::vector<T>::resize() directly, this is a hack to
+ // make compilers happy. Some compilers (e.g., Mac, Android, Linux MSan)
+ // currently don't allow resizing types like
+ // std::vector<std::vector<MoveOnlyType>>.
+ // Because the deserialization code doesn't care about the original contents
+ // of |input|, we discard them directly.
+ //
+ // The "inline" keyword of this method matters. Without it, we have observed
+ // significant perf regression with some tests on Mac. crbug.com/631415
if (input.size() != size) {
- // This is a hack to make compilers for Mac and Android happy. They
- // currently don't allow resizing types like
- // std::vector<std::vector<MoveOnlyType>>.
- // Because the deserialization code doesn't care about the original
- // contents of |input|, we discard them directly.
std::vector<T> temp(size);
input.swap(temp);
}
@@ -57,6 +63,65 @@ struct ArrayTraits<std::vector<T>> {
}
};
+// This ArrayTraits specialization is used only for serialization.
+template <typename T>
+struct ArrayTraits<std::set<T>> {
+ using Element = T;
+ using ConstIterator = typename std::set<T>::const_iterator;
+
+ static bool IsNull(const std::set<T>& input) {
+ // std::set<> is always converted to non-null mojom array.
+ return false;
+ }
+
+ static size_t GetSize(const std::set<T>& input) { return input.size(); }
+
+ static ConstIterator GetBegin(const std::set<T>& input) {
+ return input.begin();
+ }
+ static void AdvanceIterator(ConstIterator& iterator) {
+ ++iterator;
+ }
+ static const T& GetValue(ConstIterator& iterator) {
+ return *iterator;
+ }
+};
+
+template <typename K, typename V>
+struct MapValuesArrayView {
+ explicit MapValuesArrayView(const std::map<K, V>& map) : map(map) {}
+ const std::map<K, V>& map;
+};
+
+// Convenience function to create a MapValuesArrayView<> that infers the
+// template arguments from its argument type.
+template <typename K, typename V>
+MapValuesArrayView<K, V> MapValuesToArray(const std::map<K, V>& map) {
+ return MapValuesArrayView<K, V>(map);
+}
+
+// This ArrayTraits specialization is used only for serialization and converts
+// a map<K, V> into an array<V>, discarding the keys.
+template <typename K, typename V>
+struct ArrayTraits<MapValuesArrayView<K, V>> {
+ using Element = V;
+ using ConstIterator = typename std::map<K, V>::const_iterator;
+
+ static bool IsNull(const MapValuesArrayView<K, V>& input) {
+ // std::map<> is always converted to non-null mojom array.
+ return false;
+ }
+
+ static size_t GetSize(const MapValuesArrayView<K, V>& input) {
+ return input.map.size();
+ }
+ static ConstIterator GetBegin(const MapValuesArrayView<K, V>& input) {
+ return input.map.begin();
+ }
+ static void AdvanceIterator(ConstIterator& iterator) { ++iterator; }
+ static const V& GetValue(ConstIterator& iterator) { return iterator->second; }
+};
+
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STL_H_
diff --git a/mojo/public/cpp/bindings/array_traits_wtf.h b/mojo/public/cpp/bindings/array_traits_wtf.h
deleted file mode 100644
index 7e773fc..0000000
--- a/mojo/public/cpp/bindings/array_traits_wtf.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_WTF_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_WTF_H_
-
-#include "mojo/public/cpp/bindings/array_traits.h"
-#include "mojo/public/cpp/bindings/wtf_array.h"
-
-namespace mojo {
-
-template <typename U>
-struct ArrayTraits<WTFArray<U>> {
- using Element = U;
-
- static bool IsNull(const WTFArray<U>& input) { return input.is_null(); }
- static void SetToNull(WTFArray<U>* output) { *output = nullptr; }
-
- static size_t GetSize(const WTFArray<U>& input) { return input.size(); }
-
- static U* GetData(WTFArray<U>& input) { return &input.front(); }
-
- static const U* GetData(const WTFArray<U>& input) { return &input.front(); }
-
- static U& GetAt(WTFArray<U>& input, size_t index) { return input[index]; }
-
- static const U& GetAt(const WTFArray<U>& input, size_t index) {
- return input[index];
- }
-
- static bool Resize(WTFArray<U>& input, size_t size) {
- input.resize(size);
- return true;
- }
-};
-
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_WTF_H_
diff --git a/mojo/public/cpp/bindings/associated_binding.h b/mojo/public/cpp/bindings/associated_binding.h
index 1da5009..5941166 100644
--- a/mojo/public/cpp/bindings/associated_binding.h
+++ b/mojo/public/cpp/bindings/associated_binding.h
@@ -6,23 +6,78 @@
#define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_BINDING_H_
#include <memory>
+#include <string>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "mojo/public/cpp/bindings/associated_group.h"
-#include "mojo/public/cpp/bindings/associated_group_controller.h"
+#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
#include "mojo/public/cpp/bindings/associated_interface_request.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
+#include "mojo/public/cpp/bindings/connection_error_callback.h"
#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
+#include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
namespace mojo {
+class MessageReceiver;
+
+// Base class used to factor out code in AssociatedBinding<T> expansions, in
+// particular for Bind().
+class MOJO_CPP_BINDINGS_EXPORT AssociatedBindingBase {
+ public:
+ AssociatedBindingBase();
+ ~AssociatedBindingBase();
+
+ // Adds a message filter to be notified of each incoming message before
+ // dispatch. If a filter returns |false| from Accept(), the message is not
+ // dispatched and the pipe is closed. Filters cannot be removed.
+ void AddFilter(std::unique_ptr<MessageReceiver> filter);
+
+ // Closes the associated interface. Puts this object into a state where it can
+ // be rebound.
+ void Close();
+
+ // Similar to the method above, but also specifies a disconnect reason.
+ void CloseWithReason(uint32_t custom_reason, const std::string& description);
+
+ // Sets an error handler that will be called if a connection error occurs.
+ //
+ // This method may only be called after this AssociatedBinding has been bound
+ // to a message pipe. The error handler will be reset when this
+ // AssociatedBinding is unbound or closed.
+ void set_connection_error_handler(const base::Closure& error_handler);
+
+ void set_connection_error_with_reason_handler(
+ const ConnectionErrorWithReasonCallback& error_handler);
+
+ // Indicates whether the associated binding has been completed.
+ bool is_bound() const { return !!endpoint_client_; }
+
+ // Sends a message on the underlying message pipe and runs the current
+ // message loop until its response is received. This can be used in tests to
+ // verify that no message was sent on a message pipe in response to some
+ // stimulus.
+ void FlushForTesting();
+
+ protected:
+ void BindImpl(ScopedInterfaceEndpointHandle handle,
+ MessageReceiverWithResponderStatus* receiver,
+ std::unique_ptr<MessageReceiver> payload_validator,
+ bool expect_sync_requests,
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ uint32_t interface_version);
+
+ std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
+};
+
// Represents the implementation side of an associated interface. It is similar
// to Binding, except that it doesn't own a message pipe handle.
//
@@ -33,53 +88,48 @@ namespace mojo {
// single thread for the purposes of task scheduling. Please note that incoming
// synchrounous method calls may not be run from this task runner, when they
// reenter outgoing synchrounous calls on the same thread.
-template <typename Interface>
-class AssociatedBinding {
+template <typename Interface,
+ typename ImplRefTraits = RawPtrImplRefTraits<Interface>>
+class AssociatedBinding : public AssociatedBindingBase {
public:
+ using ImplPointerType = typename ImplRefTraits::PointerType;
+
// Constructs an incomplete associated binding that will use the
// implementation |impl|. It may be completed with a subsequent call to the
// |Bind| method. Does not take ownership of |impl|, which must outlive this
// object.
- explicit AssociatedBinding(Interface* impl) : impl_(impl) {
- stub_.set_sink(impl_);
- }
+ explicit AssociatedBinding(ImplPointerType impl) { stub_.set_sink(impl); }
// Constructs a completed associated binding of |impl|. The output |ptr_info|
- // should be passed through the message pipe endpoint referred to by
- // |associated_group| to setup the corresponding asssociated interface
- // pointer. |impl| must outlive this object.
- AssociatedBinding(Interface* impl,
+ // should be sent by another interface. |impl| must outlive this object.
+ AssociatedBinding(ImplPointerType impl,
AssociatedInterfacePtrInfo<Interface>* ptr_info,
- AssociatedGroup* associated_group,
scoped_refptr<base::SingleThreadTaskRunner> runner =
base::ThreadTaskRunnerHandle::Get())
- : AssociatedBinding(impl) {
- Bind(ptr_info, associated_group, std::move(runner));
+ : AssociatedBinding(std::move(impl)) {
+ Bind(ptr_info, std::move(runner));
}
// Constructs a completed associated binding of |impl|. |impl| must outlive
// the binding.
- AssociatedBinding(Interface* impl,
+ AssociatedBinding(ImplPointerType impl,
AssociatedInterfaceRequest<Interface> request,
scoped_refptr<base::SingleThreadTaskRunner> runner =
base::ThreadTaskRunnerHandle::Get())
- : AssociatedBinding(impl) {
+ : AssociatedBinding(std::move(impl)) {
Bind(std::move(request), std::move(runner));
}
~AssociatedBinding() {}
// Creates an associated inteface and sets up this object as the
- // implementation side. The output |ptr_info| should be passed through the
- // message pipe endpoint referred to by |associated_group| to setup the
- // corresponding asssociated interface pointer.
+ // implementation side. The output |ptr_info| should be sent by another
+ // interface.
void Bind(AssociatedInterfacePtrInfo<Interface>* ptr_info,
- AssociatedGroup* associated_group,
scoped_refptr<base::SingleThreadTaskRunner> runner =
base::ThreadTaskRunnerHandle::Get()) {
- AssociatedInterfaceRequest<Interface> request;
- associated_group->CreateAssociatedInterface(AssociatedGroup::WILL_PASS_PTR,
- ptr_info, &request);
+ auto request = MakeRequest(ptr_info);
+ ptr_info->set_version(Interface::Version_);
Bind(std::move(request), std::move(runner));
}
@@ -87,35 +137,10 @@ class AssociatedBinding {
void Bind(AssociatedInterfaceRequest<Interface> request,
scoped_refptr<base::SingleThreadTaskRunner> runner =
base::ThreadTaskRunnerHandle::Get()) {
- ScopedInterfaceEndpointHandle handle = request.PassHandle();
-
- DCHECK(handle.is_local())
- << "The AssociatedInterfaceRequest is supposed to be used at the "
- << "other side of the message pipe.";
-
- if (!handle.is_valid() || !handle.is_local()) {
- endpoint_client_.reset();
- return;
- }
-
- endpoint_client_.reset(new InterfaceEndpointClient(
- std::move(handle), &stub_,
- base::WrapUnique(new typename Interface::RequestValidator_()),
- Interface::HasSyncMethods_, std::move(runner)));
- endpoint_client_->set_connection_error_handler(
- base::Bind(&AssociatedBinding::RunConnectionErrorHandler,
- base::Unretained(this)));
-
- stub_.serialization_context()->group_controller =
- endpoint_client_->group_controller();
- }
-
- // Closes the associated interface. Puts this object into a state where it can
- // be rebound.
- void Close() {
- DCHECK(endpoint_client_);
- endpoint_client_.reset();
- connection_error_handler_.Reset();
+ BindImpl(request.PassHandle(), &stub_,
+ base::WrapUnique(new typename Interface::RequestValidator_()),
+ Interface::HasSyncMethods_, std::move(runner),
+ Interface::Version_);
}
// Unbinds and returns the associated interface request so it can be
@@ -128,44 +153,15 @@ class AssociatedBinding {
request.Bind(endpoint_client_->PassHandle());
endpoint_client_.reset();
- connection_error_handler_.Reset();
return request;
}
- // Sets an error handler that will be called if a connection error occurs.
- //
- // This method may only be called after this AssociatedBinding has been bound
- // to a message pipe. The error handler will be reset when this
- // AssociatedBinding is unbound or closed.
- void set_connection_error_handler(const base::Closure& error_handler) {
- DCHECK(is_bound());
- connection_error_handler_ = error_handler;
- }
-
// Returns the interface implementation that was previously specified.
- Interface* impl() { return impl_; }
-
- // Indicates whether the associated binding has been completed.
- bool is_bound() const { return !!endpoint_client_; }
-
- // Returns the associated group that this object belongs to. Returns null if
- // the object is not bound.
- AssociatedGroup* associated_group() {
- return endpoint_client_ ? endpoint_client_->associated_group() : nullptr;
- }
+ Interface* impl() { return ImplRefTraits::GetRawPointer(&stub_.sink()); }
private:
- void RunConnectionErrorHandler() {
- if (!connection_error_handler_.is_null())
- connection_error_handler_.Run();
- }
-
- std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
-
- typename Interface::Stub_ stub_;
- Interface* impl_;
- base::Closure connection_error_handler_;
+ typename Interface::template Stub_<ImplRefTraits> stub_;
DISALLOW_COPY_AND_ASSIGN(AssociatedBinding);
};
diff --git a/mojo/public/cpp/bindings/associated_group.h b/mojo/public/cpp/bindings/associated_group.h
index 836c0d6..14e78ec 100644
--- a/mojo/public/cpp/bindings/associated_group.h
+++ b/mojo/public/cpp/bindings/associated_group.h
@@ -5,11 +5,9 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_GROUP_H_
#define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_GROUP_H_
-#include <utility>
-
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
-#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
-#include "mojo/public/cpp/bindings/associated_interface_request.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
namespace mojo {
@@ -17,71 +15,34 @@ namespace mojo {
class AssociatedGroupController;
// AssociatedGroup refers to all the interface endpoints running at one end of a
-// message pipe. It is used to create associated interfaces for that message
-// pipe.
+// message pipe.
// It is thread safe and cheap to make copies.
-class AssociatedGroup {
+class MOJO_CPP_BINDINGS_EXPORT AssociatedGroup {
public:
- // Configuration used by CreateAssociatedInterface(). Please see the comments
- // of that method for more details.
- enum AssociatedInterfaceConfig { WILL_PASS_PTR, WILL_PASS_REQUEST };
-
AssociatedGroup();
- AssociatedGroup(const AssociatedGroup& other);
- ~AssociatedGroup();
-
- AssociatedGroup& operator=(const AssociatedGroup& other);
+ explicit AssociatedGroup(scoped_refptr<AssociatedGroupController> controller);
- // |config| indicates whether |ptr_info| or |request| will be sent to the
- // remote side of the message pipe.
- //
- // NOTE: If |config| is |WILL_PASS_REQUEST|, you will want to bind |ptr_info|
- // to a local AssociatedInterfacePtr to make calls. However, there is one
- // restriction: the pointer should NOT be used to make calls before |request|
- // is sent. Violating that will cause the message pipe to be closed. On the
- // other hand, as soon as |request| is sent, the pointer is usable. There is
- // no need to wait until |request| is bound to an implementation at the remote
- // side.
- template <typename T>
- void CreateAssociatedInterface(
- AssociatedInterfaceConfig config,
- AssociatedInterfacePtrInfo<T>* ptr_info,
- AssociatedInterfaceRequest<T>* request) {
- ScopedInterfaceEndpointHandle local;
- ScopedInterfaceEndpointHandle remote;
- CreateEndpointHandlePair(&local, &remote);
+ explicit AssociatedGroup(const ScopedInterfaceEndpointHandle& handle);
- if (!local.is_valid() || !remote.is_valid()) {
- *ptr_info = AssociatedInterfacePtrInfo<T>();
- *request = AssociatedInterfaceRequest<T>();
- return;
- }
+ AssociatedGroup(const AssociatedGroup& other);
- if (config == WILL_PASS_PTR) {
- ptr_info->set_handle(std::move(remote));
+ ~AssociatedGroup();
- // The implementation is local, therefore set the version according to
- // the interface definition that this code is built against.
- ptr_info->set_version(T::Version_);
- request->Bind(std::move(local));
- } else {
- ptr_info->set_handle(std::move(local));
+ AssociatedGroup& operator=(const AssociatedGroup& other);
- // The implementation is remote, we don't know about its actual version
- // yet.
- ptr_info->set_version(0u);
- request->Bind(std::move(remote));
- }
- }
+ // The return value of this getter if this object is initialized with a
+ // ScopedInterfaceEndpointHandle:
+ // - If the handle is invalid, the return value will always be null.
+ // - If the handle is valid and non-pending, the return value will be
+ // non-null and remain unchanged even if the handle is later reset.
+ // - If the handle is pending asssociation, the return value will initially
+ // be null, change to non-null when/if the handle is associated, and
+ // remain unchanged ever since.
+ AssociatedGroupController* GetController();
private:
- friend class AssociatedGroupController;
-
- void CreateEndpointHandlePair(
- ScopedInterfaceEndpointHandle* local_endpoint,
- ScopedInterfaceEndpointHandle* remote_endpoint);
-
+ base::Callback<AssociatedGroupController*()> controller_getter_;
scoped_refptr<AssociatedGroupController> controller_;
};
diff --git a/mojo/public/cpp/bindings/associated_group_controller.h b/mojo/public/cpp/bindings/associated_group_controller.h
index 0ab8253..d33c277 100644
--- a/mojo/public/cpp/bindings/associated_group_controller.h
+++ b/mojo/public/cpp/bindings/associated_group_controller.h
@@ -9,41 +9,47 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/ref_counted_delete_on_message_loop.h"
+#include "base/optional.h"
#include "base/single_thread_task_runner.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
+#include "mojo/public/cpp/bindings/disconnect_reason.h"
#include "mojo/public/cpp/bindings/interface_id.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
namespace mojo {
-class AssociatedGroup;
class InterfaceEndpointClient;
class InterfaceEndpointController;
-// An internal interface used to manage endpoints within an associated group.
-class AssociatedGroupController :
- public base::RefCountedDeleteOnMessageLoop<AssociatedGroupController> {
+// An internal interface used to manage endpoints within an associated group,
+// which corresponds to one end of a message pipe.
+class MOJO_CPP_BINDINGS_EXPORT AssociatedGroupController
+ : public base::RefCountedThreadSafe<AssociatedGroupController> {
public:
- explicit AssociatedGroupController(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner);
-
- // Creates a pair of interface endpoint handles. The method generates a new
- // interface ID and assigns it to the two handles. |local_endpoint| is used
- // locally; while |remote_endpoint| is sent over the message pipe.
- virtual void CreateEndpointHandlePair(
- ScopedInterfaceEndpointHandle* local_endpoint,
- ScopedInterfaceEndpointHandle* remote_endpoint) = 0;
+ // Associates an interface with this AssociatedGroupController's message pipe.
+ // It takes ownership of |handle_to_send| and returns an interface ID that
+ // could be sent by any endpoints within the same associated group.
+ // If |handle_to_send| is not in pending association state, it returns
+ // kInvalidInterfaceId. Otherwise, the peer handle of |handle_to_send| joins
+ // the associated group and is no longer pending.
+ virtual InterfaceId AssociateInterface(
+ ScopedInterfaceEndpointHandle handle_to_send) = 0;
// Creates an interface endpoint handle from a given interface ID. The handle
- // is used locally.
+ // 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
// interface ID from the message pipe.
+ //
+ // On failure, the method returns an invalid handle. Usually that is because
+ // the ID has already been used to create a handle.
virtual ScopedInterfaceEndpointHandle CreateLocalEndpointHandle(
InterfaceId id) = 0;
// Closes an interface endpoint handle.
- virtual void CloseEndpointHandle(InterfaceId id, bool is_local) = 0;
+ virtual void CloseEndpointHandle(
+ InterfaceId id,
+ const base::Optional<DisconnectReason>& reason) = 0;
// Attaches a client to the specified endpoint to send and receive messages.
// The returned object is still owned by the controller. It must only be used
@@ -63,21 +69,23 @@ class AssociatedGroupController :
// and notifies all interfaces running on this pipe.
virtual void RaiseError() = 0;
- std::unique_ptr<AssociatedGroup> CreateAssociatedGroup();
-
protected:
- friend class base::RefCountedDeleteOnMessageLoop<AssociatedGroupController>;
- friend class base::DeleteHelper<AssociatedGroupController>;
+ friend class base::RefCountedThreadSafe<AssociatedGroupController>;
- // Creates a new ScopedInterfaceEndpointHandle associated with this
- // controller.
+ // Creates a new ScopedInterfaceEndpointHandle within this associated group.
ScopedInterfaceEndpointHandle CreateScopedInterfaceEndpointHandle(
- InterfaceId id,
- bool is_local);
+ InterfaceId id);
- virtual ~AssociatedGroupController();
+ // Notifies that the interface represented by |handle_to_send| and its peer
+ // has been associated with this AssociatedGroupController's message pipe, and
+ // |handle_to_send|'s peer has joined this associated group. (Note: it is the
+ // peer who has joined the associated group; |handle_to_send| will be sent to
+ // the remote side.)
+ // Returns false if |handle_to_send|'s peer has closed.
+ bool NotifyAssociation(ScopedInterfaceEndpointHandle* handle_to_send,
+ InterfaceId id);
- DISALLOW_COPY_AND_ASSIGN(AssociatedGroupController);
+ virtual ~AssociatedGroupController();
};
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/associated_interface_ptr.h b/mojo/public/cpp/bindings/associated_interface_ptr.h
index 10494ce..8e66f4e 100644
--- a/mojo/public/cpp/bindings/associated_interface_ptr.h
+++ b/mojo/public/cpp/bindings/associated_interface_ptr.h
@@ -6,6 +6,8 @@
#define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
#include <stdint.h>
+
+#include <string>
#include <utility>
#include "base/callback.h"
@@ -14,10 +16,12 @@
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "mojo/public/cpp/bindings/associated_group.h"
#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
#include "mojo/public/cpp/bindings/associated_interface_request.h"
+#include "mojo/public/cpp/bindings/connection_error_callback.h"
#include "mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h"
+#include "mojo/public/cpp/bindings/lib/multiplex_router.h"
+#include "mojo/public/cpp/system/message_pipe.h"
namespace mojo {
@@ -26,6 +30,9 @@ namespace mojo {
template <typename Interface>
class AssociatedInterfacePtr {
public:
+ using InterfaceType = Interface;
+ using PtrInfoType = AssociatedInterfacePtrInfo<Interface>;
+
// Constructs an unbound AssociatedInterfacePtr.
AssociatedInterfacePtr() {}
AssociatedInterfacePtr(decltype(nullptr)) {}
@@ -58,20 +65,16 @@ class AssociatedInterfacePtr {
// multiple task runners to a single thread for the purposes of task
// scheduling.
//
- // NOTE: Please see the comments of
- // AssociatedGroup.CreateAssociatedInterface() about when you can use this
- // object to make calls.
+ // NOTE: The corresponding AssociatedInterfaceRequest must be sent over
+ // another interface before using this object to make calls. Please see the
+ // comments of MakeRequest(AssociatedInterfacePtr<Interface>*) for more
+ // details.
void Bind(AssociatedInterfacePtrInfo<Interface> info,
scoped_refptr<base::SingleThreadTaskRunner> runner =
base::ThreadTaskRunnerHandle::Get()) {
reset();
- bool is_local = info.handle().is_local();
-
- DCHECK(is_local) << "The AssociatedInterfacePtrInfo is supposed to be used "
- "at the other side of the message pipe.";
-
- if (info.is_valid() && is_local)
+ if (info.is_valid())
internal_state_.Bind(std::move(info), std::move(runner));
}
@@ -86,9 +89,6 @@ class AssociatedInterfacePtr {
// Returns the version number of the interface that the remote side supports.
uint32_t version() const { return internal_state_.version(); }
- // Returns the internal interface ID of this associated interface.
- uint32_t interface_id() const { return internal_state_.interface_id(); }
-
// Queries the max version that the remote side supports. On completion, the
// result will be returned as the input of |callback|. The version number of
// this object will also be updated.
@@ -107,6 +107,12 @@ class AssociatedInterfacePtr {
internal_state_.RequireVersion(version);
}
+ // Sends a message on the underlying message pipe and runs the current
+ // message loop until its response is received. This can be used in tests to
+ // verify that no message was sent on a message pipe in response to some
+ // stimulus.
+ void FlushForTesting() { internal_state_.FlushForTesting(); }
+
// Closes the associated interface (if any) and returns the pointer to the
// unbound state.
void reset() {
@@ -114,6 +120,13 @@ class AssociatedInterfacePtr {
internal_state_.Swap(&doomed);
}
+ // Similar to the method above, but also specifies a disconnect reason.
+ void ResetWithReason(uint32_t custom_reason, const std::string& description) {
+ if (internal_state_.is_bound())
+ internal_state_.CloseWithReason(custom_reason, description);
+ reset();
+ }
+
// Indicates whether an error has been encountered. If true, method calls made
// on this interface will be dropped (and may already have been dropped).
bool encountered_error() const { return internal_state_.encountered_error(); }
@@ -126,6 +139,11 @@ class AssociatedInterfacePtr {
internal_state_.set_connection_error_handler(error_handler);
}
+ void set_connection_error_with_reason_handler(
+ const ConnectionErrorWithReasonCallback& error_handler) {
+ internal_state_.set_connection_error_with_reason_handler(error_handler);
+ }
+
// Unbinds and returns the associated interface pointer information which
// could be used to setup an AssociatedInterfacePtr again. This method may be
// used to move the proxy to a different thread.
@@ -141,12 +159,6 @@ class AssociatedInterfacePtr {
return state.PassInterface();
}
- // Returns the associated group that this object belongs to. Returns null if
- // the object is not bound.
- AssociatedGroup* associated_group() {
- return internal_state_.associated_group();
- }
-
// DO NOT USE. Exposed only for internal use and for testing.
internal::AssociatedInterfacePtrState<Interface>* internal_state() {
return &internal_state_;
@@ -179,30 +191,95 @@ class AssociatedInterfacePtr {
DISALLOW_COPY_AND_ASSIGN(AssociatedInterfacePtr);
};
-// Creates an associated interface. The output |ptr| should be used locally
-// while the returned request should be passed through the message pipe endpoint
-// referred to by |associated_group| to setup the corresponding asssociated
-// interface implementation at the remote side.
+// Creates an associated interface. The returned request is supposed to be sent
+// over another interface (either associated or non-associated).
//
-// NOTE: |ptr| should NOT be used to make calls before the request is sent.
-// Violating that will cause the message pipe to be closed. On the other hand,
-// as soon as the request is sent, |ptr| is usable. There is no need to wait
-// until the request is bound to an implementation at the remote side.
+// NOTE: |ptr| must NOT be used to make calls before the request is sent.
+// Violating that will lead to crash. On the other hand, as soon as the request
+// is sent, |ptr| is usable. There is no need to wait until the request is bound
+// to an implementation at the remote side.
template <typename Interface>
-AssociatedInterfaceRequest<Interface> GetProxy(
+AssociatedInterfaceRequest<Interface> MakeRequest(
AssociatedInterfacePtr<Interface>* ptr,
- AssociatedGroup* group,
scoped_refptr<base::SingleThreadTaskRunner> runner =
base::ThreadTaskRunnerHandle::Get()) {
- AssociatedInterfaceRequest<Interface> request;
AssociatedInterfacePtrInfo<Interface> ptr_info;
- group->CreateAssociatedInterface(AssociatedGroup::WILL_PASS_REQUEST,
- &ptr_info, &request);
-
+ auto request = MakeRequest(&ptr_info);
ptr->Bind(std::move(ptr_info), std::move(runner));
return request;
}
+// Creates an associated interface. One of the two endpoints is supposed to be
+// sent over another interface (either associated or non-associated); while the
+// other is used locally.
+//
+// NOTE: If |ptr_info| is used locally and bound to an AssociatedInterfacePtr,
+// the interface pointer must NOT be used to make calls before the request is
+// sent. Please see NOTE of the previous function for more details.
+template <typename Interface>
+AssociatedInterfaceRequest<Interface> MakeRequest(
+ AssociatedInterfacePtrInfo<Interface>* ptr_info) {
+ ScopedInterfaceEndpointHandle handle0;
+ ScopedInterfaceEndpointHandle handle1;
+ ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&handle0,
+ &handle1);
+
+ ptr_info->set_handle(std::move(handle0));
+ ptr_info->set_version(0);
+
+ AssociatedInterfaceRequest<Interface> request;
+ request.Bind(std::move(handle1));
+ return request;
+}
+
+// Like |GetProxy|, but the interface is never associated with any other
+// interface. The returned request can be bound directly to the corresponding
+// associated interface implementation, without first passing it through a
+// message pipe endpoint.
+//
+// This function has two main uses:
+//
+// * In testing, where the returned request is bound to e.g. a mock and there
+// are no other interfaces involved.
+//
+// * When discarding messages sent on an interface, which can be done by
+// discarding the returned request.
+template <typename Interface>
+AssociatedInterfaceRequest<Interface> GetIsolatedProxy(
+ AssociatedInterfacePtr<Interface>* ptr) {
+ MessagePipe pipe;
+ scoped_refptr<internal::MultiplexRouter> router0 =
+ new internal::MultiplexRouter(std::move(pipe.handle0),
+ internal::MultiplexRouter::MULTI_INTERFACE,
+ false, base::ThreadTaskRunnerHandle::Get());
+ scoped_refptr<internal::MultiplexRouter> router1 =
+ new internal::MultiplexRouter(std::move(pipe.handle1),
+ internal::MultiplexRouter::MULTI_INTERFACE,
+ true, base::ThreadTaskRunnerHandle::Get());
+
+ ScopedInterfaceEndpointHandle endpoint0, endpoint1;
+ ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&endpoint0,
+ &endpoint1);
+ InterfaceId id = router1->AssociateInterface(std::move(endpoint0));
+ endpoint0 = router0->CreateLocalEndpointHandle(id);
+
+ ptr->Bind(AssociatedInterfacePtrInfo<Interface>(std::move(endpoint0),
+ Interface::Version_));
+
+ AssociatedInterfaceRequest<Interface> request;
+ request.Bind(std::move(endpoint1));
+ return request;
+}
+
+// Creates an associated interface proxy in its own AssociatedGroup.
+// TODO(yzshen): Rename GetIsolatedProxy() to MakeIsolatedRequest(), and change
+// all callsites of this function to directly use that.
+template <typename Interface>
+AssociatedInterfaceRequest<Interface> MakeRequestForTesting(
+ AssociatedInterfacePtr<Interface>* ptr) {
+ return GetIsolatedProxy(ptr);
+}
+
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
diff --git a/mojo/public/cpp/bindings/associated_interface_ptr_info.h b/mojo/public/cpp/bindings/associated_interface_ptr_info.h
index bfb3297..3c6ca54 100644
--- a/mojo/public/cpp/bindings/associated_interface_ptr_info.h
+++ b/mojo/public/cpp/bindings/associated_interface_ptr_info.h
@@ -20,6 +20,7 @@ template <typename Interface>
class AssociatedInterfacePtrInfo {
public:
AssociatedInterfacePtrInfo() : version_(0u) {}
+ AssociatedInterfacePtrInfo(std::nullptr_t) : version_(0u) {}
AssociatedInterfacePtrInfo(AssociatedInterfacePtrInfo&& other)
: handle_(std::move(other.handle_)), version_(other.version_) {
diff --git a/mojo/public/cpp/bindings/associated_interface_request.h b/mojo/public/cpp/bindings/associated_interface_request.h
index 30fcd16..c37636c 100644
--- a/mojo/public/cpp/bindings/associated_interface_request.h
+++ b/mojo/public/cpp/bindings/associated_interface_request.h
@@ -5,6 +5,7 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_REQUEST_H_
#define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_REQUEST_H_
+#include <string>
#include <utility>
#include "base/macros.h"
@@ -64,6 +65,10 @@ class AssociatedInterfaceRequest {
return !is_pending() && !other.is_pending();
}
+ void ResetWithReason(uint32_t custom_reason, const std::string& description) {
+ handle_.ResetWithReason(custom_reason, description);
+ }
+
private:
ScopedInterfaceEndpointHandle handle_;
diff --git a/mojo/public/cpp/bindings/binding.h b/mojo/public/cpp/bindings/binding.h
index 8c9ee2f..1da331b 100644
--- a/mojo/public/cpp/bindings/binding.h
+++ b/mojo/public/cpp/bindings/binding.h
@@ -5,6 +5,7 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_BINDING_H_
#define MOJO_PUBLIC_CPP_BINDINGS_BINDING_H_
+#include <string>
#include <utility>
#include "base/callback_forward.h"
@@ -12,15 +13,17 @@
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "mojo/public/cpp/bindings/connection_error_callback.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "mojo/public/cpp/bindings/interface_ptr_info.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/bindings/lib/binding_state.h"
+#include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h"
#include "mojo/public/cpp/system/core.h"
namespace mojo {
-class AssociatedGroup;
+class MessageReceiver;
// Represents the binding of an interface implementation to a message pipe.
// When the |Binding| object is destroyed, the binding between the message pipe
@@ -63,21 +66,24 @@ class AssociatedGroup;
// single thread for the purposes of task scheduling. Please note that incoming
// synchrounous method calls may not be run from this task runner, when they
// reenter outgoing synchrounous calls on the same thread.
-template <typename Interface>
+template <typename Interface,
+ typename ImplRefTraits = RawPtrImplRefTraits<Interface>>
class Binding {
public:
+ using ImplPointerType = typename ImplRefTraits::PointerType;
+
// Constructs an incomplete binding that will use the implementation |impl|.
// The binding may be completed with a subsequent call to the |Bind| method.
// Does not take ownership of |impl|, which must outlive the binding.
- explicit Binding(Interface* impl) : internal_state_(impl) {}
+ explicit Binding(ImplPointerType impl) : internal_state_(std::move(impl)) {}
// Constructs a completed binding of message pipe |handle| to implementation
// |impl|. Does not take ownership of |impl|, which must outlive the binding.
- Binding(Interface* impl,
+ Binding(ImplPointerType impl,
ScopedMessagePipeHandle handle,
scoped_refptr<base::SingleThreadTaskRunner> runner =
base::ThreadTaskRunnerHandle::Get())
- : Binding(impl) {
+ : Binding(std::move(impl)) {
Bind(std::move(handle), std::move(runner));
}
@@ -86,22 +92,22 @@ class Binding {
// pass |ptr| on to the client of the service. Does not take ownership of any
// of the parameters. |impl| must outlive the binding. |ptr| only needs to
// last until the constructor returns.
- Binding(Interface* impl,
+ Binding(ImplPointerType impl,
InterfacePtr<Interface>* ptr,
scoped_refptr<base::SingleThreadTaskRunner> runner =
base::ThreadTaskRunnerHandle::Get())
- : Binding(impl) {
+ : Binding(std::move(impl)) {
Bind(ptr, std::move(runner));
}
// Constructs a completed binding of |impl| to the message pipe endpoint in
// |request|, taking ownership of the endpoint. Does not take ownership of
// |impl|, which must outlive the binding.
- Binding(Interface* impl,
+ Binding(ImplPointerType impl,
InterfaceRequest<Interface> request,
scoped_refptr<base::SingleThreadTaskRunner> runner =
base::ThreadTaskRunnerHandle::Get())
- : Binding(impl) {
+ : Binding(std::move(impl)) {
Bind(request.PassMessagePipe(), std::move(runner));
}
@@ -152,6 +158,14 @@ class Binding {
Bind(request.PassMessagePipe(), std::move(runner));
}
+ // Adds a message filter to be notified of each incoming message before
+ // dispatch. If a filter returns |false| from Accept(), the message is not
+ // dispatched and the pipe is closed. Filters cannot be removed.
+ void AddFilter(std::unique_ptr<MessageReceiver> filter) {
+ DCHECK(is_bound());
+ internal_state_.AddFilter(std::move(filter));
+ }
+
// Whether there are any associated interfaces running on the pipe currently.
bool HasAssociatedInterfaces() const {
return internal_state_.HasAssociatedInterfaces();
@@ -189,6 +203,11 @@ class Binding {
// state where it can be rebound to a new pipe.
void Close() { internal_state_.Close(); }
+ // Similar to the method above, but also specifies a disconnect reason.
+ void CloseWithReason(uint32_t custom_reason, const std::string& description) {
+ internal_state_.CloseWithReason(custom_reason, description);
+ }
+
// Unbinds the underlying pipe from this binding and returns it so it can be
// used in another context, such as on another thread or with a different
// implementation. Put this object into a state where it can be rebound to a
@@ -217,6 +236,12 @@ class Binding {
internal_state_.set_connection_error_handler(error_handler);
}
+ void set_connection_error_with_reason_handler(
+ const ConnectionErrorWithReasonCallback& error_handler) {
+ DCHECK(is_bound());
+ internal_state_.set_connection_error_with_reason_handler(error_handler);
+ }
+
// Returns the interface implementation that was previously specified. Caller
// does not take ownership.
Interface* impl() { return internal_state_.impl(); }
@@ -231,20 +256,17 @@ class Binding {
// transferred to the caller.
MessagePipeHandle handle() const { return internal_state_.handle(); }
- // Returns the associated group that this object belongs to. Returns null if:
- // - this object is not bound; or
- // - the interface doesn't have methods to pass associated interface
- // pointers or requests.
- AssociatedGroup* associated_group() {
- return internal_state_.associated_group();
- }
+ // Sends a no-op message on the underlying message pipe and runs the current
+ // message loop until its response is received. This can be used in tests to
+ // verify that no message was sent on a message pipe in response to some
+ // stimulus.
+ void FlushForTesting() { internal_state_.FlushForTesting(); }
// Exposed for testing, should not generally be used.
void EnableTestingMode() { internal_state_.EnableTestingMode(); }
private:
- internal::BindingState<Interface, Interface::PassesAssociatedKinds_>
- internal_state_;
+ internal::BindingState<Interface, ImplRefTraits> internal_state_;
DISALLOW_COPY_AND_ASSIGN(Binding);
};
diff --git a/mojo/public/cpp/bindings/binding_set.h b/mojo/public/cpp/bindings/binding_set.h
index b1baca6..919f9c0 100644
--- a/mojo/public/cpp/bindings/binding_set.h
+++ b/mojo/public/cpp/bindings/binding_set.h
@@ -5,111 +5,263 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_
#define MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_
-#include <algorithm>
+#include <string>
#include <utility>
-#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
+#include "base/memory/ptr_util.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/connection_error_callback.h"
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/message.h"
namespace mojo {
-// Use this class to manage a set of bindings, which are automatically destroyed
-// and removed from the set when the pipe they are bound to is disconnected.
-template <typename Interface>
-class BindingSet {
+template <typename BindingType>
+struct BindingSetTraits;
+
+template <typename Interface, typename ImplRefTraits>
+struct BindingSetTraits<Binding<Interface, ImplRefTraits>> {
+ using ProxyType = InterfacePtr<Interface>;
+ using RequestType = InterfaceRequest<Interface>;
+ using BindingType = Binding<Interface, ImplRefTraits>;
+ using ImplPointerType = typename BindingType::ImplPointerType;
+
+ static RequestType MakeRequest(ProxyType* proxy) {
+ return mojo::MakeRequest(proxy);
+ }
+};
+
+using BindingId = size_t;
+
+template <typename ContextType>
+struct BindingSetContextTraits {
+ using Type = ContextType;
+
+ static constexpr bool SupportsContext() { return true; }
+};
+
+template <>
+struct BindingSetContextTraits<void> {
+ // NOTE: This choice of Type only matters insofar as it affects the size of
+ // the |context_| field of a BindingSetBase::Entry with void context. The
+ // context value is never used in this case.
+ using Type = bool;
+
+ static constexpr bool SupportsContext() { return false; }
+};
+
+// Generic definition used for BindingSet and AssociatedBindingSet to own a
+// collection of bindings which point to the same implementation.
+//
+// If |ContextType| is non-void, then every added binding must include a context
+// value of that type, and |dispatch_context()| will return that value during
+// the extent of any message dispatch targeting that specific binding.
+template <typename Interface, typename BindingType, typename ContextType>
+class BindingSetBase {
public:
- BindingSet() {}
- ~BindingSet() { CloseAllBindings(); }
+ using ContextTraits = BindingSetContextTraits<ContextType>;
+ using Context = typename ContextTraits::Type;
+ using PreDispatchCallback = base::Callback<void(const Context&)>;
+ using Traits = BindingSetTraits<BindingType>;
+ using ProxyType = typename Traits::ProxyType;
+ using RequestType = typename Traits::RequestType;
+ using ImplPointerType = typename Traits::ImplPointerType;
+
+ BindingSetBase() {}
void set_connection_error_handler(const base::Closure& error_handler) {
error_handler_ = error_handler;
+ error_with_reason_handler_.Reset();
}
- void AddBinding(Interface* impl, InterfaceRequest<Interface> request) {
- auto binding = new Element(impl, std::move(request));
- binding->set_connection_error_handler(
- base::Bind(&BindingSet::OnConnectionError, base::Unretained(this)));
- bindings_.push_back(binding->GetWeakPtr());
+ void set_connection_error_with_reason_handler(
+ const ConnectionErrorWithReasonCallback& error_handler) {
+ error_with_reason_handler_ = error_handler;
+ error_handler_.Reset();
}
- // Returns an InterfacePtr bound to one end of a pipe whose other end is
- // bound to |this|.
- InterfacePtr<Interface> CreateInterfacePtrAndBind(Interface* impl) {
- InterfacePtr<Interface> interface_ptr;
- AddBinding(impl, GetProxy(&interface_ptr));
- return interface_ptr;
+ // Sets a callback to be invoked immediately before dispatching any message or
+ // error received by any of the bindings in the set. This may only be used
+ // with a non-void |ContextType|.
+ void set_pre_dispatch_handler(const PreDispatchCallback& handler) {
+ static_assert(ContextTraits::SupportsContext(),
+ "Pre-dispatch handler usage requires non-void context type.");
+ pre_dispatch_handler_ = handler;
}
- void CloseAllBindings() {
- for (const auto& it : bindings_) {
- if (it) {
- it->Close();
- delete it.get();
- }
- }
- bindings_.clear();
+ // Adds a new binding to the set which binds |request| to |impl| with no
+ // additional context.
+ BindingId AddBinding(ImplPointerType impl, RequestType request) {
+ static_assert(!ContextTraits::SupportsContext(),
+ "Context value required for non-void context type.");
+ return AddBindingImpl(std::move(impl), std::move(request), false);
+ }
+
+ // Adds a new binding associated with |context|.
+ BindingId AddBinding(ImplPointerType impl,
+ RequestType request,
+ Context context) {
+ static_assert(ContextTraits::SupportsContext(),
+ "Context value unsupported for void context type.");
+ return AddBindingImpl(std::move(impl), std::move(request),
+ std::move(context));
+ }
+
+ // Removes a binding from the set. Note that this is safe to call even if the
+ // binding corresponding to |id| has already been removed.
+ //
+ // Returns |true| if the binding was removed and |false| if it didn't exist.
+ bool RemoveBinding(BindingId id) {
+ auto it = bindings_.find(id);
+ if (it == bindings_.end())
+ return false;
+ bindings_.erase(it);
+ return true;
+ }
+
+ // Returns a proxy bound to one end of a pipe whose other end is bound to
+ // |this|. If |id_storage| is not null, |*id_storage| will be set to the ID
+ // of the added binding.
+ ProxyType CreateInterfacePtrAndBind(ImplPointerType impl,
+ BindingId* id_storage = nullptr) {
+ ProxyType proxy;
+ BindingId id = AddBinding(std::move(impl), Traits::MakeRequest(&proxy));
+ if (id_storage)
+ *id_storage = id;
+ return proxy;
}
+ void CloseAllBindings() { bindings_.clear(); }
+
bool empty() const { return bindings_.empty(); }
+ // Implementations may call this when processing a dispatched message or
+ // error. During the extent of message or error dispatch, this will return the
+ // context associated with the specific binding which received the message or
+ // error. Use AddBinding() to associated a context with a specific binding.
+ const Context& dispatch_context() const {
+ static_assert(ContextTraits::SupportsContext(),
+ "dispatch_context() requires non-void context type.");
+ DCHECK(dispatch_context_);
+ return *dispatch_context_;
+ }
+
+ void FlushForTesting() {
+ for (auto& binding : bindings_)
+ binding.second->FlushForTesting();
+ }
+
private:
- class Element {
+ friend class Entry;
+
+ class Entry {
public:
- Element(Interface* impl, InterfaceRequest<Interface> request)
- : binding_(impl, std::move(request)), weak_ptr_factory_(this) {
- binding_.set_connection_error_handler(
- base::Bind(&Element::OnConnectionError, base::Unretained(this)));
+ Entry(ImplPointerType impl,
+ RequestType request,
+ BindingSetBase* binding_set,
+ BindingId binding_id,
+ Context context)
+ : binding_(std::move(impl), std::move(request)),
+ binding_set_(binding_set),
+ binding_id_(binding_id),
+ context_(std::move(context)) {
+ if (ContextTraits::SupportsContext())
+ binding_.AddFilter(base::MakeUnique<DispatchFilter>(this));
+ binding_.set_connection_error_with_reason_handler(
+ base::Bind(&Entry::OnConnectionError, base::Unretained(this)));
}
- ~Element() {}
+ void FlushForTesting() { binding_.FlushForTesting(); }
- void set_connection_error_handler(const base::Closure& error_handler) {
- error_handler_ = error_handler;
- }
+ private:
+ class DispatchFilter : public MessageReceiver {
+ public:
+ explicit DispatchFilter(Entry* entry) : entry_(entry) {}
+ ~DispatchFilter() override {}
- base::WeakPtr<Element> GetWeakPtr() {
- return weak_ptr_factory_.GetWeakPtr();
- }
+ private:
+ // MessageReceiver:
+ bool Accept(Message* message) override {
+ entry_->WillDispatch();
+ return true;
+ }
- void Close() { binding_.Close(); }
+ Entry* entry_;
- void OnConnectionError() {
- base::Closure error_handler = error_handler_;
- delete this;
- if (!error_handler.is_null())
- error_handler.Run();
+ DISALLOW_COPY_AND_ASSIGN(DispatchFilter);
+ };
+
+ void WillDispatch() {
+ DCHECK(ContextTraits::SupportsContext());
+ binding_set_->SetDispatchContext(&context_);
}
- private:
- Binding<Interface> binding_;
- base::Closure error_handler_;
- base::WeakPtrFactory<Element> weak_ptr_factory_;
+ void OnConnectionError(uint32_t custom_reason,
+ const std::string& description) {
+ if (ContextTraits::SupportsContext())
+ WillDispatch();
+ binding_set_->OnConnectionError(binding_id_, custom_reason, description);
+ }
- DISALLOW_COPY_AND_ASSIGN(Element);
+ BindingType binding_;
+ BindingSetBase* const binding_set_;
+ const BindingId binding_id_;
+ Context const context_;
+
+ DISALLOW_COPY_AND_ASSIGN(Entry);
};
- void OnConnectionError() {
- // Clear any deleted bindings.
- bindings_.erase(std::remove_if(bindings_.begin(), bindings_.end(),
- [](const base::WeakPtr<Element>& p) {
- return p.get() == nullptr;
- }),
- bindings_.end());
+ void SetDispatchContext(const Context* context) {
+ DCHECK(ContextTraits::SupportsContext());
+ dispatch_context_ = context;
+ if (!pre_dispatch_handler_.is_null())
+ pre_dispatch_handler_.Run(*context);
+ }
+
+ BindingId AddBindingImpl(ImplPointerType impl,
+ RequestType request,
+ Context context) {
+ BindingId id = next_binding_id_++;
+ DCHECK_GE(next_binding_id_, 0u);
+ auto entry = base::MakeUnique<Entry>(std::move(impl), std::move(request),
+ this, id, std::move(context));
+ bindings_.insert(std::make_pair(id, std::move(entry)));
+ return id;
+ }
+
+ void OnConnectionError(BindingId id,
+ uint32_t custom_reason,
+ const std::string& description) {
+ auto it = bindings_.find(id);
+ DCHECK(it != bindings_.end());
+
+ // We keep the Entry alive throughout error dispatch.
+ std::unique_ptr<Entry> entry = std::move(it->second);
+ bindings_.erase(it);
if (!error_handler_.is_null())
error_handler_.Run();
+ else if (!error_with_reason_handler_.is_null())
+ error_with_reason_handler_.Run(custom_reason, description);
}
base::Closure error_handler_;
- std::vector<base::WeakPtr<Element>> bindings_;
+ ConnectionErrorWithReasonCallback error_with_reason_handler_;
+ PreDispatchCallback pre_dispatch_handler_;
+ BindingId next_binding_id_ = 0;
+ std::map<BindingId, std::unique_ptr<Entry>> bindings_;
+ const Context* dispatch_context_ = nullptr;
- DISALLOW_COPY_AND_ASSIGN(BindingSet);
+ DISALLOW_COPY_AND_ASSIGN(BindingSetBase);
};
+template <typename Interface, typename ContextType = void>
+using BindingSet = BindingSetBase<Interface, Binding<Interface>, ContextType>;
+
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_
diff --git a/mojo/public/cpp/bindings/bindings_export.h b/mojo/public/cpp/bindings/bindings_export.h
new file mode 100644
index 0000000..9fd7a27
--- /dev/null
+++ b/mojo/public/cpp/bindings/bindings_export.h
@@ -0,0 +1,34 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_BINDINGS_EXPORT_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_BINDINGS_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(WIN32)
+
+#if defined(MOJO_CPP_BINDINGS_IMPLEMENTATION)
+#define MOJO_CPP_BINDINGS_EXPORT __declspec(dllexport)
+#else
+#define MOJO_CPP_BINDINGS_EXPORT __declspec(dllimport)
+#endif
+
+#else // !defined(WIN32)
+
+#if defined(MOJO_CPP_BINDINGS_IMPLEMENTATION)
+#define MOJO_CPP_BINDINGS_EXPORT __attribute((visibility("default")))
+#else
+#define MOJO_CPP_BINDINGS_EXPORT
+#endif
+
+#endif // defined(WIN32)
+
+#else // !defined(COMPONENT_BUILD)
+
+#define MOJO_CPP_BINDINGS_EXPORT
+
+#endif // defined(COMPONENT_BUILD)
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_BINDINGS_EXPORT_H_
diff --git a/mojo/public/cpp/bindings/clone_traits.h b/mojo/public/cpp/bindings/clone_traits.h
new file mode 100644
index 0000000..203ab34
--- /dev/null
+++ b/mojo/public/cpp/bindings/clone_traits.h
@@ -0,0 +1,86 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_CLONE_TRAITS_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_CLONE_TRAITS_H_
+
+#include <type_traits>
+#include <unordered_map>
+#include <vector>
+
+#include "base/optional.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+
+namespace mojo {
+
+template <typename T>
+struct HasCloneMethod {
+ template <typename U>
+ static char Test(decltype(&U::Clone));
+ template <typename U>
+ static int Test(...);
+ static const bool value = sizeof(Test<T>(0)) == sizeof(char);
+
+ private:
+ internal::EnsureTypeIsComplete<T> check_t_;
+};
+
+template <typename T, bool has_clone_method = HasCloneMethod<T>::value>
+struct CloneTraits;
+
+template <typename T>
+T Clone(const T& input);
+
+template <typename T>
+struct CloneTraits<T, true> {
+ static T Clone(const T& input) { return input.Clone(); }
+};
+
+template <typename T>
+struct CloneTraits<T, false> {
+ static T Clone(const T& input) { return input; }
+};
+
+template <typename T>
+struct CloneTraits<base::Optional<T>, false> {
+ static base::Optional<T> Clone(const base::Optional<T>& input) {
+ if (!input)
+ return base::nullopt;
+
+ return base::Optional<T>(mojo::Clone(*input));
+ }
+};
+
+template <typename T>
+struct CloneTraits<std::vector<T>, false> {
+ static std::vector<T> Clone(const std::vector<T>& input) {
+ std::vector<T> result;
+ result.reserve(input.size());
+ for (const auto& element : input)
+ result.push_back(mojo::Clone(element));
+
+ return result;
+ }
+};
+
+template <typename K, typename V>
+struct CloneTraits<std::unordered_map<K, V>, false> {
+ static std::unordered_map<K, V> Clone(const std::unordered_map<K, V>& input) {
+ std::unordered_map<K, V> result;
+ for (const auto& element : input) {
+ result.insert(std::make_pair(mojo::Clone(element.first),
+ mojo::Clone(element.second)));
+ }
+ return result;
+ }
+};
+
+template <typename T>
+T Clone(const T& input) {
+ return CloneTraits<T>::Clone(input);
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_CLONE_TRAITS_H_
diff --git a/mojo/public/cpp/bindings/connection_error_callback.h b/mojo/public/cpp/bindings/connection_error_callback.h
new file mode 100644
index 0000000..306e99e
--- /dev/null
+++ b/mojo/public/cpp/bindings/connection_error_callback.h
@@ -0,0 +1,21 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_CONNECTION_ERROR_CALLBACK_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_CONNECTION_ERROR_CALLBACK_H_
+
+#include "base/callback.h"
+
+namespace mojo {
+
+// This callback type accepts user-defined disconnect reason and description. If
+// the other side specifies a reason on closing the connection, it will be
+// passed to the error handler.
+using ConnectionErrorWithReasonCallback =
+ base::Callback<void(uint32_t /* custom_reason */,
+ const std::string& /* description */)>;
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_CONNECTION_ERROR_CALLBACK_H_
diff --git a/mojo/public/cpp/bindings/connector.h b/mojo/public/cpp/bindings/connector.h
index d14ad17..01e9236 100644
--- a/mojo/public/cpp/bindings/connector.h
+++ b/mojo/public/cpp/bindings/connector.h
@@ -8,10 +8,13 @@
#include <memory>
#include "base/callback.h"
+#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/message.h"
#include "mojo/public/cpp/bindings/sync_handle_watcher.h"
#include "mojo/public/cpp/system/core.h"
@@ -33,7 +36,8 @@ namespace mojo {
// - Sending messages can be configured to be thread safe (please see comments
// of the constructor). Other than that, the object should only be accessed
// on the creating thread.
-class Connector : public MessageReceiver {
+class MOJO_CPP_BINDINGS_EXPORT Connector
+ : NON_EXPORTED_BASE(public MessageReceiver) {
public:
enum ConnectorConfig {
// Connector::Accept() is only called from a single thread.
@@ -138,6 +142,7 @@ class Connector : public MessageReceiver {
// Whether currently the control flow is inside the sync handle watcher
// callback.
+ // It always returns false after CloseMessagePipe()/PassMessagePipe().
bool during_sync_handle_watcher_callback() const {
return sync_handle_watcher_callback_count_ > 0;
}
@@ -146,6 +151,10 @@ class Connector : public MessageReceiver {
return task_runner_.get();
}
+ // Sets the tag used by the heap profiler.
+ // |tag| must be a const string literal.
+ void SetWatcherHeapProfilerTag(const char* tag);
+
private:
// Callback of mojo::Watcher.
void OnWatcherHandleReady(MojoResult result);
@@ -155,7 +164,8 @@ class Connector : public MessageReceiver {
void WaitToReadMore();
- // Returns false if |this| was destroyed during message dispatch.
+ // Returns false if it is impossible to receive more messages in the future.
+ // |this| may have been destroyed in that case.
WARN_UNUSED_RESULT bool ReadSingleMessage(MojoResult* read_result);
// |this| can be destroyed during message dispatch.
@@ -175,31 +185,40 @@ class Connector : public MessageReceiver {
base::Closure connection_error_handler_;
ScopedMessagePipeHandle message_pipe_;
- MessageReceiver* incoming_receiver_;
+ MessageReceiver* incoming_receiver_ = nullptr;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- Watcher handle_watcher_;
+ std::unique_ptr<Watcher> handle_watcher_;
- bool error_;
- bool drop_writes_;
- bool enforce_errors_from_incoming_receiver_;
+ bool error_ = false;
+ bool drop_writes_ = false;
+ bool enforce_errors_from_incoming_receiver_ = true;
- bool paused_;
+ bool paused_ = false;
// If sending messages is allowed from multiple threads, |lock_| is used to
// protect modifications to |message_pipe_| and |drop_writes_|.
- std::unique_ptr<base::Lock> lock_;
+ base::Optional<base::Lock> lock_;
std::unique_ptr<SyncHandleWatcher> sync_watcher_;
- bool allow_woken_up_by_others_;
+ bool allow_woken_up_by_others_ = false;
// If non-zero, currently the control flow is inside the sync handle watcher
// callback.
- size_t sync_handle_watcher_callback_count_;
+ size_t sync_handle_watcher_callback_count_ = 0;
base::ThreadChecker thread_checker_;
+ base::Lock connected_lock_;
+ bool connected_ = true;
+
+ // The tag used to track heap allocations that originated from a Watcher
+ // notification.
+ const char* heap_profiler_tag_ = nullptr;
+
// Create a single weak ptr and use it everywhere, to avoid the malloc/free
// cost of creating a new weak ptr whenever it is needed.
+ // NOTE: This weak pointer is invalidated when the message pipe is closed or
+ // transferred (i.e., when |connected_| is set to false).
base::WeakPtr<Connector> weak_self_;
base::WeakPtrFactory<Connector> weak_factory_;
diff --git a/mojo/public/cpp/bindings/disconnect_reason.h b/mojo/public/cpp/bindings/disconnect_reason.h
new file mode 100644
index 0000000..c04e8ad
--- /dev/null
+++ b/mojo/public/cpp/bindings/disconnect_reason.h
@@ -0,0 +1,25 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_DISCONNECT_REASON_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_DISCONNECT_REASON_H_
+
+#include <stdint.h>
+
+#include <string>
+
+namespace mojo {
+
+struct DisconnectReason {
+ public:
+ DisconnectReason(uint32_t in_custom_reason, const std::string& in_description)
+ : custom_reason(in_custom_reason), description(in_description) {}
+
+ uint32_t custom_reason;
+ std::string description;
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_DISCONNECT_REASON_H_
diff --git a/mojo/public/cpp/bindings/lib/filter_chain.h b/mojo/public/cpp/bindings/filter_chain.h
index 447be3d..1262f39 100644
--- a/mojo/public/cpp/bindings/lib/filter_chain.h
+++ b/mojo/public/cpp/bindings/filter_chain.h
@@ -2,20 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_FILTER_CHAIN_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_LIB_FILTER_CHAIN_H_
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_FILTER_CHAIN_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_FILTER_CHAIN_H_
#include <utility>
#include <vector>
+#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/message.h"
-#include "mojo/public/cpp/bindings/message_filter.h"
namespace mojo {
-namespace internal {
-class FilterChain {
+class MOJO_CPP_BINDINGS_EXPORT FilterChain
+ : NON_EXPORTED_BASE(public MessageReceiver) {
public:
// Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while
// this object is alive.
@@ -23,25 +25,22 @@ class FilterChain {
FilterChain(FilterChain&& other);
FilterChain& operator=(FilterChain&& other);
- ~FilterChain();
+ ~FilterChain() override;
template <typename FilterType, typename... Args>
inline void Append(Args&&... args);
+ void Append(std::unique_ptr<MessageReceiver> filter);
+
// Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while
// this object is alive.
void SetSink(MessageReceiver* sink);
- // Returns a receiver to accept messages. Messages flow through all filters in
- // the same order as they were appended to the chain. If all filters allow a
- // message to pass, it will be forwarded to |sink_|.
- // The returned value is invalidated when this object goes away.
- MessageReceiver* GetHead();
+ // MessageReceiver:
+ bool Accept(Message* message) override;
private:
- // Owned by this object.
- // TODO(dcheng): Use unique_ptr.
- std::vector<MessageFilter*> filters_;
+ std::vector<std::unique_ptr<MessageReceiver>> filters_;
MessageReceiver* sink_;
@@ -50,17 +49,13 @@ class FilterChain {
template <typename FilterType, typename... Args>
inline void FilterChain::Append(Args&&... args) {
- FilterType* filter = new FilterType(std::forward<Args>(args)..., sink_);
- if (!filters_.empty())
- filters_.back()->set_sink(filter);
- filters_.push_back(filter);
+ Append(base::MakeUnique<FilterType>(std::forward<Args>(args)...));
}
template <>
inline void FilterChain::Append<PassThroughFilter>() {
}
-} // namespace internal
} // namespace mojo
-#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_FILTER_CHAIN_H_
+#endif // MOJO_PUBLIC_CPP_BINDINGS_FILTER_CHAIN_H_
diff --git a/mojo/public/cpp/bindings/interface_data_view.h b/mojo/public/cpp/bindings/interface_data_view.h
new file mode 100644
index 0000000..ef12254
--- /dev/null
+++ b/mojo/public/cpp/bindings/interface_data_view.h
@@ -0,0 +1,25 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_DATA_VIEW_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_DATA_VIEW_H_
+
+namespace mojo {
+
+// They are used for type identification purpose only.
+template <typename Interface>
+class AssociatedInterfacePtrInfoDataView {};
+
+template <typename Interface>
+class AssociatedInterfaceRequestDataView {};
+
+template <typename Interface>
+class InterfacePtrDataView {};
+
+template <typename Interface>
+class InterfaceRequestDataView {};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_DATA_VIEW_H_
diff --git a/mojo/public/cpp/bindings/interface_endpoint_client.h b/mojo/public/cpp/bindings/interface_endpoint_client.h
index 9dc40a2..0aea756 100644
--- a/mojo/public/cpp/bindings/interface_endpoint_client.h
+++ b/mojo/public/cpp/bindings/interface_endpoint_client.h
@@ -11,34 +11,42 @@
#include <memory>
#include "base/callback.h"
+#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
+#include "mojo/public/cpp/bindings/connection_error_callback.h"
+#include "mojo/public/cpp/bindings/disconnect_reason.h"
+#include "mojo/public/cpp/bindings/filter_chain.h"
+#include "mojo/public/cpp/bindings/lib/control_message_handler.h"
+#include "mojo/public/cpp/bindings/lib/control_message_proxy.h"
#include "mojo/public/cpp/bindings/message.h"
-#include "mojo/public/cpp/bindings/message_filter.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
namespace mojo {
class AssociatedGroup;
-class AssociatedGroupController;
class InterfaceEndpointController;
// InterfaceEndpointClient handles message sending and receiving of an interface
// endpoint, either the implementation side or the client side.
// It should only be accessed and destructed on the creating thread.
-class InterfaceEndpointClient : public MessageReceiverWithResponder {
+class MOJO_CPP_BINDINGS_EXPORT InterfaceEndpointClient
+ : NON_EXPORTED_BASE(public MessageReceiverWithResponder) {
public:
// |receiver| is okay to be null. If it is not null, it must outlive this
// object.
InterfaceEndpointClient(ScopedInterfaceEndpointHandle handle,
MessageReceiverWithResponderStatus* receiver,
- std::unique_ptr<MessageFilter> payload_validator,
+ std::unique_ptr<MessageReceiver> payload_validator,
bool expect_sync_requests,
- scoped_refptr<base::SingleThreadTaskRunner> runner);
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ uint32_t interface_version);
~InterfaceEndpointClient() override;
// Sets the error handler to receive notifications when an error is
@@ -46,6 +54,14 @@ class InterfaceEndpointClient : public MessageReceiverWithResponder {
void set_connection_error_handler(const base::Closure& error_handler) {
DCHECK(thread_checker_.CalledOnValidThread());
error_handler_ = error_handler;
+ error_with_reason_handler_.Reset();
+ }
+
+ void set_connection_error_with_reason_handler(
+ const ConnectionErrorWithReasonCallback& error_handler) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ error_with_reason_handler_ = error_handler;
+ error_handler_.Reset();
}
// Returns true if an error was encountered.
@@ -60,11 +76,11 @@ class InterfaceEndpointClient : public MessageReceiverWithResponder {
return !async_responders_.empty() || !sync_responses_.empty();
}
- AssociatedGroupController* group_controller() const {
- return handle_.group_controller();
- }
AssociatedGroup* associated_group();
- uint32_t interface_id() const;
+
+ // Adds a MessageReceiver which can filter a message after validation but
+ // before dispatch.
+ void AddFilter(std::unique_ptr<MessageReceiver> filter);
// After this call the object is in an invalid state and shouldn't be reused.
ScopedInterfaceEndpointHandle PassHandle();
@@ -73,7 +89,11 @@ class InterfaceEndpointClient : public MessageReceiverWithResponder {
// and notifies all interfaces running on this pipe.
void RaiseError();
+ void CloseWithReason(uint32_t custom_reason, const std::string& description);
+
// MessageReceiverWithResponder implementation:
+ // They must only be called when the handle is not in pending association
+ // state.
bool Accept(Message* message) override;
bool AcceptWithResponder(Message* message,
MessageReceiver* responder) override;
@@ -83,7 +103,14 @@ class InterfaceEndpointClient : public MessageReceiverWithResponder {
// NOTE: |message| must have passed message header validation.
bool HandleIncomingMessage(Message* message);
- void NotifyError();
+ void NotifyError(const base::Optional<DisconnectReason>& reason);
+
+ // The following methods send interface control messages.
+ // They must only be called when the handle is not in pending association
+ // state.
+ void QueryVersion(const base::Callback<void(uint32_t)>& callback);
+ void RequireVersion(uint32_t version);
+ void FlushForTesting();
private:
// Maps from the id of a response to the MessageReceiver that handles the
@@ -96,7 +123,7 @@ class InterfaceEndpointClient : public MessageReceiverWithResponder {
explicit SyncResponseInfo(bool* in_response_received);
~SyncResponseInfo();
- std::unique_ptr<Message> response;
+ Message response;
// Points to a stack-allocated variable.
bool* response_received;
@@ -123,26 +150,37 @@ class InterfaceEndpointClient : public MessageReceiverWithResponder {
DISALLOW_COPY_AND_ASSIGN(HandleIncomingMessageThunk);
};
+ void InitControllerIfNecessary();
+
+ void OnAssociationEvent(
+ ScopedInterfaceEndpointHandle::AssociationEvent event);
+
bool HandleValidatedMessage(Message* message);
+ const bool expect_sync_requests_ = false;
+
ScopedInterfaceEndpointHandle handle_;
std::unique_ptr<AssociatedGroup> associated_group_;
- InterfaceEndpointController* controller_;
+ InterfaceEndpointController* controller_ = nullptr;
- MessageReceiverWithResponderStatus* const incoming_receiver_;
- std::unique_ptr<MessageFilter> payload_validator_;
+ MessageReceiverWithResponderStatus* const incoming_receiver_ = nullptr;
HandleIncomingMessageThunk thunk_;
+ FilterChain filters_;
AsyncResponderMap async_responders_;
SyncResponseMap sync_responses_;
- uint64_t next_request_id_;
+ uint64_t next_request_id_ = 1;
base::Closure error_handler_;
- bool encountered_error_;
+ ConnectionErrorWithReasonCallback error_with_reason_handler_;
+ bool encountered_error_ = false;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ internal::ControlMessageProxy control_message_proxy_;
+ internal::ControlMessageHandler control_message_handler_;
+
base::ThreadChecker thread_checker_;
base::WeakPtrFactory<InterfaceEndpointClient> weak_ptr_factory_;
diff --git a/mojo/public/cpp/bindings/interface_ptr.h b/mojo/public/cpp/bindings/interface_ptr.h
index edcb9bf..e88be74 100644
--- a/mojo/public/cpp/bindings/interface_ptr.h
+++ b/mojo/public/cpp/bindings/interface_ptr.h
@@ -6,6 +6,8 @@
#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_
#include <stdint.h>
+
+#include <string>
#include <utility>
#include "base/callback_forward.h"
@@ -14,13 +16,12 @@
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "mojo/public/cpp/bindings/connection_error_callback.h"
#include "mojo/public/cpp/bindings/interface_ptr_info.h"
#include "mojo/public/cpp/bindings/lib/interface_ptr_state.h"
namespace mojo {
-class AssociatedGroup;
-
// A pointer to a local proxy of a remote Interface implementation. Uses a
// message pipe to communicate with the remote implementation, and automatically
// closes the pipe and deletes the proxy on destruction. The pointer must be
@@ -37,6 +38,9 @@ class AssociatedGroup;
template <typename Interface>
class InterfacePtr {
public:
+ using InterfaceType = Interface;
+ using PtrInfoType = InterfacePtrInfo<Interface>;
+
// Constructs an unbound InterfacePtr.
InterfacePtr() {}
InterfacePtr(decltype(nullptr)) {}
@@ -114,6 +118,12 @@ class InterfacePtr {
internal_state_.RequireVersion(version);
}
+ // Sends a no-op message on the underlying message pipe and runs the current
+ // message loop until its response is received. This can be used in tests to
+ // verify that no message was sent on a message pipe in response to some
+ // stimulus.
+ void FlushForTesting() { internal_state_.FlushForTesting(); }
+
// Closes the bound message pipe (if any) and returns the pointer to the
// unbound state.
void reset() {
@@ -121,6 +131,13 @@ class InterfacePtr {
internal_state_.Swap(&doomed);
}
+ // Similar to the method above, but also specifies a disconnect reason.
+ void ResetWithReason(uint32_t custom_reason, const std::string& description) {
+ if (internal_state_.is_bound())
+ internal_state_.CloseWithReason(custom_reason, description);
+ reset();
+ }
+
// Whether there are any associated interfaces running on the pipe currently.
bool HasAssociatedInterfaces() const {
return internal_state_.HasAssociatedInterfaces();
@@ -140,6 +157,11 @@ class InterfacePtr {
internal_state_.set_connection_error_handler(error_handler);
}
+ void set_connection_error_with_reason_handler(
+ const ConnectionErrorWithReasonCallback& error_handler) {
+ internal_state_.set_connection_error_with_reason_handler(error_handler);
+ }
+
// Unbinds the InterfacePtr and returns the information which could be used
// to setup an InterfacePtr again. This method may be used to move the proxy
// to a different thread (see class comments for details).
@@ -162,14 +184,6 @@ class InterfacePtr {
return state.PassInterface();
}
- // Returns the associated group that this object belongs to. Returns null if:
- // - this object is not bound; or
- // - the interface doesn't have methods to pass associated interface
- // pointers or requests.
- AssociatedGroup* associated_group() {
- return internal_state_.associated_group();
- }
-
bool Equals(const InterfacePtr& other) const {
if (this == &other)
return true;
@@ -180,8 +194,7 @@ class InterfacePtr {
}
// DO NOT USE. Exposed only for internal use and for testing.
- internal::InterfacePtrState<Interface, Interface::PassesAssociatedKinds_>*
- internal_state() {
+ internal::InterfacePtrState<Interface>* internal_state() {
return &internal_state_;
}
@@ -189,9 +202,7 @@ class InterfacePtr {
// implicitly convertible to a real bool (which is dangerous).
private:
// TODO(dcheng): Use an explicit conversion operator.
- typedef internal::InterfacePtrState<Interface,
- Interface::PassesAssociatedKinds_>
- InterfacePtr::*Testable;
+ typedef internal::InterfacePtrState<Interface> InterfacePtr::*Testable;
public:
operator Testable() const {
@@ -207,8 +218,7 @@ class InterfacePtr {
template <typename T>
bool operator!=(const InterfacePtr<T>& other) const = delete;
- typedef internal::InterfacePtrState<Interface,
- Interface::PassesAssociatedKinds_> State;
+ typedef internal::InterfacePtrState<Interface> State;
mutable State internal_state_;
DISALLOW_COPY_AND_ASSIGN(InterfacePtr);
diff --git a/mojo/public/cpp/bindings/interface_ptr_set.h b/mojo/public/cpp/bindings/interface_ptr_set.h
index d4b2046..09a2682 100644
--- a/mojo/public/cpp/bindings/interface_ptr_set.h
+++ b/mojo/public/cpp/bindings/interface_ptr_set.h
@@ -16,6 +16,10 @@
namespace mojo {
namespace internal {
+// TODO(blundell): This class should be rewritten to be structured
+// similarly to BindingSet if possible, with PtrSet owning its
+// Elements and those Elements calling back into PtrSet on connection
+// error.
template <typename Interface, template <typename> class Ptr>
class PtrSet {
public:
@@ -55,7 +59,13 @@ class PtrSet {
~Element() {}
- void Close() { ptr_.reset(); }
+ void Close() {
+ ptr_.reset();
+
+ // Resetting the interface ptr means that it won't call this object back
+ // on connection error anymore, so this object must delete itself now.
+ DeleteElement(this);
+ }
Interface* get() { return ptr_.get(); }
diff --git a/mojo/public/cpp/bindings/interface_request.h b/mojo/public/cpp/bindings/interface_request.h
index fc23aec..29d8836 100644
--- a/mojo/public/cpp/bindings/interface_request.h
+++ b/mojo/public/cpp/bindings/interface_request.h
@@ -5,12 +5,17 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_
#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_
+#include <string>
#include <utility>
#include "base/macros.h"
+#include "base/optional.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "mojo/public/cpp/bindings/disconnect_reason.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/public/cpp/bindings/pipe_control_message_proxy.h"
+#include "mojo/public/cpp/system/message_pipe.h"
namespace mojo {
@@ -28,6 +33,19 @@ class InterfaceRequest {
InterfaceRequest() {}
InterfaceRequest(decltype(nullptr)) {}
+ // Creates a new message pipe over which Interface is to be served, binding
+ // the specified InterfacePtr to one end of the message pipe and this
+ // InterfaceRequest to the other. For example usage, see comments on
+ // MakeRequest(InterfacePtr*) below.
+ explicit InterfaceRequest(InterfacePtr<Interface>* ptr,
+ scoped_refptr<base::SingleThreadTaskRunner> runner =
+ base::ThreadTaskRunnerHandle::Get()) {
+ MessagePipe pipe;
+ ptr->Bind(InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u),
+ std::move(runner));
+ Bind(std::move(pipe.handle1));
+ }
+
// Takes the message pipe from another InterfaceRequest.
InterfaceRequest(InterfaceRequest&& other) {
handle_ = std::move(other.handle_);
@@ -64,6 +82,20 @@ class InterfaceRequest {
return !is_pending() && !other.is_pending();
}
+ void ResetWithReason(uint32_t custom_reason, const std::string& description) {
+ if (!handle_.is_valid())
+ return;
+
+ Message message =
+ PipeControlMessageProxy::ConstructPeerEndpointClosedMessage(
+ kMasterInterfaceId, DisconnectReason(custom_reason, description));
+ MojoResult result = WriteMessageNew(
+ handle_.get(), message.TakeMojoMessage(), MOJO_WRITE_MESSAGE_FLAG_NONE);
+ DCHECK_EQ(MOJO_RESULT_OK, result);
+
+ handle_.reset();
+ }
+
private:
ScopedMessagePipeHandle handle_;
@@ -103,9 +135,9 @@ InterfaceRequest<Interface> MakeRequest(ScopedMessagePipeHandle handle) {
//
// DatabasePtr database = ...; // Connect to database.
// TablePtr table;
-// database->OpenTable(GetProxy(&table));
+// database->OpenTable(MakeRequest(&table));
//
-// Upon return from GetProxy, |table| is ready to have methods called on it.
+// Upon return from MakeRequest, |table| is ready to have methods called on it.
//
// Example #2: Registering a local implementation with a remote service.
// =====================================================================
@@ -119,19 +151,16 @@ InterfaceRequest<Interface> MakeRequest(ScopedMessagePipeHandle handle) {
//
// CollectorPtr collector = ...; // Connect to Collector.
// SourcePtr source;
-// InterfaceRequest<Source> source_request = GetProxy(&source);
+// InterfaceRequest<Source> source_request(&source);
// collector->RegisterSource(std::move(source));
// CreateSource(std::move(source_request)); // Create implementation locally.
//
template <typename Interface>
-InterfaceRequest<Interface> GetProxy(
+InterfaceRequest<Interface> MakeRequest(
InterfacePtr<Interface>* ptr,
scoped_refptr<base::SingleThreadTaskRunner> runner =
base::ThreadTaskRunnerHandle::Get()) {
- MessagePipe pipe;
- ptr->Bind(InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u),
- std::move(runner));
- return MakeRequest<Interface>(std::move(pipe.handle1));
+ return InterfaceRequest<Interface>(ptr, runner);
}
// Fuses an InterfaceRequest<T> endpoint with an InterfacePtrInfo<T> endpoint.
diff --git a/mojo/public/cpp/bindings/lib/array_internal.h b/mojo/public/cpp/bindings/lib/array_internal.h
index ba6d16e..eecfcfb 100644
--- a/mojo/public/cpp/bindings/lib/array_internal.h
+++ b/mojo/public/cpp/bindings/lib/array_internal.h
@@ -13,6 +13,7 @@
#include "base/logging.h"
#include "mojo/public/c/system/macros.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
#include "mojo/public/cpp/bindings/lib/buffer.h"
#include "mojo/public/cpp/bindings/lib/serialization_util.h"
@@ -28,13 +29,13 @@ namespace internal {
template <typename K, typename V>
class Map_Data;
-std::string MakeMessageWithArrayIndex(const char* message,
- size_t size,
- size_t index);
+MOJO_CPP_BINDINGS_EXPORT std::string
+MakeMessageWithArrayIndex(const char* message, size_t size, size_t index);
-std::string MakeMessageWithExpectedArraySize(const char* message,
- size_t size,
- size_t expected_size);
+MOJO_CPP_BINDINGS_EXPORT std::string MakeMessageWithExpectedArraySize(
+ const char* message,
+ size_t size,
+ size_t expected_size);
template <typename T>
struct ArrayDataTraits {
@@ -67,7 +68,7 @@ template <>
struct ArrayDataTraits<bool> {
// Helper class to emulate a reference to a bool, used for direct element
// access.
- class BitRef {
+ class MOJO_CPP_BINDINGS_EXPORT BitRef {
public:
~BitRef();
BitRef& operator=(bool value);
@@ -109,7 +110,7 @@ struct ArrayDataTraits<bool> {
//
// TODO(yzshen): Validation code should be organzied in a way similar to
// Serializer<>, or merged into it. It should be templatized with the mojo
-// wrapper type instead of the data type, that way we can use MojomTypeTraits
+// data view type instead of the data type, that way we can use MojomTypeTraits
// to determine the categories.
template <typename T, bool is_union, bool is_handle_or_interface>
@@ -262,7 +263,7 @@ class Array_Data {
T,
IsUnionDataType<T>::value,
std::is_same<T, AssociatedInterface_Data>::value ||
- std::is_same<T, AssociatedInterfaceRequest_Data>::value ||
+ std::is_same<T, AssociatedEndpointHandle_Data>::value ||
std::is_same<T, Interface_Data>::value ||
std::is_same<T, Handle_Data>::value>;
using Element = T;
diff --git a/mojo/public/cpp/bindings/lib/array_serialization.h b/mojo/public/cpp/bindings/lib/array_serialization.h
index 5db27a5..d2f8ecf 100644
--- a/mojo/public/cpp/bindings/lib/array_serialization.h
+++ b/mojo/public/cpp/bindings/lib/array_serialization.h
@@ -14,12 +14,11 @@
#include <vector>
#include "base/logging.h"
-#include "mojo/public/cpp/bindings/array.h"
+#include "mojo/public/cpp/bindings/array_data_view.h"
#include "mojo/public/cpp/bindings/lib/array_internal.h"
#include "mojo/public/cpp/bindings/lib/serialization_forward.h"
#include "mojo/public/cpp/bindings/lib/template_util.h"
#include "mojo/public/cpp/bindings/lib/validation_errors.h"
-#include "mojo/public/cpp/bindings/map.h"
namespace mojo {
namespace internal {
@@ -46,7 +45,7 @@ class ArrayIterator<Traits, MaybeConstUserType, true> {
using GetNextResult =
decltype(Traits::GetValue(std::declval<IteratorType&>()));
GetNextResult GetNext() {
- auto& value = Traits::GetValue(iter_);
+ GetNextResult value = Traits::GetValue(iter_);
Traits::AdvanceIterator(iter_);
return value;
}
@@ -287,13 +286,19 @@ struct ArraySerializer<
using Element = typename MojomType::Element;
using Traits = ArrayTraits<UserType>;
- static_assert(std::is_same<Element, typename Traits::Element>::value,
- "Incorrect array serializer");
-
static size_t GetSerializedSize(UserTypeIterator* input,
SerializationContext* context) {
- return sizeof(Data) +
- Align(input->GetSize() * sizeof(typename Data::Element));
+ size_t element_count = input->GetSize();
+ if (BelongsTo<Element,
+ MojomTypeCategory::ASSOCIATED_INTERFACE |
+ MojomTypeCategory::ASSOCIATED_INTERFACE_REQUEST>::value) {
+ for (size_t i = 0; i < element_count; ++i) {
+ typename UserTypeIterator::GetNextResult next = input->GetNext();
+ size_t size = PrepareToSerialize<Element>(next, context);
+ DCHECK_EQ(size, 0u);
+ }
+ }
+ return sizeof(Data) + Align(element_count * sizeof(typename Data::Element));
}
static void SerializeElements(UserTypeIterator* input,
@@ -306,7 +311,8 @@ struct ArraySerializer<
size_t size = input->GetSize();
for (size_t i = 0; i < size; ++i) {
- Serialize<Element>(input->GetNext(), &output->at(i), context);
+ typename UserTypeIterator::GetNextResult next = input->GetNext();
+ Serialize<Element>(next, &output->at(i), context);
static const ValidationError kError =
BelongsTo<Element,
@@ -361,8 +367,10 @@ struct ArraySerializer<MojomType,
SerializationContext* context) {
size_t element_count = input->GetSize();
size_t size = sizeof(Data) + element_count * sizeof(typename Data::Element);
- for (size_t i = 0; i < element_count; ++i)
- size += PrepareToSerialize<Element>(input->GetNext(), context);
+ for (size_t i = 0; i < element_count; ++i) {
+ typename UserTypeIterator::GetNextResult next = input->GetNext();
+ size += PrepareToSerialize<Element>(next, context);
+ }
return size;
}
@@ -374,7 +382,8 @@ struct ArraySerializer<MojomType,
size_t size = input->GetSize();
for (size_t i = 0; i < size; ++i) {
DataElementPtr data_ptr;
- SerializeCaller<Element>::Run(input->GetNext(), buf, &data_ptr,
+ typename UserTypeIterator::GetNextResult next = input->GetNext();
+ SerializeCaller<Element>::Run(next, buf, &data_ptr,
validate_params->element_validate_params,
context);
output->at(i).Set(data_ptr);
@@ -444,10 +453,6 @@ struct ArraySerializer<
using Element = typename MojomType::Element;
using Traits = ArrayTraits<UserType>;
- static_assert(std::is_same<typename MojomType::Element,
- typename Traits::Element>::value,
- "Incorrect array serializer");
-
static size_t GetSerializedSize(UserTypeIterator* input,
SerializationContext* context) {
size_t element_count = input->GetSize();
@@ -455,7 +460,8 @@ struct ArraySerializer<
for (size_t i = 0; i < element_count; ++i) {
// Call with |inlined| set to false, so that it will account for both the
// data in the union and the space in the array used to hold the union.
- size += PrepareToSerialize<Element>(input->GetNext(), false, context);
+ typename UserTypeIterator::GetNextResult next = input->GetNext();
+ size += PrepareToSerialize<Element>(next, false, context);
}
return size;
}
@@ -468,7 +474,8 @@ struct ArraySerializer<
size_t size = input->GetSize();
for (size_t i = 0; i < size; ++i) {
typename Data::Element* result = output->storage() + i;
- Serialize<Element>(input->GetNext(), buf, &result, true, context);
+ typename UserTypeIterator::GetNextResult next = input->GetNext();
+ Serialize<Element>(next, buf, &result, true, context);
MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
!validate_params->element_is_nullable && output->at(i).is_null(),
VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
@@ -492,13 +499,13 @@ struct ArraySerializer<
};
template <typename Element, typename MaybeConstUserType>
-struct Serializer<Array<Element>, MaybeConstUserType> {
+struct Serializer<ArrayDataView<Element>, MaybeConstUserType> {
using UserType = typename std::remove_const<MaybeConstUserType>::type;
using Traits = ArrayTraits<UserType>;
- using Impl = ArraySerializer<Array<Element>,
+ using Impl = ArraySerializer<ArrayDataView<Element>,
MaybeConstUserType,
ArrayIterator<Traits, MaybeConstUserType>>;
- using Data = typename MojomTypeTraits<Array<Element>>::Data;
+ using Data = typename MojomTypeTraits<ArrayDataView<Element>>::Data;
static size_t PrepareToSerialize(MaybeConstUserType& input,
SerializationContext* context) {
diff --git a/mojo/public/cpp/bindings/lib/associated_group.cc b/mojo/public/cpp/bindings/lib/associated_group.cc
index a9c53b5..3e95eeb 100644
--- a/mojo/public/cpp/bindings/lib/associated_group.cc
+++ b/mojo/public/cpp/bindings/lib/associated_group.cc
@@ -8,28 +8,27 @@
namespace mojo {
-AssociatedGroup::AssociatedGroup() {}
+AssociatedGroup::AssociatedGroup() = default;
-AssociatedGroup::AssociatedGroup(const AssociatedGroup& other)
- : controller_(other.controller_) {}
+AssociatedGroup::AssociatedGroup(
+ scoped_refptr<AssociatedGroupController> controller)
+ : controller_(std::move(controller)) {}
-AssociatedGroup::~AssociatedGroup() {}
+AssociatedGroup::AssociatedGroup(const ScopedInterfaceEndpointHandle& handle)
+ : controller_getter_(handle.CreateGroupControllerGetter()) {}
-AssociatedGroup& AssociatedGroup::operator=(const AssociatedGroup& other) {
- if (this == &other)
- return *this;
+AssociatedGroup::AssociatedGroup(const AssociatedGroup& other) = default;
- controller_ = other.controller_;
- return *this;
-}
+AssociatedGroup::~AssociatedGroup() = default;
+
+AssociatedGroup& AssociatedGroup::operator=(const AssociatedGroup& other) =
+ default;
-void AssociatedGroup::CreateEndpointHandlePair(
- ScopedInterfaceEndpointHandle* local_endpoint,
- ScopedInterfaceEndpointHandle* remote_endpoint) {
- if (!controller_)
- return;
+AssociatedGroupController* AssociatedGroup::GetController() {
+ if (controller_)
+ return controller_.get();
- controller_->CreateEndpointHandlePair(local_endpoint, remote_endpoint);
+ return controller_getter_.Run();
}
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/associated_group_controller.cc b/mojo/public/cpp/bindings/lib/associated_group_controller.cc
index 42db9b3..f4a9aa2 100644
--- a/mojo/public/cpp/bindings/lib/associated_group_controller.cc
+++ b/mojo/public/cpp/bindings/lib/associated_group_controller.cc
@@ -8,25 +8,17 @@
namespace mojo {
-AssociatedGroupController::AssociatedGroupController(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : base::RefCountedDeleteOnMessageLoop<AssociatedGroupController>(
- task_runner) {}
-
AssociatedGroupController::~AssociatedGroupController() {}
-std::unique_ptr<AssociatedGroup>
-AssociatedGroupController::CreateAssociatedGroup() {
- std::unique_ptr<AssociatedGroup> group(new AssociatedGroup);
- group->controller_ = this;
- return group;
+ScopedInterfaceEndpointHandle
+AssociatedGroupController::CreateScopedInterfaceEndpointHandle(InterfaceId id) {
+ return ScopedInterfaceEndpointHandle(id, this);
}
-ScopedInterfaceEndpointHandle
-AssociatedGroupController::CreateScopedInterfaceEndpointHandle(
- InterfaceId id,
- bool is_local) {
- return ScopedInterfaceEndpointHandle(id, is_local, this);
+bool AssociatedGroupController::NotifyAssociation(
+ ScopedInterfaceEndpointHandle* handle_to_send,
+ InterfaceId id) {
+ return handle_to_send->NotifyAssociation(id, this);
}
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
index c7f74fb..72f7960 100644
--- a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
+++ b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
@@ -9,6 +9,7 @@
#include <algorithm> // For |std::swap()|.
#include <memory>
+#include <string>
#include <utility>
#include "base/bind.h"
@@ -18,11 +19,10 @@
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "mojo/public/cpp/bindings/associated_group.h"
-#include "mojo/public/cpp/bindings/associated_group_controller.h"
#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
+#include "mojo/public/cpp/bindings/connection_error_callback.h"
#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
#include "mojo/public/cpp/bindings/interface_id.h"
-#include "mojo/public/cpp/bindings/lib/control_message_proxy.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
#include "mojo/public/cpp/system/message_pipe.h"
@@ -46,18 +46,12 @@ class AssociatedInterfacePtrState {
uint32_t version() const { return version_; }
- uint32_t interface_id() const {
- DCHECK(is_bound());
- return endpoint_client_->interface_id();
- }
-
void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
- // Do a static cast in case the interface contains methods with the same
- // name. It is safe to capture |this| because the callback won't be run
- // after this object goes away.
- static_cast<ControlMessageProxy*>(proxy_.get())
- ->QueryVersion(base::Bind(&AssociatedInterfacePtrState::OnQueryVersion,
- base::Unretained(this), callback));
+ // It is safe to capture |this| because the callback won't be run after this
+ // object goes away.
+ endpoint_client_->QueryVersion(
+ base::Bind(&AssociatedInterfacePtrState::OnQueryVersion,
+ base::Unretained(this), callback));
}
void RequireVersion(uint32_t version) {
@@ -65,9 +59,13 @@ class AssociatedInterfacePtrState {
return;
version_ = version;
- // Do a static cast in case the interface contains methods with the same
- // name.
- static_cast<ControlMessageProxy*>(proxy_.get())->RequireVersion(version);
+ endpoint_client_->RequireVersion(version);
+ }
+
+ void FlushForTesting() { endpoint_client_->FlushForTesting(); }
+
+ void CloseWithReason(uint32_t custom_reason, const std::string& description) {
+ endpoint_client_->CloseWithReason(custom_reason, description);
}
void Swap(AssociatedInterfacePtrState* other) {
@@ -85,13 +83,13 @@ class AssociatedInterfacePtrState {
DCHECK(info.is_valid());
version_ = info.version();
+ // The version is only queried from the client so the value passed here
+ // will not be used.
endpoint_client_.reset(new InterfaceEndpointClient(
info.PassHandle(), nullptr,
base::WrapUnique(new typename Interface::ResponseValidator_()), false,
- std::move(runner)));
+ std::move(runner), 0u));
proxy_.reset(new Proxy(endpoint_client_.get()));
- proxy_->serialization_context()->group_controller =
- endpoint_client_->group_controller();
}
// After this method is called, the object is in an invalid state and
@@ -114,6 +112,12 @@ class AssociatedInterfacePtrState {
endpoint_client_->set_connection_error_handler(error_handler);
}
+ void set_connection_error_with_reason_handler(
+ const ConnectionErrorWithReasonCallback& error_handler) {
+ DCHECK(endpoint_client_);
+ endpoint_client_->set_connection_error_with_reason_handler(error_handler);
+ }
+
// Returns true if bound and awaiting a response to a message.
bool has_pending_callbacks() const {
return endpoint_client_ && endpoint_client_->has_pending_responders();
@@ -123,6 +127,13 @@ class AssociatedInterfacePtrState {
return endpoint_client_ ? endpoint_client_->associated_group() : nullptr;
}
+ void ForwardMessage(Message message) { endpoint_client_->Accept(&message); }
+
+ void ForwardMessageWithResponder(Message message,
+ std::unique_ptr<MessageReceiver> responder) {
+ endpoint_client_->AcceptWithResponder(&message, responder.release());
+ }
+
private:
using Proxy = typename Interface::Proxy_;
diff --git a/mojo/public/cpp/bindings/lib/binding_state.cc b/mojo/public/cpp/bindings/lib/binding_state.cc
new file mode 100644
index 0000000..b34cb47
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/binding_state.cc
@@ -0,0 +1,90 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/public/cpp/bindings/lib/binding_state.h"
+
+namespace mojo {
+namespace internal {
+
+BindingStateBase::BindingStateBase() = default;
+
+BindingStateBase::~BindingStateBase() = default;
+
+void BindingStateBase::AddFilter(std::unique_ptr<MessageReceiver> filter) {
+ DCHECK(endpoint_client_);
+ endpoint_client_->AddFilter(std::move(filter));
+}
+
+bool BindingStateBase::HasAssociatedInterfaces() const {
+ return router_ ? router_->HasAssociatedEndpoints() : false;
+}
+
+void BindingStateBase::PauseIncomingMethodCallProcessing() {
+ DCHECK(router_);
+ router_->PauseIncomingMethodCallProcessing();
+}
+void BindingStateBase::ResumeIncomingMethodCallProcessing() {
+ DCHECK(router_);
+ router_->ResumeIncomingMethodCallProcessing();
+}
+
+bool BindingStateBase::WaitForIncomingMethodCall(MojoDeadline deadline) {
+ DCHECK(router_);
+ return router_->WaitForIncomingMessage(deadline);
+}
+
+void BindingStateBase::Close() {
+ if (!router_)
+ return;
+
+ endpoint_client_.reset();
+ router_->CloseMessagePipe();
+ router_ = nullptr;
+}
+
+void BindingStateBase::CloseWithReason(uint32_t custom_reason,
+ const std::string& description) {
+ if (endpoint_client_)
+ endpoint_client_->CloseWithReason(custom_reason, description);
+
+ Close();
+}
+
+void BindingStateBase::FlushForTesting() {
+ endpoint_client_->FlushForTesting();
+}
+
+void BindingStateBase::EnableTestingMode() {
+ DCHECK(is_bound());
+ router_->EnableTestingMode();
+}
+
+void BindingStateBase::BindInternal(
+ ScopedMessagePipeHandle handle,
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const char* interface_name,
+ std::unique_ptr<MessageReceiver> request_validator,
+ bool passes_associated_kinds,
+ bool has_sync_methods,
+ MessageReceiverWithResponderStatus* stub,
+ uint32_t interface_version) {
+ DCHECK(!router_);
+
+ MultiplexRouter::Config config =
+ passes_associated_kinds
+ ? MultiplexRouter::MULTI_INTERFACE
+ : (has_sync_methods
+ ? MultiplexRouter::SINGLE_INTERFACE_WITH_SYNC_METHODS
+ : MultiplexRouter::SINGLE_INTERFACE);
+ router_ = new MultiplexRouter(std::move(handle), config, false, runner);
+ router_->SetMasterInterfaceName(interface_name);
+
+ endpoint_client_.reset(new InterfaceEndpointClient(
+ router_->CreateLocalEndpointHandle(kMasterInterfaceId), stub,
+ std::move(request_validator), has_sync_methods, std::move(runner),
+ interface_version));
+}
+
+} // namesapce internal
+} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/binding_state.h b/mojo/public/cpp/bindings/lib/binding_state.h
index c8d3e83..0b0dbee 100644
--- a/mojo/public/cpp/bindings/lib/binding_state.h
+++ b/mojo/public/cpp/bindings/lib/binding_state.h
@@ -6,6 +6,7 @@
#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDING_STATE_H_
#include <memory>
+#include <string>
#include <utility>
#include "base/bind.h"
@@ -15,15 +16,15 @@
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
-#include "mojo/public/cpp/bindings/associated_group.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
+#include "mojo/public/cpp/bindings/connection_error_callback.h"
+#include "mojo/public/cpp/bindings/filter_chain.h"
#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
#include "mojo/public/cpp/bindings/interface_id.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "mojo/public/cpp/bindings/interface_ptr_info.h"
#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/bindings/lib/filter_chain.h"
#include "mojo/public/cpp/bindings/lib/multiplex_router.h"
-#include "mojo/public/cpp/bindings/lib/router.h"
#include "mojo/public/cpp/bindings/message_header_validator.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
#include "mojo/public/cpp/system/core.h"
@@ -31,76 +32,34 @@
namespace mojo {
namespace internal {
-template <typename Interface, bool use_multiplex_router>
-class BindingState;
-
-// Uses a single-threaded, dedicated router. If |Interface| doesn't have any
-// methods to pass associated interface pointers or requests, there won't be
-// multiple interfaces running on the underlying message pipe. In that case, we
-// can use this specialization to reduce cost.
-template <typename Interface>
-class BindingState<Interface, false> {
+class MOJO_CPP_BINDINGS_EXPORT BindingStateBase {
public:
- explicit BindingState(Interface* impl) : impl_(impl) {
- stub_.set_sink(impl_);
- }
+ BindingStateBase();
+ ~BindingStateBase();
- ~BindingState() { Close(); }
+ void AddFilter(std::unique_ptr<MessageReceiver> filter);
- void Bind(ScopedMessagePipeHandle handle,
- scoped_refptr<base::SingleThreadTaskRunner> runner) {
- DCHECK(!router_);
- internal::FilterChain filters;
- filters.Append<MessageHeaderValidator>(Interface::Name_);
- filters.Append<typename Interface::RequestValidator_>();
-
- router_ =
- new internal::Router(std::move(handle), std::move(filters),
- Interface::HasSyncMethods_, std::move(runner));
- router_->set_incoming_receiver(&stub_);
- router_->set_connection_error_handler(
- base::Bind(&BindingState::RunConnectionErrorHandler,
- base::Unretained(this)));
- }
-
- bool HasAssociatedInterfaces() const { return false; }
+ bool HasAssociatedInterfaces() const;
- void PauseIncomingMethodCallProcessing() {
- DCHECK(router_);
- router_->PauseIncomingMethodCallProcessing();
- }
- void ResumeIncomingMethodCallProcessing() {
- DCHECK(router_);
- router_->ResumeIncomingMethodCallProcessing();
- }
+ void PauseIncomingMethodCallProcessing();
+ void ResumeIncomingMethodCallProcessing();
bool WaitForIncomingMethodCall(
- MojoDeadline deadline = MOJO_DEADLINE_INDEFINITE) {
- DCHECK(router_);
- return router_->WaitForIncomingMessage(deadline);
- }
-
- void Close() {
- if (!router_)
- return;
-
- router_->CloseMessagePipe();
- DestroyRouter();
- }
+ MojoDeadline deadline = MOJO_DEADLINE_INDEFINITE);
- InterfaceRequest<Interface> Unbind() {
- InterfaceRequest<Interface> request =
- MakeRequest<Interface>(router_->PassMessagePipe());
- DestroyRouter();
- return std::move(request);
- }
+ void Close();
+ void CloseWithReason(uint32_t custom_reason, const std::string& description);
void set_connection_error_handler(const base::Closure& error_handler) {
DCHECK(is_bound());
- connection_error_handler_ = error_handler;
+ endpoint_client_->set_connection_error_handler(error_handler);
}
- Interface* impl() { return impl_; }
+ void set_connection_error_with_reason_handler(
+ const ConnectionErrorWithReasonCallback& error_handler) {
+ DCHECK(is_bound());
+ endpoint_client_->set_connection_error_with_reason_handler(error_handler);
+ }
bool is_bound() const { return !!router_; }
@@ -109,90 +68,42 @@ class BindingState<Interface, false> {
return router_->handle();
}
- AssociatedGroup* associated_group() { return nullptr; }
+ void FlushForTesting();
- void EnableTestingMode() {
- DCHECK(is_bound());
- router_->EnableTestingMode();
- }
+ void EnableTestingMode();
- private:
- void DestroyRouter() {
- router_->set_connection_error_handler(base::Closure());
- delete router_;
- router_ = nullptr;
- connection_error_handler_.Reset();
- }
-
- void RunConnectionErrorHandler() {
- if (!connection_error_handler_.is_null())
- connection_error_handler_.Run();
- }
+ protected:
+ void BindInternal(ScopedMessagePipeHandle handle,
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const char* interface_name,
+ std::unique_ptr<MessageReceiver> request_validator,
+ bool passes_associated_kinds,
+ bool has_sync_methods,
+ MessageReceiverWithResponderStatus* stub,
+ uint32_t interface_version);
- internal::Router* router_ = nullptr;
- typename Interface::Stub_ stub_;
- Interface* impl_;
- base::Closure connection_error_handler_;
-
- DISALLOW_COPY_AND_ASSIGN(BindingState);
+ scoped_refptr<internal::MultiplexRouter> router_;
+ std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
};
-// Uses a multiplexing router. If |Interface| has methods to pass associated
-// interface pointers or requests, this specialization should be used.
-template <typename Interface>
-class BindingState<Interface, true> {
+template <typename Interface, typename ImplRefTraits>
+class BindingState : public BindingStateBase {
public:
- explicit BindingState(Interface* impl) : impl_(impl) {
- stub_.set_sink(impl_);
+ using ImplPointerType = typename ImplRefTraits::PointerType;
+
+ explicit BindingState(ImplPointerType impl) {
+ stub_.set_sink(std::move(impl));
}
~BindingState() { Close(); }
void Bind(ScopedMessagePipeHandle handle,
scoped_refptr<base::SingleThreadTaskRunner> runner) {
- DCHECK(!router_);
-
- router_ = new internal::MultiplexRouter(false, std::move(handle), runner);
- router_->SetMasterInterfaceName(Interface::Name_);
- stub_.serialization_context()->group_controller = router_;
-
- endpoint_client_.reset(new InterfaceEndpointClient(
- router_->CreateLocalEndpointHandle(kMasterInterfaceId),
- &stub_, base::WrapUnique(new typename Interface::RequestValidator_()),
- Interface::HasSyncMethods_, std::move(runner)));
-
- endpoint_client_->set_connection_error_handler(
- base::Bind(&BindingState::RunConnectionErrorHandler,
- base::Unretained(this)));
- }
-
- bool HasAssociatedInterfaces() const {
- return router_ ? router_->HasAssociatedEndpoints() : false;
- }
-
- void PauseIncomingMethodCallProcessing() {
- DCHECK(router_);
- router_->PauseIncomingMethodCallProcessing();
- }
- void ResumeIncomingMethodCallProcessing() {
- DCHECK(router_);
- router_->ResumeIncomingMethodCallProcessing();
- }
-
- bool WaitForIncomingMethodCall(
- MojoDeadline deadline = MOJO_DEADLINE_INDEFINITE) {
- DCHECK(router_);
- return router_->WaitForIncomingMessage(deadline);
- }
-
- void Close() {
- if (!router_)
- return;
-
- endpoint_client_.reset();
- router_->CloseMessagePipe();
- router_ = nullptr;
- connection_error_handler_.Reset();
+ BindingStateBase::BindInternal(
+ std::move(handle), runner, Interface::Name_,
+ base::MakeUnique<typename Interface::RequestValidator_>(),
+ Interface::PassesAssociatedKinds_, Interface::HasSyncMethods_, &stub_,
+ Interface::Version_);
}
InterfaceRequest<Interface> Unbind() {
@@ -200,45 +111,13 @@ class BindingState<Interface, true> {
InterfaceRequest<Interface> request =
MakeRequest<Interface>(router_->PassMessagePipe());
router_ = nullptr;
- connection_error_handler_.Reset();
return request;
}
- void set_connection_error_handler(const base::Closure& error_handler) {
- DCHECK(is_bound());
- connection_error_handler_ = error_handler;
- }
-
- Interface* impl() { return impl_; }
-
- bool is_bound() const { return !!router_; }
-
- MessagePipeHandle handle() const {
- DCHECK(is_bound());
- return router_->handle();
- }
-
- AssociatedGroup* associated_group() {
- return endpoint_client_ ? endpoint_client_->associated_group() : nullptr;
- }
-
- void EnableTestingMode() {
- DCHECK(is_bound());
- router_->EnableTestingMode();
- }
+ Interface* impl() { return ImplRefTraits::GetRawPointer(&stub_.sink()); }
private:
- void RunConnectionErrorHandler() {
- if (!connection_error_handler_.is_null())
- connection_error_handler_.Run();
- }
-
- scoped_refptr<internal::MultiplexRouter> router_;
- std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
-
- typename Interface::Stub_ stub_;
- Interface* impl_;
- base::Closure connection_error_handler_;
+ typename Interface::template Stub_<ImplRefTraits> stub_;
DISALLOW_COPY_AND_ASSIGN(BindingState);
};
diff --git a/mojo/public/cpp/bindings/lib/bindings_internal.cc b/mojo/public/cpp/bindings/lib/bindings_internal.cc
deleted file mode 100644
index a3bdb1f..0000000
--- a/mojo/public/cpp/bindings/lib/bindings_internal.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
-
-namespace mojo {
-namespace internal {
-
-namespace {
-
-const size_t kAlignment = 8;
-
-template <typename T>
-T AlignImpl(T t) {
- return t + (kAlignment - (t % kAlignment)) % kAlignment;
-}
-
-} // namespace
-
-size_t Align(size_t size) {
- return AlignImpl(size);
-}
-
-char* AlignPointer(char* ptr) {
- return reinterpret_cast<char*>(AlignImpl(reinterpret_cast<uintptr_t>(ptr)));
-}
-
-bool IsAligned(const void* ptr) {
- return !(reinterpret_cast<uintptr_t>(ptr) % kAlignment);
-}
-
-void EncodePointer(const void* ptr, uint64_t* offset) {
- if (!ptr) {
- *offset = 0;
- return;
- }
-
- const char* p_obj = reinterpret_cast<const char*>(ptr);
- const char* p_slot = reinterpret_cast<const char*>(offset);
- DCHECK(p_obj > p_slot);
-
- *offset = static_cast<uint64_t>(p_obj - p_slot);
-}
-
-} // namespace internal
-} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/bindings_internal.h b/mojo/public/cpp/bindings/lib/bindings_internal.h
index b37d872..631daec 100644
--- a/mojo/public/cpp/bindings/lib/bindings_internal.h
+++ b/mojo/public/cpp/bindings/lib/bindings_internal.h
@@ -17,30 +17,26 @@
namespace mojo {
template <typename T>
-class Array;
+class ArrayDataView;
template <typename T>
-class AssociatedInterfacePtrInfo;
+class AssociatedInterfacePtrInfoDataView;
template <typename T>
-class AssociatedInterfaceRequest;
+class AssociatedInterfaceRequestDataView;
template <typename T>
-class InterfacePtr;
+class InterfacePtrDataView;
template <typename T>
-class InterfaceRequest;
+class InterfaceRequestDataView;
template <typename K, typename V>
-class Map;
+class MapDataView;
-class String;
+class NativeStructDataView;
-template <typename T>
-class StructPtr;
-
-template <typename T>
-class InlinedStructPtr;
+class StringDataView;
namespace internal {
@@ -58,12 +54,17 @@ class Array_Data;
template <typename K, typename V>
class Map_Data;
+class NativeStruct_Data;
+
using String_Data = Array_Data<char>;
-size_t Align(size_t size);
-char* AlignPointer(char* ptr);
+inline size_t Align(size_t size) {
+ return (size + 7) & ~0x7;
+}
-bool IsAligned(const void* ptr);
+inline bool IsAligned(const void* ptr) {
+ return !(reinterpret_cast<uintptr_t>(ptr) & 0x7);
+}
// Pointers are encoded as relative offsets. The offsets are relative to the
// address of where the offset value is stored, such that the pointer may be
@@ -73,7 +74,19 @@ bool IsAligned(const void* ptr);
//
// A null pointer is encoded as an offset value of 0.
//
-void EncodePointer(const void* ptr, uint64_t* offset);
+inline void EncodePointer(const void* ptr, uint64_t* offset) {
+ if (!ptr) {
+ *offset = 0;
+ return;
+ }
+
+ const char* p_obj = reinterpret_cast<const char*>(ptr);
+ const char* p_slot = reinterpret_cast<const char*>(offset);
+ DCHECK(p_obj > p_slot);
+
+ *offset = static_cast<uint64_t>(p_obj - p_slot);
+}
+
// Note: This function doesn't validate the encoded pointer value.
inline const void* DecodePointer(const uint64_t* offset) {
if (!*offset)
@@ -111,6 +124,8 @@ struct Pointer {
};
static_assert(sizeof(Pointer<char>) == 8, "Bad_sizeof(Pointer)");
+using GenericPointer = Pointer<void>;
+
struct Handle_Data {
Handle_Data() = default;
explicit Handle_Data(uint32_t value) : value(value) {}
@@ -127,19 +142,24 @@ struct Interface_Data {
};
static_assert(sizeof(Interface_Data) == 8, "Bad_sizeof(Interface_Data)");
+struct AssociatedEndpointHandle_Data {
+ AssociatedEndpointHandle_Data() = default;
+ explicit AssociatedEndpointHandle_Data(uint32_t value) : value(value) {}
+
+ bool is_valid() const { return value != kEncodedInvalidHandleValue; }
+
+ uint32_t value;
+};
+static_assert(sizeof(AssociatedEndpointHandle_Data) == 4,
+ "Bad_sizeof(AssociatedEndpointHandle_Data)");
+
struct AssociatedInterface_Data {
- InterfaceId interface_id;
+ AssociatedEndpointHandle_Data handle;
uint32_t version;
};
static_assert(sizeof(AssociatedInterface_Data) == 8,
"Bad_sizeof(AssociatedInterface_Data)");
-struct AssociatedInterfaceRequest_Data {
- InterfaceId interface_id;
-};
-static_assert(sizeof(AssociatedInterfaceRequest_Data) == 4,
- "Bad_sizeof(AssociatedInterfaceRequest_Data)");
-
#pragma pack(pop)
template <typename T>
@@ -203,7 +223,7 @@ struct MojomTypeTraits {
};
template <typename T>
-struct MojomTypeTraits<Array<T>, false> {
+struct MojomTypeTraits<ArrayDataView<T>, false> {
using Data = Array_Data<typename MojomTypeTraits<T>::DataAsArrayElement>;
using DataAsArrayElement = Pointer<Data>;
@@ -211,7 +231,7 @@ struct MojomTypeTraits<Array<T>, false> {
};
template <typename T>
-struct MojomTypeTraits<AssociatedInterfacePtrInfo<T>, false> {
+struct MojomTypeTraits<AssociatedInterfacePtrInfoDataView<T>, false> {
using Data = AssociatedInterface_Data;
using DataAsArrayElement = Data;
@@ -220,8 +240,8 @@ struct MojomTypeTraits<AssociatedInterfacePtrInfo<T>, false> {
};
template <typename T>
-struct MojomTypeTraits<AssociatedInterfaceRequest<T>, false> {
- using Data = AssociatedInterfaceRequest_Data;
+struct MojomTypeTraits<AssociatedInterfaceRequestDataView<T>, false> {
+ using Data = AssociatedEndpointHandle_Data;
using DataAsArrayElement = Data;
static const MojomTypeCategory category =
@@ -253,7 +273,7 @@ struct MojomTypeTraits<ScopedHandleBase<T>, false> {
};
template <typename T>
-struct MojomTypeTraits<InterfacePtr<T>, false> {
+struct MojomTypeTraits<InterfacePtrDataView<T>, false> {
using Data = Interface_Data;
using DataAsArrayElement = Data;
@@ -261,7 +281,7 @@ struct MojomTypeTraits<InterfacePtr<T>, false> {
};
template <typename T>
-struct MojomTypeTraits<InterfaceRequest<T>, false> {
+struct MojomTypeTraits<InterfaceRequestDataView<T>, false> {
using Data = Handle_Data;
using DataAsArrayElement = Data;
@@ -270,7 +290,7 @@ struct MojomTypeTraits<InterfaceRequest<T>, false> {
};
template <typename K, typename V>
-struct MojomTypeTraits<Map<K, V>, false> {
+struct MojomTypeTraits<MapDataView<K, V>, false> {
using Data = Map_Data<typename MojomTypeTraits<K>::DataAsArrayElement,
typename MojomTypeTraits<V>::DataAsArrayElement>;
using DataAsArrayElement = Pointer<Data>;
@@ -279,37 +299,19 @@ struct MojomTypeTraits<Map<K, V>, false> {
};
template <>
-struct MojomTypeTraits<String, false> {
- using Data = String_Data;
+struct MojomTypeTraits<NativeStructDataView, false> {
+ using Data = internal::NativeStruct_Data;
using DataAsArrayElement = Pointer<Data>;
- static const MojomTypeCategory category = MojomTypeCategory::STRING;
+ static const MojomTypeCategory category = MojomTypeCategory::STRUCT;
};
-template <typename T>
-struct MojomTypeTraits<StructPtr<T>, false> {
- using Data = typename T::Data_;
- using DataAsArrayElement =
- typename std::conditional<IsUnionDataType<Data>::value,
- Data,
- Pointer<Data>>::type;
-
- static const MojomTypeCategory category = IsUnionDataType<Data>::value
- ? MojomTypeCategory::UNION
- : MojomTypeCategory::STRUCT;
-};
+template <>
+struct MojomTypeTraits<StringDataView, false> {
+ using Data = String_Data;
+ using DataAsArrayElement = Pointer<Data>;
-template <typename T>
-struct MojomTypeTraits<InlinedStructPtr<T>, false> {
- using Data = typename T::Data_;
- using DataAsArrayElement =
- typename std::conditional<IsUnionDataType<Data>::value,
- Data,
- Pointer<Data>>::type;
-
- static const MojomTypeCategory category = IsUnionDataType<Data>::value
- ? MojomTypeCategory::UNION
- : MojomTypeCategory::STRUCT;
+ static const MojomTypeCategory category = MojomTypeCategory::STRING;
};
template <typename T, MojomTypeCategory categories>
diff --git a/mojo/public/cpp/bindings/lib/buffer.h b/mojo/public/cpp/bindings/lib/buffer.h
index c3b570e..213a445 100644
--- a/mojo/public/cpp/bindings/lib/buffer.h
+++ b/mojo/public/cpp/bindings/lib/buffer.h
@@ -7,15 +7,61 @@
#include <stddef.h>
+#include "base/logging.h"
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+
namespace mojo {
namespace internal {
-// Buffer provides a way to allocate memory. Allocations are 8-byte aligned and
-// zero-initialized. Allocations remain valid for the lifetime of the Buffer.
+// Buffer provides an interface to allocate memory blocks which are 8-byte
+// aligned and zero-initialized. It doesn't own the underlying memory. Users
+// must ensure that the memory stays valid while using the allocated blocks from
+// Buffer.
class Buffer {
public:
- virtual ~Buffer() {}
- virtual void* Allocate(size_t num_bytes) = 0;
+ Buffer() {}
+
+ // The memory must have been zero-initialized. |data| must be 8-byte
+ // aligned.
+ void Initialize(void* data, size_t size) {
+ DCHECK(IsAligned(data));
+
+ data_ = data;
+ size_ = size;
+ cursor_ = reinterpret_cast<uintptr_t>(data);
+ data_end_ = cursor_ + size;
+ }
+
+ size_t size() const { return size_; }
+
+ void* data() const { return data_; }
+
+ // Allocates |num_bytes| from the buffer and returns a pointer to the start of
+ // the allocated block.
+ // The resulting address is 8-byte aligned, and the content of the memory is
+ // zero-filled.
+ void* Allocate(size_t num_bytes) {
+ num_bytes = Align(num_bytes);
+ uintptr_t result = cursor_;
+ cursor_ += num_bytes;
+ if (cursor_ > data_end_ || cursor_ < result) {
+ NOTREACHED();
+ cursor_ -= num_bytes;
+ return nullptr;
+ }
+
+ return reinterpret_cast<void*>(result);
+ }
+
+ private:
+ void* data_ = nullptr;
+ size_t size_ = 0;
+
+ uintptr_t cursor_ = 0;
+ uintptr_t data_end_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(Buffer);
};
} // namespace internal
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc
index 1bb38f0..4426def 100644
--- a/mojo/public/cpp/bindings/lib/connector.cc
+++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -12,52 +12,20 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/synchronization/lock.h"
+#include "mojo/public/cpp/bindings/lib/may_auto_lock.h"
#include "mojo/public/cpp/bindings/sync_handle_watcher.h"
namespace mojo {
-namespace {
-
-// Similar to base::AutoLock, except that it does nothing if |lock| passed into
-// the constructor is null.
-class MayAutoLock {
- public:
- explicit MayAutoLock(base::Lock* lock) : lock_(lock) {
- if (lock_)
- lock_->Acquire();
- }
-
- ~MayAutoLock() {
- if (lock_) {
- lock_->AssertAcquired();
- lock_->Release();
- }
- }
-
- private:
- base::Lock* lock_;
- DISALLOW_COPY_AND_ASSIGN(MayAutoLock);
-};
-
-} // namespace
-
-// ----------------------------------------------------------------------------
-
Connector::Connector(ScopedMessagePipeHandle message_pipe,
ConnectorConfig config,
scoped_refptr<base::SingleThreadTaskRunner> runner)
: message_pipe_(std::move(message_pipe)),
- incoming_receiver_(nullptr),
task_runner_(std::move(runner)),
- handle_watcher_(task_runner_),
- error_(false),
- drop_writes_(false),
- enforce_errors_from_incoming_receiver_(true),
- paused_(false),
- lock_(config == MULTI_THREADED_SEND ? new base::Lock : nullptr),
- allow_woken_up_by_others_(false),
- sync_handle_watcher_callback_count_(0),
weak_factory_(this) {
+ if (config == MULTI_THREADED_SEND)
+ lock_.emplace();
+
weak_self_ = weak_factory_.GetWeakPtr();
// Even though we don't have an incoming receiver, we still want to monitor
// the message pipe to know if is closed or encounters an error.
@@ -65,25 +33,34 @@ Connector::Connector(ScopedMessagePipeHandle message_pipe,
}
Connector::~Connector() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ {
+ // Allow for quick destruction on any thread if the pipe is already closed.
+ base::AutoLock lock(connected_lock_);
+ if (!connected_)
+ return;
+ }
+ DCHECK(thread_checker_.CalledOnValidThread());
CancelWait();
}
void Connector::CloseMessagePipe() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- CancelWait();
- MayAutoLock locker(lock_.get());
- message_pipe_.reset();
+ // Throw away the returned message pipe.
+ PassMessagePipe();
}
ScopedMessagePipeHandle Connector::PassMessagePipe() {
DCHECK(thread_checker_.CalledOnValidThread());
CancelWait();
- MayAutoLock locker(lock_.get());
- return std::move(message_pipe_);
+ internal::MayAutoLock locker(&lock_);
+ ScopedMessagePipeHandle message_pipe = std::move(message_pipe_);
+ weak_factory_.InvalidateWeakPtrs();
+ sync_handle_watcher_callback_count_ = 0;
+
+ base::AutoLock lock(connected_lock_);
+ connected_ = false;
+ return message_pipe;
}
void Connector::RaiseError() {
@@ -143,7 +120,7 @@ bool Connector::Accept(Message* message) {
if (error_)
return false;
- MayAutoLock locker(lock_.get());
+ internal::MayAutoLock locker(&lock_);
if (!message_pipe_.is_valid() || drop_writes_)
return true;
@@ -204,6 +181,13 @@ bool Connector::SyncWatch(const bool* should_stop) {
return sync_watcher_->SyncWatch(should_stop);
}
+void Connector::SetWatcherHeapProfilerTag(const char* tag) {
+ heap_profiler_tag_ = tag;
+ if (handle_watcher_) {
+ handle_watcher_->set_heap_profiler_tag(tag);
+ }
+}
+
void Connector::OnWatcherHandleReady(MojoResult result) {
OnHandleReadyInternal(result);
}
@@ -214,8 +198,10 @@ void Connector::OnSyncHandleWatcherHandleReady(MojoResult result) {
sync_handle_watcher_callback_count_++;
OnHandleReadyInternal(result);
// At this point, this object might have been deleted.
- if (weak_self)
+ if (weak_self) {
+ DCHECK_LT(0u, sync_handle_watcher_callback_count_);
sync_handle_watcher_callback_count_--;
+ }
}
void Connector::OnHandleReadyInternal(MojoResult result) {
@@ -231,12 +217,14 @@ void Connector::OnHandleReadyInternal(MojoResult result) {
void Connector::WaitToReadMore() {
CHECK(!paused_);
- DCHECK(!handle_watcher_.IsWatching());
+ DCHECK(!handle_watcher_);
- MojoResult rv = handle_watcher_.Start(
+ handle_watcher_.reset(new Watcher(FROM_HERE, task_runner_));
+ if (heap_profiler_tag_)
+ handle_watcher_->set_heap_profiler_tag(heap_profiler_tag_);
+ MojoResult rv = handle_watcher_->Start(
message_pipe_.get(), MOJO_HANDLE_SIGNAL_READABLE,
- base::Bind(&Connector::OnWatcherHandleReady,
- base::Unretained(this)));
+ base::Bind(&Connector::OnWatcherHandleReady, base::Unretained(this)));
if (rv != MOJO_RESULT_OK) {
// If the watch failed because the handle is invalid or its conditions can
@@ -257,8 +245,8 @@ bool Connector::ReadSingleMessage(MojoResult* read_result) {
bool receiver_result = false;
- // Detect if |this| was destroyed during message dispatch. Allow for the
- // possibility of re-entering ReadMore() through message dispatch.
+ // Detect if |this| was destroyed or the message pipe was closed/transferred
+ // during message dispatch.
base::WeakPtr<Connector> weak_self = weak_self_;
Message message;
@@ -292,9 +280,11 @@ void Connector::ReadAllAvailableMessages() {
while (!error_) {
MojoResult rv;
- // Return immediately if |this| was destroyed. Do not touch any members!
- if (!ReadSingleMessage(&rv))
+ if (!ReadSingleMessage(&rv)) {
+ // Return immediately without touching any members. |this| may have been
+ // destroyed.
return;
+ }
if (paused_)
return;
@@ -305,7 +295,7 @@ void Connector::ReadAllAvailableMessages() {
}
void Connector::CancelWait() {
- handle_watcher_.Cancel();
+ handle_watcher_.reset();
sync_watcher_.reset();
}
@@ -325,7 +315,7 @@ void Connector::HandleError(bool force_pipe_reset, bool force_async_handler) {
if (force_pipe_reset) {
CancelWait();
- MayAutoLock locker(lock_.get());
+ internal::MayAutoLock locker(&lock_);
message_pipe_.reset();
MessagePipe dummy_pipe;
message_pipe_ = std::move(dummy_pipe.handle0);
diff --git a/mojo/public/cpp/bindings/lib/control_message_handler.cc b/mojo/public/cpp/bindings/lib/control_message_handler.cc
index 9f44e88..c90aada 100644
--- a/mojo/public/cpp/bindings/lib/control_message_handler.cc
+++ b/mojo/public/cpp/bindings/lib/control_message_handler.cc
@@ -11,15 +11,53 @@
#include "base/logging.h"
#include "mojo/public/cpp/bindings/lib/message_builder.h"
#include "mojo/public/cpp/bindings/lib/serialization.h"
+#include "mojo/public/cpp/bindings/lib/validation_util.h"
#include "mojo/public/interfaces/bindings/interface_control_messages.mojom.h"
namespace mojo {
namespace internal {
+namespace {
+
+bool ValidateControlRequestWithResponse(Message* message) {
+ ValidationContext validation_context(message->payload(),
+ message->payload_num_bytes(), 0, 0,
+ message, "ControlRequestValidator");
+ if (!ValidateMessageIsRequestExpectingResponse(message, &validation_context))
+ return false;
+
+ switch (message->header()->name) {
+ case interface_control::kRunMessageId:
+ return ValidateMessagePayload<
+ interface_control::internal::RunMessageParams_Data>(
+ message, &validation_context);
+ }
+ return false;
+}
+
+bool ValidateControlRequestWithoutResponse(Message* message) {
+ ValidationContext validation_context(message->payload(),
+ message->payload_num_bytes(), 0, 0,
+ message, "ControlRequestValidator");
+ if (!ValidateMessageIsRequestWithoutResponse(message, &validation_context))
+ return false;
+
+ switch (message->header()->name) {
+ case interface_control::kRunOrClosePipeMessageId:
+ return ValidateMessageIsRequestWithoutResponse(message,
+ &validation_context) &&
+ ValidateMessagePayload<
+ interface_control::internal::RunOrClosePipeMessageParams_Data>(
+ message, &validation_context);
+ }
+ return false;
+}
+
+} // namespace
// static
bool ControlMessageHandler::IsControlMessage(const Message* message) {
- return message->header()->name == kRunMessageId ||
- message->header()->name == kRunOrClosePipeMessageId;
+ return message->header()->name == interface_control::kRunMessageId ||
+ message->header()->name == interface_control::kRunOrClosePipeMessageId;
}
ControlMessageHandler::ControlMessageHandler(uint32_t interface_version)
@@ -30,7 +68,10 @@ ControlMessageHandler::~ControlMessageHandler() {
}
bool ControlMessageHandler::Accept(Message* message) {
- if (message->header()->name == kRunOrClosePipeMessageId)
+ if (!ValidateControlRequestWithoutResponse(message))
+ return false;
+
+ if (message->header()->name == interface_control::kRunOrClosePipeMessageId)
return RunOrClosePipe(message);
NOTREACHED();
@@ -40,7 +81,10 @@ bool ControlMessageHandler::Accept(Message* message) {
bool ControlMessageHandler::AcceptWithResponder(
Message* message,
MessageReceiverWithStatus* responder) {
- if (message->header()->name == kRunMessageId)
+ if (!ValidateControlRequestWithResponse(message))
+ return false;
+
+ if (message->header()->name == interface_control::kRunMessageId)
return Run(message, responder);
NOTREACHED();
@@ -49,20 +93,37 @@ bool ControlMessageHandler::AcceptWithResponder(
bool ControlMessageHandler::Run(Message* message,
MessageReceiverWithStatus* responder) {
- RunResponseMessageParamsPtr response_params_ptr(
- RunResponseMessageParams::New());
- response_params_ptr->reserved0 = 16u;
- response_params_ptr->reserved1 = 0u;
- response_params_ptr->query_version_result = QueryVersionResult::New();
- response_params_ptr->query_version_result->version = interface_version_;
-
- size_t size = PrepareToSerialize<RunResponseMessageParamsPtr>(
- response_params_ptr, &context_);
- ResponseMessageBuilder builder(kRunMessageId, size, message->request_id());
-
- RunResponseMessageParams_Data* response_params = nullptr;
- Serialize<RunResponseMessageParamsPtr>(response_params_ptr, builder.buffer(),
- &response_params, &context_);
+ interface_control::internal::RunMessageParams_Data* params =
+ reinterpret_cast<interface_control::internal::RunMessageParams_Data*>(
+ message->mutable_payload());
+ interface_control::RunMessageParamsPtr params_ptr;
+ Deserialize<interface_control::RunMessageParamsDataView>(params, &params_ptr,
+ &context_);
+ auto& input = *params_ptr->input;
+ interface_control::RunOutputPtr output = interface_control::RunOutput::New();
+ if (input.is_query_version()) {
+ output->set_query_version_result(
+ interface_control::QueryVersionResult::New());
+ output->get_query_version_result()->version = interface_version_;
+ } else if (input.is_flush_for_testing()) {
+ output.reset();
+ } else {
+ output.reset();
+ }
+
+ auto response_params_ptr = interface_control::RunResponseMessageParams::New();
+ response_params_ptr->output = std::move(output);
+ size_t size =
+ PrepareToSerialize<interface_control::RunResponseMessageParamsDataView>(
+ response_params_ptr, &context_);
+ MessageBuilder builder(interface_control::kRunMessageId,
+ Message::kFlagIsResponse, size, 0);
+ builder.message()->set_request_id(message->request_id());
+
+ interface_control::internal::RunResponseMessageParams_Data* response_params =
+ nullptr;
+ Serialize<interface_control::RunResponseMessageParamsDataView>(
+ response_params_ptr, builder.buffer(), &response_params, &context_);
bool ok = responder->Accept(builder.message());
ALLOW_UNUSED_LOCAL(ok);
delete responder;
@@ -71,13 +132,18 @@ bool ControlMessageHandler::Run(Message* message,
}
bool ControlMessageHandler::RunOrClosePipe(Message* message) {
- RunOrClosePipeMessageParams_Data* params =
- reinterpret_cast<RunOrClosePipeMessageParams_Data*>(
+ interface_control::internal::RunOrClosePipeMessageParams_Data* params =
+ reinterpret_cast<
+ interface_control::internal::RunOrClosePipeMessageParams_Data*>(
message->mutable_payload());
- RunOrClosePipeMessageParamsPtr params_ptr;
- Deserialize<RunOrClosePipeMessageParamsPtr>(params, &params_ptr, &context_);
+ interface_control::RunOrClosePipeMessageParamsPtr params_ptr;
+ Deserialize<interface_control::RunOrClosePipeMessageParamsDataView>(
+ params, &params_ptr, &context_);
+ auto& input = *params_ptr->input;
+ if (input.is_require_version())
+ return interface_version_ >= input.get_require_version()->version;
- return interface_version_ >= params_ptr->require_version->version;
+ return false;
}
} // namespace internal
diff --git a/mojo/public/cpp/bindings/lib/control_message_handler.h b/mojo/public/cpp/bindings/lib/control_message_handler.h
index 13b5aa6..3c385e4 100644
--- a/mojo/public/cpp/bindings/lib/control_message_handler.h
+++ b/mojo/public/cpp/bindings/lib/control_message_handler.h
@@ -7,7 +7,9 @@
#include <stdint.h>
+#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/lib/serialization_context.h"
#include "mojo/public/cpp/bindings/message.h"
@@ -15,7 +17,8 @@ namespace mojo {
namespace internal {
// Handlers for request messages defined in interface_control_messages.mojom.
-class ControlMessageHandler : public MessageReceiverWithResponderStatus {
+class MOJO_CPP_BINDINGS_EXPORT ControlMessageHandler
+ : NON_EXPORTED_BASE(public MessageReceiverWithResponderStatus) {
public:
static bool IsControlMessage(const Message* message);
diff --git a/mojo/public/cpp/bindings/lib/control_message_proxy.cc b/mojo/public/cpp/bindings/lib/control_message_proxy.cc
index 7af409d..23de991 100644
--- a/mojo/public/cpp/bindings/lib/control_message_proxy.cc
+++ b/mojo/public/cpp/bindings/lib/control_message_proxy.cc
@@ -9,9 +9,12 @@
#include <utility>
#include "base/bind.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
+#include "base/run_loop.h"
#include "mojo/public/cpp/bindings/lib/message_builder.h"
#include "mojo/public/cpp/bindings/lib/serialization.h"
+#include "mojo/public/cpp/bindings/lib/validation_util.h"
#include "mojo/public/cpp/bindings/message.h"
#include "mojo/public/interfaces/bindings/interface_control_messages.mojom.h"
@@ -20,11 +23,28 @@ namespace internal {
namespace {
-using RunCallback = base::Callback<void(QueryVersionResultPtr)>;
+bool ValidateControlResponse(Message* message) {
+ ValidationContext validation_context(message->payload(),
+ message->payload_num_bytes(), 0, 0,
+ message, "ControlResponseValidator");
+ if (!ValidateMessageIsResponse(message, &validation_context))
+ return false;
+
+ switch (message->header()->name) {
+ case interface_control::kRunMessageId:
+ return ValidateMessagePayload<
+ interface_control::internal::RunResponseMessageParams_Data>(
+ message, &validation_context);
+ }
+ return false;
+}
+
+using RunCallback =
+ base::Callback<void(interface_control::RunResponseMessageParamsPtr)>;
class RunResponseForwardToCallback : public MessageReceiver {
public:
- RunResponseForwardToCallback(const RunCallback& callback)
+ explicit RunResponseForwardToCallback(const RunCallback& callback)
: callback_(callback) {}
bool Accept(Message* message) override;
@@ -34,59 +54,83 @@ class RunResponseForwardToCallback : public MessageReceiver {
};
bool RunResponseForwardToCallback::Accept(Message* message) {
- RunResponseMessageParams_Data* params =
- reinterpret_cast<RunResponseMessageParams_Data*>(
+ if (!ValidateControlResponse(message))
+ return false;
+
+ interface_control::internal::RunResponseMessageParams_Data* params =
+ reinterpret_cast<
+ interface_control::internal::RunResponseMessageParams_Data*>(
message->mutable_payload());
- RunResponseMessageParamsPtr params_ptr;
+ interface_control::RunResponseMessageParamsPtr params_ptr;
SerializationContext context;
- Deserialize<RunResponseMessageParamsPtr>(params, &params_ptr, &context);
+ Deserialize<interface_control::RunResponseMessageParamsDataView>(
+ params, &params_ptr, &context);
- callback_.Run(std::move(params_ptr->query_version_result));
+ callback_.Run(std::move(params_ptr));
return true;
}
void SendRunMessage(MessageReceiverWithResponder* receiver,
- QueryVersionPtr query_version,
- const RunCallback& callback,
- SerializationContext* context) {
- RunMessageParamsPtr params_ptr(RunMessageParams::New());
- params_ptr->reserved0 = 16u;
- params_ptr->reserved1 = 0u;
- params_ptr->query_version = std::move(query_version);
-
- size_t size = PrepareToSerialize<RunMessageParamsPtr>(params_ptr, context);
- RequestMessageBuilder builder(kRunMessageId, size);
-
- RunMessageParams_Data* params = nullptr;
- Serialize<RunMessageParamsPtr>(params_ptr, builder.buffer(), &params,
- context);
+ interface_control::RunInputPtr input_ptr,
+ const RunCallback& callback) {
+ SerializationContext context;
+
+ auto params_ptr = interface_control::RunMessageParams::New();
+ params_ptr->input = std::move(input_ptr);
+ size_t size = PrepareToSerialize<interface_control::RunMessageParamsDataView>(
+ params_ptr, &context);
+ MessageBuilder builder(interface_control::kRunMessageId,
+ Message::kFlagExpectsResponse, size, 0);
+
+ interface_control::internal::RunMessageParams_Data* params = nullptr;
+ Serialize<interface_control::RunMessageParamsDataView>(
+ params_ptr, builder.buffer(), &params, &context);
MessageReceiver* responder = new RunResponseForwardToCallback(callback);
if (!receiver->AcceptWithResponder(builder.message(), responder))
delete responder;
}
-void SendRunOrClosePipeMessage(MessageReceiverWithResponder* receiver,
- RequireVersionPtr require_version,
- SerializationContext* context) {
- RunOrClosePipeMessageParamsPtr params_ptr(RunOrClosePipeMessageParams::New());
- params_ptr->reserved0 = 16u;
- params_ptr->reserved1 = 0u;
- params_ptr->require_version = std::move(require_version);
-
- size_t size =
- PrepareToSerialize<RunOrClosePipeMessageParamsPtr>(params_ptr, context);
- MessageBuilder builder(kRunOrClosePipeMessageId, size);
-
- RunOrClosePipeMessageParams_Data* params = nullptr;
- Serialize<RunOrClosePipeMessageParamsPtr>(params_ptr, builder.buffer(),
- &params, context);
- bool ok = receiver->Accept(builder.message());
+Message ConstructRunOrClosePipeMessage(
+ interface_control::RunOrClosePipeInputPtr input_ptr) {
+ SerializationContext context;
+
+ auto params_ptr = interface_control::RunOrClosePipeMessageParams::New();
+ params_ptr->input = std::move(input_ptr);
+
+ size_t size = PrepareToSerialize<
+ interface_control::RunOrClosePipeMessageParamsDataView>(params_ptr,
+ &context);
+ MessageBuilder builder(interface_control::kRunOrClosePipeMessageId, 0, size,
+ 0);
+
+ interface_control::internal::RunOrClosePipeMessageParams_Data* params =
+ nullptr;
+ Serialize<interface_control::RunOrClosePipeMessageParamsDataView>(
+ params_ptr, builder.buffer(), &params, &context);
+ return std::move(*builder.message());
+}
+
+void SendRunOrClosePipeMessage(
+ MessageReceiverWithResponder* receiver,
+ interface_control::RunOrClosePipeInputPtr input_ptr) {
+ Message message(ConstructRunOrClosePipeMessage(std::move(input_ptr)));
+
+ bool ok = receiver->Accept(&message);
ALLOW_UNUSED_LOCAL(ok);
}
-void RunVersionCallback(const base::Callback<void(uint32_t)>& callback,
- QueryVersionResultPtr query_version_result) {
- callback.Run(query_version_result->version);
+void RunVersionCallback(
+ const base::Callback<void(uint32_t)>& callback,
+ interface_control::RunResponseMessageParamsPtr run_response) {
+ uint32_t version = 0u;
+ if (run_response->output && run_response->output->is_query_version_result())
+ version = run_response->output->get_query_version_result()->version;
+ callback.Run(version);
+}
+
+void RunClosure(const base::Closure& callback,
+ interface_control::RunResponseMessageParamsPtr run_response) {
+ callback.Run();
}
} // namespace
@@ -95,16 +139,49 @@ ControlMessageProxy::ControlMessageProxy(MessageReceiverWithResponder* receiver)
: receiver_(receiver) {
}
+ControlMessageProxy::~ControlMessageProxy() = default;
+
void ControlMessageProxy::QueryVersion(
const base::Callback<void(uint32_t)>& callback) {
- SendRunMessage(receiver_, QueryVersion::New(),
- base::Bind(&RunVersionCallback, callback), &context_);
+ auto input_ptr = interface_control::RunInput::New();
+ input_ptr->set_query_version(interface_control::QueryVersion::New());
+ SendRunMessage(receiver_, std::move(input_ptr),
+ base::Bind(&RunVersionCallback, callback));
}
void ControlMessageProxy::RequireVersion(uint32_t version) {
- RequireVersionPtr require_version(RequireVersion::New());
+ auto require_version = interface_control::RequireVersion::New();
require_version->version = version;
- SendRunOrClosePipeMessage(receiver_, std::move(require_version), &context_);
+ auto input_ptr = interface_control::RunOrClosePipeInput::New();
+ input_ptr->set_require_version(std::move(require_version));
+ SendRunOrClosePipeMessage(receiver_, std::move(input_ptr));
+}
+
+void ControlMessageProxy::FlushForTesting() {
+ if (encountered_error_)
+ return;
+
+ auto input_ptr = interface_control::RunInput::New();
+ input_ptr->set_flush_for_testing(interface_control::FlushForTesting::New());
+ base::RunLoop run_loop;
+ run_loop_quit_closure_ = run_loop.QuitClosure();
+ SendRunMessage(
+ receiver_, std::move(input_ptr),
+ base::Bind(&RunClosure,
+ base::Bind(&ControlMessageProxy::RunFlushForTestingClosure,
+ base::Unretained(this))));
+ run_loop.Run();
+}
+
+void ControlMessageProxy::RunFlushForTestingClosure() {
+ DCHECK(!run_loop_quit_closure_.is_null());
+ base::ResetAndReturn(&run_loop_quit_closure_).Run();
+}
+
+void ControlMessageProxy::OnConnectionError() {
+ encountered_error_ = true;
+ if (!run_loop_quit_closure_.is_null())
+ RunFlushForTestingClosure();
}
} // namespace internal
diff --git a/mojo/public/cpp/bindings/lib/control_message_proxy.h b/mojo/public/cpp/bindings/lib/control_message_proxy.h
index 5ec6ddc..2f9314e 100644
--- a/mojo/public/cpp/bindings/lib/control_message_proxy.h
+++ b/mojo/public/cpp/bindings/lib/control_message_proxy.h
@@ -7,8 +7,9 @@
#include <stdint.h>
-#include "base/callback_forward.h"
+#include "base/callback.h"
#include "base/macros.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/lib/serialization_context.h"
namespace mojo {
@@ -18,18 +19,26 @@ class MessageReceiverWithResponder;
namespace internal {
// Proxy for request messages defined in interface_control_messages.mojom.
-class ControlMessageProxy {
+class MOJO_CPP_BINDINGS_EXPORT ControlMessageProxy {
public:
// Doesn't take ownership of |receiver|. It must outlive this object.
explicit ControlMessageProxy(MessageReceiverWithResponder* receiver);
+ ~ControlMessageProxy();
void QueryVersion(const base::Callback<void(uint32_t)>& callback);
void RequireVersion(uint32_t version);
- protected:
+ void FlushForTesting();
+ void OnConnectionError();
+
+ private:
+ void RunFlushForTestingClosure();
+
// Not owned.
MessageReceiverWithResponder* receiver_;
- SerializationContext context_;
+ bool encountered_error_ = false;
+
+ base::Closure run_loop_quit_closure_;
DISALLOW_COPY_AND_ASSIGN(ControlMessageProxy);
};
diff --git a/mojo/public/cpp/bindings/lib/clone_equals_util.h b/mojo/public/cpp/bindings/lib/equals_traits.h
index f7bd898..53c7dce 100644
--- a/mojo/public/cpp/bindings/lib/clone_equals_util.h
+++ b/mojo/public/cpp/bindings/lib/equals_traits.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_CLONE_EQUALS_UTIL_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_LIB_CLONE_EQUALS_UTIL_H_
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_EQUALS_TRAITS_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_EQUALS_TRAITS_H_
#include <type_traits>
#include <unordered_map>
@@ -16,73 +16,6 @@ namespace mojo {
namespace internal {
template <typename T>
-struct HasCloneMethod {
- template <typename U>
- static char Test(decltype(&U::Clone));
- template <typename U>
- static int Test(...);
- static const bool value = sizeof(Test<T>(0)) == sizeof(char);
-
- private:
- EnsureTypeIsComplete<T> check_t_;
-};
-
-template <typename T, bool has_clone_method = HasCloneMethod<T>::value>
-struct CloneTraits;
-
-template <typename T>
-T Clone(const T& input);
-
-template <typename T>
-struct CloneTraits<T, true> {
- static T Clone(const T& input) { return input.Clone(); }
-};
-
-template <typename T>
-struct CloneTraits<T, false> {
- static T Clone(const T& input) { return input; }
-};
-
-template <typename T>
-struct CloneTraits<base::Optional<T>, false> {
- static base::Optional<T> Clone(const base::Optional<T>& input) {
- if (!input)
- return base::nullopt;
-
- return base::Optional<T>(internal::Clone(*input));
- }
-};
-
-template <typename T>
-struct CloneTraits<std::vector<T>, false> {
- static std::vector<T> Clone(const std::vector<T>& input) {
- std::vector<T> result;
- result.reserve(input.size());
- for (const auto& element : input)
- result.push_back(internal::Clone(element));
-
- return result;
- }
-};
-
-template <typename K, typename V>
-struct CloneTraits<std::unordered_map<K, V>, false> {
- static std::unordered_map<K, V> Clone(const std::unordered_map<K, V>& input) {
- std::unordered_map<K, V> result;
- for (const auto& element : input) {
- result.insert(std::make_pair(internal::Clone(element.first),
- internal::Clone(element.second)));
- }
- return result;
- }
-};
-
-template <typename T>
-T Clone(const T& input) {
- return CloneTraits<T>::Clone(input);
-};
-
-template <typename T>
struct HasEqualsMethod {
template <typename U>
static char Test(decltype(&U::Equals));
@@ -158,4 +91,4 @@ bool Equals(const T& a, const T& b) {
} // namespace internal
} // namespace mojo
-#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_CLONE_EQUALS_UTIL_H_
+#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_EQUALS_TRAITS_H_
diff --git a/mojo/public/cpp/bindings/lib/filter_chain.cc b/mojo/public/cpp/bindings/lib/filter_chain.cc
index 899bac1..5d919fe 100644
--- a/mojo/public/cpp/bindings/lib/filter_chain.cc
+++ b/mojo/public/cpp/bindings/lib/filter_chain.cc
@@ -2,14 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "mojo/public/cpp/bindings/lib/filter_chain.h"
+#include "mojo/public/cpp/bindings/filter_chain.h"
#include <algorithm>
#include "base/logging.h"
namespace mojo {
-namespace internal {
FilterChain::FilterChain(MessageReceiver* sink) : sink_(sink) {
}
@@ -26,24 +25,23 @@ FilterChain& FilterChain::operator=(FilterChain&& other) {
}
FilterChain::~FilterChain() {
- for (std::vector<MessageFilter*>::iterator iter = filters_.begin();
- iter != filters_.end();
- ++iter) {
- delete *iter;
- }
}
void FilterChain::SetSink(MessageReceiver* sink) {
DCHECK(!sink_);
sink_ = sink;
- if (!filters_.empty())
- filters_.back()->set_sink(sink);
}
-MessageReceiver* FilterChain::GetHead() {
+bool FilterChain::Accept(Message* message) {
DCHECK(sink_);
- return filters_.empty() ? sink_ : filters_.front();
+ for (auto& filter : filters_)
+ if (!filter->Accept(message))
+ return false;
+ return sink_->Accept(message);
+}
+
+void FilterChain::Append(std::unique_ptr<MessageReceiver> filter) {
+ filters_.emplace_back(std::move(filter));
}
-} // namespace internal
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/fixed_buffer.cc b/mojo/public/cpp/bindings/lib/fixed_buffer.cc
index 50b8a21..725a193 100644
--- a/mojo/public/cpp/bindings/lib/fixed_buffer.cc
+++ b/mojo/public/cpp/bindings/lib/fixed_buffer.cc
@@ -4,56 +4,25 @@
#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
-#include <stddef.h>
#include <stdlib.h>
-#include <algorithm>
-
-#include "base/logging.h"
-#include "mojo/public/cpp/bindings/lib/serialization_util.h"
-
namespace mojo {
namespace internal {
-FixedBuffer::FixedBuffer() : ptr_(nullptr), cursor_(0), size_(0) {}
-
-void FixedBuffer::Initialize(void* memory, size_t size) {
- DCHECK(size == internal::Align(size));
-
- ptr_ = static_cast<char*>(memory);
- cursor_ = 0;
- size_ = size;
-}
-
-void* FixedBuffer::Allocate(size_t delta) {
- delta = internal::Align(delta);
-
- if (delta == 0 || delta > size_ - cursor_) {
- NOTREACHED();
- return nullptr;
- }
-
- char* result = ptr_ + cursor_;
- cursor_ += delta;
-
- return result;
-}
-
FixedBufferForTesting::FixedBufferForTesting(size_t size) {
- size_ = internal::Align(size);
+ size = internal::Align(size);
// Use calloc here to ensure all message memory is zero'd out.
- ptr_ = static_cast<char*>(calloc(size_, 1));
+ void* ptr = calloc(size, 1);
+ Initialize(ptr, size);
}
FixedBufferForTesting::~FixedBufferForTesting() {
- free(ptr_);
+ free(data());
}
void* FixedBufferForTesting::Leak() {
- char* ptr = ptr_;
- ptr_ = nullptr;
- cursor_ = 0;
- size_ = 0;
+ void* ptr = data();
+ Initialize(nullptr, 0);
return ptr;
}
diff --git a/mojo/public/cpp/bindings/lib/fixed_buffer.h b/mojo/public/cpp/bindings/lib/fixed_buffer.h
index 9a5704b..070b0c8 100644
--- a/mojo/public/cpp/bindings/lib/fixed_buffer.h
+++ b/mojo/public/cpp/bindings/lib/fixed_buffer.h
@@ -7,62 +7,21 @@
#include <stddef.h>
+#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/lib/buffer.h"
namespace mojo {
namespace internal {
-// FixedBuffer provides a simple way to allocate objects within a fixed chunk
-// of memory. Objects are allocated by calling the |Allocate| method, which
-// extends the buffer accordingly. Objects allocated in this way are not freed
-// explicitly. Instead, they remain valid so long as the FixedBuffer remains
-// valid. The Leak method may be used to steal the underlying memory from the
-// FixedBuffer.
-//
-// Typical usage:
-//
-// {
-// FixedBuffer buf(8 + 8);
-//
-// int* a = static_cast<int*>(buf->Allocate(sizeof(int)));
-// *a = 2;
-//
-// double* b = static_cast<double*>(buf->Allocate(sizeof(double)));
-// *b = 3.14f;
-//
-// void* data = buf.Leak();
-// Process(data);
-//
-// free(data);
-// }
-
-class FixedBuffer : public Buffer {
- public:
- FixedBuffer();
-
- // |size| should be aligned using internal::Align.
- void Initialize(void* memory, size_t size);
-
- size_t size() const { return size_; }
-
- // Grows the buffer by |num_bytes| and returns a pointer to the start of the
- // addition. The resulting address is 8-byte aligned, and the content of the
- // memory is zero-filled.
- void* Allocate(size_t num_bytes) override;
-
- protected:
- char* ptr_;
- size_t cursor_;
- size_t size_;
-
- DISALLOW_COPY_AND_ASSIGN(FixedBuffer);
-};
-
-class FixedBufferForTesting : public FixedBuffer {
+// FixedBufferForTesting owns its buffer. The Leak method may be used to steal
+// the underlying memory.
+class MOJO_CPP_BINDINGS_EXPORT FixedBufferForTesting
+ : NON_EXPORTED_BASE(public Buffer) {
public:
explicit FixedBufferForTesting(size_t size);
- ~FixedBufferForTesting() override;
+ ~FixedBufferForTesting();
// Returns the internal memory owned by the Buffer to the caller. The Buffer
// relinquishes its pointer, effectively resetting the state of the Buffer
diff --git a/mojo/public/cpp/bindings/lib/handle_interface_serialization.h b/mojo/public/cpp/bindings/lib/handle_interface_serialization.h
index 344c2ca..14ed21f 100644
--- a/mojo/public/cpp/bindings/lib/handle_interface_serialization.h
+++ b/mojo/public/cpp/bindings/lib/handle_interface_serialization.h
@@ -5,9 +5,12 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_HANDLE_INTERFACE_SERIALIZATION_H_
#define MOJO_PUBLIC_CPP_BINDINGS_LIB_HANDLE_INTERFACE_SERIALIZATION_H_
+#include <type_traits>
+
#include "mojo/public/cpp/bindings/associated_group_controller.h"
#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
#include "mojo/public/cpp/bindings/associated_interface_request.h"
+#include "mojo/public/cpp/bindings/interface_data_view.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
@@ -18,52 +21,98 @@
namespace mojo {
namespace internal {
-template <typename T>
-struct Serializer<AssociatedInterfacePtrInfo<T>,
+template <typename Base, typename T>
+struct Serializer<AssociatedInterfacePtrInfoDataView<Base>,
AssociatedInterfacePtrInfo<T>> {
+ static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch.");
+
+ static size_t PrepareToSerialize(const AssociatedInterfacePtrInfo<T>& input,
+ SerializationContext* context) {
+ if (input.handle().is_valid())
+ context->associated_endpoint_count++;
+ return 0;
+ }
+
static void Serialize(AssociatedInterfacePtrInfo<T>& input,
AssociatedInterface_Data* output,
SerializationContext* context) {
- DCHECK(!input.handle().is_valid() || !input.handle().is_local());
- DCHECK_EQ(input.handle().group_controller(),
- context->group_controller.get());
+ DCHECK(!input.handle().is_valid() || input.handle().pending_association());
+ if (input.handle().is_valid()) {
+ // Set to the index of the element pushed to the back of the vector.
+ output->handle.value =
+ static_cast<uint32_t>(context->associated_endpoint_handles.size());
+ context->associated_endpoint_handles.push_back(input.PassHandle());
+ } else {
+ output->handle.value = kEncodedInvalidHandleValue;
+ }
output->version = input.version();
- output->interface_id = input.PassHandle().release();
}
static bool Deserialize(AssociatedInterface_Data* input,
AssociatedInterfacePtrInfo<T>* output,
SerializationContext* context) {
- output->set_handle(context->group_controller->CreateLocalEndpointHandle(
- FetchAndReset(&input->interface_id)));
+ if (input->handle.is_valid()) {
+ DCHECK_LT(input->handle.value,
+ context->associated_endpoint_handles.size());
+ output->set_handle(
+ std::move(context->associated_endpoint_handles[input->handle.value]));
+ } else {
+ output->set_handle(ScopedInterfaceEndpointHandle());
+ }
output->set_version(input->version);
return true;
}
};
-template <typename T>
-struct Serializer<AssociatedInterfaceRequest<T>,
+template <typename Base, typename T>
+struct Serializer<AssociatedInterfaceRequestDataView<Base>,
AssociatedInterfaceRequest<T>> {
+ static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch.");
+
+ static size_t PrepareToSerialize(const AssociatedInterfaceRequest<T>& input,
+ SerializationContext* context) {
+ if (input.handle().is_valid())
+ context->associated_endpoint_count++;
+ return 0;
+ }
+
static void Serialize(AssociatedInterfaceRequest<T>& input,
- AssociatedInterfaceRequest_Data* output,
+ AssociatedEndpointHandle_Data* output,
SerializationContext* context) {
- DCHECK(!input.handle().is_valid() || !input.handle().is_local());
- DCHECK_EQ(input.handle().group_controller(),
- context->group_controller.get());
- output->interface_id = input.PassHandle().release();
+ DCHECK(!input.handle().is_valid() || input.handle().pending_association());
+ if (input.handle().is_valid()) {
+ // Set to the index of the element pushed to the back of the vector.
+ output->value =
+ static_cast<uint32_t>(context->associated_endpoint_handles.size());
+ context->associated_endpoint_handles.push_back(input.PassHandle());
+ } else {
+ output->value = kEncodedInvalidHandleValue;
+ }
}
- static bool Deserialize(AssociatedInterfaceRequest_Data* input,
+ static bool Deserialize(AssociatedEndpointHandle_Data* input,
AssociatedInterfaceRequest<T>* output,
SerializationContext* context) {
- output->Bind(context->group_controller->CreateLocalEndpointHandle(
- FetchAndReset(&input->interface_id)));
+ if (input->is_valid()) {
+ DCHECK_LT(input->value, context->associated_endpoint_handles.size());
+ output->Bind(
+ std::move(context->associated_endpoint_handles[input->value]));
+ } else {
+ output->Bind(ScopedInterfaceEndpointHandle());
+ }
return true;
}
};
-template <typename T>
-struct Serializer<InterfacePtr<T>, InterfacePtr<T>> {
+template <typename Base, typename T>
+struct Serializer<InterfacePtrDataView<Base>, InterfacePtr<T>> {
+ static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch.");
+
+ static size_t PrepareToSerialize(const InterfacePtr<T>& input,
+ SerializationContext* context) {
+ return 0;
+ }
+
static void Serialize(InterfacePtr<T>& input,
Interface_Data* output,
SerializationContext* context) {
@@ -82,8 +131,15 @@ struct Serializer<InterfacePtr<T>, InterfacePtr<T>> {
}
};
-template <typename T>
-struct Serializer<InterfaceRequest<T>, InterfaceRequest<T>> {
+template <typename Base, typename T>
+struct Serializer<InterfaceRequestDataView<Base>, InterfaceRequest<T>> {
+ static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch.");
+
+ static size_t PrepareToSerialize(const InterfaceRequest<T>& input,
+ SerializationContext* context) {
+ return 0;
+ }
+
static void Serialize(InterfaceRequest<T>& input,
Handle_Data* output,
SerializationContext* context) {
@@ -100,6 +156,11 @@ struct Serializer<InterfaceRequest<T>, InterfaceRequest<T>> {
template <typename T>
struct Serializer<ScopedHandleBase<T>, ScopedHandleBase<T>> {
+ static size_t PrepareToSerialize(const ScopedHandleBase<T>& input,
+ SerializationContext* context) {
+ return 0;
+ }
+
static void Serialize(ScopedHandleBase<T>& input,
Handle_Data* output,
SerializationContext* context) {
diff --git a/mojo/public/cpp/bindings/lib/hash_util.h b/mojo/public/cpp/bindings/lib/hash_util.h
new file mode 100644
index 0000000..93280d6
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/hash_util.h
@@ -0,0 +1,84 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_HASH_UTIL_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_HASH_UTIL_H_
+
+#include <cstring>
+#include <functional>
+#include <type_traits>
+#include <vector>
+
+#include "base/optional.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+
+namespace mojo {
+namespace internal {
+
+template <typename T>
+size_t HashCombine(size_t seed, const T& value) {
+ // Based on proposal in:
+ // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
+ return seed ^ (std::hash<T>()(value) + (seed << 6) + (seed >> 2));
+}
+
+template <typename T>
+struct HasHashMethod {
+ template <typename U>
+ static char Test(decltype(&U::Hash));
+ template <typename U>
+ static int Test(...);
+ static const bool value = sizeof(Test<T>(0)) == sizeof(char);
+
+ private:
+ EnsureTypeIsComplete<T> check_t_;
+};
+
+template <typename T, bool has_hash_method = HasHashMethod<T>::value>
+struct HashTraits;
+
+template <typename T>
+size_t Hash(size_t seed, const T& value);
+
+template <typename T>
+struct HashTraits<T, true> {
+ static size_t Hash(size_t seed, const T& value) { return value.Hash(seed); }
+};
+
+template <typename T>
+struct HashTraits<T, false> {
+ static size_t Hash(size_t seed, const T& value) {
+ return HashCombine(seed, value);
+ }
+};
+
+template <typename T>
+struct HashTraits<std::vector<T>, false> {
+ static size_t Hash(size_t seed, const std::vector<T>& value) {
+ for (const auto& element : value) {
+ seed = HashCombine(seed, element);
+ }
+ return seed;
+ }
+};
+
+template <typename T>
+struct HashTraits<base::Optional<std::vector<T>>, false> {
+ static size_t Hash(size_t seed, const base::Optional<std::vector<T>>& value) {
+ if (!value)
+ return HashCombine(seed, 0);
+
+ return Hash(seed, *value);
+ }
+};
+
+template <typename T>
+size_t Hash(size_t seed, const T& value) {
+ return HashTraits<T>::Hash(seed, value);
+}
+
+} // namespace internal
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_HASH_UTIL_H_
diff --git a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
index e1f388a..3eca5a1 100644
--- a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
+++ b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/location.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
@@ -17,6 +18,7 @@
#include "mojo/public/cpp/bindings/associated_group.h"
#include "mojo/public/cpp/bindings/associated_group_controller.h"
#include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
+#include "mojo/public/cpp/bindings/lib/validation_util.h"
#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
namespace mojo {
@@ -45,7 +47,7 @@ class ResponderThunk : public MessageReceiverWithStatus {
task_runner_(std::move(runner)) {}
~ResponderThunk() override {
if (!accept_was_invoked_) {
- // The Mojo application handled a message that was expecting a response
+ // The Service handled a message that was expecting a response
// but did not send a response.
// We raise an error to signal the calling application that an error
// condition occurred. Without this the calling application would have no
@@ -132,47 +134,47 @@ bool InterfaceEndpointClient::HandleIncomingMessageThunk::Accept(
InterfaceEndpointClient::InterfaceEndpointClient(
ScopedInterfaceEndpointHandle handle,
MessageReceiverWithResponderStatus* receiver,
- std::unique_ptr<MessageFilter> payload_validator,
+ std::unique_ptr<MessageReceiver> payload_validator,
bool expect_sync_requests,
- scoped_refptr<base::SingleThreadTaskRunner> runner)
- : handle_(std::move(handle)),
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ uint32_t interface_version)
+ : expect_sync_requests_(expect_sync_requests),
+ handle_(std::move(handle)),
incoming_receiver_(receiver),
- payload_validator_(std::move(payload_validator)),
thunk_(this),
- next_request_id_(1),
- encountered_error_(false),
+ filters_(&thunk_),
task_runner_(std::move(runner)),
+ control_message_proxy_(this),
+ control_message_handler_(interface_version),
weak_ptr_factory_(this) {
DCHECK(handle_.is_valid());
- DCHECK(handle_.is_local());
// TODO(yzshen): the way to use validator (or message filter in general)
// directly is a little awkward.
- payload_validator_->set_sink(&thunk_);
+ if (payload_validator)
+ filters_.Append(std::move(payload_validator));
- controller_ = handle_.group_controller()->AttachEndpointClient(
- handle_, this, task_runner_);
- if (expect_sync_requests)
- controller_->AllowWokenUpBySyncWatchOnSameThread();
+ if (handle_.pending_association()) {
+ handle_.SetAssociationEventHandler(base::Bind(
+ &InterfaceEndpointClient::OnAssociationEvent, base::Unretained(this)));
+ } else {
+ InitControllerIfNecessary();
+ }
}
InterfaceEndpointClient::~InterfaceEndpointClient() {
DCHECK(thread_checker_.CalledOnValidThread());
- handle_.group_controller()->DetachEndpointClient(handle_);
+ if (controller_)
+ handle_.group_controller()->DetachEndpointClient(handle_);
}
AssociatedGroup* InterfaceEndpointClient::associated_group() {
if (!associated_group_)
- associated_group_ = handle_.group_controller()->CreateAssociatedGroup();
+ associated_group_ = base::MakeUnique<AssociatedGroup>(handle_);
return associated_group_.get();
}
-uint32_t InterfaceEndpointClient::interface_id() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- return handle_.id();
-}
-
ScopedInterfaceEndpointHandle InterfaceEndpointClient::PassHandle() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!has_pending_responders());
@@ -180,38 +182,73 @@ ScopedInterfaceEndpointHandle InterfaceEndpointClient::PassHandle() {
if (!handle_.is_valid())
return ScopedInterfaceEndpointHandle();
- controller_ = nullptr;
- handle_.group_controller()->DetachEndpointClient(handle_);
+ handle_.SetAssociationEventHandler(
+ ScopedInterfaceEndpointHandle::AssociationEventCallback());
+
+ if (controller_) {
+ controller_ = nullptr;
+ handle_.group_controller()->DetachEndpointClient(handle_);
+ }
return std::move(handle_);
}
+void InterfaceEndpointClient::AddFilter(
+ std::unique_ptr<MessageReceiver> filter) {
+ filters_.Append(std::move(filter));
+}
+
void InterfaceEndpointClient::RaiseError() {
DCHECK(thread_checker_.CalledOnValidThread());
- handle_.group_controller()->RaiseError();
+ if (!handle_.pending_association())
+ handle_.group_controller()->RaiseError();
+}
+
+void InterfaceEndpointClient::CloseWithReason(uint32_t custom_reason,
+ const std::string& description) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ auto handle = PassHandle();
+ handle.ResetWithReason(custom_reason, description);
}
bool InterfaceEndpointClient::Accept(Message* message) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(controller_);
DCHECK(!message->has_flag(Message::kFlagExpectsResponse));
+ DCHECK(!handle_.pending_association());
+
+ // This has to been done even if connection error has occurred. For example,
+ // the message contains a pending associated request. The user may try to use
+ // the corresponding associated interface pointer after sending this message.
+ // That associated interface pointer has to join an associated group in order
+ // to work properly.
+ if (!message->associated_endpoint_handles()->empty())
+ message->SerializeAssociatedEndpointHandles(handle_.group_controller());
if (encountered_error_)
return false;
+ InitControllerIfNecessary();
+
return controller_->SendMessage(message);
}
bool InterfaceEndpointClient::AcceptWithResponder(Message* message,
MessageReceiver* responder) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(controller_);
DCHECK(message->has_flag(Message::kFlagExpectsResponse));
+ DCHECK(!handle_.pending_association());
+
+ // Please see comments in Accept().
+ if (!message->associated_endpoint_handles()->empty())
+ message->SerializeAssociatedEndpointHandles(handle_.group_controller());
if (encountered_error_)
return false;
+ InitControllerIfNecessary();
+
// Reserve 0 in case we want it to convey special meaning in the future.
uint64_t request_id = next_request_id_++;
if (request_id == 0)
@@ -234,20 +271,18 @@ bool InterfaceEndpointClient::AcceptWithResponder(Message* message,
bool response_received = false;
std::unique_ptr<MessageReceiver> sync_responder(responder);
sync_responses_.insert(std::make_pair(
- request_id, base::WrapUnique(new SyncResponseInfo(&response_received))));
+ request_id, base::MakeUnique<SyncResponseInfo>(&response_received)));
base::WeakPtr<InterfaceEndpointClient> weak_self =
weak_ptr_factory_.GetWeakPtr();
controller_->SyncWatch(&response_received);
// Make sure that this instance hasn't been destroyed.
if (weak_self) {
- DCHECK(ContainsKey(sync_responses_, request_id));
+ DCHECK(base::ContainsKey(sync_responses_, request_id));
auto iter = sync_responses_.find(request_id);
DCHECK_EQ(&response_received, iter->second->response_received);
- if (response_received) {
- std::unique_ptr<Message> response = std::move(iter->second->response);
- ignore_result(sync_responder->Accept(response.get()));
- }
+ if (response_received)
+ ignore_result(sync_responder->Accept(&iter->second->response));
sync_responses_.erase(iter);
}
@@ -257,30 +292,97 @@ bool InterfaceEndpointClient::AcceptWithResponder(Message* message,
bool InterfaceEndpointClient::HandleIncomingMessage(Message* message) {
DCHECK(thread_checker_.CalledOnValidThread());
-
- return payload_validator_->Accept(message);
+ return filters_.Accept(message);
}
-void InterfaceEndpointClient::NotifyError() {
+void InterfaceEndpointClient::NotifyError(
+ const base::Optional<DisconnectReason>& reason) {
DCHECK(thread_checker_.CalledOnValidThread());
if (encountered_error_)
return;
encountered_error_ = true;
- if (!error_handler_.is_null())
- error_handler_.Run();
+
+ // Response callbacks may hold on to resource, and there's no need to keep
+ // them alive any longer. Note that it's allowed that a pending response
+ // callback may own this endpoint, so we simply move the responders onto the
+ // stack here and let them be destroyed when the stack unwinds.
+ AsyncResponderMap responders = std::move(async_responders_);
+
+ control_message_proxy_.OnConnectionError();
+
+ if (!error_handler_.is_null()) {
+ base::Closure error_handler = std::move(error_handler_);
+ error_handler.Run();
+ } else if (!error_with_reason_handler_.is_null()) {
+ ConnectionErrorWithReasonCallback error_with_reason_handler =
+ std::move(error_with_reason_handler_);
+ if (reason) {
+ error_with_reason_handler.Run(reason->custom_reason, reason->description);
+ } else {
+ error_with_reason_handler.Run(0, std::string());
+ }
+ }
+}
+
+void InterfaceEndpointClient::QueryVersion(
+ const base::Callback<void(uint32_t)>& callback) {
+ control_message_proxy_.QueryVersion(callback);
+}
+
+void InterfaceEndpointClient::RequireVersion(uint32_t version) {
+ control_message_proxy_.RequireVersion(version);
+}
+
+void InterfaceEndpointClient::FlushForTesting() {
+ control_message_proxy_.FlushForTesting();
+}
+
+void InterfaceEndpointClient::InitControllerIfNecessary() {
+ if (controller_ || handle_.pending_association())
+ return;
+
+ controller_ = handle_.group_controller()->AttachEndpointClient(handle_, this,
+ task_runner_);
+ if (expect_sync_requests_)
+ controller_->AllowWokenUpBySyncWatchOnSameThread();
+}
+
+void InterfaceEndpointClient::OnAssociationEvent(
+ ScopedInterfaceEndpointHandle::AssociationEvent event) {
+ if (event == ScopedInterfaceEndpointHandle::ASSOCIATED) {
+ InitControllerIfNecessary();
+ } else if (event ==
+ ScopedInterfaceEndpointHandle::PEER_CLOSED_BEFORE_ASSOCIATION) {
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&InterfaceEndpointClient::NotifyError,
+ weak_ptr_factory_.GetWeakPtr(),
+ handle_.disconnect_reason()));
+ }
}
bool InterfaceEndpointClient::HandleValidatedMessage(Message* message) {
DCHECK_EQ(handle_.id(), message->interface_id());
- if (message->has_flag(Message::kFlagExpectsResponse)) {
- if (!incoming_receiver_)
- return false;
+ if (encountered_error_) {
+ // This message is received after error has been encountered. For associated
+ // interfaces, this means the remote side sends a
+ // PeerAssociatedEndpointClosed event but continues to send more messages
+ // for the same interface. Close the pipe because this shouldn't happen.
+ DVLOG(1) << "A message is received for an interface after it has been "
+ << "disconnected. Closing the pipe.";
+ return false;
+ }
+ if (message->has_flag(Message::kFlagExpectsResponse)) {
MessageReceiverWithStatus* responder =
new ResponderThunk(weak_ptr_factory_.GetWeakPtr(), task_runner_);
- bool ok = incoming_receiver_->AcceptWithResponder(message, responder);
+ bool ok = false;
+ if (mojo::internal::ControlMessageHandler::IsControlMessage(message)) {
+ ok = control_message_handler_.AcceptWithResponder(message, responder);
+ } else {
+ ok = incoming_receiver_->AcceptWithResponder(message, responder);
+ }
if (!ok)
delete responder;
return ok;
@@ -291,8 +393,7 @@ bool InterfaceEndpointClient::HandleValidatedMessage(Message* message) {
auto it = sync_responses_.find(request_id);
if (it == sync_responses_.end())
return false;
- it->second->response.reset(new Message());
- message->MoveTo(it->second->response.get());
+ it->second->response = std::move(*message);
*it->second->response_received = true;
return true;
}
@@ -304,8 +405,8 @@ bool InterfaceEndpointClient::HandleValidatedMessage(Message* message) {
async_responders_.erase(it);
return responder->Accept(message);
} else {
- if (!incoming_receiver_)
- return false;
+ if (mojo::internal::ControlMessageHandler::IsControlMessage(message))
+ return control_message_handler_.Accept(message);
return incoming_receiver_->Accept(message);
}
diff --git a/mojo/public/cpp/bindings/lib/interface_ptr_state.h b/mojo/public/cpp/bindings/lib/interface_ptr_state.h
index 584933e..8f5b4ff 100644
--- a/mojo/public/cpp/bindings/lib/interface_ptr_state.h
+++ b/mojo/public/cpp/bindings/lib/interface_ptr_state.h
@@ -9,6 +9,7 @@
#include <algorithm> // For |std::swap()|.
#include <memory>
+#include <string>
#include <utility>
#include "base/bind.h"
@@ -19,174 +20,20 @@
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "mojo/public/cpp/bindings/associated_group.h"
+#include "mojo/public/cpp/bindings/connection_error_callback.h"
+#include "mojo/public/cpp/bindings/filter_chain.h"
#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
#include "mojo/public/cpp/bindings/interface_id.h"
#include "mojo/public/cpp/bindings/interface_ptr_info.h"
-#include "mojo/public/cpp/bindings/lib/control_message_proxy.h"
-#include "mojo/public/cpp/bindings/lib/filter_chain.h"
#include "mojo/public/cpp/bindings/lib/multiplex_router.h"
-#include "mojo/public/cpp/bindings/lib/router.h"
#include "mojo/public/cpp/bindings/message_header_validator.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
namespace mojo {
namespace internal {
-template <typename Interface, bool use_multiplex_router>
-class InterfacePtrState;
-
-// Uses a single-threaded, dedicated router. If |Interface| doesn't have any
-// methods to pass associated interface pointers or requests, there won't be
-// multiple interfaces running on the underlying message pipe. In that case, we
-// can use this specialization to reduce cost.
-template <typename Interface>
-class InterfacePtrState<Interface, false> {
- public:
- InterfacePtrState() : proxy_(nullptr), router_(nullptr), version_(0u) {}
-
- ~InterfacePtrState() {
- // Destruction order matters here. We delete |proxy_| first, even though
- // |router_| may have a reference to it, so that destructors for any request
- // callbacks still pending can interact with the InterfacePtr.
- delete proxy_;
- delete router_;
- }
-
- Interface* instance() {
- ConfigureProxyIfNecessary();
-
- // This will be null if the object is not bound.
- return proxy_;
- }
-
- uint32_t version() const { return version_; }
-
- void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
- ConfigureProxyIfNecessary();
-
- // Do a static cast in case the interface contains methods with the same
- // name. It is safe to capture |this| because the callback won't be run
- // after this object goes away.
- static_cast<ControlMessageProxy*>(proxy_)->QueryVersion(
- base::Bind(&InterfacePtrState::OnQueryVersion, base::Unretained(this),
- callback));
- }
-
- void RequireVersion(uint32_t version) {
- ConfigureProxyIfNecessary();
-
- if (version <= version_)
- return;
-
- version_ = version;
- // Do a static cast in case the interface contains methods with the same
- // name.
- static_cast<ControlMessageProxy*>(proxy_)->RequireVersion(version);
- }
-
- void Swap(InterfacePtrState* other) {
- using std::swap;
- swap(other->proxy_, proxy_);
- swap(other->router_, router_);
- handle_.swap(other->handle_);
- runner_.swap(other->runner_);
- swap(other->version_, version_);
- }
-
- void Bind(InterfacePtrInfo<Interface> info,
- scoped_refptr<base::SingleThreadTaskRunner> runner) {
- DCHECK(!proxy_);
- DCHECK(!router_);
- DCHECK(!handle_.is_valid());
- DCHECK_EQ(0u, version_);
- DCHECK(info.is_valid());
-
- handle_ = info.PassHandle();
- version_ = info.version();
- runner_ = std::move(runner);
- }
-
- bool HasAssociatedInterfaces() const { return false; }
-
- // After this method is called, the object is in an invalid state and
- // shouldn't be reused.
- InterfacePtrInfo<Interface> PassInterface() {
- return InterfacePtrInfo<Interface>(
- router_ ? router_->PassMessagePipe() : std::move(handle_), version_);
- }
-
- bool is_bound() const { return handle_.is_valid() || router_; }
-
- bool encountered_error() const {
- return router_ ? router_->encountered_error() : false;
- }
-
- void set_connection_error_handler(const base::Closure& error_handler) {
- ConfigureProxyIfNecessary();
-
- DCHECK(router_);
- router_->set_connection_error_handler(error_handler);
- }
-
- // Returns true if bound and awaiting a response to a message.
- bool has_pending_callbacks() const {
- return router_ && router_->has_pending_responders();
- }
-
- AssociatedGroup* associated_group() { return nullptr; }
-
- void EnableTestingMode() {
- ConfigureProxyIfNecessary();
- router_->EnableTestingMode();
- }
-
- private:
- using Proxy = typename Interface::Proxy_;
-
- void ConfigureProxyIfNecessary() {
- // The proxy has been configured.
- if (proxy_) {
- DCHECK(router_);
- return;
- }
- // The object hasn't been bound.
- if (!handle_.is_valid())
- return;
-
- FilterChain filters;
- filters.Append<MessageHeaderValidator>(Interface::Name_);
- filters.Append<typename Interface::ResponseValidator_>();
-
- router_ = new Router(std::move(handle_), std::move(filters), false,
- std::move(runner_));
-
- proxy_ = new Proxy(router_);
- }
-
- void OnQueryVersion(const base::Callback<void(uint32_t)>& callback,
- uint32_t version) {
- version_ = version;
- callback.Run(version);
- }
-
- Proxy* proxy_;
- Router* router_;
-
- // |proxy_| and |router_| are not initialized until read/write with the
- // message pipe handle is needed. |handle_| is valid between the Bind() call
- // and the initialization of |proxy_| and |router_|.
- ScopedMessagePipeHandle handle_;
- scoped_refptr<base::SingleThreadTaskRunner> runner_;
-
- uint32_t version_;
-
- DISALLOW_COPY_AND_ASSIGN(InterfacePtrState);
-};
-
-// Uses a multiplexing router. If |Interface| has methods to pass associated
-// interface pointers or requests, this specialization should be used.
template <typename Interface>
-class InterfacePtrState<Interface, true> {
+class InterfacePtrState {
public:
InterfacePtrState() : version_(0u) {}
@@ -209,13 +56,10 @@ class InterfacePtrState<Interface, true> {
void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
ConfigureProxyIfNecessary();
-
- // Do a static cast in case the interface contains methods with the same
- // name. It is safe to capture |this| because the callback won't be run
- // after this object goes away.
- static_cast<ControlMessageProxy*>(proxy_.get())->QueryVersion(
- base::Bind(&InterfacePtrState::OnQueryVersion, base::Unretained(this),
- callback));
+ // It is safe to capture |this| because the callback won't be run after this
+ // object goes away.
+ endpoint_client_->QueryVersion(base::Bind(
+ &InterfacePtrState::OnQueryVersion, base::Unretained(this), callback));
}
void RequireVersion(uint32_t version) {
@@ -225,9 +69,17 @@ class InterfacePtrState<Interface, true> {
return;
version_ = version;
- // Do a static cast in case the interface contains methods with the same
- // name.
- static_cast<ControlMessageProxy*>(proxy_.get())->RequireVersion(version);
+ endpoint_client_->RequireVersion(version);
+ }
+
+ void FlushForTesting() {
+ ConfigureProxyIfNecessary();
+ endpoint_client_->FlushForTesting();
+ }
+
+ void CloseWithReason(uint32_t custom_reason, const std::string& description) {
+ ConfigureProxyIfNecessary();
+ endpoint_client_->CloseWithReason(custom_reason, description);
}
void Swap(InterfacePtrState* other) {
@@ -280,6 +132,14 @@ class InterfacePtrState<Interface, true> {
endpoint_client_->set_connection_error_handler(error_handler);
}
+ void set_connection_error_with_reason_handler(
+ const ConnectionErrorWithReasonCallback& error_handler) {
+ ConfigureProxyIfNecessary();
+
+ DCHECK(endpoint_client_);
+ endpoint_client_->set_connection_error_with_reason_handler(error_handler);
+ }
+
// Returns true if bound and awaiting a response to a message.
bool has_pending_callbacks() const {
return endpoint_client_ && endpoint_client_->has_pending_responders();
@@ -295,6 +155,17 @@ class InterfacePtrState<Interface, true> {
router_->EnableTestingMode();
}
+ void ForwardMessage(Message message) {
+ ConfigureProxyIfNecessary();
+ endpoint_client_->Accept(&message);
+ }
+
+ void ForwardMessageWithResponder(Message message,
+ std::unique_ptr<MessageReceiver> responder) {
+ ConfigureProxyIfNecessary();
+ endpoint_client_->AcceptWithResponder(&message, responder.release());
+ }
+
private:
using Proxy = typename Interface::Proxy_;
@@ -309,15 +180,22 @@ class InterfacePtrState<Interface, true> {
if (!handle_.is_valid())
return;
- router_ = new MultiplexRouter(true, std::move(handle_), runner_);
+ MultiplexRouter::Config config =
+ Interface::PassesAssociatedKinds_
+ ? MultiplexRouter::MULTI_INTERFACE
+ : (Interface::HasSyncMethods_
+ ? MultiplexRouter::SINGLE_INTERFACE_WITH_SYNC_METHODS
+ : MultiplexRouter::SINGLE_INTERFACE);
+ router_ = new MultiplexRouter(std::move(handle_), config, true, runner_);
router_->SetMasterInterfaceName(Interface::Name_);
endpoint_client_.reset(new InterfaceEndpointClient(
router_->CreateLocalEndpointHandle(kMasterInterfaceId), nullptr,
base::WrapUnique(new typename Interface::ResponseValidator_()), false,
- std::move(runner_)));
+ std::move(runner_),
+ // The version is only queried from the client so the value passed here
+ // will not be used.
+ 0u));
proxy_.reset(new Proxy(endpoint_client_.get()));
- proxy_->serialization_context()->group_controller =
- endpoint_client_->group_controller();
}
void OnQueryVersion(const base::Callback<void(uint32_t)>& callback,
diff --git a/mojo/public/cpp/bindings/lib/map_serialization.h b/mojo/public/cpp/bindings/lib/map_serialization.h
index c28b835..718a763 100644
--- a/mojo/public/cpp/bindings/lib/map_serialization.h
+++ b/mojo/public/cpp/bindings/lib/map_serialization.h
@@ -8,11 +8,11 @@
#include <type_traits>
#include <vector>
-#include "mojo/public/cpp/bindings/array.h"
+#include "mojo/public/cpp/bindings/array_data_view.h"
#include "mojo/public/cpp/bindings/lib/array_serialization.h"
#include "mojo/public/cpp/bindings/lib/map_data_internal.h"
#include "mojo/public/cpp/bindings/lib/serialization_forward.h"
-#include "mojo/public/cpp/bindings/map.h"
+#include "mojo/public/cpp/bindings/map_data_view.h"
namespace mojo {
namespace internal {
@@ -46,12 +46,15 @@ class MapKeyReader : public MapReaderBase<MaybeConstUserType> {
public:
using Base = MapReaderBase<MaybeConstUserType>;
using Traits = typename Base::Traits;
+ using MaybeConstIterator = typename Base::MaybeConstIterator;
explicit MapKeyReader(MaybeConstUserType& input) : Base(input) {}
~MapKeyReader() {}
- const typename Traits::Key& GetNext() {
- const typename Traits::Key& key = Traits::GetKey(this->iter_);
+ using GetNextResult =
+ decltype(Traits::GetKey(std::declval<MaybeConstIterator&>()));
+ GetNextResult GetNext() {
+ GetNextResult key = Traits::GetKey(this->iter_);
Traits::AdvanceIterator(this->iter_);
return key;
}
@@ -78,17 +81,17 @@ class MapValueReader : public MapReaderBase<MaybeConstUserType> {
};
template <typename Key, typename Value, typename MaybeConstUserType>
-struct Serializer<Map<Key, Value>, MaybeConstUserType> {
+struct Serializer<MapDataView<Key, Value>, MaybeConstUserType> {
using UserType = typename std::remove_const<MaybeConstUserType>::type;
using Traits = MapTraits<UserType>;
using UserKey = typename Traits::Key;
using UserValue = typename Traits::Value;
- using Data = typename MojomTypeTraits<Map<Key, Value>>::Data;
- using KeyArraySerializer = ArraySerializer<Array<Key>,
+ using Data = typename MojomTypeTraits<MapDataView<Key, Value>>::Data;
+ using KeyArraySerializer = ArraySerializer<ArrayDataView<Key>,
std::vector<UserKey>,
MapKeyReader<MaybeConstUserType>>;
using ValueArraySerializer =
- ArraySerializer<Array<Value>,
+ ArraySerializer<ArrayDataView<Value>,
std::vector<UserValue>,
MapValueReader<MaybeConstUserType>>;
@@ -122,8 +125,8 @@ struct Serializer<Map<Key, Value>, MaybeConstUserType> {
auto result = Data::New(buf);
if (result) {
- auto keys_ptr =
- MojomTypeTraits<Array<Key>>::Data::New(Traits::GetSize(input), buf);
+ auto keys_ptr = MojomTypeTraits<ArrayDataView<Key>>::Data::New(
+ Traits::GetSize(input), buf);
if (keys_ptr) {
MapKeyReader<MaybeConstUserType> key_reader(input);
KeyArraySerializer::SerializeElements(
@@ -132,8 +135,8 @@ struct Serializer<Map<Key, Value>, MaybeConstUserType> {
result->keys.Set(keys_ptr);
}
- auto values_ptr =
- MojomTypeTraits<Array<Value>>::Data::New(Traits::GetSize(input), buf);
+ auto values_ptr = MojomTypeTraits<ArrayDataView<Value>>::Data::New(
+ Traits::GetSize(input), buf);
if (values_ptr) {
MapValueReader<MaybeConstUserType> value_reader(input);
ValueArraySerializer::SerializeElements(
diff --git a/mojo/public/cpp/bindings/lib/may_auto_lock.h b/mojo/public/cpp/bindings/lib/may_auto_lock.h
new file mode 100644
index 0000000..06091fe
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/may_auto_lock.h
@@ -0,0 +1,62 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_MAY_AUTO_LOCK_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MAY_AUTO_LOCK_H_
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "base/synchronization/lock.h"
+
+namespace mojo {
+namespace internal {
+
+// Similar to base::AutoLock, except that it does nothing if |lock| passed into
+// the constructor is null.
+class MayAutoLock {
+ public:
+ explicit MayAutoLock(base::Optional<base::Lock>* lock)
+ : lock_(lock->has_value() ? &lock->value() : nullptr) {
+ if (lock_)
+ lock_->Acquire();
+ }
+
+ ~MayAutoLock() {
+ if (lock_) {
+ lock_->AssertAcquired();
+ lock_->Release();
+ }
+ }
+
+ private:
+ base::Lock* lock_;
+ DISALLOW_COPY_AND_ASSIGN(MayAutoLock);
+};
+
+// Similar to base::AutoUnlock, except that it does nothing if |lock| passed
+// into the constructor is null.
+class MayAutoUnlock {
+ public:
+ explicit MayAutoUnlock(base::Optional<base::Lock>* lock)
+ : lock_(lock->has_value() ? &lock->value() : nullptr) {
+ if (lock_) {
+ lock_->AssertAcquired();
+ lock_->Release();
+ }
+ }
+
+ ~MayAutoUnlock() {
+ if (lock_)
+ lock_->Acquire();
+ }
+
+ private:
+ base::Lock* lock_;
+ DISALLOW_COPY_AND_ASSIGN(MayAutoUnlock);
+};
+
+} // namespace internal
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MAY_AUTO_LOCK_H_
diff --git a/mojo/public/cpp/bindings/lib/message.cc b/mojo/public/cpp/bindings/lib/message.cc
index 939e064..e5f3808 100644
--- a/mojo/public/cpp/bindings/lib/message.cc
+++ b/mojo/public/cpp/bindings/lib/message.cc
@@ -11,18 +11,58 @@
#include <algorithm>
#include <utility>
+#include "base/bind.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
+#include "base/threading/thread_local.h"
+#include "mojo/public/cpp/bindings/associated_group_controller.h"
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
namespace mojo {
+namespace {
+
+base::LazyInstance<base::ThreadLocalPointer<internal::MessageDispatchContext>>::
+ DestructorAtExit g_tls_message_dispatch_context = LAZY_INSTANCE_INITIALIZER;
+
+base::LazyInstance<base::ThreadLocalPointer<SyncMessageResponseContext>>::
+ DestructorAtExit g_tls_sync_response_context = LAZY_INSTANCE_INITIALIZER;
+
+void DoNotifyBadMessage(Message message, const std::string& error) {
+ message.NotifyBadMessage(error);
+}
+
+} // namespace
+
Message::Message() {
}
+Message::Message(Message&& other)
+ : buffer_(std::move(other.buffer_)),
+ handles_(std::move(other.handles_)),
+ associated_endpoint_handles_(
+ std::move(other.associated_endpoint_handles_)) {}
+
Message::~Message() {
CloseHandles();
}
+Message& Message::operator=(Message&& other) {
+ Reset();
+ std::swap(other.buffer_, buffer_);
+ std::swap(other.handles_, handles_);
+ std::swap(other.associated_endpoint_handles_, associated_endpoint_handles_);
+ return *this;
+}
+
+void Message::Reset() {
+ CloseHandles();
+ handles_.clear();
+ associated_endpoint_handles_.clear();
+ buffer_.reset();
+}
+
void Message::Initialize(size_t capacity, bool zero_initialized) {
DCHECK(!buffer_);
buffer_.reset(new internal::MessageBuffer(capacity, zero_initialized));
@@ -36,19 +76,52 @@ void Message::InitializeFromMojoMessage(ScopedMessageHandle message,
handles_.swap(*handles);
}
-void Message::MoveTo(Message* destination) {
- DCHECK(this != destination);
+const uint8_t* Message::payload() const {
+ if (version() < 2)
+ return data() + header()->num_bytes;
- // No copy needed.
- std::swap(destination->buffer_, buffer_);
- std::swap(destination->handles_, handles_);
+ return static_cast<const uint8_t*>(header_v2()->payload.Get());
+}
- CloseHandles();
- handles_.clear();
- buffer_.reset();
+uint32_t Message::payload_num_bytes() const {
+ DCHECK_GE(data_num_bytes(), header()->num_bytes);
+ size_t num_bytes;
+ if (version() < 2) {
+ num_bytes = data_num_bytes() - header()->num_bytes;
+ } else {
+ auto payload = reinterpret_cast<uintptr_t>(header_v2()->payload.Get());
+ if (!payload) {
+ num_bytes = 0;
+ } else {
+ auto payload_end =
+ reinterpret_cast<uintptr_t>(header_v2()->payload_interface_ids.Get());
+ if (!payload_end)
+ payload_end = reinterpret_cast<uintptr_t>(data() + data_num_bytes());
+ DCHECK_GE(payload_end, payload);
+ num_bytes = payload_end - payload;
+ }
+ }
+ DCHECK_LE(num_bytes, std::numeric_limits<uint32_t>::max());
+ return static_cast<uint32_t>(num_bytes);
+}
+
+uint32_t Message::payload_num_interface_ids() const {
+ auto* array_pointer =
+ version() < 2 ? nullptr : header_v2()->payload_interface_ids.Get();
+ return array_pointer ? static_cast<uint32_t>(array_pointer->size()) : 0;
+}
+
+const uint32_t* Message::payload_interface_ids() const {
+ auto* array_pointer =
+ version() < 2 ? nullptr : header_v2()->payload_interface_ids.Get();
+ return array_pointer ? array_pointer->storage() : nullptr;
}
ScopedMessageHandle Message::TakeMojoMessage() {
+ // If there are associated endpoints transferred,
+ // SerializeAssociatedEndpointHandles() must be called before this method.
+ DCHECK(associated_endpoint_handles_.empty());
+
if (handles_.empty()) // Fast path for the common case: No handles.
return buffer_->TakeMessage();
@@ -80,6 +153,7 @@ ScopedMessageHandle Message::TakeMojoMessage() {
}
void Message::NotifyBadMessage(const std::string& error) {
+ DCHECK(buffer_);
buffer_->NotifyBadMessage(error);
}
@@ -91,6 +165,88 @@ void Message::CloseHandles() {
}
}
+void Message::SerializeAssociatedEndpointHandles(
+ AssociatedGroupController* group_controller) {
+ if (associated_endpoint_handles_.empty())
+ return;
+
+ DCHECK_GE(version(), 2u);
+ DCHECK(header_v2()->payload_interface_ids.is_null());
+
+ size_t size = associated_endpoint_handles_.size();
+ auto* data = internal::Array_Data<uint32_t>::New(size, buffer());
+ header_v2()->payload_interface_ids.Set(data);
+
+ for (size_t i = 0; i < size; ++i) {
+ ScopedInterfaceEndpointHandle& handle = associated_endpoint_handles_[i];
+
+ DCHECK(handle.pending_association());
+ data->storage()[i] =
+ group_controller->AssociateInterface(std::move(handle));
+ }
+ associated_endpoint_handles_.clear();
+}
+
+bool Message::DeserializeAssociatedEndpointHandles(
+ AssociatedGroupController* group_controller) {
+ associated_endpoint_handles_.clear();
+
+ uint32_t num_ids = payload_num_interface_ids();
+ if (num_ids == 0)
+ return true;
+
+ associated_endpoint_handles_.reserve(num_ids);
+ uint32_t* ids = header_v2()->payload_interface_ids.Get()->storage();
+ bool result = true;
+ for (uint32_t i = 0; i < num_ids; ++i) {
+ auto handle = group_controller->CreateLocalEndpointHandle(ids[i]);
+ if (IsValidInterfaceId(ids[i]) && !handle.is_valid()) {
+ // |ids[i]| itself is valid but handle creation failed. In that case, mark
+ // deserialization as failed but continue to deserialize the rest of
+ // handles.
+ result = false;
+ }
+
+ associated_endpoint_handles_.push_back(std::move(handle));
+ ids[i] = kInvalidInterfaceId;
+ }
+ return result;
+}
+
+PassThroughFilter::PassThroughFilter() {}
+
+PassThroughFilter::~PassThroughFilter() {}
+
+bool PassThroughFilter::Accept(Message* message) { return true; }
+
+SyncMessageResponseContext::SyncMessageResponseContext()
+ : outer_context_(current()) {
+ g_tls_sync_response_context.Get().Set(this);
+}
+
+SyncMessageResponseContext::~SyncMessageResponseContext() {
+ DCHECK_EQ(current(), this);
+ g_tls_sync_response_context.Get().Set(outer_context_);
+}
+
+// static
+SyncMessageResponseContext* SyncMessageResponseContext::current() {
+ return g_tls_sync_response_context.Get().Get();
+}
+
+void SyncMessageResponseContext::ReportBadMessage(const std::string& error) {
+ GetBadMessageCallback().Run(error);
+}
+
+const ReportBadMessageCallback&
+SyncMessageResponseContext::GetBadMessageCallback() {
+ if (bad_message_callback_.is_null()) {
+ bad_message_callback_ =
+ base::Bind(&DoNotifyBadMessage, base::Passed(&response_));
+ }
+ return bad_message_callback_;
+}
+
MojoResult ReadMessage(MessagePipeHandle handle, Message* message) {
MojoResult rv;
@@ -122,4 +278,55 @@ MojoResult ReadMessage(MessagePipeHandle handle, Message* message) {
return MOJO_RESULT_OK;
}
+void ReportBadMessage(const std::string& error) {
+ internal::MessageDispatchContext* context =
+ internal::MessageDispatchContext::current();
+ DCHECK(context);
+ context->GetBadMessageCallback().Run(error);
+}
+
+ReportBadMessageCallback GetBadMessageCallback() {
+ internal::MessageDispatchContext* context =
+ internal::MessageDispatchContext::current();
+ DCHECK(context);
+ return context->GetBadMessageCallback();
+}
+
+namespace internal {
+
+MessageHeaderV2::MessageHeaderV2() = default;
+
+MessageDispatchContext::MessageDispatchContext(Message* message)
+ : outer_context_(current()), message_(message) {
+ g_tls_message_dispatch_context.Get().Set(this);
+}
+
+MessageDispatchContext::~MessageDispatchContext() {
+ DCHECK_EQ(current(), this);
+ g_tls_message_dispatch_context.Get().Set(outer_context_);
+}
+
+// static
+MessageDispatchContext* MessageDispatchContext::current() {
+ return g_tls_message_dispatch_context.Get().Get();
+}
+
+const ReportBadMessageCallback&
+MessageDispatchContext::GetBadMessageCallback() {
+ if (bad_message_callback_.is_null()) {
+ bad_message_callback_ =
+ base::Bind(&DoNotifyBadMessage, base::Passed(message_));
+ }
+ return bad_message_callback_;
+}
+
+// static
+void SyncMessageResponseSetup::SetCurrentSyncResponseMessage(Message* message) {
+ SyncMessageResponseContext* context = SyncMessageResponseContext::current();
+ if (context)
+ context->response_ = std::move(*message);
+}
+
+} // namespace internal
+
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/message_buffer.cc b/mojo/public/cpp/bindings/lib/message_buffer.cc
index af79cfd..cc12ef6 100644
--- a/mojo/public/cpp/bindings/lib/message_buffer.cc
+++ b/mojo/public/cpp/bindings/lib/message_buffer.cc
@@ -13,54 +13,35 @@ namespace internal {
MessageBuffer::MessageBuffer(size_t capacity, bool zero_initialized) {
DCHECK_LE(capacity, std::numeric_limits<uint32_t>::max());
- data_num_bytes_ = static_cast<uint32_t>(capacity);
MojoResult rv = AllocMessage(capacity, nullptr, 0,
MOJO_ALLOC_MESSAGE_FLAG_NONE, &message_);
CHECK_EQ(rv, MOJO_RESULT_OK);
- if (capacity == 0) {
- buffer_ = nullptr;
- } else {
- rv = GetMessageBuffer(message_.get(), &buffer_);
+ void* buffer = nullptr;
+ if (capacity != 0) {
+ rv = GetMessageBuffer(message_.get(), &buffer);
CHECK_EQ(rv, MOJO_RESULT_OK);
if (zero_initialized)
- memset(buffer_, 0, capacity);
+ memset(buffer, 0, capacity);
}
+ Initialize(buffer, capacity);
}
MessageBuffer::MessageBuffer(ScopedMessageHandle message, uint32_t num_bytes) {
message_ = std::move(message);
- data_num_bytes_ = num_bytes;
- if (num_bytes == 0) {
- buffer_ = nullptr;
- } else {
- MojoResult rv = GetMessageBuffer(message_.get(), &buffer_);
+ void* buffer = nullptr;
+ if (num_bytes != 0) {
+ MojoResult rv = GetMessageBuffer(message_.get(), &buffer);
CHECK_EQ(rv, MOJO_RESULT_OK);
}
+ Initialize(buffer, num_bytes);
}
MessageBuffer::~MessageBuffer() {}
-void* MessageBuffer::Allocate(size_t delta) {
- delta = internal::Align(delta);
-
- DCHECK_LE(delta, static_cast<size_t>(data_num_bytes_));
- DCHECK_GT(bytes_claimed_ + static_cast<uint32_t>(delta), bytes_claimed_);
-
- uint32_t new_bytes_claimed = bytes_claimed_ + static_cast<uint32_t>(delta);
- if (new_bytes_claimed > data_num_bytes_) {
- NOTREACHED();
- return nullptr;
- }
-
- char* start = static_cast<char*>(buffer_) + bytes_claimed_;
- bytes_claimed_ = new_bytes_claimed;
- return static_cast<void*>(start);
-}
-
void MessageBuffer::NotifyBadMessage(const std::string& error) {
DCHECK(message_.is_valid());
MojoResult result = mojo::NotifyBadMessage(message_.get(), error);
diff --git a/mojo/public/cpp/bindings/lib/message_buffer.h b/mojo/public/cpp/bindings/lib/message_buffer.h
index 0382131..96d5140 100644
--- a/mojo/public/cpp/bindings/lib/message_buffer.h
+++ b/mojo/public/cpp/bindings/lib/message_buffer.h
@@ -5,7 +5,6 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_LIB_MESSAGE_BUFFER_H_
#define MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_LIB_MESSAGE_BUFFER_H_
-#include <stddef.h>
#include <stdint.h>
#include <utility>
@@ -17,7 +16,7 @@
namespace mojo {
namespace internal {
-// A fixed-size Buffer implementation using a Mojo message object for storage.
+// A fixed-size Buffer using a Mojo message object for storage.
class MessageBuffer : public Buffer {
public:
// Initializes this buffer to carry a fixed byte capacity and no handles.
@@ -26,24 +25,14 @@ class MessageBuffer : public Buffer {
// Initializes this buffer from an existing Mojo MessageHandle.
MessageBuffer(ScopedMessageHandle message, uint32_t num_bytes);
- ~MessageBuffer() override;
-
- void* data() const { return buffer_; }
- uint32_t data_num_bytes() const { return data_num_bytes_; }
-
- // Buffer:
- void* Allocate(size_t delta) override;
+ ~MessageBuffer();
ScopedMessageHandle TakeMessage() { return std::move(message_); }
void NotifyBadMessage(const std::string& error);
private:
- uint32_t data_num_bytes_ = 0;
ScopedMessageHandle message_;
- void* buffer_;
-
- uint32_t bytes_claimed_ = 0;
DISALLOW_COPY_AND_ASSIGN(MessageBuffer);
};
diff --git a/mojo/public/cpp/bindings/lib/message_builder.cc b/mojo/public/cpp/bindings/lib/message_builder.cc
index 4ffa180..6806a73 100644
--- a/mojo/public/cpp/bindings/lib/message_builder.cc
+++ b/mojo/public/cpp/bindings/lib/message_builder.cc
@@ -4,11 +4,10 @@
#include "mojo/public/cpp/bindings/lib/message_builder.h"
-#include <stddef.h>
-#include <stdint.h>
-
-#include "mojo/public/cpp/bindings/lib/serialization_util.h"
-#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/buffer.h"
+#include "mojo/public/cpp/bindings/lib/message_internal.h"
namespace mojo {
namespace internal {
@@ -19,38 +18,52 @@ void Allocate(Buffer* buf, Header** header) {
(*header)->num_bytes = sizeof(Header);
}
-MessageBuilder::MessageBuilder(uint32_t name, size_t payload_size) {
- InitializeMessage(sizeof(MessageHeader) + payload_size);
+MessageBuilder::MessageBuilder(uint32_t name,
+ uint32_t flags,
+ size_t payload_size,
+ size_t payload_interface_id_count) {
+ if (payload_interface_id_count > 0) {
+ // Version 2
+ InitializeMessage(
+ sizeof(MessageHeaderV2) + Align(payload_size) +
+ ArrayDataTraits<uint32_t>::GetStorageSize(
+ static_cast<uint32_t>(payload_interface_id_count)));
+
+ MessageHeaderV2* header;
+ Allocate(message_.buffer(), &header);
+ header->version = 2;
+ header->name = name;
+ header->flags = flags;
+ // The payload immediately follows the header.
+ header->payload.Set(header + 1);
+ } else if (flags &
+ (Message::kFlagExpectsResponse | Message::kFlagIsResponse)) {
+ // Version 1
+ InitializeMessage(sizeof(MessageHeaderV1) + payload_size);
+
+ MessageHeaderV1* header;
+ Allocate(message_.buffer(), &header);
+ header->version = 1;
+ header->name = name;
+ header->flags = flags;
+ } else {
+ InitializeMessage(sizeof(MessageHeader) + payload_size);
- MessageHeader* header;
- Allocate(message_.buffer(), &header);
- header->version = 0;
- header->name = name;
+ MessageHeader* header;
+ Allocate(message_.buffer(), &header);
+ header->version = 0;
+ header->name = name;
+ header->flags = flags;
+ }
}
MessageBuilder::~MessageBuilder() {
}
-MessageBuilder::MessageBuilder() {}
-
void MessageBuilder::InitializeMessage(size_t size) {
message_.Initialize(static_cast<uint32_t>(Align(size)),
true /* zero_initialized */);
}
-MessageWithRequestIDBuilder::MessageWithRequestIDBuilder(uint32_t name,
- size_t payload_size,
- uint32_t flags,
- uint64_t request_id) {
- InitializeMessage(sizeof(MessageHeaderWithRequestID) + payload_size);
-
- MessageHeaderWithRequestID* header;
- Allocate(message_.buffer(), &header);
- header->version = 1;
- header->name = name;
- header->flags = flags;
- header->request_id = request_id;
-}
-
} // namespace internal
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/message_builder.h b/mojo/public/cpp/bindings/lib/message_builder.h
index a5a050f..8a4d5c4 100644
--- a/mojo/public/cpp/bindings/lib/message_builder.h
+++ b/mojo/public/cpp/bindings/lib/message_builder.h
@@ -8,24 +8,30 @@
#include <stddef.h>
#include <stdint.h>
-#include "mojo/public/cpp/bindings/lib/message_internal.h"
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/message.h"
namespace mojo {
+
class Message;
namespace internal {
-class MessageBuilder {
+class Buffer;
+
+class MOJO_CPP_BINDINGS_EXPORT MessageBuilder {
public:
- MessageBuilder(uint32_t name, size_t payload_size);
+ MessageBuilder(uint32_t name,
+ uint32_t flags,
+ size_t payload_size,
+ size_t payload_interface_id_count);
~MessageBuilder();
Buffer* buffer() { return message_.buffer(); }
Message* message() { return &message_; }
- protected:
- MessageBuilder();
+ private:
void InitializeMessage(size_t size);
Message message_;
@@ -33,51 +39,6 @@ class MessageBuilder {
DISALLOW_COPY_AND_ASSIGN(MessageBuilder);
};
-class MessageWithRequestIDBuilder : public MessageBuilder {
- public:
- MessageWithRequestIDBuilder(uint32_t name,
- size_t payload_size,
- uint32_t flags,
- uint64_t request_id);
-};
-
-class RequestMessageBuilder : public MessageWithRequestIDBuilder {
- public:
- RequestMessageBuilder(uint32_t name, size_t payload_size)
- : MessageWithRequestIDBuilder(name,
- payload_size,
- Message::kFlagExpectsResponse,
- 0) {}
-
- RequestMessageBuilder(uint32_t name,
- size_t payload_size,
- uint32_t extra_flags)
- : MessageWithRequestIDBuilder(name,
- payload_size,
- Message::kFlagExpectsResponse | extra_flags,
- 0) {}
-};
-
-class ResponseMessageBuilder : public MessageWithRequestIDBuilder {
- public:
- ResponseMessageBuilder(uint32_t name,
- size_t payload_size,
- uint64_t request_id)
- : MessageWithRequestIDBuilder(name,
- payload_size,
- Message::kFlagIsResponse,
- request_id) {}
-
- ResponseMessageBuilder(uint32_t name,
- size_t payload_size,
- uint64_t request_id,
- uint32_t extra_flags)
- : MessageWithRequestIDBuilder(name,
- payload_size,
- Message::kFlagIsResponse | extra_flags,
- request_id) {}
-};
-
} // namespace internal
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/message_filter.cc b/mojo/public/cpp/bindings/lib/message_filter.cc
deleted file mode 100644
index b09f40d..0000000
--- a/mojo/public/cpp/bindings/lib/message_filter.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/public/cpp/bindings/message_filter.h"
-
-namespace mojo {
-
-MessageFilter::MessageFilter(MessageReceiver* sink) : sink_(sink) {
-}
-
-MessageFilter::~MessageFilter() {
-}
-
-PassThroughFilter::PassThroughFilter(MessageReceiver* sink)
- : MessageFilter(sink) {
-}
-
-bool PassThroughFilter::Accept(Message* message) {
- return sink_->Accept(message);
-}
-
-} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/message_header_validator.cc b/mojo/public/cpp/bindings/lib/message_header_validator.cc
index 10f7774..9f8c627 100644
--- a/mojo/public/cpp/bindings/lib/message_header_validator.cc
+++ b/mojo/public/cpp/bindings/lib/message_header_validator.cc
@@ -4,6 +4,8 @@
#include "mojo/public/cpp/bindings/message_header_validator.h"
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/lib/validate_params.h"
#include "mojo/public/cpp/bindings/lib/validation_context.h"
#include "mojo/public/cpp/bindings/lib/validation_errors.h"
#include "mojo/public/cpp/bindings/lib/validation_util.h"
@@ -11,40 +13,40 @@
namespace mojo {
namespace {
+// TODO(yzshen): Define a mojom struct for message header and use the generated
+// validation and data view code.
bool IsValidMessageHeader(const internal::MessageHeader* header,
internal::ValidationContext* validation_context) {
// NOTE: Our goal is to preserve support for future extension of the message
// header. If we encounter fields we do not understand, we must ignore them.
// Extra validation of the struct header:
- if (header->version == 0) {
- if (header->num_bytes != sizeof(internal::MessageHeader)) {
- internal::ReportValidationError(
- validation_context,
- internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
- return false;
+ do {
+ if (header->version == 0) {
+ if (header->num_bytes == sizeof(internal::MessageHeader))
+ break;
+ } else if (header->version == 1) {
+ if (header->num_bytes == sizeof(internal::MessageHeaderV1))
+ break;
+ } else if (header->version == 2) {
+ if (header->num_bytes == sizeof(internal::MessageHeaderV2))
+ break;
+ } else if (header->version > 2) {
+ if (header->num_bytes >= sizeof(internal::MessageHeaderV2))
+ break;
}
- } else if (header->version == 1) {
- if (header->num_bytes != sizeof(internal::MessageHeaderWithRequestID)) {
- internal::ReportValidationError(
- validation_context,
- internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
- return false;
- }
- } else if (header->version > 1) {
- if (header->num_bytes < sizeof(internal::MessageHeaderWithRequestID)) {
- internal::ReportValidationError(
- validation_context,
- internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
- return false;
- }
- }
+ internal::ReportValidationError(
+ validation_context,
+ internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
+ return false;
+ } while (false);
// Validate flags (allow unknown bits):
// These flags require a RequestID.
- if (header->version < 1 && ((header->flags & Message::kFlagExpectsResponse) ||
- (header->flags & Message::kFlagIsResponse))) {
+ constexpr uint32_t kRequestIdFlags =
+ Message::kFlagExpectsResponse | Message::kFlagIsResponse;
+ if (header->version == 0 && (header->flags & kRequestIdFlags)) {
internal::ReportValidationError(
validation_context,
internal::VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID);
@@ -52,25 +54,60 @@ bool IsValidMessageHeader(const internal::MessageHeader* header,
}
// These flags are mutually exclusive.
- if ((header->flags & Message::kFlagExpectsResponse) &&
- (header->flags & Message::kFlagIsResponse)) {
+ if ((header->flags & kRequestIdFlags) == kRequestIdFlags) {
internal::ReportValidationError(
validation_context,
internal::VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS);
return false;
}
+ if (header->version < 2)
+ return true;
+
+ auto* header_v2 = static_cast<const internal::MessageHeaderV2*>(header);
+ // For the payload pointer:
+ // - Check that the pointer can be safely decoded.
+ // - Claim one byte that the pointer points to. It makes sure not only the
+ // address is within the message, but also the address precedes the array
+ // storing interface IDs (which is important for safely calculating the
+ // payload size).
+ // - Validation of the payload contents will be done separately based on the
+ // payload type.
+ if (!header_v2->payload.is_null() &&
+ (!internal::ValidatePointer(header_v2->payload, validation_context) ||
+ !validation_context->ClaimMemory(header_v2->payload.Get(), 1))) {
+ return false;
+ }
+
+ const internal::ContainerValidateParams validate_params(0, false, nullptr);
+ if (!internal::ValidateContainer(header_v2->payload_interface_ids,
+ validation_context, &validate_params)) {
+ return false;
+ }
+
+ if (!header_v2->payload_interface_ids.is_null()) {
+ size_t num_ids = header_v2->payload_interface_ids.Get()->size();
+ const uint32_t* ids = header_v2->payload_interface_ids.Get()->storage();
+ for (size_t i = 0; i < num_ids; ++i) {
+ if (!IsValidInterfaceId(ids[i]) || IsMasterInterfaceId(ids[i])) {
+ internal::ReportValidationError(
+ validation_context,
+ internal::VALIDATION_ERROR_ILLEGAL_INTERFACE_ID);
+ return false;
+ }
+ }
+ }
+
return true;
}
} // namespace
-MessageHeaderValidator::MessageHeaderValidator(MessageReceiver* sink)
- : MessageHeaderValidator("MessageHeaderValidator", sink) {}
+MessageHeaderValidator::MessageHeaderValidator()
+ : MessageHeaderValidator("MessageHeaderValidator") {}
-MessageHeaderValidator::MessageHeaderValidator(const std::string& description,
- MessageReceiver* sink)
- : MessageFilter(sink), description_(description) {
+MessageHeaderValidator::MessageHeaderValidator(const std::string& description)
+ : description_(description) {
}
void MessageHeaderValidator::SetDescription(const std::string& description) {
@@ -78,10 +115,10 @@ void MessageHeaderValidator::SetDescription(const std::string& description) {
}
bool MessageHeaderValidator::Accept(Message* message) {
- // Pass 0 as number of handles because we don't expect any in the header, even
- // if |message| contains handles.
+ // Pass 0 as number of handles and associated endpoint handles because we
+ // don't expect any in the header, even if |message| contains handles.
internal::ValidationContext validation_context(
- message->data(), message->data_num_bytes(), 0, message, description_);
+ message->data(), message->data_num_bytes(), 0, 0, message, description_);
if (!internal::ValidateStructHeaderAndClaimMemory(message->data(),
&validation_context))
@@ -90,7 +127,7 @@ bool MessageHeaderValidator::Accept(Message* message) {
if (!IsValidMessageHeader(message->header(), &validation_context))
return false;
- return sink_->Accept(message);
+ return true;
}
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/message_internal.h b/mojo/public/cpp/bindings/lib/message_internal.h
index 63edffd..6693198 100644
--- a/mojo/public/cpp/bindings/lib/message_internal.h
+++ b/mojo/public/cpp/bindings/lib/message_internal.h
@@ -7,11 +7,22 @@
#include <stdint.h>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
namespace mojo {
+
+class Message;
+
namespace internal {
+template <typename T>
+class Array_Data;
+
#pragma pack(push, 1)
struct MessageHeader : internal::StructHeader {
@@ -27,16 +38,44 @@ struct MessageHeader : internal::StructHeader {
};
static_assert(sizeof(MessageHeader) == 24, "Bad sizeof(MessageHeader)");
-struct MessageHeaderWithRequestID : MessageHeader {
+struct MessageHeaderV1 : MessageHeader {
// Only used if either kFlagExpectsResponse or kFlagIsResponse is set in
// order to match responses with corresponding requests.
uint64_t request_id;
};
-static_assert(sizeof(MessageHeaderWithRequestID) == 32,
- "Bad sizeof(MessageHeaderWithRequestID)");
+static_assert(sizeof(MessageHeaderV1) == 32, "Bad sizeof(MessageHeaderV1)");
+
+struct MessageHeaderV2 : MessageHeaderV1 {
+ MessageHeaderV2();
+ GenericPointer payload;
+ Pointer<Array_Data<uint32_t>> payload_interface_ids;
+};
+static_assert(sizeof(MessageHeaderV2) == 48, "Bad sizeof(MessageHeaderV2)");
#pragma pack(pop)
+class MOJO_CPP_BINDINGS_EXPORT MessageDispatchContext {
+ public:
+ explicit MessageDispatchContext(Message* message);
+ ~MessageDispatchContext();
+
+ static MessageDispatchContext* current();
+
+ const base::Callback<void(const std::string&)>& GetBadMessageCallback();
+
+ private:
+ MessageDispatchContext* outer_context_;
+ Message* message_;
+ base::Callback<void(const std::string&)> bad_message_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessageDispatchContext);
+};
+
+class MOJO_CPP_BINDINGS_EXPORT SyncMessageResponseSetup {
+ public:
+ static void SetCurrentSyncResponseMessage(Message* message);
+};
+
} // namespace internal
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.cc b/mojo/public/cpp/bindings/lib/multiplex_router.cc
index dcfbab1..2da459a 100644
--- a/mojo/public/cpp/bindings/lib/multiplex_router.cc
+++ b/mojo/public/cpp/bindings/lib/multiplex_router.cc
@@ -15,9 +15,9 @@
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "mojo/public/cpp/bindings/associated_group.h"
#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
#include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
+#include "mojo/public/cpp/bindings/lib/may_auto_lock.h"
#include "mojo/public/cpp/bindings/sync_handle_watcher.h"
namespace mojo {
@@ -36,6 +36,7 @@ class MultiplexRouter::InterfaceEndpoint
id_(id),
closed_(false),
peer_closed_(false),
+ handle_created_(false),
client_(nullptr),
event_signalled_(false) {}
@@ -50,16 +51,31 @@ class MultiplexRouter::InterfaceEndpoint
bool closed() const { return closed_; }
void set_closed() {
- router_->lock_.AssertAcquired();
+ router_->AssertLockAcquired();
closed_ = true;
}
bool peer_closed() const { return peer_closed_; }
void set_peer_closed() {
- router_->lock_.AssertAcquired();
+ router_->AssertLockAcquired();
peer_closed_ = true;
}
+ bool handle_created() const { return handle_created_; }
+ void set_handle_created() {
+ router_->AssertLockAcquired();
+ handle_created_ = true;
+ }
+
+ const base::Optional<DisconnectReason>& disconnect_reason() const {
+ return disconnect_reason_;
+ }
+ void set_disconnect_reason(
+ const base::Optional<DisconnectReason>& disconnect_reason) {
+ router_->AssertLockAcquired();
+ disconnect_reason_ = disconnect_reason;
+ }
+
base::SingleThreadTaskRunner* task_runner() const {
return task_runner_.get();
}
@@ -68,7 +84,7 @@ class MultiplexRouter::InterfaceEndpoint
void AttachClient(InterfaceEndpointClient* client,
scoped_refptr<base::SingleThreadTaskRunner> runner) {
- router_->lock_.AssertAcquired();
+ router_->AssertLockAcquired();
DCHECK(!client_);
DCHECK(!closed_);
DCHECK(runner->BelongsToCurrentThread());
@@ -80,7 +96,7 @@ class MultiplexRouter::InterfaceEndpoint
// This method must be called on the same thread as the corresponding
// AttachClient() call.
void DetachClient() {
- router_->lock_.AssertAcquired();
+ router_->AssertLockAcquired();
DCHECK(client_);
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(!closed_);
@@ -91,18 +107,36 @@ class MultiplexRouter::InterfaceEndpoint
}
void SignalSyncMessageEvent() {
- router_->lock_.AssertAcquired();
+ router_->AssertLockAcquired();
if (event_signalled_)
return;
- EnsureEventMessagePipeExists();
event_signalled_ = true;
+ if (!sync_message_event_sender_.is_valid())
+ return;
+
MojoResult result =
WriteMessageRaw(sync_message_event_sender_.get(), nullptr, 0, nullptr,
0, MOJO_WRITE_MESSAGE_FLAG_NONE);
DCHECK_EQ(MOJO_RESULT_OK, result);
}
+ void ResetSyncMessageSignal() {
+ router_->AssertLockAcquired();
+
+ if (!event_signalled_)
+ return;
+
+ event_signalled_ = false;
+ if (!sync_message_event_receiver_.is_valid())
+ return;
+
+ MojoResult result =
+ ReadMessageRaw(sync_message_event_receiver_.get(), nullptr, nullptr,
+ nullptr, nullptr, MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
+ DCHECK_EQ(MOJO_RESULT_OK, result);
+ }
+
// ---------------------------------------------------------------------------
// The following public methods (i.e., InterfaceEndpointController
// implementation) are called by the client on the same thread as the
@@ -132,7 +166,7 @@ class MultiplexRouter::InterfaceEndpoint
friend class base::RefCounted<InterfaceEndpoint>;
~InterfaceEndpoint() override {
- router_->lock_.AssertAcquired();
+ router_->AssertLockAcquired();
DCHECK(!client_);
DCHECK(closed_);
@@ -142,26 +176,23 @@ class MultiplexRouter::InterfaceEndpoint
void OnHandleReady(MojoResult result) {
DCHECK(task_runner_->BelongsToCurrentThread());
- scoped_refptr<InterfaceEndpoint> self_protector(this);
scoped_refptr<MultiplexRouter> router_protector(router_);
// Because we never close |sync_message_event_{sender,receiver}_| before
// destruction or set a deadline, |result| should always be MOJO_RESULT_OK.
DCHECK_EQ(MOJO_RESULT_OK, result);
- bool reset_sync_watcher = false;
- {
- base::AutoLock locker(router_->lock_);
- bool more_to_process = router_->ProcessFirstSyncMessageForEndpoint(id_);
+ MayAutoLock locker(&router_->lock_);
+ scoped_refptr<InterfaceEndpoint> self_protector(this);
- if (!more_to_process)
- ResetSyncMessageSignal();
+ bool more_to_process = router_->ProcessFirstSyncMessageForEndpoint(id_);
- // Currently there are no queued sync messages and the peer has closed so
- // there won't be incoming sync messages in the future.
- reset_sync_watcher = !more_to_process && peer_closed_;
- }
- if (reset_sync_watcher) {
+ if (!more_to_process)
+ ResetSyncMessageSignal();
+
+ // Currently there are no queued sync messages and the peer has closed so
+ // there won't be incoming sync messages in the future.
+ if (!more_to_process && peer_closed_) {
// If a SyncWatch() call (or multiple ones) of this interface endpoint is
// on the call stack, resetting the sync watcher will allow it to exit
// when the call stack unwinds to that frame.
@@ -175,12 +206,21 @@ class MultiplexRouter::InterfaceEndpoint
return;
{
- base::AutoLock locker(router_->lock_);
- EnsureEventMessagePipeExists();
-
- auto iter = router_->sync_message_tasks_.find(id_);
- if (iter != router_->sync_message_tasks_.end() && !iter->second.empty())
- SignalSyncMessageEvent();
+ MayAutoLock locker(&router_->lock_);
+
+ if (!sync_message_event_sender_.is_valid()) {
+ MojoResult result =
+ CreateMessagePipe(nullptr, &sync_message_event_sender_,
+ &sync_message_event_receiver_);
+ DCHECK_EQ(MOJO_RESULT_OK, result);
+
+ if (event_signalled_) {
+ // Reset the flag so that SignalSyncMessageEvent() will actually
+ // signal using the newly-created message pipe.
+ event_signalled_ = false;
+ SignalSyncMessageEvent();
+ }
+ }
}
sync_watcher_.reset(new SyncHandleWatcher(
@@ -188,31 +228,6 @@ class MultiplexRouter::InterfaceEndpoint
base::Bind(&InterfaceEndpoint::OnHandleReady, base::Unretained(this))));
}
- void EnsureEventMessagePipeExists() {
- router_->lock_.AssertAcquired();
-
- if (sync_message_event_receiver_.is_valid())
- return;
-
- MojoResult result = CreateMessagePipe(nullptr, &sync_message_event_sender_,
- &sync_message_event_receiver_);
- DCHECK_EQ(MOJO_RESULT_OK, result);
- }
-
- void ResetSyncMessageSignal() {
- router_->lock_.AssertAcquired();
-
- if (!event_signalled_)
- return;
-
- DCHECK(sync_message_event_receiver_.is_valid());
- MojoResult result = ReadMessageRaw(sync_message_event_receiver_.get(),
- nullptr, nullptr, nullptr, nullptr,
- MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
- DCHECK_EQ(MOJO_RESULT_OK, result);
- event_signalled_ = false;
- }
-
// ---------------------------------------------------------------------------
// The following members are safe to access from any threads.
@@ -227,6 +242,12 @@ class MultiplexRouter::InterfaceEndpoint
// Whether the peer endpoint has been closed.
bool peer_closed_;
+ // Whether there is already a ScopedInterfaceEndpointHandle created for this
+ // endpoint.
+ bool handle_created_;
+
+ base::Optional<DisconnectReason> disconnect_reason_;
+
// The task runner on which |client_|'s methods can be called.
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
// Not owned. It is null if no client is attached to this endpoint.
@@ -250,13 +271,53 @@ class MultiplexRouter::InterfaceEndpoint
DISALLOW_COPY_AND_ASSIGN(InterfaceEndpoint);
};
+// MessageWrapper objects are always destroyed under the router's lock. On
+// destruction, if the message it wrappers contains
+// ScopedInterfaceEndpointHandles (which cannot be destructed under the
+// router's lock), the wrapper unlocks to clean them up.
+class MultiplexRouter::MessageWrapper {
+ public:
+ MessageWrapper() = default;
+
+ MessageWrapper(MultiplexRouter* router, Message message)
+ : router_(router), value_(std::move(message)) {}
+
+ MessageWrapper(MessageWrapper&& other)
+ : router_(other.router_), value_(std::move(other.value_)) {}
+
+ ~MessageWrapper() {
+ if (value_.associated_endpoint_handles()->empty())
+ return;
+
+ router_->AssertLockAcquired();
+ {
+ MayAutoUnlock unlocker(&router_->lock_);
+ value_.mutable_associated_endpoint_handles()->clear();
+ }
+ }
+
+ MessageWrapper& operator=(MessageWrapper&& other) {
+ router_ = other.router_;
+ value_ = std::move(other.value_);
+ return *this;
+ }
+
+ Message& value() { return value_; }
+
+ private:
+ MultiplexRouter* router_ = nullptr;
+ Message value_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessageWrapper);
+};
+
struct MultiplexRouter::Task {
public:
// Doesn't take ownership of |message| but takes its contents.
- static std::unique_ptr<Task> CreateMessageTask(Message* message) {
+ static std::unique_ptr<Task> CreateMessageTask(
+ MessageWrapper message_wrapper) {
Task* task = new Task(MESSAGE);
- task->message.reset(new Message);
- message->MoveTo(task->message.get());
+ task->message_wrapper = std::move(message_wrapper);
return base::WrapUnique(task);
}
static std::unique_ptr<Task> CreateNotifyErrorTask(
@@ -271,7 +332,7 @@ struct MultiplexRouter::Task {
bool IsMessageTask() const { return type == MESSAGE; }
bool IsNotifyErrorTask() const { return type == NOTIFY_ERROR; }
- std::unique_ptr<Message> message;
+ MessageWrapper message_wrapper;
scoped_refptr<InterfaceEndpoint> endpoint_to_notify;
enum Type { MESSAGE, NOTIFY_ERROR };
@@ -279,36 +340,56 @@ struct MultiplexRouter::Task {
private:
explicit Task(Type in_type) : type(in_type) {}
+
+ DISALLOW_COPY_AND_ASSIGN(Task);
};
MultiplexRouter::MultiplexRouter(
- bool set_interface_id_namesapce_bit,
ScopedMessagePipeHandle message_pipe,
+ Config config,
+ bool set_interface_id_namesapce_bit,
scoped_refptr<base::SingleThreadTaskRunner> runner)
- : AssociatedGroupController(base::ThreadTaskRunnerHandle::Get()),
- set_interface_id_namespace_bit_(set_interface_id_namesapce_bit),
- header_validator_(this),
+ : set_interface_id_namespace_bit_(set_interface_id_namesapce_bit),
+ task_runner_(runner),
+ header_validator_(nullptr),
+ filters_(this),
connector_(std::move(message_pipe),
- Connector::MULTI_THREADED_SEND,
+ config == MULTI_INTERFACE ? Connector::MULTI_THREADED_SEND
+ : Connector::SINGLE_THREADED_SEND,
std::move(runner)),
control_message_handler_(this),
control_message_proxy_(&connector_),
next_interface_id_value_(1),
posted_to_process_tasks_(false),
encountered_error_(false),
+ paused_(false),
testing_mode_(false) {
- // Always participate in sync handle watching, because even if it doesn't
- // expect sync requests during sync handle watching, it may still need to
- // dispatch messages to associated endpoints on a different thread.
- connector_.AllowWokenUpBySyncWatchOnSameThread();
- connector_.set_incoming_receiver(&header_validator_);
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ if (config == MULTI_INTERFACE)
+ lock_.emplace();
+
+ if (config == SINGLE_INTERFACE_WITH_SYNC_METHODS ||
+ config == MULTI_INTERFACE) {
+ // Always participate in sync handle watching in multi-interface mode,
+ // because even if it doesn't expect sync requests during sync handle
+ // watching, it may still need to dispatch messages to associated endpoints
+ // on a different thread.
+ connector_.AllowWokenUpBySyncWatchOnSameThread();
+ }
+ connector_.set_incoming_receiver(&filters_);
connector_.set_connection_error_handler(
base::Bind(&MultiplexRouter::OnPipeConnectionError,
base::Unretained(this)));
+
+ std::unique_ptr<MessageHeaderValidator> header_validator =
+ base::MakeUnique<MessageHeaderValidator>();
+ header_validator_ = header_validator.get();
+ filters_.Append(std::move(header_validator));
}
MultiplexRouter::~MultiplexRouter() {
- base::AutoLock locker(lock_);
+ MayAutoLock locker(&lock_);
sync_message_tasks_.clear();
tasks_.clear();
@@ -319,40 +400,66 @@ MultiplexRouter::~MultiplexRouter() {
// because it may remove the corresponding value from the map.
++iter;
- DCHECK(endpoint->closed());
- UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
+ if (!endpoint->closed()) {
+ // This happens when a NotifyPeerEndpointClosed message been received, but
+ // the interface ID hasn't been used to create local endpoint handle.
+ DCHECK(!endpoint->client());
+ DCHECK(endpoint->peer_closed());
+ UpdateEndpointStateMayRemove(endpoint, ENDPOINT_CLOSED);
+ } else {
+ UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
+ }
}
DCHECK(endpoints_.empty());
}
-void MultiplexRouter::SetMasterInterfaceName(const std::string& name) {
+void MultiplexRouter::SetMasterInterfaceName(const char* name) {
DCHECK(thread_checker_.CalledOnValidThread());
- header_validator_.SetDescription(name + " [master] MessageHeaderValidator");
+ header_validator_->SetDescription(
+ std::string(name) + " [master] MessageHeaderValidator");
control_message_handler_.SetDescription(
- name + " [master] PipeControlMessageHandler");
+ std::string(name) + " [master] PipeControlMessageHandler");
+ connector_.SetWatcherHeapProfilerTag(name);
}
-void MultiplexRouter::CreateEndpointHandlePair(
- ScopedInterfaceEndpointHandle* local_endpoint,
- ScopedInterfaceEndpointHandle* remote_endpoint) {
- base::AutoLock locker(lock_);
+InterfaceId MultiplexRouter::AssociateInterface(
+ ScopedInterfaceEndpointHandle handle_to_send) {
+ if (!handle_to_send.pending_association())
+ return kInvalidInterfaceId;
+
uint32_t id = 0;
- do {
- if (next_interface_id_value_ >= kInterfaceIdNamespaceMask)
- next_interface_id_value_ = 1;
- id = next_interface_id_value_++;
- if (set_interface_id_namespace_bit_)
- id |= kInterfaceIdNamespaceMask;
- } while (ContainsKey(endpoints_, id));
-
- InterfaceEndpoint* endpoint = new InterfaceEndpoint(this, id);
- endpoints_[id] = endpoint;
- if (encountered_error_)
- UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
+ {
+ MayAutoLock locker(&lock_);
+ do {
+ if (next_interface_id_value_ >= kInterfaceIdNamespaceMask)
+ next_interface_id_value_ = 1;
+ id = next_interface_id_value_++;
+ if (set_interface_id_namespace_bit_)
+ id |= kInterfaceIdNamespaceMask;
+ } while (base::ContainsKey(endpoints_, id));
+
+ InterfaceEndpoint* endpoint = new InterfaceEndpoint(this, id);
+ endpoints_[id] = endpoint;
+ if (encountered_error_)
+ UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
+ endpoint->set_handle_created();
+ }
+
+ if (!NotifyAssociation(&handle_to_send, id)) {
+ // The peer handle of |handle_to_send|, which is supposed to join this
+ // associated group, has been closed.
+ {
+ MayAutoLock locker(&lock_);
+ InterfaceEndpoint* endpoint = FindEndpoint(id);
+ if (endpoint)
+ UpdateEndpointStateMayRemove(endpoint, ENDPOINT_CLOSED);
+ }
- *local_endpoint = CreateScopedInterfaceEndpointHandle(id, true);
- *remote_endpoint = CreateScopedInterfaceEndpointHandle(id, false);
+ control_message_proxy_.NotifyPeerEndpointClosed(
+ id, handle_to_send.disconnect_reason());
+ }
+ return id;
}
ScopedInterfaceEndpointHandle MultiplexRouter::CreateLocalEndpointHandle(
@@ -360,10 +467,12 @@ ScopedInterfaceEndpointHandle MultiplexRouter::CreateLocalEndpointHandle(
if (!IsValidInterfaceId(id))
return ScopedInterfaceEndpointHandle();
- base::AutoLock locker(lock_);
+ MayAutoLock locker(&lock_);
bool inserted = false;
InterfaceEndpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
if (inserted) {
+ DCHECK(!endpoint->handle_created());
+
if (encountered_error_)
UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
} else {
@@ -371,34 +480,32 @@ ScopedInterfaceEndpointHandle MultiplexRouter::CreateLocalEndpointHandle(
// notification that the peer endpoint has closed.
CHECK(!endpoint->closed());
CHECK(endpoint->peer_closed());
+
+ if (endpoint->handle_created())
+ return ScopedInterfaceEndpointHandle();
}
- return CreateScopedInterfaceEndpointHandle(id, true);
+
+ endpoint->set_handle_created();
+ return CreateScopedInterfaceEndpointHandle(id);
}
-void MultiplexRouter::CloseEndpointHandle(InterfaceId id, bool is_local) {
+void MultiplexRouter::CloseEndpointHandle(
+ InterfaceId id,
+ const base::Optional<DisconnectReason>& reason) {
if (!IsValidInterfaceId(id))
return;
- base::AutoLock locker(lock_);
-
- if (!is_local) {
- DCHECK(ContainsKey(endpoints_, id));
- DCHECK(!IsMasterInterfaceId(id));
-
- // We will receive a NotifyPeerEndpointClosed message from the other side.
- control_message_proxy_.NotifyEndpointClosedBeforeSent(id);
-
- return;
- }
-
- DCHECK(ContainsKey(endpoints_, id));
+ MayAutoLock locker(&lock_);
+ DCHECK(base::ContainsKey(endpoints_, id));
InterfaceEndpoint* endpoint = endpoints_[id].get();
DCHECK(!endpoint->client());
DCHECK(!endpoint->closed());
UpdateEndpointStateMayRemove(endpoint, ENDPOINT_CLOSED);
- if (!IsMasterInterfaceId(id))
- control_message_proxy_.NotifyPeerEndpointClosed(id);
+ if (!IsMasterInterfaceId(id) || reason) {
+ MayAutoUnlock unlocker(&lock_);
+ control_message_proxy_.NotifyPeerEndpointClosed(id, reason);
+ }
ProcessTasks(NO_DIRECT_CLIENT_CALLS, nullptr);
}
@@ -412,8 +519,8 @@ InterfaceEndpointController* MultiplexRouter::AttachEndpointClient(
DCHECK(IsValidInterfaceId(id));
DCHECK(client);
- base::AutoLock locker(lock_);
- DCHECK(ContainsKey(endpoints_, id));
+ MayAutoLock locker(&lock_);
+ DCHECK(base::ContainsKey(endpoints_, id));
InterfaceEndpoint* endpoint = endpoints_[id].get();
endpoint->AttachClient(client, std::move(runner));
@@ -431,8 +538,8 @@ void MultiplexRouter::DetachEndpointClient(
DCHECK(IsValidInterfaceId(id));
- base::AutoLock locker(lock_);
- DCHECK(ContainsKey(endpoints_, id));
+ MayAutoLock locker(&lock_);
+ DCHECK(base::ContainsKey(endpoints_, id));
InterfaceEndpoint* endpoint = endpoints_[id].get();
endpoint->DetachClient();
@@ -456,21 +563,51 @@ void MultiplexRouter::CloseMessagePipe() {
OnPipeConnectionError();
}
+void MultiplexRouter::PauseIncomingMethodCallProcessing() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ connector_.PauseIncomingMethodCallProcessing();
+
+ MayAutoLock locker(&lock_);
+ paused_ = true;
+
+ for (auto iter = endpoints_.begin(); iter != endpoints_.end(); ++iter)
+ iter->second->ResetSyncMessageSignal();
+}
+
+void MultiplexRouter::ResumeIncomingMethodCallProcessing() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ connector_.ResumeIncomingMethodCallProcessing();
+
+ MayAutoLock locker(&lock_);
+ paused_ = false;
+
+ for (auto iter = endpoints_.begin(); iter != endpoints_.end(); ++iter) {
+ auto sync_iter = sync_message_tasks_.find(iter->first);
+ if (iter->second->peer_closed() ||
+ (sync_iter != sync_message_tasks_.end() &&
+ !sync_iter->second.empty())) {
+ iter->second->SignalSyncMessageEvent();
+ }
+ }
+
+ ProcessTasks(NO_DIRECT_CLIENT_CALLS, nullptr);
+}
+
bool MultiplexRouter::HasAssociatedEndpoints() const {
DCHECK(thread_checker_.CalledOnValidThread());
- base::AutoLock locker(lock_);
+ MayAutoLock locker(&lock_);
if (endpoints_.size() > 1)
return true;
if (endpoints_.size() == 0)
return false;
- return !ContainsKey(endpoints_, kMasterInterfaceId);
+ return !base::ContainsKey(endpoints_, kMasterInterfaceId);
}
void MultiplexRouter::EnableTestingMode() {
DCHECK(thread_checker_.CalledOnValidThread());
- base::AutoLock locker(lock_);
+ MayAutoLock locker(&lock_);
testing_mode_ = true;
connector_.set_enforce_errors_from_incoming_receiver(false);
@@ -479,8 +616,13 @@ void MultiplexRouter::EnableTestingMode() {
bool MultiplexRouter::Accept(Message* message) {
DCHECK(thread_checker_.CalledOnValidThread());
+ if (!message->DeserializeAssociatedEndpointHandles(this))
+ return false;
+
scoped_refptr<MultiplexRouter> protector(this);
- base::AutoLock locker(lock_);
+ MayAutoLock locker(&lock_);
+
+ DCHECK(!paused_);
ClientCallBehavior client_call_behavior =
connector_.during_sync_handle_watcher_callback()
@@ -494,15 +636,16 @@ bool MultiplexRouter::Accept(Message* message) {
if (!processed) {
// Either the task queue is not empty or we cannot process the message
// directly. In both cases, there is no need to call ProcessTasks().
- tasks_.push_back(Task::CreateMessageTask(message));
+ tasks_.push_back(
+ Task::CreateMessageTask(MessageWrapper(this, std::move(*message))));
Task* task = tasks_.back().get();
- if (task->message->has_flag(Message::kFlagIsSync)) {
- InterfaceId id = task->message->interface_id();
+ if (task->message_wrapper.value().has_flag(Message::kFlagIsSync)) {
+ InterfaceId id = task->message_wrapper.value().interface_id();
sync_message_tasks_[id].push_back(task);
- auto iter = endpoints_.find(id);
- if (iter != endpoints_.end())
- iter->second->SignalSyncMessageEvent();
+ InterfaceEndpoint* endpoint = FindEndpoint(id);
+ if (endpoint)
+ endpoint->SignalSyncMessageEvent();
}
} else if (!tasks_.empty()) {
// Processing the message may result in new tasks (for error notification)
@@ -516,14 +659,17 @@ bool MultiplexRouter::Accept(Message* message) {
return true;
}
-bool MultiplexRouter::OnPeerAssociatedEndpointClosed(InterfaceId id) {
- lock_.AssertAcquired();
-
- if (IsMasterInterfaceId(id))
- return false;
+bool MultiplexRouter::OnPeerAssociatedEndpointClosed(
+ InterfaceId id,
+ const base::Optional<DisconnectReason>& reason) {
+ DCHECK(!IsMasterInterfaceId(id) || reason);
+ MayAutoLock locker(&lock_);
InterfaceEndpoint* endpoint = FindOrInsertEndpoint(id, nullptr);
+ if (reason)
+ endpoint->set_disconnect_reason(reason);
+
// It is possible that this endpoint has been set as peer closed. That is
// because when the message pipe is closed, all the endpoints are updated with
// PEER_ENDPOINT_CLOSED. We continue to process remaining tasks in the queue,
@@ -541,26 +687,11 @@ bool MultiplexRouter::OnPeerAssociatedEndpointClosed(InterfaceId id) {
return true;
}
-bool MultiplexRouter::OnAssociatedEndpointClosedBeforeSent(InterfaceId id) {
- lock_.AssertAcquired();
-
- if (IsMasterInterfaceId(id))
- return false;
-
- InterfaceEndpoint* endpoint = FindOrInsertEndpoint(id, nullptr);
- DCHECK(!endpoint->closed());
- UpdateEndpointStateMayRemove(endpoint, ENDPOINT_CLOSED);
-
- control_message_proxy_.NotifyPeerEndpointClosed(id);
-
- return true;
-}
-
void MultiplexRouter::OnPipeConnectionError() {
DCHECK(thread_checker_.CalledOnValidThread());
scoped_refptr<MultiplexRouter> protector(this);
- base::AutoLock locker(lock_);
+ MayAutoLock locker(&lock_);
encountered_error_ = true;
@@ -585,20 +716,21 @@ void MultiplexRouter::OnPipeConnectionError() {
void MultiplexRouter::ProcessTasks(
ClientCallBehavior client_call_behavior,
base::SingleThreadTaskRunner* current_task_runner) {
- lock_.AssertAcquired();
+ AssertLockAcquired();
if (posted_to_process_tasks_)
return;
- while (!tasks_.empty()) {
+ while (!tasks_.empty() && !paused_) {
std::unique_ptr<Task> task(std::move(tasks_.front()));
tasks_.pop_front();
InterfaceId id = kInvalidInterfaceId;
- bool sync_message = task->IsMessageTask() && task->message &&
- task->message->has_flag(Message::kFlagIsSync);
+ bool sync_message =
+ task->IsMessageTask() && !task->message_wrapper.value().IsNull() &&
+ task->message_wrapper.value().has_flag(Message::kFlagIsSync);
if (sync_message) {
- id = task->message->interface_id();
+ id = task->message_wrapper.value().interface_id();
auto& sync_message_queue = sync_message_tasks_[id];
DCHECK_EQ(task.get(), sync_message_queue.front());
sync_message_queue.pop_front();
@@ -608,8 +740,8 @@ void MultiplexRouter::ProcessTasks(
task->IsNotifyErrorTask()
? ProcessNotifyErrorTask(task.get(), client_call_behavior,
current_task_runner)
- : ProcessIncomingMessage(task->message.get(), client_call_behavior,
- current_task_runner);
+ : ProcessIncomingMessage(&task->message_wrapper.value(),
+ client_call_behavior, current_task_runner);
if (!processed) {
if (sync_message) {
@@ -629,21 +761,25 @@ void MultiplexRouter::ProcessTasks(
}
bool MultiplexRouter::ProcessFirstSyncMessageForEndpoint(InterfaceId id) {
- lock_.AssertAcquired();
+ AssertLockAcquired();
auto iter = sync_message_tasks_.find(id);
if (iter == sync_message_tasks_.end())
return false;
+ if (paused_)
+ return true;
+
MultiplexRouter::Task* task = iter->second.front();
iter->second.pop_front();
DCHECK(task->IsMessageTask());
- std::unique_ptr<Message> message(std::move(task->message));
+ MessageWrapper message_wrapper = std::move(task->message_wrapper);
- // Note: after this call, |task| and |iter| may be invalidated.
+ // Note: after this call, |task| and |iter| may be invalidated.
bool processed = ProcessIncomingMessage(
- message.get(), ALLOW_DIRECT_CLIENT_CALLS_FOR_SYNC_MESSAGES, nullptr);
+ &message_wrapper.value(), ALLOW_DIRECT_CLIENT_CALLS_FOR_SYNC_MESSAGES,
+ nullptr);
DCHECK(processed);
iter = sync_message_tasks_.find(id);
@@ -663,7 +799,9 @@ bool MultiplexRouter::ProcessNotifyErrorTask(
ClientCallBehavior client_call_behavior,
base::SingleThreadTaskRunner* current_task_runner) {
DCHECK(!current_task_runner || current_task_runner->BelongsToCurrentThread());
- lock_.AssertAcquired();
+ DCHECK(!paused_);
+
+ AssertLockAcquired();
InterfaceEndpoint* endpoint = task->endpoint_to_notify.get();
if (!endpoint->client())
return true;
@@ -677,14 +815,17 @@ bool MultiplexRouter::ProcessNotifyErrorTask(
DCHECK(endpoint->task_runner()->BelongsToCurrentThread());
InterfaceEndpointClient* client = endpoint->client();
+ base::Optional<DisconnectReason> disconnect_reason(
+ endpoint->disconnect_reason());
+
{
// We must unlock before calling into |client| because it may call this
// object within NotifyError(). Holding the lock will lead to deadlock.
//
// It is safe to call into |client| without the lock. Because |client| is
// always accessed on the same thread, including DetachEndpointClient().
- base::AutoUnlock unlocker(lock_);
- client->NotifyError();
+ MayAutoUnlock unlocker(&lock_);
+ client->NotifyError(disconnect_reason);
}
return true;
}
@@ -694,47 +835,35 @@ bool MultiplexRouter::ProcessIncomingMessage(
ClientCallBehavior client_call_behavior,
base::SingleThreadTaskRunner* current_task_runner) {
DCHECK(!current_task_runner || current_task_runner->BelongsToCurrentThread());
- lock_.AssertAcquired();
+ DCHECK(!paused_);
+ DCHECK(message);
+ AssertLockAcquired();
- if (!message) {
+ if (message->IsNull()) {
// This is a sync message and has been processed during sync handle
// watching.
return true;
}
if (PipeControlMessageHandler::IsPipeControlMessage(message)) {
- if (!control_message_handler_.Accept(message))
+ bool result = false;
+
+ {
+ MayAutoUnlock unlocker(&lock_);
+ result = control_message_handler_.Accept(message);
+ }
+
+ if (!result)
RaiseErrorInNonTestingMode();
+
return true;
}
InterfaceId id = message->interface_id();
DCHECK(IsValidInterfaceId(id));
- bool inserted = false;
- InterfaceEndpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
- if (inserted) {
- // Currently, it is legitimate to receive messages for an endpoint
- // that is not registered. For example, the endpoint is transferred in
- // a message that is discarded. Once we add support to specify all
- // enclosing endpoints in message header, we should be able to remove
- // this.
- UpdateEndpointStateMayRemove(endpoint, ENDPOINT_CLOSED);
-
- // It is also possible that this newly-inserted endpoint is the master
- // endpoint. When the master InterfacePtr/Binding goes away, the message
- // pipe is closed and we explicitly trigger a pipe connection error. The
- // error updates all the endpoints, including the master endpoint, with
- // PEER_ENDPOINT_CLOSED and removes the master endpoint from the
- // registration. We continue to process remaining tasks in the queue, as
- // long as there are refs keeping the router alive. If there are remaining
- // messages for the master endpoint, we will get here.
- if (!IsMasterInterfaceId(id))
- control_message_proxy_.NotifyPeerEndpointClosed(id);
- return true;
- }
-
- if (endpoint->closed())
+ InterfaceEndpoint* endpoint = FindEndpoint(id);
+ if (!endpoint || endpoint->closed())
return true;
if (!endpoint->client()) {
@@ -768,7 +897,7 @@ bool MultiplexRouter::ProcessIncomingMessage(
//
// It is safe to call into |client| without the lock. Because |client| is
// always accessed on the same thread, including DetachEndpointClient().
- base::AutoUnlock unlocker(lock_);
+ MayAutoUnlock unlocker(&lock_);
result = client->HandleIncomingMessage(message);
}
if (!result)
@@ -779,7 +908,7 @@ bool MultiplexRouter::ProcessIncomingMessage(
void MultiplexRouter::MaybePostToProcessTasks(
base::SingleThreadTaskRunner* task_runner) {
- lock_.AssertAcquired();
+ AssertLockAcquired();
if (posted_to_process_tasks_)
return;
@@ -792,7 +921,7 @@ void MultiplexRouter::MaybePostToProcessTasks(
void MultiplexRouter::LockAndCallProcessTasks() {
// There is no need to hold a ref to this class in this case because this is
// always called using base::Bind(), which holds a ref.
- base::AutoLock locker(lock_);
+ MayAutoLock locker(&lock_);
posted_to_process_tasks_ = false;
scoped_refptr<base::SingleThreadTaskRunner> runner(
std::move(posted_to_task_runner_));
@@ -802,23 +931,20 @@ void MultiplexRouter::LockAndCallProcessTasks() {
void MultiplexRouter::UpdateEndpointStateMayRemove(
InterfaceEndpoint* endpoint,
EndpointStateUpdateType type) {
- switch (type) {
- case ENDPOINT_CLOSED:
- endpoint->set_closed();
- break;
- case PEER_ENDPOINT_CLOSED:
- endpoint->set_peer_closed();
- // If the interface endpoint is performing a sync watch, this makes sure
- // it is notified and eventually exits the sync watch.
- endpoint->SignalSyncMessageEvent();
- break;
+ if (type == ENDPOINT_CLOSED) {
+ endpoint->set_closed();
+ } else {
+ endpoint->set_peer_closed();
+ // If the interface endpoint is performing a sync watch, this makes sure
+ // it is notified and eventually exits the sync watch.
+ endpoint->SignalSyncMessageEvent();
}
if (endpoint->closed() && endpoint->peer_closed())
endpoints_.erase(endpoint->id());
}
void MultiplexRouter::RaiseErrorInNonTestingMode() {
- lock_.AssertAcquired();
+ AssertLockAcquired();
if (!testing_mode_)
RaiseError();
}
@@ -826,24 +952,35 @@ void MultiplexRouter::RaiseErrorInNonTestingMode() {
MultiplexRouter::InterfaceEndpoint* MultiplexRouter::FindOrInsertEndpoint(
InterfaceId id,
bool* inserted) {
- lock_.AssertAcquired();
+ AssertLockAcquired();
// Either |inserted| is nullptr or it points to a boolean initialized as
// false.
DCHECK(!inserted || !*inserted);
- auto iter = endpoints_.find(id);
- InterfaceEndpoint* endpoint;
- if (iter == endpoints_.end()) {
+ InterfaceEndpoint* endpoint = FindEndpoint(id);
+ if (!endpoint) {
endpoint = new InterfaceEndpoint(this, id);
endpoints_[id] = endpoint;
if (inserted)
*inserted = true;
- } else {
- endpoint = iter->second.get();
}
return endpoint;
}
+MultiplexRouter::InterfaceEndpoint* MultiplexRouter::FindEndpoint(
+ InterfaceId id) {
+ AssertLockAcquired();
+ auto iter = endpoints_.find(id);
+ return iter != endpoints_.end() ? iter->second.get() : nullptr;
+}
+
+void MultiplexRouter::AssertLockAcquired() {
+#if DCHECK_IS_ON()
+ if (lock_)
+ lock_->AssertAcquired();
+#endif
+}
+
} // namespace internal
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.h b/mojo/public/cpp/bindings/lib/multiplex_router.h
index dc66e8e..cac138b 100644
--- a/mojo/public/cpp/bindings/lib/multiplex_router.h
+++ b/mojo/public/cpp/bindings/lib/multiplex_router.h
@@ -12,15 +12,19 @@
#include <memory>
#include <string>
+#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "mojo/public/cpp/bindings/associated_group_controller.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/connector.h"
+#include "mojo/public/cpp/bindings/filter_chain.h"
#include "mojo/public/cpp/bindings/interface_id.h"
#include "mojo/public/cpp/bindings/message_header_validator.h"
#include "mojo/public/cpp/bindings/pipe_control_message_handler.h"
@@ -34,8 +38,6 @@ class SingleThreadTaskRunner;
namespace mojo {
-class AssociatedGroup;
-
namespace internal {
// MultiplexRouter supports routing messages for multiple interfaces over a
@@ -47,31 +49,51 @@ namespace internal {
// Some public methods are only allowed to be called on the creating thread;
// while the others are safe to call from any threads. Please see the method
// comments for more details.
-class MultiplexRouter
- : public MessageReceiver,
+//
+// NOTE: CloseMessagePipe() or PassMessagePipe() MUST be called on |runner|'s
+// thread before this object is destroyed.
+class MOJO_CPP_BINDINGS_EXPORT MultiplexRouter
+ : NON_EXPORTED_BASE(public MessageReceiver),
public AssociatedGroupController,
- public PipeControlMessageHandlerDelegate {
+ NON_EXPORTED_BASE(public PipeControlMessageHandlerDelegate) {
public:
+ enum Config {
+ // There is only the master interface running on this router. Please note
+ // that because of interface versioning, the other side of the message pipe
+ // may use a newer master interface definition which passes associated
+ // interfaces. In that case, this router may still receive pipe control
+ // messages or messages targetting associated interfaces.
+ SINGLE_INTERFACE,
+ // Similar to the mode above, there is only the master interface running on
+ // this router. Besides, the master interface has sync methods.
+ SINGLE_INTERFACE_WITH_SYNC_METHODS,
+ // There may be associated interfaces running on this router.
+ MULTI_INTERFACE
+ };
+
// If |set_interface_id_namespace_bit| is true, the interface IDs generated by
// this router will have the highest bit set.
- MultiplexRouter(bool set_interface_id_namespace_bit,
- ScopedMessagePipeHandle message_pipe,
+ MultiplexRouter(ScopedMessagePipeHandle message_pipe,
+ Config config,
+ bool set_interface_id_namespace_bit,
scoped_refptr<base::SingleThreadTaskRunner> runner);
// Sets the master interface name for this router. Only used when reporting
// message header or control message validation errors.
- void SetMasterInterfaceName(const std::string& name);
+ // |name| must be a string literal.
+ void SetMasterInterfaceName(const char* name);
// ---------------------------------------------------------------------------
// The following public methods are safe to call from any threads.
// AssociatedGroupController implementation:
- void CreateEndpointHandlePair(
- ScopedInterfaceEndpointHandle* local_endpoint,
- ScopedInterfaceEndpointHandle* remote_endpoint) override;
+ InterfaceId AssociateInterface(
+ ScopedInterfaceEndpointHandle handle_to_send) override;
ScopedInterfaceEndpointHandle CreateLocalEndpointHandle(
InterfaceId id) override;
- void CloseEndpointHandle(InterfaceId id, bool is_local) override;
+ void CloseEndpointHandle(
+ InterfaceId id,
+ const base::Optional<DisconnectReason>& reason) override;
InterfaceEndpointController* AttachEndpointClient(
const ScopedInterfaceEndpointHandle& handle,
InterfaceEndpointClient* endpoint_client,
@@ -102,14 +124,8 @@ class MultiplexRouter
}
// See Binding for details of pause/resume.
- void PauseIncomingMethodCallProcessing() {
- DCHECK(thread_checker_.CalledOnValidThread());
- connector_.PauseIncomingMethodCallProcessing();
- }
- void ResumeIncomingMethodCallProcessing() {
- DCHECK(thread_checker_.CalledOnValidThread());
- connector_.ResumeIncomingMethodCallProcessing();
- }
+ void PauseIncomingMethodCallProcessing();
+ void ResumeIncomingMethodCallProcessing();
// Whether there are any associated interfaces running currently.
bool HasAssociatedEndpoints() const;
@@ -131,8 +147,13 @@ class MultiplexRouter
return connector_.handle();
}
+ bool SimulateReceivingMessageForTesting(Message* message) {
+ return filters_.Accept(message);
+ }
+
private:
class InterfaceEndpoint;
+ class MessageWrapper;
struct Task;
~MultiplexRouter() override;
@@ -141,8 +162,9 @@ class MultiplexRouter
bool Accept(Message* message) override;
// PipeControlMessageHandlerDelegate implementation:
- bool OnPeerAssociatedEndpointClosed(InterfaceId id) override;
- bool OnAssociatedEndpointClosedBeforeSent(InterfaceId id) override;
+ bool OnPeerAssociatedEndpointClosed(
+ InterfaceId id,
+ const base::Optional<DisconnectReason>& reason) override;
void OnPipeConnectionError();
@@ -202,19 +224,30 @@ class MultiplexRouter
void RaiseErrorInNonTestingMode();
InterfaceEndpoint* FindOrInsertEndpoint(InterfaceId id, bool* inserted);
+ InterfaceEndpoint* FindEndpoint(InterfaceId id);
+
+ void AssertLockAcquired();
// Whether to set the namespace bit when generating interface IDs. Please see
// comments of kInterfaceIdNamespaceMask.
const bool set_interface_id_namespace_bit_;
- MessageHeaderValidator header_validator_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ // Owned by |filters_| below.
+ MessageHeaderValidator* header_validator_;
+
+ FilterChain filters_;
Connector connector_;
base::ThreadChecker thread_checker_;
// Protects the following members.
- mutable base::Lock lock_;
+ // Not set in Config::SINGLE_INTERFACE* mode.
+ mutable base::Optional<base::Lock> lock_;
PipeControlMessageHandler control_message_handler_;
+
+ // NOTE: It is unsafe to call into this object while holding |lock_|.
PipeControlMessageProxy control_message_proxy_;
std::map<InterfaceId, scoped_refptr<InterfaceEndpoint>> endpoints_;
@@ -229,6 +262,8 @@ class MultiplexRouter
bool encountered_error_;
+ bool paused_;
+
bool testing_mode_;
DISALLOW_COPY_AND_ASSIGN(MultiplexRouter);
diff --git a/mojo/public/cpp/bindings/lib/native_struct.cc b/mojo/public/cpp/bindings/lib/native_struct.cc
index 837b75a..7b1a1a6 100644
--- a/mojo/public/cpp/bindings/lib/native_struct.cc
+++ b/mojo/public/cpp/bindings/lib/native_struct.cc
@@ -4,27 +4,31 @@
#include "mojo/public/cpp/bindings/native_struct.h"
+#include "mojo/public/cpp/bindings/lib/hash_util.h"
+
namespace mojo {
// static
NativeStructPtr NativeStruct::New() {
- NativeStructPtr rv;
- internal::StructHelper<NativeStruct>::Initialize(&rv);
- return rv;
+ return NativeStructPtr(base::in_place);
}
-NativeStruct::NativeStruct() : data(nullptr) {}
+NativeStruct::NativeStruct() {}
NativeStruct::~NativeStruct() {}
NativeStructPtr NativeStruct::Clone() const {
NativeStructPtr rv(New());
- rv->data = data.Clone();
+ rv->data = data;
return rv;
}
bool NativeStruct::Equals(const NativeStruct& other) const {
- return data.Equals(other.data);
+ return data == other.data;
+}
+
+size_t NativeStruct::Hash(size_t seed) const {
+ return internal::Hash(seed, data);
}
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/native_struct_data.h b/mojo/public/cpp/bindings/lib/native_struct_data.h
index 5c58774..1c7cd81 100644
--- a/mojo/public/cpp/bindings/lib/native_struct_data.h
+++ b/mojo/public/cpp/bindings/lib/native_struct_data.h
@@ -7,16 +7,16 @@
#include <vector>
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/lib/array_internal.h"
#include "mojo/public/cpp/system/handle.h"
namespace mojo {
namespace internal {
-class Buffer;
class ValidationContext;
-class NativeStruct_Data {
+class MOJO_CPP_BINDINGS_EXPORT NativeStruct_Data {
public:
static bool Validate(const void* data, ValidationContext* validation_context);
diff --git a/mojo/public/cpp/bindings/lib/native_struct_serialization.cc b/mojo/public/cpp/bindings/lib/native_struct_serialization.cc
index ac06059..fa0dbf3 100644
--- a/mojo/public/cpp/bindings/lib/native_struct_serialization.cc
+++ b/mojo/public/cpp/bindings/lib/native_struct_serialization.cc
@@ -15,7 +15,8 @@ size_t UnmappedNativeStructSerializerImpl::PrepareToSerialize(
SerializationContext* context) {
if (!input)
return 0;
- return internal::PrepareToSerialize<Array<uint8_t>>(input->data, context);
+ return internal::PrepareToSerialize<ArrayDataView<uint8_t>>(input->data,
+ context);
}
// static
@@ -31,8 +32,8 @@ void UnmappedNativeStructSerializerImpl::Serialize(
Array_Data<uint8_t>* data = nullptr;
const ContainerValidateParams params(0, false, nullptr);
- internal::Serialize<Array<uint8_t>>(input->data, buffer, &data, &params,
- context);
+ internal::Serialize<ArrayDataView<uint8_t>>(input->data, buffer, &data,
+ &params, context);
*output = reinterpret_cast<NativeStruct_Data*>(data);
}
@@ -44,7 +45,8 @@ bool UnmappedNativeStructSerializerImpl::Deserialize(
Array_Data<uint8_t>* data = reinterpret_cast<Array_Data<uint8_t>*>(input);
NativeStructPtr result(NativeStruct::New());
- if (!internal::Deserialize<Array<uint8_t>>(data, &result->data, context)) {
+ if (!internal::Deserialize<ArrayDataView<uint8_t>>(data, &result->data,
+ context)) {
output = nullptr;
return false;
}
diff --git a/mojo/public/cpp/bindings/lib/native_struct_serialization.h b/mojo/public/cpp/bindings/lib/native_struct_serialization.h
index e64b862..457435b 100644
--- a/mojo/public/cpp/bindings/lib/native_struct_serialization.h
+++ b/mojo/public/cpp/bindings/lib/native_struct_serialization.h
@@ -13,12 +13,14 @@
#include "base/logging.h"
#include "base/pickle.h"
#include "ipc/ipc_param_traits.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/lib/array_internal.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
#include "mojo/public/cpp/bindings/lib/native_struct_data.h"
#include "mojo/public/cpp/bindings/lib/serialization_forward.h"
#include "mojo/public/cpp/bindings/lib/serialization_util.h"
#include "mojo/public/cpp/bindings/native_struct.h"
+#include "mojo/public/cpp/bindings/native_struct_data_view.h"
namespace mojo {
namespace internal {
@@ -102,7 +104,7 @@ struct NativeStructSerializerImpl {
}
};
-struct UnmappedNativeStructSerializerImpl {
+struct MOJO_CPP_BINDINGS_EXPORT UnmappedNativeStructSerializerImpl {
static size_t PrepareToSerialize(const NativeStructPtr& input,
SerializationContext* context);
static void Serialize(const NativeStructPtr& input,
@@ -123,7 +125,7 @@ struct NativeStructSerializerImpl<const NativeStructPtr>
: public UnmappedNativeStructSerializerImpl {};
template <typename MaybeConstUserType>
-struct Serializer<NativeStructPtr, MaybeConstUserType>
+struct Serializer<NativeStructDataView, MaybeConstUserType>
: public NativeStructSerializerImpl<MaybeConstUserType> {};
} // namespace internal
diff --git a/mojo/public/cpp/bindings/lib/no_interface.cc b/mojo/public/cpp/bindings/lib/no_interface.cc
deleted file mode 100644
index 9e0945c..0000000
--- a/mojo/public/cpp/bindings/lib/no_interface.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/public/cpp/bindings/no_interface.h"
-
-namespace mojo {
-
-const char* NoInterface::Name_ = "mojo::NoInterface";
-
-bool NoInterfaceStub::Accept(Message* message) {
- return false;
-}
-
-bool NoInterfaceStub::AcceptWithResponder(Message* message,
- MessageReceiver* responder) {
- return false;
-}
-
-} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc b/mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc
index 7ee9f8a..d451c05 100644
--- a/mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc
+++ b/mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc
@@ -5,8 +5,10 @@
#include "mojo/public/cpp/bindings/pipe_control_message_handler.h"
#include "base/logging.h"
+#include "mojo/public/cpp/bindings/interface_id.h"
#include "mojo/public/cpp/bindings/lib/message_builder.h"
#include "mojo/public/cpp/bindings/lib/serialization.h"
+#include "mojo/public/cpp/bindings/lib/serialization_context.h"
#include "mojo/public/cpp/bindings/lib/validation_context.h"
#include "mojo/public/cpp/bindings/lib/validation_util.h"
#include "mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h"
@@ -41,8 +43,9 @@ bool PipeControlMessageHandler::Accept(Message* message) {
}
bool PipeControlMessageHandler::Validate(Message* message) {
- internal::ValidationContext validation_context(
- message->data(), message->data_num_bytes(), 0, message, description_);
+ internal::ValidationContext validation_context(message->payload(),
+ message->payload_num_bytes(),
+ 0, 0, message, description_);
if (message->name() == pipe_control::kRunOrClosePipeMessageId) {
if (!internal::ValidateMessageIsRequestWithoutResponse(
@@ -58,22 +61,25 @@ bool PipeControlMessageHandler::Validate(Message* message) {
}
bool PipeControlMessageHandler::RunOrClosePipe(Message* message) {
+ internal::SerializationContext context;
pipe_control::internal::RunOrClosePipeMessageParams_Data* params =
reinterpret_cast<
pipe_control::internal::RunOrClosePipeMessageParams_Data*>(
message->mutable_payload());
pipe_control::RunOrClosePipeMessageParamsPtr params_ptr;
- internal::Deserialize<pipe_control::RunOrClosePipeMessageParamsPtr>(
- params, &params_ptr, &context_);
+ internal::Deserialize<pipe_control::RunOrClosePipeMessageParamsDataView>(
+ params, &params_ptr, &context);
if (params_ptr->input->is_peer_associated_endpoint_closed_event()) {
- return delegate_->OnPeerAssociatedEndpointClosed(
- params_ptr->input->get_peer_associated_endpoint_closed_event()->id);
- }
- if (params_ptr->input->is_associated_endpoint_closed_before_sent_event()) {
- return delegate_->OnAssociatedEndpointClosedBeforeSent(
- params_ptr->input->get_associated_endpoint_closed_before_sent_event()
- ->id);
+ const auto& event =
+ params_ptr->input->get_peer_associated_endpoint_closed_event();
+
+ base::Optional<DisconnectReason> reason;
+ if (event->disconnect_reason) {
+ reason.emplace(event->disconnect_reason->custom_reason,
+ event->disconnect_reason->description);
+ }
+ return delegate_->OnPeerAssociatedEndpointClosed(event->id, reason);
}
DVLOG(1) << "Unsupported command in a RunOrClosePipe message pipe control "
diff --git a/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc b/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc
index 55ee64b..701108e 100644
--- a/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc
+++ b/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc
@@ -11,33 +11,28 @@
#include "base/logging.h"
#include "mojo/public/cpp/bindings/lib/message_builder.h"
#include "mojo/public/cpp/bindings/lib/serialization.h"
-#include "mojo/public/cpp/bindings/message.h"
#include "mojo/public/interfaces/bindings/pipe_control_messages.mojom.h"
namespace mojo {
namespace {
-void SendRunOrClosePipeMessage(MessageReceiver* receiver,
- pipe_control::RunOrClosePipeInputPtr input,
- internal::SerializationContext* context) {
- pipe_control::RunOrClosePipeMessageParamsPtr params_ptr(
- pipe_control::RunOrClosePipeMessageParams::New());
- params_ptr->input = std::move(input);
+Message ConstructRunOrClosePipeMessage(
+ pipe_control::RunOrClosePipeInputPtr input_ptr) {
+ internal::SerializationContext context;
- size_t size =
- internal::PrepareToSerialize<
- pipe_control::RunOrClosePipeMessageParamsPtr>(params_ptr, context);
- internal::MessageBuilder builder(pipe_control::kRunOrClosePipeMessageId,
- size);
+ auto params_ptr = pipe_control::RunOrClosePipeMessageParams::New();
+ params_ptr->input = std::move(input_ptr);
+
+ size_t size = internal::PrepareToSerialize<
+ pipe_control::RunOrClosePipeMessageParamsDataView>(params_ptr, &context);
+ internal::MessageBuilder builder(pipe_control::kRunOrClosePipeMessageId, 0,
+ size, 0);
pipe_control::internal::RunOrClosePipeMessageParams_Data* params = nullptr;
- internal::Serialize<pipe_control::RunOrClosePipeMessageParamsPtr>(
- params_ptr, builder.buffer(), &params, context);
+ internal::Serialize<pipe_control::RunOrClosePipeMessageParamsDataView>(
+ params_ptr, builder.buffer(), &params, &context);
builder.message()->set_interface_id(kInvalidInterfaceId);
- bool ok = receiver->Accept(builder.message());
- // This return value may be ignored as !ok implies the underlying message pipe
- // has encountered an error, which will be visible through other means.
- ALLOW_UNUSED_LOCAL(ok);
+ return std::move(*builder.message());
}
} // namespace
@@ -45,30 +40,30 @@ void SendRunOrClosePipeMessage(MessageReceiver* receiver,
PipeControlMessageProxy::PipeControlMessageProxy(MessageReceiver* receiver)
: receiver_(receiver) {}
-void PipeControlMessageProxy::NotifyPeerEndpointClosed(InterfaceId id) {
- DCHECK(!IsMasterInterfaceId(id));
- pipe_control::PeerAssociatedEndpointClosedEventPtr event(
- pipe_control::PeerAssociatedEndpointClosedEvent::New());
- event->id = id;
-
- pipe_control::RunOrClosePipeInputPtr input(
- pipe_control::RunOrClosePipeInput::New());
- input->set_peer_associated_endpoint_closed_event(std::move(event));
-
- SendRunOrClosePipeMessage(receiver_, std::move(input), &context_);
+void PipeControlMessageProxy::NotifyPeerEndpointClosed(
+ InterfaceId id,
+ const base::Optional<DisconnectReason>& reason) {
+ Message message(ConstructPeerEndpointClosedMessage(id, reason));
+ bool ok = receiver_->Accept(&message);
+ ALLOW_UNUSED_LOCAL(ok);
}
-void PipeControlMessageProxy::NotifyEndpointClosedBeforeSent(InterfaceId id) {
- DCHECK(!IsMasterInterfaceId(id));
- pipe_control::AssociatedEndpointClosedBeforeSentEventPtr event(
- pipe_control::AssociatedEndpointClosedBeforeSentEvent::New());
+// static
+Message PipeControlMessageProxy::ConstructPeerEndpointClosedMessage(
+ InterfaceId id,
+ const base::Optional<DisconnectReason>& reason) {
+ auto event = pipe_control::PeerAssociatedEndpointClosedEvent::New();
event->id = id;
+ if (reason) {
+ event->disconnect_reason = pipe_control::DisconnectReason::New();
+ event->disconnect_reason->custom_reason = reason->custom_reason;
+ event->disconnect_reason->description = reason->description;
+ }
- pipe_control::RunOrClosePipeInputPtr input(
- pipe_control::RunOrClosePipeInput::New());
- input->set_associated_endpoint_closed_before_sent_event(std::move(event));
+ auto input = pipe_control::RunOrClosePipeInput::New();
+ input->set_peer_associated_endpoint_closed_event(std::move(event));
- SendRunOrClosePipeMessage(receiver_, std::move(input), &context_);
+ return ConstructRunOrClosePipeMessage(std::move(input));
}
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/router.cc b/mojo/public/cpp/bindings/lib/router.cc
deleted file mode 100644
index 8c1b77d..0000000
--- a/mojo/public/cpp/bindings/lib/router.cc
+++ /dev/null
@@ -1,323 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/public/cpp/bindings/lib/router.h"
-
-#include <stdint.h>
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
-#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
-
-namespace mojo {
-namespace internal {
-
-// ----------------------------------------------------------------------------
-
-namespace {
-
-void DCheckIfInvalid(const base::WeakPtr<Router>& router,
- const std::string& message) {
- bool is_valid = router && !router->encountered_error() && router->is_valid();
- DCHECK(!is_valid) << message;
-}
-
-class ResponderThunk : public MessageReceiverWithStatus {
- public:
- explicit ResponderThunk(const base::WeakPtr<Router>& router,
- scoped_refptr<base::SingleThreadTaskRunner> runner)
- : router_(router),
- accept_was_invoked_(false),
- task_runner_(std::move(runner)) {}
- ~ResponderThunk() override {
- if (!accept_was_invoked_) {
- // The Mojo application handled a message that was expecting a response
- // but did not send a response.
- // We raise an error to signal the calling application that an error
- // condition occurred. Without this the calling application would have no
- // way of knowing it should stop waiting for a response.
- if (task_runner_->RunsTasksOnCurrentThread()) {
- // Please note that even if this code is run from a different task
- // runner on the same thread as |task_runner_|, it is okay to directly
- // call Router::RaiseError(), because it will raise error from the
- // correct task runner asynchronously.
- if (router_)
- router_->RaiseError();
- } else {
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&Router::RaiseError, router_));
- }
- }
- }
-
- // MessageReceiver implementation:
- bool Accept(Message* message) override {
- DCHECK(task_runner_->RunsTasksOnCurrentThread());
- accept_was_invoked_ = true;
- DCHECK(message->has_flag(Message::kFlagIsResponse));
-
- bool result = false;
-
- if (router_)
- result = router_->Accept(message);
-
- return result;
- }
-
- // MessageReceiverWithStatus implementation:
- bool IsValid() override {
- DCHECK(task_runner_->RunsTasksOnCurrentThread());
- return router_ && !router_->encountered_error() && router_->is_valid();
- }
-
- void DCheckInvalid(const std::string& message) override {
- if (task_runner_->RunsTasksOnCurrentThread()) {
- DCheckIfInvalid(router_, message);
- } else {
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&DCheckIfInvalid, router_, message));
- }
- }
-
- private:
- base::WeakPtr<Router> router_;
- bool accept_was_invoked_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-};
-
-} // namespace
-
-// ----------------------------------------------------------------------------
-
-Router::SyncResponseInfo::SyncResponseInfo(bool* in_response_received)
- : response_received(in_response_received) {}
-
-Router::SyncResponseInfo::~SyncResponseInfo() {}
-
-// ----------------------------------------------------------------------------
-
-Router::HandleIncomingMessageThunk::HandleIncomingMessageThunk(Router* router)
- : router_(router) {
-}
-
-Router::HandleIncomingMessageThunk::~HandleIncomingMessageThunk() {
-}
-
-bool Router::HandleIncomingMessageThunk::Accept(Message* message) {
- return router_->HandleIncomingMessage(message);
-}
-
-// ----------------------------------------------------------------------------
-
-Router::Router(ScopedMessagePipeHandle message_pipe,
- FilterChain filters,
- bool expects_sync_requests,
- scoped_refptr<base::SingleThreadTaskRunner> runner)
- : thunk_(this),
- filters_(std::move(filters)),
- connector_(std::move(message_pipe),
- Connector::SINGLE_THREADED_SEND,
- std::move(runner)),
- incoming_receiver_(nullptr),
- next_request_id_(0),
- testing_mode_(false),
- pending_task_for_messages_(false),
- encountered_error_(false),
- weak_factory_(this) {
- filters_.SetSink(&thunk_);
- if (expects_sync_requests)
- connector_.AllowWokenUpBySyncWatchOnSameThread();
- connector_.set_incoming_receiver(filters_.GetHead());
- connector_.set_connection_error_handler(
- base::Bind(&Router::OnConnectionError, base::Unretained(this)));
-}
-
-Router::~Router() {}
-
-bool Router::Accept(Message* message) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!message->has_flag(Message::kFlagExpectsResponse));
- return connector_.Accept(message);
-}
-
-bool Router::AcceptWithResponder(Message* message, MessageReceiver* responder) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(message->has_flag(Message::kFlagExpectsResponse));
-
- // Reserve 0 in case we want it to convey special meaning in the future.
- uint64_t request_id = next_request_id_++;
- if (request_id == 0)
- request_id = next_request_id_++;
-
- bool is_sync = message->has_flag(Message::kFlagIsSync);
- message->set_request_id(request_id);
- if (!connector_.Accept(message))
- return false;
-
- if (!is_sync) {
- // We assume ownership of |responder|.
- async_responders_[request_id] = base::WrapUnique(responder);
- return true;
- }
-
- SyncCallRestrictions::AssertSyncCallAllowed();
-
- bool response_received = false;
- std::unique_ptr<MessageReceiver> sync_responder(responder);
- sync_responses_.insert(std::make_pair(
- request_id, base::WrapUnique(new SyncResponseInfo(&response_received))));
-
- base::WeakPtr<Router> weak_self = weak_factory_.GetWeakPtr();
- connector_.SyncWatch(&response_received);
- // Make sure that this instance hasn't been destroyed.
- if (weak_self) {
- DCHECK(ContainsKey(sync_responses_, request_id));
- auto iter = sync_responses_.find(request_id);
- DCHECK_EQ(&response_received, iter->second->response_received);
- if (response_received) {
- std::unique_ptr<Message> response = std::move(iter->second->response);
- ignore_result(sync_responder->Accept(response.get()));
- }
- sync_responses_.erase(iter);
- }
-
- // Return true means that we take ownership of |responder|.
- return true;
-}
-
-void Router::EnableTestingMode() {
- DCHECK(thread_checker_.CalledOnValidThread());
- testing_mode_ = true;
- connector_.set_enforce_errors_from_incoming_receiver(false);
-}
-
-bool Router::HandleIncomingMessage(Message* message) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- const bool during_sync_call =
- connector_.during_sync_handle_watcher_callback();
- if (!message->has_flag(Message::kFlagIsSync) &&
- (during_sync_call || !pending_messages_.empty())) {
- std::unique_ptr<Message> pending_message(new Message);
- message->MoveTo(pending_message.get());
- pending_messages_.push(std::move(pending_message));
-
- if (!pending_task_for_messages_) {
- pending_task_for_messages_ = true;
- connector_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&Router::HandleQueuedMessages,
- weak_factory_.GetWeakPtr()));
- }
-
- return true;
- }
-
- return HandleMessageInternal(message);
-}
-
-void Router::HandleQueuedMessages() {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(pending_task_for_messages_);
-
- base::WeakPtr<Router> weak_self = weak_factory_.GetWeakPtr();
- while (!pending_messages_.empty()) {
- std::unique_ptr<Message> message(std::move(pending_messages_.front()));
- pending_messages_.pop();
-
- bool result = HandleMessageInternal(message.get());
- if (!weak_self)
- return;
-
- if (!result && !testing_mode_) {
- connector_.RaiseError();
- break;
- }
- }
-
- pending_task_for_messages_ = false;
-
- // We may have already seen a connection error from the connector, but
- // haven't notified the user because we want to process all the queued
- // messages first. We should do it now.
- if (connector_.encountered_error() && !encountered_error_)
- OnConnectionError();
-}
-
-bool Router::HandleMessageInternal(Message* message) {
- if (message->has_flag(Message::kFlagExpectsResponse)) {
- if (!incoming_receiver_)
- return false;
-
- MessageReceiverWithStatus* responder = new ResponderThunk(
- weak_factory_.GetWeakPtr(), connector_.task_runner());
- bool ok = incoming_receiver_->AcceptWithResponder(message, responder);
- if (!ok)
- delete responder;
- return ok;
-
- } else if (message->has_flag(Message::kFlagIsResponse)) {
- uint64_t request_id = message->request_id();
-
- if (message->has_flag(Message::kFlagIsSync)) {
- auto it = sync_responses_.find(request_id);
- if (it == sync_responses_.end()) {
- DCHECK(testing_mode_);
- return false;
- }
- it->second->response.reset(new Message());
- message->MoveTo(it->second->response.get());
- *it->second->response_received = true;
- return true;
- }
-
- auto it = async_responders_.find(request_id);
- if (it == async_responders_.end()) {
- DCHECK(testing_mode_);
- return false;
- }
- std::unique_ptr<MessageReceiver> responder = std::move(it->second);
- async_responders_.erase(it);
- return responder->Accept(message);
- } else {
- if (!incoming_receiver_)
- return false;
-
- return incoming_receiver_->Accept(message);
- }
-}
-
-void Router::OnConnectionError() {
- if (encountered_error_)
- return;
-
- if (!pending_messages_.empty()) {
- // After all the pending messages are processed, we will check whether an
- // error has been encountered and run the user's connection error handler
- // if necessary.
- DCHECK(pending_task_for_messages_);
- return;
- }
-
- if (connector_.during_sync_handle_watcher_callback()) {
- // We don't want the error handler to reenter an ongoing sync call.
- connector_.task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&Router::OnConnectionError, weak_factory_.GetWeakPtr()));
- return;
- }
-
- encountered_error_ = true;
- if (!error_handler_.is_null())
- error_handler_.Run();
-}
-
-// ----------------------------------------------------------------------------
-
-} // namespace internal
-} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/router.h b/mojo/public/cpp/bindings/lib/router.h
deleted file mode 100644
index 6dbe08d..0000000
--- a/mojo/public/cpp/bindings/lib/router.h
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <queue>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_checker.h"
-#include "mojo/public/cpp/bindings/connector.h"
-#include "mojo/public/cpp/bindings/lib/filter_chain.h"
-
-namespace mojo {
-namespace internal {
-
-// TODO(yzshen): Consider removing this class and use MultiplexRouter in all
-// cases. crbug.com/594244
-class Router : public MessageReceiverWithResponder {
- public:
- Router(ScopedMessagePipeHandle message_pipe,
- FilterChain filters,
- bool expects_sync_requests,
- scoped_refptr<base::SingleThreadTaskRunner> runner);
- ~Router() override;
-
- // Sets the receiver to handle messages read from the message pipe that do
- // not have the Message::kFlagIsResponse flag set.
- void set_incoming_receiver(MessageReceiverWithResponderStatus* receiver) {
- incoming_receiver_ = receiver;
- }
-
- // Sets the error handler to receive notifications when an error is
- // encountered while reading from the pipe or waiting to read from the pipe.
- void set_connection_error_handler(const base::Closure& error_handler) {
- error_handler_ = error_handler;
- }
-
- // Returns true if an error was encountered while reading from the pipe or
- // waiting to read from the pipe.
- bool encountered_error() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- return encountered_error_;
- }
-
- // Is the router bound to a MessagePipe handle?
- bool is_valid() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- return connector_.is_valid();
- }
-
- // Please note that this method shouldn't be called unless it results from an
- // explicit request of the user of bindings (e.g., the user sets an
- // InterfacePtr to null or closes a Binding).
- void CloseMessagePipe() {
- DCHECK(thread_checker_.CalledOnValidThread());
- connector_.CloseMessagePipe();
- }
-
- ScopedMessagePipeHandle PassMessagePipe() {
- DCHECK(thread_checker_.CalledOnValidThread());
- return connector_.PassMessagePipe();
- }
-
- void RaiseError() {
- DCHECK(thread_checker_.CalledOnValidThread());
- connector_.RaiseError();
- }
-
- // MessageReceiver implementation:
- bool Accept(Message* message) override;
- bool AcceptWithResponder(Message* message,
- MessageReceiver* responder) override;
-
- // Blocks the current thread until the first incoming method call, i.e.,
- // either a call to a client method or a callback method, or |deadline|.
- bool WaitForIncomingMessage(MojoDeadline deadline) {
- DCHECK(thread_checker_.CalledOnValidThread());
- return connector_.WaitForIncomingMessage(deadline);
- }
-
- // See Binding for details of pause/resume.
- void PauseIncomingMethodCallProcessing() {
- DCHECK(thread_checker_.CalledOnValidThread());
- connector_.PauseIncomingMethodCallProcessing();
- }
- void ResumeIncomingMethodCallProcessing() {
- DCHECK(thread_checker_.CalledOnValidThread());
- connector_.ResumeIncomingMethodCallProcessing();
- }
-
- // Sets this object to testing mode.
- // In testing mode:
- // - the object is more tolerant of unrecognized response messages;
- // - the connector continues working after seeing errors from its incoming
- // receiver.
- void EnableTestingMode();
-
- MessagePipeHandle handle() const { return connector_.handle(); }
-
- // Returns true if this Router has any pending callbacks.
- bool has_pending_responders() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- return !async_responders_.empty() || !sync_responses_.empty();
- }
-
- private:
- // Maps from the id of a response to the MessageReceiver that handles the
- // response.
- using AsyncResponderMap =
- std::map<uint64_t, std::unique_ptr<MessageReceiver>>;
-
- struct SyncResponseInfo {
- public:
- explicit SyncResponseInfo(bool* in_response_received);
- ~SyncResponseInfo();
-
- std::unique_ptr<Message> response;
-
- // Points to a stack-allocated variable.
- bool* response_received;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SyncResponseInfo);
- };
-
- using SyncResponseMap = std::map<uint64_t, std::unique_ptr<SyncResponseInfo>>;
-
- class HandleIncomingMessageThunk : public MessageReceiver {
- public:
- HandleIncomingMessageThunk(Router* router);
- ~HandleIncomingMessageThunk() override;
-
- // MessageReceiver implementation:
- bool Accept(Message* message) override;
-
- private:
- Router* router_;
- };
-
- bool HandleIncomingMessage(Message* message);
- void HandleQueuedMessages();
- bool HandleMessageInternal(Message* message);
-
- void OnConnectionError();
-
- HandleIncomingMessageThunk thunk_;
- FilterChain filters_;
- Connector connector_;
- MessageReceiverWithResponderStatus* incoming_receiver_;
- AsyncResponderMap async_responders_;
- SyncResponseMap sync_responses_;
- uint64_t next_request_id_;
- bool testing_mode_;
- std::queue<std::unique_ptr<Message>> pending_messages_;
- // Whether a task has been posted to trigger processing of
- // |pending_messages_|.
- bool pending_task_for_messages_;
- bool encountered_error_;
- base::Closure error_handler_;
- base::ThreadChecker thread_checker_;
- base::WeakPtrFactory<Router> weak_factory_;
-};
-
-} // namespace internal
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_
diff --git a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
index f54c3f7..c134507 100644
--- a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
+++ b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
@@ -4,69 +4,379 @@
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
+#include "base/bind.h"
#include "base/logging.h"
+#include "base/synchronization/lock.h"
#include "mojo/public/cpp/bindings/associated_group_controller.h"
+#include "mojo/public/cpp/bindings/lib/may_auto_lock.h"
namespace mojo {
+// ScopedInterfaceEndpointHandle::State ----------------------------------------
+
+// State could be called from multiple threads.
+class ScopedInterfaceEndpointHandle::State
+ : public base::RefCountedThreadSafe<State> {
+ public:
+ State() = default;
+
+ State(InterfaceId id,
+ scoped_refptr<AssociatedGroupController> group_controller)
+ : id_(id), group_controller_(group_controller) {}
+
+ void InitPendingState(scoped_refptr<State> peer) {
+ DCHECK(!lock_);
+ DCHECK(!pending_association_);
+
+ lock_.emplace();
+ pending_association_ = true;
+ peer_state_ = std::move(peer);
+ }
+
+ void Close(const base::Optional<DisconnectReason>& reason) {
+ scoped_refptr<AssociatedGroupController> cached_group_controller;
+ InterfaceId cached_id = kInvalidInterfaceId;
+ scoped_refptr<State> cached_peer_state;
+
+ {
+ internal::MayAutoLock locker(&lock_);
+
+ if (!association_event_handler_.is_null()) {
+ association_event_handler_.Reset();
+ runner_ = nullptr;
+ }
+
+ if (!pending_association_) {
+ if (IsValidInterfaceId(id_)) {
+ // Intentionally keep |group_controller_| unchanged.
+ // That is because the callback created by
+ // CreateGroupControllerGetter() could still be used after this point,
+ // potentially from another thread. We would like it to continue
+ // returning the same group controller.
+ //
+ // Imagine there is a ThreadSafeForwarder A:
+ // (1) On the IO thread, A's underlying associated interface pointer
+ // is closed.
+ // (2) On the proxy thread, the user makes a call on A to pass an
+ // associated request B_asso_req. The callback returned by
+ // CreateGroupControllerGetter() is used to associate B_asso_req.
+ // (3) On the proxy thread, the user immediately binds B_asso_ptr_info
+ // to B_asso_ptr and makes calls on it.
+ //
+ // If we reset |group_controller_| in step (1), step (2) won't be able
+ // to associate B_asso_req. Therefore, in step (3) B_asso_ptr won't be
+ // able to serialize associated endpoints or send message because it
+ // is still in "pending_association" state and doesn't have a group
+ // controller.
+ //
+ // We could "address" this issue by ignoring messages if there isn't a
+ // group controller. But the side effect is that we cannot detect
+ // programming errors of "using associated interface pointer before
+ // sending associated request".
+
+ cached_group_controller = group_controller_;
+ cached_id = id_;
+ id_ = kInvalidInterfaceId;
+ }
+ } else {
+ pending_association_ = false;
+ cached_peer_state = std::move(peer_state_);
+ }
+ }
+
+ if (cached_group_controller) {
+ cached_group_controller->CloseEndpointHandle(cached_id, reason);
+ } else if (cached_peer_state) {
+ cached_peer_state->OnPeerClosedBeforeAssociation(reason);
+ }
+ }
+
+ void SetAssociationEventHandler(AssociationEventCallback handler) {
+ internal::MayAutoLock locker(&lock_);
+
+ if (!pending_association_ && !IsValidInterfaceId(id_))
+ return;
+
+ association_event_handler_ = std::move(handler);
+ if (association_event_handler_.is_null()) {
+ runner_ = nullptr;
+ return;
+ }
+
+ runner_ = base::ThreadTaskRunnerHandle::Get();
+ if (!pending_association_) {
+ runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &ScopedInterfaceEndpointHandle::State::RunAssociationEventHandler,
+ this, runner_, ASSOCIATED));
+ } else if (!peer_state_) {
+ runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &ScopedInterfaceEndpointHandle::State::RunAssociationEventHandler,
+ this, runner_, PEER_CLOSED_BEFORE_ASSOCIATION));
+ }
+ }
+
+ bool NotifyAssociation(
+ InterfaceId id,
+ scoped_refptr<AssociatedGroupController> peer_group_controller) {
+ scoped_refptr<State> cached_peer_state;
+ {
+ internal::MayAutoLock locker(&lock_);
+
+ DCHECK(pending_association_);
+ pending_association_ = false;
+ cached_peer_state = std::move(peer_state_);
+ }
+
+ if (cached_peer_state) {
+ cached_peer_state->OnAssociated(id, std::move(peer_group_controller));
+ return true;
+ }
+ return false;
+ }
+
+ bool is_valid() const {
+ internal::MayAutoLock locker(&lock_);
+ return pending_association_ || IsValidInterfaceId(id_);
+ }
+
+ bool pending_association() const {
+ internal::MayAutoLock locker(&lock_);
+ return pending_association_;
+ }
+
+ InterfaceId id() const {
+ internal::MayAutoLock locker(&lock_);
+ return id_;
+ }
+
+ AssociatedGroupController* group_controller() const {
+ internal::MayAutoLock locker(&lock_);
+ return group_controller_.get();
+ }
+
+ const base::Optional<DisconnectReason>& disconnect_reason() const {
+ internal::MayAutoLock locker(&lock_);
+ return disconnect_reason_;
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<State>;
+
+ ~State() {
+ DCHECK(!pending_association_);
+ DCHECK(!IsValidInterfaceId(id_));
+ }
+
+ // Called by the peer, maybe from a different thread.
+ void OnAssociated(InterfaceId id,
+ scoped_refptr<AssociatedGroupController> group_controller) {
+ AssociationEventCallback handler;
+ {
+ internal::MayAutoLock locker(&lock_);
+
+ // There may be race between Close() of endpoint A and
+ // NotifyPeerAssociation() of endpoint A_peer on different threads.
+ // Therefore, it is possible that endpoint A has been closed but it
+ // still gets OnAssociated() call from its peer.
+ if (!pending_association_)
+ return;
+
+ pending_association_ = false;
+ peer_state_ = nullptr;
+ id_ = id;
+ group_controller_ = std::move(group_controller);
+
+ if (!association_event_handler_.is_null()) {
+ if (runner_->BelongsToCurrentThread()) {
+ handler = std::move(association_event_handler_);
+ runner_ = nullptr;
+ } else {
+ runner_->PostTask(FROM_HERE,
+ base::Bind(&ScopedInterfaceEndpointHandle::State::
+ RunAssociationEventHandler,
+ this, runner_, ASSOCIATED));
+ }
+ }
+ }
+
+ if (!handler.is_null())
+ std::move(handler).Run(ASSOCIATED);
+ }
+
+ // Called by the peer, maybe from a different thread.
+ void OnPeerClosedBeforeAssociation(
+ const base::Optional<DisconnectReason>& reason) {
+ AssociationEventCallback handler;
+ {
+ internal::MayAutoLock locker(&lock_);
+
+ // There may be race between Close()/NotifyPeerAssociation() of endpoint
+ // A and Close() of endpoint A_peer on different threads.
+ // Therefore, it is possible that endpoint A is not in pending association
+ // state but still gets OnPeerClosedBeforeAssociation() call from its
+ // peer.
+ if (!pending_association_)
+ return;
+
+ disconnect_reason_ = reason;
+ // NOTE: This handle itself is still pending.
+ peer_state_ = nullptr;
+
+ if (!association_event_handler_.is_null()) {
+ if (runner_->BelongsToCurrentThread()) {
+ handler = std::move(association_event_handler_);
+ runner_ = nullptr;
+ } else {
+ runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ScopedInterfaceEndpointHandle::State::
+ RunAssociationEventHandler,
+ this, runner_, PEER_CLOSED_BEFORE_ASSOCIATION));
+ }
+ }
+ }
+
+ if (!handler.is_null())
+ std::move(handler).Run(PEER_CLOSED_BEFORE_ASSOCIATION);
+ }
+
+ void RunAssociationEventHandler(
+ scoped_refptr<base::SingleThreadTaskRunner> posted_to_runner,
+ AssociationEvent event) {
+ AssociationEventCallback handler;
+
+ {
+ internal::MayAutoLock locker(&lock_);
+ if (posted_to_runner == runner_) {
+ runner_ = nullptr;
+ handler = std::move(association_event_handler_);
+ }
+ }
+
+ if (!handler.is_null())
+ std::move(handler).Run(event);
+ }
+
+ // Protects the following members if the handle is initially set to pending
+ // association.
+ mutable base::Optional<base::Lock> lock_;
+
+ bool pending_association_ = false;
+ base::Optional<DisconnectReason> disconnect_reason_;
+
+ scoped_refptr<State> peer_state_;
+
+ AssociationEventCallback association_event_handler_;
+ scoped_refptr<base::SingleThreadTaskRunner> runner_;
+
+ InterfaceId id_ = kInvalidInterfaceId;
+ scoped_refptr<AssociatedGroupController> group_controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(State);
+};
+
+// ScopedInterfaceEndpointHandle -----------------------------------------------
+
+// static
+void ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(
+ ScopedInterfaceEndpointHandle* handle0,
+ ScopedInterfaceEndpointHandle* handle1) {
+ ScopedInterfaceEndpointHandle result0;
+ ScopedInterfaceEndpointHandle result1;
+ result0.state_->InitPendingState(result1.state_);
+ result1.state_->InitPendingState(result0.state_);
+
+ *handle0 = std::move(result0);
+ *handle1 = std::move(result1);
+}
+
ScopedInterfaceEndpointHandle::ScopedInterfaceEndpointHandle()
- : ScopedInterfaceEndpointHandle(kInvalidInterfaceId, true, nullptr) {}
+ : state_(new State) {}
ScopedInterfaceEndpointHandle::ScopedInterfaceEndpointHandle(
ScopedInterfaceEndpointHandle&& other)
- : id_(other.id_), is_local_(other.is_local_) {
- group_controller_.swap(other.group_controller_);
- other.id_ = kInvalidInterfaceId;
+ : state_(new State) {
+ state_.swap(other.state_);
}
ScopedInterfaceEndpointHandle::~ScopedInterfaceEndpointHandle() {
- reset();
+ state_->Close(base::nullopt);
}
ScopedInterfaceEndpointHandle& ScopedInterfaceEndpointHandle::operator=(
ScopedInterfaceEndpointHandle&& other) {
reset();
- swap(other);
-
+ state_.swap(other.state_);
return *this;
}
-void ScopedInterfaceEndpointHandle::reset() {
- if (!IsValidInterfaceId(id_))
- return;
+bool ScopedInterfaceEndpointHandle::is_valid() const {
+ return state_->is_valid();
+}
+
+bool ScopedInterfaceEndpointHandle::pending_association() const {
+ return state_->pending_association();
+}
- group_controller_->CloseEndpointHandle(id_, is_local_);
+InterfaceId ScopedInterfaceEndpointHandle::id() const {
+ return state_->id();
+}
- id_ = kInvalidInterfaceId;
- is_local_ = true;
- group_controller_ = nullptr;
+AssociatedGroupController* ScopedInterfaceEndpointHandle::group_controller()
+ const {
+ return state_->group_controller();
}
-void ScopedInterfaceEndpointHandle::swap(ScopedInterfaceEndpointHandle& other) {
- using std::swap;
- swap(other.id_, id_);
- swap(other.is_local_, is_local_);
- swap(other.group_controller_, group_controller_);
+const base::Optional<DisconnectReason>&
+ScopedInterfaceEndpointHandle::disconnect_reason() const {
+ return state_->disconnect_reason();
}
-InterfaceId ScopedInterfaceEndpointHandle::release() {
- InterfaceId result = id_;
+void ScopedInterfaceEndpointHandle::SetAssociationEventHandler(
+ AssociationEventCallback handler) {
+ state_->SetAssociationEventHandler(std::move(handler));
+}
- id_ = kInvalidInterfaceId;
- is_local_ = true;
- group_controller_ = nullptr;
+void ScopedInterfaceEndpointHandle::reset() {
+ ResetInternal(base::nullopt);
+}
- return result;
+void ScopedInterfaceEndpointHandle::ResetWithReason(
+ uint32_t custom_reason,
+ const std::string& description) {
+ ResetInternal(DisconnectReason(custom_reason, description));
}
ScopedInterfaceEndpointHandle::ScopedInterfaceEndpointHandle(
InterfaceId id,
- bool is_local,
scoped_refptr<AssociatedGroupController> group_controller)
- : id_(id),
- is_local_(is_local),
- group_controller_(std::move(group_controller)) {
- DCHECK(!IsValidInterfaceId(id) || group_controller_);
+ : state_(new State(id, std::move(group_controller))) {
+ DCHECK(!IsValidInterfaceId(state_->id()) || state_->group_controller());
+}
+
+bool ScopedInterfaceEndpointHandle::NotifyAssociation(
+ InterfaceId id,
+ scoped_refptr<AssociatedGroupController> peer_group_controller) {
+ return state_->NotifyAssociation(id, peer_group_controller);
+}
+
+void ScopedInterfaceEndpointHandle::ResetInternal(
+ const base::Optional<DisconnectReason>& reason) {
+ scoped_refptr<State> new_state(new State);
+ state_->Close(reason);
+ state_.swap(new_state);
+}
+
+base::Callback<AssociatedGroupController*()>
+ScopedInterfaceEndpointHandle::CreateGroupControllerGetter() const {
+ // We allow this callback to be run on any thread. If this handle is created
+ // in non-pending state, we don't have a lock but it should still be safe
+ // because the group controller never changes.
+ return base::Bind(&State::group_controller, state_);
}
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/serialization.h b/mojo/public/cpp/bindings/lib/serialization.h
index 6d7dd8e..359b02b 100644
--- a/mojo/public/cpp/bindings/lib/serialization.h
+++ b/mojo/public/cpp/bindings/lib/serialization.h
@@ -8,19 +8,16 @@
#include <string.h>
#include "mojo/public/cpp/bindings/array_traits_carray.h"
-#include "mojo/public/cpp/bindings/array_traits_standard.h"
#include "mojo/public/cpp/bindings/array_traits_stl.h"
#include "mojo/public/cpp/bindings/lib/array_serialization.h"
-#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
+#include "mojo/public/cpp/bindings/lib/buffer.h"
#include "mojo/public/cpp/bindings/lib/handle_interface_serialization.h"
#include "mojo/public/cpp/bindings/lib/map_serialization.h"
#include "mojo/public/cpp/bindings/lib/native_enum_serialization.h"
#include "mojo/public/cpp/bindings/lib/native_struct_serialization.h"
#include "mojo/public/cpp/bindings/lib/string_serialization.h"
#include "mojo/public/cpp/bindings/lib/template_util.h"
-#include "mojo/public/cpp/bindings/map_traits_standard.h"
#include "mojo/public/cpp/bindings/map_traits_stl.h"
-#include "mojo/public/cpp/bindings/string_traits_standard.h"
#include "mojo/public/cpp/bindings/string_traits_stl.h"
#include "mojo/public/cpp/bindings/string_traits_string16.h"
#include "mojo/public/cpp/bindings/string_traits_string_piece.h"
@@ -44,7 +41,7 @@ DataArrayType StructSerializeImpl(UserType* input) {
void* result_buffer = &result.front();
// The serialization logic requires that the buffer is 8-byte aligned. If the
// result buffer is not properly aligned, we have to do an extra copy. In
- // practice, this should never happen for mojo::Array (backed by std::vector).
+ // practice, this should never happen for std::vector.
bool need_copy = !IsAligned(result_buffer);
if (need_copy) {
@@ -53,9 +50,9 @@ DataArrayType StructSerializeImpl(UserType* input) {
DCHECK(IsAligned(result_buffer));
}
- FixedBuffer buffer;
+ Buffer buffer;
buffer.Initialize(result_buffer, size);
- typename MojomType::Struct::Data_* data = nullptr;
+ typename MojomTypeTraits<MojomType>::Data* data = nullptr;
Serialize<MojomType>(*input, &buffer, &data, &context);
if (need_copy) {
@@ -70,13 +67,11 @@ template <typename MojomType, typename DataArrayType, typename UserType>
bool StructDeserializeImpl(const DataArrayType& input, UserType* output) {
static_assert(BelongsTo<MojomType, MojomTypeCategory::STRUCT>::value,
"Unexpected type.");
- using DataType = typename MojomType::Struct::Data_;
-
- if (input.is_null())
- return false;
+ using DataType = typename MojomTypeTraits<MojomType>::Data;
+ // TODO(sammc): Use DataArrayType::empty() once WTF::Vector::empty() exists.
void* input_buffer =
- input.empty()
+ input.size() == 0
? nullptr
: const_cast<void*>(reinterpret_cast<const void*>(&input.front()));
@@ -89,7 +84,7 @@ bool StructDeserializeImpl(const DataArrayType& input, UserType* output) {
memcpy(input_buffer, &input.front(), input.size());
}
- ValidationContext validation_context(input_buffer, input.size(), 0);
+ ValidationContext validation_context(input_buffer, input.size(), 0, 0);
bool result = false;
if (DataType::Validate(input_buffer, &validation_context)) {
auto data = reinterpret_cast<DataType*>(input_buffer);
diff --git a/mojo/public/cpp/bindings/lib/serialization_context.cc b/mojo/public/cpp/bindings/lib/serialization_context.cc
index 7fd80be..e2fd5c6 100644
--- a/mojo/public/cpp/bindings/lib/serialization_context.cc
+++ b/mojo/public/cpp/bindings/lib/serialization_context.cc
@@ -7,7 +7,6 @@
#include <limits>
#include "base/logging.h"
-#include "mojo/public/cpp/bindings/associated_group_controller.h"
#include "mojo/public/cpp/system/core.h"
namespace mojo {
@@ -50,10 +49,6 @@ void SerializedHandleVector::Swap(std::vector<mojo::Handle>* other) {
SerializationContext::SerializationContext() {}
-SerializationContext::SerializationContext(
- scoped_refptr<AssociatedGroupController> in_group_controller)
- : group_controller(std::move(in_group_controller)) {}
-
SerializationContext::~SerializationContext() {
DCHECK(!custom_contexts || custom_contexts->empty());
}
diff --git a/mojo/public/cpp/bindings/lib/serialization_context.h b/mojo/public/cpp/bindings/lib/serialization_context.h
index 64d2a1a..a34fe3d 100644
--- a/mojo/public/cpp/bindings/lib/serialization_context.h
+++ b/mojo/public/cpp/bindings/lib/serialization_context.h
@@ -12,18 +12,16 @@
#include <vector>
#include "base/macros.h"
-#include "base/memory/ref_counted.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
#include "mojo/public/cpp/system/handle.h"
namespace mojo {
-
-class AssociatedGroupController;
-
namespace internal {
// A container for handles during serialization/deserialization.
-class SerializedHandleVector {
+class MOJO_CPP_BINDINGS_EXPORT SerializedHandleVector {
public:
SerializedHandleVector();
~SerializedHandleVector();
@@ -54,21 +52,23 @@ class SerializedHandleVector {
};
// Context information for serialization/deserialization routines.
-struct SerializationContext {
+struct MOJO_CPP_BINDINGS_EXPORT SerializationContext {
SerializationContext();
- explicit SerializationContext(
- scoped_refptr<AssociatedGroupController> in_group_controller);
~SerializationContext();
- // Used to serialize/deserialize associated interface pointers and requests.
- scoped_refptr<AssociatedGroupController> group_controller;
-
// Opaque context pointers returned by StringTraits::SetUpContext().
std::unique_ptr<std::queue<void*>> custom_contexts;
// Stashes handles encoded in a message by index.
SerializedHandleVector handles;
+
+ // The number of ScopedInterfaceEndpointHandles that need to be serialized.
+ // It is calculated by PrepareToSerialize().
+ uint32_t associated_endpoint_count = 0;
+
+ // Stashes ScopedInterfaceEndpointHandles encoded in a message by index.
+ std::vector<ScopedInterfaceEndpointHandle> associated_endpoint_handles;
};
} // namespace internal
diff --git a/mojo/public/cpp/bindings/lib/serialization_forward.h b/mojo/public/cpp/bindings/lib/serialization_forward.h
index 5bed126..55c9982 100644
--- a/mojo/public/cpp/bindings/lib/serialization_forward.h
+++ b/mojo/public/cpp/bindings/lib/serialization_forward.h
@@ -12,6 +12,7 @@
#include "mojo/public/cpp/bindings/map_traits.h"
#include "mojo/public/cpp/bindings/string_traits.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "mojo/public/cpp/bindings/union_traits.h"
// This file is included by serialization implementation files to avoid circular
// includes.
diff --git a/mojo/public/cpp/bindings/lib/string_serialization.h b/mojo/public/cpp/bindings/lib/string_serialization.h
index 5e65891..6e0c758 100644
--- a/mojo/public/cpp/bindings/lib/string_serialization.h
+++ b/mojo/public/cpp/bindings/lib/string_serialization.h
@@ -11,14 +11,14 @@
#include "mojo/public/cpp/bindings/lib/array_internal.h"
#include "mojo/public/cpp/bindings/lib/serialization_forward.h"
#include "mojo/public/cpp/bindings/lib/serialization_util.h"
-#include "mojo/public/cpp/bindings/string.h"
+#include "mojo/public/cpp/bindings/string_data_view.h"
#include "mojo/public/cpp/bindings/string_traits.h"
namespace mojo {
namespace internal {
template <typename MaybeConstUserType>
-struct Serializer<String, MaybeConstUserType> {
+struct Serializer<StringDataView, MaybeConstUserType> {
using UserType = typename std::remove_const<MaybeConstUserType>::type;
using Traits = StringTraits<UserType>;
@@ -60,7 +60,7 @@ struct Serializer<String, MaybeConstUserType> {
SerializationContext* context) {
if (!input)
return CallSetToNullIfExists<Traits>(output);
- return Traits::Read(StringDataView(input), output);
+ return Traits::Read(StringDataView(input, context), output);
}
};
diff --git a/mojo/public/cpp/bindings/lib/string_traits_wtf.cc b/mojo/public/cpp/bindings/lib/string_traits_wtf.cc
index 19fa907..203f6f5 100644
--- a/mojo/public/cpp/bindings/lib/string_traits_wtf.cc
+++ b/mojo/public/cpp/bindings/lib/string_traits_wtf.cc
@@ -16,7 +16,7 @@ namespace {
struct UTF8AdaptorInfo {
explicit UTF8AdaptorInfo(const WTF::String& input) : utf8_adaptor(input) {
#if DCHECK_IS_ON()
- original_size_in_bytes = static_cast<size_t>(input.sizeInBytes());
+ original_size_in_bytes = input.charactersSizeInBytes();
#endif
}
@@ -34,8 +34,7 @@ UTF8AdaptorInfo* ToAdaptor(const WTF::String& input, void* context) {
UTF8AdaptorInfo* adaptor = static_cast<UTF8AdaptorInfo*>(context);
#if DCHECK_IS_ON()
- DCHECK_EQ(adaptor->original_size_in_bytes,
- static_cast<size_t>(input.sizeInBytes()));
+ DCHECK_EQ(adaptor->original_size_in_bytes, input.charactersSizeInBytes());
#endif
return adaptor;
}
diff --git a/mojo/public/cpp/bindings/lib/sync_call_restrictions.cc b/mojo/public/cpp/bindings/lib/sync_call_restrictions.cc
index 3d864af..585a8f0 100644
--- a/mojo/public/cpp/bindings/lib/sync_call_restrictions.cc
+++ b/mojo/public/cpp/bindings/lib/sync_call_restrictions.cc
@@ -6,6 +6,7 @@
#if ENABLE_SYNC_CALL_RESTRICTIONS
+#include "base/debug/leak_annotations.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/threading/thread_local.h"
@@ -37,7 +38,7 @@ class SyncCallSettings {
size_t scoped_allow_count_ = 0;
};
-base::LazyInstance<base::ThreadLocalPointer<SyncCallSettings>>
+base::LazyInstance<base::ThreadLocalPointer<SyncCallSettings>>::DestructorAtExit
g_sync_call_settings = LAZY_INSTANCE_INITIALIZER;
// static
@@ -45,6 +46,7 @@ SyncCallSettings* SyncCallSettings::current() {
SyncCallSettings* result = g_sync_call_settings.Pointer()->Get();
if (!result) {
result = new SyncCallSettings();
+ ANNOTATE_LEAKING_OBJECT_PTR(result);
DCHECK_EQ(result, g_sync_call_settings.Pointer()->Get());
}
return result;
diff --git a/mojo/public/cpp/bindings/lib/sync_handle_registry.cc b/mojo/public/cpp/bindings/lib/sync_handle_registry.cc
index f6372d9..5ae763b 100644
--- a/mojo/public/cpp/bindings/lib/sync_handle_registry.cc
+++ b/mojo/public/cpp/bindings/lib/sync_handle_registry.cc
@@ -13,7 +13,7 @@
namespace mojo {
namespace {
-base::LazyInstance<base::ThreadLocalPointer<SyncHandleRegistry>>
+base::LazyInstance<base::ThreadLocalPointer<SyncHandleRegistry>>::Leaky
g_current_sync_handle_watcher = LAZY_INSTANCE_INITIALIZER;
} // namespace
@@ -34,7 +34,7 @@ bool SyncHandleRegistry::RegisterHandle(const Handle& handle,
const HandleCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (ContainsKey(handles_, handle))
+ if (base::ContainsKey(handles_, handle))
return false;
MojoResult result = MojoAddHandle(wait_set_handle_.get().value(),
@@ -48,7 +48,7 @@ bool SyncHandleRegistry::RegisterHandle(const Handle& handle,
void SyncHandleRegistry::UnregisterHandle(const Handle& handle) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (!ContainsKey(handles_, handle))
+ if (!base::ContainsKey(handles_, handle))
return;
MojoResult result =
@@ -107,6 +107,19 @@ SyncHandleRegistry::SyncHandleRegistry() {
SyncHandleRegistry::~SyncHandleRegistry() {
DCHECK(thread_checker_.CalledOnValidThread());
+
+ // This object may be destructed after the thread local storage slot used by
+ // |g_current_sync_handle_watcher| is reset during thread shutdown.
+ // For example, another slot in the thread local storage holds a referrence to
+ // this object, and that slot is cleaned up after
+ // |g_current_sync_handle_watcher|.
+ if (!g_current_sync_handle_watcher.Pointer()->Get())
+ return;
+
+ // If this breaks, it is likely that the global variable is bulit into and
+ // accessed from multiple modules.
+ DCHECK_EQ(this, g_current_sync_handle_watcher.Pointer()->Get());
+
g_current_sync_handle_watcher.Pointer()->Set(nullptr);
}
diff --git a/mojo/public/cpp/bindings/lib/sync_handle_registry.h b/mojo/public/cpp/bindings/lib/sync_handle_registry.h
deleted file mode 100644
index d6b8c38..0000000
--- a/mojo/public/cpp/bindings/lib/sync_handle_registry.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_SYNC_HANDLE_REGISTRY_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_LIB_SYNC_HANDLE_REGISTRY_H_
-
-#include <unordered_map>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/threading/thread_checker.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace mojo {
-namespace internal {
-
-// SyncHandleRegistry is a thread-local storage to register handles that want to
-// be watched together.
-//
-// This class is not thread safe.
-class SyncHandleRegistry : public base::RefCounted<SyncHandleRegistry> {
- public:
- // Returns a thread-local object.
- static scoped_refptr<SyncHandleRegistry> current();
-
- using HandleCallback = base::Callback<void(MojoResult)>;
- bool RegisterHandle(const Handle& handle,
- MojoHandleSignals handle_signals,
- const HandleCallback& callback);
-
- void UnregisterHandle(const Handle& handle);
-
- // Waits on all the registered handles and runs callbacks synchronously for
- // those ready handles.
- // The method:
- // - returns true when any element of |should_stop| is set to true;
- // - returns false when any error occurs.
- bool WatchAllHandles(const bool* should_stop[], size_t count);
-
- private:
- friend class base::RefCounted<SyncHandleRegistry>;
-
- struct HandleHasher {
- size_t operator()(const Handle& handle) const {
- return std::hash<uint32_t>()(static_cast<uint32_t>(handle.value()));
- }
- };
- using HandleMap = std::unordered_map<Handle, HandleCallback, HandleHasher>;
-
- SyncHandleRegistry();
- ~SyncHandleRegistry();
-
- HandleMap handles_;
-
- ScopedHandle wait_set_handle_;
-
- base::ThreadChecker thread_checker_;
-
- DISALLOW_COPY_AND_ASSIGN(SyncHandleRegistry);
-};
-
-} // namespace internal
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_SYNC_HANDLE_REGISTRY_H_
diff --git a/mojo/public/cpp/bindings/lib/validation_context.cc b/mojo/public/cpp/bindings/lib/validation_context.cc
index a95e07e..ad0a364 100644
--- a/mojo/public/cpp/bindings/lib/validation_context.cc
+++ b/mojo/public/cpp/bindings/lib/validation_context.cc
@@ -4,13 +4,7 @@
#include "mojo/public/cpp/bindings/lib/validation_context.h"
-#include <stddef.h>
-#include <stdint.h>
-
#include "base/logging.h"
-#include "mojo/public/cpp/bindings/lib/serialization_util.h"
-#include "mojo/public/cpp/bindings/message.h"
-#include "mojo/public/cpp/system/handle.h"
namespace mojo {
namespace internal {
@@ -18,69 +12,39 @@ namespace internal {
ValidationContext::ValidationContext(const void* data,
size_t data_num_bytes,
size_t num_handles,
+ size_t num_associated_endpoint_handles,
Message* message,
- const base::StringPiece& description)
+ const base::StringPiece& description,
+ int stack_depth)
: message_(message),
description_(description),
data_begin_(reinterpret_cast<uintptr_t>(data)),
data_end_(data_begin_ + data_num_bytes),
handle_begin_(0),
- handle_end_(static_cast<uint32_t>(num_handles)) {
+ handle_end_(static_cast<uint32_t>(num_handles)),
+ associated_endpoint_handle_begin_(0),
+ associated_endpoint_handle_end_(
+ static_cast<uint32_t>(num_associated_endpoint_handles)),
+ stack_depth_(stack_depth) {
+ // Check whether the calculation of |data_end_| or static_cast from size_t to
+ // uint32_t causes overflow.
+ // They shouldn't happen but they do, set the corresponding range to empty.
if (data_end_ < data_begin_) {
- // The calculation of |data_end_| overflowed.
- // It shouldn't happen but if it does, set the range to empty so
- // IsValidRange() and ClaimMemory() always fail.
NOTREACHED();
data_end_ = data_begin_;
}
if (handle_end_ < num_handles) {
- // Assigning |num_handles| to |handle_end_| overflowed.
- // It shouldn't happen but if it does, set the handle index range to empty.
NOTREACHED();
handle_end_ = 0;
}
+ if (associated_endpoint_handle_end_ < num_associated_endpoint_handles) {
+ NOTREACHED();
+ associated_endpoint_handle_end_ = 0;
+ }
}
ValidationContext::~ValidationContext() {
}
-bool ValidationContext::ClaimMemory(const void* position, uint32_t num_bytes) {
- uintptr_t begin = reinterpret_cast<uintptr_t>(position);
- uintptr_t end = begin + num_bytes;
-
- if (!InternalIsValidRange(begin, end))
- return false;
-
- data_begin_ = end;
- return true;
-}
-
-bool ValidationContext::ClaimHandle(const Handle_Data& encoded_handle) {
- uint32_t index = encoded_handle.value;
- if (index == kEncodedInvalidHandleValue)
- return true;
-
- if (index < handle_begin_ || index >= handle_end_)
- return false;
-
- // |index| + 1 shouldn't overflow, because |index| is not the max value of
- // uint32_t (it is less than |handle_end_|).
- handle_begin_ = index + 1;
- return true;
-}
-
-bool ValidationContext::IsValidRange(const void* position,
- uint32_t num_bytes) const {
- uintptr_t begin = reinterpret_cast<uintptr_t>(position);
- uintptr_t end = begin + num_bytes;
-
- return InternalIsValidRange(begin, end);
-}
-
-bool ValidationContext::InternalIsValidRange(uintptr_t begin,
- uintptr_t end) const {
- return end > begin && begin >= data_begin_ && end <= data_end_;
-}
-
} // namespace internal
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/validation_context.h b/mojo/public/cpp/bindings/lib/validation_context.h
index 6045ca8..ed6c654 100644
--- a/mojo/public/cpp/bindings/lib/validation_context.h
+++ b/mojo/public/cpp/bindings/lib/validation_context.h
@@ -8,23 +8,28 @@
#include <stddef.h>
#include <stdint.h>
+#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/strings/string_piece.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+static const int kMaxRecursionDepth = 100;
+
namespace mojo {
-class Handle;
class Message;
namespace internal {
// ValidationContext is used when validating object sizes, pointers and handle
// indices in the payload of incoming messages.
-class ValidationContext {
+class MOJO_CPP_BINDINGS_EXPORT ValidationContext {
public:
// [data, data + data_num_bytes) specifies the initial valid memory range.
// [0, num_handles) specifies the initial valid range of handle indices.
+ // [0, num_associated_endpoint_handles) specifies the initial valid range of
+ // associated endpoint handle indices.
//
// If provided, |message| and |description| provide additional information
// to use when reporting validation errors. In addition if |message| is
@@ -33,8 +38,10 @@ class ValidationContext {
ValidationContext(const void* data,
size_t data_num_bytes,
size_t num_handles,
+ size_t num_associated_endpoint_handles,
Message* message = nullptr,
- const base::StringPiece& description = "");
+ const base::StringPiece& description = "",
+ int stack_depth = 0);
~ValidationContext();
@@ -43,24 +50,97 @@ class ValidationContext {
// the comments for IsValidRange().)
// On success, the valid memory range is shrinked to begin right after the end
// of the claimed range.
- bool ClaimMemory(const void* position, uint32_t num_bytes);
+ bool ClaimMemory(const void* position, uint32_t num_bytes) {
+ uintptr_t begin = reinterpret_cast<uintptr_t>(position);
+ uintptr_t end = begin + num_bytes;
+
+ if (!InternalIsValidRange(begin, end))
+ return false;
+
+ data_begin_ = end;
+ return true;
+ }
// Claims the specified encoded handle (which is basically a handle index).
// The method succeeds if:
// - |encoded_handle|'s value is |kEncodedInvalidHandleValue|.
// - the handle is contained inside the valid range of handle indices. In this
// case, the valid range is shinked to begin right after the claimed handle.
- bool ClaimHandle(const Handle_Data& encoded_handle);
+ bool ClaimHandle(const Handle_Data& encoded_handle) {
+ uint32_t index = encoded_handle.value;
+ if (index == kEncodedInvalidHandleValue)
+ return true;
+
+ if (index < handle_begin_ || index >= handle_end_)
+ return false;
+
+ // |index| + 1 shouldn't overflow, because |index| is not the max value of
+ // uint32_t (it is less than |handle_end_|).
+ handle_begin_ = index + 1;
+ return true;
+ }
+
+ // Claims the specified encoded associated endpoint handle.
+ // The method succeeds if:
+ // - |encoded_handle|'s value is |kEncodedInvalidHandleValue|.
+ // - the handle is contained inside the valid range of associated endpoint
+ // handle indices. In this case, the valid range is shinked to begin right
+ // after the claimed handle.
+ bool ClaimAssociatedEndpointHandle(
+ const AssociatedEndpointHandle_Data& encoded_handle) {
+ uint32_t index = encoded_handle.value;
+ if (index == kEncodedInvalidHandleValue)
+ return true;
+
+ if (index < associated_endpoint_handle_begin_ ||
+ index >= associated_endpoint_handle_end_)
+ return false;
+
+ // |index| + 1 shouldn't overflow, because |index| is not the max value of
+ // uint32_t (it is less than |associated_endpoint_handle_end_|).
+ associated_endpoint_handle_begin_ = index + 1;
+ return true;
+ }
// Returns true if the specified range is not empty, and the range is
// contained inside the valid memory range.
- bool IsValidRange(const void* position, uint32_t num_bytes) const;
+ bool IsValidRange(const void* position, uint32_t num_bytes) const {
+ uintptr_t begin = reinterpret_cast<uintptr_t>(position);
+ uintptr_t end = begin + num_bytes;
+
+ return InternalIsValidRange(begin, end);
+ }
+
+ // This object should be created on the stack once every time we recurse down
+ // into a subfield during validation to make sure we don't recurse too deep
+ // and blow the stack.
+ class ScopedDepthTracker {
+ public:
+ // |ctx| must outlive this object.
+ explicit ScopedDepthTracker(ValidationContext* ctx) : ctx_(ctx) {
+ ++ctx_->stack_depth_;
+ }
+
+ ~ScopedDepthTracker() { --ctx_->stack_depth_; }
+
+ private:
+ ValidationContext* ctx_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedDepthTracker);
+ };
+
+ // Returns true if the recursion depth limit has been reached.
+ bool ExceedsMaxDepth() WARN_UNUSED_RESULT {
+ return stack_depth_ > kMaxRecursionDepth;
+ }
Message* message() const { return message_; }
const base::StringPiece& description() const { return description_; }
private:
- bool InternalIsValidRange(uintptr_t begin, uintptr_t end) const;
+ bool InternalIsValidRange(uintptr_t begin, uintptr_t end) const {
+ return end > begin && begin >= data_begin_ && end <= data_end_;
+ }
Message* const message_;
const base::StringPiece description_;
@@ -73,6 +153,13 @@ class ValidationContext {
uint32_t handle_begin_;
uint32_t handle_end_;
+ // [associated_endpoint_handle_begin_, associated_endpoint_handle_end_) is the
+ // valid associated endpoint handle index range.
+ uint32_t associated_endpoint_handle_begin_;
+ uint32_t associated_endpoint_handle_end_;
+
+ int stack_depth_;
+
DISALLOW_COPY_AND_ASSIGN(ValidationContext);
};
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.cc b/mojo/public/cpp/bindings/lib/validation_errors.cc
index 90652de..904f5e4 100644
--- a/mojo/public/cpp/bindings/lib/validation_errors.cc
+++ b/mojo/public/cpp/bindings/lib/validation_errors.cc
@@ -14,6 +14,7 @@ namespace {
ValidationErrorObserverForTesting* g_validation_error_observer = nullptr;
SerializationWarningObserverForTesting* g_serialization_warning_observer =
nullptr;
+bool g_suppress_logging = false;
} // namespace
@@ -55,6 +56,8 @@ const char* ValidationErrorToString(ValidationError error) {
return "VALIDATION_ERROR_UNKNOWN_ENUM_VALUE";
case VALIDATION_ERROR_DESERIALIZATION_FAILED:
return "VALIDATION_ERROR_DESERIALIZATION_FAILED";
+ case VALIDATION_ERROR_MAX_RECURSION_DEPTH:
+ return "VALIDATION_ERROR_MAX_RECURSION_DEPTH";
}
return "Unknown error";
@@ -69,8 +72,10 @@ void ReportValidationError(ValidationContext* context,
}
if (description) {
- LOG(ERROR) << "Invalid message: " << ValidationErrorToString(error) << " ("
- << description << ")";
+ if (!g_suppress_logging) {
+ LOG(ERROR) << "Invalid message: " << ValidationErrorToString(error)
+ << " (" << description << ")";
+ }
if (context->message()) {
context->message()->NotifyBadMessage(
base::StringPrintf("Validation failed for %s [%s (%s)]",
@@ -78,7 +83,8 @@ void ReportValidationError(ValidationContext* context,
ValidationErrorToString(error), description));
}
} else {
- LOG(ERROR) << "Invalid message: " << ValidationErrorToString(error);
+ if (!g_suppress_logging)
+ LOG(ERROR) << "Invalid message: " << ValidationErrorToString(error);
if (context->message()) {
context->message()->NotifyBadMessage(
base::StringPrintf("Validation failed for %s [%s]",
@@ -88,6 +94,25 @@ void ReportValidationError(ValidationContext* context,
}
}
+void ReportValidationErrorForMessage(
+ mojo::Message* message,
+ ValidationError error,
+ const char* description) {
+ ValidationContext validation_context(nullptr, 0, 0, 0, message, description);
+ ReportValidationError(&validation_context, error);
+}
+
+ScopedSuppressValidationErrorLoggingForTests
+ ::ScopedSuppressValidationErrorLoggingForTests()
+ : was_suppressed_(g_suppress_logging) {
+ g_suppress_logging = true;
+}
+
+ScopedSuppressValidationErrorLoggingForTests
+ ::~ScopedSuppressValidationErrorLoggingForTests() {
+ g_suppress_logging = was_suppressed_;
+}
+
ValidationErrorObserverForTesting::ValidationErrorObserverForTesting(
const base::Closure& callback)
: last_error_(VALIDATION_ERROR_NONE), callback_(callback) {
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.h b/mojo/public/cpp/bindings/lib/validation_errors.h
index ec0aa27..122418d 100644
--- a/mojo/public/cpp/bindings/lib/validation_errors.h
+++ b/mojo/public/cpp/bindings/lib/validation_errors.h
@@ -8,9 +8,13 @@
#include "base/callback.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/lib/validation_context.h"
namespace mojo {
+
+class Message;
+
namespace internal {
enum ValidationError {
@@ -67,17 +71,41 @@ enum ValidationError {
// Message deserialization failure, for example due to rejection by custom
// validation logic.
VALIDATION_ERROR_DESERIALIZATION_FAILED,
+ // The message contains a too deeply nested value, for example a recursively
+ // defined field which runtime value is too large.
+ VALIDATION_ERROR_MAX_RECURSION_DEPTH,
};
-const char* ValidationErrorToString(ValidationError error);
+MOJO_CPP_BINDINGS_EXPORT const char* ValidationErrorToString(
+ ValidationError error);
+
+MOJO_CPP_BINDINGS_EXPORT void ReportValidationError(
+ ValidationContext* context,
+ ValidationError error,
+ const char* description = nullptr);
-void ReportValidationError(ValidationContext* context,
- ValidationError error,
- const char* description = nullptr);
+MOJO_CPP_BINDINGS_EXPORT void ReportValidationErrorForMessage(
+ mojo::Message* message,
+ ValidationError error,
+ const char* description = nullptr);
+
+// This class may be used by tests to suppress validation error logging. This is
+// not thread-safe and must only be instantiated on the main thread with no
+// other threads using Mojo bindings at the time of construction or destruction.
+class MOJO_CPP_BINDINGS_EXPORT ScopedSuppressValidationErrorLoggingForTests {
+ public:
+ ScopedSuppressValidationErrorLoggingForTests();
+ ~ScopedSuppressValidationErrorLoggingForTests();
+
+ private:
+ const bool was_suppressed_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedSuppressValidationErrorLoggingForTests);
+};
// Only used by validation tests and when there is only one thread doing message
// validation.
-class ValidationErrorObserverForTesting {
+class MOJO_CPP_BINDINGS_EXPORT ValidationErrorObserverForTesting {
public:
explicit ValidationErrorObserverForTesting(const base::Closure& callback);
~ValidationErrorObserverForTesting();
@@ -99,11 +127,11 @@ class ValidationErrorObserverForTesting {
//
// The function returns true if the error is recorded (by a
// SerializationWarningObserverForTesting object), false otherwise.
-bool ReportSerializationWarning(ValidationError error);
+MOJO_CPP_BINDINGS_EXPORT bool ReportSerializationWarning(ValidationError error);
// Only used by serialization tests and when there is only one thread doing
// message serialization.
-class SerializationWarningObserverForTesting {
+class MOJO_CPP_BINDINGS_EXPORT SerializationWarningObserverForTesting {
public:
SerializationWarningObserverForTesting();
~SerializationWarningObserverForTesting();
diff --git a/mojo/public/cpp/bindings/lib/validation_util.cc b/mojo/public/cpp/bindings/lib/validation_util.cc
index 9e63521..7614df5 100644
--- a/mojo/public/cpp/bindings/lib/validation_util.cc
+++ b/mojo/public/cpp/bindings/lib/validation_util.cc
@@ -16,16 +16,6 @@
namespace mojo {
namespace internal {
-bool ValidateEncodedPointer(const uint64_t* offset) {
- // - Make sure |*offset| is no more than 32-bits.
- // - Cast |offset| to uintptr_t so overflow behavior is well defined across
- // 32-bit and 64-bit systems.
- return *offset <= std::numeric_limits<uint32_t>::max() &&
- (reinterpret_cast<uintptr_t>(offset) +
- static_cast<uint32_t>(*offset) >=
- reinterpret_cast<uintptr_t>(offset));
-}
-
bool ValidateStructHeaderAndClaimMemory(const void* data,
ValidationContext* validation_context) {
if (!IsAligned(data)) {
@@ -56,20 +46,17 @@ bool ValidateStructHeaderAndClaimMemory(const void* data,
return true;
}
-bool ValidateUnionHeaderAndClaimMemory(const void* data,
- bool inlined,
- ValidationContext* validation_context) {
+bool ValidateNonInlinedUnionHeaderAndClaimMemory(
+ const void* data,
+ ValidationContext* validation_context) {
if (!IsAligned(data)) {
ReportValidationError(validation_context,
VALIDATION_ERROR_MISALIGNED_OBJECT);
return false;
}
- // If the union is inlined in another structure its memory was already
- // claimed.
- // This ONLY applies to the union itself, NOT anything which the union points
- // to.
- if (!inlined && !validation_context->ClaimMemory(data, kUnionDataSize)) {
+ if (!validation_context->ClaimMemory(data, kUnionDataSize) ||
+ *static_cast<const uint32_t*>(data) != kUnionDataSize) {
ReportValidationError(validation_context,
VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
return false;
@@ -113,41 +100,12 @@ bool ValidateMessageIsResponse(const Message* message,
return true;
}
-bool ValidateControlRequest(const Message* message,
- ValidationContext* validation_context) {
- switch (message->header()->name) {
- case kRunMessageId:
- return ValidateMessageIsRequestExpectingResponse(message,
- validation_context) &&
- ValidateMessagePayload<RunMessageParams_Data>(message,
- validation_context);
- case kRunOrClosePipeMessageId:
- return ValidateMessageIsRequestWithoutResponse(message,
- validation_context) &&
- ValidateMessagePayload<RunOrClosePipeMessageParams_Data>(
- message, validation_context);
- }
- return false;
-}
-
-bool ValidateControlResponse(const Message* message,
- ValidationContext* validation_context) {
- if (!ValidateMessageIsResponse(message, validation_context))
- return false;
- switch (message->header()->name) {
- case kRunMessageId:
- return ValidateMessagePayload<RunResponseMessageParams_Data>(
- message, validation_context);
- }
- return false;
-}
-
bool IsHandleOrInterfaceValid(const AssociatedInterface_Data& input) {
- return IsValidInterfaceId(input.interface_id);
+ return input.handle.is_valid();
}
-bool IsHandleOrInterfaceValid(const AssociatedInterfaceRequest_Data& input) {
- return IsValidInterfaceId(input.interface_id);
+bool IsHandleOrInterfaceValid(const AssociatedEndpointHandle_Data& input) {
+ return input.is_valid();
}
bool IsHandleOrInterfaceValid(const Interface_Data& input) {
@@ -172,7 +130,7 @@ bool ValidateHandleOrInterfaceNonNullable(
}
bool ValidateHandleOrInterfaceNonNullable(
- const AssociatedInterfaceRequest_Data& input,
+ const AssociatedEndpointHandle_Data& input,
const char* error_message,
ValidationContext* validation_context) {
if (IsHandleOrInterfaceValid(input))
@@ -212,7 +170,7 @@ bool ValidateHandleOrInterfaceNonNullable(
bool ValidateHandleOrInterface(const AssociatedInterface_Data& input,
ValidationContext* validation_context) {
- if (!IsMasterInterfaceId(input.interface_id))
+ if (validation_context->ClaimAssociatedEndpointHandle(input.handle))
return true;
ReportValidationError(validation_context,
@@ -220,9 +178,9 @@ bool ValidateHandleOrInterface(const AssociatedInterface_Data& input,
return false;
}
-bool ValidateHandleOrInterface(const AssociatedInterfaceRequest_Data& input,
+bool ValidateHandleOrInterface(const AssociatedEndpointHandle_Data& input,
ValidationContext* validation_context) {
- if (!IsMasterInterfaceId(input.interface_id))
+ if (validation_context->ClaimAssociatedEndpointHandle(input))
return true;
ReportValidationError(validation_context,
diff --git a/mojo/public/cpp/bindings/lib/validation_util.h b/mojo/public/cpp/bindings/lib/validation_util.h
index c883392..ea5a991 100644
--- a/mojo/public/cpp/bindings/lib/validation_util.h
+++ b/mojo/public/cpp/bindings/lib/validation_util.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
#include "mojo/public/cpp/bindings/lib/serialization_util.h"
#include "mojo/public/cpp/bindings/lib/validate_params.h"
@@ -19,7 +20,15 @@ namespace internal {
// Checks whether decoding the pointer will overflow and produce a pointer
// smaller than |offset|.
-bool ValidateEncodedPointer(const uint64_t* offset);
+inline bool ValidateEncodedPointer(const uint64_t* offset) {
+ // - Make sure |*offset| is no more than 32-bits.
+ // - Cast |offset| to uintptr_t so overflow behavior is well defined across
+ // 32-bit and 64-bit systems.
+ return *offset <= std::numeric_limits<uint32_t>::max() &&
+ (reinterpret_cast<uintptr_t>(offset) +
+ static_cast<uint32_t>(*offset) >=
+ reinterpret_cast<uintptr_t>(offset));
+}
template <typename T>
bool ValidatePointer(const Pointer<T>& input,
@@ -38,30 +47,32 @@ bool ValidatePointer(const Pointer<T>& input,
// |validation_context|. On success, the memory range is marked as occupied.
// Note: Does not verify |version| or that |num_bytes| is correct for the
// claimed version.
-bool ValidateStructHeaderAndClaimMemory(const void* data,
- ValidationContext* validation_context);
+MOJO_CPP_BINDINGS_EXPORT bool ValidateStructHeaderAndClaimMemory(
+ const void* data,
+ ValidationContext* validation_context);
// Validates that |data| contains a valid union header, in terms of alignment
-// and size. If not inlined, it checks that the memory range
-// [data, data + num_bytes) is not marked as occupied by other objects in
-// |validation_context|. On success, the memory range is marked as occupied.
-bool ValidateUnionHeaderAndClaimMemory(const void* data,
- bool inlined,
- ValidationContext* validation_context);
+// and size. It checks that the memory range [data, data + kUnionDataSize) is
+// not marked as occupied by other objects in |validation_context|. On success,
+// the memory range is marked as occupied.
+MOJO_CPP_BINDINGS_EXPORT bool ValidateNonInlinedUnionHeaderAndClaimMemory(
+ const void* data,
+ ValidationContext* validation_context);
// Validates that the message is a request which doesn't expect a response.
-bool ValidateMessageIsRequestWithoutResponse(
+MOJO_CPP_BINDINGS_EXPORT bool ValidateMessageIsRequestWithoutResponse(
const Message* message,
ValidationContext* validation_context);
// Validates that the message is a request expecting a response.
-bool ValidateMessageIsRequestExpectingResponse(
+MOJO_CPP_BINDINGS_EXPORT bool ValidateMessageIsRequestExpectingResponse(
const Message* message,
ValidationContext* validation_context);
// Validates that the message is a response.
-bool ValidateMessageIsResponse(const Message* message,
- ValidationContext* validation_context);
+MOJO_CPP_BINDINGS_EXPORT bool ValidateMessageIsResponse(
+ const Message* message,
+ ValidationContext* validation_context);
// Validates that the message payload is a valid struct of type ParamsType.
template <typename ParamsType>
@@ -70,13 +81,6 @@ bool ValidateMessagePayload(const Message* message,
return ParamsType::Validate(message->payload(), validation_context);
}
-// The following methods validate control messages defined in
-// interface_control_messages.mojom.
-bool ValidateControlRequest(const Message* message,
- ValidationContext* validation_context);
-bool ValidateControlResponse(const Message* message,
- ValidationContext* validation_context);
-
// The following Validate.*NonNullable() functions validate that the given
// |input| is not null/invalid.
template <typename T>
@@ -105,24 +109,28 @@ bool ValidateInlinedUnionNonNullable(const T& input,
return false;
}
-bool IsHandleOrInterfaceValid(const AssociatedInterface_Data& input);
-bool IsHandleOrInterfaceValid(const AssociatedInterfaceRequest_Data& input);
-bool IsHandleOrInterfaceValid(const Interface_Data& input);
-bool IsHandleOrInterfaceValid(const Handle_Data& input);
+MOJO_CPP_BINDINGS_EXPORT bool IsHandleOrInterfaceValid(
+ const AssociatedInterface_Data& input);
+MOJO_CPP_BINDINGS_EXPORT bool IsHandleOrInterfaceValid(
+ const AssociatedEndpointHandle_Data& input);
+MOJO_CPP_BINDINGS_EXPORT bool IsHandleOrInterfaceValid(
+ const Interface_Data& input);
+MOJO_CPP_BINDINGS_EXPORT bool IsHandleOrInterfaceValid(
+ const Handle_Data& input);
-bool ValidateHandleOrInterfaceNonNullable(
+MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterfaceNonNullable(
const AssociatedInterface_Data& input,
const char* error_message,
ValidationContext* validation_context);
-bool ValidateHandleOrInterfaceNonNullable(
- const AssociatedInterfaceRequest_Data& input,
+MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterfaceNonNullable(
+ const AssociatedEndpointHandle_Data& input,
const char* error_message,
ValidationContext* validation_context);
-bool ValidateHandleOrInterfaceNonNullable(
+MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterfaceNonNullable(
const Interface_Data& input,
const char* error_message,
ValidationContext* validation_context);
-bool ValidateHandleOrInterfaceNonNullable(
+MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterfaceNonNullable(
const Handle_Data& input,
const char* error_message,
ValidationContext* validation_context);
@@ -131,6 +139,12 @@ template <typename T>
bool ValidateContainer(const Pointer<T>& input,
ValidationContext* validation_context,
const ContainerValidateParams* validate_params) {
+ ValidationContext::ScopedDepthTracker depth_tracker(validation_context);
+ if (validation_context->ExceedsMaxDepth()) {
+ ReportValidationError(validation_context,
+ VALIDATION_ERROR_MAX_RECURSION_DEPTH);
+ return false;
+ }
return ValidatePointer(input, validation_context) &&
T::Validate(input.Get(), validation_context, validate_params);
}
@@ -138,6 +152,12 @@ bool ValidateContainer(const Pointer<T>& input,
template <typename T>
bool ValidateStruct(const Pointer<T>& input,
ValidationContext* validation_context) {
+ ValidationContext::ScopedDepthTracker depth_tracker(validation_context);
+ if (validation_context->ExceedsMaxDepth()) {
+ ReportValidationError(validation_context,
+ VALIDATION_ERROR_MAX_RECURSION_DEPTH);
+ return false;
+ }
return ValidatePointer(input, validation_context) &&
T::Validate(input.Get(), validation_context);
}
@@ -145,24 +165,40 @@ bool ValidateStruct(const Pointer<T>& input,
template <typename T>
bool ValidateInlinedUnion(const T& input,
ValidationContext* validation_context) {
+ ValidationContext::ScopedDepthTracker depth_tracker(validation_context);
+ if (validation_context->ExceedsMaxDepth()) {
+ ReportValidationError(validation_context,
+ VALIDATION_ERROR_MAX_RECURSION_DEPTH);
+ return false;
+ }
return T::Validate(&input, validation_context, true);
}
template <typename T>
bool ValidateNonInlinedUnion(const Pointer<T>& input,
ValidationContext* validation_context) {
+ ValidationContext::ScopedDepthTracker depth_tracker(validation_context);
+ if (validation_context->ExceedsMaxDepth()) {
+ ReportValidationError(validation_context,
+ VALIDATION_ERROR_MAX_RECURSION_DEPTH);
+ return false;
+ }
return ValidatePointer(input, validation_context) &&
T::Validate(input.Get(), validation_context, false);
}
-bool ValidateHandleOrInterface(const AssociatedInterface_Data& input,
- ValidationContext* validation_context);
-bool ValidateHandleOrInterface(const AssociatedInterfaceRequest_Data& input,
- ValidationContext* validation_context);
-bool ValidateHandleOrInterface(const Interface_Data& input,
- ValidationContext* validation_context);
-bool ValidateHandleOrInterface(const Handle_Data& input,
- ValidationContext* validation_context);
+MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterface(
+ const AssociatedInterface_Data& input,
+ ValidationContext* validation_context);
+MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterface(
+ const AssociatedEndpointHandle_Data& input,
+ ValidationContext* validation_context);
+MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterface(
+ const Interface_Data& input,
+ ValidationContext* validation_context);
+MOJO_CPP_BINDINGS_EXPORT bool ValidateHandleOrInterface(
+ const Handle_Data& input,
+ ValidationContext* validation_context);
} // namespace internal
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h b/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h
index edbf27b..cb24bc4 100644
--- a/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h
+++ b/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h
@@ -7,14 +7,14 @@
#include <type_traits>
-#include "mojo/public/cpp/bindings/lib/clone_equals_util.h"
+#include "mojo/public/cpp/bindings/clone_traits.h"
+#include "mojo/public/cpp/bindings/lib/equals_traits.h"
#include "third_party/WebKit/Source/wtf/HashMap.h"
#include "third_party/WebKit/Source/wtf/Optional.h"
#include "third_party/WebKit/Source/wtf/Vector.h"
#include "third_party/WebKit/Source/wtf/text/WTFString.h"
namespace mojo {
-namespace internal {
template <typename T>
struct CloneTraits<WTF::Vector<T>, false> {
@@ -22,7 +22,7 @@ struct CloneTraits<WTF::Vector<T>, false> {
WTF::Vector<T> result;
result.reserveCapacity(input.size());
for (const auto& element : input)
- result.append(internal::Clone(element));
+ result.push_back(mojo::Clone(element));
return result;
}
@@ -34,11 +34,13 @@ struct CloneTraits<WTF::HashMap<K, V>, false> {
WTF::HashMap<K, V> result;
auto input_end = input.end();
for (auto it = input.begin(); it != input_end; ++it)
- result.add(internal::Clone(it->key), internal::Clone(it->value));
+ result.add(mojo::Clone(it->key), mojo::Clone(it->value));
return result;
}
};
+namespace internal {
+
template <typename T>
struct EqualsTraits<WTF::Vector<T>, false> {
static bool Equals(const WTF::Vector<T>& a, const WTF::Vector<T>& b) {
diff --git a/mojo/public/cpp/bindings/lib/wtf_serialization.h b/mojo/public/cpp/bindings/lib/wtf_serialization.h
index 132e19c..0f112b9 100644
--- a/mojo/public/cpp/bindings/lib/wtf_serialization.h
+++ b/mojo/public/cpp/bindings/lib/wtf_serialization.h
@@ -5,9 +5,7 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_SERIALIZATION_H_
#define MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_SERIALIZATION_H_
-#include "mojo/public/cpp/bindings/array_traits_wtf.h"
#include "mojo/public/cpp/bindings/array_traits_wtf_vector.h"
-#include "mojo/public/cpp/bindings/map_traits_wtf.h"
#include "mojo/public/cpp/bindings/map_traits_wtf_hash_map.h"
#include "mojo/public/cpp/bindings/string_traits_wtf.h"
diff --git a/mojo/public/cpp/bindings/map.h b/mojo/public/cpp/bindings/map.h
index d4c7952..c1ba075 100644
--- a/mojo/public/cpp/bindings/map.h
+++ b/mojo/public/cpp/bindings/map.h
@@ -5,299 +5,37 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_MAP_H_
#define MOJO_PUBLIC_CPP_BINDINGS_MAP_H_
-#include <stddef.h>
#include <map>
#include <unordered_map>
#include <utility>
-#include "base/logging.h"
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/array.h"
-#include "mojo/public/cpp/bindings/lib/map_data_internal.h"
-#include "mojo/public/cpp/bindings/lib/template_util.h"
-#include "mojo/public/cpp/bindings/type_converter.h"
-
namespace mojo {
-// A move-only map that can handle move-only values. Map has the following
-// characteristics:
-// - The map itself can be null, and this is distinct from empty.
-// - Keys must not be move-only.
-// - The Key-type's "<" operator is used to sort the entries, and also is
-// used to determine equality of the key values.
-// - There can only be one entry per unique key.
-// - Values of move-only types will be moved into the Map when they are added
-// using the insert() method.
-template <typename K, typename V>
-class Map {
- public:
- using Key = K;
- using Value = V;
-
- // Map keys cannot be move only classes.
- static_assert(!internal::IsMoveOnlyType<Key>::value,
- "Map keys cannot be move only types.");
-
- using Iterator = typename std::map<Key, Value>::iterator;
- using ConstIterator = typename std::map<Key, Value>::const_iterator;
-
- // Constructs an empty map.
- Map() : is_null_(false) {}
- // Constructs a null map.
- Map(std::nullptr_t null_pointer) : is_null_(true) {}
-
- // Constructs a non-null Map containing the specified |keys| mapped to the
- // corresponding |values|.
- Map(mojo::Array<Key> keys, mojo::Array<Value> values) : is_null_(false) {
- DCHECK(keys.size() == values.size());
- for (size_t i = 0; i < keys.size(); ++i)
- map_.insert(std::make_pair(keys[i], std::move(values[i])));
- }
-
- ~Map() {}
-
- Map(std::map<Key, Value>&& other) : map_(std::move(other)), is_null_(false) {}
- Map(Map&& other) : is_null_(true) { Take(&other); }
-
- Map& operator=(std::map<Key, Value>&& other) {
- is_null_ = false;
- map_ = std::move(other);
- return *this;
- }
- Map& operator=(Map&& other) {
- Take(&other);
- return *this;
- }
-
- Map& operator=(std::nullptr_t null_pointer) {
- is_null_ = true;
- map_.clear();
- return *this;
- }
-
- // Copies the contents of some other type of map into a new Map using a
- // TypeConverter. A TypeConverter for std::map to Map is defined below.
- template <typename U>
- static Map From(const U& other) {
- return TypeConverter<Map, U>::Convert(other);
- }
-
- // Copies the contents of the Map into some other type of map. A TypeConverter
- // for Map to std::map is defined below.
- template <typename U>
- U To() const {
- return TypeConverter<U, Map>::Convert(*this);
- }
-
- // Indicates whether the map is null (which is distinct from empty).
- bool is_null() const { return is_null_; }
-
- // Indicates whether the map is empty (which is distinct from null).
- bool empty() const { return map_.empty() && !is_null_; }
-
- // Indicates the number of keys in the map, which will be zero if the map is
- // null.
- size_t size() const { return map_.size(); }
-
- // Inserts a key-value pair into the map. Like std::map, this does not insert
- // |value| if |key| is already a member of the map.
- void insert(const Key& key, const Value& value) {
- is_null_ = false;
- map_.insert(std::make_pair(key, value));
- }
- void insert(const Key& key, Value&& value) {
- is_null_ = false;
- map_.insert(std::make_pair(key, std::move(value)));
- }
-
- // Returns a reference to the value associated with the specified key,
- // crashing the process if the key is not present in the map.
- Value& at(const Key& key) { return map_.at(key); }
- const Value& at(const Key& key) const { return map_.at(key); }
-
- // Returns a reference to the value associated with the specified key,
- // creating a new entry if the key is not already present in the map. A
- // newly-created value will be value-initialized (meaning that it will be
- // initialized by the default constructor of the value type, if any, or else
- // will be zero-initialized).
- Value& operator[](const Key& key) {
- is_null_ = false;
- return map_[key];
- }
-
- // Sets the map to empty (even if previously it was null).
- void SetToEmpty() {
- is_null_ = false;
- map_.clear();
- }
-
- // Returns a const reference to the std::map managed by this class. If this
- // object is null, the return value will be an empty map.
- const std::map<Key, Value>& storage() const { return map_; }
-
- // Passes the underlying storage and resets this map to null.
- std::map<Key, Value> PassStorage() {
- is_null_ = true;
- return std::move(map_);
- }
-
- operator const std::map<Key, Value>&() const { return map_; }
-
- // Swaps the contents of this Map with another Map of the same type (including
- // nullness).
- void Swap(Map<Key, Value>* other) {
- std::swap(is_null_, other->is_null_);
- map_.swap(other->map_);
- }
-
- // Swaps the contents of this Map with an std::map containing keys and values
- // of the same type. Since std::map cannot represent the null state, the
- // std::map will be empty if Map is null. The Map will always be left in a
- // non-null state.
- void Swap(std::map<Key, Value>* other) {
- is_null_ = false;
- map_.swap(*other);
- }
-
- // Removes all contents from the Map and places them into parallel key/value
- // arrays. Each key will be copied from the source to the destination, and
- // values will be copied unless their type is designated move-only, in which
- // case they will be moved. Either way, the Map will be left in a null state.
- void DecomposeMapTo(mojo::Array<Key>* keys, mojo::Array<Value>* values) {
- std::vector<Key> key_vector;
- key_vector.reserve(map_.size());
- std::vector<Value> value_vector;
- value_vector.reserve(map_.size());
-
- for (auto& entry : map_) {
- key_vector.push_back(entry.first);
- value_vector.push_back(std::move(entry.second));
- }
-
- map_.clear();
- is_null_ = true;
-
- keys->Swap(&key_vector);
- values->Swap(&value_vector);
- }
-
- // Returns a new Map that contains a copy of the contents of this map. If the
- // key/value type defines a Clone() method, it will be used; otherwise copy
- // constructor/assignment will be used.
- //
- // Please note that calling this method will fail compilation if the key/value
- // type cannot be cloned (which usually means that it is a Mojo handle type or
- // a type containing Mojo handles).
- Map Clone() const {
- Map result;
- result.is_null_ = is_null_;
- for (auto it = map_.begin(); it != map_.end(); ++it) {
- result.map_.insert(std::make_pair(internal::Clone(it->first),
- internal::Clone(it->second)));
- }
- return result;
- }
-
- // Indicates whether the contents of this map are equal to those of another
- // Map (including nullness). If the key/value type defines an Equals() method,
- // it will be used; otherwise == operator will be used.
- bool Equals(const Map& other) const {
- if (is_null() != other.is_null())
- return false;
- if (size() != other.size())
- return false;
- auto i = begin();
- auto j = other.begin();
- while (i != end()) {
- if (!internal::Equals(i->first, j->first))
- return false;
- if (!internal::Equals(i->second, j->second))
- return false;
- ++i;
- ++j;
- }
- return true;
- }
-
- // Provide read-only iteration over map members in a way similar to STL
- // collections.
- ConstIterator begin() const { return map_.begin(); }
- Iterator begin() { return map_.begin(); }
-
- ConstIterator end() const { return map_.end(); }
- Iterator end() { return map_.end(); }
-
- // Returns the iterator pointing to the entry for |key|, if present, or else
- // returns end().
- ConstIterator find(const Key& key) const { return map_.find(key); }
- Iterator find(const Key& key) { return map_.find(key); }
-
- private:
- typedef std::map<Key, Value> Map::*Testable;
-
- public:
- // The Map may be used in boolean expressions to determine if it is non-null,
- // but is not implicitly convertible to an actual bool value (which would be
- // dangerous).
- operator Testable() const { return is_null_ ? 0 : &Map::map_; }
-
- private:
- // Forbid the == and != operators explicitly, otherwise Map will be converted
- // to Testable to do == or != comparison.
- template <typename T, typename U>
- bool operator==(const Map<T, U>& other) const = delete;
- template <typename T, typename U>
- bool operator!=(const Map<T, U>& other) const = delete;
-
- void Take(Map* other) {
- operator=(nullptr);
- Swap(other);
- }
-
- std::map<Key, Value> map_;
- bool is_null_;
-
- DISALLOW_COPY_AND_ASSIGN(Map);
-};
-
-// Copies the contents of an std::map to a new Map, optionally changing the
-// types of the keys and values along the way using TypeConverter.
-template <typename MojoKey,
- typename MojoValue,
- typename STLKey,
- typename STLValue>
-struct TypeConverter<Map<MojoKey, MojoValue>, std::map<STLKey, STLValue>> {
- static Map<MojoKey, MojoValue> Convert(
- const std::map<STLKey, STLValue>& input) {
- Map<MojoKey, MojoValue> result;
- for (auto& pair : input) {
- result.insert(TypeConverter<MojoKey, STLKey>::Convert(pair.first),
- TypeConverter<MojoValue, STLValue>::Convert(pair.second));
- }
- return result;
- }
-};
-
-// Copies the contents of a Map to an std::map, optionally changing the types of
-// the keys and values along the way using TypeConverter.
-template <typename MojoKey,
- typename MojoValue,
- typename STLKey,
- typename STLValue>
-struct TypeConverter<std::map<STLKey, STLValue>, Map<MojoKey, MojoValue>> {
- static std::map<STLKey, STLValue> Convert(
- const Map<MojoKey, MojoValue>& input) {
- std::map<STLKey, STLValue> result;
- if (!input.is_null()) {
- for (auto it = input.begin(); it != input.end(); ++it) {
- result.insert(std::make_pair(
- TypeConverter<STLKey, MojoKey>::Convert(it->first),
- TypeConverter<STLValue, MojoValue>::Convert(it->second)));
- }
- }
- return result;
- }
-};
+// TODO(yzshen): These conversion functions should be removed and callsites
+// should be revisited and changed to use the same map type.
+template <typename Key, typename Value>
+std::unordered_map<Key, Value> MapToUnorderedMap(
+ const std::map<Key, Value>& input) {
+ return std::unordered_map<Key, Value>(input.begin(), input.end());
+}
+
+template <typename Key, typename Value>
+std::unordered_map<Key, Value> MapToUnorderedMap(std::map<Key, Value>&& input) {
+ return std::unordered_map<Key, Value>(std::make_move_iterator(input.begin()),
+ std::make_move_iterator(input.end()));
+}
+
+template <typename Key, typename Value>
+std::map<Key, Value> UnorderedMapToMap(
+ const std::unordered_map<Key, Value>& input) {
+ return std::map<Key, Value>(input.begin(), input.end());
+}
+
+template <typename Key, typename Value>
+std::map<Key, Value> UnorderedMapToMap(std::unordered_map<Key, Value>&& input) {
+ return std::map<Key, Value>(std::make_move_iterator(input.begin()),
+ std::make_move_iterator(input.end()));
+}
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/map_data_view.h b/mojo/public/cpp/bindings/map_data_view.h
new file mode 100644
index 0000000..a65bb9e
--- /dev/null
+++ b/mojo/public/cpp/bindings/map_data_view.h
@@ -0,0 +1,63 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_MAP_DATA_VIEW_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_MAP_DATA_VIEW_H_
+
+#include "base/logging.h"
+#include "mojo/public/cpp/bindings/array_data_view.h"
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/map_data_internal.h"
+#include "mojo/public/cpp/bindings/lib/serialization_context.h"
+#include "mojo/public/cpp/bindings/lib/serialization_forward.h"
+
+namespace mojo {
+
+template <typename K, typename V>
+class MapDataView {
+ public:
+ using Data_ = typename internal::MojomTypeTraits<MapDataView<K, V>>::Data;
+
+ MapDataView() {}
+
+ MapDataView(Data_* data, internal::SerializationContext* context)
+ : keys_(data ? data->keys.Get() : nullptr, context),
+ values_(data ? data->values.Get() : nullptr, context) {}
+
+ bool is_null() const {
+ DCHECK_EQ(keys_.is_null(), values_.is_null());
+ return keys_.is_null();
+ }
+
+ size_t size() const {
+ DCHECK_EQ(keys_.size(), values_.size());
+ return keys_.size();
+ }
+
+ ArrayDataView<K>& keys() { return keys_; }
+ const ArrayDataView<K>& keys() const { return keys_; }
+
+ template <typename U>
+ bool ReadKeys(U* output) {
+ return internal::Deserialize<ArrayDataView<K>>(keys_.data_, output,
+ keys_.context_);
+ }
+
+ ArrayDataView<V>& values() { return values_; }
+ const ArrayDataView<V>& values() const { return values_; }
+
+ template <typename U>
+ bool ReadValues(U* output) {
+ return internal::Deserialize<ArrayDataView<V>>(values_.data_, output,
+ values_.context_);
+ }
+
+ private:
+ ArrayDataView<K> keys_;
+ ArrayDataView<V> values_;
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_MAP_DATA_VIEW_H_
diff --git a/mojo/public/cpp/bindings/map_traits.h b/mojo/public/cpp/bindings/map_traits.h
index 01dd66d..5c0d8b2 100644
--- a/mojo/public/cpp/bindings/map_traits.h
+++ b/mojo/public/cpp/bindings/map_traits.h
@@ -37,13 +37,13 @@ namespace mojo {
// static const V& GetValue(CustomConstIterator& iterator);
//
// // Returning false results in deserialization failure and causes the
-// // message pipe receiving it to be disconnected.
+// // message pipe receiving it to be disconnected. |IK| and |IV| are
+// // separate input key/value template parameters that allows for the
+// // the key/value types to be forwarded.
+// template <typename IK, typename IV>
// static bool Insert(CustomMap<K, V>& input,
-// const K& key,
-// V&& value);
-// static bool Insert(CustomMap<K, V>& input,
-// const K& key,
-// const V& value);
+// IK&& key,
+// IV&& value);
//
// static void SetToEmpty(CustomMap<K, V>* output);
// };
diff --git a/mojo/public/cpp/bindings/map_traits_standard.h b/mojo/public/cpp/bindings/map_traits_standard.h
deleted file mode 100644
index 0c76890..0000000
--- a/mojo/public/cpp/bindings/map_traits_standard.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_MAP_TRAITS_STANDARD_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_MAP_TRAITS_STANDARD_H_
-
-#include "mojo/public/cpp/bindings/map.h"
-#include "mojo/public/cpp/bindings/map_traits.h"
-
-namespace mojo {
-
-template <typename K, typename V>
-struct MapTraits<Map<K, V>> {
- using Key = K;
- using Value = V;
- using Iterator = typename Map<K, V>::Iterator;
- using ConstIterator = typename Map<K, V>::ConstIterator;
-
- static bool IsNull(const Map<K, V>& input) { return input.is_null(); }
- static void SetToNull(Map<K, V>* output) { *output = nullptr; }
-
- static size_t GetSize(const Map<K, V>& input) { return input.size(); }
-
- static ConstIterator GetBegin(const Map<K, V>& input) {
- return input.begin();
- }
- static Iterator GetBegin(Map<K, V>& input) { return input.begin(); }
-
- static void AdvanceIterator(ConstIterator& iterator) { iterator++; }
- static void AdvanceIterator(Iterator& iterator) { iterator++; }
-
- static const K& GetKey(Iterator& iterator) { return iterator->first; }
- static const K& GetKey(ConstIterator& iterator) { return iterator->first; }
-
- static V& GetValue(Iterator& iterator) { return iterator->second; }
- static const V& GetValue(ConstIterator& iterator) { return iterator->second; }
-
- static bool Insert(Map<K, V>& input, const K& key, V&& value) {
- input.insert(key, std::forward<V>(value));
- return true;
- }
- static bool Insert(Map<K, V>& input, const K& key, const V& value) {
- input.insert(key, value);
- return true;
- }
-
- static void SetToEmpty(Map<K, V>* output) { output->SetToEmpty(); }
-};
-
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_MAP_TRAITS_STANDARD_H_
diff --git a/mojo/public/cpp/bindings/map_traits_stl.h b/mojo/public/cpp/bindings/map_traits_stl.h
index ff79a20..83a4399 100644
--- a/mojo/public/cpp/bindings/map_traits_stl.h
+++ b/mojo/public/cpp/bindings/map_traits_stl.h
@@ -94,14 +94,10 @@ struct MapTraits<std::unordered_map<K, V>> {
static V& GetValue(Iterator& iterator) { return iterator->second; }
static const V& GetValue(ConstIterator& iterator) { return iterator->second; }
- static bool Insert(std::unordered_map<K, V>& input, const K& key, V&& value) {
- input.insert(std::make_pair(key, std::forward<V>(value)));
- return true;
- }
- static bool Insert(std::unordered_map<K, V>& input,
- const K& key,
- const V& value) {
- input.insert(std::make_pair(key, value));
+ template <typename IK, typename IV>
+ static bool Insert(std::unordered_map<K, V>& input, IK&& key, IV&& value) {
+ input.insert(
+ std::make_pair(std::forward<IK>(key), std::forward<IV>(value)));
return true;
}
diff --git a/mojo/public/cpp/bindings/map_traits_wtf.h b/mojo/public/cpp/bindings/map_traits_wtf.h
deleted file mode 100644
index 805e4c9..0000000
--- a/mojo/public/cpp/bindings/map_traits_wtf.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_MAP_TRAITS_WTF_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_MAP_TRAITS_WTF_H_
-
-#include "base/logging.h"
-#include "mojo/public/cpp/bindings/map_traits.h"
-#include "mojo/public/cpp/bindings/wtf_map.h"
-
-namespace mojo {
-
-template <typename K, typename V>
-struct MapTraits<WTFMap<K, V>> {
- using Key = K;
- using Value = V;
- using Iterator = typename WTFMap<K, V>::Iterator;
- using ConstIterator = typename WTFMap<K, V>::ConstIterator;
-
- static bool IsNull(const WTFMap<K, V>& input) { return input.is_null(); }
- static void SetToNull(WTFMap<K, V>* output) { *output = nullptr; }
-
- static size_t GetSize(const WTFMap<K, V>& input) { return input.size(); }
-
- static ConstIterator GetBegin(const WTFMap<K, V>& input) {
- return input.begin();
- }
- static Iterator GetBegin(WTFMap<K, V>& input) { return input.begin(); }
-
- static void AdvanceIterator(ConstIterator& iterator) { ++iterator; }
- static void AdvanceIterator(Iterator& iterator) { ++iterator; }
-
- static const K& GetKey(Iterator& iterator) { return iterator->key; }
- static const K& GetKey(ConstIterator& iterator) { return iterator->key; }
-
- static V& GetValue(Iterator& iterator) { return iterator->value; }
- static const V& GetValue(ConstIterator& iterator) { return iterator->value; }
-
- static bool Insert(WTFMap<K, V>& input, const K& key, V&& value) {
- if (!WTFMap<K, V>::IsValidKey(key)) {
- LOG(ERROR) << "The key value is disallowed by WTF::HashMap: " << key;
- return false;
- }
- input.insert(key, std::forward<V>(value));
- return true;
- }
- static bool Insert(WTFMap<K, V>& input, const K& key, const V& value) {
- if (!WTFMap<K, V>::IsValidKey(key)) {
- LOG(ERROR) << "The key value is disallowed by WTF::HashMap: " << key;
- return false;
- }
- input.insert(key, value);
- return true;
- }
-
- static void SetToEmpty(WTFMap<K, V>* output) { output->SetToEmpty(); }
-};
-
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_MAP_TRAITS_WTF_H_
diff --git a/mojo/public/cpp/bindings/map_traits_wtf_hash_map.h b/mojo/public/cpp/bindings/map_traits_wtf_hash_map.h
index 4392201..dd68b36 100644
--- a/mojo/public/cpp/bindings/map_traits_wtf_hash_map.h
+++ b/mojo/public/cpp/bindings/map_traits_wtf_hash_map.h
@@ -46,20 +46,13 @@ struct MapTraits<WTF::HashMap<K, V>> {
static V& GetValue(Iterator& iterator) { return iterator->value; }
static const V& GetValue(ConstIterator& iterator) { return iterator->value; }
- static bool Insert(WTF::HashMap<K, V>& input, const K& key, V&& value) {
+ template <typename IK, typename IV>
+ static bool Insert(WTF::HashMap<K, V>& input, IK&& key, IV&& value) {
if (!WTF::HashMap<K, V>::isValidKey(key)) {
- LOG(ERROR) << "The key value is disallowed by WTF::HashMap: " << key;
+ LOG(ERROR) << "The key value is disallowed by WTF::HashMap";
return false;
}
- input.add(key, std::forward<V>(value));
- return true;
- }
- static bool Insert(WTF::HashMap<K, V>& input, const K& key, const V& value) {
- if (!WTF::HashMap<K, V>::isValidKey(key)) {
- LOG(ERROR) << "The key value is disallowed by WTF::HashMap: " << key;
- return false;
- }
- input.add(key, value);
+ input.insert(std::forward<IK>(key), std::forward<IV>(value));
return true;
}
diff --git a/mojo/public/cpp/bindings/message.h b/mojo/public/cpp/bindings/message.h
index e758432..65d6cec 100644
--- a/mojo/public/cpp/bindings/message.h
+++ b/mojo/public/cpp/bindings/message.h
@@ -13,26 +13,46 @@
#include <string>
#include <vector>
+#include "base/callback.h"
+#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/lib/message_buffer.h"
#include "mojo/public/cpp/bindings/lib/message_internal.h"
+#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
#include "mojo/public/cpp/system/message.h"
namespace mojo {
+class AssociatedGroupController;
+
+using ReportBadMessageCallback = base::Callback<void(const std::string& error)>;
+
// Message is a holder for the data and handles to be sent over a MessagePipe.
// Message owns its data and handles, but a consumer of Message is free to
// mutate the data and handles. The message's data is comprised of a header
// followed by payload.
-class Message {
+class MOJO_CPP_BINDINGS_EXPORT Message {
public:
static const uint32_t kFlagExpectsResponse = 1 << 0;
static const uint32_t kFlagIsResponse = 1 << 1;
static const uint32_t kFlagIsSync = 1 << 2;
Message();
+ Message(Message&& other);
+
~Message();
+ Message& operator=(Message&& other);
+
+ // Resets the Message to an uninitialized state. Upon reset, the Message
+ // exists as if it were default-constructed: it has no data buffer and owns no
+ // handles.
+ void Reset();
+
+ // Indicates whether this Message is uninitialized.
+ bool IsNull() const { return !buffer_; }
+
// Initializes a Message with enough space for |capacity| bytes.
void Initialize(size_t capacity, bool zero_initialized);
@@ -41,10 +61,9 @@ class Message {
uint32_t num_bytes,
std::vector<Handle>* handles);
- // Transfers data and handles to |destination|.
- void MoveTo(Message* destination);
-
- uint32_t data_num_bytes() const { return buffer_->data_num_bytes(); }
+ uint32_t data_num_bytes() const {
+ return static_cast<uint32_t>(buffer_->size());
+ }
// Access the raw bytes of the message.
const uint8_t* data() const {
@@ -57,12 +76,30 @@ class Message {
const internal::MessageHeader* header() const {
return static_cast<const internal::MessageHeader*>(buffer_->data());
}
-
internal::MessageHeader* header() {
- return const_cast<internal::MessageHeader*>(
- static_cast<const Message*>(this)->header());
+ return static_cast<internal::MessageHeader*>(buffer_->data());
+ }
+
+ const internal::MessageHeaderV1* header_v1() const {
+ DCHECK_GE(version(), 1u);
+ return static_cast<const internal::MessageHeaderV1*>(buffer_->data());
+ }
+ internal::MessageHeaderV1* header_v1() {
+ DCHECK_GE(version(), 1u);
+ return static_cast<internal::MessageHeaderV1*>(buffer_->data());
}
+ const internal::MessageHeaderV2* header_v2() const {
+ DCHECK_GE(version(), 2u);
+ return static_cast<const internal::MessageHeaderV2*>(buffer_->data());
+ }
+ internal::MessageHeaderV2* header_v2() {
+ DCHECK_GE(version(), 2u);
+ return static_cast<internal::MessageHeaderV2*>(buffer_->data());
+ }
+
+ uint32_t version() const { return header()->version; }
+
uint32_t interface_id() const { return header()->interface_id; }
void set_interface_id(uint32_t id) { header()->interface_id = id; }
@@ -70,32 +107,32 @@ class Message {
bool has_flag(uint32_t flag) const { return !!(header()->flags & flag); }
// Access the request_id field (if present).
- bool has_request_id() const { return header()->version >= 1; }
- uint64_t request_id() const {
- DCHECK(has_request_id());
- return static_cast<const internal::MessageHeaderWithRequestID*>(
- header())->request_id;
- }
+ uint64_t request_id() const { return header_v1()->request_id; }
void set_request_id(uint64_t request_id) {
- DCHECK(has_request_id());
- static_cast<internal::MessageHeaderWithRequestID*>(header())
- ->request_id = request_id;
+ header_v1()->request_id = request_id;
}
// Access the payload.
- const uint8_t* payload() const { return data() + header()->num_bytes; }
+ const uint8_t* payload() const;
uint8_t* mutable_payload() { return const_cast<uint8_t*>(payload()); }
- uint32_t payload_num_bytes() const {
- DCHECK(buffer_->data_num_bytes() >= header()->num_bytes);
- size_t num_bytes = buffer_->data_num_bytes() - header()->num_bytes;
- DCHECK(num_bytes <= std::numeric_limits<uint32_t>::max());
- return static_cast<uint32_t>(num_bytes);
- }
+ uint32_t payload_num_bytes() const;
+
+ uint32_t payload_num_interface_ids() const;
+ const uint32_t* payload_interface_ids() const;
// Access the handles.
const std::vector<Handle>* handles() const { return &handles_; }
std::vector<Handle>* mutable_handles() { return &handles_; }
+ const std::vector<ScopedInterfaceEndpointHandle>*
+ associated_endpoint_handles() const {
+ return &associated_endpoint_handles_;
+ }
+ std::vector<ScopedInterfaceEndpointHandle>*
+ mutable_associated_endpoint_handles() {
+ return &associated_endpoint_handles_;
+ }
+
// Access the underlying Buffer interface.
internal::Buffer* buffer() { return buffer_.get(); }
@@ -108,11 +145,22 @@ class Message {
// rejected by bindings validation code.
void NotifyBadMessage(const std::string& error);
+ // Serializes |associated_endpoint_handles_| into the payload_interface_ids
+ // field.
+ void SerializeAssociatedEndpointHandles(
+ AssociatedGroupController* group_controller);
+
+ // Deserializes |associated_endpoint_handles_| from the payload_interface_ids
+ // field.
+ bool DeserializeAssociatedEndpointHandles(
+ AssociatedGroupController* group_controller);
+
private:
void CloseHandles();
std::unique_ptr<internal::MessageBuffer> buffer_;
std::vector<Handle> handles_;
+ std::vector<ScopedInterfaceEndpointHandle> associated_endpoint_handles_;
DISALLOW_COPY_AND_ASSIGN(Message);
};
@@ -186,6 +234,57 @@ class MessageReceiverWithResponderStatus : public MessageReceiver {
WARN_UNUSED_RESULT = 0;
};
+class MOJO_CPP_BINDINGS_EXPORT PassThroughFilter
+ : NON_EXPORTED_BASE(public MessageReceiver) {
+ public:
+ PassThroughFilter();
+ ~PassThroughFilter() override;
+
+ // MessageReceiver:
+ bool Accept(Message* message) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PassThroughFilter);
+};
+
+namespace internal {
+class SyncMessageResponseSetup;
+}
+
+// An object which should be constructed on the stack immediately before making
+// a sync request for which the caller wishes to perform custom validation of
+// the response value(s). It is illegal to make more than one sync call during
+// the lifetime of the topmost SyncMessageResponseContext, but it is legal to
+// nest contexts to support reentrancy.
+//
+// Usage should look something like:
+//
+// SyncMessageResponseContext response_context;
+// foo_interface->SomeSyncCall(&response_value);
+// if (response_value.IsBad())
+// response_context.ReportBadMessage("Bad response_value!");
+//
+class MOJO_CPP_BINDINGS_EXPORT SyncMessageResponseContext {
+ public:
+ SyncMessageResponseContext();
+ ~SyncMessageResponseContext();
+
+ static SyncMessageResponseContext* current();
+
+ void ReportBadMessage(const std::string& error);
+
+ const ReportBadMessageCallback& GetBadMessageCallback();
+
+ private:
+ friend class internal::SyncMessageResponseSetup;
+
+ SyncMessageResponseContext* outer_context_;
+ Message response_;
+ ReportBadMessageCallback bad_message_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(SyncMessageResponseContext);
+};
+
// Read a single message from the pipe. The caller should have created the
// Message, but not called Initialize(). Returns MOJO_RESULT_SHOULD_WAIT if
// the caller should wait on the handle to become readable. Returns
@@ -195,6 +294,22 @@ class MessageReceiverWithResponderStatus : public MessageReceiver {
// NOTE: The message hasn't been validated and may be malformed!
MojoResult ReadMessage(MessagePipeHandle handle, Message* message);
+// Reports the currently dispatching Message as bad. Note that this is only
+// legal to call from directly within the stack frame of a message dispatch. If
+// you need to do asynchronous work before you can determine the legitimacy of
+// a message, use TakeBadMessageCallback() and retain its result until you're
+// ready to invoke or discard it.
+MOJO_CPP_BINDINGS_EXPORT
+void ReportBadMessage(const std::string& error);
+
+// Acquires a callback which may be run to report the currently dispatching
+// Message as bad. Note that this is only legal to call from directly within the
+// stack frame of a message dispatch, but the returned callback may be called
+// exactly once any time thereafter to report the message as bad. This may only
+// be called once per message.
+MOJO_CPP_BINDINGS_EXPORT
+ReportBadMessageCallback GetBadMessageCallback();
+
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_H_
diff --git a/mojo/public/cpp/bindings/message_filter.h b/mojo/public/cpp/bindings/message_filter.h
deleted file mode 100644
index 638c53b..0000000
--- a/mojo/public/cpp/bindings/message_filter.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_FILTER_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_FILTER_H_
-
-#include "mojo/public/cpp/bindings/message.h"
-
-namespace mojo {
-
-// This class is the base class for message filters. Subclasses should
-// implement the pure virtual method Accept() inherited from MessageReceiver to
-// process messages and/or forward them to |sink_|.
-class MessageFilter : public MessageReceiver {
- public:
- // Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while
- // this object is alive.
- explicit MessageFilter(MessageReceiver* sink = nullptr);
- ~MessageFilter() override;
-
- void set_sink(MessageReceiver* sink) { sink_ = sink; }
-
- protected:
- MessageReceiver* sink_;
-};
-
-// A trivial filter that simply forwards every message it receives to |sink_|.
-class PassThroughFilter : public MessageFilter {
- public:
- explicit PassThroughFilter(MessageReceiver* sink = nullptr);
-
- bool Accept(Message* message) override;
-};
-
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_FILTER_H_
diff --git a/mojo/public/cpp/bindings/message_header_validator.h b/mojo/public/cpp/bindings/message_header_validator.h
index 3bcbd0a..50c19db 100644
--- a/mojo/public/cpp/bindings/message_header_validator.h
+++ b/mojo/public/cpp/bindings/message_header_validator.h
@@ -5,16 +5,17 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_HEADER_VALIDATOR_H_
#define MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_HEADER_VALIDATOR_H_
+#include "base/compiler_specific.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/message.h"
-#include "mojo/public/cpp/bindings/message_filter.h"
namespace mojo {
-class MessageHeaderValidator : public MessageFilter {
+class MOJO_CPP_BINDINGS_EXPORT MessageHeaderValidator
+ : NON_EXPORTED_BASE(public MessageReceiver) {
public:
- explicit MessageHeaderValidator(MessageReceiver* sink = nullptr);
- MessageHeaderValidator(const std::string& description,
- MessageReceiver* sink = nullptr);
+ MessageHeaderValidator();
+ explicit MessageHeaderValidator(const std::string& description);
// Sets the description associated with this validator. Used for reporting
// more detailed validation errors.
diff --git a/mojo/public/cpp/bindings/native_struct.h b/mojo/public/cpp/bindings/native_struct.h
index 882c970..ac27250 100644
--- a/mojo/public/cpp/bindings/native_struct.h
+++ b/mojo/public/cpp/bindings/native_struct.h
@@ -5,7 +5,10 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_H_
#define MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_H_
-#include "mojo/public/cpp/bindings/array.h"
+#include <vector>
+
+#include "base/optional.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/lib/native_struct_data.h"
#include "mojo/public/cpp/bindings/struct_ptr.h"
#include "mojo/public/cpp/bindings/type_converter.h"
@@ -17,7 +20,7 @@ using NativeStructPtr = StructPtr<NativeStruct>;
// Native-only structs correspond to "[Native] struct Foo;" definitions in
// mojom.
-class NativeStruct {
+class MOJO_CPP_BINDINGS_EXPORT NativeStruct {
public:
using Data_ = internal::NativeStruct_Data;
@@ -38,8 +41,9 @@ class NativeStruct {
NativeStructPtr Clone() const;
bool Equals(const NativeStruct& other) const;
+ size_t Hash(size_t seed) const;
- Array<uint8_t> data;
+ base::Optional<std::vector<uint8_t>> data;
};
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/native_struct_data_view.h b/mojo/public/cpp/bindings/native_struct_data_view.h
new file mode 100644
index 0000000..613bd7a
--- /dev/null
+++ b/mojo/public/cpp/bindings/native_struct_data_view.h
@@ -0,0 +1,36 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_DATA_VIEW_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_DATA_VIEW_H_
+
+#include "mojo/public/cpp/bindings/lib/native_struct_data.h"
+#include "mojo/public/cpp/bindings/lib/serialization_context.h"
+
+namespace mojo {
+
+class NativeStructDataView {
+ public:
+ using Data_ = internal::NativeStruct_Data;
+
+ NativeStructDataView() {}
+
+ NativeStructDataView(Data_* data, internal::SerializationContext* context)
+ : data_(data) {}
+
+ bool is_null() const { return !data_; }
+
+ size_t size() const { return data_->data.size(); }
+
+ uint8_t operator[](size_t index) const { return data_->data.at(index); }
+
+ const uint8_t* data() const { return data_->data.storage(); }
+
+ private:
+ Data_* data_ = nullptr;
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_DATA_VIEW_H_
diff --git a/mojo/public/cpp/bindings/no_interface.h b/mojo/public/cpp/bindings/no_interface.h
deleted file mode 100644
index d8915cd..0000000
--- a/mojo/public/cpp/bindings/no_interface.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_NO_INTERFACE_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_NO_INTERFACE_H_
-
-#include "mojo/public/cpp/bindings/message.h"
-#include "mojo/public/cpp/bindings/message_filter.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace mojo {
-
-// NoInterface is for use in cases when a non-existent or empty interface is
-// needed.
-
-class NoInterfaceProxy;
-class NoInterfaceStub;
-
-class NoInterface {
- public:
- static const char* Name_;
- typedef NoInterfaceProxy Proxy_;
- typedef NoInterfaceStub Stub_;
- typedef PassThroughFilter RequestValidator_;
- typedef PassThroughFilter ResponseValidator_;
- virtual ~NoInterface() {}
-};
-
-class NoInterfaceProxy : public NoInterface {
- public:
- explicit NoInterfaceProxy(MessageReceiver* receiver) {}
-};
-
-class NoInterfaceStub : public MessageReceiverWithResponder {
- public:
- NoInterfaceStub() {}
- void set_sink(NoInterface* sink) {}
- NoInterface* sink() { return nullptr; }
- bool Accept(Message* message) override;
- bool AcceptWithResponder(Message* message,
- MessageReceiver* responder) override;
-};
-
-// AnyInterface is for use in cases where any interface would do (e.g., see the
-// Shell::Connect method).
-
-typedef NoInterface AnyInterface;
-
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_NO_INTERFACE_H_
diff --git a/mojo/public/cpp/bindings/pipe_control_message_handler.h b/mojo/public/cpp/bindings/pipe_control_message_handler.h
index b387b06..a5c04da 100644
--- a/mojo/public/cpp/bindings/pipe_control_message_handler.h
+++ b/mojo/public/cpp/bindings/pipe_control_message_handler.h
@@ -5,9 +5,11 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_PIPE_CONTROL_MESSAGE_HANDLER_H_
#define MOJO_PUBLIC_CPP_BINDINGS_PIPE_CONTROL_MESSAGE_HANDLER_H_
+#include <string>
+
+#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "mojo/public/cpp/bindings/interface_id.h"
-#include "mojo/public/cpp/bindings/lib/serialization_context.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/message.h"
namespace mojo {
@@ -15,7 +17,8 @@ namespace mojo {
class PipeControlMessageHandlerDelegate;
// Handler for messages defined in pipe_control_messages.mojom.
-class PipeControlMessageHandler : public MessageReceiver {
+class MOJO_CPP_BINDINGS_EXPORT PipeControlMessageHandler
+ : NON_EXPORTED_BASE(public MessageReceiver) {
public:
explicit PipeControlMessageHandler(
PipeControlMessageHandlerDelegate* delegate);
@@ -43,7 +46,6 @@ class PipeControlMessageHandler : public MessageReceiver {
std::string description_;
PipeControlMessageHandlerDelegate* const delegate_;
- internal::SerializationContext context_;
DISALLOW_COPY_AND_ASSIGN(PipeControlMessageHandler);
};
diff --git a/mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h b/mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h
index 06f0695..16fd918 100644
--- a/mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h
+++ b/mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h
@@ -5,6 +5,8 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_PIPE_CONTROL_MESSAGE_HANDLER_DELEGATE_H_
#define MOJO_PUBLIC_CPP_BINDINGS_PIPE_CONTROL_MESSAGE_HANDLER_DELEGATE_H_
+#include "base/optional.h"
+#include "mojo/public/cpp/bindings/disconnect_reason.h"
#include "mojo/public/cpp/bindings/interface_id.h"
namespace mojo {
@@ -14,8 +16,9 @@ class PipeControlMessageHandlerDelegate {
// The implementation of the following methods should return false if the
// notification is unexpected. In that case, the user of this delegate is
// expected to close the message pipe.
- virtual bool OnPeerAssociatedEndpointClosed(InterfaceId id) = 0;
- virtual bool OnAssociatedEndpointClosedBeforeSent(InterfaceId id) = 0;
+ virtual bool OnPeerAssociatedEndpointClosed(
+ InterfaceId id,
+ const base::Optional<DisconnectReason>& reason) = 0;
protected:
virtual ~PipeControlMessageHandlerDelegate() {}
diff --git a/mojo/public/cpp/bindings/pipe_control_message_proxy.h b/mojo/public/cpp/bindings/pipe_control_message_proxy.h
index 7f3e006..52c408f 100644
--- a/mojo/public/cpp/bindings/pipe_control_message_proxy.h
+++ b/mojo/public/cpp/bindings/pipe_control_message_proxy.h
@@ -6,26 +6,36 @@
#define MOJO_PUBLIC_CPP_BINDINGS_PIPE_CONTROL_MESSAGE_PROXY_H_
#include "base/macros.h"
+#include "base/optional.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
+#include "mojo/public/cpp/bindings/disconnect_reason.h"
#include "mojo/public/cpp/bindings/interface_id.h"
#include "mojo/public/cpp/bindings/lib/serialization_context.h"
+#include "mojo/public/cpp/bindings/message.h"
namespace mojo {
class MessageReceiver;
// Proxy for request messages defined in pipe_control_messages.mojom.
-class PipeControlMessageProxy {
+//
+// NOTE: This object may be used from multiple threads.
+class MOJO_CPP_BINDINGS_EXPORT PipeControlMessageProxy {
public:
- // Doesn't take ownership of |receiver|. It must outlive this object.
+ // Doesn't take ownership of |receiver|. If This PipeControlMessageProxy will
+ // be used from multiple threads, |receiver| must be thread-safe.
explicit PipeControlMessageProxy(MessageReceiver* receiver);
- void NotifyPeerEndpointClosed(InterfaceId id);
- void NotifyEndpointClosedBeforeSent(InterfaceId id);
+ void NotifyPeerEndpointClosed(InterfaceId id,
+ const base::Optional<DisconnectReason>& reason);
+
+ static Message ConstructPeerEndpointClosedMessage(
+ InterfaceId id,
+ const base::Optional<DisconnectReason>& reason);
private:
// Not owned.
MessageReceiver* receiver_;
- internal::SerializationContext context_;
DISALLOW_COPY_AND_ASSIGN(PipeControlMessageProxy);
};
diff --git a/mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h b/mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h
new file mode 100644
index 0000000..4d40cdf
--- /dev/null
+++ b/mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h
@@ -0,0 +1,22 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_RAW_PTR_IMPL_REF_TRAITS_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_RAW_PTR_IMPL_REF_TRAITS_H_
+
+namespace mojo {
+
+// Default traits for a binding's implementation reference type. This
+// corresponds to a raw pointer.
+template <typename Interface>
+struct RawPtrImplRefTraits {
+ using PointerType = Interface*;
+
+ static bool IsNull(PointerType ptr) { return !ptr; }
+ static Interface* GetRawPointer(PointerType* ptr) { return *ptr; }
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_RAW_PTR_IMPL_REF_TRAITS_H_
diff --git a/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h b/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h
index 1f45b0c..16527cf 100644
--- a/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h
+++ b/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h
@@ -5,8 +5,16 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_SCOPED_INTERFACE_ENDPOINT_HANDLE_H_
#define MOJO_PUBLIC_CPP_BINDINGS_SCOPED_INTERFACE_ENDPOINT_HANDLE_H_
+#include <string>
+
+#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/optional.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
+#include "mojo/public/cpp/bindings/disconnect_reason.h"
#include "mojo/public/cpp/bindings/interface_id.h"
namespace mojo {
@@ -15,8 +23,16 @@ class AssociatedGroupController;
// ScopedInterfaceEndpointHandle refers to one end of an interface, either the
// implementation side or the client side.
-class ScopedInterfaceEndpointHandle {
+// Threading: At any given time, a ScopedInterfaceEndpointHandle should only
+// be accessed from a single thread.
+class MOJO_CPP_BINDINGS_EXPORT ScopedInterfaceEndpointHandle {
public:
+ // Creates a pair of handles representing the two endpoints of an interface,
+ // which are not yet associated with a message pipe.
+ static void CreatePairPendingAssociation(
+ ScopedInterfaceEndpointHandle* handle0,
+ ScopedInterfaceEndpointHandle* handle1);
+
// Creates an invalid endpoint handle.
ScopedInterfaceEndpointHandle();
@@ -27,39 +43,77 @@ class ScopedInterfaceEndpointHandle {
ScopedInterfaceEndpointHandle& operator=(
ScopedInterfaceEndpointHandle&& other);
- bool is_valid() const { return IsValidInterfaceId(id_); }
+ bool is_valid() const;
- bool is_local() const { return is_local_; }
+ // Returns true if the interface hasn't associated with a message pipe.
+ bool pending_association() const;
- void reset();
- void swap(ScopedInterfaceEndpointHandle& other);
+ // Returns kInvalidInterfaceId when in pending association state or the handle
+ // is invalid.
+ InterfaceId id() const;
- // DO NOT USE METHODS BELOW THIS LINE. These are for internal use and testing.
+ // Returns null when in pending association state or the handle is invalid.
+ AssociatedGroupController* group_controller() const;
- InterfaceId id() const { return id_; }
+ // Returns the disconnect reason if the peer handle is closed before
+ // association and specifies a custom disconnect reason.
+ const base::Optional<DisconnectReason>& disconnect_reason() const;
- AssociatedGroupController* group_controller() const {
- return group_controller_.get();
- }
+ enum AssociationEvent {
+ // The interface has been associated with a message pipe.
+ ASSOCIATED,
+ // The peer of this object has been closed before association.
+ PEER_CLOSED_BEFORE_ASSOCIATION
+ };
- // Releases the handle without closing it.
- InterfaceId release();
+ using AssociationEventCallback = base::OnceCallback<void(AssociationEvent)>;
+ // Note:
+ // - |handler| won't run if the handle is invalid. Otherwise, |handler| is run
+ // on the calling thread asynchronously, even if the interface has already
+ // been associated or the peer has been closed before association.
+ // - |handler| won't be called after this object is destroyed or reset.
+ // - A null |handler| can be used to cancel the previous callback.
+ void SetAssociationEventHandler(AssociationEventCallback handler);
+
+ void reset();
+ void ResetWithReason(uint32_t custom_reason, const std::string& description);
private:
friend class AssociatedGroupController;
+ friend class AssociatedGroup;
+
+ class State;
- // This is supposed to be used by AssociatedGroupController only.
- // |id| is the corresponding interface ID.
- // If |is_local| is false, this handle is meant to be passed over a message
- // pipe the remote side of the associated group.
+ // Used by AssociatedGroupController.
ScopedInterfaceEndpointHandle(
InterfaceId id,
- bool is_local,
scoped_refptr<AssociatedGroupController> group_controller);
- InterfaceId id_;
- bool is_local_;
- scoped_refptr<AssociatedGroupController> group_controller_;
+ // Used by AssociatedGroupController.
+ // The peer of this handle will join |peer_group_controller|.
+ bool NotifyAssociation(
+ InterfaceId id,
+ scoped_refptr<AssociatedGroupController> peer_group_controller);
+
+ void ResetInternal(const base::Optional<DisconnectReason>& reason);
+
+ // Used by AssociatedGroup.
+ // It is safe to run the returned callback on any thread, or after this handle
+ // is destroyed.
+ // The return value of the getter:
+ // - If the getter is retrieved when the handle is invalid, the return value
+ // of the getter will always be null.
+ // - If the getter is retrieved when the handle is valid and non-pending,
+ // the return value of the getter will be non-null and remain unchanged
+ // even if the handle is later reset.
+ // - If the getter is retrieved when the handle is valid but pending
+ // asssociation, the return value of the getter will initially be null,
+ // change to non-null when the handle is associated, and remain unchanged
+ // ever since.
+ base::Callback<AssociatedGroupController*()> CreateGroupControllerGetter()
+ const;
+
+ scoped_refptr<State> state_;
DISALLOW_COPY_AND_ASSIGN(ScopedInterfaceEndpointHandle);
};
diff --git a/mojo/public/cpp/bindings/stl_converters.h b/mojo/public/cpp/bindings/stl_converters.h
deleted file mode 100644
index 92b2924..0000000
--- a/mojo/public/cpp/bindings/stl_converters.h
+++ /dev/null
@@ -1,245 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_STL_CONVERTERS_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_STL_CONVERTERS_H_
-
-#include <map>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include "mojo/public/cpp/bindings/array.h"
-#include "mojo/public/cpp/bindings/map.h"
-#include "mojo/public/cpp/bindings/string.h"
-
-// Two functions are defined to facilitate conversion between
-// mojo::Array/Map/String and std::vector/map/string: mojo::UnwrapToSTLType()
-// recursively convert mojo types to STL types; mojo::WrapSTLType() does the
-// opposite. For example:
-// mojo::Array<mojo::Map<mojo::String, mojo::Array<int32_t>>> mojo_obj;
-//
-// std::vector<std::map<std::string, std::vector<int32_t>>> stl_obj =
-// mojo::UnwrapToSTLType(std::move(mojo_obj));
-//
-// mojo_obj = mojo::WrapSTLType(std::move(stl_obj));
-//
-// Notes:
-// - The conversion moves as much contents as possible. The two functions both
-// take an rvalue ref as input in order to avoid accidental copies.
-// - Because std::vector/map/string cannot express null, UnwrapToSTLType()
-// converts null mojo::Array/Map/String to empty.
-// - The recursive conversion stops at any types that are not the types listed
-// above. For example, unwrapping mojo::Array<StructContainingMojoMap> will
-// result in std::vector<StructContainingMojoMap>. It won't convert
-// mojo::Map inside the struct.
-
-namespace mojo {
-namespace internal {
-
-template <typename T>
-struct UnwrapTraits;
-
-template <typename T>
-struct UnwrapShouldGoDeeper {
- public:
- static const bool value =
- !std::is_same<T, typename UnwrapTraits<T>::Type>::value;
-};
-
-template <typename T>
-struct UnwrapTraits {
- public:
- using Type = T;
- static Type Unwrap(T input) { return input; }
-};
-
-template <typename T>
-struct UnwrapTraits<Array<T>> {
- public:
- using Type = std::vector<typename UnwrapTraits<T>::Type>;
-
- static Type Unwrap(Array<T> input) {
- return Helper<T>::Run(std::move(input));
- }
-
- private:
- template <typename U, bool should_go_deeper = UnwrapShouldGoDeeper<U>::value>
- struct Helper {};
-
- template <typename U>
- struct Helper<U, true> {
- public:
- static Type Run(Array<T> input) {
- Type output;
- output.reserve(input.size());
- for (size_t i = 0; i < input.size(); ++i)
- output.push_back(UnwrapTraits<T>::Unwrap(std::move(input[i])));
- return output;
- }
- };
-
- template <typename U>
- struct Helper<U, false> {
- public:
- static Type Run(Array<T> input) { return input.PassStorage(); }
- };
-};
-
-template <typename K, typename V>
-struct UnwrapTraits<Map<K, V>> {
- public:
- using Type =
- std::map<typename UnwrapTraits<K>::Type, typename UnwrapTraits<V>::Type>;
-
- static Type Unwrap(Map<K, V> input) {
- return Helper<K, V>::Run(std::move(input));
- }
-
- private:
- template <typename X,
- typename Y,
- bool should_go_deeper = UnwrapShouldGoDeeper<X>::value ||
- UnwrapShouldGoDeeper<Y>::value>
- struct Helper {};
-
- template <typename X, typename Y>
- struct Helper<X, Y, true> {
- public:
- static Type Run(Map<K, V> input) {
- std::map<K, V> input_storage = input.PassStorage();
- Type output;
- for (auto& pair : input_storage) {
- output.insert(
- std::make_pair(UnwrapTraits<K>::Unwrap(pair.first),
- UnwrapTraits<V>::Unwrap(std::move(pair.second))));
- }
- return output;
- }
- };
-
- template <typename X, typename Y>
- struct Helper<X, Y, false> {
- public:
- static Type Run(Map<K, V> input) { return input.PassStorage(); }
- };
-};
-
-template <>
-struct UnwrapTraits<String> {
- public:
- using Type = std::string;
-
- static std::string Unwrap(const String& input) { return input; }
-};
-
-template <typename T>
-struct WrapTraits;
-
-template <typename T>
-struct WrapShouldGoDeeper {
- public:
- static const bool value =
- !std::is_same<T, typename WrapTraits<T>::Type>::value;
-};
-
-template <typename T>
-struct WrapTraits {
- public:
- using Type = T;
-
- static T Wrap(T input) { return input; }
-};
-
-template <typename T>
-struct WrapTraits<std::vector<T>> {
- public:
- using Type = Array<typename WrapTraits<T>::Type>;
-
- static Type Wrap(std::vector<T> input) {
- return Helper<T>::Run(std::move(input));
- }
-
- private:
- template <typename U, bool should_go_deeper = WrapShouldGoDeeper<U>::value>
- struct Helper {};
-
- template <typename U>
- struct Helper<U, true> {
- public:
- static Type Run(std::vector<T> input) {
- std::vector<typename WrapTraits<T>::Type> output_storage;
- output_storage.reserve(input.size());
- for (auto& element : input)
- output_storage.push_back(WrapTraits<T>::Wrap(std::move(element)));
- return Type(std::move(output_storage));
- }
- };
-
- template <typename U>
- struct Helper<U, false> {
- public:
- static Type Run(std::vector<T> input) { return Type(std::move(input)); }
- };
-};
-
-template <typename K, typename V>
-struct WrapTraits<std::map<K, V>> {
- public:
- using Type = Map<typename WrapTraits<K>::Type, typename WrapTraits<V>::Type>;
-
- static Type Wrap(std::map<K, V> input) {
- return Helper<K, V>::Run(std::move(input));
- }
-
- private:
- template <typename X,
- typename Y,
- bool should_go_deeper =
- WrapShouldGoDeeper<X>::value || WrapShouldGoDeeper<Y>::value>
- struct Helper {};
-
- template <typename X, typename Y>
- struct Helper<X, Y, true> {
- public:
- static Type Run(std::map<K, V> input) {
- Type output;
- for (auto& pair : input) {
- output.insert(WrapTraits<K>::Wrap(pair.first),
- WrapTraits<V>::Wrap(std::move(pair.second)));
- }
- return output;
- }
- };
-
- template <typename X, typename Y>
- struct Helper<X, Y, false> {
- public:
- static Type Run(std::map<K, V> input) { return Type(std::move(input)); }
- };
-};
-
-template <>
-struct WrapTraits<std::string> {
- public:
- using Type = String;
-
- static String Wrap(const std::string& input) { return input; }
-};
-
-} // namespace internal
-
-template <typename T>
-typename internal::UnwrapTraits<T>::Type UnwrapToSTLType(T&& input) {
- return internal::UnwrapTraits<T>::Unwrap(std::move(input));
-}
-
-template <typename T>
-typename internal::WrapTraits<T>::Type WrapSTLType(T&& input) {
- return internal::WrapTraits<T>::Wrap(std::move(input));
-}
-
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_STL_CONVERTERS_H_
diff --git a/mojo/public/cpp/bindings/string.h b/mojo/public/cpp/bindings/string.h
deleted file mode 100644
index 7cfd713..0000000
--- a/mojo/public/cpp/bindings/string.h
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_STRING_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_STRING_H_
-
-#include <stddef.h>
-
-#include <string>
-
-#include "base/logging.h"
-#include "mojo/public/cpp/bindings/lib/array_internal.h"
-#include "mojo/public/cpp/bindings/type_converter.h"
-
-namespace mojo {
-
-// A UTF-8 encoded character string that can be null. Provides functions that
-// are similar to std::string, along with access to the underlying std::string
-// object.
-class String {
- public:
- // Constructs an empty string.
- String() : is_null_(false) {}
- String(const std::string& str) : value_(str), is_null_(false) {}
- String(const char* chars) : is_null_(!chars) {
- if (chars)
- value_ = chars;
- }
- String(const char* chars, size_t num_chars)
- : value_(chars, num_chars), is_null_(false) {}
- String(const mojo::String& str)
- : value_(str.value_), is_null_(str.is_null_) {}
-
- template <size_t N>
- String(const char chars[N])
- : value_(chars, N - 1), is_null_(false) {}
-
- String(std::string&& other) : value_(std::move(other)), is_null_(false) {}
- String(String&& other) : is_null_(true) { Swap(&other); }
-
- template <typename U>
- static String From(const U& other) {
- return TypeConverter<String, U>::Convert(other);
- }
-
- template <typename U>
- U To() const {
- return TypeConverter<U, String>::Convert(*this);
- }
-
- String& operator=(const mojo::String& str) {
- value_ = str.value_;
- is_null_ = str.is_null_;
- return *this;
- }
- String& operator=(const std::string& str) {
- value_ = str;
- is_null_ = false;
- return *this;
- }
- String& operator=(const char* chars) {
- is_null_ = !chars;
- if (chars) {
- value_ = chars;
- } else {
- value_.clear();
- }
- return *this;
- }
-
- String& operator=(std::string&& other) {
- value_ = std::move(other);
- is_null_ = false;
- return *this;
- }
- String& operator=(String&& other) {
- is_null_ = true;
- value_.clear();
- Swap(&other);
- return *this;
- }
-
- bool is_null() const { return is_null_; }
-
- size_t size() const { return value_.size(); }
-
- const char* data() const { return value_.data(); }
-
- const char& at(size_t offset) const { return value_.at(offset); }
- const char& operator[](size_t offset) const { return value_[offset]; }
-
- const std::string& get() const { return value_; }
- operator const std::string&() const { return value_; }
-
- // Returns a const reference to the |std::string| managed by this class. If
- // the string is null, this will be an empty std::string.
- const std::string& storage() const { return value_; }
-
- // Passes the underlying storage and resets this string to null.
- std::string PassStorage() {
- is_null_ = true;
- return std::move(value_);
- }
-
- void Swap(String* other) {
- std::swap(is_null_, other->is_null_);
- value_.swap(other->value_);
- }
-
- void Swap(std::string* other) {
- is_null_ = false;
- value_.swap(*other);
- }
-
- private:
- typedef std::string String::*Testable;
-
- public:
- operator Testable() const { return is_null_ ? 0 : &String::value_; }
-
- private:
- std::string value_;
- bool is_null_;
-};
-
-inline bool operator==(const String& a, const String& b) {
- return a.is_null() == b.is_null() && a.get() == b.get();
-}
-inline bool operator==(const char* a, const String& b) {
- return !b.is_null() && a == b.get();
-}
-inline bool operator==(const String& a, const char* b) {
- return !a.is_null() && a.get() == b;
-}
-inline bool operator!=(const String& a, const String& b) {
- return !(a == b);
-}
-inline bool operator!=(const char* a, const String& b) {
- return !(a == b);
-}
-inline bool operator!=(const String& a, const char* b) {
- return !(a == b);
-}
-
-inline std::ostream& operator<<(std::ostream& out, const String& s) {
- return out << s.get();
-}
-
-inline bool operator<(const String& a, const String& b) {
- if (a.is_null())
- return !b.is_null();
- if (b.is_null())
- return false;
-
- return a.get() < b.get();
-}
-
-// TODO(darin): Add similar variants of operator<,<=,>,>=
-
-template <>
-struct TypeConverter<String, std::string> {
- static String Convert(const std::string& input) { return String(input); }
-};
-
-template <>
-struct TypeConverter<std::string, String> {
- static std::string Convert(const String& input) { return input; }
-};
-
-template <size_t N>
-struct TypeConverter<String, char[N]> {
- static String Convert(const char input[N]) {
- DCHECK(input);
- return String(input, N - 1);
- }
-};
-
-// Appease MSVC.
-template <size_t N>
-struct TypeConverter<String, const char[N]> {
- static String Convert(const char input[N]) {
- DCHECK(input);
- return String(input, N - 1);
- }
-};
-
-template <>
-struct TypeConverter<String, const char*> {
- // |input| may be null, in which case a null String will be returned.
- static String Convert(const char* input) { return String(input); }
-};
-
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_STRING_H_
diff --git a/mojo/public/cpp/bindings/string_data_view.h b/mojo/public/cpp/bindings/string_data_view.h
new file mode 100644
index 0000000..2b091b4
--- /dev/null
+++ b/mojo/public/cpp/bindings/string_data_view.h
@@ -0,0 +1,34 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_STRING_DATA_VIEW_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_STRING_DATA_VIEW_H_
+
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/lib/serialization_context.h"
+
+namespace mojo {
+
+// Access to the contents of a serialized string.
+class StringDataView {
+ public:
+ StringDataView() {}
+
+ StringDataView(internal::String_Data* data,
+ internal::SerializationContext* context)
+ : data_(data) {}
+
+ bool is_null() const { return !data_; }
+
+ const char* storage() const { return data_->storage(); }
+
+ size_t size() const { return data_->size(); }
+
+ private:
+ internal::String_Data* data_ = nullptr;
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_STRING_DATA_VIEW_H_
diff --git a/mojo/public/cpp/bindings/string_traits.h b/mojo/public/cpp/bindings/string_traits.h
index a6ade6f..7d3075a 100644
--- a/mojo/public/cpp/bindings/string_traits.h
+++ b/mojo/public/cpp/bindings/string_traits.h
@@ -5,26 +5,10 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_H_
#define MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_H_
-#include "base/logging.h"
-#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/string_data_view.h"
namespace mojo {
-// Access to the contents of a serialized string.
-class StringDataView {
- public:
- explicit StringDataView(internal::String_Data* data) : data_(data) {
- DCHECK(data_);
- }
-
- const char* storage() const { return data_->storage(); }
-
- size_t size() const { return data_->size(); }
-
- private:
- internal::String_Data* data_;
-};
-
// This must be specialized for any type |T| to be serialized/deserialized as
// a mojom string.
//
@@ -40,6 +24,7 @@ class StringDataView {
// static size_t GetSize(const CustomString& input);
// static const char* GetData(const CustomString& input);
//
+// // The caller guarantees that |!input.is_null()|.
// static bool Read(StringDataView input, CustomString* output);
// };
//
diff --git a/mojo/public/cpp/bindings/string_traits_standard.h b/mojo/public/cpp/bindings/string_traits_standard.h
deleted file mode 100644
index 9b78d24..0000000
--- a/mojo/public/cpp/bindings/string_traits_standard.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STANDARD_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STANDARD_H_
-
-#include "mojo/public/cpp/bindings/string.h"
-#include "mojo/public/cpp/bindings/string_traits.h"
-
-namespace mojo {
-
-template <>
-struct StringTraits<String> {
- static bool IsNull(const String& input) { return input.is_null(); }
- static void SetToNull(String* output) { *output = nullptr; }
-
- static size_t GetSize(const String& input) { return input.size(); }
-
- static const char* GetData(const String& input) { return input.data(); }
-
- static bool Read(StringDataView input, String* output) {
- String result(input.storage(), input.size());
- result.Swap(output);
- return true;
- }
-};
-
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STANDARD_H_
diff --git a/mojo/public/cpp/bindings/string_traits_string16.h b/mojo/public/cpp/bindings/string_traits_string16.h
index 5a08908..f96973a 100644
--- a/mojo/public/cpp/bindings/string_traits_string16.h
+++ b/mojo/public/cpp/bindings/string_traits_string16.h
@@ -6,12 +6,13 @@
#define MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STRING16_H_
#include "base/strings/string16.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/string_traits.h"
namespace mojo {
template <>
-struct StringTraits<base::string16> {
+struct MOJO_CPP_BINDINGS_EXPORT StringTraits<base::string16> {
static bool IsNull(const base::string16& input) {
// base::string16 is always converted to non-null mojom string.
return false;
diff --git a/mojo/public/cpp/bindings/strong_binding.h b/mojo/public/cpp/bindings/strong_binding.h
index 7fb7eea..f4b4a06 100644
--- a/mojo/public/cpp/bindings/strong_binding.h
+++ b/mojo/public/cpp/bindings/strong_binding.h
@@ -5,122 +5,121 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_STRONG_BINDING_H_
#define MOJO_PUBLIC_CPP_BINDINGS_STRONG_BINDING_H_
+#include <memory>
+#include <string>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/connection_error_callback.h"
+#include "mojo/public/cpp/bindings/filter_chain.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/bindings/lib/filter_chain.h"
-#include "mojo/public/cpp/bindings/lib/router.h"
#include "mojo/public/cpp/bindings/message_header_validator.h"
#include "mojo/public/cpp/system/core.h"
namespace mojo {
+template <typename Interface>
+class StrongBinding;
+
+template <typename Interface>
+using StrongBindingPtr = base::WeakPtr<StrongBinding<Interface>>;
+
// This connects an interface implementation strongly to a pipe. When a
-// connection error is detected the implementation is deleted. Deleting the
-// connector also closes the pipe.
-//
-// Example of an implementation that is always bound strongly to a pipe
+// connection error is detected the implementation is deleted. If the task
+// runner that a StrongBinding is bound on is stopped, the connection error
+// handler will not be invoked and the implementation will not be deleted.
//
-// class StronglyBound : public Foo {
-// public:
-// explicit StronglyBound(InterfaceRequest<Foo> request)
-// : binding_(this, std::move(request)) {}
+// To use, call StrongBinding<T>::Create() (see below) or the helper
+// MakeStrongBinding function:
//
-// // Foo implementation here
+// mojo::MakeStrongBinding(base::MakeUnique<FooImpl>(),
+// std::move(foo_request));
//
-// private:
-// StrongBinding<Foo> binding_;
-// };
-//
-// class MyFooFactory : public InterfaceFactory<Foo> {
-// public:
-// void Create(..., InterfaceRequest<Foo> request) override {
-// new StronglyBound(std::move(request)); // The binding now owns the
-// // instance of StronglyBound.
-// }
-// };
-//
-// This class is thread hostile once it is bound to a message pipe. Until it is
-// bound, it may be bound or destroyed on any thread.
template <typename Interface>
class StrongBinding {
public:
- explicit StrongBinding(Interface* impl) : binding_(impl) {}
-
- StrongBinding(Interface* impl, ScopedMessagePipeHandle handle)
- : StrongBinding(impl) {
- Bind(std::move(handle));
+ // Create a new StrongBinding instance. The instance owns itself, cleaning up
+ // only in the event of a pipe connection error. Returns a WeakPtr to the new
+ // StrongBinding instance.
+ static StrongBindingPtr<Interface> Create(
+ std::unique_ptr<Interface> impl,
+ InterfaceRequest<Interface> request) {
+ StrongBinding* binding =
+ new StrongBinding(std::move(impl), std::move(request));
+ return binding->weak_factory_.GetWeakPtr();
}
- StrongBinding(Interface* impl, InterfacePtr<Interface>* ptr)
- : StrongBinding(impl) {
- Bind(ptr);
+ // Note: The error handler must not delete the interface implementation.
+ //
+ // This method may only be called after this StrongBinding has been bound to a
+ // message pipe.
+ void set_connection_error_handler(const base::Closure& error_handler) {
+ DCHECK(binding_.is_bound());
+ connection_error_handler_ = error_handler;
+ connection_error_with_reason_handler_.Reset();
}
- StrongBinding(Interface* impl, InterfaceRequest<Interface> request)
- : StrongBinding(impl) {
- Bind(std::move(request));
+ void set_connection_error_with_reason_handler(
+ const ConnectionErrorWithReasonCallback& error_handler) {
+ DCHECK(binding_.is_bound());
+ connection_error_with_reason_handler_ = error_handler;
+ connection_error_handler_.Reset();
}
- ~StrongBinding() {}
+ // Forces the binding to close. This destroys the StrongBinding instance.
+ void Close() { delete this; }
- void Bind(ScopedMessagePipeHandle handle) {
- DCHECK(!binding_.is_bound());
- binding_.Bind(std::move(handle));
- binding_.set_connection_error_handler(
- base::Bind(&StrongBinding::OnConnectionError, base::Unretained(this)));
- }
+ Interface* impl() { return impl_.get(); }
- void Bind(InterfacePtr<Interface>* ptr) {
- DCHECK(!binding_.is_bound());
- binding_.Bind(ptr);
- binding_.set_connection_error_handler(
- base::Bind(&StrongBinding::OnConnectionError, base::Unretained(this)));
- }
+ // Sends a message on the underlying message pipe and runs the current
+ // message loop until its response is received. This can be used in tests to
+ // verify that no message was sent on a message pipe in response to some
+ // stimulus.
+ void FlushForTesting() { binding_.FlushForTesting(); }
- void Bind(InterfaceRequest<Interface> request) {
- DCHECK(!binding_.is_bound());
- binding_.Bind(std::move(request));
- binding_.set_connection_error_handler(
+ private:
+ StrongBinding(std::unique_ptr<Interface> impl,
+ InterfaceRequest<Interface> request)
+ : impl_(std::move(impl)),
+ binding_(impl_.get(), std::move(request)),
+ weak_factory_(this) {
+ binding_.set_connection_error_with_reason_handler(
base::Bind(&StrongBinding::OnConnectionError, base::Unretained(this)));
}
- bool WaitForIncomingMethodCall() {
- return binding_.WaitForIncomingMethodCall();
- }
-
- // Note: The error handler must not delete the interface implementation.
- //
- // This method may only be called after this StrongBinding has been bound to a
- // message pipe.
- void set_connection_error_handler(const base::Closure& error_handler) {
- DCHECK(binding_.is_bound());
- connection_error_handler_ = error_handler;
- }
-
- Interface* impl() { return binding_.impl(); }
- // Exposed for testing, should not generally be used.
- internal::Router* internal_router() { return binding_.internal_router(); }
+ ~StrongBinding() {}
- void OnConnectionError() {
+ void OnConnectionError(uint32_t custom_reason,
+ const std::string& description) {
if (!connection_error_handler_.is_null())
connection_error_handler_.Run();
- delete binding_.impl();
+ else if (!connection_error_with_reason_handler_.is_null())
+ connection_error_with_reason_handler_.Run(custom_reason, description);
+ Close();
}
- private:
+ std::unique_ptr<Interface> impl_;
base::Closure connection_error_handler_;
+ ConnectionErrorWithReasonCallback connection_error_with_reason_handler_;
Binding<Interface> binding_;
+ base::WeakPtrFactory<StrongBinding> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(StrongBinding);
};
+template <typename Interface, typename Impl>
+StrongBindingPtr<Interface> MakeStrongBinding(
+ std::unique_ptr<Impl> impl,
+ InterfaceRequest<Interface> request) {
+ return StrongBinding<Interface>::Create(std::move(impl), std::move(request));
+}
+
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_STRONG_BINDING_H_
diff --git a/mojo/public/cpp/bindings/struct_ptr.h b/mojo/public/cpp/bindings/struct_ptr.h
index 92f2728..b135312 100644
--- a/mojo/public/cpp/bindings/struct_ptr.h
+++ b/mojo/public/cpp/bindings/struct_ptr.h
@@ -5,23 +5,26 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
#define MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
+#include <functional>
+#include <memory>
#include <new>
#include "base/logging.h"
#include "base/macros.h"
+#include "base/optional.h"
+#include "mojo/public/cpp/bindings/lib/hash_util.h"
#include "mojo/public/cpp/bindings/type_converter.h"
namespace mojo {
namespace internal {
+constexpr size_t kHashSeed = 31;
+
template <typename Struct>
-class StructHelper {
- public:
- template <typename Ptr>
- static void Initialize(Ptr* ptr) {
- ptr->Initialize();
- }
-};
+class StructPtrWTFHelper;
+
+template <typename Struct>
+class InlinedStructPtrWTFHelper;
} // namespace internal
@@ -31,35 +34,34 @@ class StructPtr {
public:
using Struct = S;
- StructPtr() : ptr_(nullptr) {}
- StructPtr(decltype(nullptr)) : ptr_(nullptr) {}
+ StructPtr() = default;
+ StructPtr(decltype(nullptr)) {}
- ~StructPtr() { delete ptr_; }
+ ~StructPtr() = default;
StructPtr& operator=(decltype(nullptr)) {
reset();
return *this;
}
- StructPtr(StructPtr&& other) : ptr_(nullptr) { Take(&other); }
+ StructPtr(StructPtr&& other) { Take(&other); }
StructPtr& operator=(StructPtr&& other) {
Take(&other);
return *this;
}
+ template <typename... Args>
+ StructPtr(base::in_place_t, Args&&... args)
+ : ptr_(new Struct(std::forward<Args>(args)...)) {}
+
template <typename U>
U To() const {
return TypeConverter<U, StructPtr>::Convert(*this);
}
- void reset() {
- if (ptr_) {
- delete ptr_;
- ptr_ = nullptr;
- }
- }
+ void reset() { ptr_.reset(); }
- bool is_null() const { return ptr_ == nullptr; }
+ bool is_null() const { return !ptr_; }
Struct& operator*() const {
DCHECK(ptr_);
@@ -67,9 +69,9 @@ class StructPtr {
}
Struct* operator->() const {
DCHECK(ptr_);
- return ptr_;
+ return ptr_.get();
}
- Struct* get() const { return ptr_; }
+ Struct* get() const { return ptr_.get(); }
void Swap(StructPtr* other) { std::swap(ptr_, other->ptr_); }
@@ -78,52 +80,52 @@ class StructPtr {
// that it contains Mojo handles).
StructPtr Clone() const { return is_null() ? StructPtr() : ptr_->Clone(); }
+ // Compares the pointees (which might both be null).
+ // TODO(tibell): Get rid of Equals in favor of the operator. Same for Hash.
bool Equals(const StructPtr& other) const {
if (is_null() || other.is_null())
return is_null() && other.is_null();
return ptr_->Equals(*other.ptr_);
}
- private:
- // TODO(dcheng): Use an explicit conversion operator.
- typedef Struct* StructPtr::*Testable;
+ // Hashes based on the pointee (which might be null).
+ size_t Hash(size_t seed) const {
+ if (is_null())
+ return internal::HashCombine(seed, 0);
+ return ptr_->Hash(seed);
+ }
- public:
- operator Testable() const { return ptr_ ? &StructPtr::ptr_ : 0; }
+ explicit operator bool() const { return !is_null(); }
private:
- friend class internal::StructHelper<Struct>;
-
- // Forbid the == and != operators explicitly, otherwise StructPtr will be
- // converted to Testable to do == or != comparison.
- template <typename T>
- bool operator==(const StructPtr<T>& other) const = delete;
- template <typename T>
- bool operator!=(const StructPtr<T>& other) const = delete;
-
- void Initialize() {
- DCHECK(!ptr_);
- ptr_ = new Struct();
- }
-
+ friend class internal::StructPtrWTFHelper<Struct>;
void Take(StructPtr* other) {
reset();
Swap(other);
}
- Struct* ptr_;
+ std::unique_ptr<Struct> ptr_;
DISALLOW_COPY_AND_ASSIGN(StructPtr);
};
+template <typename T>
+bool operator==(const StructPtr<T>& lhs, const StructPtr<T>& rhs) {
+ return lhs.Equals(rhs);
+}
+template <typename T>
+bool operator!=(const StructPtr<T>& lhs, const StructPtr<T>& rhs) {
+ return !(lhs == rhs);
+}
+
// Designed to be used when Struct is small and copyable.
template <typename S>
class InlinedStructPtr {
public:
using Struct = S;
- InlinedStructPtr() : is_null_(true) {}
- InlinedStructPtr(decltype(nullptr)) : is_null_(true) {}
+ InlinedStructPtr() : state_(NIL) {}
+ InlinedStructPtr(decltype(nullptr)) : state_(NIL) {}
~InlinedStructPtr() {}
@@ -132,79 +134,150 @@ class InlinedStructPtr {
return *this;
}
- InlinedStructPtr(InlinedStructPtr&& other) : is_null_(true) { Take(&other); }
+ InlinedStructPtr(InlinedStructPtr&& other) : state_(NIL) { Take(&other); }
InlinedStructPtr& operator=(InlinedStructPtr&& other) {
Take(&other);
return *this;
}
+ template <typename... Args>
+ InlinedStructPtr(base::in_place_t, Args&&... args)
+ : value_(std::forward<Args>(args)...), state_(VALID) {}
+
template <typename U>
U To() const {
return TypeConverter<U, InlinedStructPtr>::Convert(*this);
}
void reset() {
- is_null_ = true;
+ state_ = NIL;
value_. ~Struct();
new (&value_) Struct();
}
- bool is_null() const { return is_null_; }
+ bool is_null() const { return state_ == NIL; }
Struct& operator*() const {
- DCHECK(!is_null_);
+ DCHECK(state_ == VALID);
return value_;
}
Struct* operator->() const {
- DCHECK(!is_null_);
+ DCHECK(state_ == VALID);
return &value_;
}
Struct* get() const { return &value_; }
void Swap(InlinedStructPtr* other) {
std::swap(value_, other->value_);
- std::swap(is_null_, other->is_null_);
+ std::swap(state_, other->state_);
}
InlinedStructPtr Clone() const {
return is_null() ? InlinedStructPtr() : value_.Clone();
}
+
+ // Compares the pointees (which might both be null).
bool Equals(const InlinedStructPtr& other) const {
if (is_null() || other.is_null())
return is_null() && other.is_null();
return value_.Equals(other.value_);
}
- private:
- // TODO(dcheng): Use an explicit conversion operator.
- typedef Struct InlinedStructPtr::*Testable;
+ // Hashes based on the pointee (which might be null).
+ size_t Hash(size_t seed) const {
+ if (is_null())
+ return internal::HashCombine(seed, 0);
+ return value_.Hash(seed);
+ }
- public:
- operator Testable() const { return is_null_ ? 0 : &InlinedStructPtr::value_; }
+ explicit operator bool() const { return !is_null(); }
private:
- friend class internal::StructHelper<Struct>;
-
- // Forbid the == and != operators explicitly, otherwise InlinedStructPtr will
- // be converted to Testable to do == or != comparison.
- template <typename T>
- bool operator==(const InlinedStructPtr<T>& other) const = delete;
- template <typename T>
- bool operator!=(const InlinedStructPtr<T>& other) const = delete;
-
- void Initialize() { is_null_ = false; }
-
+ friend class internal::InlinedStructPtrWTFHelper<Struct>;
void Take(InlinedStructPtr* other) {
reset();
Swap(other);
}
+ enum State {
+ VALID,
+ NIL,
+ DELETED, // For use in WTF::HashMap only
+ };
+
mutable Struct value_;
- bool is_null_;
+ State state_;
DISALLOW_COPY_AND_ASSIGN(InlinedStructPtr);
};
+template <typename T>
+bool operator==(const InlinedStructPtr<T>& lhs,
+ const InlinedStructPtr<T>& rhs) {
+ return lhs.Equals(rhs);
+}
+template <typename T>
+bool operator!=(const InlinedStructPtr<T>& lhs,
+ const InlinedStructPtr<T>& rhs) {
+ return !(lhs == rhs);
+}
+
+namespace internal {
+
+template <typename Struct>
+class StructPtrWTFHelper {
+ public:
+ static bool IsHashTableDeletedValue(const StructPtr<Struct>& value) {
+ return value.ptr_.get() == reinterpret_cast<Struct*>(1u);
+ }
+
+ static void ConstructDeletedValue(mojo::StructPtr<Struct>& slot) {
+ // |slot| refers to a previous, real value that got deleted and had its
+ // destructor run, so this is the first time the "deleted value" has its
+ // constructor called.
+ //
+ // Dirty trick: implant an invalid pointer in |ptr_|. Destructor isn't
+ // called for deleted buckets, so this is okay.
+ new (&slot) StructPtr<Struct>();
+ slot.ptr_.reset(reinterpret_cast<Struct*>(1u));
+ }
+};
+
+template <typename Struct>
+class InlinedStructPtrWTFHelper {
+ public:
+ static bool IsHashTableDeletedValue(const InlinedStructPtr<Struct>& value) {
+ return value.state_ == InlinedStructPtr<Struct>::DELETED;
+ }
+
+ static void ConstructDeletedValue(mojo::InlinedStructPtr<Struct>& slot) {
+ // |slot| refers to a previous, real value that got deleted and had its
+ // destructor run, so this is the first time the "deleted value" has its
+ // constructor called.
+ new (&slot) InlinedStructPtr<Struct>();
+ slot.state_ = InlinedStructPtr<Struct>::DELETED;
+ }
+};
+
+} // namespace internal
} // namespace mojo
+namespace std {
+
+template <typename T>
+struct hash<mojo::StructPtr<T>> {
+ size_t operator()(const mojo::StructPtr<T>& value) const {
+ return value.Hash(mojo::internal::kHashSeed);
+ }
+};
+
+template <typename T>
+struct hash<mojo::InlinedStructPtr<T>> {
+ size_t operator()(const mojo::InlinedStructPtr<T>& value) const {
+ return value.Hash(mojo::internal::kHashSeed);
+ }
+};
+
+} // namespace std
+
#endif // MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
diff --git a/mojo/public/cpp/bindings/struct_traits.h b/mojo/public/cpp/bindings/struct_traits.h
index 0f0bea7..6cc070f 100644
--- a/mojo/public/cpp/bindings/struct_traits.h
+++ b/mojo/public/cpp/bindings/struct_traits.h
@@ -8,7 +8,11 @@
namespace mojo {
// This must be specialized for any type |T| to be serialized/deserialized as
-// a mojom struct of type |MojomType|.
+// a mojom struct. |DataViewType| is the corresponding data view type of the
+// mojom struct. For example, if the mojom struct is example.Foo,
+// |DataViewType| will be example::FooDataView, which can also be referred to by
+// example::Foo::DataView (in chromium) and example::blink::Foo::DataView (in
+// blink).
//
// Each specialization needs to implement a few things:
// 1. Static getters for each field in the Mojom type. These should be
@@ -20,19 +24,21 @@ namespace mojo {
// from |input|.
//
// Serializable form of a field:
-// Value or reference of the same type used in |MojomType|, or the
-// following alternatives:
+// Value or reference of the same type used in the generated stuct
+// wrapper type, or the following alternatives:
// - string:
// Value or reference of any type that has a StringTraits defined.
-// Supported by default: base::StringPiece, std::string.
+// Supported by default: base::StringPiece, std::string,
+// WTF::String (in blink).
//
// - array:
// Value or reference of any type that has an ArrayTraits defined.
-// Supported by default: std::vector, WTF::Vector (in blink), CArray.
+// Supported by default: std::vector, CArray, WTF::Vector (in blink)
//
// - map:
// Value or reference of any type that has a MapTraits defined.
-// Supported by default: std::map.
+// Supported by default: std::map, std::unordered_map,
+// WTF::HashMap (in blink).
//
// - struct:
// Value or reference of any type that has a StructTraits defined.
@@ -40,6 +46,10 @@ namespace mojo {
// - enum:
// Value of any type that has an EnumTraits defined.
//
+// For any nullable string/struct/array/map/union field you could also
+// return value or reference of base::Optional<T>/WTF::Optional<T>, if T
+// has the right *Traits defined.
+//
// During serialization, getters for string/struct/array/map/union fields
// are called twice (one for size calculation and one for actual
// serialization). If you want to return a value (as opposed to a
@@ -49,13 +59,13 @@ namespace mojo {
// Getters for fields of other types are called once.
//
// 2. A static Read() method to set the contents of a |T| instance from a
-// |MojomType|DataView (e.g., if |MojomType| is test::Example, the data
-// view will be test::ExampleDataView).
+// DataViewType.
//
-// static bool Read(|MojomType|DataView data, T* output);
+// static bool Read(DataViewType data, T* output);
//
-// The generated |MojomType|DataView type provides a convenient,
-// inexpensive view of a serialized struct's field data.
+// The generated DataViewType provides a convenient, inexpensive view of a
+// serialized struct's field data. The caller guarantees that
+// |!data.is_null()|.
//
// Returning false indicates invalid incoming data and causes the message
// pipe receiving it to be disconnected. Therefore, you can do custom
@@ -111,9 +121,12 @@ namespace mojo {
// reference/value to the Mojo bindings for serialization:
// - if T is used in the "type_mappings" section of a typemap config file,
// you need to declare it as pass-by-value:
-// type_mappings = [ "MojomType=T(pass_by_value)" ]
-// - if another type U's StructTraits has a getter for T, it needs to return
-// non-const reference/value.
+// type_mappings = [ "MojomType=T[move_only]" ]
+// or
+// type_mappings = [ "MojomType=T[copyable_pass_by_value]" ]
+//
+// - if another type U's StructTraits/UnionTraits has a getter for T, it
+// needs to return non-const reference/value.
//
// EXAMPLE:
//
@@ -128,7 +141,7 @@ namespace mojo {
//
// StructTraits for Foo:
// template <>
-// struct StructTraits<Foo, CustomFoo> {
+// struct StructTraits<FooDataView, CustomFoo> {
// // Optional methods dealing with null:
// static bool IsNull(const CustomFoo& input);
// static void SetToNull(CustomFoo* output);
@@ -144,7 +157,7 @@ namespace mojo {
// static bool Read(FooDataView data, CustomFoo* output);
// };
//
-template <typename MojomType, typename T>
+template <typename DataViewType, typename T>
struct StructTraits;
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/sync_call_restrictions.h b/mojo/public/cpp/bindings/sync_call_restrictions.h
index e8fc1c4..39a77a8 100644
--- a/mojo/public/cpp/bindings/sync_call_restrictions.h
+++ b/mojo/public/cpp/bindings/sync_call_restrictions.h
@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "base/threading/thread_restrictions.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
#define ENABLE_SYNC_CALL_RESTRICTIONS 1
@@ -14,8 +15,12 @@
#define ENABLE_SYNC_CALL_RESTRICTIONS 0
#endif
+namespace leveldb {
+class LevelDBMojoProxy;
+}
+
namespace ui {
-class GpuService;
+class Gpu;
}
namespace views {
@@ -36,7 +41,7 @@ namespace mojo {
// a very compelling reason to disregard that (which should be very very rare),
// you can override it by constructing a ScopedAllowSyncCall object, which
// allows making sync calls on the current thread during its lifetime.
-class SyncCallRestrictions {
+class MOJO_CPP_BINDINGS_EXPORT SyncCallRestrictions {
public:
#if ENABLE_SYNC_CALL_RESTRICTIONS
// Checks whether the current thread is allowed to make sync calls, and causes
@@ -50,7 +55,9 @@ class SyncCallRestrictions {
private:
// DO NOT ADD ANY OTHER FRIEND STATEMENTS, talk to mojo/OWNERS first.
// BEGIN ALLOWED USAGE.
- friend class ui::GpuService; // http://crbug.com/620058
+ friend class ui::Gpu; // http://crbug.com/620058
+ // LevelDBMojoProxy makes same-process sync calls from the DB thread.
+ friend class leveldb::LevelDBMojoProxy;
// END ALLOWED USAGE.
// BEGIN USAGE THAT NEEDS TO BE FIXED.
diff --git a/mojo/public/cpp/bindings/sync_handle_registry.h b/mojo/public/cpp/bindings/sync_handle_registry.h
index 6c0701e..b5415af 100644
--- a/mojo/public/cpp/bindings/sync_handle_registry.h
+++ b/mojo/public/cpp/bindings/sync_handle_registry.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/system/core.h"
namespace mojo {
@@ -19,7 +20,8 @@ namespace mojo {
// be watched together.
//
// This class is not thread safe.
-class SyncHandleRegistry : public base::RefCounted<SyncHandleRegistry> {
+class MOJO_CPP_BINDINGS_EXPORT SyncHandleRegistry
+ : public base::RefCounted<SyncHandleRegistry> {
public:
// Returns a thread-local object.
static scoped_refptr<SyncHandleRegistry> current();
diff --git a/mojo/public/cpp/bindings/sync_handle_watcher.h b/mojo/public/cpp/bindings/sync_handle_watcher.h
index 36b796b..eff73dd 100644
--- a/mojo/public/cpp/bindings/sync_handle_watcher.h
+++ b/mojo/public/cpp/bindings/sync_handle_watcher.h
@@ -8,6 +8,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
#include "mojo/public/cpp/bindings/sync_handle_registry.h"
#include "mojo/public/cpp/system/core.h"
@@ -25,7 +26,7 @@ namespace mojo {
// associated endpoints on different threads.
//
// This class is not thread safe.
-class SyncHandleWatcher {
+class MOJO_CPP_BINDINGS_EXPORT SyncHandleWatcher {
public:
// Note: |handle| must outlive this object.
SyncHandleWatcher(const Handle& handle,
diff --git a/mojo/public/cpp/bindings/thread_safe_interface_ptr.h b/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
new file mode 100644
index 0000000..bab6d22
--- /dev/null
+++ b/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
@@ -0,0 +1,278 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "mojo/public/cpp/bindings/associated_group.h"
+#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/public/cpp/bindings/message.h"
+
+namespace mojo {
+
+// Instances of this class may be used from any thread to serialize |Interface|
+// messages and forward them elsewhere. In general you should use one of the
+// ThreadSafeInterfacePtrBase helper aliases defined below, but this type may be
+// useful if you need/want to manually manage the lifetime of the underlying
+// proxy object which will be used to ultimately send messages.
+template <typename Interface>
+class ThreadSafeForwarder : public MessageReceiverWithResponder {
+ public:
+ using ProxyType = typename Interface::Proxy_;
+ using ForwardMessageCallback = base::Callback<void(Message)>;
+ using ForwardMessageWithResponderCallback =
+ base::Callback<void(Message, std::unique_ptr<MessageReceiver>)>;
+
+ // Constructs a ThreadSafeForwarder through which Messages are forwarded to
+ // |forward| or |forward_with_responder| by posting to |task_runner|.
+ //
+ // Any message sent through this forwarding interface will dispatch its reply,
+ // if any, back to the thread which called the corresponding interface method.
+ ThreadSafeForwarder(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ const ForwardMessageCallback& forward,
+ const ForwardMessageWithResponderCallback& forward_with_responder,
+ const AssociatedGroup& associated_group)
+ : proxy_(this),
+ task_runner_(task_runner),
+ forward_(forward),
+ forward_with_responder_(forward_with_responder),
+ associated_group_(associated_group) {}
+
+ ~ThreadSafeForwarder() override {}
+
+ ProxyType& proxy() { return proxy_; }
+
+ private:
+ // MessageReceiverWithResponder implementation:
+ bool Accept(Message* message) override {
+ if (!message->associated_endpoint_handles()->empty()) {
+ // If this DCHECK fails, it is likely because:
+ // - This is a non-associated interface pointer setup using
+ // PtrWrapper::BindOnTaskRunner(
+ // InterfacePtrInfo<InterfaceType> ptr_info);
+ // Please see the TODO in that method.
+ // - This is an associated interface which hasn't been associated with a
+ // message pipe. In other words, the corresponding
+ // AssociatedInterfaceRequest hasn't been sent.
+ DCHECK(associated_group_.GetController());
+ message->SerializeAssociatedEndpointHandles(
+ associated_group_.GetController());
+ }
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(forward_, base::Passed(message)));
+ return true;
+ }
+
+ bool AcceptWithResponder(Message* message,
+ MessageReceiver* response_receiver) override {
+ if (!message->associated_endpoint_handles()->empty()) {
+ // Please see comment for the DCHECK in the previous method.
+ DCHECK(associated_group_.GetController());
+ message->SerializeAssociatedEndpointHandles(
+ associated_group_.GetController());
+ }
+ auto responder = base::MakeUnique<ForwardToCallingThread>(
+ base::WrapUnique(response_receiver));
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(forward_with_responder_, base::Passed(message),
+ base::Passed(&responder)));
+ return true;
+ }
+
+ class ForwardToCallingThread : public MessageReceiver {
+ public:
+ explicit ForwardToCallingThread(std::unique_ptr<MessageReceiver> responder)
+ : responder_(std::move(responder)),
+ caller_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
+ }
+
+ private:
+ bool Accept(Message* message) {
+ // The current instance will be deleted when this method returns, so we
+ // have to relinquish the responder's ownership so it does not get
+ // deleted.
+ caller_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&ForwardToCallingThread::CallAcceptAndDeleteResponder,
+ base::Passed(std::move(responder_)),
+ base::Passed(std::move(*message))));
+ return true;
+ }
+
+ static void CallAcceptAndDeleteResponder(
+ std::unique_ptr<MessageReceiver> responder,
+ Message message) {
+ ignore_result(responder->Accept(&message));
+ }
+
+ std::unique_ptr<MessageReceiver> responder_;
+ scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
+ };
+
+ ProxyType proxy_;
+ const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ const ForwardMessageCallback forward_;
+ const ForwardMessageWithResponderCallback forward_with_responder_;
+ AssociatedGroup associated_group_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadSafeForwarder);
+};
+
+template <typename InterfacePtrType>
+class ThreadSafeInterfacePtrBase
+ : public base::RefCountedThreadSafe<
+ ThreadSafeInterfacePtrBase<InterfacePtrType>> {
+ public:
+ using InterfaceType = typename InterfacePtrType::InterfaceType;
+ using PtrInfoType = typename InterfacePtrType::PtrInfoType;
+
+ explicit ThreadSafeInterfacePtrBase(
+ std::unique_ptr<ThreadSafeForwarder<InterfaceType>> forwarder)
+ : forwarder_(std::move(forwarder)) {}
+
+ // Creates a ThreadSafeInterfacePtrBase wrapping an underlying non-thread-safe
+ // InterfacePtrType which is bound to the calling thread. All messages sent
+ // via this thread-safe proxy will internally be sent by first posting to this
+ // (the calling) thread's TaskRunner.
+ static scoped_refptr<ThreadSafeInterfacePtrBase> Create(
+ InterfacePtrType interface_ptr) {
+ scoped_refptr<PtrWrapper> wrapper =
+ new PtrWrapper(std::move(interface_ptr));
+ return new ThreadSafeInterfacePtrBase(wrapper->CreateForwarder());
+ }
+
+ // Creates a ThreadSafeInterfacePtrBase which binds the underlying
+ // non-thread-safe InterfacePtrType on the specified TaskRunner. All messages
+ // sent via this thread-safe proxy will internally be sent by first posting to
+ // that TaskRunner.
+ static scoped_refptr<ThreadSafeInterfacePtrBase> Create(
+ PtrInfoType ptr_info,
+ const scoped_refptr<base::SingleThreadTaskRunner>& bind_task_runner) {
+ scoped_refptr<PtrWrapper> wrapper = new PtrWrapper(bind_task_runner);
+ wrapper->BindOnTaskRunner(std::move(ptr_info));
+ return new ThreadSafeInterfacePtrBase(wrapper->CreateForwarder());
+ }
+
+ InterfaceType* get() { return &forwarder_->proxy(); }
+ InterfaceType* operator->() { return get(); }
+ InterfaceType& operator*() { return *get(); }
+
+ private:
+ friend class base::RefCountedThreadSafe<
+ ThreadSafeInterfacePtrBase<InterfacePtrType>>;
+
+ struct PtrWrapperDeleter;
+
+ // Helper class which owns an |InterfacePtrType| instance on an appropriate
+ // thread. This is kept alive as long its bound within some
+ // ThreadSafeForwarder's callbacks.
+ class PtrWrapper
+ : public base::RefCountedThreadSafe<PtrWrapper, PtrWrapperDeleter> {
+ public:
+ explicit PtrWrapper(InterfacePtrType ptr)
+ : PtrWrapper(base::ThreadTaskRunnerHandle::Get()) {
+ ptr_ = std::move(ptr);
+ associated_group_ = *ptr_.internal_state()->associated_group();
+ }
+
+ explicit PtrWrapper(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
+ : task_runner_(task_runner) {}
+
+ void BindOnTaskRunner(AssociatedInterfacePtrInfo<InterfaceType> ptr_info) {
+ associated_group_ = AssociatedGroup(ptr_info.handle());
+ task_runner_->PostTask(FROM_HERE, base::Bind(&PtrWrapper::Bind, this,
+ base::Passed(&ptr_info)));
+ }
+
+ void BindOnTaskRunner(InterfacePtrInfo<InterfaceType> ptr_info) {
+ // TODO(yzhsen): At the momment we don't have a group controller
+ // available. That means the user won't be able to pass associated
+ // endpoints on this interface (at least not immediately). In order to fix
+ // this, we need to create a MultiplexRouter immediately and bind it to
+ // the interface pointer on the |task_runner_|. Therefore, MultiplexRouter
+ // should be able to be created on a thread different than the one that it
+ // is supposed to listen on. crbug.com/682334
+ task_runner_->PostTask(FROM_HERE, base::Bind(&PtrWrapper::Bind, this,
+ base::Passed(&ptr_info)));
+ }
+
+ std::unique_ptr<ThreadSafeForwarder<InterfaceType>> CreateForwarder() {
+ return base::MakeUnique<ThreadSafeForwarder<InterfaceType>>(
+ task_runner_, base::Bind(&PtrWrapper::Accept, this),
+ base::Bind(&PtrWrapper::AcceptWithResponder, this),
+ associated_group_);
+ }
+
+ private:
+ friend struct PtrWrapperDeleter;
+
+ ~PtrWrapper() {}
+
+ void Bind(PtrInfoType ptr_info) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+ ptr_.Bind(std::move(ptr_info));
+ }
+
+ void Accept(Message message) {
+ ptr_.internal_state()->ForwardMessage(std::move(message));
+ }
+
+ void AcceptWithResponder(Message message,
+ std::unique_ptr<MessageReceiver> responder) {
+ ptr_.internal_state()->ForwardMessageWithResponder(std::move(message),
+ std::move(responder));
+ }
+
+ void DeleteOnCorrectThread() const {
+ if (!task_runner_->RunsTasksOnCurrentThread()) {
+ // NOTE: This is only called when there are no more references to
+ // |this|, so binding it unretained is both safe and necessary.
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&PtrWrapper::DeleteOnCorrectThread,
+ base::Unretained(this)));
+ } else {
+ delete this;
+ }
+ }
+
+ InterfacePtrType ptr_;
+ const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ AssociatedGroup associated_group_;
+
+ DISALLOW_COPY_AND_ASSIGN(PtrWrapper);
+ };
+
+ struct PtrWrapperDeleter {
+ static void Destruct(const PtrWrapper* interface_ptr) {
+ interface_ptr->DeleteOnCorrectThread();
+ }
+ };
+
+ ~ThreadSafeInterfacePtrBase() {}
+
+ const std::unique_ptr<ThreadSafeForwarder<InterfaceType>> forwarder_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadSafeInterfacePtrBase);
+};
+
+template <typename Interface>
+using ThreadSafeAssociatedInterfacePtr =
+ ThreadSafeInterfacePtrBase<AssociatedInterfacePtr<Interface>>;
+
+template <typename Interface>
+using ThreadSafeInterfacePtr =
+ ThreadSafeInterfacePtrBase<InterfacePtr<Interface>>;
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_
diff --git a/mojo/public/cpp/bindings/type_converter.h b/mojo/public/cpp/bindings/type_converter.h
index 1446ab3..395eeb4 100644
--- a/mojo/public/cpp/bindings/type_converter.h
+++ b/mojo/public/cpp/bindings/type_converter.h
@@ -7,8 +7,15 @@
#include <stdint.h>
+#include <vector>
+
namespace mojo {
+// NOTE: TypeConverter is deprecated. Please consider StructTraits /
+// UnionTraits / EnumTraits / ArrayTraits / MapTraits / StringTraits if you
+// would like to convert between custom types and the wire format of mojom
+// types.
+//
// Specialize the following class:
// template <typename T, typename U> struct TypeConverter;
// to perform type conversion for Mojom-defined structs and arrays. Here, T is
@@ -74,6 +81,9 @@ namespace mojo {
template <typename T, typename U>
struct TypeConverter;
+template <typename T, typename U>
+inline T ConvertTo(const U& obj);
+
// The following specialization is useful when you are converting between
// Array<POD> and std::vector<POD>.
template <typename T>
@@ -81,6 +91,18 @@ struct TypeConverter<T, T> {
static T Convert(const T& obj) { return obj; }
};
+template <typename T, typename Container>
+struct TypeConverter<std::vector<T>, Container> {
+ static std::vector<T> Convert(const Container& container) {
+ std::vector<T> output;
+ output.reserve(container.size());
+ for (const auto& obj : container) {
+ output.push_back(ConvertTo<T>(obj));
+ }
+ return output;
+ }
+};
+
// The following helper function is useful for shorthand. The compiler can infer
// the input type, so you can write:
// OutputType out = ConvertTo<OutputType>(input);
diff --git a/mojo/public/cpp/bindings/union_traits.h b/mojo/public/cpp/bindings/union_traits.h
new file mode 100644
index 0000000..292ee58
--- /dev/null
+++ b/mojo/public/cpp/bindings/union_traits.h
@@ -0,0 +1,39 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_UNION_TRAITS_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_UNION_TRAITS_H_
+
+namespace mojo {
+
+// This must be specialized for any type |T| to be serialized/deserialized as
+// a mojom union. |DataViewType| is the corresponding data view type of the
+// mojom union. For example, if the mojom union is example.Foo, |DataViewType|
+// will be example::FooDataView, which can also be referred to by
+// example::Foo::DataView (in chromium) and example::blink::Foo::DataView (in
+// blink).
+//
+// Similar to StructTraits, each specialization of UnionTraits implements the
+// following methods:
+// 1. Getters for each field in the Mojom type.
+// 2. Read() method.
+// 3. [Optional] IsNull() and SetToNull().
+// 4. [Optional] SetUpContext() and TearDownContext().
+// Please see the documentation of StructTraits for details of these methods.
+//
+// Unlike StructTraits, there is one more method to implement:
+// 5. A static GetTag() method indicating which field is the current active
+// field for serialization:
+//
+// static DataViewType::Tag GetTag(const T& input);
+//
+// During serialization, only the field getter corresponding to this tag
+// will be called.
+//
+template <typename DataViewType, typename T>
+struct UnionTraits;
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_UNION_TRAITS_H_
diff --git a/mojo/public/cpp/bindings/wtf_array.h b/mojo/public/cpp/bindings/wtf_array.h
deleted file mode 100644
index 46d9a69..0000000
--- a/mojo/public/cpp/bindings/wtf_array.h
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_WTF_ARRAY_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_WTF_ARRAY_H_
-
-#include <stddef.h>
-#include <utility>
-
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/lib/array_internal.h"
-#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
-#include "mojo/public/cpp/bindings/lib/template_util.h"
-#include "mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h"
-#include "mojo/public/cpp/bindings/type_converter.h"
-#include "third_party/WebKit/Source/wtf/Vector.h"
-
-namespace mojo {
-
-// Represents an array backed by WTF::Vector. Comparing with WTF::Vector,
-// mojo::WTFArray is move-only and can be null.
-// It is easy to convert between WTF::Vector<T> and mojo::WTFArray<T>:
-// - constructor WTFArray(WTF::Vector<T>&&) takes the contents of a
-// WTF::Vector<T>;
-// - method PassStorage() passes the underlying WTF::Vector.
-template <typename T>
-class WTFArray {
- public:
- // Constructs an empty array.
- WTFArray() : is_null_(false) {}
- // Constructs a null array.
- WTFArray(std::nullptr_t null_pointer) : is_null_(true) {}
-
- // Constructs a new non-null array of the specified size. The elements will
- // be value-initialized (meaning that they will be initialized by their
- // default constructor, if any, or else zero-initialized).
- explicit WTFArray(size_t size) : vec_(size), is_null_(false) {}
- ~WTFArray() {}
-
- // Moves the contents of |other| into this array.
- WTFArray(WTF::Vector<T>&& other) : vec_(std::move(other)), is_null_(false) {}
- WTFArray(WTFArray&& other) : is_null_(true) { Take(&other); }
-
- WTFArray& operator=(WTF::Vector<T>&& other) {
- vec_ = std::move(other);
- is_null_ = false;
- return *this;
- }
- WTFArray& operator=(WTFArray&& other) {
- Take(&other);
- return *this;
- }
-
- WTFArray& operator=(std::nullptr_t null_pointer) {
- is_null_ = true;
- vec_.clear();
- return *this;
- }
-
- // Creates a non-null array of the specified size. The elements will be
- // value-initialized (meaning that they will be initialized by their default
- // constructor, if any, or else zero-initialized).
- static WTFArray New(size_t size) { return WTFArray(size); }
-
- // Creates a new array with a copy of the contents of |other|.
- template <typename U>
- static WTFArray From(const U& other) {
- return TypeConverter<WTFArray, U>::Convert(other);
- }
-
- // Copies the contents of this array to a new object of type |U|.
- template <typename U>
- U To() const {
- return TypeConverter<U, WTFArray>::Convert(*this);
- }
-
- // Indicates whether the array is null (which is distinct from empty).
- bool is_null() const {
- // When the array is set to null, the underlying storage |vec_| shouldn't
- // contain any elements.
- DCHECK(!is_null_ || vec_.isEmpty());
- return is_null_;
- }
-
- // Indicates whether the array is empty (which is distinct from null).
- bool empty() const { return vec_.isEmpty() && !is_null_; }
-
- // Returns a reference to the first element of the array. Calling this on a
- // null or empty array causes undefined behavior.
- const T& front() const { return vec_.first(); }
- T& front() { return vec_.first(); }
-
- // Returns the size of the array, which will be zero if the array is null.
- size_t size() const { return vec_.size(); }
-
- // Returns a reference to the element at zero-based |offset|. Calling this on
- // an array with size less than |offset|+1 causes undefined behavior.
- const T& at(size_t offset) const { return vec_.at(offset); }
- const T& operator[](size_t offset) const { return at(offset); }
- T& at(size_t offset) { return vec_.at(offset); }
- T& operator[](size_t offset) { return at(offset); }
-
- // Resizes the array to |size| and makes it non-null. Otherwise, works just
- // like the resize method of |WTF::Vector|.
- void resize(size_t size) {
- is_null_ = false;
- vec_.resize(size);
- }
-
- // Sets the array to empty (even if previously it was null.)
- void SetToEmpty() { resize(0); }
-
- // Returns a const reference to the |WTF::Vector| managed by this class. If
- // the array is null, this will be an empty vector.
- const WTF::Vector<T>& storage() const { return vec_; }
-
- // Passes the underlying storage and resets this array to null.
- //
- // TODO(yzshen): Consider changing this to a rvalue-ref-qualified conversion
- // to WTF::Vector<T> after we move to MSVC 2015.
- WTF::Vector<T> PassStorage() {
- is_null_ = true;
- return std::move(vec_);
- }
-
- void Swap(WTFArray* other) {
- std::swap(is_null_, other->is_null_);
- vec_.swap(other->vec_);
- }
-
- // Swaps the contents of this array with the specified vector, making this
- // array non-null. Since the vector cannot represent null, it will just be
- // made empty if this array is null.
- void Swap(WTF::Vector<T>* other) {
- is_null_ = false;
- vec_.swap(*other);
- }
-
- // Returns a copy of the array where each value of the new array has been
- // "cloned" from the corresponding value of this array. If the element type
- // defines a Clone() method, it will be used; otherwise copy
- // constructor/assignment will be used.
- //
- // Please note that calling this method will fail compilation if the element
- // type cannot be cloned (which usually means that it is a Mojo handle type or
- // a type containing Mojo handles).
- WTFArray Clone() const {
- WTFArray result;
- result.is_null_ = is_null_;
- result.vec_ = internal::Clone(vec_);
- return result;
- }
-
- // Indicates whether the contents of this array are equal to |other|. A null
- // array is only equal to another null array. If the element type defines an
- // Equals() method, it will be used; otherwise == operator will be used.
- bool Equals(const WTFArray& other) const {
- if (is_null() != other.is_null())
- return false;
- return internal::Equals(vec_, other.vec_);
- }
-
- private:
- // TODO(dcheng): Use an explicit conversion operator.
- typedef WTF::Vector<T> WTFArray::*Testable;
-
- public:
- operator Testable() const {
- // When the array is set to null, the underlying storage |vec_| shouldn't
- // contain any elements.
- DCHECK(!is_null_ || vec_.isEmpty());
- return is_null_ ? 0 : &WTFArray::vec_;
- }
-
- private:
- // Forbid the == and != operators explicitly, otherwise WTFArray will be
- // converted to Testable to do == or != comparison.
- template <typename U>
- bool operator==(const WTFArray<U>& other) const = delete;
- template <typename U>
- bool operator!=(const WTFArray<U>& other) const = delete;
-
- void Take(WTFArray* other) {
- operator=(nullptr);
- Swap(other);
- }
-
- WTF::Vector<T> vec_;
- bool is_null_;
-
- DISALLOW_COPY_AND_ASSIGN(WTFArray);
-};
-
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_WTF_ARRAY_H_
diff --git a/mojo/public/cpp/bindings/wtf_map.h b/mojo/public/cpp/bindings/wtf_map.h
deleted file mode 100644
index 0aba959..0000000
--- a/mojo/public/cpp/bindings/wtf_map.h
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_WTF_MAP_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_WTF_MAP_H_
-
-#include <stddef.h>
-#include <utility>
-
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/lib/template_util.h"
-#include "mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h"
-#include "mojo/public/cpp/bindings/type_converter.h"
-#include "third_party/WebKit/Source/wtf/HashMap.h"
-#include "third_party/WebKit/Source/wtf/text/StringHash.h"
-
-namespace mojo {
-
-// Represents a map backed by WTF::HashMap. Comparing with WTF::HashMap,
-// mojo::WTFMap is move-only and can be null.
-//
-// It is easy to convert between WTF::HashMap<K, V> and mojo::WTFMap<K, V>:
-// - constructor WTFMap(WTF::HashMap<K, V>&&) takes the contents of a
-// WTF::HashMap<K, V>;
-// - method PassStorage() passes the underlying WTF::HashMap.
-//
-// NOTE: WTF::HashMap disallows certain key values. For integer types, those are
-// 0 and -1 (max value instead of -1 for unsigned). For string, that is null.
-template <typename Key, typename Value>
-class WTFMap {
- public:
- using Iterator = typename WTF::HashMap<Key, Value>::iterator;
- using ConstIterator = typename WTF::HashMap<Key, Value>::const_iterator;
-
- // Constructs an empty map.
- WTFMap() : is_null_(false) {}
- // Constructs a null map.
- WTFMap(std::nullptr_t null_pointer) : is_null_(true) {}
-
- ~WTFMap() {}
-
- WTFMap(WTF::HashMap<Key, Value>&& other)
- : map_(std::move(other)), is_null_(false) {}
- WTFMap(WTFMap&& other) : is_null_(true) { Take(&other); }
-
- WTFMap& operator=(WTF::HashMap<Key, Value>&& other) {
- is_null_ = false;
- map_ = std::move(other);
- return *this;
- }
- WTFMap& operator=(WTFMap&& other) {
- Take(&other);
- return *this;
- }
-
- WTFMap& operator=(std::nullptr_t null_pointer) {
- is_null_ = true;
- map_.clear();
- return *this;
- }
-
- static bool IsValidKey(const Key& key) {
- return WTF::HashMap<Key, Value>::isValidKey(key);
- }
-
- // Copies the contents of some other type of map into a new WTFMap using a
- // TypeConverter.
- template <typename U>
- static WTFMap From(const U& other) {
- return TypeConverter<WTFMap, U>::Convert(other);
- }
-
- // Copies the contents of the WTFMap into some other type of map.
- template <typename U>
- U To() const {
- return TypeConverter<U, WTFMap>::Convert(*this);
- }
-
- // Indicates whether the map is null (which is distinct from empty).
- bool is_null() const { return is_null_; }
-
- // Indicates whether the map is empty (which is distinct from null).
- bool empty() const { return map_.isEmpty() && !is_null_; }
-
- // Indicates the number of keys in the map, which will be zero if the map is
- // null.
- size_t size() const { return map_.size(); }
-
- // Inserts a key-value pair into the map. Like WTF::HashMap::add(), this does
- // not insert |value| if |key| is already a member of the map.
- void insert(const Key& key, const Value& value) {
- is_null_ = false;
- map_.add(key, value);
- }
- void insert(const Key& key, Value&& value) {
- is_null_ = false;
- map_.add(key, std::move(value));
- }
-
- // Returns a reference to the value associated with the specified key,
- // crashing the process if the key is not present in the map.
- Value& at(const Key& key) { return map_.find(key)->value; }
- const Value& at(const Key& key) const { return map_.find(key)->value; }
-
- // Returns a reference to the value associated with the specified key,
- // creating a new entry if the key is not already present in the map. A
- // newly-created value will be value-initialized (meaning that it will be
- // initialized by the default constructor of the value type, if any, or else
- // will be zero-initialized).
- Value& operator[](const Key& key) {
- is_null_ = false;
- if (!map_.contains(key))
- map_.add(key, Value());
- return at(key);
- }
-
- // Sets the map to empty (even if previously it was null).
- void SetToEmpty() {
- is_null_ = false;
- map_.clear();
- }
-
- // Returns a const reference to the WTF::HashMap managed by this class. If
- // this object is null, the return value will be an empty map.
- const WTF::HashMap<Key, Value>& storage() const { return map_; }
-
- // Passes the underlying storage and resets this map to null.
- WTF::HashMap<Key, Value> PassStorage() {
- is_null_ = true;
- return std::move(map_);
- }
-
- // Swaps the contents of this WTFMap with another WTFMap of the same type
- // (including nullness).
- void Swap(WTFMap<Key, Value>* other) {
- std::swap(is_null_, other->is_null_);
- map_.swap(other->map_);
- }
-
- // Swaps the contents of this WTFMap with an WTF::HashMap containing keys and
- // values of the same type. Since WTF::HashMap cannot represent the null
- // state, the WTF::HashMap will be empty if WTFMap is null. The WTFMap will
- // always be left in a non-null state.
- void Swap(WTF::HashMap<Key, Value>* other) {
- is_null_ = false;
- map_.swap(*other);
- }
-
- // Returns a new WTFMap that contains a copy of the contents of this map. If
- // the key/value type defines a Clone() method, it will be used; otherwise
- // copy constructor/assignment will be used.
- //
- // Please note that calling this method will fail compilation if the key/value
- // type cannot be cloned (which usually means that it is a Mojo handle type or
- // a type containing Mojo handles).
- WTFMap Clone() const {
- WTFMap result;
- result.is_null_ = is_null_;
- result.map_ = internal::Clone(map_);
- return result;
- }
-
- // Indicates whether the contents of this map are equal to those of another
- // WTFMap (including nullness). If the key/value type defines an Equals()
- // method, it will be used; otherwise == operator will be used.
- bool Equals(const WTFMap& other) const {
- if (is_null() != other.is_null())
- return false;
- return internal::Equals(map_, other.map_);
- }
-
- ConstIterator begin() const { return map_.begin(); }
- Iterator begin() { return map_.begin(); }
-
- ConstIterator end() const { return map_.end(); }
- Iterator end() { return map_.end(); }
-
- // Returns the iterator pointing to the entry for |key|, if present, or else
- // returns end().
- ConstIterator find(const Key& key) const { return map_.find(key); }
- Iterator find(const Key& key) { return map_.find(key); }
-
- explicit operator bool() const { return !is_null_; }
-
- private:
- void Take(WTFMap* other) {
- operator=(nullptr);
- Swap(other);
- }
-
- WTF::HashMap<Key, Value> map_;
- bool is_null_;
-
- DISALLOW_COPY_AND_ASSIGN(WTFMap);
-};
-
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_BINDINGS_WTF_MAP_H_
diff --git a/mojo/public/cpp/system/BUILD.gn b/mojo/public/cpp/system/BUILD.gn
index 8dcec71..0dc7af9 100644
--- a/mojo/public/cpp/system/BUILD.gn
+++ b/mojo/public/cpp/system/BUILD.gn
@@ -2,7 +2,26 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("system") {
+# Deletes libsystem.dylib from the build dir, since it shadows
+# /usr/lib/libSystem.dylib on macOS.
+# TODO(thakis): Remove this after a while.
+action("clean_up_old_dylib") {
+ script = "//build/rm.py"
+ stamp = "$target_gen_dir/clean_up_stamp"
+ outputs = [
+ stamp,
+ ]
+ args = [
+ "--stamp",
+ rebase_path(stamp, root_build_dir),
+ "-f",
+ "libsystem.dylib",
+ ]
+}
+
+component("system") {
+ output_name = "mojo_public_system_cpp"
+
sources = [
"buffer.cc",
"buffer.h",
@@ -14,6 +33,7 @@ source_set("system") {
"message_pipe.h",
"platform_handle.cc",
"platform_handle.h",
+ "system_export.h",
"watcher.cc",
"watcher.h",
]
@@ -22,4 +42,9 @@ source_set("system") {
"//base",
"//mojo/public/c/system",
]
+ deps = [
+ ":clean_up_old_dylib",
+ ]
+
+ defines = [ "MOJO_CPP_SYSTEM_IMPLEMENTATION" ]
}
diff --git a/mojo/public/cpp/system/buffer.h b/mojo/public/cpp/system/buffer.h
index 449c6ce..1ae923c 100644
--- a/mojo/public/cpp/system/buffer.h
+++ b/mojo/public/cpp/system/buffer.h
@@ -20,6 +20,7 @@
#include "base/logging.h"
#include "mojo/public/c/system/buffer.h"
#include "mojo/public/cpp/system/handle.h"
+#include "mojo/public/cpp/system/system_export.h"
namespace mojo {
namespace internal {
@@ -41,7 +42,8 @@ typedef ScopedHandleBase<SharedBufferHandle> ScopedSharedBufferHandle;
// A strongly-typed representation of a |MojoHandle| referring to a shared
// buffer.
-class SharedBufferHandle : public Handle {
+class MOJO_CPP_SYSTEM_EXPORT SharedBufferHandle
+ : NON_EXPORTED_BASE(public Handle) {
public:
enum class AccessMode {
READ_WRITE,
diff --git a/mojo/public/cpp/system/platform_handle.cc b/mojo/public/cpp/system/platform_handle.cc
index e4a6088..42e4aba 100644
--- a/mojo/public/cpp/system/platform_handle.cc
+++ b/mojo/public/cpp/system/platform_handle.cc
@@ -4,6 +4,11 @@
#include "mojo/public/cpp/system/platform_handle.h"
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include <mach/mach.h>
+#include "base/mac/mach_logging.h"
+#endif
+
namespace mojo {
namespace {
@@ -61,6 +66,13 @@ ScopedSharedBufferHandle WrapSharedMemoryHandle(
const base::SharedMemoryHandle& memory_handle,
size_t size,
bool read_only) {
+#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+ if (memory_handle.fd == base::kInvalidPlatformFile)
+ return ScopedSharedBufferHandle();
+#else
+ if (!memory_handle.IsValid())
+ return ScopedSharedBufferHandle();
+#endif
MojoPlatformHandle platform_handle;
platform_handle.struct_size = sizeof(MojoPlatformHandle);
platform_handle.type = kPlatformSharedBufferHandleType;
@@ -91,6 +103,8 @@ MojoResult UnwrapSharedMemoryHandle(ScopedSharedBufferHandle handle,
base::SharedMemoryHandle* memory_handle,
size_t* size,
bool* read_only) {
+ if (!handle.is_valid())
+ return MOJO_RESULT_INVALID_ARGUMENT;
MojoPlatformHandle platform_handle;
platform_handle.struct_size = sizeof(MojoPlatformHandle);
@@ -126,4 +140,39 @@ MojoResult UnwrapSharedMemoryHandle(ScopedSharedBufferHandle handle,
return MOJO_RESULT_OK;
}
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ScopedHandle WrapMachPort(mach_port_t port) {
+ kern_return_t kr =
+ mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, 1);
+ MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+ << "MachPortAttachmentMac mach_port_mod_refs";
+ if (kr != KERN_SUCCESS)
+ return ScopedHandle();
+
+ MojoPlatformHandle platform_handle;
+ platform_handle.struct_size = sizeof(MojoPlatformHandle);
+ platform_handle.type = MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT;
+ platform_handle.value = static_cast<uint64_t>(port);
+
+ MojoHandle mojo_handle;
+ MojoResult result = MojoWrapPlatformHandle(&platform_handle, &mojo_handle);
+ CHECK_EQ(result, MOJO_RESULT_OK);
+
+ return ScopedHandle(Handle(mojo_handle));
+}
+
+MojoResult UnwrapMachPort(ScopedHandle handle, mach_port_t* port) {
+ MojoPlatformHandle platform_handle;
+ platform_handle.struct_size = sizeof(MojoPlatformHandle);
+ MojoResult result =
+ MojoUnwrapPlatformHandle(handle.release().value(), &platform_handle);
+ if (result != MOJO_RESULT_OK)
+ return result;
+
+ CHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT);
+ *port = static_cast<mach_port_t>(platform_handle.value);
+ return MOJO_RESULT_OK;
+}
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
} // namespace mojo
diff --git a/mojo/public/cpp/system/platform_handle.h b/mojo/public/cpp/system/platform_handle.h
index 2a81734..801264e 100644
--- a/mojo/public/cpp/system/platform_handle.h
+++ b/mojo/public/cpp/system/platform_handle.h
@@ -22,6 +22,7 @@
#include "mojo/public/c/system/platform_handle.h"
#include "mojo/public/cpp/system/buffer.h"
#include "mojo/public/cpp/system/handle.h"
+#include "mojo/public/cpp/system/system_export.h"
#if defined(OS_WIN)
#include <windows.h>
@@ -50,15 +51,18 @@ const MojoPlatformHandleType kPlatformSharedBufferHandleType =
#endif // defined(OS_POSIX)
// Wraps a PlatformFile as a Mojo handle. Takes ownership of the file object.
+MOJO_CPP_SYSTEM_EXPORT
ScopedHandle WrapPlatformFile(base::PlatformFile platform_file);
// Unwraps a PlatformFile from a Mojo handle.
+MOJO_CPP_SYSTEM_EXPORT
MojoResult UnwrapPlatformFile(ScopedHandle handle, base::PlatformFile* file);
// Wraps a base::SharedMemoryHandle as a Mojo handle. Takes ownership of the
// SharedMemoryHandle. Note that |read_only| is only an indicator of whether
// |memory_handle| only supports read-only mapping. It does NOT have any
// influence on the access control of the shared buffer object.
+MOJO_CPP_SYSTEM_EXPORT
ScopedSharedBufferHandle WrapSharedMemoryHandle(
const base::SharedMemoryHandle& memory_handle,
size_t size,
@@ -66,10 +70,22 @@ ScopedSharedBufferHandle WrapSharedMemoryHandle(
// Unwraps a base::SharedMemoryHandle from a Mojo handle. The caller assumes
// responsibility for the lifetime of the SharedMemoryHandle.
-MojoResult UnwrapSharedMemoryHandle(ScopedSharedBufferHandle handle,
- base::SharedMemoryHandle* memory_handle,
- size_t* size,
- bool* read_only);
+MOJO_CPP_SYSTEM_EXPORT MojoResult
+UnwrapSharedMemoryHandle(ScopedSharedBufferHandle handle,
+ base::SharedMemoryHandle* memory_handle,
+ size_t* size,
+ bool* read_only);
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+// Wraps a mach_port_t as a Mojo handle. This takes a reference to the
+// Mach port.
+MOJO_CPP_SYSTEM_EXPORT ScopedHandle WrapMachPort(mach_port_t port);
+
+// Unwraps a mach_port_t from a Mojo handle. The caller gets ownership of the
+// Mach port.
+MOJO_CPP_SYSTEM_EXPORT MojoResult UnwrapMachPort(ScopedHandle handle,
+ mach_port_t* port);
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
} // namespace mojo
diff --git a/mojo/public/cpp/system/system_export.h b/mojo/public/cpp/system/system_export.h
new file mode 100644
index 0000000..c9bb140
--- /dev/null
+++ b/mojo/public/cpp/system/system_export.h
@@ -0,0 +1,34 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_SYSTEM_SYSTEM_EXPORT_H_
+#define MOJO_PUBLIC_CPP_SYSTEM_SYSTEM_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(WIN32)
+
+#if defined(MOJO_CPP_SYSTEM_IMPLEMENTATION)
+#define MOJO_CPP_SYSTEM_EXPORT __declspec(dllexport)
+#else
+#define MOJO_CPP_SYSTEM_EXPORT __declspec(dllimport)
+#endif
+
+#else // !defined(WIN32)
+
+#if defined(MOJO_CPP_SYSTEM_IMPLEMENTATION)
+#define MOJO_CPP_SYSTEM_EXPORT __attribute((visibility("default")))
+#else
+#define MOJO_CPP_SYSTEM_EXPORT
+#endif
+
+#endif // defined(WIN32)
+
+#else // !defined(COMPONENT_BUILD)
+
+#define MOJO_CPP_SYSTEM_EXPORT
+
+#endif // defined(COMPONENT_BUILD)
+
+#endif // MOJO_PUBLIC_CPP_SYSTEM_SYSTEM_EXPORT_H_
diff --git a/mojo/public/cpp/system/watcher.cc b/mojo/public/cpp/system/watcher.cc
index d9319fb..55dcf40 100644
--- a/mojo/public/cpp/system/watcher.cc
+++ b/mojo/public/cpp/system/watcher.cc
@@ -7,49 +7,17 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/trace_event/heap_profiler.h"
#include "mojo/public/c/system/functions.h"
namespace mojo {
-class Watcher::MessageLoopObserver
- : public base::MessageLoop::DestructionObserver {
- public:
- explicit MessageLoopObserver(Watcher* watcher) : watcher_(watcher) {
- base::MessageLoop::current()->AddDestructionObserver(this);
- }
-
- ~MessageLoopObserver() override {
- StopObservingIfNecessary();
- }
-
- private:
- // base::MessageLoop::DestructionObserver:
- void WillDestroyCurrentMessageLoop() override {
- StopObservingIfNecessary();
- if (watcher_->IsWatching()) {
- // TODO(yzshen): Remove this notification. crbug.com/604762
- watcher_->OnHandleReady(MOJO_RESULT_ABORTED);
- }
- }
-
- void StopObservingIfNecessary() {
- if (is_observing_) {
- is_observing_ = false;
- base::MessageLoop::current()->RemoveDestructionObserver(this);
- }
- }
-
- bool is_observing_ = true;
- Watcher* watcher_;
-
- DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver);
-};
-
-Watcher::Watcher(scoped_refptr<base::SingleThreadTaskRunner> runner)
+Watcher::Watcher(const tracked_objects::Location& from_here,
+ scoped_refptr<base::SingleThreadTaskRunner> runner)
: task_runner_(std::move(runner)),
is_default_task_runner_(task_runner_ ==
base::ThreadTaskRunnerHandle::Get()),
+ heap_profiler_tag_(from_here.file_name()),
weak_factory_(this) {
DCHECK(task_runner_->BelongsToCurrentThread());
weak_self_ = weak_factory_.GetWeakPtr();
@@ -72,7 +40,6 @@ MojoResult Watcher::Start(Handle handle,
DCHECK(!IsWatching());
DCHECK(!callback.is_null());
- message_loop_observer_.reset(new MessageLoopObserver(this));
callback_ = callback;
handle_ = handle;
MojoResult result = MojoWatch(handle_.value(), signals,
@@ -81,7 +48,6 @@ MojoResult Watcher::Start(Handle handle,
if (result != MOJO_RESULT_OK) {
handle_.set_value(kInvalidHandleValue);
callback_.Reset();
- message_loop_observer_.reset();
DCHECK(result == MOJO_RESULT_FAILED_PRECONDITION ||
result == MOJO_RESULT_INVALID_ARGUMENT);
return result;
@@ -99,7 +65,6 @@ void Watcher::Cancel() {
MojoResult result =
MojoCancelWatch(handle_.value(), reinterpret_cast<uintptr_t>(this));
- message_loop_observer_.reset();
// |result| may be MOJO_RESULT_INVALID_ARGUMENT if |handle_| has closed, but
// OnHandleReady has not yet been called.
DCHECK(result == MOJO_RESULT_INVALID_ARGUMENT || result == MOJO_RESULT_OK);
@@ -112,14 +77,15 @@ void Watcher::OnHandleReady(MojoResult result) {
ReadyCallback callback = callback_;
if (result == MOJO_RESULT_CANCELLED) {
- message_loop_observer_.reset();
handle_.set_value(kInvalidHandleValue);
callback_.Reset();
}
// NOTE: It's legal for |callback| to delete |this|.
- if (!callback.is_null())
+ if (!callback.is_null()) {
+ TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event(heap_profiler_tag_);
callback.Run(result);
+ }
}
// static
@@ -133,6 +99,7 @@ void Watcher::CallOnHandleReady(uintptr_t context,
// TODO: Maybe we should also expose |signals_state| through the Watcher API.
// Current HandleWatcher users have no need for it, so it's omitted here.
Watcher* watcher = reinterpret_cast<Watcher*>(context);
+
if ((flags & MOJO_WATCH_NOTIFICATION_FLAG_FROM_SYSTEM) &&
watcher->task_runner_->RunsTasksOnCurrentThread() &&
watcher->is_default_task_runner_) {
diff --git a/mojo/public/cpp/system/watcher.h b/mojo/public/cpp/system/watcher.h
index 82f3e81..236788b 100644
--- a/mojo/public/cpp/system/watcher.h
+++ b/mojo/public/cpp/system/watcher.h
@@ -5,8 +5,6 @@
#ifndef MOJO_PUBLIC_CPP_SYSTEM_WATCHER_H_
#define MOJO_PUBLIC_CPP_SYSTEM_WATCHER_H_
-#include <memory>
-
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
@@ -16,13 +14,14 @@
#include "base/threading/thread_task_runner_handle.h"
#include "mojo/public/c/system/types.h"
#include "mojo/public/cpp/system/handle.h"
+#include "mojo/public/cpp/system/system_export.h"
namespace mojo {
// A Watcher watches a single Mojo handle for signal state changes.
//
// NOTE: Watchers may only be used on threads which have a running MessageLoop.
-class Watcher {
+class MOJO_CPP_SYSTEM_EXPORT Watcher {
public:
// A callback to be called any time a watched handle changes state in some
// interesting way. The |result| argument indicates one of the following
@@ -35,15 +34,11 @@ class Watcher {
//
// |MOJO_RESULT_CANCELLED|: The handle has been closed and the watch has
// been cancelled implicitly.
- //
- // |MOJO_RESULT_ABORTED|: Notifications can no longer be delivered for this
- // watcher for some unspecified reason, e.g., the watching thread may
- // be shutting down soon. Note that it is still necessary to explicitly
- // Cancel() the watch in this case.
using ReadyCallback = base::Callback<void(MojoResult result)>;
- explicit Watcher(scoped_refptr<base::SingleThreadTaskRunner> runner =
- base::ThreadTaskRunnerHandle::Get());
+ Watcher(const tracked_objects::Location& from_here,
+ scoped_refptr<base::SingleThreadTaskRunner> runner =
+ base::ThreadTaskRunnerHandle::Get());
// NOTE: This destructor automatically calls |Cancel()| if the Watcher is
// still active.
@@ -80,10 +75,13 @@ class Watcher {
Handle handle() const { return handle_; }
ReadyCallback ready_callback() const { return callback_; }
- private:
- class MessageLoopObserver;
- friend class MessageLoopObserver;
+ // Sets the tag used by the heap profiler.
+ // |tag| must be a const string literal.
+ void set_heap_profiler_tag(const char* heap_profiler_tag) {
+ heap_profiler_tag_ = heap_profiler_tag;
+ }
+ private:
void OnHandleReady(MojoResult result);
static void CallOnHandleReady(uintptr_t context,
@@ -100,8 +98,6 @@ class Watcher {
// for the thread.
const bool is_default_task_runner_;
- std::unique_ptr<MessageLoopObserver> message_loop_observer_;
-
// A persistent weak reference to this Watcher which can be passed to the
// Dispatcher any time this object should be signalled. Safe to access (but
// not to dereference!) from any thread.
@@ -115,6 +111,10 @@ class Watcher {
// The callback to call when the handle is signaled.
ReadyCallback callback_;
+ // Tag used to ID memory allocations that originated from notifications in
+ // this watcher.
+ const char* heap_profiler_tag_ = nullptr;
+
base::WeakPtrFactory<Watcher> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(Watcher);
diff --git a/mojo/public/cpp/test_support/BUILD.gn b/mojo/public/cpp/test_support/BUILD.gn
index 3d33b4a..efa1712 100644
--- a/mojo/public/cpp/test_support/BUILD.gn
+++ b/mojo/public/cpp/test_support/BUILD.gn
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: mojo/public/mojo_public.gyp:mojo_public_test_utils
static_library("test_utils") {
testonly = true
diff --git a/mojo/public/interfaces/BUILD.gn b/mojo/public/interfaces/BUILD.gn
index 654145b..fb11ec2 100644
--- a/mojo/public/interfaces/BUILD.gn
+++ b/mojo/public/interfaces/BUILD.gn
@@ -4,8 +4,6 @@
group("interfaces") {
deps = [
- "application",
"bindings",
- "network",
]
}
diff --git a/mojo/public/interfaces/bindings/BUILD.gn b/mojo/public/interfaces/bindings/BUILD.gn
index c7421b9..eab75c1 100644
--- a/mojo/public/interfaces/bindings/BUILD.gn
+++ b/mojo/public/interfaces/bindings/BUILD.gn
@@ -5,8 +5,13 @@
import("../../tools/bindings/mojom.gni")
mojom("bindings") {
+ visibility = []
sources = [
"interface_control_messages.mojom",
"pipe_control_messages.mojom",
]
+
+ export_class_attribute = "MOJO_CPP_BINDINGS_EXPORT"
+ export_define = "MOJO_CPP_BINDINGS_IMPLEMENTATION"
+ export_header = "mojo/public/cpp/bindings/bindings_export.h"
}
diff --git a/mojo/public/interfaces/bindings/interface_control_messages.mojom b/mojo/public/interfaces/bindings/interface_control_messages.mojom
index 2143c06..0a19042 100644
--- a/mojo/public/interfaces/bindings/interface_control_messages.mojom
+++ b/mojo/public/interfaces/bindings/interface_control_messages.mojom
@@ -2,12 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-[JavaPackage="org.chromium.mojo.bindings"]
-module mojo;
+[JavaPackage="org.chromium.mojo.bindings.interfacecontrol"]
+module mojo.interface_control;
-// For each user-defined interface, some control functions are provided at the
-// same end of the message pipe as the user-defined interface, providing
-// information about the user-defined interface.
+// For each user-defined interface, some control functions are provided by the
+// interface endpoints at both sides.
////////////////////////////////////////////////////////////////////////////////
// Run@0xFFFFFFFF(RunInput input) => (RunOutput? output);
@@ -15,75 +14,54 @@ module mojo;
// This control function runs the input command. If the command is not
// supported, |output| is set to null; otherwise |output| stores the result,
// whose type depends on the input.
-//
-// TODO(yzshen): Once union support is ready, switch the following definition
-// to:
-// struct RunMessageParams {
-// RunInput input;
-// };
-// union RunInput {
-// QueryVersion query_version;
-// };
-//
-// struct RunResponseMessageParams {
-// RunOutput? output;
-// };
-// union RunOutput {
-// QueryVersionResult query_version_result;
-// };
const uint32 kRunMessageId = 0xFFFFFFFF;
struct RunMessageParams {
- // The reserved fields make the layout compatible with the RunInput union
- // described above.
- uint32 reserved0; // Must be set to 16.
- uint32 reserved1; // Must be set to 0;
+ RunInput input;
+};
+union RunInput {
QueryVersion query_version;
+ FlushForTesting flush_for_testing;
};
struct RunResponseMessageParams {
- // The reserved fields make the layout compatible with the RunOutput union
- // described above.
- uint32 reserved0; // Must be set to 16.
- uint32 reserved1; // Must be set to 0.
+ RunOutput? output;
+};
+union RunOutput {
QueryVersionResult query_version_result;
};
// Queries the max supported version of the user-defined interface.
+// Sent by the interface client side.
struct QueryVersion {
};
struct QueryVersionResult {
uint32 version;
};
+// Sent by either side of the interface.
+struct FlushForTesting {
+};
+
////////////////////////////////////////////////////////////////////////////////
// RunOrClosePipe@0xFFFFFFFE(RunOrClosePipeInput input);
//
// This control function runs the input command. If the operation fails or the
// command is not supported, the message pipe is closed.
-//
-// TODO(yzshen): Once union support is ready, switch the following definition
-// to:
-// struct RunOrClosePipeMessageParams {
-// RunOrClosePipeInput input;
-// };
-// union RunOrClosePipeInput {
-// RequireVersion require_version;
-// };
const uint32 kRunOrClosePipeMessageId = 0xFFFFFFFE;
struct RunOrClosePipeMessageParams {
- // The reserved fields make the layout compatible with the RunOrClosePipeInput
- // union described above.
- uint32 reserved0; // Must be set to 16.
- uint32 reserved1; // Must be set to 0.
+ RunOrClosePipeInput input;
+};
+union RunOrClosePipeInput {
RequireVersion require_version;
};
// If the specified version of the user-defined interface is not supported, the
// function fails and the pipe is closed.
+// Sent by the interface client side.
struct RequireVersion {
uint32 version;
};
diff --git a/mojo/public/interfaces/bindings/pipe_control_messages.mojom b/mojo/public/interfaces/bindings/pipe_control_messages.mojom
index c743ffe..c1453fc 100644
--- a/mojo/public/interfaces/bindings/pipe_control_messages.mojom
+++ b/mojo/public/interfaces/bindings/pipe_control_messages.mojom
@@ -25,26 +25,21 @@ struct RunOrClosePipeMessageParams {
union RunOrClosePipeInput {
PeerAssociatedEndpointClosedEvent peer_associated_endpoint_closed_event;
- AssociatedEndpointClosedBeforeSentEvent
- associated_endpoint_closed_before_sent_event;
};
-// An event to notify that an interface endpoint set up at the message sender
-// side has been closed.
-//
-// This event is only used for associated interfaces. When a master interface
-// is closed, the message pipe is shutdown directly.
-struct PeerAssociatedEndpointClosedEvent {
- // The interface ID.
- uint32 id;
+// A user-defined reason about why the interface is disconnected.
+struct DisconnectReason {
+ uint32 custom_reason;
+ string description;
};
-// An event to notify that an interface endpoint that is meant to be set up at
-// the message receiver side has been closed before sent over the message pipe.
+// An event to notify that an interface endpoint set up at the message sender
+// side has been closed.
//
-// This event is only used for associated interfaces.
-struct AssociatedEndpointClosedBeforeSentEvent {
+// This event is omitted if the endpoint belongs to the master interface and
+// there is no disconnect reason specified.
+struct PeerAssociatedEndpointClosedEvent {
// The interface ID.
uint32 id;
+ DisconnectReason? disconnect_reason;
};
-
diff --git a/mojo/public/interfaces/bindings/tests/BUILD.gn b/mojo/public/interfaces/bindings/tests/BUILD.gn
index 0a48076..9b10db0 100644
--- a/mojo/public/interfaces/bindings/tests/BUILD.gn
+++ b/mojo/public/interfaces/bindings/tests/BUILD.gn
@@ -17,7 +17,9 @@ mojom("test_interfaces") {
"sample_service.mojom",
"scoping.mojom",
"serialization_test_structs.mojom",
+ "test_bad_messages.mojom",
"test_constants.mojom",
+ "test_data_view.mojom",
"test_native_types.mojom",
"test_structs.mojom",
"test_sync_methods.mojom",
@@ -27,8 +29,59 @@ mojom("test_interfaces") {
":test_mojom_import",
":test_mojom_import2",
]
+}
+
+component("test_export_component") {
+ testonly = true
+ deps = [
+ ":test_export",
+ ]
+}
+
+if (!is_ios) {
+ component("test_export_blink_component") {
+ testonly = true
+ deps = [
+ ":test_export_blink",
+ ]
+ }
+}
+
+mojom("test_export") {
+ testonly = true
+ sources = [
+ "test_export.mojom",
+ ]
+ export_class_attribute = "MOJO_TEST_EXPORT"
+ export_define = "MOJO_TEST_IMPLEMENTATION=1"
+ export_header = "mojo/public/cpp/bindings/tests/mojo_test_export.h"
+ if (!is_ios) {
+ export_class_attribute_blink = "MOJO_TEST_BLINK_EXPORT"
+ export_define_blink = "MOJO_TEST_BLINK_IMPLEMENTATION=1"
+ export_header_blink =
+ "mojo/public/cpp/bindings/tests/mojo_test_blink_export.h"
+ }
+ visibility = [ ":test_export_component" ]
+ if (!is_ios) {
+ visibility_blink = [ ":test_export_blink_component" ]
+ }
+}
- use_new_wrapper_types = true
+mojom("test_exported_import") {
+ testonly = true
+ sources = [
+ "test_import.mojom",
+ ]
+ public_deps = [
+ ":test_export",
+ ]
+
+ overridden_deps = [ ":test_export" ]
+ component_deps = [ ":test_export_component" ]
+ if (!is_ios) {
+ overridden_deps_blink = [ ":test_export" ]
+ component_deps_blink = [ ":test_export_blink_component" ]
+ }
}
mojom("test_mojom_import") {
@@ -36,7 +89,6 @@ mojom("test_mojom_import") {
sources = [
"sample_import.mojom",
]
- use_new_wrapper_types = true
}
mojom("test_mojom_import_wrapper") {
@@ -62,7 +114,6 @@ mojom("test_mojom_import2") {
":test_mojom_import",
":test_mojom_import_wrapper_wrapper",
]
- use_new_wrapper_types = true
}
mojom("test_struct_traits_interfaces") {
@@ -70,7 +121,6 @@ mojom("test_struct_traits_interfaces") {
sources = [
"struct_with_traits.mojom",
]
- use_new_wrapper_types = true
}
mojom("test_interfaces_experimental") {
@@ -78,7 +128,6 @@ mojom("test_interfaces_experimental") {
sources = [
"test_unions.mojom",
]
- use_new_wrapper_types = true
}
mojom("test_associated_interfaces") {
@@ -89,7 +138,10 @@ mojom("test_associated_interfaces") {
"test_associated_interfaces.mojom",
"validation_test_associated_interfaces.mojom",
]
- use_new_wrapper_types = true
+
+ public_deps = [
+ ":test_interfaces",
+ ]
}
mojom("versioning_test_service_interfaces") {
@@ -97,7 +149,6 @@ mojom("versioning_test_service_interfaces") {
sources = [
"versioning_test_service.mojom",
]
- use_new_wrapper_types = true
}
mojom("versioning_test_client_interfaces") {
@@ -105,7 +156,6 @@ mojom("versioning_test_client_interfaces") {
sources = [
"versioning_test_client.mojom",
]
- use_new_wrapper_types = true
}
mojom("test_wtf_types") {
@@ -114,7 +164,6 @@ mojom("test_wtf_types") {
sources = [
"test_wtf_types.mojom",
]
- use_new_wrapper_types = true
}
mojom("test_no_sources") {
diff --git a/mojo/public/interfaces/bindings/tests/data/message_data b/mojo/public/interfaces/bindings/tests/data/message_data
deleted file mode 100644
index b288878..0000000
--- a/mojo/public/interfaces/bindings/tests/data/message_data
+++ /dev/null
@@ -1,25 +0,0 @@
-// File generated by mojo_message_generator.
-0X10
-0X00
-0X00
-0X00
-0X02
-0X00
-0X00
-0X00
-0X15
-0X00
-0X00
-0X00
-0X00
-0X00
-0X00
-0X00
-0X09
-0X08
-0X07
-0X06
-0X00
-0X00
-0X00
-0X00
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd0_good.data b/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd0_good.data
index efac7ed..b797fea 100644
--- a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd0_good.data
+++ b/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd0_good.data
@@ -1,13 +1,26 @@
[dist4]message_header // num_bytes
-[u4]0 // version
+[u4]2 // version
[u4]0 // interface ID
[u4]0 // name
[u4]0 // flags
[u4]0 // padding
+[u8]0 // request_id
+[dist8]payload
+[dist8]payload_interface_ids
[anchr]message_header
+[anchr]payload
[dist4]method0_params // num_bytes
[u4]0 // version
-[u4]4 // associated interface pointer: interface ID
+[u4]1 // associated interface pointer: interface ID index
[u4]1 // associated interface pointer: version
[anchr]method0_params
+
+[anchr]payload_interface_ids
+[dist4]interface_id_array // num_bytes
+[u4]3 // num_elements : It is okay to have IDs that are not
+ // referred to.
+[u4]4
+[u4]5
+[u4]8
+[anchr]interface_id_array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd0_unexpected_invalid_associated_interface.data b/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd0_unexpected_invalid_associated_interface.data
index dd16401..b785ed1 100644
--- a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd0_unexpected_invalid_associated_interface.data
+++ b/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd0_unexpected_invalid_associated_interface.data
@@ -1,14 +1,25 @@
[dist4]message_header // num_bytes
-[u4]0 // version
+[u4]2 // version
[u4]0 // interface ID
[u4]0 // name
[u4]0 // flags
[u4]0 // padding
+[u8]0 // request_id
+[dist8]payload
+[dist8]payload_interface_ids
[anchr]message_header
+[anchr]payload
[dist4]method0_params // num_bytes
[u4]0 // version
-[u4]0xFFFFFFFF // associated interface pointer: unexpected invalid
- // interface ID
+[u4]0xFFFFFFFF // associated interface pointer: Unexpected invalid
+ // interface ID index.
[u4]1 // associated interface pointer: version
[anchr]method0_params
+
+[anchr]payload_interface_ids
+[dist4]interface_id_array // num_bytes
+[u4]2 // num_elements
+[u4]3
+[u4]4
+[anchr]interface_id_array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd1_good.data b/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd1_good.data
index 7ebbe07..efa2162 100644
--- a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd1_good.data
+++ b/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd1_good.data
@@ -1,13 +1,26 @@
[dist4]message_header // num_bytes
-[u4]0 // version
+[u4]2 // version
[u4]0 // interface ID
[u4]1 // name
[u4]0 // flags
[u4]0 // padding
+[u8]0 // request_id
+[dist8]payload
+[dist8]payload_interface_ids
[anchr]message_header
+[anchr]payload
[dist4]method1_params // num_bytes
[u4]0 // version
-[u4]4 // associated interface request
+[u4]1 // associated interface request: interface ID index
[u4]0 // padding
[anchr]method1_params
+
+[anchr]payload_interface_ids
+[dist4]interface_id_array // num_bytes
+[u4]3 // num_elements : It is okay to have IDs that are not
+ // referred to.
+[u4]4
+[u4]5
+[u4]8
+[anchr]interface_id_array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd1_unexpected_invalid_associated_request.data b/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd1_unexpected_invalid_associated_request.data
index d74a306..5a66aad 100644
--- a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd1_unexpected_invalid_associated_request.data
+++ b/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd1_unexpected_invalid_associated_request.data
@@ -1,14 +1,27 @@
[dist4]message_header // num_bytes
-[u4]0 // version
+[u4]2 // version
[u4]0 // interface ID
[u4]1 // name
[u4]0 // flags
[u4]0 // padding
+[u8]0 // request_id
+[dist8]payload
+[dist8]payload_interface_ids
[anchr]message_header
+[anchr]payload
[dist4]method1_params // num_bytes
[u4]0 // version
-[u4]0xFFFFFFFF // associated interface request: unexpected invalid
- // interface ID
+[u4]0xFFFFFFFF // associated interface request: Unexpected invalid
+ // interface ID index.
[u4]0 // padding
[anchr]method1_params
+
+[anchr]payload_interface_ids
+[dist4]interface_id_array // num_bytes
+[u4]3 // num_elements : It is okay to have IDs that are not
+ // referred to.
+[u4]4
+[u4]5
+[u4]8
+[anchr]interface_id_array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd2_master_interface_id.data b/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd2_master_interface_id.data
deleted file mode 100644
index 511cd0d..0000000
--- a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd2_master_interface_id.data
+++ /dev/null
@@ -1,15 +0,0 @@
-[dist4]message_header // num_bytes
-[u4]0 // version
-[u4]0 // interface ID
-[u4]2 // name
-[u4]0 // flags
-[u4]0 // padding
-[anchr]message_header
-
-[dist4]method2_params // num_bytes
-[u4]0 // version
-[u4]0 // associated interface pointer: 0 is the special master
- // interface ID and should never be used as associated
- // interface ID
-[u4]1 // associated interface pointer: version
-[anchr]method2_params
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd2_master_interface_id.expected b/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd2_master_interface_id.expected
deleted file mode 100644
index 420b421..0000000
--- a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd2_master_interface_id.expected
+++ /dev/null
@@ -1 +0,0 @@
-VALIDATION_ERROR_ILLEGAL_INTERFACE_ID
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd3_good.data b/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd3_good.data
index da22db1..13df01e 100644
--- a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd3_good.data
+++ b/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd3_good.data
@@ -1,11 +1,15 @@
[dist4]message_header // num_bytes
-[u4]0 // version
+[u4]2 // version
[u4]0 // interface ID
[u4]3 // name
[u4]0 // flags
[u4]0 // padding
+[u8]0 // request_id
+[dist8]payload
+[dist8]payload_interface_ids
[anchr]message_header
+[anchr]payload
[dist4]method3_params // num_bytes
[u4]0 // version
[dist8]param0_ptr // param0
@@ -14,8 +18,18 @@
[anchr]param0_ptr
[dist4]associated_interface_array // num_bytes
[u4]2 // num_elements
-[u4]4 // interface ID
+[u4]2 // interface ID index
[u4]14 // version
-[u4]5 // interface ID
+[u4]3 // interface ID index
[u4]18 // version
[anchr]associated_interface_array
+
+[anchr]payload_interface_ids
+[dist4]interface_id_array // num_bytes
+[u4]4 // num_elements : It is okay to have IDs that are not
+ // referred to.
+[u4]4
+[u4]5
+[u4]8
+[u4]19
+[anchr]interface_id_array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd3_unexpected_invalid_associated_interface_in_array.data b/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd3_unexpected_invalid_associated_interface_in_array.data
index 788cefa..2e163be 100644
--- a/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd3_unexpected_invalid_associated_interface_in_array.data
+++ b/mojo/public/interfaces/bindings/tests/data/validation/associated_conformance_mthd3_unexpected_invalid_associated_interface_in_array.data
@@ -1,11 +1,15 @@
[dist4]message_header // num_bytes
-[u4]0 // version
+[u4]2 // version
[u4]0 // interface ID
[u4]3 // name
[u4]0 // flags
[u4]0 // padding
+[u8]0 // request_id
+[dist8]payload
+[dist8]payload_interface_ids
[anchr]message_header
+[anchr]payload
[dist4]method3_params // num_bytes
[u4]0 // version
[dist8]param0_ptr // param0
@@ -14,8 +18,19 @@
[anchr]param0_ptr
[dist4]associated_interface_array // num_bytes
[u4]2 // num_elements
-[u4]0xFFFFFFFF // unexpected invalid interface ID
+[u4]2 // interface ID index
[u4]14 // version
-[u4]5 // interface ID
+[u4]0xFFFFFFFF // interface ID index: Unexpected invalid
+ // value.
[u4]18 // version
[anchr]associated_interface_array
+
+[anchr]payload_interface_ids
+[dist4]interface_id_array // num_bytes
+[u4]4 // num_elements : It is okay to have IDs that are not
+ // referred to.
+[u4]4
+[u4]5
+[u4]8
+[u4]19
+[anchr]interface_id_array
diff --git a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd15_uknown_non_extensible_enum_array_value.data b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd15_uknown_non_extensible_enum_array_value.data
index 1cd3484..0a46e0a 100644
--- a/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd15_uknown_non_extensible_enum_array_value.data
+++ b/mojo/public/interfaces/bindings/tests/data/validation/conformance_mthd15_uknown_non_extensible_enum_array_value.data
@@ -15,7 +15,7 @@
[anchr]enum_array_0
[dist4]enum_array_0_member // num_bytes
[u4]2 // num_elements
+[u4]1
[u4]0x5678 // Unknown value is not allowed for non-extensible
// enum.
-[u4]1
[anchr]enum_array_0_member
diff --git a/mojo/public/interfaces/bindings/tests/rect.mojom b/mojo/public/interfaces/bindings/tests/rect.mojom
index 833c76b..4ecc4d9 100644
--- a/mojo/public/interfaces/bindings/tests/rect.mojom
+++ b/mojo/public/interfaces/bindings/tests/rect.mojom
@@ -12,11 +12,20 @@ struct Rect {
int32 height;
};
-// A copy of Rect that can be typemapped. Arrays of Rect are currently used,
-// which do not support typemapping.
+// A copy of Rect that is typemapped differently in the chromium and blink
+// variants.
struct TypemappedRect {
int32 x;
int32 y;
int32 width;
int32 height;
};
+
+// A copy of Rect that is typemapped to the same custom type in the chromium and
+// blink variants.
+struct SharedTypemappedRect {
+ int32 x;
+ int32 y;
+ int32 width;
+ int32 height;
+}; \ No newline at end of file
diff --git a/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom b/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom
index b1b7437..b50409e 100644
--- a/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom
+++ b/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom
@@ -23,6 +23,7 @@ struct StructWithTraits {
string f_string;
string f_string2;
array<string> f_string_array;
+ array<string> f_string_set;
NestedStructWithTraits f_struct;
array<NestedStructWithTraits> f_struct_array;
map<string, NestedStructWithTraits> f_struct_map;
@@ -33,28 +34,50 @@ struct StructWithTraitsContainer {
StructWithTraits f_struct;
};
-struct PassByValueStructWithTraits {
+// Maps to a pass-by-value trivial struct.
+struct TrivialStructWithTraits {
+ int32 value;
+};
+
+// Maps to a move-only struct.
+struct MoveOnlyStructWithTraits {
handle f_handle;
};
-// The custom type for PassByValueStructWithTraits is not clonable. Test that
+// The custom type for MoveOnlyStructWithTraits is not clonable. Test that
// this container can compile as long as Clone() is not used.
-struct PassByValueStructWithTraitsContainer {
- PassByValueStructWithTraits f_struct;
+struct MoveOnlyStructWithTraitsContainer {
+ MoveOnlyStructWithTraits f_struct;
};
-struct StructWithTraitsForUniquePtrTest {
+struct StructWithTraitsForUniquePtr {
int32 f_int32;
};
+union UnionWithTraits {
+ int32 f_int32;
+ NestedStructWithTraits f_struct;
+};
+
interface TraitsTestService {
EchoStructWithTraits(StructWithTraits s) => (StructWithTraits passed);
- EchoPassByValueStructWithTraits(PassByValueStructWithTraits s) =>
- (PassByValueStructWithTraits passed);
+ EchoTrivialStructWithTraits(TrivialStructWithTraits s) =>
+ (TrivialStructWithTraits passed);
+
+ EchoMoveOnlyStructWithTraits(MoveOnlyStructWithTraits s) =>
+ (MoveOnlyStructWithTraits passed);
+
+ EchoNullableMoveOnlyStructWithTraits(MoveOnlyStructWithTraits? s) =>
+ (MoveOnlyStructWithTraits? passed);
EchoEnumWithTraits(EnumWithTraits e) => (EnumWithTraits passed);
- EchoStructWithTraitsForUniquePtrTest(StructWithTraitsForUniquePtrTest e) => (
- StructWithTraitsForUniquePtrTest passed);
+ EchoStructWithTraitsForUniquePtr(StructWithTraitsForUniquePtr e) => (
+ StructWithTraitsForUniquePtr passed);
+
+ EchoNullableStructWithTraitsForUniquePtr(StructWithTraitsForUniquePtr? e) => (
+ StructWithTraitsForUniquePtr? passed);
+
+ EchoUnionWithTraits(UnionWithTraits u) => (UnionWithTraits passed);
};
diff --git a/mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom b/mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom
index 534cfd8..adc4e7e 100644
--- a/mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom
+++ b/mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom
@@ -4,6 +4,8 @@
module mojo.test;
+import "mojo/public/interfaces/bindings/tests/ping_service.mojom";
+
interface FooInterface {};
struct StructContainsAssociated {
@@ -42,3 +44,11 @@ interface IntegerSenderConnection {
GetSender(associated IntegerSender& sender);
AsyncGetSender() => (associated IntegerSender sender);
};
+
+interface AssociatedPingProvider {
+ GetPing(associated PingService& request);
+};
+
+interface AssociatedPingProviderProvider {
+ GetPingProvider(associated AssociatedPingProvider& request);
+};
diff --git a/mojo/public/interfaces/bindings/tests/test_constants.mojom b/mojo/public/interfaces/bindings/tests/test_constants.mojom
index 462d512..272e603 100644
--- a/mojo/public/interfaces/bindings/tests/test_constants.mojom
+++ b/mojo/public/interfaces/bindings/tests/test_constants.mojom
@@ -42,12 +42,16 @@ const float kFloatInfinity = float.INFINITY;
const float kFloatNegativeInfinity = float.NEGATIVE_INFINITY;
const float kFloatNaN = float.NAN;
+const string kStringValue = "test string contents";
+
struct StructWithConstants {
const int8 kInt8Value = 5;
const float kFloatValue = 765.432;
+ const string kStringValue = "struct test string contents";
};
interface InterfaceWithConstants {
const uint32 kUint32Value = 20100722;
const double kDoubleValue = 12.34567;
+ const string kStringValue = "interface test string contents";
};
diff --git a/mojo/public/interfaces/bindings/tests/test_native_types.mojom b/mojo/public/interfaces/bindings/tests/test_native_types.mojom
index 46c6f69..3df4318 100644
--- a/mojo/public/interfaces/bindings/tests/test_native_types.mojom
+++ b/mojo/public/interfaces/bindings/tests/test_native_types.mojom
@@ -34,4 +34,5 @@ interface PicklePasser {
interface RectService {
AddRect(TypemappedRect r);
GetLargestRect() => (TypemappedRect largest);
+ PassSharedRect(SharedTypemappedRect r) => (SharedTypemappedRect passed);
};
diff --git a/mojo/public/interfaces/bindings/tests/test_structs.mojom b/mojo/public/interfaces/bindings/tests/test_structs.mojom
index 2709d49..03a0a20 100644
--- a/mojo/public/interfaces/bindings/tests/test_structs.mojom
+++ b/mojo/public/interfaces/bindings/tests/test_structs.mojom
@@ -126,6 +126,8 @@ struct MapKeyTypes {
map<float, float> f9;
map<double, double> f10;
map<string, string> f11;
+ // TODO(tibell): JS/Java don't support struct as key.
+ // map<Rect, Rect> f12;
};
// Used to verify that various map value types can be encoded and decoded
@@ -358,6 +360,16 @@ struct MultiVersionStructV7 {
bool f_bool;
};
+// A struct where the fields are not sorted by their ordinals.
+struct ReorderedStruct {
+ [MinVersion=2]
+ int32 a@3 = 3;
+ [MinVersion=4]
+ int32 b@6 = 6;
+ [MinVersion=1]
+ int32 c@1 = 1;
+};
+
// Used to verify that interfaces that are struct members can be defined in the
// same file.
@@ -380,3 +392,23 @@ struct ContainsOther {
struct ContainsInterfaceRequest {
SomeInterface& request;
};
+
+// Used to verify that boolean fields are correctly serialized/deserialized.
+
+struct SingleBoolStruct {
+ bool value;
+};
+
+// Used to verify that structs containing typemapped types can be hashed (if the
+// typemapped type itself is hashable).
+
+struct ContainsHashable {
+ TypemappedRect rect;
+};
+
+// Used to test that nested structs can be hashed. The nested struct mustn't be
+// nullable.
+
+struct SimpleNestedStruct {
+ ContainsOther nested;
+};
diff --git a/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom b/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom
index 2fdbea8..183f184 100644
--- a/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom
+++ b/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom
@@ -25,13 +25,26 @@ union TestWTFCodeGeneration2 {
};
struct TestWTFStruct {
+ enum NestedEnum {
+ E0,
+ E1,
+ };
string str;
int32 integer;
};
interface TestWTF {
+ enum NestedEnum {
+ E0,
+ E1,
+ };
EchoString(string? str) => (string? str);
EchoStringArray(array<string?>? arr) => (array<string?>? arr);
EchoStringMap(map<string, string?>? str_map)
=> (map<string, string?>? str_map);
};
+
+enum TopLevelEnum {
+ E0,
+ E1,
+};
diff --git a/mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom b/mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom
index c46c0a5..ab69045 100644
--- a/mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom
+++ b/mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom
@@ -56,6 +56,18 @@ enum EnumB {
ENUM_B_2
};
+// A non-extensible enum with no values is valid, but about as useless as
+// you would expect: it will fail validation for all values.
+enum EmptyEnum {};
+
+[Extensible]
+enum ExtensibleEmptyEnum {};
+
+union UnionA {
+ StructA struct_a;
+ bool b;
+};
+
// This interface is used for testing bounds-checking in the mojom
// binding code. If you add a method please update the files
// ./data/validation/boundscheck_*. If you add a response please update
@@ -84,6 +96,11 @@ interface ConformanceTestInterface {
Method15(array<EnumA>? param0, array<EnumB>? param1);
Method16(map<EnumA, EnumA>? param0);
Method17(array<InterfaceA> param0);
+ Method18(UnionA? param0);
+ Method19(Recursive recursive);
+ Method20(map<StructB, uint8> param0);
+ Method21(ExtensibleEmptyEnum param0);
+ Method22(EmptyEnum param0);
};
struct BasicStruct {
@@ -111,3 +128,8 @@ struct StructWithEnum {
A, B, C, D
};
};
+
+// This is used to test that deeply recursive structures don't blow the stack.
+struct Recursive {
+ Recursive? recursive;
+};
diff --git a/mojo/public/java/BUILD.gn b/mojo/public/java/BUILD.gn
index e33faaa..0780641 100644
--- a/mojo/public/java/BUILD.gn
+++ b/mojo/public/java/BUILD.gn
@@ -4,9 +4,8 @@
import("//build/config/android/rules.gni")
-android_library("system") {
+android_library("system_java") {
java_files = [
- "system/src/org/chromium/mojo/system/AsyncWaiter.java",
"system/src/org/chromium/mojo/system/Core.java",
"system/src/org/chromium/mojo/system/DataPipe.java",
"system/src/org/chromium/mojo/system/Flags.java",
@@ -20,10 +19,11 @@ android_library("system") {
"system/src/org/chromium/mojo/system/SharedBufferHandle.java",
"system/src/org/chromium/mojo/system/UntypedHandle.java",
"system/src/org/chromium/mojo/system/RunLoop.java",
+ "system/src/org/chromium/mojo/system/Watcher.java",
]
}
-android_library("bindings") {
+android_library("bindings_java") {
java_files = [
"bindings/src/org/chromium/mojo/bindings/AssociatedInterfaceNotSupported.java",
"bindings/src/org/chromium/mojo/bindings/AssociatedInterfaceRequestNotSupported.java",
@@ -56,7 +56,7 @@ android_library("bindings") {
]
deps = [
- ":system",
+ ":system_java",
"//base:base_java",
]
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/BindingsHelper.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/BindingsHelper.java
index 6146316..f77399d 100644
--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/BindingsHelper.java
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/BindingsHelper.java
@@ -4,8 +4,8 @@
package org.chromium.mojo.bindings;
-import org.chromium.mojo.system.AsyncWaiter;
import org.chromium.mojo.system.Handle;
+import org.chromium.mojo.system.Watcher;
/**
* Helper functions.
@@ -189,9 +189,9 @@ public class BindingsHelper {
/**
* Returns an {@link AsyncWaiter} to use with the given handle, or |null| if none if available.
*/
- static AsyncWaiter getDefaultAsyncWaiterForHandle(Handle handle) {
+ static Watcher getWatcherForHandle(Handle handle) {
if (handle.getCore() != null) {
- return handle.getCore().getDefaultAsyncWaiter();
+ return handle.getCore().getWatcher();
} else {
return null;
}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java
index 3686bcf..2aa5ea6 100644
--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java
@@ -4,13 +4,13 @@
package org.chromium.mojo.bindings;
-import org.chromium.mojo.system.AsyncWaiter;
import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.MessagePipeHandle;
import org.chromium.mojo.system.MessagePipeHandle.ReadMessageResult;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojo.system.MojoResult;
import org.chromium.mojo.system.ResultAnd;
+import org.chromium.mojo.system.Watcher;
import java.nio.ByteBuffer;
@@ -27,7 +27,7 @@ public class Connector implements MessageReceiver, HandleOwner<MessagePipeHandle
/**
* The callback that is notified when the state of the owned handle changes.
*/
- private final AsyncWaiterCallback mAsyncWaiterCallback = new AsyncWaiterCallback();
+ private final WatcherCallback mWatcherCallback = new WatcherCallback();
/**
* The owned message pipe.
@@ -35,9 +35,9 @@ public class Connector implements MessageReceiver, HandleOwner<MessagePipeHandle
private final MessagePipeHandle mMessagePipeHandle;
/**
- * A waiter which is notified when a new message is available on the owned message pipe.
+ * A watcher which is notified when a new message is available on the owned message pipe.
*/
- private final AsyncWaiter mAsyncWaiter;
+ private final Watcher mWatcher;
/**
* The {@link MessageReceiver} to which received messages are sent.
@@ -45,11 +45,6 @@ public class Connector implements MessageReceiver, HandleOwner<MessagePipeHandle
private MessageReceiver mIncomingMessageReceiver;
/**
- * The Cancellable for the current wait. Is |null| when not currently waiting for new messages.
- */
- private AsyncWaiter.Cancellable mCancellable;
-
- /**
* The error handler to notify of errors.
*/
private ConnectionErrorHandler mErrorHandler;
@@ -59,17 +54,16 @@ public class Connector implements MessageReceiver, HandleOwner<MessagePipeHandle
* {@link AsyncWaiter} from the {@link Core} implementation of |messagePipeHandle|.
*/
public Connector(MessagePipeHandle messagePipeHandle) {
- this(messagePipeHandle, BindingsHelper.getDefaultAsyncWaiterForHandle(messagePipeHandle));
+ this(messagePipeHandle, BindingsHelper.getWatcherForHandle(messagePipeHandle));
}
/**
* Create a new connector over a |messagePipeHandle| using the given {@link AsyncWaiter} to get
* notified of changes on the handle.
*/
- public Connector(MessagePipeHandle messagePipeHandle, AsyncWaiter asyncWaiter) {
- mCancellable = null;
+ public Connector(MessagePipeHandle messagePipeHandle, Watcher watcher) {
mMessagePipeHandle = messagePipeHandle;
- mAsyncWaiter = asyncWaiter;
+ mWatcher = watcher;
}
/**
@@ -91,8 +85,7 @@ public class Connector implements MessageReceiver, HandleOwner<MessagePipeHandle
* Start listening for incoming messages.
*/
public void start() {
- assert mCancellable == null;
- registerAsyncWaiterForRead();
+ mWatcher.start(mMessagePipeHandle, Core.HandleSignals.READABLE, mWatcherCallback);
}
/**
@@ -140,32 +133,21 @@ public class Connector implements MessageReceiver, HandleOwner<MessagePipeHandle
}
}
- private class AsyncWaiterCallback implements AsyncWaiter.Callback {
-
+ private class WatcherCallback implements Watcher.Callback {
/**
- * @see org.chromium.mojo.system.AsyncWaiter.Callback#onResult(int)
+ * @see org.chromium.mojo.system.Watcher.Callback#onResult(int)
*/
@Override
public void onResult(int result) {
- Connector.this.onAsyncWaiterResult(result);
- }
-
- /**
- * @see org.chromium.mojo.system.AsyncWaiter.Callback#onError(MojoException)
- */
- @Override
- public void onError(MojoException exception) {
- mCancellable = null;
- Connector.this.onError(exception);
+ Connector.this.onWatcherResult(result);
}
}
/**
- * @see org.chromium.mojo.system.AsyncWaiter.Callback#onResult(int)
+ * @see org.chromium.mojo.system.Watcher.Callback#onResult(int)
*/
- private void onAsyncWaiterResult(int result) {
- mCancellable = null;
+ private void onWatcherResult(int result) {
if (result == MojoResult.OK) {
readOutstandingMessages();
} else {
@@ -175,26 +157,12 @@ public class Connector implements MessageReceiver, HandleOwner<MessagePipeHandle
private void onError(MojoException exception) {
close();
- assert mCancellable == null;
if (mErrorHandler != null) {
mErrorHandler.onConnectionError(exception);
}
}
/**
- * Register to be called back when a new message is available on the owned message pipe.
- */
- private void registerAsyncWaiterForRead() {
- assert mCancellable == null;
- if (mAsyncWaiter != null) {
- mCancellable = mAsyncWaiter.asyncWait(mMessagePipeHandle, Core.HandleSignals.READABLE,
- Core.DEADLINE_INFINITE, mAsyncWaiterCallback);
- } else {
- onError(new MojoException(MojoResult.INVALID_ARGUMENT));
- }
- }
-
- /**
* Read all available messages on the owned message pipe.
*/
private void readOutstandingMessages() {
@@ -207,18 +175,14 @@ public class Connector implements MessageReceiver, HandleOwner<MessagePipeHandle
return;
}
} while (result.getValue());
- if (result.getMojoResult() == MojoResult.SHOULD_WAIT) {
- registerAsyncWaiterForRead();
- } else {
+ if (result.getMojoResult() != MojoResult.SHOULD_WAIT) {
onError(new MojoException(result.getMojoResult()));
}
}
private void cancelIfActive() {
- if (mCancellable != null) {
- mCancellable.cancel();
- mCancellable = null;
- }
+ mWatcher.cancel();
+ mWatcher.destroy();
}
/**
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java
index 755fb01..64ff1c0 100644
--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java
@@ -29,11 +29,15 @@ public class Decoder {
/**
* Minimal value for the next handle to deserialize.
*/
- private int mMinNextClaimedHandle = 0;
+ private int mMinNextClaimedHandle;
/**
* Minimal value of the start of the next memory to claim.
*/
- private long mMinNextMemory = 0;
+ private long mMinNextMemory;
+ /**
+ * The current nesting level when decoding.
+ */
+ private long mStackDepth;
/**
* The maximal memory accessible.
@@ -46,11 +50,17 @@ public class Decoder {
private final long mNumberOfHandles;
/**
+ * The maximum nesting level when decoding.
+ */
+ private static final int MAX_RECURSION_DEPTH = 100;
+
+ /**
* Constructor.
*/
Validator(long maxMemory, int numberOfHandles) {
mMaxMemory = maxMemory;
mNumberOfHandles = numberOfHandles;
+ mStackDepth = 0;
}
public void claimHandle(int handle) {
@@ -79,6 +89,17 @@ public class Decoder {
}
mMinNextMemory = BindingsHelper.align(end);
}
+
+ public void increaseStackDepth() {
+ ++mStackDepth;
+ if (mStackDepth >= MAX_RECURSION_DEPTH) {
+ throw new DeserializationException("Recursion depth limit exceeded.");
+ }
+ }
+
+ public void decreaseStackDepth() {
+ --mStackDepth;
+ }
}
/**
@@ -744,4 +765,12 @@ public class Decoder {
throw new DeserializationException("Buffer is smaller than expected.");
}
}
+
+ public void increaseStackDepth() {
+ mValidator.increaseStackDepth();
+ }
+
+ public void decreaseStackDepth() {
+ mValidator.decreaseStackDepth();
+ }
}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java
index c621d9b..bb49cbc 100644
--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java
@@ -4,8 +4,6 @@
package org.chromium.mojo.bindings;
-import org.chromium.mojo.system.AsyncWaiter;
-import org.chromium.mojo.system.AsyncWaiter.Callback;
import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.MessagePipeHandle;
import org.chromium.mojo.system.MessagePipeHandle.ReadMessageResult;
@@ -13,6 +11,8 @@ import org.chromium.mojo.system.MojoException;
import org.chromium.mojo.system.MojoResult;
import org.chromium.mojo.system.Pair;
import org.chromium.mojo.system.ResultAnd;
+import org.chromium.mojo.system.Watcher;
+import org.chromium.mojo.system.Watcher.Callback;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -58,32 +58,23 @@ class ExecutorFactory {
*/
private final Object mLock;
/**
- * The {@link AsyncWaiter} to get notified of new message availability on |mReadHandle|.
+ * The {@link Watcher} to get notified of new message availability on |mReadHandle|.
*/
- private final AsyncWaiter mWaiter;
+ private final Watcher mWatcher;
/**
* Constructor.
*/
public PipedExecutor(Core core) {
- mWaiter = core.getDefaultAsyncWaiter();
- assert mWaiter != null;
+ mWatcher = core.getWatcher();
+ assert mWatcher != null;
mLock = new Object();
Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(
new MessagePipeHandle.CreateOptions());
mReadHandle = handles.first;
mWriteHandle = handles.second;
mPendingActions = new ArrayList<Runnable>();
- asyncWait();
- }
-
- /**
- * Asynchronously wait for the next command to arrive. This should only be called on the
- * executor thread.
- */
- private void asyncWait() {
- mWaiter.asyncWait(mReadHandle, Core.HandleSignals.READABLE, Core.DEADLINE_INFINITE,
- this);
+ mWatcher.start(mReadHandle, Core.HandleSignals.READABLE, this);
}
/**
@@ -99,14 +90,6 @@ class ExecutorFactory {
}
/**
- * @see Callback#onError(MojoException)
- */
- @Override
- public void onError(MojoException exception) {
- close();
- }
-
- /**
* Close the handles. Should only be called on the executor thread.
*/
private void close() {
@@ -114,6 +97,8 @@ class ExecutorFactory {
mWriteHandle.close();
mPendingActions.clear();
}
+ mWatcher.cancel();
+ mWatcher.destroy();
mReadHandle.close();
}
@@ -126,7 +111,6 @@ class ExecutorFactory {
ResultAnd<ReadMessageResult> readMessageResult =
mReadHandle.readMessage(NOTIFY_BUFFER, 0, MessagePipeHandle.ReadFlags.NONE);
if (readMessageResult.getMojoResult() == MojoResult.OK) {
- asyncWait();
return true;
}
} catch (MojoException e) {
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java
index 90fdb3a..385eb40 100644
--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java
@@ -6,6 +6,14 @@ package org.chromium.mojo.bindings;
import org.chromium.mojo.bindings.Callbacks.Callback1;
import org.chromium.mojo.bindings.Interface.AbstractProxy.HandlerImpl;
+import org.chromium.mojo.bindings.interfacecontrol.QueryVersion;
+import org.chromium.mojo.bindings.interfacecontrol.RequireVersion;
+import org.chromium.mojo.bindings.interfacecontrol.RunInput;
+import org.chromium.mojo.bindings.interfacecontrol.RunMessageParams;
+import org.chromium.mojo.bindings.interfacecontrol.RunOrClosePipeInput;
+import org.chromium.mojo.bindings.interfacecontrol.RunOrClosePipeMessageParams;
+import org.chromium.mojo.bindings.interfacecontrol.RunOutput;
+import org.chromium.mojo.bindings.interfacecontrol.RunResponseMessageParams;
import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.MessagePipeHandle;
import org.chromium.mojo.system.MojoException;
@@ -99,12 +107,12 @@ public interface Interface extends ConnectionErrorHandler, Closeable {
/**
* The {@link ConnectionErrorHandler} that will be notified of errors.
*/
- private ConnectionErrorHandler mErrorHandler = null;
+ private ConnectionErrorHandler mErrorHandler;
/**
* The currently known version of the interface.
*/
- private int mVersion = 0;
+ private int mVersion;
/**
* Constructor.
@@ -186,16 +194,19 @@ public interface Interface extends ConnectionErrorHandler, Closeable {
@Override
public void queryVersion(final Callback1<Integer> callback) {
RunMessageParams message = new RunMessageParams();
- message.reserved0 = 16;
- message.reserved1 = 0;
- message.queryVersion = new QueryVersion();
+ message.input = new RunInput();
+ message.input.setQueryVersion(new QueryVersion());
InterfaceControlMessagesHelper.sendRunMessage(getCore(), mMessageReceiver, message,
new Callback1<RunResponseMessageParams>() {
@Override
public void call(RunResponseMessageParams response) {
- mVersion = response.queryVersionResult.version;
- try {
+ if (response.output != null
+ && response.output.which()
+ == RunOutput.Tag.QueryVersionResult) {
+ mVersion = response.output.getQueryVersionResult().version;
+ }
+ try {
callback.call(mVersion);
} catch (RuntimeException e) {
// TODO(lhchavez): Remove this hack. See b/28986534 for details.
@@ -216,10 +227,9 @@ public interface Interface extends ConnectionErrorHandler, Closeable {
}
mVersion = version;
RunOrClosePipeMessageParams message = new RunOrClosePipeMessageParams();
- message.reserved0 = 16;
- message.reserved1 = 0;
- message.requireVersion = new RequireVersion();
- message.requireVersion.version = version;
+ message.input = new RunOrClosePipeInput();
+ message.input.setRequireVersion(new RequireVersion());
+ message.input.getRequireVersion().version = version;
InterfaceControlMessagesHelper.sendRunOrClosePipeMessage(
getCore(), mMessageReceiver, message);
}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/InterfaceControlMessagesHelper.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/InterfaceControlMessagesHelper.java
index 939fb93..51f543d 100644
--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/InterfaceControlMessagesHelper.java
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/InterfaceControlMessagesHelper.java
@@ -7,6 +7,14 @@ package org.chromium.mojo.bindings;
import org.chromium.mojo.bindings.Callbacks.Callback1;
import org.chromium.mojo.bindings.Interface.Manager;
import org.chromium.mojo.bindings.Interface.Proxy;
+import org.chromium.mojo.bindings.interfacecontrol.InterfaceControlMessagesConstants;
+import org.chromium.mojo.bindings.interfacecontrol.QueryVersionResult;
+import org.chromium.mojo.bindings.interfacecontrol.RunInput;
+import org.chromium.mojo.bindings.interfacecontrol.RunMessageParams;
+import org.chromium.mojo.bindings.interfacecontrol.RunOrClosePipeInput;
+import org.chromium.mojo.bindings.interfacecontrol.RunOrClosePipeMessageParams;
+import org.chromium.mojo.bindings.interfacecontrol.RunOutput;
+import org.chromium.mojo.bindings.interfacecontrol.RunResponseMessageParams;
import org.chromium.mojo.system.Core;
/**
@@ -64,11 +72,16 @@ public class InterfaceControlMessagesHelper {
*/
public static <I extends Interface, P extends Proxy> boolean handleRun(
Core core, Manager<I, P> manager, ServiceMessage message, MessageReceiver responder) {
+ Message payload = message.getPayload();
+ RunMessageParams query = RunMessageParams.deserialize(payload);
RunResponseMessageParams response = new RunResponseMessageParams();
- response.reserved0 = 16;
- response.reserved1 = 0;
- response.queryVersionResult = new QueryVersionResult();
- response.queryVersionResult.version = manager.getVersion();
+ response.output = new RunOutput();
+ if (query.input.which() == RunInput.Tag.QueryVersion) {
+ response.output.setQueryVersionResult(new QueryVersionResult());
+ response.output.getQueryVersionResult().version = manager.getVersion();
+ } else {
+ response.output = null;
+ }
return responder.accept(response.serializeWithHeader(
core, new MessageHeader(InterfaceControlMessagesConstants.RUN_MESSAGE_ID,
@@ -84,6 +97,9 @@ public class InterfaceControlMessagesHelper {
Manager<I, P> manager, ServiceMessage message) {
Message payload = message.getPayload();
RunOrClosePipeMessageParams query = RunOrClosePipeMessageParams.deserialize(payload);
- return query.requireVersion.version <= manager.getVersion();
+ if (query.input.which() == RunOrClosePipeInput.Tag.RequireVersion) {
+ return query.input.getRequireVersion().version <= manager.getVersion();
+ }
+ return false;
}
}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Message.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Message.java
index 0d270cc..996c457 100644
--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Message.java
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Message.java
@@ -29,7 +29,7 @@ public class Message {
/**
* This message interpreted as a message for a mojo service with an appropriate header.
*/
- private ServiceMessage mWithHeader = null;
+ private ServiceMessage mWithHeader;
/**
* Constructor.
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java
index 16b29b4..a278cc5 100644
--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java
@@ -6,9 +6,9 @@ package org.chromium.mojo.bindings;
import android.annotation.SuppressLint;
-import org.chromium.mojo.system.AsyncWaiter;
import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.MessagePipeHandle;
+import org.chromium.mojo.system.Watcher;
import java.util.HashMap;
import java.util.Map;
@@ -48,7 +48,7 @@ public class RouterImpl implements Router {
* {@link MessageReceiver} used to return responses to the caller.
*/
class ResponderThunk implements MessageReceiver {
- private boolean mAcceptWasInvoked = false;
+ private boolean mAcceptWasInvoked;
/**
* @see
@@ -109,23 +109,23 @@ public class RouterImpl implements Router {
private final Executor mExecutor;
/**
- * Constructor that will use the default {@link AsyncWaiter}.
+ * Constructor that will use the default {@link Watcher}.
*
* @param messagePipeHandle The {@link MessagePipeHandle} to route message for.
*/
public RouterImpl(MessagePipeHandle messagePipeHandle) {
- this(messagePipeHandle, BindingsHelper.getDefaultAsyncWaiterForHandle(messagePipeHandle));
+ this(messagePipeHandle, BindingsHelper.getWatcherForHandle(messagePipeHandle));
}
/**
* Constructor.
*
* @param messagePipeHandle The {@link MessagePipeHandle} to route message for.
- * @param asyncWaiter the {@link AsyncWaiter} to use to get notification of new messages on the
+ * @param watcher the {@link Watcher} to use to get notification of new messages on the
* handle.
*/
- public RouterImpl(MessagePipeHandle messagePipeHandle, AsyncWaiter asyncWaiter) {
- mConnector = new Connector(messagePipeHandle, asyncWaiter);
+ public RouterImpl(MessagePipeHandle messagePipeHandle, Watcher watcher) {
+ mConnector = new Connector(messagePipeHandle, watcher);
mConnector.setIncomingMessageReceiver(new HandleIncomingMessageThunk());
Core core = messagePipeHandle.getCore();
if (core != null) {
@@ -171,23 +171,20 @@ public class RouterImpl implements Router {
assert messageWithHeader.getHeader().hasFlag(MessageHeader.MESSAGE_EXPECTS_RESPONSE_FLAG);
// Compute a request id for being able to route the response.
- // TODO(lhchavez): Remove this hack. See b/28986534 for details.
- synchronized (mResponders) {
- long requestId = mNextRequestId++;
- // Reserve 0 in case we want it to convey special meaning in the future.
- if (requestId == 0) {
- requestId = mNextRequestId++;
- }
- if (mResponders.containsKey(requestId)) {
- throw new IllegalStateException("Unable to find a new request identifier.");
- }
- messageWithHeader.setRequestId(requestId);
- if (!mConnector.accept(messageWithHeader)) {
- return false;
- }
- // Only keep the responder is the message has been accepted.
- mResponders.put(requestId, responder);
+ long requestId = mNextRequestId++;
+ // Reserve 0 in case we want it to convey special meaning in the future.
+ if (requestId == 0) {
+ requestId = mNextRequestId++;
+ }
+ if (mResponders.containsKey(requestId)) {
+ throw new IllegalStateException("Unable to find a new request identifier.");
}
+ messageWithHeader.setRequestId(requestId);
+ if (!mConnector.accept(messageWithHeader)) {
+ return false;
+ }
+ // Only keep the responder is the message has been accepted.
+ mResponders.put(requestId, responder);
return true;
}
@@ -230,15 +227,11 @@ public class RouterImpl implements Router {
return false;
} else if (header.hasFlag(MessageHeader.MESSAGE_IS_RESPONSE_FLAG)) {
long requestId = header.getRequestId();
- MessageReceiver responder;
- // TODO(lhchavez): Remove this hack. See b/28986534 for details.
- synchronized (mResponders) {
- responder = mResponders.get(requestId);
- if (responder == null) {
- return false;
- }
- mResponders.remove(requestId);
+ MessageReceiver responder = mResponders.get(requestId);
+ if (responder == null) {
+ return false;
}
+ mResponders.remove(requestId);
return responder.accept(message);
} else {
if (mIncomingMessageReceiver != null) {
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Struct.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Struct.java
index 85cc97c..14f4e1e 100644
--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Struct.java
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Struct.java
@@ -6,6 +6,8 @@ package org.chromium.mojo.bindings;
import org.chromium.mojo.system.Core;
+import java.nio.ByteBuffer;
+
/**
* Base class for all mojo structs.
*/
@@ -49,6 +51,23 @@ public abstract class Struct {
}
/**
+ * Similar to the method above, but returns the serialization result as |ByteBuffer|.
+ *
+ * @throws UnsupportedOperationException if the struct contains interfaces or handles.
+ * @throws SerializationException on serialization failure.
+ */
+ public ByteBuffer serialize() {
+ // If the struct contains interfaces which require a non-null |Core| instance, it will throw
+ // UnsupportedOperationException.
+ Message message = serialize(null);
+
+ if (!message.getHandles().isEmpty())
+ throw new UnsupportedOperationException("Handles are discarded.");
+
+ return message.getData();
+ }
+
+ /**
* Returns the serialization of the struct prepended with the given header.
*
* @param header the header to prepend to the returned message.
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/AsyncWaiter.java b/mojo/public/java/system/src/org/chromium/mojo/system/AsyncWaiter.java
deleted file mode 100644
index 474de4b..0000000
--- a/mojo/public/java/system/src/org/chromium/mojo/system/AsyncWaiter.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.mojo.system;
-
-import org.chromium.mojo.system.Core.HandleSignals;
-
-/**
- * A class which implements the {@link AsyncWaiter} allows asynchronously waiting on a background
- * thread.
- */
-public interface AsyncWaiter {
-
- /**
- * Allows cancellation of an asyncWait operation.
- */
- interface Cancellable {
- /**
- * Cancels an asyncWait operation. Has no effect if the operation has already been canceled
- * or the callback has already been called.
- * <p>
- * Must be called from the same thread as {@link AsyncWaiter#asyncWait} was called from.
- */
- void cancel();
- }
-
- /**
- * Callback passed to {@link AsyncWaiter#asyncWait}.
- */
- public interface Callback {
- /**
- * Called when the handle is ready.
- */
- public void onResult(int result);
-
- /**
- * Called when an error occurred while waiting.
- */
- public void onError(MojoException exception);
- }
-
- /**
- * Asynchronously call wait on a background thread. The given {@link Callback} will be notified
- * of the result of the wait on the same thread as asyncWait was called.
- *
- * @return a {@link Cancellable} object that can be used to cancel waiting. The cancellable
- * should only be used on the current thread, and becomes invalid once the callback has
- * been notified.
- */
- Cancellable asyncWait(Handle handle, HandleSignals signals, long deadline, Callback callback);
-
-}
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/Core.java b/mojo/public/java/system/src/org/chromium/mojo/system/Core.java
index ba0e5c6..e5c6d08 100644
--- a/mojo/public/java/system/src/org/chromium/mojo/system/Core.java
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/Core.java
@@ -305,9 +305,9 @@ public interface Core {
public UntypedHandle acquireNativeHandle(int handle);
/**
- * Returns a default implementation of {@link AsyncWaiter}.
+ * Returns an implementation of {@link Watcher}.
*/
- public AsyncWaiter getDefaultAsyncWaiter();
+ public Watcher getWatcher();
/**
* Returns a new run loop.
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/Watcher.java b/mojo/public/java/system/src/org/chromium/mojo/system/Watcher.java
new file mode 100644
index 0000000..9c70161
--- /dev/null
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/Watcher.java
@@ -0,0 +1,38 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.mojo.system;
+
+import org.chromium.mojo.system.Core.HandleSignals;
+
+/**
+ * Watches a handle for signals being satisfied.
+ */
+public interface Watcher {
+ /**
+ * Callback passed to {@link Watcher#start}.
+ */
+ public interface Callback {
+ /**
+ * Called when the handle is ready.
+ */
+ public void onResult(int result);
+ }
+
+ /**
+ * Starts watching a handle.
+ */
+ int start(Handle handle, HandleSignals signals, Callback callback);
+
+ /**
+ * Cancels an already-started watch.
+ */
+ void cancel();
+
+ /**
+ * Destroys the underlying implementation. Other methods will fail after destroy has been
+ * called.
+ */
+ void destroy();
+}
diff --git a/mojo/public/js/BUILD.gn b/mojo/public/js/BUILD.gn
index eda7e04..0fae4b4 100644
--- a/mojo/public/js/BUILD.gn
+++ b/mojo/public/js/BUILD.gn
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+interfaces_bindings_gen_dir = "$root_gen_dir/mojo/public/interfaces/bindings"
+
source_set("js") {
sources = [
"constants.cc",
@@ -11,34 +13,43 @@ source_set("js") {
group("bindings") {
data = [
+ "$interfaces_bindings_gen_dir/interface_control_messages.mojom.js",
"bindings.js",
"buffer.js",
"codec.js",
- "connection.js",
"connector.js",
- "constants.cc",
- "constants.h",
"core.js",
+ "interface_types.js",
+ "lib/control_message_handler.js",
+ "lib/control_message_proxy.js",
"router.js",
"support.js",
"threading.js",
"unicode.js",
"validator.js",
]
+
+ deps = [
+ "//mojo/public/interfaces/bindings:bindings__generator",
+ ]
}
group("tests") {
testonly = true
data = [
- "codec_unittests.js",
- "core_unittests.js",
- "struct_unittests.js",
- "test/validation_test_input_parser.js",
- "union_unittests.js",
- "validation_unittests.js",
"//mojo/public/interfaces/bindings/tests/data/validation/",
+ "tests/codec_unittest.js",
+ "tests/connection_unittest.js",
+ "tests/core_unittest.js",
+ "tests/interface_ptr_unittest.js",
+ "tests/sample_service_unittest.js",
+ "tests/struct_unittest.js",
+ "tests/union_unittest.js",
+ "tests/validation_test_input_parser.js",
+ "tests/validation_unittest.js",
]
+
public_deps = [
":bindings",
]
diff --git a/mojo/public/js/bindings.js b/mojo/public/js/bindings.js
index 2fdcae3..f3e40d2 100644
--- a/mojo/public/js/bindings.js
+++ b/mojo/public/js/bindings.js
@@ -3,115 +3,283 @@
// found in the LICENSE file.
define("mojo/public/js/bindings", [
- "mojo/public/js/router",
"mojo/public/js/core",
-], function(router, core) {
-
- var Router = router.Router;
+ "mojo/public/js/lib/control_message_proxy",
+ "mojo/public/js/interface_types",
+ "mojo/public/js/router",
+], function(core, controlMessageProxy, types, router) {
- var kProxyProperties = Symbol("proxyProperties");
- var kStubProperties = Symbol("stubProperties");
+ // ---------------------------------------------------------------------------
- // Public proxy class properties that are managed at runtime by the JS
- // bindings. See ProxyBindings below.
- function ProxyProperties(receiver) {
- this.receiver = receiver;
+ function makeRequest(interfacePtr) {
+ var pipe = core.createMessagePipe();
+ interfacePtr.ptr.bind(new types.InterfacePtrInfo(pipe.handle0, 0));
+ return new types.InterfaceRequest(pipe.handle1);
}
- // TODO(hansmuller): remove then after 'Client=' has been removed from Mojom.
- ProxyProperties.prototype.getLocalDelegate = function() {
- return this.local && StubBindings(this.local).delegate;
- }
+ // ---------------------------------------------------------------------------
- // TODO(hansmuller): remove then after 'Client=' has been removed from Mojom.
- ProxyProperties.prototype.setLocalDelegate = function(impl) {
- if (this.local)
- StubBindings(this.local).delegate = impl;
- else
- throw new Error("no stub object");
- }
+ // Operations used to setup/configure an interface pointer. Exposed as the
+ // |ptr| field of generated interface pointer classes.
+ // |ptrInfoOrHandle| could be omitted and passed into bind() later.
+ function InterfacePtrController(interfaceType, ptrInfoOrHandle) {
+ this.version = 0;
- ProxyProperties.prototype.close = function() {
- this.connection.close();
- }
+ this.interfaceType_ = interfaceType;
+ this.router_ = null;
+ this.proxy_ = null;
- // Public stub class properties that are managed at runtime by the JS
- // bindings. See StubBindings below.
- function StubProperties(delegate) {
- this.delegate = delegate;
- }
+ // |router_| is lazily initialized. |handle_| is valid between bind() and
+ // the initialization of |router_|.
+ this.handle_ = null;
+ this.controlMessageProxy_ = null;
- StubProperties.prototype.close = function() {
- this.connection.close();
+ if (ptrInfoOrHandle)
+ this.bind(ptrInfoOrHandle);
}
- // The base class for generated proxy classes.
- function ProxyBase(receiver) {
- this[kProxyProperties] = new ProxyProperties(receiver);
+ InterfacePtrController.prototype.bind = function(ptrInfoOrHandle) {
+ this.reset();
- // TODO(hansmuller): Temporary, for Chrome backwards compatibility.
- if (receiver instanceof Router)
- this.receiver_ = receiver;
- }
+ if (ptrInfoOrHandle instanceof types.InterfacePtrInfo) {
+ this.version = ptrInfoOrHandle.version;
+ this.handle_ = ptrInfoOrHandle.handle;
+ } else {
+ this.handle_ = ptrInfoOrHandle;
+ }
+ };
- // The base class for generated stub classes.
- function StubBase(delegate) {
- this[kStubProperties] = new StubProperties(delegate);
- }
+ InterfacePtrController.prototype.isBound = function() {
+ return this.router_ !== null || this.handle_ !== null;
+ };
- // TODO(hansmuller): remove everything except the connection property doc
- // after 'Client=' has been removed from Mojom.
+ // Although users could just discard the object, reset() closes the pipe
+ // immediately.
+ InterfacePtrController.prototype.reset = function() {
+ this.version = 0;
+ if (this.router_) {
+ this.router_.close();
+ this.router_ = null;
- // Provides access to properties added to a proxy object without risking
- // Mojo interface name collisions. Unless otherwise specified, the initial
- // value of all properties is undefined.
- //
- // ProxyBindings(proxy).connection - The Connection object that links the
- // proxy for a remote Mojo service to an optional local stub for a local
- // service. The value of ProxyBindings(proxy).connection.remote == proxy.
+ this.proxy_ = null;
+ }
+ if (this.handle_) {
+ core.close(this.handle_);
+ this.handle_ = null;
+ }
+ };
+
+ InterfacePtrController.prototype.setConnectionErrorHandler
+ = function(callback) {
+ if (!this.isBound())
+ throw new Error("Cannot set connection error handler if not bound.");
+
+ this.configureProxyIfNecessary_();
+ this.router_.setErrorHandler(callback);
+ };
+
+ InterfacePtrController.prototype.passInterface = function() {
+ var result;
+ if (this.router_) {
+ // TODO(yzshen): Fix Router interface to support extracting handle.
+ result = new types.InterfacePtrInfo(
+ this.router_.connector_.handle_, this.version);
+ this.router_.connector_.handle_ = null;
+ } else {
+ // This also handles the case when this object is not bound.
+ result = new types.InterfacePtrInfo(this.handle_, this.version);
+ this.handle_ = null;
+ }
+
+ this.reset();
+ return result;
+ };
+
+ InterfacePtrController.prototype.getProxy = function() {
+ this.configureProxyIfNecessary_();
+ return this.proxy_;
+ };
+
+ InterfacePtrController.prototype.enableTestingMode = function() {
+ this.configureProxyIfNecessary_();
+ return this.router_.enableTestingMode();
+ };
+
+ InterfacePtrController.prototype.configureProxyIfNecessary_ = function() {
+ if (!this.handle_)
+ return;
+
+ this.router_ = new router.Router(this.handle_);
+ this.handle_ = null;
+ this.router_ .setPayloadValidators([this.interfaceType_.validateResponse]);
+
+ this.controlMessageProxy_ = new
+ controlMessageProxy.ControlMessageProxy(this.router_);
+
+ this.proxy_ = new this.interfaceType_.proxyClass(this.router_);
+ };
+
+ InterfacePtrController.prototype.queryVersion = function() {
+ function onQueryVersion(version) {
+ this.version = version;
+ return version;
+ }
+
+ this.configureProxyIfNecessary_();
+ return this.controlMessageProxy_.queryVersion().then(
+ onQueryVersion.bind(this));
+ };
+
+ InterfacePtrController.prototype.requireVersion = function(version) {
+ this.configureProxyIfNecessary_();
+
+ if (this.version >= version) {
+ return;
+ }
+ this.version = version;
+ this.controlMessageProxy_.requireVersion(version);
+ };
+
+ // ---------------------------------------------------------------------------
+
+ // |request| could be omitted and passed into bind() later.
//
- // ProxyBindings(proxy).local - The "local" stub object whose delegate
- // implements the proxy's Mojo client interface.
+ // Example:
//
- // ProxyBindings(proxy).setLocalDelegate(impl) - Sets the implementation
- // delegate of the proxy's client stub object. This is just shorthand
- // for |StubBindings(ProxyBindings(proxy).local).delegate = impl|.
+ // // FooImpl implements mojom.Foo.
+ // function FooImpl() { ... }
+ // FooImpl.prototype.fooMethod1 = function() { ... }
+ // FooImpl.prototype.fooMethod2 = function() { ... }
//
- // ProxyBindings(proxy).getLocalDelegate() - Returns the implementation
- // delegate of the proxy's client stub object. This is just shorthand
- // for |StubBindings(ProxyBindings(proxy).local).delegate|.
+ // var fooPtr = new mojom.FooPtr();
+ // var request = makeRequest(fooPtr);
+ // var binding = new Binding(mojom.Foo, new FooImpl(), request);
+ // fooPtr.fooMethod1();
+ function Binding(interfaceType, impl, requestOrHandle) {
+ this.interfaceType_ = interfaceType;
+ this.impl_ = impl;
+ this.router_ = null;
+ this.stub_ = null;
- function ProxyBindings(proxy) {
- return (proxy instanceof ProxyBase) ? proxy[kProxyProperties] : proxy;
+ if (requestOrHandle)
+ this.bind(requestOrHandle);
}
- // TODO(hansmuller): remove the remote doc after 'Client=' has been
- // removed from Mojom.
+ Binding.prototype.isBound = function() {
+ return this.router_ !== null;
+ };
- // Provides access to properties added to a stub object without risking
- // Mojo interface name collisions. Unless otherwise specified, the initial
- // value of all properties is undefined.
- //
- // StubBindings(stub).delegate - The optional implementation delegate for
- // the Mojo interface stub.
- //
- // StubBindings(stub).connection - The Connection object that links an
- // optional proxy for a remote service to this stub. The value of
- // StubBindings(stub).connection.local == stub.
- //
- // StubBindings(stub).remote - A proxy for the the stub's Mojo client
- // service.
+ Binding.prototype.createInterfacePtrAndBind = function() {
+ var ptr = new this.interfaceType_.ptrClass();
+ // TODO(yzshen): Set the version of the interface pointer.
+ this.bind(makeRequest(ptr));
+ return ptr;
+ }
+
+ Binding.prototype.bind = function(requestOrHandle) {
+ this.close();
+
+ var handle = requestOrHandle instanceof types.InterfaceRequest ?
+ requestOrHandle.handle : requestOrHandle;
+ if (!core.isHandle(handle))
+ return;
+
+ this.stub_ = new this.interfaceType_.stubClass(this.impl_);
+ this.router_ = new router.Router(handle, this.interfaceType_.kVersion);
+ this.router_.setIncomingReceiver(this.stub_);
+ this.router_ .setPayloadValidators([this.interfaceType_.validateRequest]);
+ };
+
+ Binding.prototype.close = function() {
+ if (!this.isBound())
+ return;
+
+ this.router_.close();
+ this.router_ = null;
+ this.stub_ = null;
+ };
+
+ Binding.prototype.setConnectionErrorHandler
+ = function(callback) {
+ if (!this.isBound())
+ throw new Error("Cannot set connection error handler if not bound.");
+ this.router_.setErrorHandler(callback);
+ };
+
+ Binding.prototype.unbind = function() {
+ if (!this.isBound())
+ return new types.InterfaceRequest(null);
+
+ var result = new types.InterfaceRequest(this.router_.connector_.handle_);
+ this.router_.connector_.handle_ = null;
+ this.close();
+ return result;
+ };
+
+ Binding.prototype.enableTestingMode = function() {
+ return this.router_.enableTestingMode();
+ };
- function StubBindings(stub) {
- return stub instanceof StubBase ? stub[kStubProperties] : stub;
+ // ---------------------------------------------------------------------------
+
+ function BindingSetEntry(bindingSet, interfaceType, impl, requestOrHandle,
+ bindingId) {
+ this.bindingSet_ = bindingSet;
+ this.bindingId_ = bindingId;
+ this.binding_ = new Binding(interfaceType, impl, requestOrHandle);
+
+ this.binding_.setConnectionErrorHandler(function() {
+ this.bindingSet_.onConnectionError(bindingId);
+ }.bind(this));
+ }
+
+ BindingSetEntry.prototype.close = function() {
+ this.binding_.close();
+ };
+
+ function BindingSet(interfaceType) {
+ this.interfaceType_ = interfaceType;
+ this.nextBindingId_ = 0;
+ this.bindings_ = new Map();
+ this.errorHandler_ = null;
}
+ BindingSet.prototype.isEmpty = function() {
+ return this.bindings_.size == 0;
+ };
+
+ BindingSet.prototype.addBinding = function(impl, requestOrHandle) {
+ this.bindings_.set(
+ this.nextBindingId_,
+ new BindingSetEntry(this, this.interfaceType_, impl, requestOrHandle,
+ this.nextBindingId_));
+ ++this.nextBindingId_;
+ };
+
+ BindingSet.prototype.closeAllBindings = function() {
+ for (var entry of this.bindings_.values())
+ entry.close();
+ this.bindings_.clear();
+ };
+
+ BindingSet.prototype.setConnectionErrorHandler = function(callback) {
+ this.errorHandler_ = callback;
+ };
+
+ BindingSet.prototype.onConnectionError = function(bindingId) {
+ this.bindings_.delete(bindingId);
+
+ if (this.errorHandler_)
+ this.errorHandler_();
+ };
+
var exports = {};
- exports.EmptyProxy = ProxyBase;
- exports.EmptyStub = StubBase;
- exports.ProxyBase = ProxyBase;
- exports.ProxyBindings = ProxyBindings;
- exports.StubBase = StubBase;
- exports.StubBindings = StubBindings;
+ exports.InterfacePtrInfo = types.InterfacePtrInfo;
+ exports.InterfaceRequest = types.InterfaceRequest;
+ exports.makeRequest = makeRequest;
+ exports.InterfacePtrController = InterfacePtrController;
+ exports.Binding = Binding;
+ exports.BindingSet = BindingSet;
+
return exports;
});
diff --git a/mojo/public/js/codec.js b/mojo/public/js/codec.js
index 4003b51..ff5d31a 100644
--- a/mojo/public/js/codec.js
+++ b/mojo/public/js/codec.js
@@ -3,9 +3,10 @@
// found in the LICENSE file.
define("mojo/public/js/codec", [
- "mojo/public/js/unicode",
"mojo/public/js/buffer",
-], function(unicode, buffer) {
+ "mojo/public/js/interface_types",
+ "mojo/public/js/unicode",
+], function(buffer, types, unicode) {
var kErrorUnsigned = "Passing negative value to unsigned";
var kErrorArray = "Passing non Array for array type";
@@ -303,8 +304,12 @@ define("mojo/public/js/codec", [
};
Encoder.prototype.encodeHandle = function(handle) {
- this.handles.push(handle);
- this.writeUint32(this.handles.length - 1);
+ if (handle) {
+ this.handles.push(handle);
+ this.writeUint32(this.handles.length - 1);
+ } else {
+ this.writeUint32(kEncodedInvalidHandleValue);
+ }
};
Encoder.prototype.encodeString = function(val) {
@@ -711,6 +716,20 @@ define("mojo/public/js/codec", [
encoder.writeDouble(val);
};
+ function Enum(cls) {
+ this.cls = cls;
+ }
+
+ Enum.prototype.encodedSize = 4;
+
+ Enum.prototype.decode = function(decoder) {
+ return decoder.readInt32();
+ };
+
+ Enum.prototype.encode = function(encoder, val) {
+ encoder.writeInt32(val);
+ };
+
function PointerTo(cls) {
this.cls = cls;
}
@@ -788,33 +807,54 @@ define("mojo/public/js/codec", [
NullableHandle.encode = Handle.encode;
- function Interface() {
+ function Interface(cls) {
+ this.cls = cls;
}
- Interface.encodedSize = 8;
+ Interface.prototype.encodedSize = 8;
- Interface.decode = function(decoder) {
- var handle = decoder.decodeHandle();
- // Ignore the version field for now.
- decoder.readUint32();
+ Interface.prototype.decode = function(decoder) {
+ var interfacePtrInfo = new types.InterfacePtrInfo(
+ decoder.decodeHandle(), decoder.readUint32());
+ var interfacePtr = new this.cls();
+ interfacePtr.ptr.bind(interfacePtrInfo);
+ return interfacePtr;
+ };
- return handle;
+ Interface.prototype.encode = function(encoder, val) {
+ var interfacePtrInfo =
+ val ? val.ptr.passInterface() : new types.InterfacePtrInfo(null, 0);
+ encoder.encodeHandle(interfacePtrInfo.handle);
+ encoder.writeUint32(interfacePtrInfo.version);
};
- Interface.encode = function(encoder, val) {
- encoder.encodeHandle(val);
- // Set the version field to 0 for now.
- encoder.writeUint32(0);
+ function NullableInterface(cls) {
+ Interface.call(this, cls);
+ }
+
+ NullableInterface.prototype = Object.create(Interface.prototype);
+
+ function InterfaceRequest() {
+ }
+
+ InterfaceRequest.encodedSize = 4;
+
+ InterfaceRequest.decode = function(decoder) {
+ return new types.InterfaceRequest(decoder.decodeHandle());
+ };
+
+ InterfaceRequest.encode = function(encoder, val) {
+ encoder.encodeHandle(val ? val.handle : null);
};
- function NullableInterface() {
+ function NullableInterfaceRequest() {
}
- NullableInterface.encodedSize = Interface.encodedSize;
+ NullableInterfaceRequest.encodedSize = InterfaceRequest.encodedSize;
- NullableInterface.decode = Interface.decode;
+ NullableInterfaceRequest.decode = InterfaceRequest.decode;
- NullableInterface.encode = Interface.encode;
+ NullableInterfaceRequest.encode = InterfaceRequest.encode;
function MapOf(keyClass, valueClass) {
this.keyClass = keyClass;
@@ -863,6 +903,7 @@ define("mojo/public/js/codec", [
exports.Float = Float;
exports.Double = Double;
exports.String = String;
+ exports.Enum = Enum;
exports.NullableString = NullableString;
exports.PointerTo = PointerTo;
exports.NullablePointerTo = NullablePointerTo;
@@ -873,6 +914,8 @@ define("mojo/public/js/codec", [
exports.NullableHandle = NullableHandle;
exports.Interface = Interface;
exports.NullableInterface = NullableInterface;
+ exports.InterfaceRequest = InterfaceRequest;
+ exports.NullableInterfaceRequest = NullableInterfaceRequest;
exports.MapOf = MapOf;
exports.NullableMapOf = NullableMapOf;
return exports;
diff --git a/mojo/public/js/codec_unittests.js b/mojo/public/js/codec_unittests.js
deleted file mode 100644
index b610d9a..0000000
--- a/mojo/public/js/codec_unittests.js
+++ /dev/null
@@ -1,296 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define([
- "gin/test/expect",
- "mojo/public/js/codec",
- "mojo/public/interfaces/bindings/tests/rect.mojom",
- "mojo/public/interfaces/bindings/tests/sample_service.mojom",
- "mojo/public/interfaces/bindings/tests/test_structs.mojom",
- ], function(expect, codec, rect, sample, structs) {
- testBar();
- testFoo();
- testNamedRegion();
- testTypes();
- testAlign();
- testUtf8();
- testTypedPointerValidation();
- this.result = "PASS";
-
- function testBar() {
- var bar = new sample.Bar();
- bar.alpha = 1;
- bar.beta = 2;
- bar.gamma = 3;
- bar.type = 0x08070605;
- bar.extraProperty = "banana";
-
- var messageName = 42;
- var payloadSize = sample.Bar.encodedSize;
-
- var builder = new codec.MessageBuilder(messageName, payloadSize);
- builder.encodeStruct(sample.Bar, bar);
-
- var message = builder.finish();
-
- var expectedMemory = new Uint8Array([
- 24, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 42, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
-
- 16, 0, 0, 0,
- 0, 0, 0, 0,
-
- 1, 2, 3, 0,
- 5, 6, 7, 8,
- ]);
-
- var actualMemory = new Uint8Array(message.buffer.arrayBuffer);
- expect(actualMemory).toEqual(expectedMemory);
-
- var reader = new codec.MessageReader(message);
-
- expect(reader.payloadSize).toBe(payloadSize);
- expect(reader.messageName).toBe(messageName);
-
- var bar2 = reader.decodeStruct(sample.Bar);
-
- expect(bar2.alpha).toBe(bar.alpha);
- expect(bar2.beta).toBe(bar.beta);
- expect(bar2.gamma).toBe(bar.gamma);
- expect("extraProperty" in bar2).toBeFalsy();
- }
-
- function testFoo() {
- var foo = new sample.Foo();
- foo.x = 0x212B4D5;
- foo.y = 0x16E93;
- foo.a = 1;
- foo.b = 0;
- foo.c = 3; // This will get truncated to one bit.
- foo.bar = new sample.Bar();
- foo.bar.alpha = 91;
- foo.bar.beta = 82;
- foo.bar.gamma = 73;
- foo.data = [
- 4, 5, 6, 7, 8,
- ];
- foo.extra_bars = [
- new sample.Bar(), new sample.Bar(), new sample.Bar(),
- ];
- for (var i = 0; i < foo.extra_bars.length; ++i) {
- foo.extra_bars[i].alpha = 1 * i;
- foo.extra_bars[i].beta = 2 * i;
- foo.extra_bars[i].gamma = 3 * i;
- }
- foo.name = "I am a banana";
- // This is supposed to be a handle, but we fake it with an integer.
- foo.source = 23423782;
- foo.array_of_array_of_bools = [
- [true], [false, true]
- ];
- foo.array_of_bools = [
- true, false, true, false, true, false, true, true
- ];
-
-
- var messageName = 31;
- var payloadSize = 304;
-
- var builder = new codec.MessageBuilder(messageName, payloadSize);
- builder.encodeStruct(sample.Foo, foo);
-
- var message = builder.finish();
-
- var expectedMemory = new Uint8Array([
- /* 0: */ 24, 0, 0, 0, 0, 0, 0, 0,
- /* 8: */ 0, 0, 0, 0, 31, 0, 0, 0,
- /* 16: */ 0, 0, 0, 0, 0, 0, 0, 0,
- /* 24: */ 96, 0, 0, 0, 0, 0, 0, 0,
- /* 32: */ 0xD5, 0xB4, 0x12, 0x02, 0x93, 0x6E, 0x01, 0,
- /* 40: */ 5, 0, 0, 0, 0, 0, 0, 0,
- /* 48: */ 72, 0, 0, 0, 0, 0, 0, 0,
- ]);
- // TODO(abarth): Test more of the message's raw memory.
- var actualMemory = new Uint8Array(message.buffer.arrayBuffer,
- 0, expectedMemory.length);
- expect(actualMemory).toEqual(expectedMemory);
-
- var expectedHandles = [
- 23423782,
- ];
-
- expect(message.handles).toEqual(expectedHandles);
-
- var reader = new codec.MessageReader(message);
-
- expect(reader.payloadSize).toBe(payloadSize);
- expect(reader.messageName).toBe(messageName);
-
- var foo2 = reader.decodeStruct(sample.Foo);
-
- expect(foo2.x).toBe(foo.x);
- expect(foo2.y).toBe(foo.y);
-
- expect(foo2.a).toBe(foo.a & 1 ? true : false);
- expect(foo2.b).toBe(foo.b & 1 ? true : false);
- expect(foo2.c).toBe(foo.c & 1 ? true : false);
-
- expect(foo2.bar).toEqual(foo.bar);
- expect(foo2.data).toEqual(foo.data);
-
- expect(foo2.extra_bars).toEqual(foo.extra_bars);
- expect(foo2.name).toBe(foo.name);
- expect(foo2.source).toEqual(foo.source);
-
- expect(foo2.array_of_bools).toEqual(foo.array_of_bools);
- }
-
- function createRect(x, y, width, height) {
- var r = new rect.Rect();
- r.x = x;
- r.y = y;
- r.width = width;
- r.height = height;
- return r;
- }
-
- // Verify that the references to the imported Rect type in test_structs.mojom
- // are generated correctly.
- function testNamedRegion() {
- var r = new structs.NamedRegion();
- r.name = "rectangle";
- r.rects = new Array(createRect(1, 2, 3, 4), createRect(10, 20, 30, 40));
-
- var builder = new codec.MessageBuilder(1, structs.NamedRegion.encodedSize);
- builder.encodeStruct(structs.NamedRegion, r);
- var reader = new codec.MessageReader(builder.finish());
- var result = reader.decodeStruct(structs.NamedRegion);
-
- expect(result.name).toEqual("rectangle");
- expect(result.rects[0]).toEqual(createRect(1, 2, 3, 4));
- expect(result.rects[1]).toEqual(createRect(10, 20, 30, 40));
- }
-
- function testTypes() {
- function encodeDecode(cls, input, expectedResult, encodedSize) {
- var messageName = 42;
- var payloadSize = encodedSize || cls.encodedSize;
-
- var builder = new codec.MessageBuilder(messageName, payloadSize);
- builder.encodeStruct(cls, input)
- var message = builder.finish();
-
- var reader = new codec.MessageReader(message);
- expect(reader.payloadSize).toBe(payloadSize);
- expect(reader.messageName).toBe(messageName);
- var result = reader.decodeStruct(cls);
- expect(result).toEqual(expectedResult);
- }
- encodeDecode(codec.String, "banana", "banana", 24);
- encodeDecode(codec.NullableString, null, null, 8);
- encodeDecode(codec.Int8, -1, -1);
- encodeDecode(codec.Int8, 0xff, -1);
- encodeDecode(codec.Int16, -1, -1);
- encodeDecode(codec.Int16, 0xff, 0xff);
- encodeDecode(codec.Int16, 0xffff, -1);
- encodeDecode(codec.Int32, -1, -1);
- encodeDecode(codec.Int32, 0xffff, 0xffff);
- encodeDecode(codec.Int32, 0xffffffff, -1);
- encodeDecode(codec.Float, 1.0, 1.0);
- encodeDecode(codec.Double, 1.0, 1.0);
- }
-
- function testAlign() {
- var aligned = [
- 0, // 0
- 8, // 1
- 8, // 2
- 8, // 3
- 8, // 4
- 8, // 5
- 8, // 6
- 8, // 7
- 8, // 8
- 16, // 9
- 16, // 10
- 16, // 11
- 16, // 12
- 16, // 13
- 16, // 14
- 16, // 15
- 16, // 16
- 24, // 17
- 24, // 18
- 24, // 19
- 24, // 20
- ];
- for (var i = 0; i < aligned.length; ++i)
- expect(codec.align(i)).toBe(aligned[i]);
- }
-
- function testUtf8() {
- var str = "B\u03ba\u1f79"; // some UCS-2 codepoints
- var messageName = 42;
- var payloadSize = 24;
-
- var builder = new codec.MessageBuilder(messageName, payloadSize);
- var encoder = builder.createEncoder(8);
- encoder.encodeStringPointer(str);
- var message = builder.finish();
- var expectedMemory = new Uint8Array([
- /* 0: */ 24, 0, 0, 0, 0, 0, 0, 0,
- /* 8: */ 0, 0, 0, 0, 42, 0, 0, 0,
- /* 16: */ 0, 0, 0, 0, 0, 0, 0, 0,
- /* 24: */ 8, 0, 0, 0, 0, 0, 0, 0,
- /* 32: */ 14, 0, 0, 0, 6, 0, 0, 0,
- /* 40: */ 0x42, 0xCE, 0xBA, 0xE1, 0xBD, 0xB9, 0, 0,
- ]);
- var actualMemory = new Uint8Array(message.buffer.arrayBuffer);
- expect(actualMemory.length).toEqual(expectedMemory.length);
- expect(actualMemory).toEqual(expectedMemory);
-
- var reader = new codec.MessageReader(message);
- expect(reader.payloadSize).toBe(payloadSize);
- expect(reader.messageName).toBe(messageName);
- var str2 = reader.decoder.decodeStringPointer();
- expect(str2).toEqual(str);
- }
-
- function testTypedPointerValidation() {
- var encoder = new codec.MessageBuilder(42, 24).createEncoder(8);
- function DummyClass() {};
- var testCases = [
- // method, args, invalid examples, valid examples
- [encoder.encodeArrayPointer, [DummyClass], [75],
- [[], null, undefined, new Uint8Array([])]],
- [encoder.encodeStringPointer, [], [75, new String("foo")],
- ["", "bar", null, undefined]],
- [encoder.encodeMapPointer, [DummyClass, DummyClass], [75],
- [new Map(), null, undefined]],
- ];
-
- testCases.forEach(function(test) {
- var method = test[0];
- var baseArgs = test[1];
- var invalidExamples = test[2];
- var validExamples = test[3];
-
- var encoder = new codec.MessageBuilder(42, 24).createEncoder(8);
- invalidExamples.forEach(function(invalid) {
- expect(function() {
- method.apply(encoder, baseArgs.concat(invalid));
- }).toThrow();
- });
-
- validExamples.forEach(function(valid) {
- var encoder = new codec.MessageBuilder(42, 24).createEncoder(8);
- method.apply(encoder, baseArgs.concat(valid));
- });
- });
- }
-});
diff --git a/mojo/public/js/connection.js b/mojo/public/js/connection.js
deleted file mode 100644
index 3f7e839..0000000
--- a/mojo/public/js/connection.js
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define("mojo/public/js/connection", [
- "mojo/public/js/bindings",
- "mojo/public/js/connector",
- "mojo/public/js/core",
- "mojo/public/js/router",
-], function(bindings, connector, core, router) {
-
- var Router = router.Router;
- var EmptyProxy = bindings.EmptyProxy;
- var EmptyStub = bindings.EmptyStub;
- var ProxyBindings = bindings.ProxyBindings;
- var StubBindings = bindings.StubBindings;
- var TestConnector = connector.TestConnector;
- var TestRouter = router.TestRouter;
-
- // TODO(hansmuller): the proxy receiver_ property should be receiver$
-
- function BaseConnection(localStub, remoteProxy, router) {
- this.router_ = router;
- this.local = localStub;
- this.remote = remoteProxy;
-
- this.router_.setIncomingReceiver(localStub);
- this.router_.setErrorHandler(function() {
- if (StubBindings(this.local) &&
- StubBindings(this.local).connectionErrorHandler)
- StubBindings(this.local).connectionErrorHandler();
- }.bind(this));
- if (this.remote)
- this.remote.receiver_ = router;
-
- // Validate incoming messages: remote responses and local requests.
- var validateRequest = localStub && localStub.validator;
- var validateResponse = remoteProxy && remoteProxy.validator;
- var payloadValidators = [];
- if (validateRequest)
- payloadValidators.push(validateRequest);
- if (validateResponse)
- payloadValidators.push(validateResponse);
- this.router_.setPayloadValidators(payloadValidators);
- }
-
- BaseConnection.prototype.close = function() {
- this.router_.close();
- this.router_ = null;
- this.local = null;
- this.remote = null;
- };
-
- BaseConnection.prototype.encounteredError = function() {
- return this.router_.encounteredError();
- };
-
- function Connection(
- handle, localFactory, remoteFactory, routerFactory, connectorFactory) {
- var routerClass = routerFactory || Router;
- var router = new routerClass(handle, connectorFactory);
- var remoteProxy = remoteFactory && new remoteFactory(router);
- var localStub = localFactory && new localFactory(remoteProxy);
- BaseConnection.call(this, localStub, remoteProxy, router);
- }
-
- Connection.prototype = Object.create(BaseConnection.prototype);
-
- // The TestConnection subclass is only intended to be used in unit tests.
- function TestConnection(handle, localFactory, remoteFactory) {
- Connection.call(this,
- handle,
- localFactory,
- remoteFactory,
- TestRouter,
- TestConnector);
- }
-
- TestConnection.prototype = Object.create(Connection.prototype);
-
- // Return a handle for a message pipe that's connected to a proxy
- // for remoteInterface. Used by generated code for outgoing interface&
- // (request) parameters: the caller is given the generated proxy via
- // |proxyCallback(proxy)| and the generated code sends the handle
- // returned by this function.
- function bindProxy(proxyCallback, remoteInterface) {
- var messagePipe = core.createMessagePipe();
- if (messagePipe.result != core.RESULT_OK)
- throw new Error("createMessagePipe failed " + messagePipe.result);
-
- var proxy = new remoteInterface.proxyClass;
- var router = new Router(messagePipe.handle0);
- var connection = new BaseConnection(undefined, proxy, router);
- ProxyBindings(proxy).connection = connection;
- if (proxyCallback)
- proxyCallback(proxy);
-
- return messagePipe.handle1;
- }
-
- // Return a handle for a message pipe that's connected to a stub for
- // localInterface. Used by generated code for outgoing interface
- // parameters: the caller is given the generated stub via
- // |stubCallback(stub)| and the generated code sends the handle
- // returned by this function. The caller is responsible for managing
- // the lifetime of the stub and for setting it's implementation
- // delegate with: StubBindings(stub).delegate = myImpl;
- function bindImpl(stubCallback, localInterface) {
- var messagePipe = core.createMessagePipe();
- if (messagePipe.result != core.RESULT_OK)
- throw new Error("createMessagePipe failed " + messagePipe.result);
-
- var stub = new localInterface.stubClass;
- var router = new Router(messagePipe.handle0);
- var connection = new BaseConnection(stub, undefined, router);
- StubBindings(stub).connection = connection;
- if (stubCallback)
- stubCallback(stub);
-
- return messagePipe.handle1;
- }
-
- // Return a remoteInterface proxy for handle. Used by generated code
- // for converting incoming interface parameters to proxies.
- function bindHandleToProxy(handle, remoteInterface) {
- if (!core.isHandle(handle))
- throw new Error("Not a handle " + handle);
-
- var proxy = new remoteInterface.proxyClass;
- var router = new Router(handle);
- var connection = new BaseConnection(undefined, proxy, router);
- ProxyBindings(proxy).connection = connection;
- return proxy;
- }
-
- // Return a localInterface stub for handle. Used by generated code
- // for converting incoming interface& request parameters to localInterface
- // stubs. The caller can specify the stub's implementation of localInterface
- // like this: StubBindings(stub).delegate = myStubImpl.
- function bindHandleToStub(handle, localInterface) {
- if (!core.isHandle(handle))
- throw new Error("Not a handle " + handle);
-
- var stub = new localInterface.stubClass;
- var router = new Router(handle);
- var connection = new BaseConnection(stub, undefined, router);
- StubBindings(stub).connection = connection;
- return stub;
- }
-
- /**
- * Creates a messape pipe and links one end of the pipe to the given object.
- * @param {!Object} obj The object to create a handle for. Must be a subclass
- * of an auto-generated stub class.
- * @return {!MojoHandle} The other (not yet connected) end of the message
- * pipe.
- */
- function bindStubDerivedImpl(obj) {
- var pipe = core.createMessagePipe();
- var router = new Router(pipe.handle0);
- var connection = new BaseConnection(obj, undefined, router);
- obj.connection = connection;
- return pipe.handle1;
- }
-
- var exports = {};
- exports.Connection = Connection;
- exports.TestConnection = TestConnection;
-
- exports.bindProxy = bindProxy;
- exports.bindImpl = bindImpl;
- exports.bindHandleToProxy = bindHandleToProxy;
- exports.bindHandleToStub = bindHandleToStub;
- exports.bindStubDerivedImpl = bindStubDerivedImpl;
- return exports;
-});
diff --git a/mojo/public/js/connector.js b/mojo/public/js/connector.js
index 674f36b..ee16be8 100644
--- a/mojo/public/js/connector.js
+++ b/mojo/public/js/connector.js
@@ -82,6 +82,12 @@ define("mojo/public/js/connector", [
return this.error_;
};
+ Connector.prototype.waitForNextMessageForTesting = function() {
+ var wait = core.wait(this.handle_, core.HANDLE_SIGNAL_READABLE,
+ core.DEADLINE_INDEFINITE);
+ this.readMore_(wait.result);
+ };
+
Connector.prototype.readMore_ = function(result) {
for (;;) {
var read = core.readMessage(this.handle_,
@@ -98,29 +104,12 @@ define("mojo/public/js/connector", [
}
var messageBuffer = new buffer.Buffer(read.buffer);
var message = new codec.Message(messageBuffer, read.handles);
- if (this.incomingReceiver_) {
- this.incomingReceiver_.accept(message);
- }
+ if (this.incomingReceiver_)
+ this.incomingReceiver_.accept(message);
}
};
- // The TestConnector subclass is only intended to be used in unit tests. It
- // doesn't automatically listen for input messages. Instead, you need to
- // call waitForNextMessage to block and wait for the next incoming message.
- function TestConnector(handle) {
- Connector.call(this, handle);
- }
-
- TestConnector.prototype = Object.create(Connector.prototype);
-
- TestConnector.prototype.waitForNextMessage = function() {
- var wait = core.wait(this.handle_, core.HANDLE_SIGNAL_READABLE,
- core.DEADLINE_INDEFINITE);
- this.readMore_(wait.result);
- }
-
var exports = {};
exports.Connector = Connector;
- exports.TestConnector = TestConnector;
return exports;
});
diff --git a/mojo/public/js/constants.cc b/mojo/public/js/constants.cc
index d29f5cb..58cf274 100644
--- a/mojo/public/js/constants.cc
+++ b/mojo/public/js/constants.cc
@@ -9,10 +9,15 @@ namespace mojo {
const char kBindingsModuleName[] = "mojo/public/js/bindings";
const char kBufferModuleName[] = "mojo/public/js/buffer";
const char kCodecModuleName[] = "mojo/public/js/codec";
-const char kConnectionModuleName[] = "mojo/public/js/connection";
const char kConnectorModuleName[] = "mojo/public/js/connector";
-const char kUnicodeModuleName[] = "mojo/public/js/unicode";
+const char kControlMessageHandlerModuleName[] =
+ "mojo/public/js/lib/control_message_handler";
+const char kControlMessageProxyModuleName[] =
+ "mojo/public/js/lib/control_message_proxy";
+const char kInterfaceControlMessagesMojom[] =
+ "mojo/public/interfaces/bindings/interface_control_messages.mojom";
+const char kInterfaceTypesModuleName[] = "mojo/public/js/interface_types";
const char kRouterModuleName[] = "mojo/public/js/router";
+const char kUnicodeModuleName[] = "mojo/public/js/unicode";
const char kValidatorModuleName[] = "mojo/public/js/validator";
-
} // namespace mojo
diff --git a/mojo/public/js/constants.h b/mojo/public/js/constants.h
index de75a90..9d32d20 100644
--- a/mojo/public/js/constants.h
+++ b/mojo/public/js/constants.h
@@ -11,10 +11,13 @@ namespace mojo {
extern const char kBindingsModuleName[];
extern const char kBufferModuleName[];
extern const char kCodecModuleName[];
-extern const char kConnectionModuleName[];
extern const char kConnectorModuleName[];
-extern const char kUnicodeModuleName[];
+extern const char kControlMessageHandlerModuleName[];
+extern const char kControlMessageProxyModuleName[];
+extern const char kInterfaceControlMessagesMojom[];
+extern const char kInterfaceTypesModuleName[];
extern const char kRouterModuleName[];
+extern const char kUnicodeModuleName[];
extern const char kValidatorModuleName[];
} // namespace mojo
diff --git a/mojo/public/js/core.js b/mojo/public/js/core.js
index b89a956..ef480ee 100644
--- a/mojo/public/js/core.js
+++ b/mojo/public/js/core.js
@@ -114,6 +114,27 @@ var READ_DATA_FLAG_QUERY;
var READ_DATA_FLAG_PEEK;
/**
+ * MojoCreateSharedBufferOptionsFlags: Used to specify options to
+ * |createSharedBuffer()|.
+ * See core.h for more information.
+ */
+var CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE;
+
+/**
+ * MojoDuplicateBufferHandleOptionsFlags: Used to specify options to
+ * |duplicateBufferHandle()|.
+ * See core.h for more information.
+ */
+var DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE;
+var DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY;
+
+/**
+ * MojoMapBufferFlags: Used to specify options to |mapBuffer()|.
+ * See core.h for more information.
+ */
+var MAP_BUFFER_FLAG_NONE;
+
+/**
* Closes the given |handle|. See MojoClose for more info.
* @param {MojoHandle} Handle to close.
* @return {MojoResult} Result code.
@@ -236,3 +257,57 @@ function readData(handle, flags) { [native code] }
* @return true or false
*/
function isHandle(value) { [native code] }
+
+/**
+ * Creates shared buffer of specified size |num_bytes|.
+ * See MojoCreateSharedBuffer for more information including error codes.
+ *
+ * @param {number} num_bytes Size of the memory to be allocated for shared
+ * @param {MojoCreateSharedBufferOptionsFlags} flags Flags.
+ * buffer.
+ * @return {object} An object of the form {
+ * result, // |RESULT_OK| on success, error code otherwise.
+ * handle, // An MojoHandle for shared buffer (only on success).
+ * }
+ */
+function createSharedBuffer(num_bytes, flags) { [native code] }
+
+/**
+ * Duplicates the |buffer_handle| to a shared buffer. Duplicated handle can be
+ * sent to another process over message pipe. See MojoDuplicateBufferHandle for
+ * more information including error codes.
+ *
+ * @param {MojoHandle} buffer_handle MojoHandle.
+ * @param {MojoCreateSharedBufferOptionsFlags} flags Flags.
+ * @return {object} An object of the form {
+ * result, // |RESULT_OK| on success, error code otherwise.
+ * handle, // A duplicated MojoHandle for shared buffer (only on success).
+ * }
+ */
+function duplicateBufferHandle(buffer_handle, flags) { [native code] }
+
+/**
+ * Maps the part (at offset |offset| of length |num_bytes|) of the buffer given
+ * by |buffer_handle| into ArrayBuffer memory |buffer|, with options specified
+ * by |flags|. See MojoMapBuffer for more information including error codes.
+ *
+ * @param {MojoHandle} buffer_handle A sharedBufferHandle returned by
+ * createSharedBuffer.
+ * @param {number} offset Offset.
+ * @param {number} num_bytes Size of the memory to be mapped.
+ * @param {MojoMapBufferFlags} flags Flags.
+ * @return {object} An object of the form {
+ * result, // |RESULT_OK| on success, error code otherwise.
+ * buffer, // An ArrayBuffer (only on success).
+ * }
+ */
+function mapBuffer(buffer_handle, offset, num_bytes, flags) { [native code] }
+
+/**
+ * Unmaps buffer that was mapped using mapBuffer.
+ * See MojoUnmapBuffer for more information including error codes.
+ *
+ * @param {ArrayBuffer} buffer ArrayBuffer.
+ * @return {MojoResult} Result code.
+ */
+function unmapBuffer(buffer) { [native code] }
diff --git a/mojo/public/js/core_unittests.js b/mojo/public/js/core_unittests.js
deleted file mode 100644
index 12364dc..0000000
--- a/mojo/public/js/core_unittests.js
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define([
- "gin/test/expect",
- "mojo/public/js/core",
- "gc",
- ], function(expect, core, gc) {
-
- var HANDLE_SIGNAL_READWRITABLE = core.HANDLE_SIGNAL_WRITABLE |
- core.HANDLE_SIGNAL_READABLE;
- var HANDLE_SIGNAL_ALL = core.HANDLE_SIGNAL_WRITABLE |
- core.HANDLE_SIGNAL_READABLE |
- core.HANDLE_SIGNAL_PEER_CLOSED;
-
- runWithMessagePipe(testNop);
- runWithMessagePipe(testReadAndWriteMessage);
- runWithMessagePipeWithOptions(testNop);
- runWithMessagePipeWithOptions(testReadAndWriteMessage);
- runWithDataPipe(testNop);
- runWithDataPipe(testReadAndWriteDataPipe);
- runWithDataPipeWithOptions(testNop);
- runWithDataPipeWithOptions(testReadAndWriteDataPipe);
- runWithMessagePipe(testIsHandleMessagePipe);
- runWithDataPipe(testIsHandleDataPipe);
- gc.collectGarbage(); // should not crash
- this.result = "PASS";
-
- function runWithMessagePipe(test) {
- var pipe = core.createMessagePipe();
- expect(pipe.result).toBe(core.RESULT_OK);
-
- test(pipe);
-
- expect(core.close(pipe.handle0)).toBe(core.RESULT_OK);
- expect(core.close(pipe.handle1)).toBe(core.RESULT_OK);
- }
-
- function runWithMessagePipeWithOptions(test) {
- var pipe = core.createMessagePipe({
- flags: core.CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE
- });
- expect(pipe.result).toBe(core.RESULT_OK);
-
- test(pipe);
-
- expect(core.close(pipe.handle0)).toBe(core.RESULT_OK);
- expect(core.close(pipe.handle1)).toBe(core.RESULT_OK);
- }
-
- function runWithDataPipe(test) {
- var pipe = core.createDataPipe();
- expect(pipe.result).toBe(core.RESULT_OK);
-
- test(pipe);
-
- expect(core.close(pipe.producerHandle)).toBe(core.RESULT_OK);
- expect(core.close(pipe.consumerHandle)).toBe(core.RESULT_OK);
- }
-
- function runWithDataPipeWithOptions(test) {
- var pipe = core.createDataPipe({
- flags: core.CREATE_DATA_PIPE_OPTIONS_FLAG_NONE,
- elementNumBytes: 1,
- capacityNumBytes: 64
- });
- expect(pipe.result).toBe(core.RESULT_OK);
-
- test(pipe);
-
- expect(core.close(pipe.producerHandle)).toBe(core.RESULT_OK);
- expect(core.close(pipe.consumerHandle)).toBe(core.RESULT_OK);
- }
-
- function testNop(pipe) {
- }
-
- function testReadAndWriteMessage(pipe) {
- var wait = core.waitMany([], [], 0);
- expect(wait.result).toBe(core.RESULT_INVALID_ARGUMENT);
- expect(wait.index).toBe(null);
- expect(wait.signalsState).toBe(null);
-
- wait = core.wait(pipe.handle0, core.HANDLE_SIGNAL_READABLE, 0);
- expect(wait.result).toBe(core.RESULT_DEADLINE_EXCEEDED);
- expect(wait.signalsState.satisfiedSignals).toBe(
- core.HANDLE_SIGNAL_WRITABLE);
- expect(wait.signalsState.satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
-
- wait = core.waitMany(
- [pipe.handle0, pipe.handle1],
- [core.HANDLE_SIGNAL_READABLE,core.HANDLE_SIGNAL_READABLE],
- 0);
- expect(wait.result).toBe(core.RESULT_DEADLINE_EXCEEDED);
- expect(wait.index).toBe(null);
- expect(wait.signalsState[0].satisfiedSignals).toBe(
- core.HANDLE_SIGNAL_WRITABLE);
- expect(wait.signalsState[0].satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
- expect(wait.signalsState[1].satisfiedSignals).toBe(
- core.HANDLE_SIGNAL_WRITABLE);
- expect(wait.signalsState[1].satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
-
- wait = core.wait(pipe.handle0, core.HANDLE_SIGNAL_WRITABLE, 0);
- expect(wait.result).toBe(core.RESULT_OK);
- expect(wait.signalsState.satisfiedSignals).toBe(
- core.HANDLE_SIGNAL_WRITABLE);
- expect(wait.signalsState.satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
-
- var senderData = new Uint8Array(42);
- for (var i = 0; i < senderData.length; ++i) {
- senderData[i] = i * i;
- }
-
- var result = core.writeMessage(
- pipe.handle0, senderData, [],
- core.WRITE_MESSAGE_FLAG_NONE);
-
- expect(result).toBe(core.RESULT_OK);
-
- wait = core.wait(pipe.handle0, core.HANDLE_SIGNAL_WRITABLE, 0);
- expect(wait.result).toBe(core.RESULT_OK);
- expect(wait.signalsState.satisfiedSignals).toBe(
- core.HANDLE_SIGNAL_WRITABLE);
- expect(wait.signalsState.satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
-
- wait = core.wait(pipe.handle1, core.HANDLE_SIGNAL_READABLE,
- core.DEADLINE_INDEFINITE);
- expect(wait.result).toBe(core.RESULT_OK);
- expect(wait.signalsState.satisfiedSignals).toBe(HANDLE_SIGNAL_READWRITABLE);
- expect(wait.signalsState.satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
-
- var read = core.readMessage(pipe.handle1, core.READ_MESSAGE_FLAG_NONE);
-
- expect(read.result).toBe(core.RESULT_OK);
- expect(read.buffer.byteLength).toBe(42);
- expect(read.handles.length).toBe(0);
-
- var memory = new Uint8Array(read.buffer);
- for (var i = 0; i < memory.length; ++i)
- expect(memory[i]).toBe((i * i) & 0xFF);
- }
-
- function testReadAndWriteDataPipe(pipe) {
- var senderData = new Uint8Array(42);
- for (var i = 0; i < senderData.length; ++i) {
- senderData[i] = i * i;
- }
-
- var write = core.writeData(
- pipe.producerHandle, senderData,
- core.WRITE_DATA_FLAG_ALL_OR_NONE);
-
- expect(write.result).toBe(core.RESULT_OK);
- expect(write.numBytes).toBe(42);
-
- var wait = core.wait(pipe.consumerHandle, core.HANDLE_SIGNAL_READABLE,
- core.DEADLINE_INDEFINITE);
- expect(wait.result).toBe(core.RESULT_OK);
- var peeked = core.readData(
- pipe.consumerHandle,
- core.READ_DATA_FLAG_PEEK | core.READ_DATA_FLAG_ALL_OR_NONE);
- expect(peeked.result).toBe(core.RESULT_OK);
- expect(peeked.buffer.byteLength).toBe(42);
-
- var peeked_memory = new Uint8Array(peeked.buffer);
- for (var i = 0; i < peeked_memory.length; ++i)
- expect(peeked_memory[i]).toBe((i * i) & 0xFF);
-
- var read = core.readData(
- pipe.consumerHandle, core.READ_DATA_FLAG_ALL_OR_NONE);
-
- expect(read.result).toBe(core.RESULT_OK);
- expect(read.buffer.byteLength).toBe(42);
-
- var memory = new Uint8Array(read.buffer);
- for (var i = 0; i < memory.length; ++i)
- expect(memory[i]).toBe((i * i) & 0xFF);
- }
-
- function testIsHandleMessagePipe(pipe) {
- expect(core.isHandle(123).toBeFalsy);
- expect(core.isHandle("123").toBeFalsy);
- expect(core.isHandle({}).toBeFalsy);
- expect(core.isHandle([]).toBeFalsy);
- expect(core.isHandle(undefined).toBeFalsy);
- expect(core.isHandle(pipe).toBeFalsy);
- expect(core.isHandle(pipe.handle0)).toBeTruthy();
- expect(core.isHandle(pipe.handle1)).toBeTruthy();
- expect(core.isHandle(null)).toBeTruthy();
- }
-
- function testIsHandleDataPipe(pipe) {
- expect(core.isHandle(pipe.consumerHandle)).toBeTruthy();
- expect(core.isHandle(pipe.producerHandle)).toBeTruthy();
- }
-
-});
diff --git a/mojo/public/js/router.js b/mojo/public/js/router.js
index e3db0a6..e94c5eb 100644
--- a/mojo/public/js/router.js
+++ b/mojo/public/js/router.js
@@ -3,17 +3,20 @@
// found in the LICENSE file.
define("mojo/public/js/router", [
+ "console",
"mojo/public/js/codec",
"mojo/public/js/core",
"mojo/public/js/connector",
+ "mojo/public/js/lib/control_message_handler",
"mojo/public/js/validator",
-], function(codec, core, connector, validator) {
+], function(console, codec, core, connector, controlMessageHandler, validator) {
var Connector = connector.Connector;
var MessageReader = codec.MessageReader;
var Validator = validator.Validator;
+ var ControlMessageHandler = controlMessageHandler.ControlMessageHandler;
- function Router(handle, connectorFactory) {
+ function Router(handle, interface_version, connectorFactory) {
if (!core.isHandle(handle))
throw new Error("Router constructor: Not a handle");
if (connectorFactory === undefined)
@@ -24,6 +27,12 @@ define("mojo/public/js/router", [
this.nextRequestID_ = 0;
this.completers_ = new Map();
this.payloadValidators_ = [];
+ this.testingController_ = null;
+
+ if (interface_version !== undefined) {
+ this.controlMessageHandler_ = new
+ ControlMessageHandler(interface_version);
+ }
this.connector_.setIncomingReceiver({
accept: this.handleIncomingMessage_.bind(this),
@@ -36,6 +45,7 @@ define("mojo/public/js/router", [
Router.prototype.close = function() {
this.completers_.clear(); // Drop any responders.
this.connector_.close();
+ this.testingController_ = null;
};
Router.prototype.accept = function(message) {
@@ -81,6 +91,11 @@ define("mojo/public/js/router", [
return this.connector_.encounteredError();
};
+ Router.prototype.enableTestingMode = function() {
+ this.testingController_ = new RouterTestingController(this.connector_);
+ return this.testingController_;
+ };
+
Router.prototype.handleIncomingMessage_ = function(message) {
var noError = validator.validationError.NONE;
var messageValidator = new Validator(message);
@@ -95,8 +110,17 @@ define("mojo/public/js/router", [
};
Router.prototype.handleValidIncomingMessage_ = function(message) {
+ if (this.testingController_)
+ return;
+
if (message.expectsResponse()) {
- if (this.incomingReceiver_) {
+ if (controlMessageHandler.isControlMessage(message)) {
+ if (this.controlMessageHandler_) {
+ this.controlMessageHandler_.acceptWithResponder(message, this);
+ } else {
+ this.close();
+ }
+ } else if (this.incomingReceiver_) {
this.incomingReceiver_.acceptWithResponder(message, this);
} else {
// If we receive a request expecting a response when the client is not
@@ -107,17 +131,39 @@ define("mojo/public/js/router", [
var reader = new MessageReader(message);
var requestID = reader.requestID;
var completer = this.completers_.get(requestID);
- this.completers_.delete(requestID);
- completer.resolve(message);
+ if (completer) {
+ this.completers_.delete(requestID);
+ completer.resolve(message);
+ } else {
+ console.log("Unexpected response with request ID: " + requestID);
+ }
} else {
- if (this.incomingReceiver_)
+ if (controlMessageHandler.isControlMessage(message)) {
+ if (this.controlMessageHandler_) {
+ var ok = this.controlMessageHandler_.accept(message);
+ if (ok) return;
+ }
+ this.close();
+ } else if (this.incomingReceiver_) {
this.incomingReceiver_.accept(message);
+ }
}
- }
+ };
Router.prototype.handleInvalidIncomingMessage_ = function(message, error) {
- this.close();
- }
+ if (!this.testingController_) {
+ // TODO(yzshen): Consider notifying the embedder.
+ // TODO(yzshen): This should also trigger connection error handler.
+ // Consider making accept() return a boolean and let the connector deal
+ // with this, as the C++ code does.
+ console.log("Invalid message: " + validator.validationError[error]);
+
+ this.close();
+ return;
+ }
+
+ this.testingController_.onInvalidIncomingMessage(error);
+ };
Router.prototype.handleConnectionError_ = function(result) {
this.completers_.forEach(function(value) {
@@ -128,25 +174,30 @@ define("mojo/public/js/router", [
this.close();
};
- // The TestRouter subclass is only intended to be used in unit tests.
- // It defeats valid message handling and delgates invalid message handling.
+ // The RouterTestingController is used in unit tests. It defeats valid message
+ // handling and delgates invalid message handling.
- function TestRouter(handle, connectorFactory) {
- Router.call(this, handle, connectorFactory);
+ function RouterTestingController(connector) {
+ this.connector_ = connector;
+ this.invalidMessageHandler_ = null;
}
- TestRouter.prototype = Object.create(Router.prototype);
+ RouterTestingController.prototype.waitForNextMessage = function() {
+ this.connector_.waitForNextMessageForTesting();
+ };
- TestRouter.prototype.handleValidIncomingMessage_ = function() {
+ RouterTestingController.prototype.setInvalidIncomingMessageHandler =
+ function(callback) {
+ this.invalidMessageHandler_ = callback;
};
- TestRouter.prototype.handleInvalidIncomingMessage_ =
- function(message, error) {
- this.validationErrorHandler(error);
- };
+ RouterTestingController.prototype.onInvalidIncomingMessage =
+ function(error) {
+ if (this.invalidMessageHandler_)
+ this.invalidMessageHandler_(error);
+ };
var exports = {};
exports.Router = Router;
- exports.TestRouter = TestRouter;
return exports;
});
diff --git a/mojo/public/js/struct_unittests.js b/mojo/public/js/struct_unittests.js
deleted file mode 100644
index 691d51b..0000000
--- a/mojo/public/js/struct_unittests.js
+++ /dev/null
@@ -1,279 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define([
- "gin/test/expect",
- "mojo/public/interfaces/bindings/tests/rect.mojom",
- "mojo/public/interfaces/bindings/tests/test_structs.mojom",
- "mojo/public/js/codec",
- "mojo/public/js/validator",
-], function(expect,
- rect,
- testStructs,
- codec,
- validator) {
-
- function testConstructors() {
- var r = new rect.Rect();
- expect(r).toEqual(new rect.Rect({x:0, y:0, width:0, height:0}));
- expect(r).toEqual(new rect.Rect({foo:100, bar:200}));
-
- r.x = 10;
- r.y = 20;
- r.width = 30;
- r.height = 40;
- var rp = new testStructs.RectPair({first: r, second: r});
- expect(rp.first).toEqual(r);
- expect(rp.second).toEqual(r);
-
- expect(new testStructs.RectPair({second: r}).first).toBeNull();
-
- var nr = new testStructs.NamedRegion();
- expect(nr.name).toBeNull();
- expect(nr.rects).toBeNull();
- expect(nr).toEqual(new testStructs.NamedRegion({}));
-
- nr.name = "foo";
- nr.rects = [r, r, r];
- expect(nr).toEqual(new testStructs.NamedRegion({
- name: "foo",
- rects: [r, r, r],
- }));
-
- var e = new testStructs.EmptyStruct();
- expect(e).toEqual(new testStructs.EmptyStruct({foo:123}));
- }
-
- function testNoDefaultFieldValues() {
- var s = new testStructs.NoDefaultFieldValues();
- expect(s.f0).toEqual(false);
-
- // f1 - f10, number type fields
- for (var i = 1; i <= 10; i++)
- expect(s["f" + i]).toEqual(0);
-
- // f11,12 strings, f13-22 handles, f23-f26 arrays, f27,28 structs
- for (var i = 11; i <= 28; i++)
- expect(s["f" + i]).toBeNull();
- }
-
- function testDefaultFieldValues() {
- var s = new testStructs.DefaultFieldValues();
- expect(s.f0).toEqual(true);
-
- // f1 - f12, number type fields
- for (var i = 1; i <= 12; i++)
- expect(s["f" + i]).toEqual(100);
-
- // f13,14 "foo"
- for (var i = 13; i <= 14; i++)
- expect(s["f" + i]).toEqual("foo");
-
- // f15,16 a default instance of Rect
- var r = new rect.Rect();
- expect(s.f15).toEqual(r);
- expect(s.f16).toEqual(r);
- }
-
- function testScopedConstants() {
- expect(testStructs.ScopedConstants.TEN).toEqual(10);
- expect(testStructs.ScopedConstants.ALSO_TEN).toEqual(10);
-
- expect(testStructs.ScopedConstants.EType.E0).toEqual(0);
- expect(testStructs.ScopedConstants.EType.E1).toEqual(1);
- expect(testStructs.ScopedConstants.EType.E2).toEqual(10);
- expect(testStructs.ScopedConstants.EType.E3).toEqual(10);
- expect(testStructs.ScopedConstants.EType.E4).toEqual(11);
-
- var s = new testStructs.ScopedConstants();
- expect(s.f0).toEqual(0);
- expect(s.f1).toEqual(1);
- expect(s.f2).toEqual(10);
- expect(s.f3).toEqual(10);
- expect(s.f4).toEqual(11);
- expect(s.f5).toEqual(10);
- expect(s.f6).toEqual(10);
- }
-
- function structEncodeDecode(struct) {
- var structClass = struct.constructor;
- var builder = new codec.MessageBuilder(1234, structClass.encodedSize);
- builder.encodeStruct(structClass, struct);
- var message = builder.finish();
-
- var messageValidator = new validator.Validator(message);
- var err = structClass.validate(messageValidator, codec.kMessageHeaderSize);
- expect(err).toEqual(validator.validationError.NONE);
-
- var reader = new codec.MessageReader(message);
- return reader.decodeStruct(structClass);
- }
-
- function testMapKeyTypes() {
- var mapFieldsStruct = new testStructs.MapKeyTypes({
- f0: new Map([[true, false], [false, true]]), // map<bool, bool>
- f1: new Map([[0, 0], [1, 127], [-1, -128]]), // map<int8, int8>
- f2: new Map([[0, 0], [1, 127], [2, 255]]), // map<uint8, uint8>
- f3: new Map([[0, 0], [1, 32767], [2, -32768]]), // map<int16, int16>
- f4: new Map([[0, 0], [1, 32768], [2, 0xFFFF]]), // map<uint16, uint16>
- f5: new Map([[0, 0], [1, 32767], [2, -32768]]), // map<int32, int32>
- f6: new Map([[0, 0], [1, 32768], [2, 0xFFFF]]), // map<uint32, uint32>
- f7: new Map([[0, 0], [1, 32767], [2, -32768]]), // map<int64, int64>
- f8: new Map([[0, 0], [1, 32768], [2, 0xFFFF]]), // map<uint64, uint64>
- f9: new Map([[1000.5, -50000], [100.5, 5000]]), // map<float, float>
- f10: new Map([[-100.5, -50000], [0, 50000000]]), // map<double, double>
- f11: new Map([["one", "two"], ["free", "four"]]), // map<string, string>
- });
- var decodedStruct = structEncodeDecode(mapFieldsStruct);
- expect(decodedStruct.f0).toEqual(mapFieldsStruct.f0);
- expect(decodedStruct.f1).toEqual(mapFieldsStruct.f1);
- expect(decodedStruct.f2).toEqual(mapFieldsStruct.f2);
- expect(decodedStruct.f3).toEqual(mapFieldsStruct.f3);
- expect(decodedStruct.f4).toEqual(mapFieldsStruct.f4);
- expect(decodedStruct.f5).toEqual(mapFieldsStruct.f5);
- expect(decodedStruct.f6).toEqual(mapFieldsStruct.f6);
- expect(decodedStruct.f7).toEqual(mapFieldsStruct.f7);
- expect(decodedStruct.f8).toEqual(mapFieldsStruct.f8);
- expect(decodedStruct.f9).toEqual(mapFieldsStruct.f9);
- expect(decodedStruct.f10).toEqual(mapFieldsStruct.f10);
- expect(decodedStruct.f11).toEqual(mapFieldsStruct.f11);
- }
-
- function testMapValueTypes() {
- var mapFieldsStruct = new testStructs.MapValueTypes({
- // map<string, array<string>>
- f0: new Map([["a", ["b", "c"]], ["d", ["e"]]]),
- // map<string, array<string>?>
- f1: new Map([["a", null], ["b", ["c", "d"]]]),
- // map<string, array<string?>>
- f2: new Map([["a", [null]], ["b", [null, "d"]]]),
- // map<string, array<string,2>>
- f3: new Map([["a", ["1", "2"]], ["b", ["1", "2"]]]),
- // map<string, array<array<string, 2>?>>
- f4: new Map([["a", [["1", "2"]]], ["b", [null]]]),
- // map<string, array<array<string, 2>, 1>>
- f5: new Map([["a", [["1", "2"]]]]),
- // map<string, Rect?>
- f6: new Map([["a", null]]),
- // map<string, map<string, string>>
- f7: new Map([["a", new Map([["b", "c"]])]]),
- // map<string, array<map<string, string>>>
- f8: new Map([["a", [new Map([["b", "c"]])]]]),
- // map<string, handle>
- f9: new Map([["a", 1234]]),
- // map<string, array<handle>>
- f10: new Map([["a", [1234, 5678]]]),
- // map<string, map<string, handle>>
- f11: new Map([["a", new Map([["b", 1234]])]]),
- });
- var decodedStruct = structEncodeDecode(mapFieldsStruct);
- expect(decodedStruct.f0).toEqual(mapFieldsStruct.f0);
- expect(decodedStruct.f1).toEqual(mapFieldsStruct.f1);
- expect(decodedStruct.f2).toEqual(mapFieldsStruct.f2);
- expect(decodedStruct.f3).toEqual(mapFieldsStruct.f3);
- expect(decodedStruct.f4).toEqual(mapFieldsStruct.f4);
- expect(decodedStruct.f5).toEqual(mapFieldsStruct.f5);
- expect(decodedStruct.f6).toEqual(mapFieldsStruct.f6);
- expect(decodedStruct.f7).toEqual(mapFieldsStruct.f7);
- expect(decodedStruct.f8).toEqual(mapFieldsStruct.f8);
- expect(decodedStruct.f9).toEqual(mapFieldsStruct.f9);
- expect(decodedStruct.f10).toEqual(mapFieldsStruct.f10);
- expect(decodedStruct.f11).toEqual(mapFieldsStruct.f11);
- }
-
- function testFloatNumberValues() {
- var decodedStruct = structEncodeDecode(new testStructs.FloatNumberValues);
- expect(decodedStruct.f0).toEqual(testStructs.FloatNumberValues.V0);
- expect(decodedStruct.f1).toEqual(testStructs.FloatNumberValues.V1);
- expect(decodedStruct.f2).toEqual(testStructs.FloatNumberValues.V2);
- expect(decodedStruct.f3).toEqual(testStructs.FloatNumberValues.V3);
- expect(decodedStruct.f4).toEqual(testStructs.FloatNumberValues.V4);
- expect(decodedStruct.f5).toEqual(testStructs.FloatNumberValues.V5);
- expect(decodedStruct.f6).toEqual(testStructs.FloatNumberValues.V6);
- expect(decodedStruct.f7).toEqual(testStructs.FloatNumberValues.V7);
- expect(decodedStruct.f8).toEqual(testStructs.FloatNumberValues.V8);
- expect(decodedStruct.f9).toEqual(testStructs.FloatNumberValues.V9);
- }
-
- function testIntegerNumberValues() {
- var decodedStruct = structEncodeDecode(new testStructs.IntegerNumberValues);
- expect(decodedStruct.f0).toEqual(testStructs.IntegerNumberValues.V0);
- expect(decodedStruct.f1).toEqual(testStructs.IntegerNumberValues.V1);
- expect(decodedStruct.f2).toEqual(testStructs.IntegerNumberValues.V2);
- expect(decodedStruct.f3).toEqual(testStructs.IntegerNumberValues.V3);
- expect(decodedStruct.f4).toEqual(testStructs.IntegerNumberValues.V4);
- expect(decodedStruct.f5).toEqual(testStructs.IntegerNumberValues.V5);
- expect(decodedStruct.f6).toEqual(testStructs.IntegerNumberValues.V6);
- expect(decodedStruct.f7).toEqual(testStructs.IntegerNumberValues.V7);
- expect(decodedStruct.f8).toEqual(testStructs.IntegerNumberValues.V8);
- expect(decodedStruct.f9).toEqual(testStructs.IntegerNumberValues.V9);
- expect(decodedStruct.f10).toEqual(testStructs.IntegerNumberValues.V10);
- expect(decodedStruct.f11).toEqual(testStructs.IntegerNumberValues.V11);
- expect(decodedStruct.f12).toEqual(testStructs.IntegerNumberValues.V12);
- expect(decodedStruct.f13).toEqual(testStructs.IntegerNumberValues.V13);
- expect(decodedStruct.f14).toEqual(testStructs.IntegerNumberValues.V14);
- expect(decodedStruct.f15).toEqual(testStructs.IntegerNumberValues.V15);
- expect(decodedStruct.f16).toEqual(testStructs.IntegerNumberValues.V16);
- expect(decodedStruct.f17).toEqual(testStructs.IntegerNumberValues.V17);
- expect(decodedStruct.f18).toEqual(testStructs.IntegerNumberValues.V18);
- expect(decodedStruct.f19).toEqual(testStructs.IntegerNumberValues.V19);
- }
-
- function testUnsignedNumberValues() {
- var decodedStruct =
- structEncodeDecode(new testStructs.UnsignedNumberValues);
- expect(decodedStruct.f0).toEqual(testStructs.UnsignedNumberValues.V0);
- expect(decodedStruct.f1).toEqual(testStructs.UnsignedNumberValues.V1);
- expect(decodedStruct.f2).toEqual(testStructs.UnsignedNumberValues.V2);
- expect(decodedStruct.f3).toEqual(testStructs.UnsignedNumberValues.V3);
- expect(decodedStruct.f4).toEqual(testStructs.UnsignedNumberValues.V4);
- expect(decodedStruct.f5).toEqual(testStructs.UnsignedNumberValues.V5);
- expect(decodedStruct.f6).toEqual(testStructs.UnsignedNumberValues.V6);
- expect(decodedStruct.f7).toEqual(testStructs.UnsignedNumberValues.V7);
- expect(decodedStruct.f8).toEqual(testStructs.UnsignedNumberValues.V8);
- expect(decodedStruct.f9).toEqual(testStructs.UnsignedNumberValues.V9);
- expect(decodedStruct.f10).toEqual(testStructs.UnsignedNumberValues.V10);
- expect(decodedStruct.f11).toEqual(testStructs.UnsignedNumberValues.V11);
- }
-
-
- function testBitArrayValues() {
- var bitArraysStruct = new testStructs.BitArrayValues({
- // array<bool, 1> f0;
- f0: [true],
- // array<bool, 7> f1;
- f1: [true, false, true, false, true, false, true],
- // array<bool, 9> f2;
- f2: [true, false, true, false, true, false, true, false, true],
- // array<bool> f3;
- f3: [true, false, true, false, true, false, true, false],
- // array<array<bool>> f4;
- f4: [[true], [false], [true, false], [true, false, true, false]],
- // array<array<bool>?> f5;
- f5: [[true], null, null, [true, false, true, false]],
- // array<array<bool, 2>?> f6;
- f6: [[true, false], [true, false], [true, false]],
- });
- var decodedStruct = structEncodeDecode(bitArraysStruct);
- expect(decodedStruct.f0).toEqual(bitArraysStruct.f0);
- expect(decodedStruct.f1).toEqual(bitArraysStruct.f1);
- expect(decodedStruct.f2).toEqual(bitArraysStruct.f2);
- expect(decodedStruct.f3).toEqual(bitArraysStruct.f3);
- expect(decodedStruct.f4).toEqual(bitArraysStruct.f4);
- expect(decodedStruct.f5).toEqual(bitArraysStruct.f5);
- expect(decodedStruct.f6).toEqual(bitArraysStruct.f6);
- }
-
- testConstructors();
- testNoDefaultFieldValues();
- testDefaultFieldValues();
- testScopedConstants();
- testMapKeyTypes();
- testMapValueTypes();
- testFloatNumberValues();
- testIntegerNumberValues();
- testUnsignedNumberValues();
- testBitArrayValues();
- this.result = "PASS";
-});
diff --git a/mojo/public/js/test/validation_test_input_parser.js b/mojo/public/js/test/validation_test_input_parser.js
deleted file mode 100644
index f5a57f9..0000000
--- a/mojo/public/js/test/validation_test_input_parser.js
+++ /dev/null
@@ -1,299 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Support for parsing binary sequences encoded as readable strings
-// or ".data" files. The input format is described here:
-// mojo/public/cpp/bindings/tests/validation_test_input_parser.h
-
-define([
- "mojo/public/js/buffer"
- ], function(buffer) {
-
- // Files and Lines represent the raw text from an input string
- // or ".data" file.
-
- function InputError(message, line) {
- this.message = message;
- this.line = line;
- }
-
- InputError.prototype.toString = function() {
- var s = 'Error: ' + this.message;
- if (this.line)
- s += ', at line ' +
- (this.line.number + 1) + ': "' + this.line.contents + '"';
- return s;
- }
-
- function File(contents) {
- this.contents = contents;
- this.index = 0;
- this.lineNumber = 0;
- }
-
- File.prototype.endReached = function() {
- return this.index >= this.contents.length;
- }
-
- File.prototype.nextLine = function() {
- if (this.endReached())
- return null;
- var start = this.index;
- var end = this.contents.indexOf('\n', start);
- if (end == -1)
- end = this.contents.length;
- this.index = end + 1;
- return new Line(this.contents.substring(start, end), this.lineNumber++);
- }
-
- function Line(contents, number) {
- var i = contents.indexOf('//');
- var s = (i == -1) ? contents.trim() : contents.substring(0, i).trim();
- this.contents = contents;
- this.items = (s.length > 0) ? s.split(/\s+/) : [];
- this.index = 0;
- this.number = number;
- }
-
- Line.prototype.endReached = function() {
- return this.index >= this.items.length;
- }
-
- var ITEM_TYPE_SIZES = {
- u1: 1, u2: 2, u4: 4, u8: 8, s1: 1, s2: 2, s4: 4, s8: 8, b: 1, f: 4, d: 8,
- dist4: 4, dist8: 8, anchr: 0, handles: 0
- };
-
- function isValidItemType(type) {
- return ITEM_TYPE_SIZES[type] !== undefined;
- }
-
- Line.prototype.nextItem = function() {
- if (this.endReached())
- return null;
-
- var itemString = this.items[this.index++];
- var type = 'u1';
- var value = itemString;
-
- if (itemString.charAt(0) == '[') {
- var i = itemString.indexOf(']');
- if (i != -1 && i + 1 < itemString.length) {
- type = itemString.substring(1, i);
- value = itemString.substring(i + 1);
- } else {
- throw new InputError('invalid item', this);
- }
- }
- if (!isValidItemType(type))
- throw new InputError('invalid item type', this);
-
- return new Item(this, type, value);
- }
-
- // The text for each whitespace delimited binary data "item" is represented
- // by an Item.
-
- function Item(line, type, value) {
- this.line = line;
- this.type = type;
- this.value = value;
- this.size = ITEM_TYPE_SIZES[type];
- }
-
- Item.prototype.isFloat = function() {
- return this.type == 'f' || this.type == 'd';
- }
-
- Item.prototype.isInteger = function() {
- return ['u1', 'u2', 'u4', 'u8',
- 's1', 's2', 's4', 's8'].indexOf(this.type) != -1;
- }
-
- Item.prototype.isNumber = function() {
- return this.isFloat() || this.isInteger();
- }
-
- Item.prototype.isByte = function() {
- return this.type == 'b';
- }
-
- Item.prototype.isDistance = function() {
- return this.type == 'dist4' || this.type == 'dist8';
- }
-
- Item.prototype.isAnchor = function() {
- return this.type == 'anchr';
- }
-
- Item.prototype.isHandles = function() {
- return this.type == 'handles';
- }
-
- // A TestMessage represents the complete binary message loaded from an input
- // string or ".data" file. The parseTestMessage() function below constructs
- // a TestMessage from a File.
-
- function TestMessage(byteLength) {
- this.index = 0;
- this.buffer = new buffer.Buffer(byteLength);
- this.distances = {};
- this.handleCount = 0;
- }
-
- function checkItemNumberValue(item, n, min, max) {
- if (n < min || n > max)
- throw new InputError('invalid item value', item.line);
- }
-
- TestMessage.prototype.addNumber = function(item) {
- var n = item.isInteger() ? parseInt(item.value) : parseFloat(item.value);
- if (Number.isNaN(n))
- throw new InputError("can't parse item value", item.line);
-
- switch(item.type) {
- case 'u1':
- checkItemNumberValue(item, n, 0, 0xFF);
- this.buffer.setUint8(this.index, n);
- break;
- case 'u2':
- checkItemNumberValue(item, n, 0, 0xFFFF);
- this.buffer.setUint16(this.index, n);
- break;
- case 'u4':
- checkItemNumberValue(item, n, 0, 0xFFFFFFFF);
- this.buffer.setUint32(this.index, n);
- break;
- case 'u8':
- checkItemNumberValue(item, n, 0, Number.MAX_SAFE_INTEGER);
- this.buffer.setUint64(this.index, n);
- break;
- case 's1':
- checkItemNumberValue(item, n, -128, 127);
- this.buffer.setInt8(this.index, n);
- break;
- case 's2':
- checkItemNumberValue(item, n, -32768, 32767);
- this.buffer.setInt16(this.index, n);
- break;
- case 's4':
- checkItemNumberValue(item, n, -2147483648, 2147483647);
- this.buffer.setInt32(this.index, n);
- break;
- case 's8':
- checkItemNumberValue(item, n,
- Number.MIN_SAFE_INTEGER,
- Number.MAX_SAFE_INTEGER);
- this.buffer.setInt64(this.index, n);
- break;
- case 'f':
- this.buffer.setFloat32(this.index, n);
- break;
- case 'd':
- this.buffer.setFloat64(this.index, n);
- break;
-
- default:
- throw new InputError('unrecognized item type', item.line);
- }
- }
-
- TestMessage.prototype.addByte = function(item) {
- if (!/^[01]{8}$/.test(item.value))
- throw new InputError('invalid byte item value', item.line);
- function b(i) {
- return (item.value.charAt(7 - i) == '1') ? 1 << i : 0;
- }
- var n = b(0) | b(1) | b(2) | b(3) | b(4) | b(5) | b(6) | b(7);
- this.buffer.setUint8(this.index, n);
- }
-
- TestMessage.prototype.addDistance = function(item) {
- if (this.distances[item.value])
- throw new InputError('duplicate distance item', item.line);
- this.distances[item.value] = {index: this.index, item: item};
- }
-
- TestMessage.prototype.addAnchor = function(item) {
- var dist = this.distances[item.value];
- if (!dist)
- throw new InputError('unmatched anchor item', item.line);
- delete this.distances[item.value];
-
- var n = this.index - dist.index;
- // TODO(hansmuller): validate n
-
- if (dist.item.type == 'dist4')
- this.buffer.setUint32(dist.index, n);
- else if (dist.item.type == 'dist8')
- this.buffer.setUint64(dist.index, n);
- else
- throw new InputError('unrecognzed distance item type', dist.item.line);
- }
-
- TestMessage.prototype.addHandles = function(item) {
- this.handleCount = parseInt(item.value);
- if (Number.isNaN(this.handleCount))
- throw new InputError("can't parse handleCount", item.line);
- }
-
- TestMessage.prototype.addItem = function(item) {
- if (item.isNumber())
- this.addNumber(item);
- else if (item.isByte())
- this.addByte(item);
- else if (item.isDistance())
- this.addDistance(item);
- else if (item.isAnchor())
- this.addAnchor(item);
- else if (item.isHandles())
- this.addHandles(item);
- else
- throw new InputError('unrecognized item type', item.line);
-
- this.index += item.size;
- }
-
- TestMessage.prototype.unanchoredDistances = function() {
- var names = null;
- for (var name in this.distances) {
- if (this.distances.hasOwnProperty(name))
- names = (names === null) ? name : names + ' ' + name;
- }
- return names;
- }
-
- function parseTestMessage(text) {
- var file = new File(text);
- var items = [];
- var messageLength = 0;
- while(!file.endReached()) {
- var line = file.nextLine();
- while (!line.endReached()) {
- var item = line.nextItem();
- if (item.isHandles() && items.length > 0)
- throw new InputError('handles item is not first');
- messageLength += item.size;
- items.push(item);
- }
- }
-
- var msg = new TestMessage(messageLength);
- for (var i = 0; i < items.length; i++)
- msg.addItem(items[i]);
-
- if (messageLength != msg.index)
- throw new InputError('failed to compute message length');
- var names = msg.unanchoredDistances();
- if (names)
- throw new InputError('no anchors for ' + names, 0);
-
- return msg;
- }
-
- var exports = {};
- exports.parseTestMessage = parseTestMessage;
- exports.InputError = InputError;
- return exports;
-});
diff --git a/mojo/public/js/threading.js b/mojo/public/js/threading.js
index cfe5037..49ab5c9 100644
--- a/mojo/public/js/threading.js
+++ b/mojo/public/js/threading.js
@@ -7,7 +7,7 @@
// Note: This file is for documentation purposes only. The code here is not
// actually executed. The real module is implemented natively in Mojo.
//
-// This module provides a way for a Mojo application implemented in JS
+// This module provides a way for a Service implemented in JS
// to exit by quitting the current message loop. This module is not
// intended to be used by Mojo JS application started by the JS
// content handler.
diff --git a/mojo/public/js/union_unittests.js b/mojo/public/js/union_unittests.js
deleted file mode 100644
index 5dcda7d..0000000
--- a/mojo/public/js/union_unittests.js
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define([
- "gin/test/expect",
- "mojo/public/interfaces/bindings/tests/test_unions.mojom",
- "mojo/public/js/codec",
- "mojo/public/js/validator",
-], function(expect,
- unions,
- codec,
- validator) {
- function testConstructors() {
- var u = new unions.PodUnion();
- expect(u.$data).toEqual(null);
- expect(u.$tag).toBeUndefined();
-
- u.f_uint32 = 32;
-
- expect(u.f_uint32).toEqual(32);
- expect(u.$tag).toEqual(unions.PodUnion.Tags.f_uint32);
-
- var u = new unions.PodUnion({f_uint64: 64});
- expect(u.f_uint64).toEqual(64);
- expect(u.$tag).toEqual(unions.PodUnion.Tags.f_uint64);
- expect(function() {var v = u.f_uint32;}).toThrow();
-
- expect(function() {
- var u = new unions.PodUnion({
- f_uint64: 64,
- f_uint32: 32,
- });
- }).toThrow();
-
- expect(function() {
- var u = new unions.PodUnion({ foo: 64 }); }).toThrow();
-
- expect(function() {
- var u = new unions.PodUnion([1,2,3,4]); }).toThrow();
- }
-
- function structEncodeDecode(struct) {
- var structClass = struct.constructor;
- var builder = new codec.MessageBuilder(1234, structClass.encodedSize);
- builder.encodeStruct(structClass, struct);
-
- var message = builder.finish();
-
- var messageValidator = new validator.Validator(message);
- var err = structClass.validate(messageValidator, codec.kMessageHeaderSize);
- expect(err).toEqual(validator.validationError.NONE);
-
- var reader = new codec.MessageReader(message);
- var view = reader.decoder.buffer.dataView;
-
- return reader.decodeStruct(structClass);
- }
-
- function testBasicEncoding() {
- var s = new unions.WrapperStruct({
- pod_union: new unions.PodUnion({
- f_uint64: 64})});
-
- var decoded = structEncodeDecode(s);
- expect(decoded).toEqual(s);
-
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion({
- f_dummy: new unions.DummyStruct({
- f_int8: 8})})});
-
- var decoded = structEncodeDecode(s);
- expect(decoded).toEqual(s);
-
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion({
- f_array_int8: [1, 2, 3]})});
-
- var decoded = structEncodeDecode(s);
- expect(decoded).toEqual(s);
-
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion({
- f_map_int8: new Map([
- ["first", 1],
- ["second", 2],
- ])})});
-
- var decoded = structEncodeDecode(s);
- expect(decoded).toEqual(s);
-
- // Encoding a union with no member set is an error.
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion()});
- expect(function() {
- structEncodeDecode(s); }).toThrow();
- }
-
- function testUnionsInArrayEncoding() {
- var s = new unions.SmallStruct({
- pod_union_array: [
- new unions.PodUnion({f_uint32: 32}),
- new unions.PodUnion({f_uint64: 64}),
- ]
- });
-
- var decoded = structEncodeDecode(s);
- expect(decoded).toEqual(s);
- }
-
- function testUnionsInMapEncoding() {
- var s = new unions.SmallStruct({
- pod_union_map: new Map([
- ["thirty-two", new unions.PodUnion({f_uint32: 32})],
- ["sixty-four", new unions.PodUnion({f_uint64: 64})],
- ])
- });
-
- var decoded = structEncodeDecode(s);
- expect(decoded).toEqual(s);
- }
-
- function testNestedUnionsEncoding() {
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion({
- f_pod_union: new unions.PodUnion({f_uint32: 32})
- })});
- var decoded = structEncodeDecode(s);
- expect(decoded).toEqual(s);
- }
-
- function structValidate(struct) {
- var structClass = struct.constructor;
- var builder = new codec.MessageBuilder(1234, structClass.encodedSize);
- builder.encodeStruct(structClass, struct);
-
- var message = builder.finish();
-
- var messageValidator = new validator.Validator(message);
- return structClass.validate(messageValidator, codec.kMessageHeaderSize);
- }
-
- function testNullUnionMemberValidation() {
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion({
- f_dummy: null})});
-
- var err = structValidate(s);
- expect(err).toEqual(validator.validationError.UNEXPECTED_NULL_POINTER);
-
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion({
- f_nullable: null})});
-
- var err = structValidate(s);
- expect(err).toEqual(validator.validationError.NONE);
- }
-
- function testNullUnionValidation() {
- var s = new unions.SmallStructNonNullableUnion({
- pod_union: null});
-
- var err = structValidate(s);
- expect(err).toEqual(validator.validationError.UNEXPECTED_NULL_UNION);
-
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion({
- f_pod_union: null})
- });
-
- var err = structValidate(s);
- expect(err).toEqual(validator.validationError.UNEXPECTED_NULL_UNION);
- }
-
- testConstructors();
- testBasicEncoding();
- testUnionsInArrayEncoding();
- testUnionsInMapEncoding();
- testNestedUnionsEncoding();
- testNullUnionMemberValidation();
- testNullUnionValidation();
- this.result = "PASS";
-});
diff --git a/mojo/public/js/validation_unittests.js b/mojo/public/js/validation_unittests.js
deleted file mode 100644
index 817d42c..0000000
--- a/mojo/public/js/validation_unittests.js
+++ /dev/null
@@ -1,349 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define([
- "console",
- "file",
- "gin/test/expect",
- "mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom",
- "mojo/public/js/buffer",
- "mojo/public/js/codec",
- "mojo/public/js/connection",
- "mojo/public/js/connector",
- "mojo/public/js/core",
- "mojo/public/js/test/validation_test_input_parser",
- "mojo/public/js/router",
- "mojo/public/js/validator",
-], function(console,
- file,
- expect,
- testInterface,
- buffer,
- codec,
- connection,
- connector,
- core,
- parser,
- router,
- validator) {
-
- var noError = validator.validationError.NONE;
-
- function checkTestMessageParser() {
- function TestMessageParserFailure(message, input) {
- this.message = message;
- this.input = input;
- }
-
- TestMessageParserFailure.prototype.toString = function() {
- return 'Error: ' + this.message + ' for "' + this.input + '"';
- }
-
- function checkData(data, expectedData, input) {
- if (data.byteLength != expectedData.byteLength) {
- var s = "message length (" + data.byteLength + ") doesn't match " +
- "expected length: " + expectedData.byteLength;
- throw new TestMessageParserFailure(s, input);
- }
-
- for (var i = 0; i < data.byteLength; i++) {
- if (data.getUint8(i) != expectedData.getUint8(i)) {
- var s = 'message data mismatch at byte offset ' + i;
- throw new TestMessageParserFailure(s, input);
- }
- }
- }
-
- function testFloatItems() {
- var input = '[f]+.3e9 [d]-10.03';
- var msg = parser.parseTestMessage(input);
- var expectedData = new buffer.Buffer(12);
- expectedData.setFloat32(0, +.3e9);
- expectedData.setFloat64(4, -10.03);
- checkData(msg.buffer, expectedData, input);
- }
-
- function testUnsignedIntegerItems() {
- var input = '[u1]0x10// hello world !! \n\r \t [u2]65535 \n' +
- '[u4]65536 [u8]0xFFFFFFFFFFFFF 0 0Xff';
- var msg = parser.parseTestMessage(input);
- var expectedData = new buffer.Buffer(17);
- expectedData.setUint8(0, 0x10);
- expectedData.setUint16(1, 65535);
- expectedData.setUint32(3, 65536);
- expectedData.setUint64(7, 0xFFFFFFFFFFFFF);
- expectedData.setUint8(15, 0);
- expectedData.setUint8(16, 0xff);
- checkData(msg.buffer, expectedData, input);
- }
-
- function testSignedIntegerItems() {
- var input = '[s8]-0x800 [s1]-128\t[s2]+0 [s4]-40';
- var msg = parser.parseTestMessage(input);
- var expectedData = new buffer.Buffer(15);
- expectedData.setInt64(0, -0x800);
- expectedData.setInt8(8, -128);
- expectedData.setInt16(9, 0);
- expectedData.setInt32(11, -40);
- checkData(msg.buffer, expectedData, input);
- }
-
- function testByteItems() {
- var input = '[b]00001011 [b]10000000 // hello world\n [b]00000000';
- var msg = parser.parseTestMessage(input);
- var expectedData = new buffer.Buffer(3);
- expectedData.setUint8(0, 11);
- expectedData.setUint8(1, 128);
- expectedData.setUint8(2, 0);
- checkData(msg.buffer, expectedData, input);
- }
-
- function testAnchors() {
- var input = '[dist4]foo 0 [dist8]bar 0 [anchr]foo [anchr]bar';
- var msg = parser.parseTestMessage(input);
- var expectedData = new buffer.Buffer(14);
- expectedData.setUint32(0, 14);
- expectedData.setUint8(4, 0);
- expectedData.setUint64(5, 9);
- expectedData.setUint8(13, 0);
- checkData(msg.buffer, expectedData, input);
- }
-
- function testHandles() {
- var input = '// This message has handles! \n[handles]50 [u8]2';
- var msg = parser.parseTestMessage(input);
- var expectedData = new buffer.Buffer(8);
- expectedData.setUint64(0, 2);
-
- if (msg.handleCount != 50) {
- var s = 'wrong handle count (' + msg.handleCount + ')';
- throw new TestMessageParserFailure(s, input);
- }
- checkData(msg.buffer, expectedData, input);
- }
-
- function testEmptyInput() {
- var msg = parser.parseTestMessage('');
- if (msg.buffer.byteLength != 0)
- throw new TestMessageParserFailure('expected empty message', '');
- }
-
- function testBlankInput() {
- var input = ' \t // hello world \n\r \t// the answer is 42 ';
- var msg = parser.parseTestMessage(input);
- if (msg.buffer.byteLength != 0)
- throw new TestMessageParserFailure('expected empty message', input);
- }
-
- function testInvalidInput() {
- function parserShouldFail(input) {
- try {
- parser.parseTestMessage(input);
- } catch (e) {
- if (e instanceof parser.InputError)
- return;
- throw new TestMessageParserFailure(
- 'unexpected exception ' + e.toString(), input);
- }
- throw new TestMessageParserFailure("didn't detect invalid input", file);
- }
-
- ['/ hello world',
- '[u1]x',
- '[u2]-1000',
- '[u1]0x100',
- '[s2]-0x8001',
- '[b]1',
- '[b]1111111k',
- '[dist4]unmatched',
- '[anchr]hello [dist8]hello',
- '[dist4]a [dist4]a [anchr]a',
- // '[dist4]a [anchr]a [dist4]a [anchr]a',
- '0 [handles]50'
- ].forEach(parserShouldFail);
- }
-
- try {
- testFloatItems();
- testUnsignedIntegerItems();
- testSignedIntegerItems();
- testByteItems();
- testInvalidInput();
- testEmptyInput();
- testBlankInput();
- testHandles();
- testAnchors();
- } catch (e) {
- return e.toString();
- }
- return null;
- }
-
- function getMessageTestFiles(prefix) {
- var sourceRoot = file.getSourceRootDirectory();
- expect(sourceRoot).not.toBeNull();
-
- var testDir = sourceRoot +
- "/mojo/public/interfaces/bindings/tests/data/validation/";
- var testFiles = file.getFilesInDirectory(testDir);
- expect(testFiles).not.toBeNull();
- expect(testFiles.length).toBeGreaterThan(0);
-
- // The matching ".data" pathnames with the extension removed.
- return testFiles.filter(function(s) {
- return s.substr(-5) == ".data" && s.indexOf(prefix) == 0;
- }).map(function(s) {
- return testDir + s.slice(0, -5);
- });
- }
-
- function readTestMessage(filename) {
- var contents = file.readFileToString(filename + ".data");
- expect(contents).not.toBeNull();
- return parser.parseTestMessage(contents);
- }
-
- function readTestExpected(filename) {
- var contents = file.readFileToString(filename + ".expected");
- expect(contents).not.toBeNull();
- return contents.trim();
- }
-
- function checkValidationResult(testFile, err) {
- var actualResult = (err === noError) ? "PASS" : err;
- var expectedResult = readTestExpected(testFile);
- if (actualResult != expectedResult)
- console.log("[Test message validation failed: " + testFile + " ]");
- expect(actualResult).toEqual(expectedResult);
- }
-
- function testMessageValidation(prefix, filters) {
- var testFiles = getMessageTestFiles(prefix);
- expect(testFiles.length).toBeGreaterThan(0);
-
- for (var i = 0; i < testFiles.length; i++) {
- // TODO(hansmuller) Temporarily skipping array pointer overflow tests
- // because JS numbers are limited to 53 bits.
- // TODO(yzshen) Skipping struct versioning tests (tests with "mthd11"
- // in the name) because the feature is not supported in JS yet.
- // TODO(yzshen) Skipping enum validation tests (tests with "enum" in the
- // name) because the feature is not supported in JS yet. crbug.com/581390
- // TODO(rudominer): Temporarily skipping 'no-such-method',
- // 'invalid_request_flags', and 'invalid_response_flags' until additional
- // logic in *RequestValidator and *ResponseValidator is ported from
- // cpp to js.
- if (testFiles[i].indexOf("overflow") != -1 ||
- testFiles[i].indexOf("mthd11") != -1 ||
- testFiles[i].indexOf("enum") != -1 ||
- testFiles[i].indexOf("no_such_method") != -1 ||
- testFiles[i].indexOf("invalid_request_flags") != -1 ||
- testFiles[i].indexOf("invalid_response_flags") != -1) {
- console.log("[Skipping " + testFiles[i] + "]");
- continue;
- }
-
- var testMessage = readTestMessage(testFiles[i]);
- var handles = new Array(testMessage.handleCount);
- var message = new codec.Message(testMessage.buffer, handles);
- var messageValidator = new validator.Validator(message);
-
- var err = messageValidator.validateMessageHeader();
- for (var j = 0; err === noError && j < filters.length; ++j)
- err = filters[j](messageValidator);
-
- checkValidationResult(testFiles[i], err);
- }
- }
-
- function testConformanceMessageValidation() {
- testMessageValidation("conformance_", [
- testInterface.ConformanceTestInterface.validateRequest]);
- }
-
- function testBoundsCheckMessageValidation() {
- testMessageValidation("boundscheck_", [
- testInterface.BoundsCheckTestInterface.validateRequest]);
- }
-
- function testResponseConformanceMessageValidation() {
- testMessageValidation("resp_conformance_", [
- testInterface.ConformanceTestInterface.validateResponse]);
- }
-
- function testResponseBoundsCheckMessageValidation() {
- testMessageValidation("resp_boundscheck_", [
- testInterface.BoundsCheckTestInterface.validateResponse]);
- }
-
- function testIntegratedMessageValidation(testFilesPattern,
- localFactory,
- remoteFactory) {
- var testFiles = getMessageTestFiles(testFilesPattern);
- expect(testFiles.length).toBeGreaterThan(0);
-
- var testMessagePipe = core.createMessagePipe();
- expect(testMessagePipe.result).toBe(core.RESULT_OK);
- var testConnection = new connection.TestConnection(
- testMessagePipe.handle1, localFactory, remoteFactory);
-
- for (var i = 0; i < testFiles.length; i++) {
- var testMessage = readTestMessage(testFiles[i]);
- var handles = new Array(testMessage.handleCount);
-
- var writeMessageValue = core.writeMessage(
- testMessagePipe.handle0,
- new Uint8Array(testMessage.buffer.arrayBuffer),
- new Array(testMessage.handleCount),
- core.WRITE_MESSAGE_FLAG_NONE);
- expect(writeMessageValue).toBe(core.RESULT_OK);
-
- var validationError = noError;
- testConnection.router_.validationErrorHandler = function(err) {
- validationError = err;
- }
-
- testConnection.router_.connector_.waitForNextMessage();
- checkValidationResult(testFiles[i], validationError);
- }
-
- testConnection.close();
- expect(core.close(testMessagePipe.handle0)).toBe(core.RESULT_OK);
- }
-
- function testIntegratedMessageHeaderValidation() {
- testIntegratedMessageValidation(
- "integration_msghdr",
- testInterface.IntegrationTestInterface.stubClass,
- undefined);
- testIntegratedMessageValidation(
- "integration_msghdr",
- undefined,
- testInterface.IntegrationTestInterface.proxyClass);
- }
-
- function testIntegratedRequestMessageValidation() {
- testIntegratedMessageValidation(
- "integration_intf_rqst",
- testInterface.IntegrationTestInterface.stubClass,
- undefined);
- }
-
- function testIntegratedResponseMessageValidation() {
- testIntegratedMessageValidation(
- "integration_intf_resp",
- undefined,
- testInterface.IntegrationTestInterface.proxyClass);
- }
-
- expect(checkTestMessageParser()).toBeNull();
- testConformanceMessageValidation();
- testBoundsCheckMessageValidation();
- testResponseConformanceMessageValidation();
- testResponseBoundsCheckMessageValidation();
- testIntegratedMessageHeaderValidation();
- testIntegratedResponseMessageValidation();
- testIntegratedRequestMessageValidation();
-
- this.result = "PASS";
-});
diff --git a/mojo/public/js/validator.js b/mojo/public/js/validator.js
index cbf7521..fee742d 100644
--- a/mojo/public/js/validator.js
+++ b/mojo/public/js/validator.js
@@ -24,10 +24,15 @@ define("mojo/public/js/validator", [
'VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP',
INVALID_UNION_SIZE: 'VALIDATION_ERROR_INVALID_UNION_SIZE',
UNEXPECTED_NULL_UNION: 'VALIDATION_ERROR_UNEXPECTED_NULL_UNION',
+ UNKNOWN_ENUM_VALUE: 'VALIDATION_ERROR_UNKNOWN_ENUM_VALUE',
};
var NULL_MOJO_POINTER = "NULL_MOJO_POINTER";
+ function isEnumClass(cls) {
+ return cls instanceof codec.Enum;
+ }
+
function isStringClass(cls) {
return cls === codec.String || cls === codec.NullableString;
}
@@ -37,12 +42,18 @@ define("mojo/public/js/validator", [
}
function isInterfaceClass(cls) {
- return cls === codec.Interface || cls === codec.NullableInterface;
+ return cls instanceof codec.Interface;
+ }
+
+ function isInterfaceRequestClass(cls) {
+ return cls === codec.InterfaceRequest ||
+ cls === codec.NullableInterfaceRequest;
}
function isNullable(type) {
return type === codec.NullableString || type === codec.NullableHandle ||
type === codec.NullableInterface ||
+ type === codec.NullableInterfaceRequest ||
type instanceof codec.NullableArrayOf ||
type instanceof codec.NullablePointerTo;
}
@@ -76,7 +87,7 @@ define("mojo/public/js/validator", [
return false;
return true;
- }
+ };
Validator.prototype.claimRange = function(start, numBytes) {
if (this.isValidRange(start, numBytes)) {
@@ -84,7 +95,7 @@ define("mojo/public/js/validator", [
return true;
}
return false;
- }
+ };
Validator.prototype.claimHandle = function(index) {
if (index === codec.kEncodedInvalidHandleValue)
@@ -96,6 +107,13 @@ define("mojo/public/js/validator", [
// This is safe because handle indices are uint32.
this.handleIndex = index + 1;
return true;
+ };
+
+ Validator.prototype.validateEnum = function(offset, enumClass) {
+ // Note: Assumes that enums are always 32 bits! But this matches
+ // mojom::generate::pack::PackedField::GetSizeForKind, so it should be okay.
+ var value = this.message.buffer.getInt32(offset);
+ return enumClass.validate(value);
}
Validator.prototype.validateHandle = function(offset, nullable) {
@@ -107,15 +125,19 @@ define("mojo/public/js/validator", [
if (!this.claimHandle(index))
return validationError.ILLEGAL_HANDLE;
+
return validationError.NONE;
- }
+ };
Validator.prototype.validateInterface = function(offset, nullable) {
return this.validateHandle(offset, nullable);
- }
+ };
+
+ Validator.prototype.validateInterfaceRequest = function(offset, nullable) {
+ return this.validateHandle(offset, nullable);
+ };
- Validator.prototype.validateStructHeader =
- function(offset, minNumBytes, minVersion) {
+ Validator.prototype.validateStructHeader = function(offset, minNumBytes) {
if (!codec.isAligned(offset))
return validationError.MISALIGNED_OBJECT;
@@ -123,20 +145,44 @@ define("mojo/public/js/validator", [
return validationError.ILLEGAL_MEMORY_RANGE;
var numBytes = this.message.buffer.getUint32(offset);
- var version = this.message.buffer.getUint32(offset + 4);
- // Backward compatibility is not yet supported.
- if (numBytes < minNumBytes || version < minVersion)
+ if (numBytes < minNumBytes)
return validationError.UNEXPECTED_STRUCT_HEADER;
if (!this.claimRange(offset, numBytes))
return validationError.ILLEGAL_MEMORY_RANGE;
return validationError.NONE;
- }
+ };
+
+ Validator.prototype.validateStructVersion = function(offset, versionSizes) {
+ var numBytes = this.message.buffer.getUint32(offset);
+ var version = this.message.buffer.getUint32(offset + 4);
+
+ if (version <= versionSizes[versionSizes.length - 1].version) {
+ // Scan in reverse order to optimize for more recent versionSizes.
+ for (var i = versionSizes.length - 1; i >= 0; --i) {
+ if (version >= versionSizes[i].version) {
+ if (numBytes == versionSizes[i].numBytes)
+ break;
+ return validationError.UNEXPECTED_STRUCT_HEADER;
+ }
+ }
+ } else if (numBytes < versionSizes[versionSizes.length-1].numBytes) {
+ return validationError.UNEXPECTED_STRUCT_HEADER;
+ }
+
+ return validationError.NONE;
+ };
+
+ Validator.prototype.isFieldInStructVersion = function(offset, fieldVersion) {
+ var structVersion = this.message.buffer.getUint32(offset + 4);
+ return fieldVersion <= structVersion;
+ };
Validator.prototype.validateMessageHeader = function() {
- var err = this.validateStructHeader(0, codec.kMessageHeaderSize, 0);
+
+ var err = this.validateStructHeader(0, codec.kMessageHeaderSize);
if (err != validationError.NONE)
return err;
@@ -162,7 +208,28 @@ define("mojo/public/js/validator", [
return validationError.MESSAGE_HEADER_INVALID_FLAGS;
return validationError.NONE;
- }
+ };
+
+ Validator.prototype.validateMessageIsRequestWithoutResponse = function() {
+ if (this.message.isResponse() || this.message.expectsResponse()) {
+ return validationError.MESSAGE_HEADER_INVALID_FLAGS;
+ }
+ return validationError.NONE;
+ };
+
+ Validator.prototype.validateMessageIsRequestExpectingResponse = function() {
+ if (this.message.isResponse() || !this.message.expectsResponse()) {
+ return validationError.MESSAGE_HEADER_INVALID_FLAGS;
+ }
+ return validationError.NONE;
+ };
+
+ Validator.prototype.validateMessageIsResponse = function() {
+ if (this.message.expectsResponse() || !this.message.isResponse()) {
+ return validationError.MESSAGE_HEADER_INVALID_FLAGS;
+ }
+ return validationError.NONE;
+ };
// Returns the message.buffer relative offset this pointer "points to",
// NULL_MOJO_POINTER if the pointer represents a null, or JS null if the
@@ -173,7 +240,7 @@ define("mojo/public/js/validator", [
return NULL_MOJO_POINTER;
var bufferOffset = offset + pointerValue;
return Number.isSafeInteger(bufferOffset) ? bufferOffset : null;
- }
+ };
Validator.prototype.decodeUnionSize = function(offset) {
return this.message.buffer.getUint32(offset);
@@ -196,7 +263,7 @@ define("mojo/public/js/validator", [
return this.validateArray(arrayOffset, elementSize, elementType,
expectedDimensionSizes, currentDimension);
- }
+ };
Validator.prototype.validateStructPointer = function(
offset, structClass, nullable) {
@@ -209,7 +276,7 @@ define("mojo/public/js/validator", [
validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
return structClass.validate(this, structOffset);
- }
+ };
Validator.prototype.validateUnion = function(
offset, unionClass, nullable) {
@@ -220,7 +287,7 @@ define("mojo/public/js/validator", [
}
return unionClass.validate(this, offset);
- }
+ };
Validator.prototype.validateNestedUnion = function(
offset, unionClass, nullable) {
@@ -233,7 +300,7 @@ define("mojo/public/js/validator", [
validationError.NONE : validationError.UNEXPECTED_NULL_UNION;
return this.validateUnion(unionOffset, unionClass, nullable);
- }
+ };
// This method assumes that the array at arrayPointerOffset has
// been validated.
@@ -241,7 +308,7 @@ define("mojo/public/js/validator", [
Validator.prototype.arrayLength = function(arrayPointerOffset) {
var arrayOffset = this.decodePointer(arrayPointerOffset);
return this.message.buffer.getUint32(arrayOffset + 4);
- }
+ };
Validator.prototype.validateMapPointer = function(
offset, mapIsNullable, keyClass, valueClass, valueIsNullable) {
@@ -256,7 +323,7 @@ define("mojo/public/js/validator", [
validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
var mapEncodedSize = codec.kStructHeaderSize + codec.kMapStructPayloadSize;
- var err = this.validateStructHeader(structOffset, mapEncodedSize, 0);
+ var err = this.validateStructHeader(structOffset, mapEncodedSize);
if (err !== validationError.NONE)
return err;
@@ -289,12 +356,12 @@ define("mojo/public/js/validator", [
return validationError.DIFFERENT_SIZED_ARRAYS_IN_MAP;
return validationError.NONE;
- }
+ };
Validator.prototype.validateStringPointer = function(offset, nullable) {
return this.validateArrayPointer(
offset, codec.Uint8.encodedSize, codec.Uint8, nullable, [0], 0);
- }
+ };
// Similar to Array_Data<T>::Validate()
// mojo/public/cpp/bindings/lib/array_internal.h
@@ -337,6 +404,9 @@ define("mojo/public/js/validator", [
if (isInterfaceClass(elementType))
return this.validateInterfaceElements(
elementsOffset, numElements, nullable);
+ if (isInterfaceRequestClass(elementType))
+ return this.validateInterfaceRequestElements(
+ elementsOffset, numElements, nullable);
if (isStringClass(elementType))
return this.validateArrayElements(
elementsOffset, numElements, codec.Uint8, nullable, [0], 0);
@@ -347,9 +417,12 @@ define("mojo/public/js/validator", [
return this.validateArrayElements(
elementsOffset, numElements, elementType.cls, nullable,
expectedDimensionSizes, currentDimension + 1);
+ if (isEnumClass(elementType))
+ return this.validateEnumElements(elementsOffset, numElements,
+ elementType.cls);
return validationError.NONE;
- }
+ };
// Note: the |offset + i * elementSize| computation in the validateFooElements
// methods below is "safe" because elementSize <= 8, offset and
@@ -365,11 +438,11 @@ define("mojo/public/js/validator", [
return err;
}
return validationError.NONE;
- }
+ };
Validator.prototype.validateInterfaceElements =
function(offset, numElements, nullable) {
- var elementSize = codec.Interface.encodedSize;
+ var elementSize = codec.Interface.prototype.encodedSize;
for (var i = 0; i < numElements; i++) {
var elementOffset = offset + i * elementSize;
var err = this.validateInterface(elementOffset, nullable);
@@ -377,7 +450,19 @@ define("mojo/public/js/validator", [
return err;
}
return validationError.NONE;
- }
+ };
+
+ Validator.prototype.validateInterfaceRequestElements =
+ function(offset, numElements, nullable) {
+ var elementSize = codec.InterfaceRequest.encodedSize;
+ for (var i = 0; i < numElements; i++) {
+ var elementOffset = offset + i * elementSize;
+ var err = this.validateInterfaceRequest(elementOffset, nullable);
+ if (err != validationError.NONE)
+ return err;
+ }
+ return validationError.NONE;
+ };
// The elementClass parameter is the element type of the element arrays.
Validator.prototype.validateArrayElements =
@@ -393,7 +478,7 @@ define("mojo/public/js/validator", [
return err;
}
return validationError.NONE;
- }
+ };
Validator.prototype.validateStructElements =
function(offset, numElements, structClass, nullable) {
@@ -406,7 +491,19 @@ define("mojo/public/js/validator", [
return err;
}
return validationError.NONE;
- }
+ };
+
+ Validator.prototype.validateEnumElements =
+ function(offset, numElements, enumClass) {
+ var elementSize = codec.Enum.prototype.encodedSize;
+ for (var i = 0; i < numElements; i++) {
+ var elementOffset = offset + i * elementSize;
+ var err = this.validateEnum(elementOffset, enumClass);
+ if (err != validationError.NONE)
+ return err;
+ }
+ return validationError.NONE;
+ };
var exports = {};
exports.validationError = validationError;
diff --git a/mojo/public/mojo_application.gni b/mojo/public/mojo_application.gni
deleted file mode 100644
index 28c8a8d..0000000
--- a/mojo/public/mojo_application.gni
+++ /dev/null
@@ -1,270 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/toolchain/toolchain.gni")
-import("//mojo/public/mojo_constants.gni")
-
-if (is_android) {
- import("//build/config/android/rules.gni")
- import("//build/config/zip.gni")
-}
-
-# Generate a binary Mojo application in a self-named directory.
-# Application resources are copied to a "resources" directory alongside the app.
-# The parameters of this template are those of a shared library.
-template("mojo_native_application") {
- base_target_name = target_name
- if (defined(invoker.output_name)) {
- base_target_name = invoker.output_name
- }
-
- final_target_name = target_name
-
- mojo_deps = []
- if (defined(invoker.deps)) {
- mojo_deps += invoker.deps
- }
-
- mojo_data_deps = []
-
- if (defined(invoker.resources)) {
- copy_step_name = "${base_target_name}__copy_resources"
- copy(copy_step_name) {
- sources = invoker.resources
- outputs = [
- "${root_out_dir}/${mojo_application_subdir}/${base_target_name}/resources/{{source_file_part}}",
- ]
- if (defined(invoker.testonly)) {
- testonly = invoker.testonly
- }
- deps = mojo_deps
- }
- mojo_data_deps += [ ":$copy_step_name" ]
- }
-
- output = base_target_name + ".mojo"
- library_target_name = base_target_name + "_library"
- library_name = "${shlib_prefix}${library_target_name}${shlib_extension}"
-
- shared_library(library_target_name) {
- if (defined(invoker.cflags)) {
- cflags = invoker.cflags
- }
- if (defined(invoker.cflags_c)) {
- cflags_c = invoker.cflags_c
- }
- if (defined(invoker.cflags_cc)) {
- cflags_cc = invoker.cflags_cc
- }
- if (defined(invoker.cflags_objc)) {
- cflags_objc = invoker.cflags_objc
- }
- if (defined(invoker.cflags_objcc)) {
- cflags_objcc = invoker.cflags_objcc
- }
- if (defined(invoker.defines)) {
- defines = invoker.defines
- }
- if (defined(invoker.include_dirs)) {
- include_dirs = invoker.include_dirs
- }
- if (defined(invoker.ldflags)) {
- ldflags = invoker.ldflags
- }
- if (defined(invoker.lib_dirs)) {
- lib_dirs = invoker.lib_dirs
- }
- if (defined(invoker.libs)) {
- libs = invoker.libs
- }
-
- data_deps = []
- if (!defined(invoker.avoid_runner_cycle) || !invoker.avoid_runner_cycle) {
- # Give the user an out; as some mojo services are depended on by the
- # runner.
- data_deps += [ "//services/shell/standalone" ]
- }
- if (defined(invoker.data_deps)) {
- data_deps += invoker.data_deps
- }
- data_deps += mojo_data_deps
-
- deps = [
- "//mojo/public/c/system:set_thunks_for_app",
- "//services/shell/public/cpp:application_support",
- ]
-
- deps += mojo_deps
- if (defined(invoker.public_deps)) {
- public_deps = invoker.public_deps
- }
- if (defined(invoker.all_dependent_configs)) {
- all_dependent_configs = invoker.all_dependent_configs
- }
- if (defined(invoker.public_configs)) {
- public_configs = invoker.public_configs
- }
- if (defined(invoker.check_includes)) {
- check_includes = invoker.check_includes
- }
- if (defined(invoker.configs)) {
- configs += invoker.configs
- }
- if (defined(invoker.data)) {
- data = invoker.data
- }
- if (defined(invoker.inputs)) {
- inputs = invoker.inputs
- }
- if (defined(invoker.public)) {
- public = invoker.public
- }
- if (defined(invoker.sources)) {
- sources = invoker.sources
- }
- if (defined(invoker.testonly)) {
- testonly = invoker.testonly
- }
- }
-
- copy(final_target_name) {
- forward_variables_from(invoker,
- [
- "testonly",
- "visibility",
- ])
- deps = [
- ":${library_target_name}",
- ]
-
- sources = [
- "${root_shlib_dir}/${library_name}",
- ]
- outputs = [
- "${root_out_dir}/${mojo_application_subdir}/${base_target_name}/${output}",
- ]
- }
-
- if (is_android) {
- android_assets("${final_target_name}_assets") {
- forward_variables_from(invoker, [ "testonly" ])
- deps = [
- ":${library_target_name}",
- ]
- if (defined(invoker.deps)) {
- deps += invoker.deps
- }
- renaming_sources = [ "${root_shlib_dir}/${library_name}" ]
- renaming_destinations = [ "${base_target_name}/${output}" ]
- if (defined(invoker.resources)) {
- renaming_sources += invoker.resources
- renaming_destinations += process_file_template(
- invoker.resources,
- [ "$base_target_name/resources/{{source_file_part}}" ])
- }
- }
- }
-}
-
-if (is_android) {
- # Declares an Android Mojo application consisting of an .so file and a
- # corresponding .dex.jar file.
- #
- # Variables:
- # input_so: the .so file to bundle
- # input_dex_jar: the .dex.jar file to bundle
- # deps / public_deps / data_deps (optional):
- # Dependencies. The targets that generate the .so/jar inputs should be
- # listed in either deps or public_deps.
- # output_name (optional): override for the output file name
- template("mojo_android_application") {
- assert(defined(invoker.input_so))
- assert(defined(invoker.input_dex_jar))
-
- base_target_name = target_name
- if (defined(invoker.output_name)) {
- base_target_name = invoker.output_name
- }
-
- mojo_data_deps = []
- if (defined(invoker.resources)) {
- copy_step_name = "${base_target_name}__copy_resources"
- copy(copy_step_name) {
- sources = invoker.resources
- outputs = [
- "${root_out_dir}/${mojo_application_subdir}/${base_target_name}/resources/{{source_file_part}}",
- ]
- if (defined(invoker.testonly)) {
- testonly = invoker.testonly
- }
- if (defined(invoker.deps)) {
- deps = invoker.deps
- }
- }
- mojo_data_deps += [ ":$copy_step_name" ]
- }
-
- zip_action_name = "${target_name}_zip"
- zip_action_output = "$target_gen_dir/${target_name}.zip"
- prepend_action_name = target_name
- zip(zip_action_name) {
- visibility = [ ":$prepend_action_name" ]
- inputs = [
- invoker.input_so,
- invoker.input_dex_jar,
- ]
- output = zip_action_output
- forward_variables_from(invoker,
- [
- "deps",
- "public_deps",
- "data_deps",
- ])
- }
-
- _mojo_output = "${root_out_dir}/${mojo_application_subdir}/${base_target_name}/${base_target_name}.mojo"
-
- action(target_name) {
- script = "//mojo/public/tools/prepend.py"
-
- input = zip_action_output
- inputs = [
- input,
- ]
-
- outputs = [
- _mojo_output,
- ]
-
- rebase_input = rebase_path(input, root_build_dir)
- rebase_output = rebase_path(_mojo_output, root_build_dir)
- args = [
- "--input=$rebase_input",
- "--output=$rebase_output",
- "--line=#!mojo mojo:android_handler",
- ]
-
- data_deps = mojo_data_deps
-
- public_deps = [
- ":$zip_action_name",
- ]
- }
-
- android_assets("${target_name}_assets") {
- forward_variables_from(invoker, [ "testonly" ])
- deps = [
- ":$prepend_action_name",
- ]
- renaming_sources = [ _mojo_output ]
- renaming_destinations = [ "${base_target_name}/${base_target_name}.mojo" ]
- if (defined(invoker.resources)) {
- renaming_sources += invoker.resources
- renaming_destinations += process_file_template(
- invoker.resources,
- [ "$base_target_name/resources/{{source_file_part}}" ])
- }
- }
- }
-}
diff --git a/mojo/public/mojo_application_manifest.gni b/mojo/public/mojo_application_manifest.gni
deleted file mode 100644
index 6184417..0000000
--- a/mojo/public/mojo_application_manifest.gni
+++ /dev/null
@@ -1,139 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//mojo/public/mojo_constants.gni")
-
-# Used to produce a Mojo Application Manifest for an application.
-#
-# Parameters:
-#
-# source
-# The manifest file template for this application, must be valid JSON with
-# a valid 'url' key matching application_name.
-#
-# base_manifest (optional)
-# A manifest file template to use as a base for |source|. Any properties
-# defined in |source| will overwrite or be merged with properties defined
-# in |base_manifest|.
-#
-# application_name
-# The host portion of the mojo: URL of the application. The script
-# validates that the value of this parameter matches the host name portion
-# of the 'url' property set in the manifest and throws a ValueError if
-# they do not.
-#
-# base_deps (optional)
-# Dependencies required to generate |base_manifest| if applicable.
-#
-# deps (optional)
-# An array of dependent instances of this template. This template enforces
-# that dependencies can only be instances of this template.
-#
-# packaged_applications (optional)
-# An array of application_names of the dependent applications.
-#
-# type (default is mojo)
-# Possible values are 'mojo' and 'exe'. Default is 'mojo'.
-#
-# Outputs:
-#
-# An instantiation of this template produces in
-# $outdir/<application_name>/manifest.json
-# a meta manifest from the source template and the output manifest of all
-# dependent children.
-#
-template("mojo_application_manifest") {
- assert(defined(invoker.source),
- "\"source\" must be defined for the $target_name template")
- assert(defined(invoker.application_name),
- "\"application_name\" must be defined for the $target_name template")
- if (defined(invoker.deps)) {
- assert(defined(invoker.packaged_applications),
- "\"packaged_applications\" listing the directory containing the " +
- "manifest.json of dependent applications must be provided.")
- }
- if (defined(invoker.packaged_applications)) {
- assert(defined(invoker.deps),
- "\"deps\" building the dependent packaged applications must be " +
- "provided.")
- }
- if (defined(invoker.type)) {
- assert(invoker.type == "mojo" || invoker.type == "exe",
- "\"type\" must be one of \"mojo\" or \"exe\".")
- }
-
- action(target_name) {
- script = "//mojo/public/tools/manifest/manifest_collator.py"
-
- type = "mojo"
- if (defined(invoker.type)) {
- type = invoker.type
- }
-
- application_name = invoker.application_name
- inputs = [
- invoker.source,
- ]
-
- if (type == "mojo") {
- output = "$root_out_dir/$mojo_application_subdir/$application_name/manifest.json"
- } else {
- output = "$root_out_dir/${application_name}_manifest.json"
- }
- outputs = [
- output,
- ]
-
- rebase_parent = rebase_path(invoker.source, root_build_dir)
- rebase_output = rebase_path(output, root_build_dir)
-
- args = [
- "--application-name=$application_name",
- "--parent=$rebase_parent",
- "--output=$rebase_output",
- ]
-
- if (defined(invoker.base_manifest)) {
- rebase_base = rebase_path(invoker.base_manifest, root_build_dir)
- args += [ "--base-manifest=$rebase_base" ]
- }
-
- if (defined(invoker.packaged_applications)) {
- foreach(application_name, invoker.packaged_applications) {
- input = "$root_out_dir/$mojo_application_subdir/$application_name/manifest.json"
- inputs += [ input ]
- args += [ rebase_path(input, root_build_dir) ]
- }
- }
- deps = []
- data_deps = []
- if (defined(invoker.deps)) {
- deps += invoker.deps
- data_deps += invoker.deps
- }
- if (defined(invoker.base_deps)) {
- deps += invoker.base_deps
- data_deps += invoker.base_deps
- }
- }
-
- all_deps = []
- if (defined(invoker.deps)) {
- all_deps += invoker.deps
- }
-
- group("${target_name}__is_mojo_application_manifest") {
- }
-
- # Explicitly ensure that all dependencies are mojo_application_manifest
- # targets themselves.
- group("${target_name}__check_deps_are_all_mojo_application_manifest") {
- deps = []
- foreach(d, all_deps) {
- name = get_label_info(d, "label_no_toolchain")
- toolchain = get_label_info(d, "toolchain")
- deps += [ "${name}__is_mojo_application_manifest(${toolchain})" ]
- }
- }
-}
diff --git a/mojo/public/mojo_application_manifest.gypi b/mojo/public/mojo_application_manifest.gypi
deleted file mode 100644
index 9b89abb..0000000
--- a/mojo/public/mojo_application_manifest.gypi
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'variables': {
- 'variables': {
- 'application_name%': '<(application_name)',
- 'application_type%': '<(application_type)',
- 'base_manifest%': 'none',
- 'packaged_manifests%': []
- },
- 'application_type%': '<(application_type)',
- 'application_name%': '<(application_name)',
- 'base_manifest%': '<(base_manifest)',
- 'manifest_collator_script%':
- '<(DEPTH)/mojo/public/tools/manifest/manifest_collator.py',
- 'packaged_manifests%': '<(packaged_manifests)',
- 'source_manifest%': '<(source_manifest)',
- 'conditions': [
- ['application_type=="mojo"', {
- 'output_manifest%': '<(PRODUCT_DIR)/Mojo Applications/<(application_name)/manifest.json',
- }, {
- 'output_manifest%': '<(PRODUCT_DIR)/<(application_name)_manifest.json',
- }],
- ['base_manifest!="none"', {
- 'extra_args%': [
- '--base-manifest=<(base_manifest)',
- '<@(packaged_manifests)',
- ],
- }, {
- 'extra_args%': [
- '<@(packaged_manifests)',
- ],
- }]
- ],
- },
- 'actions': [{
- 'action_name': '<(_target_name)_collation',
- 'inputs': [
- '<(manifest_collator_script)',
- '<(source_manifest)',
- ],
- 'outputs': [
- '<(output_manifest)',
- ],
- 'action': [
- 'python',
- '<(manifest_collator_script)',
- '--application-name', '<(application_name)',
- '--parent=<(source_manifest)',
- '--output=<(output_manifest)',
- '<@(extra_args)',
- ],
- }],
-}
diff --git a/mojo/public/mojo_constants.gni b/mojo/public/mojo_constants.gni
deleted file mode 100644
index 3165a8d..0000000
--- a/mojo/public/mojo_constants.gni
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-declare_args() {
- # Mojo application directories are created within this subdirectory.
- mojo_application_subdir = "Mojo Applications"
-}
diff --git a/mojo/public/tools/bindings/BUILD.gn b/mojo/public/tools/bindings/BUILD.gn
index eeea5c5..153d110 100644
--- a/mojo/public/tools/bindings/BUILD.gn
+++ b/mojo/public/tools/bindings/BUILD.gn
@@ -16,7 +16,9 @@ action("precompile_templates") {
"$mojom_generator_root/generators/cpp_templates/interface_request_validator_declaration.tmpl",
"$mojom_generator_root/generators/cpp_templates/interface_response_validator_declaration.tmpl",
"$mojom_generator_root/generators/cpp_templates/interface_stub_declaration.tmpl",
- "$mojom_generator_root/generators/cpp_templates/module-internal.h.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module-shared-internal.h.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module-shared.cc.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module-shared.h.tmpl",
"$mojom_generator_root/generators/cpp_templates/module.cc.tmpl",
"$mojom_generator_root/generators/cpp_templates/module.h.tmpl",
"$mojom_generator_root/generators/cpp_templates/struct_data_view_declaration.tmpl",
@@ -25,11 +27,15 @@ action("precompile_templates") {
"$mojom_generator_root/generators/cpp_templates/struct_definition.tmpl",
"$mojom_generator_root/generators/cpp_templates/struct_macros.tmpl",
"$mojom_generator_root/generators/cpp_templates/struct_serialization_declaration.tmpl",
- "$mojom_generator_root/generators/cpp_templates/struct_serialization_definition.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/struct_traits_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/struct_traits_definition.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/union_data_view_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/union_data_view_definition.tmpl",
"$mojom_generator_root/generators/cpp_templates/union_declaration.tmpl",
"$mojom_generator_root/generators/cpp_templates/union_definition.tmpl",
"$mojom_generator_root/generators/cpp_templates/union_serialization_declaration.tmpl",
- "$mojom_generator_root/generators/cpp_templates/union_serialization_definition.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/union_traits_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/union_traits_definition.tmpl",
"$mojom_generator_root/generators/cpp_templates/validation_macros.tmpl",
"$mojom_generator_root/generators/cpp_templates/wrapper_class_declaration.tmpl",
"$mojom_generator_root/generators/cpp_templates/wrapper_class_definition.tmpl",
diff --git a/mojo/public/tools/bindings/bindings.gyp b/mojo/public/tools/bindings/bindings.gyp
deleted file mode 100644
index 0f00114..0000000
--- a/mojo/public/tools/bindings/bindings.gyp
+++ /dev/null
@@ -1,83 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'includes': [
- '../../../mojom_bindings_generator_variables.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'precompile_mojom_bindings_generator_templates',
- 'type': 'none',
- 'actions': [
- {
- 'action_name': 'precompile_mojom_bindings_generator_templates',
- 'inputs': [
- '<@(mojom_bindings_generator_sources)',
- 'generators/cpp_templates/enum_macros.tmpl',
- 'generators/cpp_templates/enum_serialization_declaration.tmpl',
- 'generators/cpp_templates/interface_declaration.tmpl',
- 'generators/cpp_templates/interface_definition.tmpl',
- 'generators/cpp_templates/interface_macros.tmpl',
- 'generators/cpp_templates/interface_proxy_declaration.tmpl',
- 'generators/cpp_templates/interface_request_validator_declaration.tmpl',
- 'generators/cpp_templates/interface_response_validator_declaration.tmpl',
- 'generators/cpp_templates/interface_stub_declaration.tmpl',
- 'generators/cpp_templates/module.cc.tmpl',
- 'generators/cpp_templates/module.h.tmpl',
- 'generators/cpp_templates/module-internal.h.tmpl',
- 'generators/cpp_templates/struct_data_view_declaration.tmpl',
- 'generators/cpp_templates/struct_data_view_definition.tmpl',
- 'generators/cpp_templates/struct_declaration.tmpl',
- 'generators/cpp_templates/struct_definition.tmpl',
- 'generators/cpp_templates/struct_macros.tmpl',
- 'generators/cpp_templates/struct_serialization_declaration.tmpl',
- 'generators/cpp_templates/struct_serialization_definition.tmpl',
- 'generators/cpp_templates/union_declaration.tmpl',
- 'generators/cpp_templates/union_definition.tmpl',
- 'generators/cpp_templates/union_serialization_declaration.tmpl',
- 'generators/cpp_templates/union_serialization_definition.tmpl',
- 'generators/cpp_templates/validation_macros.tmpl',
- 'generators/cpp_templates/wrapper_class_declaration.tmpl',
- 'generators/cpp_templates/wrapper_class_definition.tmpl',
- 'generators/cpp_templates/wrapper_class_template_definition.tmpl',
- 'generators/cpp_templates/wrapper_union_class_declaration.tmpl',
- 'generators/cpp_templates/wrapper_union_class_definition.tmpl',
- 'generators/cpp_templates/wrapper_union_class_template_definition.tmpl',
- 'generators/java_templates/constant_definition.tmpl',
- 'generators/java_templates/constants.java.tmpl',
- 'generators/java_templates/data_types_definition.tmpl',
- 'generators/java_templates/enum_definition.tmpl',
- 'generators/java_templates/enum.java.tmpl',
- 'generators/java_templates/header.java.tmpl',
- 'generators/java_templates/interface_definition.tmpl',
- 'generators/java_templates/interface_internal.java.tmpl',
- 'generators/java_templates/interface.java.tmpl',
- 'generators/java_templates/struct.java.tmpl',
- 'generators/java_templates/union.java.tmpl',
- 'generators/js_templates/enum_definition.tmpl',
- 'generators/js_templates/interface_definition.tmpl',
- 'generators/js_templates/module_definition.tmpl',
- 'generators/js_templates/module.amd.tmpl',
- 'generators/js_templates/struct_definition.tmpl',
- 'generators/js_templates/union_definition.tmpl',
- 'generators/js_templates/validation_macros.tmpl',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/mojo/public/tools/bindings/cpp_templates.zip',
- '<(SHARED_INTERMEDIATE_DIR)/mojo/public/tools/bindings/java_templates.zip',
- '<(SHARED_INTERMEDIATE_DIR)/mojo/public/tools/bindings/js_templates.zip',
- ],
- 'action': [
- 'python', '<@(mojom_bindings_generator)',
- '--use_bundled_pylibs', 'precompile',
- '-o', '<(SHARED_INTERMEDIATE_DIR)/mojo/public/tools/bindings',
- ],
- }
- ],
- 'hard_dependency': 1,
- },
- ],
-}
-
diff --git a/mojo/public/tools/bindings/blink_bindings_configuration.gni b/mojo/public/tools/bindings/blink_bindings_configuration.gni
index ef19cc3..bb0fc43 100644
--- a/mojo/public/tools/bindings/blink_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/blink_bindings_configuration.gni
@@ -9,21 +9,25 @@ for_blink = true
_typemap_imports = [
"//mojo/public/cpp/bindings/tests/blink_typemaps.gni",
"//third_party/WebKit/Source/platform/mojo/blink_typemaps.gni",
+ "//third_party/WebKit/public/blink_typemaps.gni",
+ "//third_party/WebKit/public/public_typemaps.gni",
]
_typemaps = []
foreach(typemap_import, _typemap_imports) {
+ # Avoid reassignment error by assigning to empty scope first.
+ _imported = {
+ }
_imported = read_file(typemap_import, "scope")
_typemaps += _imported.typemaps
}
typemaps = []
foreach(typemap, _typemaps) {
- typemaps += [ read_file(typemap, "scope") ]
+ typemaps += [ {
+ filename = typemap
+ config = read_file(typemap, "scope")
+ } ]
}
-blacklist = [
- # TODO(sammc): Remove the following once |for_blink| bindings support WTF
- # maps with enum keys. See https://crbug.com/583738.
- "//mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom",
-]
+blacklist = []
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index 44c2ae6..831157f 100644
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -3,28 +3,78 @@
# found in the LICENSE file.
_typemap_imports = [
+ "//ash/public/interfaces/typemaps.gni",
"//cc/ipc/typemaps.gni",
- "//device/bluetooth/public/interfaces/typemaps.gni",
+ "//chrome/browser/media/router/mojo/typemaps.gni",
+ "//chrome/common/extensions/typemaps.gni",
+ "//chrome/common/importer/typemaps.gni",
+ "//chrome/typemaps.gni",
"//components/arc/common/typemaps.gni",
+ "//components/metrics/public/cpp/typemaps.gni",
"//components/typemaps.gni",
+ "//content/common/bluetooth/typemaps.gni",
+ "//content/common/indexed_db/typemaps.gni",
+ "//content/common/presentation/typemaps.gni",
+ "//content/common/typemaps.gni",
+ "//content/public/common/typemaps.gni",
+ "//device/bluetooth/public/interfaces/typemaps.gni",
+ "//device/gamepad/public/interfaces/typemaps.gni",
+ "//device/generic_sensor/public/interfaces/typemaps.gni",
+ "//device/usb/public/interfaces/typemaps.gni",
"//gpu/ipc/common/typemaps.gni",
+ "//media/capture/mojo/typemaps.gni",
"//media/mojo/interfaces/typemaps.gni",
"//mojo/common/typemaps.gni",
"//mojo/public/cpp/bindings/tests/chromium_typemaps.gni",
+ "//net/interfaces/typemaps.gni",
+ "//services/preferences/public/cpp/typemaps.gni",
+ "//services/resource_coordinator/public/cpp/typemaps.gni",
+ "//services/service_manager/public/cpp/typemaps.gni",
+ "//services/ui/gpu/interfaces/typemaps.gni",
+ "//services/ui/public/interfaces/ime/typemaps.gni",
+ "//services/video_capture/public/interfaces/typemaps.gni",
"//skia/public/interfaces/typemaps.gni",
+ "//third_party/WebKit/public/public_typemaps.gni",
+ "//ui/base/mojo/typemaps.gni",
+ "//ui/display/mojo/typemaps.gni",
"//ui/events/devices/mojo/typemaps.gni",
"//ui/events/mojo/typemaps.gni",
"//ui/gfx/typemaps.gni",
+ "//ui/message_center/mojo/typemaps.gni",
"//url/mojo/typemaps.gni",
]
-_typemaps = []
+_typemap_imports_mac = [ "//content/common/typemaps_mac.gni" ]
+
+_typemaps = []
foreach(typemap_import, _typemap_imports) {
+ # Avoid reassignment error by assigning to empty scope first.
+ _imported = {
+ }
_imported = read_file(typemap_import, "scope")
_typemaps += _imported.typemaps
}
typemaps = []
foreach(typemap, _typemaps) {
- typemaps += [ read_file(typemap, "scope") ]
+ typemaps += [ {
+ filename = typemap
+ config = read_file(typemap, "scope")
+ } ]
+}
+
+_typemaps_mac = []
+foreach(typemap_import, _typemap_imports_mac) {
+ _imported = {
+ }
+ _imported = read_file(typemap_import, "scope")
+ _typemaps_mac += _imported.typemaps
+}
+
+typemaps_mac = []
+foreach(typemap, _typemaps_mac) {
+ typemaps_mac += [ {
+ filename = typemap
+ config = read_file(typemap, "scope")
+ } ]
}
diff --git a/mojo/public/tools/bindings/generate_type_mappings.py b/mojo/public/tools/bindings/generate_type_mappings.py
index e2fbf31..824f804 100755
--- a/mojo/public/tools/bindings/generate_type_mappings.py
+++ b/mojo/public/tools/bindings/generate_type_mappings.py
@@ -97,8 +97,9 @@ def ParseTypemap(typemap):
mojom_type = match_result.group(1)
native_type = match_result.group(2)
- # The only attribute supported currently is "move_only".
- move_only = match_result.group(3) and match_result.group(3) == "move_only"
+ attributes = []
+ if match_result.group(3):
+ attributes = match_result.group(3).split(',')
assert mojom_type not in result, (
"Cannot map multiple native types (%s, %s) to the same mojom type: %s" %
@@ -106,7 +107,11 @@ def ParseTypemap(typemap):
result[mojom_type] = {
'typename': native_type,
- 'move_only': move_only,
+ 'non_copyable_non_movable': 'non_copyable_non_movable' in attributes,
+ 'move_only': 'move_only' in attributes,
+ 'copyable_pass_by_value': 'copyable_pass_by_value' in attributes,
+ 'nullable_is_same_type': 'nullable_is_same_type' in attributes,
+ 'hashable': 'hashable' in attributes,
'public_headers': values['public_headers'],
'traits_headers': values['traits_headers'],
}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl
index 0a446a7..f0d503e 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl
@@ -1,22 +1,55 @@
{#---
Macro for enum definition, and the declaration of associated functions.
---#}
+
{%- macro enum_decl(enum) %}
-enum class {{enum.name}} : int32_t {
-{%- for field in enum.fields %}
-{%- if field.value %}
+{%- set enum_name = enum|get_name_for_kind(flatten_nested_kind=True) %}
+enum class {{enum_name}} : int32_t {
+{%- for field in enum.fields %}
+{%- if field.value %}
{{field.name}} = {{field.value|expression_to_text}},
-{%- else %}
+{%- else %}
{{field.name}},
-{%- endif %}
-{%- endfor %}
+{%- endif %}
+{%- endfor %}
};
+
+inline std::ostream& operator<<(std::ostream& os, {{enum_name}} value) {
+{%- if enum.fields %}
+ switch(value) {
+{%- for _, values in enum.fields|groupby('numeric_value') %}
+ case {{enum_name}}::{{values[0].name}}:
+ return os << "{{enum_name}}::
+{%- if values|length > 1 -%}
+ {{'{'}}
+{%- endif -%}
+ {{values|map(attribute='name')|join(', ')}}
+{%- if values|length > 1 -%}
+ {{'}'}}
+{%- endif -%}
+ ";
+{%- endfor %}
+ default:
+ return os << "Unknown {{enum_name}} value: " << static_cast<int32_t>(value);
+ }
+{%- else %}
+ return os << "Unknown {{enum_name}} value: " << static_cast<int32_t>(value);
+{%- endif %}
+}
+
+{#- Returns true if the given enum value exists in this version of enum. #}
+inline bool IsKnownEnumValue({{enum_name}} value) {
+ return {{enum|get_name_for_kind(internal=True,
+ flatten_nested_kind=True)}}::IsKnownValue(
+ static_cast<int32_t>(value));
+}
{%- endmacro %}
{%- macro enum_data_decl(enum) %}
-struct {{enum.name}}_Data {
+{%- set enum_name = enum|get_name_for_kind(flatten_nested_kind=True) %}
+struct {{enum_name}}_Data {
public:
- static bool const kIsExtensible = {% if enum.extensible %}true{% else %}false{% endif %};
+ static bool constexpr kIsExtensible = {% if enum.extensible %}true{% else %}false{% endif %};
static bool IsKnownValue(int32_t value) {
{%- if enum.fields %}
@@ -42,42 +75,57 @@ struct {{enum.name}}_Data {
};
{%- endmacro %}
-{#--- macros for enum-associated functions. Namely:
- * operator<<(): outputs the given enum value.
- * IsKnownEnumValue(): returns true if the given enum value exists in this
- generated version of enum.
----#}
+{%- macro enum_hash(enum) %}
+{%- set enum_name = enum|get_qualified_name_for_kind(
+ flatten_nested_kind=True) %}
+template <>
+struct hash<{{enum_name}}>
+ : public mojo::internal::EnumHashImpl<{{enum_name}}> {};
+{%- endmacro %}
-{%- macro enum_stream_operator(enum) %}
-inline std::ostream& operator<<(std::ostream& os, {{enum|get_name_for_kind}} value) {
- switch(value) {
-{%- for _, values in enum.fields|groupby('numeric_value') %}
- case {{enum|get_name_for_kind}}::{{values[0].name}}:
- return os << "{{enum|get_name_for_kind}}::
-{%- if values|length > 1 -%}
- {{'{'}}
-{%- endif -%}
- {{values|map(attribute='name')|join(', ')}}
-{%- if values|length > 1 -%}
- {{'}'}}
-{%- endif -%}
- ";
-{%- endfor %}
- default:
- return os << "Unknown {{enum|get_name_for_kind}} value: " << static_cast<int32_t>(value);
+{%- macro enum_hash_blink(enum) %}
+{%- set enum_name = enum|get_qualified_name_for_kind(
+ flatten_nested_kind=True, include_variant=False) %}
+{%- set hash_fn_name = enum|wtf_hash_fn_name_for_enum %}
+{# We need two unused enum values: #}
+{%- set empty_value = -1000000 %}
+{%- set deleted_value = -1000001 %}
+{%- set empty_value_unused = "false" if empty_value in enum|all_enum_values else "true" %}
+{%- set deleted_value_unused = "false" if empty_value in enum|all_enum_values else "true" %}
+namespace WTF {
+struct {{hash_fn_name}} {
+ static unsigned hash(const {{enum_name}}& value) {
+ typedef base::underlying_type<{{enum_name}}>::type utype;
+ return DefaultHash<utype>::Hash().hash(static_cast<utype>(value));
}
-}
-{%- endmacro %}
+ static bool equal(const {{enum_name}}& left, const {{enum_name}}& right) {
+ return left == right;
+ }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
-{%- macro is_known_enum_value(enum) %}
-inline bool IsKnownEnumValue({{enum|get_name_for_kind}} value) {
- return {{enum|get_qualified_name_for_kind(internal=True)}}::IsKnownValue(
- static_cast<int32_t>(value));
-}
-{%- endmacro %}
+template <>
+struct DefaultHash<{{enum_name}}> {
+ using Hash = {{hash_fn_name}};
+};
-{%- macro enum_hash(enum) %}
template <>
-struct hash<{{enum|get_qualified_name_for_kind}}>
- : public mojo::internal::EnumHashImpl<{{enum|get_qualified_name_for_kind}}> {};
+struct HashTraits<{{enum_name}}>
+ : public GenericHashTraits<{{enum_name}}> {
+ static_assert({{empty_value_unused}},
+ "{{empty_value}} is a reserved enum value");
+ static_assert({{deleted_value_unused}},
+ "{{deleted_value}} is a reserved enum value");
+ static const bool hasIsEmptyValueFunction = true;
+ static bool isEmptyValue(const {{enum_name}}& value) {
+ return value == static_cast<{{enum_name}}>({{empty_value}});
+ }
+ static void constructDeletedValue({{enum_name}}& slot, bool) {
+ slot = static_cast<{{enum_name}}>({{deleted_value}});
+ }
+ static bool isDeletedValue(const {{enum_name}}& value) {
+ return value == static_cast<{{enum_name}}>({{deleted_value}});
+ }
+};
+} // namespace WTF
{%- endmacro %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/enum_serialization_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/enum_serialization_declaration.tmpl
index e42128d..d7d0e5d 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/enum_serialization_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/enum_serialization_declaration.tmpl
@@ -1,4 +1,5 @@
-{%- set mojom_type = enum|get_qualified_name_for_kind %}
+{%- set mojom_type = enum|get_qualified_name_for_kind(
+ flatten_nested_kind=True) %}
template <>
struct EnumTraits<{{mojom_type}}, {{mojom_type}}> {
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl
index 0249ef3..7f64974 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl
@@ -1,5 +1,7 @@
{%- import "interface_macros.tmpl" as interface_macros %}
class {{interface.name}}Proxy;
+
+template <typename ImplRefTraits>
class {{interface.name}}Stub;
class {{interface.name}}RequestValidator;
@@ -7,15 +9,18 @@ class {{interface.name}}RequestValidator;
class {{interface.name}}ResponseValidator;
{%- endif %}
-class {{interface.name}} {
+class {{export_attribute}} {{interface.name}}
+ : public {{interface.name}}InterfaceBase {
public:
static const char Name_[];
- static const uint32_t Version_ = {{interface.version}};
- static const bool PassesAssociatedKinds_ = {% if interface|passes_associated_kinds %}true{% else %}false{% endif %};
- static const bool HasSyncMethods_ = {% if interface|has_sync_methods %}true{% else %}false{% endif %};
+ static constexpr uint32_t Version_ = {{interface.version}};
+ static constexpr bool PassesAssociatedKinds_ = {% if interface|passes_associated_kinds %}true{% else %}false{% endif %};
+ static constexpr bool HasSyncMethods_ = {% if interface|has_sync_methods %}true{% else %}false{% endif %};
using Proxy_ = {{interface.name}}Proxy;
- using Stub_ = {{interface.name}}Stub;
+
+ template <typename ImplRefTraits>
+ using Stub_ = {{interface.name}}Stub<ImplRefTraits>;
using RequestValidator_ = {{interface.name}}RequestValidator;
{%- if interface|has_callbacks %}
@@ -24,23 +29,21 @@ class {{interface.name}} {
using ResponseValidator_ = mojo::PassThroughFilter;
{%- endif %}
+{#--- Metadata #}
+ enum MethodMinVersions : uint32_t {
+{%- for method in interface.methods %}
+ k{{method.name}}MinVersion = {{method.min_version|default(0, true)}},
+{%- endfor %}
+ };
+
{#--- Enums #}
-{% from "enum_macros.tmpl" import enum_decl -%}
{%- for enum in interface.enums %}
-{%- if enum|is_native_only_kind %}
- using {{enum.name}} = mojo::NativeEnum;
-{%- else %}
- {{enum_decl(enum)|indent(2)}}
-{%- endif %}
+ using {{enum.name}} = {{enum|get_name_for_kind(flatten_nested_kind=True)}};
{%- endfor %}
{#--- Constants #}
{%- for constant in interface.constants %}
-{%- if constant.kind|is_integral_kind %}
- static const {{constant.kind|cpp_pod_type}} {{constant.name}} = {{constant|constant_value}};
-{%- else %}
- static const {{constant.kind|cpp_pod_type}} {{constant.name}};
-{%- endif %}
+ static {{constant|format_constant_declaration(nested=True)}};
{%- endfor %}
{#--- Methods #}
@@ -55,8 +58,8 @@ class {{interface.name}} {
{%- endif %}
using {{method.name}}Callback = {{interface_macros.declare_callback(method,
- for_blink, use_new_wrapper_types)}};
+ for_blink, use_once_callback)}};
{%- endif %}
- virtual void {{method.name}}({{interface_macros.declare_request_params("", method)}}) = 0;
+ virtual void {{method.name}}({{interface_macros.declare_request_params("", method, use_once_callback)}}) = 0;
{%- endfor %}
};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
index 4017fc5..a23b107 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
@@ -5,24 +5,22 @@
{%- set proxy_name = interface.name ~ "Proxy" %}
{%- set namespace_as_string = "%s"|format(namespace|replace(".","::")) %}
-{%- macro alloc_params(struct, params, message, serialization_context,
- description) %}
- ({{serialization_context}})->handles.Swap(({{message}})->mutable_handles());
+{%- macro alloc_params(struct, params, message, description) %}
+ mojo::internal::SerializationContext serialization_context;
+ serialization_context.handles.Swap(({{message}})->mutable_handles());
+ serialization_context.associated_endpoint_handles.swap(
+ *({{message}})->mutable_associated_endpoint_handles());
bool success = true;
{%- for param in struct.packed.packed_fields_in_ordinal_order %}
{{param.field.kind|cpp_wrapper_type}} p_{{param.field.name}}{};
{%- endfor %}
- {{struct.name}}DataView input_data_view({{params}},
- {{serialization_context}});
+ {{struct.name}}DataView input_data_view({{params}}, &serialization_context);
{{struct_macros.deserialize(struct, "input_data_view", "p_%s", "success")}}
if (!success) {
- mojo::internal::ValidationContext validation_context(
- {{message}}->data(), {{message}}->data_num_bytes(),
- {{message}}->handles()->size(), {{message}},
+ ReportValidationErrorForMessage(
+ {{message}},
+ mojo::internal::VALIDATION_ERROR_DESERIALIZATION_FAILED,
"{{description}} deserializer");
- ReportValidationError(
- &validation_context,
- mojo::internal::VALIDATION_ERROR_DESERIALIZATION_FAILED);
return false;
}
{%- endmacro %}
@@ -41,18 +39,17 @@ std::move(p_{{param.name}})
serialization_context)}}
({{serialization_context}})->handles.Swap(
builder.message()->mutable_handles());
+ ({{serialization_context}})->associated_endpoint_handles.swap(
+ *builder.message()->mutable_associated_endpoint_handles());
{%- endmacro %}
{#--- Begin #}
const char {{class_name}}::Name_[] = "{{namespace_as_string}}::{{class_name}}";
-const uint32_t {{class_name}}::Version_;
{#--- Constants #}
{%- for constant in interface.constants %}
-{%- if constant.kind|is_integral_kind %}
-const {{constant.kind|cpp_pod_type}} {{interface.name}}::{{constant.name}};
-{%- else %}
-const {{constant.kind|cpp_pod_type}} {{interface.name}}::{{constant.name}} = {{constant|constant_value}};
+{%- if constant.kind|is_string_kind %}
+const char {{interface.name}}::{{constant.name}}[] = {{constant|constant_value}};
{%- endif %}
{%- endfor %}
@@ -74,12 +71,11 @@ class {{class_name}}_{{method.name}}_HandleSyncResponse
: public mojo::MessageReceiver {
public:
{{class_name}}_{{method.name}}_HandleSyncResponse(
- scoped_refptr<mojo::AssociatedGroupController> group_controller,
bool* result
{%- for param in method.response_parameters -%}
, {{param.kind|cpp_wrapper_type}}* out_{{param.name}}
{%- endfor %})
- : serialization_context_(std::move(group_controller)), result_(result)
+ : result_(result)
{%- for param in method.response_parameters -%}
, out_{{param.name}}_(out_{{param.name}})
{%- endfor %} {
@@ -87,7 +83,6 @@ class {{class_name}}_{{method.name}}_HandleSyncResponse
}
bool Accept(mojo::Message* message) override;
private:
- mojo::internal::SerializationContext serialization_context_;
bool* result_;
{%- for param in method.response_parameters %}
{{param.kind|cpp_wrapper_type}}* out_{{param.name}}_;
@@ -100,13 +95,14 @@ bool {{class_name}}_{{method.name}}_HandleSyncResponse::Accept(
reinterpret_cast<internal::{{class_name}}_{{method.name}}_ResponseParams_Data*>(
message->mutable_payload());
- {{alloc_params(method.response_param_struct, "params", "message",
- "&serialization_context_",
- "{{class_name}}::{{method.name}} response")}}
+{%- set desc = class_name~"::"~method.name~" response" %}
+ {{alloc_params(method.response_param_struct, "params", "message", desc)}}
{%- for param in method.response_parameters %}
*out_{{param.name}}_ = std::move(p_{{param.name}});
{%- endfor %}
+ mojo::internal::SyncMessageResponseSetup::SetCurrentSyncResponseMessage(
+ message);
*result_ = true;
return true;
}
@@ -116,15 +112,16 @@ class {{class_name}}_{{method.name}}_ForwardToCallback
: public mojo::MessageReceiver {
public:
{{class_name}}_{{method.name}}_ForwardToCallback(
- const {{class_name}}::{{method.name}}Callback& callback,
- scoped_refptr<mojo::AssociatedGroupController> group_controller)
- : callback_(callback),
- serialization_context_(std::move(group_controller)) {
+{%- if use_once_callback %}
+ {{class_name}}::{{method.name}}Callback callback
+{%- else %}
+ const {{class_name}}::{{method.name}}Callback& callback
+{%- endif %}
+ ) : callback_(std::move(callback)) {
}
bool Accept(mojo::Message* message) override;
private:
{{class_name}}::{{method.name}}Callback callback_;
- mojo::internal::SerializationContext serialization_context_;
DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ForwardToCallback);
};
bool {{class_name}}_{{method.name}}_ForwardToCallback::Accept(
@@ -133,18 +130,19 @@ bool {{class_name}}_{{method.name}}_ForwardToCallback::Accept(
reinterpret_cast<internal::{{class_name}}_{{method.name}}_ResponseParams_Data*>(
message->mutable_payload());
- {{alloc_params(method.response_param_struct, "params", "message",
- "&serialization_context_",
- "{{class_name}}_{{method.name}} response")}}
- if (!callback_.is_null())
- callback_.Run({{pass_params(method.response_parameters)}});
+{%- set desc = class_name~"::"~method.name~" response" %}
+ {{alloc_params(method.response_param_struct, "params", "message", desc)}}
+ if (!callback_.is_null()) {
+ mojo::internal::MessageDispatchContext context(message);
+ std::move(callback_).Run({{pass_params(method.response_parameters)}});
+ }
return true;
}
{%- endif %}
{%- endfor %}
{{proxy_name}}::{{proxy_name}}(mojo::MessageReceiverWithResponder* receiver)
- : ControlMessageProxy(receiver) {
+ : receiver_(receiver) {
}
{#--- Proxy definitions #}
@@ -158,19 +156,22 @@ bool {{class_name}}_{{method.name}}_ForwardToCallback::Accept(
{%- if method.sync %}
bool {{proxy_name}}::{{method.name}}(
{{interface_macros.declare_sync_method_params("param_", method)}}) {
+ mojo::internal::SerializationContext serialization_context;
{{struct_macros.get_serialized_size(params_struct, "param_%s",
- "&serialization_context_")}}
+ "&serialization_context")}}
- mojo::internal::RequestMessageBuilder builder({{message_name}}, size,
- mojo::Message::kFlagIsSync);
+ mojo::internal::MessageBuilder builder(
+ {{message_name}},
+ mojo::Message::kFlagIsSync | mojo::Message::kFlagExpectsResponse,
+ size, serialization_context.associated_endpoint_count);
{{build_message(params_struct, "param_%s", params_description,
- "&serialization_context_")}}
+ "&serialization_context")}}
bool result = false;
mojo::MessageReceiver* responder =
new {{class_name}}_{{method.name}}_HandleSyncResponse(
- serialization_context_.group_controller, &result
+ &result
{%- for param in method.response_parameters -%}
, param_{{param.name}}
{%- endfor %});
@@ -181,23 +182,26 @@ bool {{proxy_name}}::{{method.name}}(
{%- endif %}
void {{proxy_name}}::{{method.name}}(
- {{interface_macros.declare_request_params("in_", method)}}) {
+ {{interface_macros.declare_request_params("in_", method, use_once_callback)}}) {
+ mojo::internal::SerializationContext serialization_context;
{{struct_macros.get_serialized_size(params_struct, "in_%s",
- "&serialization_context_")}}
+ "&serialization_context")}}
{%- if method.response_parameters != None %}
- mojo::internal::RequestMessageBuilder builder({{message_name}}, size);
+ constexpr uint32_t kFlags = mojo::Message::kFlagExpectsResponse;
{%- else %}
- mojo::internal::MessageBuilder builder({{message_name}}, size);
+ constexpr uint32_t kFlags = 0;
{%- endif %}
+ mojo::internal::MessageBuilder builder(
+ {{message_name}}, kFlags, size,
+ serialization_context.associated_endpoint_count);
{{build_message(params_struct, "in_%s", params_description,
- "&serialization_context_")}}
+ "&serialization_context")}}
{%- if method.response_parameters != None %}
mojo::MessageReceiver* responder =
- new {{class_name}}_{{method.name}}_ForwardToCallback(
- callback, serialization_context_.group_controller);
+ new {{class_name}}_{{method.name}}_ForwardToCallback(std::move(callback));
if (!receiver_->AcceptWithResponder(builder.message(), responder))
delete responder;
{%- else %}
@@ -217,42 +221,23 @@ void {{proxy_name}}::{{method.name}}(
{%- set response_params_struct = method.response_param_struct %}
{%- set params_description =
"%s.%s response"|format(interface.name, method.name) %}
-class {{class_name}}_{{method.name}}_ProxyToResponder
- : public base::RefCountedThreadSafe<
- {{class_name}}_{{method.name}}_ProxyToResponder> {
+class {{class_name}}_{{method.name}}_ProxyToResponder {
public:
static {{class_name}}::{{method.name}}Callback CreateCallback(
uint64_t request_id,
bool is_sync,
- mojo::MessageReceiverWithStatus* responder,
- scoped_refptr<mojo::AssociatedGroupController>
- group_controller) {
- scoped_refptr<{{class_name}}_{{method.name}}_ProxyToResponder> proxy
- = new {{class_name}}_{{method.name}}_ProxyToResponder(
- request_id, is_sync, responder, group_controller);
+ mojo::MessageReceiverWithStatus* responder) {
+ std::unique_ptr<{{class_name}}_{{method.name}}_ProxyToResponder> proxy(
+ new {{class_name}}_{{method.name}}_ProxyToResponder(
+ request_id, is_sync, responder));
return base::Bind(&{{class_name}}_{{method.name}}_ProxyToResponder::Run,
- proxy);
- }
-
- private:
- friend class base::RefCountedThreadSafe<
- {{class_name}}_{{method.name}}_ProxyToResponder>;
-
- {{class_name}}_{{method.name}}_ProxyToResponder(
- uint64_t request_id,
- bool is_sync,
- mojo::MessageReceiverWithStatus* responder,
- scoped_refptr<mojo::AssociatedGroupController> group_controller)
- : request_id_(request_id),
- is_sync_(is_sync),
- responder_(responder),
- serialization_context_(std::move(group_controller)) {
+ base::Passed(&proxy));
}
~{{class_name}}_{{method.name}}_ProxyToResponder() {
#if DCHECK_IS_ON()
if (responder_) {
- // Is the Mojo application destroying the callback without running it
+ // Is the Service destroying the callback without running it
// and without first closing the pipe?
responder_->DCheckInvalid("The callback passed to "
"{{class_name}}::{{method.name}}() was never run.");
@@ -263,31 +248,43 @@ class {{class_name}}_{{method.name}}_ProxyToResponder
delete responder_;
}
+ private:
+ {{class_name}}_{{method.name}}_ProxyToResponder(
+ uint64_t request_id,
+ bool is_sync,
+ mojo::MessageReceiverWithStatus* responder)
+ : request_id_(request_id),
+ is_sync_(is_sync),
+ responder_(responder) {
+ }
+
void Run(
{{interface_macros.declare_responder_params(
- "in_", method.response_parameters, for_blink,
- use_new_wrapper_types)}});
+ "in_", method.response_parameters, for_blink)}});
uint64_t request_id_;
bool is_sync_;
mojo::MessageReceiverWithStatus* responder_;
- // TODO(yzshen): maybe I should use a ref to the original one?
- mojo::internal::SerializationContext serialization_context_;
DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ProxyToResponder);
};
void {{class_name}}_{{method.name}}_ProxyToResponder::Run(
{{interface_macros.declare_responder_params(
- "in_", method.response_parameters, for_blink,
- use_new_wrapper_types)}}) {
+ "in_", method.response_parameters, for_blink)}}) {
+ mojo::internal::SerializationContext serialization_context;
{{struct_macros.get_serialized_size(response_params_struct, "in_%s",
- "&serialization_context_")}}
- mojo::internal::ResponseMessageBuilder builder(
- {{message_name}}, size, request_id_,
- is_sync_ ? mojo::Message::kFlagIsSync : 0);
+ "&serialization_context")}}
+
+ uint32_t flags = (is_sync_ ? mojo::Message::kFlagIsSync : 0) |
+ mojo::Message::kFlagIsResponse;
+ mojo::internal::MessageBuilder builder(
+ {{message_name}}, flags, size,
+ serialization_context.associated_endpoint_count);
+ builder.message()->set_request_id(request_id_);
+
{{build_message(response_params_struct, "in_%s", params_description,
- "&serialization_context_")}}
+ "&serialization_context")}}
bool ok = responder_->Accept(builder.message());
ALLOW_UNUSED_LOCAL(ok);
// TODO(darin): !ok returned here indicates a malformed message, and that may
@@ -299,18 +296,12 @@ void {{class_name}}_{{method.name}}_ProxyToResponder::Run(
{%- endif -%}
{%- endfor %}
-{{class_name}}Stub::{{class_name}}Stub()
- : sink_(nullptr),
- control_message_handler_({{interface.name}}::Version_) {
-}
-
-{{class_name}}Stub::~{{interface.name}}Stub() {}
-
-{#--- Stub definition #}
+{#--- StubDispatch definition #}
-bool {{class_name}}Stub::Accept(mojo::Message* message) {
- if (mojo::internal::ControlMessageHandler::IsControlMessage(message))
- return control_message_handler_.Accept(message);
+// static
+bool {{class_name}}StubDispatch::Accept(
+ {{interface.name}}* impl,
+ mojo::Message* message) {
{%- if interface.methods %}
switch (message->header()->name) {
{%- for method in interface.methods %}
@@ -320,13 +311,14 @@ bool {{class_name}}Stub::Accept(mojo::Message* message) {
reinterpret_cast<internal::{{class_name}}_{{method.name}}_Params_Data*>(
message->mutable_payload());
- {{alloc_params(method.param_struct, "params", "message",
- "&serialization_context_", "{{class_name}}::{{method.name}}")
- |indent(4)}}
- // A null |sink_| means no implementation was bound.
- assert(sink_);
+{%- set desc = class_name~"::"~method.name %}
+ {{alloc_params(method.param_struct, "params", "message", desc)|
+ indent(4)}}
+ // A null |impl| means no implementation was bound.
+ assert(impl);
TRACE_EVENT0("mojom", "{{class_name}}::{{method.name}}");
- sink_->{{method.name}}({{pass_params(method.parameters)}});
+ mojo::internal::MessageDispatchContext context(message);
+ impl->{{method.name}}({{pass_params(method.parameters)}});
return true;
{%- else %}
break;
@@ -338,10 +330,11 @@ bool {{class_name}}Stub::Accept(mojo::Message* message) {
return false;
}
-bool {{class_name}}Stub::AcceptWithResponder(
- mojo::Message* message, mojo::MessageReceiverWithStatus* responder) {
- if (mojo::internal::ControlMessageHandler::IsControlMessage(message))
- return control_message_handler_.AcceptWithResponder(message, responder);
+// static
+bool {{class_name}}StubDispatch::AcceptWithResponder(
+ {{interface.name}}* impl,
+ mojo::Message* message,
+ mojo::MessageReceiverWithStatus* responder) {
{%- if interface.methods %}
switch (message->header()->name) {
{%- for method in interface.methods %}
@@ -351,20 +344,19 @@ bool {{class_name}}Stub::AcceptWithResponder(
reinterpret_cast<internal::{{class_name}}_{{method.name}}_Params_Data*>(
message->mutable_payload());
- {{alloc_params(method.param_struct, "params", "message",
- "&serialization_context_", "{{class_name}}::{{method.name}}")|
- indent(4)}}
+{%- set desc = class_name~"::"~method.name %}
+ {{alloc_params(method.param_struct, "params", "message", desc)|
+ indent(4)}}
{{class_name}}::{{method.name}}Callback callback =
{{class_name}}_{{method.name}}_ProxyToResponder::CreateCallback(
message->request_id(),
- message->has_flag(mojo::Message::kFlagIsSync),
- responder,
- serialization_context_.group_controller);
- // A null |sink_| means no implementation was bound.
- assert(sink_);
+ message->has_flag(mojo::Message::kFlagIsSync), responder);
+ // A null |impl| means no implementation was bound.
+ assert(impl);
TRACE_EVENT0("mojom", "{{class_name}}::{{method.name}}");
- sink_->{{method.name}}(
-{%- if method.parameters -%}{{pass_params(method.parameters)}}, {% endif -%}callback);
+ mojo::internal::MessageDispatchContext context(message);
+ impl->{{method.name}}(
+{%- if method.parameters -%}{{pass_params(method.parameters)}}, {% endif -%}std::move(callback));
return true;
{%- else %}
break;
@@ -378,22 +370,14 @@ bool {{class_name}}Stub::AcceptWithResponder(
{#--- Request validator definitions #}
-{{class_name}}RequestValidator::{{class_name}}RequestValidator(
- mojo::MessageReceiver* sink) : MessageFilter(sink) {
-}
-
bool {{class_name}}RequestValidator::Accept(mojo::Message* message) {
- assert(sink_);
+ if (mojo::internal::ControlMessageHandler::IsControlMessage(message))
+ return true;
mojo::internal::ValidationContext validation_context(
- message->data(), message->data_num_bytes(), message->handles()->size(),
- message, "{{class_name}} RequestValidator");
-
- if (mojo::internal::ControlMessageHandler::IsControlMessage(message)) {
- if (!mojo::internal::ValidateControlRequest(message, &validation_context))
- return false;
- return sink_->Accept(message);
- }
+ message->payload(), message->payload_num_bytes(),
+ message->handles()->size(), message->payload_num_interface_ids(), message,
+ "{{class_name}} RequestValidator");
switch (message->header()->name) {
{%- for method in interface.methods %}
@@ -414,7 +398,7 @@ bool {{class_name}}RequestValidator::Accept(mojo::Message* message) {
message, &validation_context)) {
return false;
}
- return sink_->Accept(message);
+ return true;
}
{%- endfor %}
default:
@@ -430,22 +414,14 @@ bool {{class_name}}RequestValidator::Accept(mojo::Message* message) {
{#--- Response validator definitions #}
{% if interface|has_callbacks %}
-{{class_name}}ResponseValidator::{{class_name}}ResponseValidator(
- mojo::MessageReceiver* sink) : MessageFilter(sink) {
-}
-
bool {{class_name}}ResponseValidator::Accept(mojo::Message* message) {
- assert(sink_);
+ if (mojo::internal::ControlMessageHandler::IsControlMessage(message))
+ return true;
mojo::internal::ValidationContext validation_context(
- message->data(), message->data_num_bytes(), message->handles()->size(),
- message, "{{class_name}} ResponseValidator");
-
- if (mojo::internal::ControlMessageHandler::IsControlMessage(message)) {
- if (!mojo::internal::ValidateControlResponse(message, &validation_context))
- return false;
- return sink_->Accept(message);
- }
+ message->payload(), message->payload_num_bytes(),
+ message->handles()->size(), message->payload_num_interface_ids(), message,
+ "{{class_name}} ResponseValidator");
if (!mojo::internal::ValidateMessageIsResponse(message, &validation_context))
return false;
@@ -457,7 +433,7 @@ bool {{class_name}}ResponseValidator::Accept(mojo::Message* message) {
message, &validation_context)) {
return false;
}
- return sink_->Accept(message);
+ return true;
}
{%- endfor %}
default:
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
index 4bec4c6..8649273 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
@@ -5,39 +5,35 @@
{%- endfor %}
{%- endmacro %}
-{%- macro declare_responder_params(prefix, parameters, for_blink, use_new_wrapper_types) %}
+{%- macro declare_responder_params(prefix, parameters, for_blink) %}
{%- for param in parameters -%}
-{%- if (not param.kind|is_string_kind) or for_blink or
- use_new_wrapper_types -%}
{{param.kind|cpp_wrapper_param_type}} {{prefix}}{{param.name}}
-{%- else %}
-mojo::String {{prefix}}{{param.name}}
-{%- endif %}
{%- if not loop.last %}, {% endif %}
{%- endfor %}
{%- endmacro %}
-{%- macro declare_callback(method, for_blink, use_new_wrapper_types) -%}
+{%- macro declare_callback(method, for_blink, use_once_callback) -%}
+{%- if use_once_callback -%}
+base::OnceCallback<void(
+{%- else -%}
base::Callback<void(
+{%- endif -%}
{%- for param in method.response_parameters -%}
-{#- TODO(yzshen): For historical reasons, we use mojo::String here (instead of
- const mojo::String&) inconsistently. Preserve the behavior temporarily. #}
-{%- if (not param.kind|is_string_kind) or for_blink or
- use_new_wrapper_types -%}
{{param.kind|cpp_wrapper_param_type}}
-{%- else -%}
-mojo::String
-{%- endif %}
{%- if not loop.last %}, {% endif %}
{%- endfor -%}
)>
{%- endmacro -%}
-{%- macro declare_request_params(prefix, method) -%}
+{%- macro declare_request_params(prefix, method, use_once_callback) -%}
{{declare_params(prefix, method.parameters)}}
{%- if method.response_parameters != None -%}
-{%- if method.parameters %}, {% endif -%}
+{%- if method.parameters %}, {% endif -%}
+{%- if use_once_callback -%}
+{{method.name}}Callback callback
+{%- else -%}
const {{method.name}}Callback& callback
+{%- endif -%}
{%- endif -%}
{%- endmacro -%}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl
index 477116b..0a158ec 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl
@@ -1,7 +1,6 @@
{%- import "interface_macros.tmpl" as interface_macros %}
-class {{interface.name}}Proxy
- : public {{interface.name}},
- public mojo::internal::ControlMessageProxy {
+class {{export_attribute}} {{interface.name}}Proxy
+ : public {{interface.name}} {
public:
explicit {{interface.name}}Proxy(mojo::MessageReceiverWithResponder* receiver);
@@ -9,13 +8,9 @@ class {{interface.name}}Proxy
{%- if method.sync %}
bool {{method.name}}({{interface_macros.declare_sync_method_params("", method)}}) override;
{%- endif %}
- void {{method.name}}({{interface_macros.declare_request_params("", method)}}) override;
+ void {{method.name}}({{interface_macros.declare_request_params("", method, use_once_callback)}}) override;
{%- endfor %}
- mojo::internal::SerializationContext* serialization_context() {
- return &serialization_context_;
- }
-
private:
- mojo::internal::SerializationContext serialization_context_;
+ mojo::MessageReceiverWithResponder* receiver_;
};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl
index 29917ea..a00d148 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl
@@ -1,6 +1,4 @@
-class {{interface.name}}RequestValidator : public mojo::MessageFilter {
+class {{export_attribute}} {{interface.name}}RequestValidator : public NON_EXPORTED_BASE(mojo::MessageReceiver) {
public:
- explicit {{interface.name}}RequestValidator(mojo::MessageReceiver* sink = nullptr);
-
bool Accept(mojo::Message* message) override;
};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl
index 5893bfd..e2caa02 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl
@@ -1,6 +1,4 @@
-class {{interface.name}}ResponseValidator : public mojo::MessageFilter {
+class {{export_attribute}} {{interface.name}}ResponseValidator : public NON_EXPORTED_BASE(mojo::MessageReceiver) {
public:
- explicit {{interface.name}}ResponseValidator(mojo::MessageReceiver* sink = nullptr);
-
bool Accept(mojo::Message* message) override;
};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl
index 30b5de7..9f01348 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl
@@ -1,19 +1,40 @@
-class {{interface.name}}Stub : public mojo::MessageReceiverWithResponderStatus {
+class {{export_attribute}} {{interface.name}}StubDispatch {
public:
- {{interface.name}}Stub();
- ~{{interface.name}}Stub() override;
- void set_sink({{interface.name}}* sink) { sink_ = sink; }
- {{interface.name}}* sink() { return sink_; }
- mojo::internal::SerializationContext* serialization_context() {
- return &serialization_context_;
+ static bool Accept({{interface.name}}* impl, mojo::Message* message);
+ static bool AcceptWithResponder({{interface.name}}* impl,
+ mojo::Message* message,
+ mojo::MessageReceiverWithStatus* responder);
+};
+
+template <typename ImplRefTraits =
+ mojo::RawPtrImplRefTraits<{{interface.name}}>>
+class {{interface.name}}Stub
+ : public NON_EXPORTED_BASE(mojo::MessageReceiverWithResponderStatus) {
+ public:
+ using ImplPointerType = typename ImplRefTraits::PointerType;
+
+ {{interface.name}}Stub() {}
+ ~{{interface.name}}Stub() override {}
+
+ void set_sink(ImplPointerType sink) { sink_ = std::move(sink); }
+ ImplPointerType& sink() { return sink_; }
+
+ bool Accept(mojo::Message* message) override {
+ if (ImplRefTraits::IsNull(sink_))
+ return false;
+ return {{interface.name}}StubDispatch::Accept(
+ ImplRefTraits::GetRawPointer(&sink_), message);
}
- bool Accept(mojo::Message* message) override;
- bool AcceptWithResponder(mojo::Message* message,
- mojo::MessageReceiverWithStatus* responder) override;
+ bool AcceptWithResponder(
+ mojo::Message* message,
+ mojo::MessageReceiverWithStatus* responder) override {
+ if (ImplRefTraits::IsNull(sink_))
+ return false;
+ return {{interface.name}}StubDispatch::AcceptWithResponder(
+ ImplRefTraits::GetRawPointer(&sink_), message, responder);
+ }
private:
- {{interface.name}}* sink_;
- mojo::internal::SerializationContext serialization_context_;
- mojo::internal::ControlMessageHandler control_message_handler_;
+ ImplPointerType sink_;
};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl
deleted file mode 100644
index 5256e75..0000000
--- a/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-{%- if variant -%}
-{%- set variant_path = "%s-%s"|format(module.path, variant) -%}
-{%- else -%}
-{%- set variant_path = module.path -%}
-{%- endif -%}
-
-{%- set header_guard = "%s_INTERNAL_H_"|format(
- variant_path|upper|replace("/","_")|replace(".","_")|
- replace("-", "_")) %}
-
-#ifndef {{header_guard}}
-#define {{header_guard}}
-
-#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
-#include "mojo/public/cpp/bindings/lib/buffer.h"
-#include "mojo/public/cpp/bindings/lib/serialization.h"
-#include "mojo/public/cpp/bindings/lib/union_accessor.h"
-#include "mojo/public/cpp/bindings/struct_ptr.h"
-
-{%- for import in imports %}
-{%- if variant %}
-#include "{{"%s-%s-internal.h"|format(import.module.path, variant)}}"
-{%- else %}
-#include "{{import.module.path}}-internal.h"
-{%- endif %}
-{%- endfor %}
-
-namespace mojo {
-namespace internal {
-class ValidationContext;
-}
-}
-
-{%- for namespace in namespaces_as_array %}
-namespace {{namespace}} {
-{%- endfor %}
-{%- if variant %}
-namespace {{variant}} {
-{%- endif %}
-
-{#--- Wrapper forward declarations #}
-{% for struct in structs %}
-{%- if struct|is_native_only_kind %}
-using {{struct.name}} = mojo::NativeStruct;
-{%- else %}
-class {{struct.name}};
-{%- endif %}
-{%- endfor %}
-
-{#--- Wrapper forward declarations for unions #}
-{% for union in unions %}
-class {{union.name}};
-{%- endfor %}
-
-namespace internal {
-
-{#--- Internal forward declarations #}
-{% for struct in structs %}
-{%- if struct|is_native_only_kind %}
-using {{struct.name}}_Data = mojo::internal::NativeStruct_Data;
-{%- else %}
-class {{struct.name}}_Data;
-{%- endif %}
-{%- endfor %}
-
-{% for union in unions %}
-class {{union.name}}_Data;
-{%- endfor %}
-
-{#--- Enums #}
-{% from "enum_macros.tmpl" import enum_data_decl -%}
-{%- for enum in enums %}
-{%- if enum|is_native_only_kind %}
- using {{enum.name}}_Data = mojo::internal::NativeEnum_Data;
-{%- else %}
- {{enum_data_decl(enum)}}
-{%- endif %}
-{%- endfor %}
-
-#pragma pack(push, 1)
-
-{#--- Unions must be declared first because they can be members of structs #}
-{#--- Union class declarations #}
-{% for union in unions %}
-{% include "union_declaration.tmpl" %}
-{%- endfor %}
-
-{#--- Struct class declarations #}
-{% for struct in structs %}
-{%- if not struct|is_native_only_kind %}
-{% include "struct_declaration.tmpl" %}
-{%- endif %}
-{%- endfor %}
-
-{#--- Interface class declarations. They are needed only when they contain
- enums. #}
-{%- for interface in interfaces %}
-{%- if interface.enums %}
-class {{interface.name}}_Data {
- public:
-{%- for enum in interface.enums %}
-{%- if enum|is_native_only_kind %}
- using {{enum.name}}_Data = mojo::internal::NativeEnum_Data;
-{%- else %}
- {{enum_data_decl(enum)|indent(2)}}
-{%- endif %}
-{%- endfor %}
-};
-{%- endif %}
-{%- endfor %}
-
-#pragma pack(pop)
-
-} // namespace internal
-{%- if variant %}
-} // namespace {{variant}}
-{%- endif %}
-{%- for namespace in namespaces_as_array|reverse %}
-} // namespace {{namespace}}
-{%- endfor %}
-
-#endif // {{header_guard}}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl
new file mode 100644
index 0000000..964b254
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl
@@ -0,0 +1,96 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+{%- set header_guard = "%s_SHARED_INTERNAL_H_"|format(
+ module.path|upper|replace("/","_")|replace(".","_")|
+ replace("-", "_")) %}
+
+#ifndef {{header_guard}}
+#define {{header_guard}}
+
+#include <stdint.h>
+
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/map_data_internal.h"
+#include "mojo/public/cpp/bindings/lib/native_enum_data.h"
+#include "mojo/public/cpp/bindings/lib/native_struct_data.h"
+#include "mojo/public/cpp/bindings/lib/buffer.h"
+
+{%- for import in imports %}
+#include "{{import.module.path}}-shared-internal.h"
+{%- endfor %}
+
+namespace mojo {
+namespace internal {
+class ValidationContext;
+}
+}
+
+{%- for namespace in namespaces_as_array %}
+namespace {{namespace}} {
+{%- endfor %}
+namespace internal {
+
+{#--- Internal forward declarations #}
+{%- for struct in structs %}
+{%- if struct|is_native_only_kind %}
+using {{struct.name}}_Data = mojo::internal::NativeStruct_Data;
+{%- else %}
+class {{struct.name}}_Data;
+{%- endif %}
+{%- endfor %}
+
+{%- for union in unions %}
+class {{union.name}}_Data;
+{%- endfor %}
+
+{#--- Enums #}
+{%- from "enum_macros.tmpl" import enum_data_decl -%}
+{%- for enum in all_enums %}
+{%- if enum|is_native_only_kind %}
+using {{enum|get_name_for_kind(flatten_nested_kind=True)}}_Data =
+ mojo::internal::NativeEnum_Data;
+{%- else %}
+{{enum_data_decl(enum)}}
+{%- endif %}
+{%- endfor %}
+
+#pragma pack(push, 1)
+
+{#--- Unions must be declared first because they can be members of structs #}
+{#--- Union class declarations #}
+{%- for union in unions %}
+{% include "union_declaration.tmpl" %}
+{%- endfor %}
+
+{#--- Struct class declarations #}
+{%- for struct in structs %}
+{%- if not struct|is_native_only_kind %}
+{% include "struct_declaration.tmpl" %}
+{%- endif %}
+{%- endfor %}
+
+{#--- Interface parameter definitions #}
+{%- for interface in interfaces %}
+{%- for method in interface.methods %}
+{%- set method_name = "k%s_%s_Name"|format(interface.name, method.name) %}
+constexpr uint32_t {{method_name}} = {{method.ordinal}};
+{%- set struct = method.param_struct %}
+{% include "struct_declaration.tmpl" %}
+{%- if method.response_parameters != None %}
+{%- set struct = method.response_param_struct %}
+{% include "struct_declaration.tmpl" %}
+{%- endif %}
+{%- endfor %}
+{%- endfor %}
+
+#pragma pack(pop)
+
+} // namespace internal
+{%- for namespace in namespaces_as_array|reverse %}
+} // namespace {{namespace}}
+{%- endfor %}
+
+#endif // {{header_guard}}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl
new file mode 100644
index 0000000..645bb69
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl
@@ -0,0 +1,64 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4065)
+#endif
+
+#include "{{module.path}}-shared.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "mojo/public/cpp/bindings/lib/validate_params.h"
+#include "mojo/public/cpp/bindings/lib/validation_context.h"
+#include "mojo/public/cpp/bindings/lib/validation_errors.h"
+#include "mojo/public/cpp/bindings/lib/validation_util.h"
+
+{%- for header in extra_traits_headers %}
+#include "{{header}}"
+{%- endfor %}
+
+{%- for namespace in namespaces_as_array %}
+namespace {{namespace}} {
+{%- endfor %}
+
+namespace internal {
+
+{#--- Union definitions #}
+{%- for union in unions %}
+{% include "union_definition.tmpl" %}
+{%- endfor %}
+
+{#--- Struct definitions #}
+{%- for struct in structs %}
+{%- if not struct|is_native_only_kind %}
+{% include "struct_definition.tmpl" %}
+{%- endif %}
+{%- endfor %}
+
+{#--- Interface parameter definitions #}
+{%- for interface in interfaces %}
+{%- for method in interface.methods %}
+{%- set method_name = "k%s_%s_Name"|format(interface.name, method.name) %}
+{%- set struct = method.param_struct %}
+{% include "struct_definition.tmpl" %}
+{%- if method.response_parameters != None %}
+{%- set struct = method.response_param_struct %}
+{% include "struct_definition.tmpl" %}
+{%- endif %}
+{%- endfor %}
+{%- endfor %}
+
+} // namespace internal
+
+{%- for namespace in namespaces_as_array|reverse %}
+} // namespace {{namespace}}
+{%- endfor %}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl
new file mode 100644
index 0000000..dd13466
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl
@@ -0,0 +1,212 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+{%- set header_guard = "%s_SHARED_H_"|format(
+ module.path|upper|replace("/","_")|replace(".","_")|
+ replace("-", "_")) %}
+
+{%- macro mojom_type_traits(kind) %}
+template <>
+struct MojomTypeTraits<{{kind|get_qualified_name_for_kind}}DataView> {
+ using Data = {{kind|get_qualified_name_for_kind(internal=True)}};
+{%- if kind|is_union_kind %}
+ using DataAsArrayElement = Data;
+ static constexpr MojomTypeCategory category = MojomTypeCategory::UNION;
+{%- else %}
+ using DataAsArrayElement = Pointer<Data>;
+ static constexpr MojomTypeCategory category = MojomTypeCategory::STRUCT;
+{%- endif %}
+};
+{%- endmacro %}
+
+{%- macro namespace_begin() %}
+{%- for namespace in namespaces_as_array %}
+namespace {{namespace}} {
+{%- endfor %}
+{%- endmacro %}
+
+{%- macro namespace_end() %}
+{%- for namespace in namespaces_as_array|reverse %}
+} // namespace {{namespace}}
+{%- endfor %}
+{%- endmacro %}
+
+#ifndef {{header_guard}}
+#define {{header_guard}}
+
+#include <stdint.h>
+
+#include <functional>
+#include <ostream>
+#include <type_traits>
+#include <utility>
+
+#include "base/compiler_specific.h"
+#include "mojo/public/cpp/bindings/array_data_view.h"
+#include "mojo/public/cpp/bindings/enum_traits.h"
+#include "mojo/public/cpp/bindings/interface_data_view.h"
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/serialization.h"
+#include "mojo/public/cpp/bindings/map_data_view.h"
+#include "mojo/public/cpp/bindings/native_enum.h"
+#include "mojo/public/cpp/bindings/native_struct_data_view.h"
+#include "mojo/public/cpp/bindings/string_data_view.h"
+#include "{{module.path}}-shared-internal.h"
+{%- for import in imports %}
+#include "{{import.module.path}}-shared.h"
+{%- endfor %}
+
+{{namespace_begin()}}
+
+{#--- Struct Forward Declarations -#}
+{%- for struct in structs %}
+{%- if struct|is_native_only_kind %}
+using {{struct.name}}DataView = mojo::NativeStructDataView;
+{%- else %}
+class {{struct.name}}DataView;
+{%- endif %}
+{% endfor %}
+
+{#--- Union Forward Declarations -#}
+{%- for union in unions %}
+class {{union.name}}DataView;
+{%- endfor %}
+
+{{namespace_end()}}
+
+namespace mojo {
+namespace internal {
+
+{%- for struct in structs %}
+{%- if not struct|is_native_only_kind %}
+{{mojom_type_traits(struct)}}
+{%- endif %}
+{%- endfor %}
+
+{%- for union in unions %}
+{{mojom_type_traits(union)}}
+{%- endfor %}
+
+} // namespace internal
+} // namespace mojo
+
+{{namespace_begin()}}
+
+{#--- Enums #}
+{%- from "enum_macros.tmpl" import enum_decl%}
+{%- for enum in all_enums %}
+{%- if enum|is_native_only_kind %}
+using {{enum|get_name_for_kind(flatten_nested_kind=True)}} = mojo::NativeEnum;
+{%- else %}
+{{enum_decl(enum)}}
+{%- endif %}
+{%- endfor %}
+
+{#--- Interfaces #}
+{%- if interfaces %}
+// Interface base classes. They are used for type safety check.
+{%- endif %}
+{%- for interface in interfaces %}
+class {{interface.name}}InterfaceBase {};
+
+using {{interface.name}}PtrDataView =
+ mojo::InterfacePtrDataView<{{interface.name}}InterfaceBase>;
+using {{interface.name}}RequestDataView =
+ mojo::InterfaceRequestDataView<{{interface.name}}InterfaceBase>;
+using {{interface.name}}AssociatedPtrInfoDataView =
+ mojo::AssociatedInterfacePtrInfoDataView<{{interface.name}}InterfaceBase>;
+using {{interface.name}}AssociatedRequestDataView =
+ mojo::AssociatedInterfaceRequestDataView<{{interface.name}}InterfaceBase>;
+
+{%- endfor %}
+
+{#--- Structs #}
+{%- for struct in structs %}
+{%- if not struct|is_native_only_kind %}
+{% include "struct_data_view_declaration.tmpl" %}
+{%- endif %}
+{%- endfor %}
+
+{#--- Interface parameter definitions #}
+{%- for interface in interfaces %}
+{%- for method in interface.methods %}
+{%- set struct = method.param_struct %}
+{% include "struct_data_view_declaration.tmpl" %}
+{%- if method.response_parameters != None %}
+{%- set struct = method.response_param_struct %}
+{% include "struct_data_view_declaration.tmpl" %}
+{%- endif %}
+{%- endfor %}
+{%- endfor %}
+
+{#--- Unions #}
+{%- for union in unions %}
+{% include "union_data_view_declaration.tmpl" %}
+{%- endfor %}
+
+{{namespace_end()}}
+
+namespace std {
+
+{%- from "enum_macros.tmpl" import enum_hash %}
+{%- for enum in all_enums %}
+{%- if not enum|is_native_only_kind %}
+{{enum_hash(enum)}}
+{%- endif %}
+{%- endfor %}
+
+} // namespace std
+
+namespace mojo {
+
+{#--- Enum Serialization Helpers -#}
+{%- for enum in all_enums %}
+{%- if not enum|is_native_only_kind %}
+{% include "enum_serialization_declaration.tmpl" %}
+{%- endif %}
+{%- endfor %}
+
+{#--- Struct Serialization Helpers -#}
+{% for struct in structs %}
+{%- if not struct|is_native_only_kind %}
+{% include "struct_serialization_declaration.tmpl" %}
+{%- endif %}
+{%- endfor %}
+
+{#--- Union Serialization Helpers -#}
+{% if unions %}
+{%- for union in unions %}
+{% include "union_serialization_declaration.tmpl" %}
+{%- endfor %}
+{%- endif %}
+
+} // namespace mojo
+
+{{namespace_begin()}}
+
+{%- for struct in structs %}
+{%- if not struct|is_native_only_kind %}
+{% include "struct_data_view_definition.tmpl" %}
+{%- endif %}
+{%- endfor %}
+
+{%- for interface in interfaces %}
+{%- for method in interface.methods %}
+{%- set struct = method.param_struct %}
+{% include "struct_data_view_definition.tmpl" %}
+{%- if method.response_parameters != None %}
+{%- set struct = method.response_param_struct %}
+{% include "struct_data_view_definition.tmpl" %}
+{%- endif %}
+{%- endfor %}
+{%- endfor %}
+
+{%- for union in unions %}
+{% include "union_data_view_definition.tmpl" %}
+{%- endfor %}
+
+{{namespace_end()}}
+
+#endif // {{header_guard}}
+
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
index efb9db6..2c66a85 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
@@ -26,13 +26,11 @@
#include "base/logging.h"
#include "base/trace_event/trace_event.h"
-#include "mojo/public/cpp/bindings/lib/map_data_internal.h"
#include "mojo/public/cpp/bindings/lib/message_builder.h"
#include "mojo/public/cpp/bindings/lib/serialization_util.h"
#include "mojo/public/cpp/bindings/lib/validate_params.h"
#include "mojo/public/cpp/bindings/lib/validation_context.h"
#include "mojo/public/cpp/bindings/lib/validation_errors.h"
-#include "mojo/public/cpp/bindings/lib/validation_util.h"
#include "mojo/public/interfaces/bindings/interface_control_messages.mojom.h"
{%- if for_blink %}
@@ -52,75 +50,16 @@ namespace {{variant}} {
{#--- Constants #}
{%- for constant in module.constants %}
-{%- if not constant.kind|is_integral_kind %}
-const {{constant.kind|cpp_pod_type}} {{constant.name}} = {{constant|constant_value}};
+{%- if constant.kind|is_string_kind %}
+const char {{constant.name}}[] = {{constant|constant_value}};
{%- endif %}
{%- endfor %}
-namespace internal {
-namespace {
-
-#pragma pack(push, 1)
-
-{#--- Interface parameter definitions #}
-{%- for interface in interfaces %}
-{%- for method in interface.methods %}
-{%- set method_name = "k%s_%s_Name"|format(interface.name, method.name) %}
-const uint32_t {{method_name}} = {{method.ordinal}};
-{% set struct = method.param_struct %}
-{% include "struct_declaration.tmpl" %}
-{%- include "struct_definition.tmpl" %}
-{%- if method.response_parameters != None %}
-{%- set struct = method.response_param_struct %}
-{% include "struct_declaration.tmpl" %}
-{%- include "struct_definition.tmpl" %}
-{%- endif %}
-{%- endfor %}
-{%- endfor %}
-
-#pragma pack(pop)
-
-} // namespace
-
-{#--- Struct definitions #}
-{% for struct in structs %}
-{%- if not struct|is_native_only_kind %}
-{%- include "struct_definition.tmpl" %}
-{%- endif %}
-{%- endfor %}
-
-{#--- Union definitions #}
-{% for union in unions %}
-{%- include "union_definition.tmpl" %}
-{%- endfor %}
-
-} // namespace internal
-
-namespace {
-
-{#--- Interface parameter data view definitions #}
-{%- for interface in interfaces %}
-{%- for method in interface.methods %}
-{% set struct = method.param_struct %}
-{% include "struct_data_view_declaration.tmpl" %}
-{% include "struct_data_view_definition.tmpl" %}
-{%- if method.response_parameters != None %}
-{%- set struct = method.response_param_struct %}
-{% include "struct_data_view_declaration.tmpl" %}
-{% include "struct_data_view_definition.tmpl" %}
-{%- endif %}
-{%- endfor %}
-{%- endfor %}
-
-} // namespace
-
{#--- Struct Constants #}
{%- for struct in structs %}
{%- for constant in struct.constants %}
-{%- if constant.kind|is_integral_kind %}
-const {{constant.kind|cpp_pod_type}} {{struct.name}}::{{constant.name}};
-{%- else %}
-const {{constant.kind|cpp_pod_type}} {{struct.name}}::{{constant.name}} = {{constant|constant_value}};
+{%- if constant.kind|is_string_kind %}
+const char {{struct.name}}::{{constant.name}}[] = {{constant|constant_value}};
{%- endif %}
{%- endfor %}
{%- endfor %}
@@ -129,7 +68,6 @@ const {{constant.kind|cpp_pod_type}} {{struct.name}}::{{constant.name}} = {{cons
{%- for struct in structs %}
{%- if not struct|is_native_only_kind %}
{%- include "wrapper_class_definition.tmpl" %}
-{%- include "struct_data_view_definition.tmpl" %}
{%- endif %}
{%- endfor %}
@@ -155,18 +93,17 @@ namespace mojo {
{#--- Struct Serialization Helpers -#}
{% for struct in structs %}
{%- if not struct|is_native_only_kind %}
-{% include "struct_serialization_definition.tmpl" %}
+{% include "struct_traits_definition.tmpl" %}
{%- endif %}
{%- endfor %}
{#--- Union Serialization Helpers #}
{%- for union in unions %}
-{%- include "union_serialization_definition.tmpl" %}
+{%- include "union_traits_definition.tmpl" %}
{%- endfor %}
} // namespace mojo
-
#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(_MSC_VER)
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
index c4f3e07..acdad5e 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
@@ -12,11 +12,6 @@
variant_path|upper|replace("/","_")|replace(".","_")|
replace("-", "_")) %}
-{%- from "enum_macros.tmpl" import enum_decl %}
-{%- from "enum_macros.tmpl" import enum_stream_operator %}
-{%- from "enum_macros.tmpl" import is_known_enum_value %}
-{%- from "enum_macros.tmpl" import enum_hash %}
-
{%- macro namespace_begin() %}
{%- for namespace in namespaces_as_array %}
namespace {{namespace}} {
@@ -40,30 +35,30 @@ namespace {{variant}} {
#include <stdint.h>
-#include <functional>
-#include <ostream>
+#include <limits>
#include <type_traits>
#include <utility>
#include "base/callback.h"
#include "base/optional.h"
-#include "base/strings/string_piece.h"
#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
#include "mojo/public/cpp/bindings/associated_interface_request.h"
+#include "mojo/public/cpp/bindings/clone_traits.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/lib/equals_traits.h"
#include "mojo/public/cpp/bindings/lib/control_message_handler.h"
#include "mojo/public/cpp/bindings/lib/control_message_proxy.h"
#include "mojo/public/cpp/bindings/lib/serialization.h"
-#include "mojo/public/cpp/bindings/map.h"
-#include "mojo/public/cpp/bindings/message_filter.h"
-#include "mojo/public/cpp/bindings/native_enum.h"
+#include "mojo/public/cpp/bindings/lib/union_accessor.h"
#include "mojo/public/cpp/bindings/native_struct.h"
-#include "mojo/public/cpp/bindings/no_interface.h"
+#include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h"
#include "mojo/public/cpp/bindings/struct_ptr.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
-#include "{{variant_path}}-internal.h"
+#include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
+#include "mojo/public/cpp/bindings/union_traits.h"
+#include "{{module.path}}-shared.h"
{%- for import in imports %}
{%- if variant %}
#include "{{"%s-%s.h"|format(import.module.path, variant)}}"
@@ -72,11 +67,13 @@ namespace {{variant}} {
{%- endif %}
{%- endfor %}
{%- if not for_blink %}
-#include "mojo/public/cpp/bindings/array.h"
-#include "mojo/public/cpp/bindings/string.h"
+#include <string>
+#include <vector>
{%- else %}
-#include "mojo/public/cpp/bindings/wtf_array.h"
-#include "mojo/public/cpp/bindings/wtf_map.h"
+{# hash_util.h includes template specializations that should be present for
+ every use of {Inlined}StructPtr. #}
+#include "mojo/public/cpp/bindings/lib/wtf_hash_util.h"
+#include "third_party/WebKit/Source/wtf/HashFunctions.h"
#include "third_party/WebKit/Source/wtf/Optional.h"
#include "third_party/WebKit/Source/wtf/text/WTFString.h"
{%- endif %}
@@ -85,42 +82,32 @@ namespace {{variant}} {
#include "{{header}}"
{%- endfor %}
-{#--- Enums #}
-{%- if enums %}
-{{namespace_begin()}}
-{%- for enum in enums %}
-{%- if enum|is_native_only_kind %}
-using {{enum.name}} = mojo::NativeEnum;
-{%- else %}
-{{enum_decl(enum)}}
-{{enum_stream_operator(enum)}}
-{{is_known_enum_value(enum)}}
-{%- endif %}
-{%- endfor %}
-{{namespace_end()}}
-
-namespace std {
+{%- if export_header %}
+#include "{{export_header}}"
+{%- endif %}
-{%- for enum in enums %}
+{#--- WTF enum hashing #}
+{%- from "enum_macros.tmpl" import enum_hash_blink%}
+{%- if for_blink %}
+{%- for enum in all_enums %}
{%- if not enum|is_native_only_kind %}
-{{enum_hash(enum)}}
+{{enum_hash_blink(enum)}}
{%- endif %}
{%- endfor %}
-
-} // namespace std
{%- endif %}
{{namespace_begin()}}
+{#--- Enums #}
+{%- if variant %}
+{%- for enum in enums %}
+using {{enum.name}} = {{enum.name}}; // Alias for definition in the parent namespace.
+{%- endfor %}
+{%- endif %}
+
{#--- Constants #}
{%- for constant in module.constants %}
-{#- To be consistent with constants defined inside interfaces, only make
- integral types compile-time constants. #}
-{%- if constant.kind|is_integral_kind %}
-const {{constant.kind|cpp_pod_type}} {{constant.name}} = {{constant|constant_value}};
-{%- else %}
-extern const {{constant.kind|cpp_pod_type}} {{constant.name}};
-{%- endif %}
+{{constant|format_constant_declaration}};
{%- endfor %}
{#--- Interface Forward Declarations -#}
@@ -128,9 +115,13 @@ extern const {{constant.kind|cpp_pod_type}} {{constant.name}};
class {{interface.name}};
using {{interface.name}}Ptr = mojo::InterfacePtr<{{interface.name}}>;
using {{interface.name}}PtrInfo = mojo::InterfacePtrInfo<{{interface.name}}>;
+using ThreadSafe{{interface.name}}Ptr =
+ mojo::ThreadSafeInterfacePtr<{{interface.name}}>;
using {{interface.name}}Request = mojo::InterfaceRequest<{{interface.name}}>;
using {{interface.name}}AssociatedPtr =
mojo::AssociatedInterfacePtr<{{interface.name}}>;
+using ThreadSafe{{interface.name}}AssociatedPtr =
+ mojo::ThreadSafeAssociatedInterfacePtr<{{interface.name}}>;
using {{interface.name}}AssociatedPtrInfo =
mojo::AssociatedInterfacePtrInfo<{{interface.name}}>;
using {{interface.name}}AssociatedRequest =
@@ -144,7 +135,6 @@ using {{struct.name}} = mojo::NativeStruct;
using {{struct.name}}Ptr = mojo::NativeStructPtr;
{%- else %}
class {{struct.name}};
-class {{struct.name}}DataView;
{%- if struct|should_inline %}
using {{struct.name}}Ptr = mojo::InlinedStructPtr<{{struct.name}}>;
{%- else %}
@@ -166,27 +156,6 @@ typedef mojo::StructPtr<{{union.name}}> {{union.name}}Ptr;
{#--- Interfaces -#}
{% for interface in interfaces %}
{% include "interface_declaration.tmpl" %}
-
-{%- if interface.enums %}
-{{namespace_end()}}
-namespace std {
-
-{%- for enum in interface.enums %}
-{%- if not enum|is_native_only_kind %}
-{{enum_hash(enum)}}
-{%- endif %}
-{%- endfor %}
-
-} // namespace std
-{{namespace_begin()}}
-{%- endif %}
-
-{%- for enum in interface.enums %}
-{%- if not enum|is_native_only_kind %}
-{{enum_stream_operator(enum)}}
-{{is_known_enum_value(enum)}}
-{%- endif %}
-{%- endfor %}
{%- endfor %}
{#--- Interface Proxies -#}
@@ -216,7 +185,6 @@ namespace std {
{% for struct in structs %}
{% if struct|should_inline and not struct|is_native_only_kind %}
{% include "wrapper_class_declaration.tmpl" %}
-{% include "struct_data_view_declaration.tmpl" %}
{% endif %}
{%- endfor %}
@@ -231,7 +199,6 @@ namespace std {
{% for struct in structs %}
{% if not struct|should_inline and not struct|is_native_only_kind %}
{% include "wrapper_class_declaration.tmpl" %}
-{% include "struct_data_view_declaration.tmpl" %}
{% endif %}
{%- endfor %}
@@ -243,67 +210,23 @@ namespace std {
{%- if not struct|is_native_only_kind %}
{% include "wrapper_class_template_definition.tmpl" %}
{%- endif %}
-
-{%- if struct.enums %}
-{{namespace_end()}}
-namespace std {
-
-{%- for enum in struct.enums %}
-{%- if not enum|is_native_only_kind %}
-{{enum_hash(enum)}}
-{%- endif %}
-{%- endfor %}
-
-} // namespace std
-{{namespace_begin()}}
-{%- endif %}
-
-{%- for enum in struct.enums %}
-{%- if not enum|is_native_only_kind %}
-{{enum_stream_operator(enum)}}
-{{is_known_enum_value(enum)}}
-{%- endif %}
-{%- endfor %}
{%- endfor %}
{{namespace_end()}}
namespace mojo {
-{#--- Enum Serialization Helpers -#}
-{%- for enum in enums %}
-{%- if not enum|is_native_only_kind %}
-{% include "enum_serialization_declaration.tmpl" %}
-{%- endif %}
-{%- endfor %}
-
-{%- for struct in structs %}
-{%- for enum in struct.enums %}
-{%- if not enum|is_native_only_kind %}
-{% include "enum_serialization_declaration.tmpl" %}
-{%- endif %}
-{%- endfor %}
-{%- endfor %}
-
-{%- for interface in interfaces %}
-{%- for enum in interface.enums %}
-{%- if not enum|is_native_only_kind %}
-{% include "enum_serialization_declaration.tmpl" %}
-{%- endif %}
-{%- endfor %}
-{%- endfor %}
-
{#--- Struct Serialization Helpers -#}
{% for struct in structs %}
{%- if not struct|is_native_only_kind %}
-{% include "struct_serialization_declaration.tmpl" %}
+{% include "struct_traits_declaration.tmpl" %}
{%- endif %}
{%- endfor %}
{#--- Union Serialization Helpers -#}
{% if unions %}
{%- for union in unions %}
-{% include "union_serialization_declaration.tmpl" %}
+{% include "union_traits_declaration.tmpl" %}
{%- endfor %}
{%- endif %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl
index 7c34939..96e0d61 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl
@@ -1,29 +1,56 @@
class {{struct.name}}DataView {
public:
+ {{struct.name}}DataView() {}
+
{{struct.name}}DataView(
internal::{{struct.name}}_Data* data,
- mojo::internal::SerializationContext* context);
+ mojo::internal::SerializationContext* context)
+{%- if struct|requires_context_for_data_view %}
+ : data_(data), context_(context) {}
+{%- else %}
+ : data_(data) {}
+{%- endif %}
+
+ bool is_null() const { return !data_; }
{%- for pf in struct.packed.packed_fields_in_ordinal_order %}
-{%- set kind = pf.field.kind -%}
-{%- set name = pf.field.name -%}
-{%- if kind|is_struct_kind or kind|is_array_kind or kind|is_string_kind
- or kind|is_map_kind %}
+{%- set kind = pf.field.kind %}
+{%- set name = pf.field.name %}
+{%- if kind|is_union_kind %}
+ inline void Get{{name|under_to_camel}}DataView(
+ {{kind|cpp_data_view_type}}* output);
+
+ template <typename UserType>
+ WARN_UNUSED_RESULT bool Read{{name|under_to_camel}}(UserType* output) {
+{%- if pf.min_version != 0 %}
+ auto* pointer = data_->header_.version >= {{pf.min_version}}
+ ? &data_->{{name}} : nullptr;
+{%- else %}
+ auto* pointer = &data_->{{name}};
+{%- endif %}
+ return mojo::internal::Deserialize<{{kind|unmapped_type_for_serializer}}>(
+ pointer, output, context_);
+ }
+
+{%- elif kind|is_object_kind %}
+ inline void Get{{name|under_to_camel}}DataView(
+ {{kind|cpp_data_view_type}}* output);
+
template <typename UserType>
- bool Read{{name|under_to_camel}}(UserType* value) {
-{%- if pf.min_version != 0 %}
- auto pointer = data_->header_.version >= {{pf.min_version}}
- ? data_->{{name}}.Get() : nullptr;
-{%- else %}
- auto pointer = data_->{{name}}.Get();
-{%- endif %}
+ WARN_UNUSED_RESULT bool Read{{name|under_to_camel}}(UserType* output) {
+{%- if pf.min_version != 0 %}
+ auto* pointer = data_->header_.version >= {{pf.min_version}}
+ ? data_->{{name}}.Get() : nullptr;
+{%- else %}
+ auto* pointer = data_->{{name}}.Get();
+{%- endif %}
return mojo::internal::Deserialize<{{kind|unmapped_type_for_serializer}}>(
- pointer, value, context_);
+ pointer, output, context_);
}
{%- elif kind|is_enum_kind %}
template <typename UserType>
- bool Read{{name|under_to_camel}}(UserType* value) const {
+ WARN_UNUSED_RESULT bool Read{{name|under_to_camel}}(UserType* output) const {
{%- if pf.min_version != 0 %}
auto data_value = data_->header_.version >= {{pf.min_version}}
? data_->{{name}} : 0;
@@ -31,23 +58,61 @@ class {{struct.name}}DataView {
auto data_value = data_->{{name}};
{%- endif %}
return mojo::internal::Deserialize<{{kind|unmapped_type_for_serializer}}>(
- data_value, value);
+ data_value, output);
}
- {{kind|get_qualified_name_for_kind}} {{name}}() const;
+ {{kind|cpp_data_view_type}} {{name}}() const {
+{%- if pf.min_version != 0 %}
+ if (data_->header_.version < {{pf.min_version}})
+ return {{kind|get_qualified_name_for_kind}}{};
+{%- endif %}
+ return static_cast<{{kind|cpp_data_view_type}}>(data_->{{name}});
+ }
-{%- elif kind|is_union_kind %}
- bool Read{{name|under_to_camel}}({{kind|cpp_wrapper_type}}* value);
+{%- elif kind|is_any_handle_kind %}
+ {{kind|cpp_data_view_type}} Take{{name|under_to_camel}}() {
+ {{kind|cpp_data_view_type}} result;
+{%- if pf.min_version != 0 %}
+ if (data_->header_.version < {{pf.min_version}})
+ return result;
+{%- endif %}
+ bool ret =
+ mojo::internal::Deserialize<{{kind|unmapped_type_for_serializer}}>(
+ &data_->{{name}}, &result, context_);
+ DCHECK(ret);
+ return result;
+ }
-{%- elif kind|is_any_handle_or_interface_kind %}
- {{kind|cpp_wrapper_type}} Take{{name|under_to_camel}}();
+{%- elif kind|is_any_interface_kind %}
+ template <typename UserType>
+ UserType Take{{name|under_to_camel}}() {
+ UserType result;
+{%- if pf.min_version != 0 %}
+ if (data_->header_.version < {{pf.min_version}})
+ return result;
+{%- endif %}
+ bool ret =
+ mojo::internal::Deserialize<{{kind|unmapped_type_for_serializer}}>(
+ &data_->{{name}}, &result, context_);
+ DCHECK(ret);
+ return result;
+ }
{%- else %}
- {{kind|cpp_wrapper_type}} {{name}}() const;
+ {{kind|cpp_data_view_type}} {{name}}() const {
+{%- if pf.min_version != 0 %}
+ if (data_->header_.version < {{pf.min_version}})
+ return {{kind|cpp_data_view_type}}{};
+{%- endif %}
+ return data_->{{name}};
+ }
+
{%- endif %}
{%- endfor %}
private:
- internal::{{struct.name}}_Data* data_;
- mojo::internal::SerializationContext* context_;
+ internal::{{struct.name}}_Data* data_ = nullptr;
+{%- if struct|requires_context_for_data_view %}
+ mojo::internal::SerializationContext* context_ = nullptr;
+{%- endif %}
};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_definition.tmpl
index 2be92b3..95311dc 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_definition.tmpl
@@ -1,59 +1,29 @@
-{{struct.name}}DataView::{{struct.name}}DataView(
- internal::{{struct.name}}_Data* data,
- mojo::internal::SerializationContext* context)
- : data_(data), context_(context) {
- DCHECK(data_);
-}
-
{%- for pf in struct.packed.packed_fields_in_ordinal_order %}
-{%- set kind = pf.field.kind -%}
-{%- set name = pf.field.name -%}
-{%- if kind|is_struct_kind or kind|is_array_kind or kind|is_string_kind or
- kind|is_map_kind %}
-{#- Does nothing. They are already defined in the class declaration. #}
-
-{%- elif kind|is_enum_kind %}
-{{kind|get_qualified_name_for_kind}} {{struct.name}}DataView::{{name}}() const {
-{%- if pf.min_version != 0 %}
- if (data_->header_.version < {{pf.min_version}})
- return {{kind|get_qualified_name_for_kind}}{};
-{%- endif %}
- return static_cast<{{kind|get_qualified_name_for_kind}}>(data_->{{name}});
-}
+{%- set kind = pf.field.kind %}
+{%- set name = pf.field.name %}
-{%- elif kind|is_union_kind %}
-bool {{struct.name}}DataView::Read{{name|under_to_camel}}(
- {{kind|cpp_wrapper_type}}* value) {
+{%- if kind|is_union_kind %}
+inline void {{struct.name}}DataView::Get{{name|under_to_camel}}DataView(
+ {{kind|cpp_data_view_type}}* output) {
{%- if pf.min_version != 0 %}
- auto pointer = data_->header_.version >= {{pf.min_version}}
- ? &data_->{{name}} : nullptr;
+ auto pointer = data_->header_.version >= {{pf.min_version}}
+ ? &data_->{{name}} : nullptr;
{%- else %}
- auto pointer = &data_->{{name}};
+ auto pointer = &data_->{{name}};
{%- endif %}
- return mojo::internal::Deserialize<{{kind|unmapped_type_for_serializer}}>(
- pointer, value, context_);
+ *output = {{kind|cpp_data_view_type}}(pointer, context_);
}
-{%- elif kind|is_any_handle_or_interface_kind %}
-{{kind|cpp_wrapper_type}} {{struct.name}}DataView::Take{{name|under_to_camel}}() {
- {{kind|cpp_wrapper_type}} result;
+{%- elif kind|is_object_kind %}
+inline void {{struct.name}}DataView::Get{{name|under_to_camel}}DataView(
+ {{kind|cpp_data_view_type}}* output) {
{%- if pf.min_version != 0 %}
- if (data_->header_.version < {{pf.min_version}})
- return result;
-{%- endif %}
- bool ret = mojo::internal::Deserialize<{{kind|unmapped_type_for_serializer}}>(
- &data_->{{name}}, &result, context_);
- DCHECK(ret);
- return result;
-}
-
-{%- else %}
-{{kind|cpp_wrapper_type}} {{struct.name}}DataView::{{name}}() const {
-{%- if pf.min_version != 0 %}
- if (data_->header_.version < {{pf.min_version}})
- return {{kind|cpp_wrapper_type}}{};
+ auto pointer = data_->header_.version >= {{pf.min_version}}
+ ? data_->{{name}}.Get() : nullptr;
+{%- else %}
+ auto pointer = data_->{{name}}.Get();
{%- endif %}
- return data_->{{name}};
+ *output = {{kind|cpp_data_view_type}}(pointer, context_);
}
{%- endif %}
{%- endfor %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl
index dd87be7..156f774 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl
@@ -2,21 +2,13 @@
class {{class_name}} {
public:
- static {{class_name}}* New(mojo::internal::Buffer* buf);
+ static {{class_name}}* New(mojo::internal::Buffer* buf) {
+ return new (buf->Allocate(sizeof({{class_name}}))) {{class_name}}();
+ }
static bool Validate(const void* data,
mojo::internal::ValidationContext* validation_context);
-{% from "enum_macros.tmpl" import enum_data_decl -%}
-{#--- Enums #}
-{%- for enum in struct.enums -%}
-{%- if enum|is_native_only_kind %}
- using {{enum.name}}_Data = mojo::internal::NativeEnum_Data;
-{%- else %}
- {{enum_data_decl(enum)|indent(2)}}
-{%- endif %}
-{%- endfor %}
-
mojo::internal::StructHeader header_;
{%- for packed_field in struct.packed.packed_fields %}
{%- set name = packed_field.field.name %}
@@ -46,7 +38,8 @@ class {{class_name}} {
{%- endif %}
private:
- {{class_name}}();
+ {{class_name}}() : header_({sizeof(*this), {{struct.versions[-1].version}}}) {
+ }
~{{class_name}}() = delete;
};
static_assert(sizeof({{class_name}}) == {{struct.versions[-1].num_bytes}},
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl
index a2e5708..60dca40 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl
@@ -2,11 +2,6 @@
{%- set class_name = struct.name ~ "_Data" %}
// static
-{{class_name}}* {{class_name}}::New(mojo::internal::Buffer* buf) {
- return new (buf->Allocate(sizeof({{class_name}}))) {{class_name}}();
-}
-
-// static
bool {{class_name}}::Validate(
const void* data,
mojo::internal::ValidationContext* validation_context) {
@@ -20,7 +15,7 @@ bool {{class_name}}::Validate(
// the message comes from an older version.
const {{class_name}}* object = static_cast<const {{class_name}}*>(data);
- static const struct {
+ static constexpr struct {
uint32_t version;
uint32_t num_bytes;
} kVersionSizes[] = {
@@ -73,7 +68,3 @@ bool {{class_name}}::Validate(
return true;
}
-{{class_name}}::{{class_name}}() {
- header_.num_bytes = sizeof(*this);
- header_.version = {{struct.versions[-1].version}};
-}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
index c59f317..bb5fb9c 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
@@ -19,7 +19,8 @@
{%- macro get_serialized_size(struct, input_field_pattern, context,
input_may_be_temp=False) -%}
size_t size = sizeof({{struct|get_qualified_name_for_kind(internal=True)}});
-{%- for pf in struct.packed.packed_fields_in_ordinal_order if pf.field.kind|is_object_kind %}
+{%- for pf in struct.packed.packed_fields_in_ordinal_order
+ if pf.field.kind|is_object_kind or pf.field.kind|is_associated_kind %}
{%- set name = pf.field.name -%}
{%- set kind = pf.field.kind -%}
{%- set original_input_field = input_field_pattern|format(name) %}
@@ -148,8 +149,11 @@
{%- if kind|is_object_kind or kind|is_enum_kind %}
if (!{{input}}.Read{{name|under_to_camel}}(&{{output_field}}))
{{success}} = false;
-{%- elif kind|is_any_handle_or_interface_kind %}
+{%- elif kind|is_any_handle_kind %}
{{output_field}} = {{input}}.Take{{name|under_to_camel}}();
+{%- elif kind|is_any_interface_kind %}
+ {{output_field}} =
+ {{input}}.Take{{name|under_to_camel}}<decltype({{output_field}})>();
{%- else %}
{{output_field}} = {{input}}.{{name}}();
{%- endif %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
index aede1a7..835178b 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
@@ -1,37 +1,13 @@
{%- import "struct_macros.tmpl" as struct_macros %}
-{%- set mojom_type = struct|get_qualified_name_for_kind %}
+{%- set data_view = struct|get_qualified_name_for_kind ~ "DataView" %}
{%- set data_type = struct|get_qualified_name_for_kind(internal=True) %}
-template <>
-struct StructTraits<{{mojom_type}}, {{mojom_type}}Ptr> {
- static bool IsNull(const {{mojom_type}}Ptr& input) { return !input; }
- static void SetToNull({{mojom_type}}Ptr* output) { output->reset(); }
-
-{%- for field in struct.fields %}
-{%- set return_ref = field.kind|is_object_kind or
- field.kind|is_any_handle_or_interface_kind %}
-{%- if return_ref %}
- static decltype({{mojom_type}}::{{field.name}})& {{field.name}}(
- {{mojom_type}}Ptr& input) {
- return input->{{field.name}};
- }
-{%- else %}
- static decltype({{mojom_type}}::{{field.name}}) {{field.name}}(
- const {{mojom_type}}Ptr& input) {
- return input->{{field.name}};
- }
-{%- endif %}
-{%- endfor %}
-
- static bool Read({{mojom_type}}DataView input, {{mojom_type}}Ptr* output);
-};
-
namespace internal {
template <typename MaybeConstUserType>
-struct Serializer<{{mojom_type}}Ptr, MaybeConstUserType> {
+struct Serializer<{{data_view}}, MaybeConstUserType> {
using UserType = typename std::remove_const<MaybeConstUserType>::type;
- using Traits = StructTraits<{{mojom_type}}, UserType>;
+ using Traits = StructTraits<{{data_view}}, UserType>;
static size_t PrepareToSerialize(MaybeConstUserType& input,
SerializationContext* context) {
@@ -61,7 +37,7 @@ struct Serializer<{{mojom_type}}Ptr, MaybeConstUserType> {
{{struct_macros.serialize(
struct, struct.name ~ " struct",
"CallWithContext(Traits::%s, input, custom_context)", "result",
- "buffer", "context", True)|indent(4)}}
+ "buffer", "context", True)|indent(2)}}
*output = result;
CustomContextHelper<Traits>::TearDown(input, custom_context);
@@ -73,7 +49,7 @@ struct Serializer<{{mojom_type}}Ptr, MaybeConstUserType> {
if (!input)
return CallSetToNullIfExists<Traits>(output);
- {{mojom_type}}DataView data_view(input, context);
+ {{data_view}} data_view(input, context);
return Traits::Read(data_view, output);
}
};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_traits_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_traits_declaration.tmpl
new file mode 100644
index 0000000..1b7cf89
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_traits_declaration.tmpl
@@ -0,0 +1,32 @@
+{%- set mojom_type = struct|get_qualified_name_for_kind %}
+
+template <>
+struct {{export_attribute}} StructTraits<{{mojom_type}}::DataView,
+ {{mojom_type}}Ptr> {
+ static bool IsNull(const {{mojom_type}}Ptr& input) { return !input; }
+ static void SetToNull({{mojom_type}}Ptr* output) { output->reset(); }
+
+{%- for field in struct.fields %}
+{%- set return_ref = field.kind|is_object_kind or
+ field.kind|is_any_handle_or_interface_kind %}
+{# We want the field accessor to be const whenever possible to allow
+ structs to be used as map keys.
+ TODO(tibell): Make this check more precise to deal with e.g.
+ custom types which don't contain handles but require non-const
+ reference for serialization. #}
+{%- set maybe_const = "" if field.kind|contains_handles_or_interfaces else "const" %}
+{%- if return_ref %}
+ static {{maybe_const}} decltype({{mojom_type}}::{{field.name}})& {{field.name}}(
+ {{maybe_const}} {{mojom_type}}Ptr& input) {
+ return input->{{field.name}};
+ }
+{%- else %}
+ static decltype({{mojom_type}}::{{field.name}}) {{field.name}}(
+ const {{mojom_type}}Ptr& input) {
+ return input->{{field.name}};
+ }
+{%- endif %}
+{%- endfor %}
+
+ static bool Read({{mojom_type}}::DataView input, {{mojom_type}}Ptr* output);
+};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_traits_definition.tmpl
index 7421abc..f84337f 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_traits_definition.tmpl
@@ -2,8 +2,8 @@
{%- set mojom_type = struct|get_qualified_name_for_kind %}
// static
-bool StructTraits<{{mojom_type}}, {{mojom_type}}Ptr>::Read(
- {{mojom_type}}DataView input,
+bool StructTraits<{{mojom_type}}::DataView, {{mojom_type}}Ptr>::Read(
+ {{mojom_type}}::DataView input,
{{mojom_type}}Ptr* output) {
bool success = true;
{{mojom_type}}Ptr result({{mojom_type}}::New());
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_data_view_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_data_view_declaration.tmpl
new file mode 100644
index 0000000..2a9e02d
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_data_view_declaration.tmpl
@@ -0,0 +1,91 @@
+class {{union.name}}DataView {
+ public:
+ using Tag = internal::{{union.name}}_Data::{{union.name}}_Tag;
+
+ {{union.name}}DataView() {}
+
+ {{union.name}}DataView(
+ internal::{{union.name}}_Data* data,
+ mojo::internal::SerializationContext* context)
+{%- if union|requires_context_for_data_view %}
+ : data_(data), context_(context) {}
+{%- else %}
+ : data_(data) {}
+{%- endif %}
+
+ bool is_null() const {
+ // For inlined unions, |data_| is always non-null. In that case we need to
+ // check |data_->is_null()|.
+ return !data_ || data_->is_null();
+ }
+
+ Tag tag() const { return data_->tag; }
+
+{%- for field in union.fields %}
+{%- set kind = field.kind %}
+{%- set name = field.name %}
+ bool is_{{name}}() const { return data_->tag == Tag::{{name|upper}}; }
+
+{%- if kind|is_object_kind %}
+ inline void Get{{name|under_to_camel}}DataView(
+ {{kind|cpp_data_view_type}}* output);
+
+ template <typename UserType>
+ WARN_UNUSED_RESULT bool Read{{name|under_to_camel}}(UserType* output) {
+ DCHECK(is_{{name}}());
+ return mojo::internal::Deserialize<{{kind|unmapped_type_for_serializer}}>(
+ data_->data.f_{{name}}.Get(), output, context_);
+ }
+
+{%- elif kind|is_enum_kind %}
+ template <typename UserType>
+ WARN_UNUSED_RESULT bool Read{{name|under_to_camel}}(UserType* output) const {
+ DCHECK(is_{{name}}());
+ return mojo::internal::Deserialize<{{kind|unmapped_type_for_serializer}}>(
+ data_->data.f_{{name}}, output);
+ }
+
+ {{kind|cpp_data_view_type}} {{name}}() const {
+ DCHECK(is_{{name}}());
+ return static_cast<{{kind|cpp_data_view_type}}>(
+ data_->data.f_{{name}});
+ }
+
+{%- elif kind|is_any_handle_kind %}
+ {{kind|cpp_data_view_type}} Take{{name|under_to_camel}}() {
+ DCHECK(is_{{name}}());
+ {{kind|cpp_data_view_type}} result;
+ bool ret =
+ mojo::internal::Deserialize<{{kind|unmapped_type_for_serializer}}>(
+ &data_->data.f_{{name}}, &result, context_);
+ DCHECK(ret);
+ return result;
+ }
+
+{%- elif kind|is_any_interface_kind %}
+ template <typename UserType>
+ UserType Take{{name|under_to_camel}}() {
+ DCHECK(is_{{name}}());
+ UserType result;
+ bool ret =
+ mojo::internal::Deserialize<{{kind|unmapped_type_for_serializer}}>(
+ &data_->data.f_{{name}}, &result, context_);
+ DCHECK(ret);
+ return result;
+ }
+
+{%- else %}
+ {{kind|cpp_data_view_type}} {{name}}() const {
+ DCHECK(is_{{name}}());
+ return data_->data.f_{{name}};
+ }
+
+{%- endif %}
+{%- endfor %}
+
+ private:
+ internal::{{union.name}}_Data* data_ = nullptr;
+{%- if union|requires_context_for_data_view %}
+ mojo::internal::SerializationContext* context_ = nullptr;
+{%- endif %}
+};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_data_view_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_data_view_definition.tmpl
new file mode 100644
index 0000000..6da9280
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_data_view_definition.tmpl
@@ -0,0 +1,12 @@
+{%- for field in union.fields %}
+{%- set kind = field.kind %}
+{%- set name = field.name %}
+
+{%- if kind|is_object_kind %}
+inline void {{union.name}}DataView::Get{{name|under_to_camel}}DataView(
+ {{kind|cpp_data_view_type}}* output) {
+ DCHECK(is_{{name}}());
+ *output = {{kind|cpp_data_view_type}}(data_->data.f_{{name}}.Get(), context_);
+}
+{%- endif %}
+{%- endfor %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl
index be2db4c..005ba76 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl
@@ -6,20 +6,27 @@ class {{class_name}} {
public:
// Used to identify Mojom Union Data Classes.
typedef void MojomUnionDataType;
- static {{class_name}}* New(mojo::internal::Buffer* buf);
- {{class_name}}();
- // Do nothing in the destructor since it won't be called.
+
+ {{class_name}}() {}
+ // Do nothing in the destructor since it won't be called when it is a
+ // non-inlined union.
~{{class_name}}() {}
+ static {{class_name}}* New(mojo::internal::Buffer* buf) {
+ return new (buf->Allocate(sizeof({{class_name}}))) {{class_name}}();
+ }
+
static bool Validate(const void* data,
mojo::internal::ValidationContext* validation_context,
bool inlined);
- bool is_null() const {
- return size == 0;
- }
+ bool is_null() const { return size == 0; }
- void set_null();
+ void set_null() {
+ size = 0U;
+ tag = static_cast<{{enum_name}}>(0);
+ data.unknown = 0U;
+ }
enum class {{enum_name}} : uint32_t {
{% for field in union.fields %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl
index fc6eddf..af5ea9f 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl
@@ -3,24 +3,31 @@
{%- set enum_name = union.name ~ "_Tag" -%}
// static
-{{class_name}}* {{class_name}}::New(mojo::internal::Buffer* buf) {
- return new (buf->Allocate(sizeof({{class_name}}))) {{class_name}}();
-}
-
-// static
bool {{class_name}}::Validate(
const void* data,
mojo::internal::ValidationContext* validation_context,
bool inlined) {
- if (!data)
+ if (!data) {
+ DCHECK(!inlined);
return true;
+ }
- if (!ValidateUnionHeaderAndClaimMemory(data, inlined, validation_context))
+ // If it is inlined, the alignment is already enforced by its enclosing
+ // object. We don't have to validate that.
+ DCHECK(!inlined || mojo::internal::IsAligned(data));
+
+ if (!inlined &&
+ !mojo::internal::ValidateNonInlinedUnionHeaderAndClaimMemory(
+ data, validation_context)) {
return false;
+ }
const {{class_name}}* object = static_cast<const {{class_name}}*>(data);
ALLOW_UNUSED_LOCAL(object);
+ if (inlined && object->is_null())
+ return true;
+
switch (object->tag) {
{% for field in union.fields %}
case {{enum_name}}::{{field.name|upper}}: {
@@ -38,13 +45,3 @@ bool {{class_name}}::Validate(
}
}
}
-
-void {{class_name}}::set_null() {
- size = 0U;
- tag = static_cast<{{enum_name}}>(0);
- data.unknown = 0U;
-}
-
-{{class_name}}::{{class_name}}() {
-}
-
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl
index bab9045..b589ae9 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl
@@ -1,37 +1,141 @@
-{%- set mojom_type = union|get_qualified_name_for_kind %}
+{%- set data_view = union|get_qualified_name_for_kind ~ "DataView" %}
{%- set data_type = union|get_qualified_name_for_kind(internal=True) %}
namespace internal {
-template <typename MojomType>
-struct UnionSerializerImpl;
+template <typename MaybeConstUserType>
+struct Serializer<{{data_view}}, MaybeConstUserType> {
+ using UserType = typename std::remove_const<MaybeConstUserType>::type;
+ using Traits = UnionTraits<{{data_view}}, UserType>;
-template <>
-struct UnionSerializerImpl<{{mojom_type}}Ptr> {
- static size_t PrepareToSerialize({{mojom_type}}Ptr& input,
+ static size_t PrepareToSerialize(MaybeConstUserType& input,
bool inlined,
- SerializationContext* context);
+ SerializationContext* context) {
+ size_t size = inlined ? 0 : sizeof({{data_type}});
+
+ if (CallIsNullIfExists<Traits>(input))
+ return size;
+
+ void* custom_context = CustomContextHelper<Traits>::SetUp(input, context);
+ ALLOW_UNUSED_LOCAL(custom_context);
- static void Serialize({{mojom_type}}Ptr& input,
+ switch (CallWithContext(Traits::GetTag, input, custom_context)) {
+{%- for field in union.fields %}
+{%- set name = field.name %}
+ case {{data_view}}::Tag::{{name|upper}}: {
+{%- if field.kind|is_object_kind or field.kind|is_associated_kind %}
+{%- set kind = field.kind %}
+{%- set serializer_type = kind|unmapped_type_for_serializer %}
+ decltype(CallWithContext(Traits::{{name}}, input, custom_context))
+ in_{{name}} = CallWithContext(Traits::{{name}}, input,
+ custom_context);
+{%- if kind|is_union_kind %}
+ size += mojo::internal::PrepareToSerialize<{{serializer_type}}>(
+ in_{{name}}, false, context);
+{%- else %}
+ size += mojo::internal::PrepareToSerialize<{{serializer_type}}>(
+ in_{{name}}, context);
+{%- endif %}
+{%- endif %}
+ break;
+ }
+{%- endfor %}
+ }
+ return size;
+ }
+
+ static void Serialize(MaybeConstUserType& input,
Buffer* buffer,
{{data_type}}** output,
bool inlined,
- SerializationContext* context);
+ SerializationContext* context) {
+ if (CallIsNullIfExists<Traits>(input)) {
+ if (inlined)
+ (*output)->set_null();
+ else
+ *output = nullptr;
+ return;
+ }
- static bool Deserialize({{data_type}}* input,
- {{mojom_type}}Ptr* output,
- SerializationContext* context);
-};
+ void* custom_context = CustomContextHelper<Traits>::GetNext(context);
-template <typename MaybeConstUserType>
-struct Serializer<{{mojom_type}}Ptr, MaybeConstUserType>
- : public UnionSerializerImpl<{{mojom_type}}Ptr> {
- using UserType = typename std::remove_const<MaybeConstUserType>::type;
+ if (!inlined)
+ *output = {{data_type}}::New(buffer);
+
+ {{data_type}}* result = *output;
+ ALLOW_UNUSED_LOCAL(result);
+ // TODO(azani): Handle unknown and objects.
+ // Set the not-null flag.
+ result->size = kUnionDataSize;
+ result->tag = CallWithContext(Traits::GetTag, input, custom_context);
+ switch (result->tag) {
+{%- for field in union.fields %}
+{%- set name = field.name %}
+{%- set kind = field.kind %}
+{%- set serializer_type = kind|unmapped_type_for_serializer %}
+ case {{data_view}}::Tag::{{field.name|upper}}: {
+ decltype(CallWithContext(Traits::{{name}}, input, custom_context))
+ in_{{name}} = CallWithContext(Traits::{{name}}, input,
+ custom_context);
+{%- if kind|is_object_kind %}
+ typename decltype(result->data.f_{{name}})::BaseType* ptr;
+{%- if kind|is_union_kind %}
+ mojo::internal::Serialize<{{serializer_type}}>(
+ in_{{name}}, buffer, &ptr, false, context);
+{%- elif kind|is_array_kind or kind|is_map_kind %}
+ const ContainerValidateParams {{name}}_validate_params(
+ {{kind|get_container_validate_params_ctor_args|indent(16)}});
+ mojo::internal::Serialize<{{serializer_type}}>(
+ in_{{name}}, buffer, &ptr, &{{name}}_validate_params, context);
+{%- else %}
+ mojo::internal::Serialize<{{serializer_type}}>(
+ in_{{name}}, buffer, &ptr, context);
+{%- endif %}
+ result->data.f_{{name}}.Set(ptr);
+{%- if not kind|is_nullable_kind %}
+ MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
+ !ptr, mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
+ "null {{name}} in {{union.name}} union");
+{%- endif %}
+
+{%- elif kind|is_any_handle_or_interface_kind %}
+ mojo::internal::Serialize<{{serializer_type}}>(
+ in_{{name}}, &result->data.f_{{name}}, context);
+{%- if not kind|is_nullable_kind %}
+ MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
+ !mojo::internal::IsHandleOrInterfaceValid(result->data.f_{{name}}),
+{%- if kind|is_associated_kind %}
+ mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID,
+{%- else %}
+ mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
+{%- endif %}
+ "invalid {{name}} in {{union.name}} union");
+{%- endif %}
+
+{%- elif kind|is_enum_kind %}
+ mojo::internal::Serialize<{{serializer_type}}>(
+ in_{{name}}, &result->data.f_{{name}});
+
+{%- else %}
+ result->data.f_{{name}} = in_{{name}};
+{%- endif %}
+ break;
+ }
+{%- endfor %}
+ }
+
+ CustomContextHelper<Traits>::TearDown(input, custom_context);
+ }
+
+ static bool Deserialize({{data_type}}* input,
+ UserType* output,
+ SerializationContext* context) {
+ if (!input || input->is_null())
+ return CallSetToNullIfExists<Traits>(output);
- static_assert(std::is_same<MaybeConstUserType, UserType>::value,
- "Only support serialization of non-const Unions.");
- static_assert(std::is_same<UserType, {{mojom_type}}Ptr>::value,
- "Custom mapping of mojom union is not supported.");
+ {{data_view}} data_view(input, context);
+ return Traits::Read(data_view, output);
+ }
};
} // namespace internal
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl
deleted file mode 100644
index 5a11ff7..0000000
--- a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl
+++ /dev/null
@@ -1,164 +0,0 @@
-{%- set mojom_type = union|get_qualified_name_for_kind %}
-{%- set data_type = union|get_qualified_name_for_kind(internal=True) %}
-
-namespace internal {
-
-// static
-size_t UnionSerializerImpl<{{mojom_type}}Ptr>::PrepareToSerialize(
- {{mojom_type}}Ptr& input,
- bool inlined,
- SerializationContext* context) {
- size_t size = inlined ? 0 : sizeof({{data_type}});
-
- if (!input)
- return size;
-
- UnionAccessor<{{mojom_type}}> input_acc(input.get());
- switch (input->which()) {
-{% for field in union.fields %}
-{% if field.kind|is_object_kind %}
-{%- set serializer_type = field.kind|unmapped_type_for_serializer %}
- case {{mojom_type}}::Tag::{{field.name|upper}}:
-{% if field.kind|is_union_kind %}
- size += mojo::internal::PrepareToSerialize<{{serializer_type}}>(
- *(input_acc.data()->{{field.name}}), false, context);
-{% else %}
- size += mojo::internal::PrepareToSerialize<{{serializer_type}}>(
- *(input_acc.data()->{{field.name}}), context);
-{% endif %}
- break;
-{%- endif %}
-{%- endfor %}
- default:
- break;
- }
- return size;
-}
-
-// static
-void UnionSerializerImpl<{{mojom_type}}Ptr>::Serialize(
- {{mojom_type}}Ptr& input,
- Buffer* buf,
- {{data_type}}** output,
- bool inlined,
- SerializationContext* context) {
- {{data_type}}* result = *output;
- if (input) {
- if (!inlined)
- result = {{data_type}}::New(buf);
- UnionAccessor<{{mojom_type}}> input_acc(input.get());
- // TODO(azani): Handle unknown and objects.
- // Set the not-null flag.
- result->size = 16;
- result->tag = input->which();
- switch (input->which()) {
-{%- for field in union.fields %}
- case {{mojom_type}}::Tag::{{field.name|upper}}: {
-{%- set serializer_type = field.kind|unmapped_type_for_serializer %}
-{%- if field.kind|is_object_kind %}
- typename decltype(result->data.f_{{field.name}})::BaseType* ptr;
-{%- if field.kind|is_union_kind %}
- mojo::internal::Serialize<{{serializer_type}}>(
- *(input_acc.data()->{{field.name}}), buf, &ptr, false, context);
-{%- elif field.kind|is_array_kind or field.kind|is_map_kind %}
- const ContainerValidateParams {{field.name}}_validate_params(
- {{field.kind|get_container_validate_params_ctor_args|indent(16)}});
- mojo::internal::Serialize<{{serializer_type}}>(
- *(input_acc.data()->{{field.name}}), buf, &ptr,
- &{{field.name}}_validate_params, context);
-{%- else %}
- mojo::internal::Serialize<{{serializer_type}}>(
- *(input_acc.data()->{{field.name}}), buf, &ptr, context);
-{%- endif %}
- result->data.f_{{field.name}}.Set(ptr);
-{%- if not field.kind|is_nullable_kind %}
- MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
- !ptr, mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
- "null {{field.name}} in {{union.name}} union");
-{%- endif %}
-
-{%- elif field.kind|is_any_handle_or_interface_kind %}
- mojo::internal::Serialize<{{serializer_type}}>(
- *input_acc.data()->{{field.name}}, &result->data.f_{{field.name}},
- context);
-{%- if not field.kind|is_nullable_kind %}
- MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
- !mojo::internal::IsHandleOrInterfaceValid(result->data.f_{{field.name}}),
-{%- if field.kind|is_associated_kind %}
- mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID,
-{%- else %}
- mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
-{%- endif %}
- "invalid {{field.name}} in {{union.name}} union");
-{%- endif %}
-
-{%- elif field.kind|is_enum_kind %}
- mojo::internal::Serialize<{{serializer_type}}>(
- input_acc.data()->{{field.name}}, &result->data.f_{{field.name}});
-
-{%- else %}
- result->data.f_{{field.name}} = input_acc.data()->{{field.name}};
-{%- endif %}
- break;
- }
-{%- endfor %}
- }
- } else if (inlined) {
- result->set_null();
- } else {
- result = nullptr;
- }
- *output = result;
-}
-
-// static
-bool UnionSerializerImpl<{{mojom_type}}Ptr>::Deserialize(
- {{data_type}}* input,
- {{mojom_type}}Ptr* output,
- SerializationContext* context) {
- bool success = true;
- if (input && !input->is_null()) {
- {{mojom_type}}Ptr result({{mojom_type}}::New());
- UnionAccessor<{{mojom_type}}> result_acc(result.get());
- switch (input->tag) {
-{%- for field in union.fields %}
- case {{mojom_type}}::Tag::{{field.name|upper}}: {
-{%- set serializer_type = field.kind|unmapped_type_for_serializer %}
-{%- if field.kind|is_object_kind %}
- result_acc.SwitchActive({{mojom_type}}::Tag::{{field.name|upper}});
- if (!mojo::internal::Deserialize<{{serializer_type}}>(
- input->data.f_{{field.name}}.Get(),
- result_acc.data()->{{field.name}}, context))
- success = false;
-
-{%- elif field.kind|is_any_handle_or_interface_kind %}
- typename std::remove_reference<
- decltype(result->get_{{field.name}}())>::type result_{{field.name}};
- bool ret = mojo::internal::Deserialize<{{serializer_type}}>(
- &input->data.f_{{field.name}}, &result_{{field.name}}, context);
- DCHECK(ret);
- result->set_{{field.name}}(std::move(result_{{field.name}}));
-
-{%- elif field.kind|is_enum_kind %}
- decltype(result->get_{{field.name}}()) result_{{field.name}};
- if (!mojo::internal::Deserialize<{{serializer_type}}>(
- input->data.f_{{field.name}}, &result_{{field.name}}))
- success = false;
- else
- result->set_{{field.name}}(result_{{field.name}});
-
-{%- else %}
- result->set_{{field.name}}(input->data.f_{{field.name}});
-{%- endif %}
- break;
- }
-{%- endfor %}
- }
- *output = std::move(result);
- } else {
- output->reset();
- }
- return success;
-}
-
-} // namespace internal
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_traits_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_traits_declaration.tmpl
new file mode 100644
index 0000000..4933e57
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_traits_declaration.tmpl
@@ -0,0 +1,24 @@
+{%- set mojom_type = union|get_qualified_name_for_kind %}
+
+template <>
+struct {{export_attribute}} UnionTraits<{{mojom_type}}::DataView,
+ {{mojom_type}}Ptr> {
+ static bool IsNull(const {{mojom_type}}Ptr& input) { return !input; }
+ static void SetToNull({{mojom_type}}Ptr* output) { output->reset(); }
+
+ static {{mojom_type}}::Tag GetTag(const {{mojom_type}}Ptr& input) {
+ return input->which();
+ }
+
+{%- for field in union.fields %}
+{%- set maybe_const_in = "" if field.kind|contains_handles_or_interfaces else "const" %}
+{%- set maybe_const_out = "" if field.kind|contains_handles_or_interfaces or not field.kind|is_reference_kind else "const" %}
+{# We want the field accessor to be const whenever possible to allow
+ structs to be used as map keys. #}
+ static {{maybe_const_out}} {{field.kind|cpp_union_trait_getter_return_type}} {{field.name}}({{maybe_const_in}} {{mojom_type}}Ptr& input) {
+ return input->get_{{field.name}}();
+ }
+{%- endfor %}
+
+ static bool Read({{mojom_type}}::DataView input, {{mojom_type}}Ptr* output);
+};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_traits_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_traits_definition.tmpl
new file mode 100644
index 0000000..cde3f95
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_traits_definition.tmpl
@@ -0,0 +1,47 @@
+{%- set mojom_type = union|get_qualified_name_for_kind %}
+
+// static
+bool UnionTraits<{{mojom_type}}::DataView, {{mojom_type}}Ptr>::Read(
+ {{mojom_type}}::DataView input,
+ {{mojom_type}}Ptr* output) {
+ *output = {{mojom_type}}::New();
+ {{mojom_type}}Ptr& result = *output;
+
+ internal::UnionAccessor<{{mojom_type}}> result_acc(result.get());
+ switch (input.tag()) {
+{%- for field in union.fields %}
+ case {{mojom_type}}::Tag::{{field.name|upper}}: {
+{%- set name = field.name %}
+{%- set kind = field.kind %}
+{%- set serializer_type = kind|unmapped_type_for_serializer %}
+{%- if kind|is_object_kind %}
+ result_acc.SwitchActive({{mojom_type}}::Tag::{{name|upper}});
+ if (!input.Read{{name|under_to_camel}}(result_acc.data()->{{name}}))
+ return false;
+
+{%- elif kind|is_any_handle_kind %}
+ auto result_{{name}} = input.Take{{name|under_to_camel}}();
+ result->set_{{name}}(std::move(result_{{name}}));
+
+{%- elif kind|is_any_interface_kind %}
+ auto result_{{name}} =
+ input.Take{{name|under_to_camel}}<typename std::remove_reference<decltype(result->get_{{name}}())>::type>();
+ result->set_{{name}}(std::move(result_{{name}}));
+
+{%- elif kind|is_enum_kind %}
+ decltype(result->get_{{name}}()) result_{{name}};
+ if (!input.Read{{name|under_to_camel}}(&result_{{name}}))
+ return false;
+ result->set_{{name}}(result_{{name}});
+
+{%- else %}
+ result->set_{{name}}(input.{{name}}());
+{%- endif %}
+ break;
+ }
+{%- endfor %}
+ default:
+ return false;
+ }
+ return true;
+}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/validation_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/validation_macros.tmpl
index 367be6d..a50a585 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/validation_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/validation_macros.tmpl
@@ -66,7 +66,7 @@
{#- Validates the specified field, which is supposed to be an enum.
This macro is expanded by the Validate() method. #}
{%- macro validate_enum(field, field_expr) %}
- if (!{{field.kind|get_qualified_name_for_kind(internal=True)}}
+ if (!{{field.kind|get_qualified_name_for_kind(internal=True,flatten_nested_kind=True)}}
::Validate({{field_expr}}, validation_context))
return false;
{%- endmacro %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
index 98ae23c..9e6e46f 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
@@ -1,29 +1,24 @@
-{% from "enum_macros.tmpl" import enum_decl -%}
-
-class {{struct.name}} {
+class {{export_attribute}} {{struct.name}} {
public:
using DataView = {{struct.name}}DataView;
using Data_ = internal::{{struct.name}}_Data;
{#--- Enums #}
{%- for enum in struct.enums -%}
-{%- if enum|is_native_only_kind %}
- using {{enum.name}} = mojo::NativeEnum;
-{%- else %}
- {{enum_decl(enum)|indent(2)}}
-{%- endif %}
+ using {{enum.name}} = {{enum|get_name_for_kind(flatten_nested_kind=True)}};
{%- endfor %}
{#--- Constants #}
{%- for constant in struct.constants %}
-{%- if constant.kind|is_integral_kind %}
- static const {{constant.kind|cpp_pod_type}} {{constant.name}} = {{constant|constant_value}};
-{%- else %}
- static const {{constant.kind|cpp_pod_type}} {{constant.name}};
-{%- endif %}
+ static {{constant|format_constant_declaration(nested=True)}};
{%- endfor %}
- static {{struct.name}}Ptr New();
+ template <typename... Args>
+ static {{struct.name}}Ptr New(Args&&... args) {
+ return {{struct.name}}Ptr(
+ base::in_place,
+ std::forward<Args>(args)...);
+ }
template <typename U>
static {{struct.name}}Ptr From(const U& u) {
@@ -35,7 +30,15 @@ class {{struct.name}} {
return mojo::TypeConverter<U, {{struct.name}}>::Convert(*this);
}
- {{struct.name}}();
+{% for constructor in struct|struct_constructors %}
+ {% if constructor.params|length == 1 %}explicit {% endif %}{{struct.name}}(
+{%- for field in constructor.params %}
+{%- set type = field.kind|cpp_wrapper_param_type %}
+{%- set name = field.name %}
+ {{type}} {{name}}
+{%- if not loop.last -%},{%- endif %}
+{%- endfor %});
+{% endfor %}
~{{struct.name}}();
// Clone() is a template so it is only instantiated if it is used. Thus, the
@@ -52,20 +55,24 @@ class {{struct.name}} {
T, {{struct.name}}>::value>::type* = nullptr>
bool Equals(const T& other) const;
-{%- set serialization_result_type = "mojo::WTFArray<uint8_t>"
- if for_blink else "mojo::Array<uint8_t>" %}
+{%- if struct|is_hashable %}
+ size_t Hash(size_t seed) const;
+{%- endif %}
+
+{%- set serialization_result_type = "WTF::Vector<uint8_t>"
+ if for_blink else "std::vector<uint8_t>" %}
template <typename UserType>
static {{serialization_result_type}} Serialize(UserType* input) {
return mojo::internal::StructSerializeImpl<
- {{struct.name}}Ptr, {{serialization_result_type}}>(input);
+ {{struct.name}}::DataView, {{serialization_result_type}}>(input);
}
template <typename UserType>
static bool Deserialize(const {{serialization_result_type}}& input,
UserType* output) {
return mojo::internal::StructDeserializeImpl<
- {{struct.name}}Ptr, {{serialization_result_type}}>(
+ {{struct.name}}::DataView, {{serialization_result_type}}>(
input, output);
}
@@ -75,5 +82,10 @@ class {{struct.name}} {
{%- set name = field.name %}
{{type}} {{name}};
{%- endfor %}
+
+{%- if struct|contains_move_only_members %}
+ private:
+ DISALLOW_COPY_AND_ASSIGN({{struct.name}});
+{%- endif %}
};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl
index 0bb1cda..e75543f 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl
@@ -1,15 +1,33 @@
-// static
-{{struct.name}}Ptr {{struct.name}}::New() {
- {{struct.name}}Ptr rv;
- mojo::internal::StructHelper<{{struct.name}}>::Initialize(&rv);
- return rv;
-}
-
-{{struct.name}}::{{struct.name}}()
-{%- for field in struct.fields %}
- {% if loop.first %}:{% else %} {% endif %} {{field.name}}({{field|default_value}}){% if not loop.last %},{% endif %}
-{%- endfor %} {
-}
+{% for constructor in struct|struct_constructors %}
+{{struct.name}}::{{struct.name}}(
+{%- for field in constructor.params %}
+{%- set type = field.kind|cpp_wrapper_param_type %}
+{%- set name = field.name %}
+ {{type}} {{name}}_in
+{%- if not loop.last -%},{%- endif %}
+{%- endfor %})
+{%- for field, is_parameter in constructor.fields %}
+{%- set name = field.name %}
+ {% if loop.first %}:{% else %} {% endif %} {{name}}(
+{%- if is_parameter -%}
+std::move({{name}}_in)
+{%- else -%}
+{{ field|default_value }}
+{%- endif -%}
+){% if not loop.last %},{% endif %}
+{%- endfor %} {}
+{% endfor %}
+{{struct.name}}::~{{struct.name}}() = default;
-{{struct.name}}::~{{struct.name}}() {
+{%- if struct|is_hashable %}
+size_t {{struct.name}}::Hash(size_t seed) const {
+{%- for field in struct.fields %}
+{%- if for_blink %}
+ seed = mojo::internal::WTFHash(seed, this->{{field.name}});
+{%- else %}
+ seed = mojo::internal::Hash(seed, this->{{field.name}});
+{%- endif %}
+{%- endfor %}
+ return seed;
}
+{%- endif %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl
index f4aa314..feb8615 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl
@@ -1,12 +1,11 @@
template <typename StructPtrType>
{{struct.name}}Ptr {{struct.name}}::Clone() const {
- // Use StructPtrType to prevent the compiler from trying to compile this
- // without being asked.
- StructPtrType rv(New());
+ return New(
{%- for field in struct.fields %}
- rv->{{field.name}} = mojo::internal::Clone({{field.name}});
+ mojo::Clone({{field.name}})
+{%- if not loop.last -%},{%- endif %}
{%- endfor %}
- return rv;
+ );
}
template <typename T,
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl
index f62bc72..8b7cf9e 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl
@@ -1,5 +1,6 @@
-class {{union.name}} {
+class {{export_attribute}} {{union.name}} {
public:
+ using DataView = {{union.name}}DataView;
using Data_ = internal::{{union.name}}_Data;
using Tag = Data_::{{union.name}}_Tag;
@@ -32,13 +33,27 @@ class {{union.name}} {
T, {{union.name}}>::value>::type* = nullptr>
bool Equals(const T& other) const;
+{%- if union|is_hashable %}
+ size_t Hash(size_t seed) const;
+{%- endif %}
+
Tag which() const {
return tag_;
}
{% for field in union.fields %}
- bool is_{{field.name}}() const;
- {{field.kind|cpp_union_getter_return_type}} get_{{field.name}}() const;
+ bool is_{{field.name}}() const { return tag_ == Tag::{{field.name|upper}}; }
+
+ {{field.kind|cpp_union_getter_return_type}} get_{{field.name}}() const {
+ DCHECK(tag_ == Tag::{{field.name|upper}});
+{%- if field.kind|is_object_kind or
+ field.kind|is_any_handle_or_interface_kind %}
+ return *(data_.{{field.name}});
+{%- else %}
+ return data_.{{field.name}};
+{%- endif %}
+ }
+
void set_{{field.name}}({{field.kind|cpp_wrapper_param_type}} {{field.name}});
{%- endfor %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl
index 85cc4e6..b9e416a 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl
@@ -1,8 +1,6 @@
// static
{{union.name}}Ptr {{union.name}}::New() {
- {{union.name}}Ptr rv;
- mojo::internal::StructHelper<{{union.name}}>::Initialize(&rv);
- return rv;
+ return {{union.name}}Ptr(base::in_place);
}
{{union.name}}::{{union.name}}() {
@@ -16,20 +14,6 @@
}
{% for field in union.fields %}
-bool {{union.name}}::is_{{field.name}}() const {
- return tag_ == Tag::{{field.name|upper}};
-}
-
-{{field.kind|cpp_union_getter_return_type}} {{union.name}}::get_{{field.name}}() const {
- DCHECK(tag_ == Tag::{{field.name|upper}});
-{% if field.kind|is_object_kind or
- field.kind|is_any_handle_or_interface_kind %}
- return *(data_.{{field.name}});
-{%- else %}
- return data_.{{field.name}};
-{%- endif %}
-}
-
void {{union.name}}::set_{{field.name}}({{field.kind|cpp_wrapper_param_type}} {{field.name}}) {
SwitchActive(Tag::{{field.name|upper}});
{% if field.kind|is_string_kind %}
@@ -79,3 +63,23 @@ void {{union.name}}::DestroyActive() {
{%- endfor %}
}
}
+
+{%- if union|is_hashable %}
+size_t {{union.name}}::Hash(size_t seed) const {
+ seed = mojo::internal::HashCombine(seed, static_cast<uint32_t>(tag_));
+ switch (tag_) {
+{% for field in union.fields %}
+ case Tag::{{field.name|upper}}:
+{%- if for_blink %}
+ return mojo::internal::WTFHash(seed, data_.{{field.name}});
+{%- else %}
+ return mojo::internal::Hash(seed, data_.{{field.name}});
+{%- endif %}
+{%- endfor %}
+ default:
+ NOTREACHED();
+ return seed;
+ }
+}
+
+{%- endif %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_template_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_template_definition.tmpl
index d3371d9..4c4851f 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_template_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_template_definition.tmpl
@@ -8,9 +8,9 @@ template <typename UnionPtrType>
case Tag::{{field.name|upper}}:
{%- if field.kind|is_object_kind or
field.kind|is_any_handle_or_interface_kind %}
- rv->set_{{field.name}}(mojo::internal::Clone(*data_.{{field.name}}));
+ rv->set_{{field.name}}(mojo::Clone(*data_.{{field.name}}));
{%- else %}
- rv->set_{{field.name}}(mojo::internal::Clone(data_.{{field.name}}));
+ rv->set_{{field.name}}(mojo::Clone(data_.{{field.name}}));
{%- endif %}
break;
{%- endfor %}
diff --git a/mojo/public/tools/bindings/generators/java_templates/data_types_definition.tmpl b/mojo/public/tools/bindings/generators/java_templates/data_types_definition.tmpl
index 5cf9a68..4c0823c 100644
--- a/mojo/public/tools/bindings/generators/java_templates/data_types_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/java_templates/data_types_definition.tmpl
@@ -1,19 +1,19 @@
-{% from "constant_definition.tmpl" import constant_def %}
-{% from "enum_definition.tmpl" import enum_def %}
+{%- from "constant_definition.tmpl" import constant_def %}
+{%- from "enum_definition.tmpl" import enum_def %}
{%- macro equality(kind, v1, v2, ne=False) -%}
{%- if kind|is_reference_kind -%}
{%- if kind|is_array_kind -%}
{%- if kind.kind|is_reference_kind -%}
-{% if ne %}!{% endif %}java.util.Arrays.deepEquals({{v1}}, {{v2}})
+{%- if ne %}!{%- endif %}java.util.Arrays.deepEquals({{v1}}, {{v2}})
{%- else -%}
-{% if ne %}!{% endif %}java.util.Arrays.equals({{v1}}, {{v2}})
+{%- if ne %}!{%- endif %}java.util.Arrays.equals({{v1}}, {{v2}})
{%- endif -%}
{%- else -%}
-{% if ne %}!{% endif %}org.chromium.mojo.bindings.BindingsHelper.equals({{v1}}, {{v2}})
+{%- if ne %}!{%- endif %}org.chromium.mojo.bindings.BindingsHelper.equals({{v1}}, {{v2}})
{%- endif -%}
{%- else -%}
-{{v1}} {% if ne %}!={% else %}=={% endif %} {{v2}}
+{{v1}} {%- if ne %}!={%- else %}=={%- endif %} {{v2}}
{%- endif -%}
{%- endmacro -%}
@@ -37,27 +37,27 @@ org.chromium.mojo.bindings.BindingsHelper.POINTER_SIZE
{%- endif -%}
{%- endmacro -%}
-{% macro encode(variable, kind, offset, bit, level=0, check_for_null=True) %}
-{% if kind|is_pointer_array_kind or kind|is_union_array_kind %}
-{% set sub_kind = kind.kind %}
-{% if check_for_null %}
+{%- macro encode(variable, kind, offset, bit, level=0, check_for_null=True) %}
+{%- if kind|is_pointer_array_kind or kind|is_union_array_kind %}
+{%- set sub_kind = kind.kind %}
+{%- if check_for_null %}
if ({{variable}} == null) {
encoder{{level}}.encodeNullPointer({{offset}}, {{kind|is_nullable_kind|java_true_false}});
} else {
-{% else %}
+{%- else %}
{
-{% endif %}
-{% if kind|is_pointer_array_kind %}
-{% set encodePointer = 'encodePointerArray' %}
-{% else %}
-{% set encodePointer = 'encodeUnionArray' %}
-{% endif %}
+{%- endif %}
+{%- if kind|is_pointer_array_kind %}
+{%- set encodePointer = 'encodePointerArray' %}
+{%- else %}
+{%- set encodePointer = 'encodeUnionArray' %}
+{%- endif %}
org.chromium.mojo.bindings.Encoder encoder{{level + 1}} = encoder{{level}}.{{encodePointer}}({{variable}}.length, {{offset}}, {{kind|array_expected_length}});
for (int i{{level}} = 0; i{{level}} < {{variable}}.length; ++i{{level}}) {
{{encode(variable~'[i'~level~']', sub_kind, 'org.chromium.mojo.bindings.DataHeader.HEADER_SIZE + ' ~ array_element_size(sub_kind) ~ ' * i'~level, 0, level+1)|indent(8)}}
}
}
-{% elif kind|is_map_kind %}
+{%- elif kind|is_map_kind %}
if ({{variable}} == null) {
encoder{{level}}.encodeNullPointer({{offset}}, {{kind|is_nullable_kind|java_true_false}});
} else {
@@ -74,28 +74,28 @@ if ({{variable}} == null) {
{{encode('keys'~level, kind.key_kind|array, 'org.chromium.mojo.bindings.DataHeader.HEADER_SIZE', 0, level+1, False)|indent(4)}}
{{encode('values'~level, kind.value_kind|array, 'org.chromium.mojo.bindings.DataHeader.HEADER_SIZE + org.chromium.mojo.bindings.BindingsHelper.POINTER_SIZE', 0, level+1, False)|indent(4)}}
}
-{% else %}
+{%- else %}
encoder{{level}}.{{kind|encode_method(variable, offset, bit)}};
-{% endif %}
-{% endmacro %}
+{%- endif %}
+{%- endmacro %}
-{% macro decode(variable, kind, offset, bit, level=0) %}
-{% if kind|is_struct_kind or
+{%- macro decode(variable, kind, offset, bit, level=0) %}
+{%- if kind|is_struct_kind or
kind|is_pointer_array_kind or
kind|is_union_array_kind or
kind|is_map_kind %}
org.chromium.mojo.bindings.Decoder decoder{{level+1}} = decoder{{level}}.readPointer({{offset}}, {{kind|is_nullable_kind|java_true_false}});
-{% if kind|is_struct_kind %}
+{%- if kind|is_struct_kind %}
{{variable}} = {{kind|java_type}}.decode(decoder{{level+1}});
-{% else %}{# kind|is_pointer_array_kind or is_map_kind #}
-{% if kind|is_nullable_kind %}
+{%- else %}{# kind|is_pointer_array_kind or is_map_kind #}
+{%- if kind|is_nullable_kind %}
if (decoder{{level+1}} == null) {
{{variable}} = null;
} else {
-{% else %}
+{%- else %}
{
-{% endif %}
-{% if kind|is_map_kind %}
+{%- endif %}
+{%- if kind|is_map_kind %}
decoder{{level+1}}.readDataHeaderForMap();
{{kind.key_kind|java_type}}[] keys{{level}};
{{kind.value_kind|java_type}}[] values{{level}};
@@ -109,69 +109,69 @@ if (decoder{{level+1}} == null) {
for (int index{{level}} = 0; index{{level}} < keys{{level}}.length; ++index{{level}}) {
{{variable}}.put(keys{{level}}[index{{level}}], values{{level}}[index{{level}}]);
}
-{% else %}
+{%- else %}
org.chromium.mojo.bindings.DataHeader si{{level+1}} = decoder{{level+1}}.readDataHeaderForPointerArray({{kind|array_expected_length}});
{{variable}} = {{kind|new_array('si'~(level+1)~'.elementsOrVersion')}};
for (int i{{level+1}} = 0; i{{level+1}} < si{{level+1}}.elementsOrVersion; ++i{{level+1}}) {
{{decode(variable~'[i'~(level+1)~']', kind.kind, 'org.chromium.mojo.bindings.DataHeader.HEADER_SIZE + ' ~ array_element_size(kind.kind) ~' * i'~(level+1), 0, level+1)|indent(8)}}
}
-{% endif %}
+{%- endif %}
}
-{% endif %}
-{% elif kind|is_union_kind %}
+{%- endif %}
+{%- elif kind|is_union_kind %}
{{variable}} = {{kind|java_type}}.decode(decoder{{level}}, {{offset}});
-{% else %}
+{%- else %}
{{variable}} = decoder{{level}}.{{kind|decode_method(offset, bit)}};
-{% if kind|is_array_kind and kind.kind|is_enum_kind %}
-{% if kind|is_nullable_kind %}
+{%- if kind|is_array_kind and kind.kind|is_enum_kind %}
+{%- if kind|is_nullable_kind %}
if ({{variable}} != null) {
-{% else %}
+{%- else %}
{
-{% endif %}
+{%- endif %}
for (int i{{level}} = 0; i{{level}} < {{variable}}.length; ++i{{level}}) {
{{kind.kind|java_class_for_enum}}.validate({{variable}}[i{{level}}]);
}
}
-{% elif kind|is_enum_kind %}
+{%- elif kind|is_enum_kind %}
{{kind|java_class_for_enum}}.validate({{variable}});
-{% endif %}
-{% endif %}
-{% endmacro %}
+{%- endif %}
+{%- endif %}
+{%- endmacro %}
-{% macro struct_def(struct, inner_class=False) %}
+{%- macro struct_def(struct, inner_class=False) %}
{{'static' if inner_class else 'public'}} final class {{struct|name}} extends org.chromium.mojo.bindings.Struct {
private static final int STRUCT_SIZE = {{struct.versions[-1].num_bytes}};
private static final org.chromium.mojo.bindings.DataHeader[] VERSION_ARRAY = new org.chromium.mojo.bindings.DataHeader[] {
{%- for version in struct.versions -%}
- new org.chromium.mojo.bindings.DataHeader({{version.num_bytes}}, {{version.version}}){% if not loop.last %}, {% endif -%}
+ new org.chromium.mojo.bindings.DataHeader({{version.num_bytes}}, {{version.version}}){%- if not loop.last %}, {%- endif -%}
{%- endfor -%}
};
private static final org.chromium.mojo.bindings.DataHeader DEFAULT_STRUCT_INFO = VERSION_ARRAY[{{struct.versions|length - 1}}];
-{% for constant in struct.constants %}
+{%- for constant in struct.constants %}
{{constant_def(constant)|indent(4)}}
-{% endfor %}
-{% for enum in struct.enums %}
+{%- endfor %}
+{%- for enum in struct.enums %}
{{enum_def(enum, false)|indent(4)}}
-{% endfor %}
-{% if struct.fields %}
+{%- endfor %}
+{%- if struct.fields %}
-{% for field in struct.fields %}
+{%- for field in struct.fields %}
public {{field.kind|java_type}} {{field|name}};
-{% endfor %}
-{% endif %}
+{%- endfor %}
+{%- endif %}
private {{struct|name}}(int version) {
super(STRUCT_SIZE, version);
-{% for field in struct.fields %}
-{% if field.default %}
+{%- for field in struct.fields %}
+{%- if field.default %}
{{field|name}} = {{field|default_value}};
-{% elif field.kind|is_any_handle_kind and not field.kind|is_interface_request_kind %}
+{%- elif field.kind|is_any_handle_kind %}
{{field|name}} = org.chromium.mojo.system.InvalidHandle.INSTANCE;
-{% endif %}
-{% endfor %}
+{%- endif %}
+{%- endfor %}
}
public {{struct|name}}() {
@@ -182,36 +182,55 @@ if ({{variable}} != null) {
return decode(new org.chromium.mojo.bindings.Decoder(message));
}
+ /**
+ * Similar to the method above, but deserializes from a |ByteBuffer| instance.
+ *
+ * @throws org.chromium.mojo.bindings.DeserializationException on deserialization failure.
+ */
+ public static {{struct|name}} deserialize(java.nio.ByteBuffer data) {
+ if (data == null)
+ return null;
+
+ return deserialize(new org.chromium.mojo.bindings.Message(
+ data, new java.util.ArrayList<org.chromium.mojo.system.Handle>()));
+ }
+
@SuppressWarnings("unchecked")
public static {{struct|name}} decode(org.chromium.mojo.bindings.Decoder decoder0) {
if (decoder0 == null) {
return null;
}
- org.chromium.mojo.bindings.DataHeader mainDataHeader = decoder0.readAndValidateDataHeader(VERSION_ARRAY);
- {{struct|name}} result = new {{struct|name}}(mainDataHeader.elementsOrVersion);
-{% for byte in struct.bytes %}
-{% for packed_field in byte.packed_fields %}
- if (mainDataHeader.elementsOrVersion >= {{packed_field.min_version}}) {
- {{decode('result.' ~ packed_field.field|name, packed_field.field.kind, 8+packed_field.offset, packed_field.bit)|indent(12)}}
+ decoder0.increaseStackDepth();
+ {{struct|name}} result;
+ try {
+ org.chromium.mojo.bindings.DataHeader mainDataHeader = decoder0.readAndValidateDataHeader(VERSION_ARRAY);
+ result = new {{struct|name}}(mainDataHeader.elementsOrVersion);
+{%- for byte in struct.bytes %}
+{%- for packed_field in byte.packed_fields %}
+ if (mainDataHeader.elementsOrVersion >= {{packed_field.min_version}}) {
+ {{decode('result.' ~ packed_field.field|name, packed_field.field.kind, 8+packed_field.offset, packed_field.bit)|indent(16)}}
+ }
+{%- endfor %}
+{%- endfor %}
+ } finally {
+ decoder0.decreaseStackDepth();
}
-{% endfor %}
-{% endfor %}
return result;
}
@SuppressWarnings("unchecked")
@Override
protected final void encode(org.chromium.mojo.bindings.Encoder encoder) {
-{% if not struct.bytes %}
+{%- if not struct.bytes %}
encoder.getEncoderAtDataOffset(DEFAULT_STRUCT_INFO);
-{% else %}
+{%- else %}
org.chromium.mojo.bindings.Encoder encoder0 = encoder.getEncoderAtDataOffset(DEFAULT_STRUCT_INFO);
-{% endif %}
-{% for byte in struct.bytes %}
-{% for packed_field in byte.packed_fields %}
+{%- endif %}
+{%- for byte in struct.bytes %}
+{%- for packed_field in byte.packed_fields %}
{{encode(packed_field.field|name, packed_field.field.kind, 8+packed_field.offset, packed_field.bit)|indent(8)}}
-{% endfor %}
-{% endfor %}
+{%- endfor %}
+{%- endfor %}
}
/**
@@ -225,13 +244,13 @@ if ({{variable}} != null) {
return false;
if (getClass() != object.getClass())
return false;
-{% if struct.fields|length %}
+{%- if struct.fields|length %}
{{struct|name}} other = ({{struct|name}}) object;
-{% for field in struct.fields %}
+{%- for field in struct.fields %}
if ({{equality(field.kind, 'this.'~field|name, 'other.'~field|name, True)}})
return false;
-{% endfor %}
-{% endif %}
+{%- endfor %}
+{%- endif %}
return true;
}
@@ -242,28 +261,28 @@ if ({{variable}} != null) {
public int hashCode() {
final int prime = 31;
int result = prime + getClass().hashCode();
-{% for field in struct.fields %}
+{%- for field in struct.fields %}
result = prime * result + {{hash(field.kind, field|name)}};
-{% endfor %}
+{%- endfor %}
return result;
}
}
-{% endmacro %}
+{%- endmacro %}
-{% macro union_def(union) %}
+{%- macro union_def(union) %}
public final class {{union|name}} extends org.chromium.mojo.bindings.Union {
public static final class Tag {
-{% for field in union.fields %}
+{%- for field in union.fields %}
public static final int {{field|ucc}} = {{loop.index0}};
-{% endfor %}
+{%- endfor %}
};
private int mTag_ = -1;
-{% for field in union.fields %}
+{%- for field in union.fields %}
private {{field.kind|java_type}} m{{field|ucc}};
-{% endfor %}
+{%- endfor %}
public int which() {
return mTag_;
@@ -272,7 +291,7 @@ public final class {{union|name}} extends org.chromium.mojo.bindings.Union {
public boolean isUnknown() {
return mTag_ == -1;
}
-{% for field in union.fields %}
+{%- for field in union.fields %}
// TODO(rockot): Fix the findbugs error and remove this suppression.
// See http://crbug.com/570386.
@@ -289,7 +308,7 @@ public final class {{union|name}} extends org.chromium.mojo.bindings.Union {
assert mTag_ == Tag.{{field|ucc}};
return m{{field|ucc}};
}
-{% endfor %}
+{%- endfor %}
@Override
@@ -297,20 +316,20 @@ public final class {{union|name}} extends org.chromium.mojo.bindings.Union {
encoder0.encode(org.chromium.mojo.bindings.BindingsHelper.UNION_SIZE, offset);
encoder0.encode(mTag_, offset + 4);
switch (mTag_) {
-{% for field in union.fields %}
+{%- for field in union.fields %}
case Tag.{{field|ucc}}: {
-{% if field.kind|is_union_kind %}
+{%- if field.kind|is_union_kind %}
if (m{{field|ucc}} == null) {
encoder0.encodeNullPointer(offset + 8, {{field.kind|is_nullable_kind|java_true_false}});
} else {
m{{field|ucc}}.encode(encoder0.encoderForUnionPointer(offset + 8), 0);
}
-{% else %}
+{%- else %}
{{encode('m' ~ field|ucc, field.kind, 'offset + 8', 0)|indent(16)}}
-{% endif %}
+{%- endif %}
break;
}
-{% endfor %}
+{%- endfor %}
default: {
break;
}
@@ -328,20 +347,20 @@ public final class {{union|name}} extends org.chromium.mojo.bindings.Union {
}
{{union|name}} result = new {{union|name}}();
switch (dataHeader.elementsOrVersion) {
-{% for field in union.fields %}
+{%- for field in union.fields %}
case Tag.{{field|ucc}}: {
-{% if field.kind|is_union_kind %}
+{%- if field.kind|is_union_kind %}
org.chromium.mojo.bindings.Decoder decoder1 = decoder0.readPointer(offset + org.chromium.mojo.bindings.DataHeader.HEADER_SIZE, {{field.kind|is_nullable_kind|java_true_false}});
if (decoder1 != null) {
result.m{{field|ucc}} = {{field.kind|name}}.decode(decoder1, 0);
}
-{% else %}
+{%- else %}
{{decode('result.m'~field|ucc, field.kind, 'offset + org.chromium.mojo.bindings.DataHeader.HEADER_SIZE', 0)|indent(16)}}
-{% endif %}
+{%- endif %}
result.mTag_ = Tag.{{field|ucc}};
break;
}
-{% endfor %}
+{%- endfor %}
default: {
break;
}
@@ -364,10 +383,10 @@ public final class {{union|name}} extends org.chromium.mojo.bindings.Union {
if (mTag_ != other.mTag_)
return false;
switch (mTag_) {
-{% for field in union.fields %}
+{%- for field in union.fields %}
case Tag.{{field|ucc}}:
return {{equality(field.kind, 'm'~field|ucc, 'other.m'~field|ucc)}};
-{% endfor %}
+{%- endfor %}
default:
break;
}
@@ -383,12 +402,12 @@ public final class {{union|name}} extends org.chromium.mojo.bindings.Union {
int result = prime + getClass().hashCode();
result = prime * result + org.chromium.mojo.bindings.BindingsHelper.hashCode(mTag_);
switch (mTag_) {
-{% for field in union.fields %}
+{%- for field in union.fields %}
case Tag.{{field|ucc}}: {
result = prime * result + {{hash(field.kind, 'm'~field|ucc)}};
break;
}
-{% endfor %}
+{%- endfor %}
default: {
break;
}
@@ -396,4 +415,4 @@ public final class {{union|name}} extends org.chromium.mojo.bindings.Union {
return result;
}
}
-{% endmacro %}
+{%- endmacro %}
diff --git a/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl
index 3928e0c..c7dcbbc 100644
--- a/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl
@@ -91,11 +91,11 @@ try {
}
switch(header.getType()) {
{% if with_response %}
- case org.chromium.mojo.bindings.InterfaceControlMessagesConstants.RUN_MESSAGE_ID:
+ case org.chromium.mojo.bindings.interfacecontrol.InterfaceControlMessagesConstants.RUN_MESSAGE_ID:
return org.chromium.mojo.bindings.InterfaceControlMessagesHelper.handleRun(
getCore(), {{interface|name}}_Internal.MANAGER, messageWithHeader, receiver);
{% else %}
- case org.chromium.mojo.bindings.InterfaceControlMessagesConstants.RUN_OR_CLOSE_PIPE_MESSAGE_ID:
+ case org.chromium.mojo.bindings.interfacecontrol.InterfaceControlMessagesConstants.RUN_OR_CLOSE_PIPE_MESSAGE_ID:
return org.chromium.mojo.bindings.InterfaceControlMessagesHelper.handleRunOrClosePipe(
{{interface|name}}_Internal.MANAGER, messageWithHeader);
{% endif %}
@@ -113,12 +113,7 @@ try {
{% else %}
{{request_struct|name}}.deserialize(messageWithHeader.getPayload());
{% endif %}
- try {
- getImpl().{{method|name}}({{run_callback('data', method.parameters)}}{% if with_response %}{% if method.parameters %}, {% endif %}new {{response_struct|name}}ProxyToResponder(getCore(), receiver, header.getRequestId()){% endif %});
- } catch (RuntimeException e) {
- // TODO(lhchavez): Remove this hack. See b/28814913 for details.
- android.util.Log.wtf("{{namespace}}.{{interface.name}}", "Uncaught runtime exception", e);
- }
+ getImpl().{{method|name}}({{run_callback('data', method.parameters)}}{% if with_response %}{% if method.parameters %}, {% endif %}new {{response_struct|name}}ProxyToResponder(getCore(), receiver, header.getRequestId()){% endif %});
return true;
}
{% endif %}
diff --git a/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl
index 4ae0a9b..019b1b6 100644
--- a/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl
@@ -1,13 +1,33 @@
{%- macro enum_def(enum_name, enum) -%}
{{enum_name}} = {};
-{%- set prev_enum = 0 %}
-{%- for field in enum.fields %}
-{%- if field.value %}
+{%- set prev_enum = 0 %}
+{%- for field in enum.fields %}
+{%- if field.value %}
{{enum_name}}.{{field.name}} = {{field.value|expression_to_text}};
-{%- elif loop.first %}
+{%- elif loop.first %}
{{enum_name}}.{{field.name}} = 0;
-{%- else %}
+{%- else %}
{{enum_name}}.{{field.name}} = {{enum_name}}.{{enum.fields[loop.index0 - 1].name}} + 1;
+{%- endif %}
+{%- endfor %}
+
+ {{enum_name}}.isKnownEnumValue = function(value) {
+{%- if enum.fields %}
+ switch (value) {
+{%- for enum_field in enum.fields|groupby('numeric_value') %}
+ case {{enum_field[0]}}:
+{%- endfor %}
+ return true;
+ }
{%- endif %}
-{%- endfor %}
+ return false;
+ };
+
+ {{enum_name}}.validate = function(enumValue) {
+ var isExtensible = {% if enum.extensible %}true{% else %}false{% endif %};
+ if (isExtensible || this.isKnownEnumValue(enumValue))
+ return validator.validationError.NONE;
+
+ return validator.validationError.UNKNOWN_ENUM_VALUE;
+ };
{%- endmacro %}
diff --git a/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl
index 1b5cafa..54e2d4e 100644
--- a/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl
@@ -2,12 +2,21 @@
var k{{interface.name}}_{{method.name}}_Name = {{method.ordinal}};
{%- endfor %}
+ function {{interface.name}}Ptr(handleOrPtrInfo) {
+ this.ptr = new bindings.InterfacePtrController({{interface.name}},
+ handleOrPtrInfo);
+ }
+
function {{interface.name}}Proxy(receiver) {
- bindings.ProxyBase.call(this, receiver);
+ this.receiver_ = receiver;
}
- {{interface.name}}Proxy.prototype = Object.create(bindings.ProxyBase.prototype);
{%- for method in interface.methods %}
+ {{interface.name}}Ptr.prototype.{{method.name|stylize_method}} = function() {
+ return {{interface.name}}Proxy.prototype.{{method.name|stylize_method}}
+ .apply(this.ptr.getProxy(), arguments);
+ };
+
{{interface.name}}Proxy.prototype.{{method.name|stylize_method}} = function(
{%- for parameter in method.parameters -%}
{{parameter.name}}{% if not loop.last %}, {% endif %}
@@ -15,7 +24,7 @@
) {
var params = new {{interface.name}}_{{method.name}}_Params();
{%- for parameter in method.parameters %}
- params.{{parameter.name}} = {{parameter|js_proxy_method_parameter_value}};
+ params.{{parameter.name}} = {{parameter.name}};
{%- endfor %}
{%- if method.response_parameters == None %}
@@ -47,15 +56,13 @@
{%- endfor %}
function {{interface.name}}Stub(delegate) {
- bindings.StubBase.call(this, delegate);
+ this.delegate_ = delegate;
}
- {{interface.name}}Stub.prototype = Object.create(bindings.StubBase.prototype);
{%- for method in interface.methods %}
{%- set js_method_name = method.name|stylize_method %}
-{%- set delegate_expr = "bindings.StubBindings(this).delegate" %}
{{interface.name}}Stub.prototype.{{js_method_name}} = function({{method.parameters|map(attribute='name')|join(', ')}}) {
- return {{delegate_expr}} && {{delegate_expr}}.{{js_method_name}} && {{delegate_expr}}.{{js_method_name}}({{method.parameters|map('js_stub_method_parameter_value')|join(', ')}});
+ return this.delegate_ && this.delegate_.{{js_method_name}} && this.delegate_.{{js_method_name}}({{method.parameters|map(attribute='name')|join(', ')}});
}
{%- endfor %}
@@ -162,6 +169,8 @@ params.{{parameter.name}}{% if not loop.last %}, {% endif -%}
var {{interface.name}} = {
name: '{{namespace|replace(".","::")}}::{{interface.name}}',
+ kVersion: {{interface.version}},
+ ptrClass: {{interface.name}}Ptr,
proxyClass: {{interface.name}}Proxy,
stubClass: {{interface.name}}Stub,
validateRequest: validate{{interface.name}}Request,
diff --git a/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl b/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl
index 6d7a1a2..3ce4ab6 100644
--- a/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl
@@ -3,15 +3,19 @@
// found in the LICENSE file.
define("{{module.path}}", [
+{%- if module.path != "mojo/public/interfaces/bindings/interface_control_messages.mojom" %}
"mojo/public/js/bindings",
+{%- endif %}
"mojo/public/js/codec",
- "mojo/public/js/connection",
"mojo/public/js/core",
"mojo/public/js/validator",
{%- for import in imports %}
"{{import.module.path}}",
{%- endfor %}
-], function(bindings, codec, connection, core, validator
+], function(
+{%- if module.path != "mojo/public/interfaces/bindings/interface_control_messages.mojom" -%}
+bindings, {% endif -%}
+codec, core, validator
{%- for import in imports -%}
, {{import.unique_name}}
{%- endfor -%}
diff --git a/mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl
index 86ea2ce..ddfef72 100644
--- a/mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl
@@ -40,6 +40,7 @@
{%- endfor %}
{%- for interface in interfaces %}
exports.{{interface.name}} = {{interface.name}};
+ exports.{{interface.name}}Ptr = {{interface.name}}Ptr;
{#--- Interface Client #}
{%- if interface.client in interfaces|map(attribute='name') %}
exports.{{interface.name}}.client = {{interface.client}};
diff --git a/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl
index ca80d67..e823e46 100644
--- a/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl
@@ -34,16 +34,40 @@
{{struct.name}}.validate = function(messageValidator, offset) {
var err;
- err = messageValidator.validateStructHeader(offset, {{struct.name}}.encodedSize, {{struct.versions[-1].version}});
+ err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
if (err !== validator.validationError.NONE)
return err;
+ var kVersionSizes = [
+{%- for version in struct.versions %}
+ {version: {{version.version}}, numBytes: {{version.num_bytes}}}{% if not loop.last %},
+ {%- endif -%}
+{% endfor %}
+ ];
+ err = messageValidator.validateStructVersion(offset, kVersionSizes);
+ if (err !== validator.validationError.NONE)
+ return err;
+
+{#- Before validating fields introduced at a certain version, we need to add
+ a version check, which makes sure we skip further validation if |object|
+ is from an earlier version. |last_checked_version| records the last
+ version that we have added such version check. #}
{%- from "validation_macros.tmpl" import validate_struct_field %}
-{%- for packed_field in struct.packed.packed_fields %}
+{%- set last_checked_version = 0 %}
+{%- for packed_field in struct.packed.packed_fields_in_ordinal_order %}
{%- set offset = packed_field|field_offset %}
{%- set field = packed_field.field %}
{%- set name = struct.name ~ '.' ~ field.name %}
+{% if field|is_object_field or field|is_any_handle_or_interface_field or
+ field|is_enum_field %}
+{% if packed_field.min_version > last_checked_version %}
+{% set last_checked_version = packed_field.min_version %}
+ // version check {{name}}
+ if (!messageValidator.isFieldInStructVersion(offset, {{packed_field.min_version}}))
+ return validator.validationError.NONE;
+{%- endif -%}
{{validate_struct_field(field, offset, name)|indent(4)}}
+{%- endif %}
{%- endfor %}
return validator.validationError.NONE;
@@ -59,7 +83,8 @@
var numberOfBytes = decoder.readUint32();
var version = decoder.readUint32();
{%- for byte in struct.bytes %}
-{%- if byte.packed_fields|length > 1 %}
+{%- if byte.packed_fields|length >= 1 and
+ byte.packed_fields[0].field|is_bool_field %}
packed = decoder.readUint8();
{%- for packed_field in byte.packed_fields %}
val.{{packed_field.field.name}} = (packed >> {{packed_field.bit}}) & 1 ? true : false;
@@ -82,7 +107,8 @@
encoder.writeUint32({{struct.versions[-1].version}});
{%- for byte in struct.bytes %}
-{%- if byte.packed_fields|length > 1 %}
+{%- if byte.packed_fields|length >= 1 and
+ byte.packed_fields[0].field|is_bool_field %}
packed = 0;
{%- for packed_field in byte.packed_fields %}
packed |= (val.{{packed_field.field.name}} & 1) << {{packed_field.bit}}
diff --git a/mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl
index 3c903bc..4823feb 100644
--- a/mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl
@@ -89,7 +89,11 @@ Object.defineProperty({{union.name}}.prototype, "{{field.name}}", {
switch (val.$tag) {
{%- for field in union.fields %}
case {{union.name}}.Tags.{{field.name}}:
+{%- if field|is_bool_field %}
+ encoder.writeUint8(val.{{field.name}} ? 1 : 0);
+{%- else %}
encoder.{{field.kind|union_encode_snippet}}val.{{field.name}});
+{%- endif %}
break;
{%- endfor %}
}
@@ -111,7 +115,11 @@ Object.defineProperty({{union.name}}.prototype, "{{field.name}}", {
switch (tag) {
{%- for field in union.fields %}
case {{union.name}}.Tags.{{field.name}}:
+{%- if field|is_bool_field %}
+ result.{{field.name}} = decoder.readUint8() ? true : false;
+{%- else %}
result.{{field.name}} = decoder.{{field.kind|union_decode_snippet}};
+{%- endif %}
break;
{%- endfor %}
}
diff --git a/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl b/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl
index 7a39749..d4e15a7 100644
--- a/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl
@@ -6,7 +6,7 @@ if (err !== validator.validationError.NONE)
{%- macro _validate_field(field, offset, name) %}
{%- if field|is_string_pointer_field %}
// validate {{name}}
-err = messageValidator.validateStringPointer({{offset}}, {{field|validate_string_params}})
+err = messageValidator.validateStringPointer({{offset}}, {{field|validate_nullable_params}})
{{_check_err()}}
{%- elif field|is_array_pointer_field %}
// validate {{name}}
@@ -22,11 +22,19 @@ err = messageValidator.validateMapPointer({{offset}}, {{field|validate_map_param
{{_check_err()}}
{%- elif field|is_interface_field %}
// validate {{name}}
-err = messageValidator.validateInterface({{offset}}, {{field|validate_interface_params}});
+err = messageValidator.validateInterface({{offset}}, {{field|validate_nullable_params}});
+{{_check_err()}}
+{%- elif field|is_interface_request_field %}
+// validate {{name}}
+err = messageValidator.validateInterfaceRequest({{offset}}, {{field|validate_nullable_params}})
{{_check_err()}}
{%- elif field|is_handle_field %}
// validate {{name}}
-err = messageValidator.validateHandle({{offset}}, {{field|validate_handle_params}})
+err = messageValidator.validateHandle({{offset}}, {{field|validate_nullable_params}})
+{{_check_err()}}
+{%- elif field|is_enum_field %}
+// validate {{name}}
+err = messageValidator.validateEnum({{offset}}, {{field|validate_enum_params}});
{{_check_err()}}
{%- endif %}
{%- endmacro %}
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
index 38b219c..38d222b 100644
--- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -36,10 +36,10 @@ _kind_to_cpp_literal_suffix = {
# generator library code so that filters can use the generator as context.
_current_typemap = {}
_for_blink = False
-_use_new_wrapper_types = False
# TODO(rockot, yzshen): The variant handling is kind of a hack currently. Make
# it right.
_variant = None
+_export_attribute = None
class _NameFormatter(object):
@@ -50,22 +50,40 @@ class _NameFormatter(object):
self._variant = variant
def Format(self, separator, prefixed=False, internal=False,
- include_variant=False, add_same_module_namespaces=False):
+ include_variant=False, add_same_module_namespaces=False,
+ flatten_nested_kind=False):
+ """Formats the name according to the given configuration.
+
+ Args:
+ separator: Separator between different parts of the name.
+ prefixed: Whether a leading separator should be added.
+ internal: Returns the name in the "internal" namespace.
+ include_variant: Whether to include variant as namespace. If |internal| is
+ True, then this flag is ignored and variant is not included.
+ add_same_module_namespaces: Includes all namespaces even if the token is
+ from the same module as the current mojom file.
+ flatten_nested_kind: It is allowed to define enums inside structs and
+ interfaces. If this flag is set to True, this method concatenates the
+ parent kind and the nested kind with '_', instead of treating the
+ parent kind as a scope."""
+
parts = []
if self._ShouldIncludeNamespace(add_same_module_namespaces):
if prefixed:
parts.append("")
parts.extend(self._GetNamespace())
- if include_variant and self._variant:
+ if include_variant and self._variant and not internal:
parts.append(self._variant)
- parts.extend(self._GetName(internal))
+ parts.extend(self._GetName(internal, flatten_nested_kind))
return separator.join(parts)
- def FormatForCpp(self, add_same_module_namespaces=False, internal=False):
+ def FormatForCpp(self, add_same_module_namespaces=False, internal=False,
+ flatten_nested_kind=False):
return self.Format(
"::", prefixed=True,
add_same_module_namespaces=add_same_module_namespaces,
- internal=internal, include_variant=True)
+ internal=internal, include_variant=True,
+ flatten_nested_kind=flatten_nested_kind)
def FormatForMojom(self):
return self.Format(".", add_same_module_namespaces=True)
@@ -74,24 +92,32 @@ class _NameFormatter(object):
if not internal:
return token.name
if (mojom.IsStructKind(token) or mojom.IsUnionKind(token) or
- mojom.IsInterfaceKind(token) or mojom.IsEnumKind(token)):
+ mojom.IsEnumKind(token)):
return token.name + "_Data"
return token.name
- def _GetName(self, internal):
- name = []
+ def _GetName(self, internal, flatten_nested_kind):
+ if isinstance(self._token, mojom.EnumValue):
+ name_parts = _NameFormatter(self._token.enum, self._variant)._GetName(
+ internal, flatten_nested_kind)
+ name_parts.append(self._token.name)
+ return name_parts
+
+ name_parts = []
if internal:
- name.append("internal")
+ name_parts.append("internal")
+
+ if (flatten_nested_kind and mojom.IsEnumKind(self._token) and
+ self._token.parent_kind):
+ name = "%s_%s" % (self._token.parent_kind.name,
+ self._MapKindName(self._token, internal))
+ name_parts.append(name)
+ return name_parts
+
if self._token.parent_kind:
- name.append(self._MapKindName(self._token.parent_kind, internal))
- # Both variable and enum constants are constructed like:
- # Namespace::Struct::CONSTANT_NAME
- # For enums, CONSTANT_NAME is EnumName::ENUM_VALUE.
- if isinstance(self._token, mojom.EnumValue):
- name.extend([self._token.enum.name, self._token.name])
- else:
- name.append(self._MapKindName(self._token, internal))
- return name
+ name_parts.append(self._MapKindName(self._token.parent_kind, internal))
+ name_parts.append(self._MapKindName(self._token, internal))
+ return name_parts
def _ShouldIncludeNamespace(self, add_same_module_namespaces):
return add_same_module_namespaces or self._token.imported_from
@@ -116,22 +142,30 @@ def DefaultValue(field):
if not IsTypemappedKind(field.kind):
return "%s::New()" % GetNameForKind(field.kind)
return ExpressionToText(field.default, kind=field.kind)
- if not _use_new_wrapper_types:
- if mojom.IsArrayKind(field.kind) or mojom.IsMapKind(field.kind):
- return "nullptr";
- if mojom.IsStringKind(field.kind):
- return "" if _for_blink else "nullptr"
return ""
def NamespaceToArray(namespace):
return namespace.split(".") if namespace else []
-def GetNameForKind(kind, internal=False):
- return _NameFormatter(kind, _variant).FormatForCpp(internal=internal)
-
-def GetQualifiedNameForKind(kind, internal=False):
+def GetNameForKind(kind, internal=False, flatten_nested_kind=False,
+ add_same_module_namespaces=False):
return _NameFormatter(kind, _variant).FormatForCpp(
- internal=internal, add_same_module_namespaces=True)
+ internal=internal, flatten_nested_kind=flatten_nested_kind,
+ add_same_module_namespaces=add_same_module_namespaces)
+
+def GetQualifiedNameForKind(kind, internal=False, flatten_nested_kind=False,
+ include_variant=True):
+ return _NameFormatter(
+ kind, _variant if include_variant else None).FormatForCpp(
+ internal=internal, add_same_module_namespaces=True,
+ flatten_nested_kind=flatten_nested_kind)
+
+
+def GetWtfHashFnNameForEnum(enum):
+ return _NameFormatter(
+ enum, None).Format("_", internal=True, add_same_module_namespaces=True,
+ flatten_nested_kind=True) + "HashFn"
+
def GetFullMojomNameForKind(kind):
return _NameFormatter(kind, _variant).FormatForMojom()
@@ -144,60 +178,128 @@ def IsNativeOnlyKind(kind):
return (mojom.IsStructKind(kind) or mojom.IsEnumKind(kind)) and \
kind.native_only
+
+def IsHashableKind(kind):
+ """Check if the kind can be hashed.
+
+ Args:
+ kind: {Kind} The kind to check.
+
+ Returns:
+ {bool} True if a value of this kind can be hashed.
+ """
+ checked = set()
+ def Check(kind):
+ if kind.spec in checked:
+ return True
+ checked.add(kind.spec)
+ if mojom.IsNullableKind(kind):
+ return False
+ elif mojom.IsStructKind(kind):
+ if (IsTypemappedKind(kind) and
+ not _current_typemap[GetFullMojomNameForKind(kind)]["hashable"]):
+ return False
+ return all(Check(field.kind) for field in kind.fields)
+ elif mojom.IsEnumKind(kind):
+ return not IsTypemappedKind(kind) or _current_typemap[
+ GetFullMojomNameForKind(kind)]["hashable"]
+ elif mojom.IsUnionKind(kind):
+ return all(Check(field.kind) for field in kind.fields)
+ elif mojom.IsAnyHandleKind(kind):
+ return False
+ elif mojom.IsAnyInterfaceKind(kind):
+ return False
+ # TODO(tibell): Arrays and maps could be made hashable. We just don't have a
+ # use case yet.
+ elif mojom.IsArrayKind(kind):
+ return False
+ elif mojom.IsMapKind(kind):
+ return False
+ else:
+ return True
+ return Check(kind)
+
+
+def AllEnumValues(enum):
+ """Return all enum values associated with an enum.
+
+ Args:
+ enum: {mojom.Enum} The enum type.
+
+ Returns:
+ {Set[int]} The values.
+ """
+ return set(field.numeric_value for field in enum.fields)
+
+
def GetNativeTypeName(typemapped_kind):
return _current_typemap[GetFullMojomNameForKind(typemapped_kind)]["typename"]
def GetCppPodType(kind):
- if mojom.IsStringKind(kind):
- return "char*"
return _kind_to_cpp_type[kind]
-def GetCppWrapperType(kind):
+def FormatConstantDeclaration(constant, nested=False):
+ if mojom.IsStringKind(constant.kind):
+ if nested:
+ return "const char %s[]" % constant.name
+ return "%sextern const char %s[]" % \
+ ((_export_attribute + " ") if _export_attribute else "", constant.name)
+ return "constexpr %s %s = %s" % (GetCppPodType(constant.kind), constant.name,
+ ConstantValue(constant))
+
+def GetCppWrapperType(kind, add_same_module_namespaces=False):
+ def _AddOptional(type_name):
+ pattern = "WTF::Optional<%s>" if _for_blink else "base::Optional<%s>"
+ return pattern % type_name
+
if IsTypemappedKind(kind):
- return GetNativeTypeName(kind)
+ type_name = GetNativeTypeName(kind)
+ if (mojom.IsNullableKind(kind) and
+ not _current_typemap[GetFullMojomNameForKind(kind)][
+ "nullable_is_same_type"]):
+ type_name = _AddOptional(type_name)
+ return type_name
if mojom.IsEnumKind(kind):
- return GetNameForKind(kind)
+ return GetNameForKind(
+ kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
- return "%sPtr" % GetNameForKind(kind)
+ return "%sPtr" % GetNameForKind(
+ kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsArrayKind(kind):
- pattern = None
- if _use_new_wrapper_types:
- if mojom.IsNullableKind(kind):
- pattern = ("WTF::Optional<WTF::Vector<%s>>" if _for_blink else
- "base::Optional<std::vector<%s>>")
- else:
- pattern = "WTF::Vector<%s>" if _for_blink else "std::vector<%s>"
- else:
- pattern = "mojo::WTFArray<%s>" if _for_blink else "mojo::Array<%s>"
- return pattern % GetCppWrapperType(kind.kind)
+ pattern = "WTF::Vector<%s>" if _for_blink else "std::vector<%s>"
+ if mojom.IsNullableKind(kind):
+ pattern = _AddOptional(pattern)
+ return pattern % GetCppWrapperType(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsMapKind(kind):
- pattern = None
- if _use_new_wrapper_types:
- if mojom.IsNullableKind(kind):
- pattern = ("WTF::Optional<WTF::HashMap<%s, %s>>" if _for_blink else
- "base::Optional<std::unordered_map<%s, %s>>")
- else:
- pattern = ("WTF::HashMap<%s, %s>" if _for_blink else
- "std::unordered_map<%s, %s>")
- else:
- pattern = "mojo::WTFMap<%s, %s>" if _for_blink else "mojo::Map<%s, %s>"
- return pattern % (GetCppWrapperType(kind.key_kind),
- GetCppWrapperType(kind.value_kind))
+ pattern = ("WTF::HashMap<%s, %s>" if _for_blink else
+ "std::unordered_map<%s, %s>")
+ if mojom.IsNullableKind(kind):
+ pattern = _AddOptional(pattern)
+ return pattern % (
+ GetCppWrapperType(
+ kind.key_kind,
+ add_same_module_namespaces=add_same_module_namespaces),
+ GetCppWrapperType(
+ kind.value_kind,
+ add_same_module_namespaces=add_same_module_namespaces))
if mojom.IsInterfaceKind(kind):
- return "%sPtr" % GetNameForKind(kind)
+ return "%sPtr" % GetNameForKind(
+ kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsInterfaceRequestKind(kind):
- return "%sRequest" % GetNameForKind(kind.kind)
+ return "%sRequest" % GetNameForKind(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsAssociatedInterfaceKind(kind):
- return "%sAssociatedPtrInfo" % GetNameForKind(kind.kind)
+ return "%sAssociatedPtrInfo" % GetNameForKind(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsAssociatedInterfaceRequestKind(kind):
- return "%sAssociatedRequest" % GetNameForKind(kind.kind)
+ return "%sAssociatedRequest" % GetNameForKind(
+ kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsStringKind(kind):
if _for_blink:
return "WTF::String"
- if not _use_new_wrapper_types:
- return "mojo::String"
- return ("base::Optional<std::string>" if mojom.IsNullableKind(kind) else
- "std::string")
+ type_name = "std::string"
+ return _AddOptional(type_name) if mojom.IsNullableKind(kind) else type_name
if mojom.IsGenericHandleKind(kind):
return "mojo::ScopedHandle"
if mojom.IsDataPipeConsumerKind(kind):
@@ -220,15 +322,22 @@ def IsMoveOnlyKind(kind):
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
return True
if mojom.IsArrayKind(kind):
- return IsMoveOnlyKind(kind.kind) if _use_new_wrapper_types else True
+ return IsMoveOnlyKind(kind.kind)
if mojom.IsMapKind(kind):
- return IsMoveOnlyKind(kind.value_kind) if _use_new_wrapper_types else True
+ return IsMoveOnlyKind(kind.value_kind)
if mojom.IsAnyHandleOrInterfaceKind(kind):
return True
return False
+def IsCopyablePassByValue(kind):
+ if not IsTypemappedKind(kind):
+ return False
+ return _current_typemap[GetFullMojomNameForKind(kind)][
+ "copyable_pass_by_value"]
+
def ShouldPassParamByValue(kind):
- return (not mojom.IsReferenceKind(kind)) or IsMoveOnlyKind(kind)
+ return ((not mojom.IsReferenceKind(kind)) or IsMoveOnlyKind(kind) or
+ IsCopyablePassByValue(kind))
def GetCppWrapperParamType(kind):
cpp_wrapper_type = GetCppWrapperType(kind)
@@ -254,7 +363,7 @@ def GetCppFieldType(kind):
if mojom.IsAssociatedInterfaceKind(kind):
return "mojo::internal::AssociatedInterface_Data"
if mojom.IsAssociatedInterfaceRequestKind(kind):
- return "mojo::internal::AssociatedInterfaceRequest_Data"
+ return "mojo::internal::AssociatedEndpointHandle_Data"
if mojom.IsEnumKind(kind):
return "int32_t"
if mojom.IsStringKind(kind):
@@ -273,27 +382,47 @@ def GetUnionGetterReturnType(kind):
return "%s&" % GetCppWrapperType(kind)
return GetCppWrapperType(kind)
-def GetUnmappedTypeForSerializer(kind):
+def GetUnionTraitGetterReturnType(kind):
+ """Get field type used in UnionTraits template specialization.
+
+ The type may be qualified as UnionTraits specializations live outside the
+ namespace where e.g. structs are defined.
+
+ Args:
+ kind: {Kind} The type of the field.
+
+ Returns:
+ {str} The C++ type to use for the field.
+ """
+ if mojom.IsReferenceKind(kind):
+ return "%s&" % GetCppWrapperType(kind, add_same_module_namespaces=True)
+ return GetCppWrapperType(kind, add_same_module_namespaces=True)
+
+def GetCppDataViewType(kind, qualified=False):
+ def _GetName(input_kind):
+ return _NameFormatter(input_kind, None).FormatForCpp(
+ add_same_module_namespaces=qualified, flatten_nested_kind=True)
+
if mojom.IsEnumKind(kind):
- return GetQualifiedNameForKind(kind)
+ return _GetName(kind)
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
- return "%sPtr" % GetQualifiedNameForKind(kind)
+ return "%sDataView" % _GetName(kind)
if mojom.IsArrayKind(kind):
- return "mojo::Array<%s>" % GetUnmappedTypeForSerializer(kind.kind)
+ return "mojo::ArrayDataView<%s>" % GetCppDataViewType(kind.kind, qualified)
if mojom.IsMapKind(kind):
- return "mojo::Map<%s, %s>" % (
- GetUnmappedTypeForSerializer(kind.key_kind),
- GetUnmappedTypeForSerializer(kind.value_kind))
+ return ("mojo::MapDataView<%s, %s>" % (
+ GetCppDataViewType(kind.key_kind, qualified),
+ GetCppDataViewType(kind.value_kind, qualified)))
+ if mojom.IsStringKind(kind):
+ return "mojo::StringDataView"
if mojom.IsInterfaceKind(kind):
- return "%sPtr" % GetQualifiedNameForKind(kind)
+ return "%sPtrDataView" % _GetName(kind)
if mojom.IsInterfaceRequestKind(kind):
- return "%sRequest" % GetQualifiedNameForKind(kind.kind)
+ return "%sRequestDataView" % _GetName(kind.kind)
if mojom.IsAssociatedInterfaceKind(kind):
- return "%sAssociatedPtrInfo" % GetQualifiedNameForKind(kind.kind)
+ return "%sAssociatedPtrInfoDataView" % _GetName(kind.kind)
if mojom.IsAssociatedInterfaceRequestKind(kind):
- return "%sAssociatedRequest" % GetQualifiedNameForKind(kind.kind)
- if mojom.IsStringKind(kind):
- return "mojo::String"
+ return "%sAssociatedRequestDataView" % _GetName(kind.kind)
if mojom.IsGenericHandleKind(kind):
return "mojo::ScopedHandle"
if mojom.IsDataPipeConsumerKind(kind):
@@ -306,18 +435,26 @@ def GetUnmappedTypeForSerializer(kind):
return "mojo::ScopedSharedBufferHandle"
return _kind_to_cpp_type[kind]
+def GetUnmappedTypeForSerializer(kind):
+ return GetCppDataViewType(kind, qualified=True)
+
def TranslateConstants(token, kind):
if isinstance(token, mojom.NamedValue):
- return _NameFormatter(token, _variant).FormatForCpp()
+ return GetNameForKind(token, flatten_nested_kind=True)
if isinstance(token, mojom.BuiltinValue):
- if token.value == "double.INFINITY" or token.value == "float.INFINITY":
- return "INFINITY";
- if token.value == "double.NEGATIVE_INFINITY" or \
- token.value == "float.NEGATIVE_INFINITY":
- return "-INFINITY";
- if token.value == "double.NAN" or token.value == "float.NAN":
- return "NAN";
+ if token.value == "double.INFINITY":
+ return "std::numeric_limits<double>::infinity()"
+ if token.value == "float.INFINITY":
+ return "std::numeric_limits<float>::infinity()"
+ if token.value == "double.NEGATIVE_INFINITY":
+ return "-std::numeric_limits<double>::infinity()"
+ if token.value == "float.NEGATIVE_INFINITY":
+ return "-std::numeric_limits<float>::infinity()"
+ if token.value == "double.NAN":
+ return "std::numeric_limits<double>::quiet_NaN()"
+ if token.value == "float.NAN":
+ return "std::numeric_limits<float>::quiet_NaN()"
if (kind is not None and mojom.IsFloatKind(kind)):
return token if token.isdigit() else token + "f";
@@ -342,6 +479,12 @@ def TranslateConstants(token, kind):
def ExpressionToText(value, kind=None):
return TranslateConstants(value, kind)
+def RequiresContextForDataView(kind):
+ for field in kind.fields:
+ if mojom.IsReferenceKind(field.kind):
+ return True
+ return False
+
def ShouldInlineStruct(struct):
# TODO(darin): Base this on the size of the wrapper class.
if len(struct.fields) > 4:
@@ -351,11 +494,69 @@ def ShouldInlineStruct(struct):
return False
return True
+def ContainsMoveOnlyMembers(struct):
+ for field in struct.fields:
+ if IsMoveOnlyKind(field.kind):
+ return True
+ return False
+
def ShouldInlineUnion(union):
return not any(
mojom.IsReferenceKind(field.kind) and not mojom.IsStringKind(field.kind)
for field in union.fields)
+
+class StructConstructor(object):
+ """Represents a constructor for a generated struct.
+
+ Fields:
+ fields: {[Field]} All struct fields in order.
+ params: {[Field]} The fields that are passed as params.
+ """
+
+ def __init__(self, fields, params):
+ self._fields = fields
+ self._params = set(params)
+
+ @property
+ def params(self):
+ return [field for field in self._fields if field in self._params]
+
+ @property
+ def fields(self):
+ for field in self._fields:
+ yield (field, field in self._params)
+
+
+def GetStructConstructors(struct):
+ """Returns a list of constructors for a struct.
+
+ Params:
+ struct: {Struct} The struct to return constructors for.
+
+ Returns:
+ {[StructConstructor]} A list of StructConstructors that should be generated
+ for |struct|.
+ """
+ if not mojom.IsStructKind(struct):
+ raise TypeError
+ # Types that are neither copyable nor movable can't be passed to a struct
+ # constructor so only generate a default constructor.
+ if any(IsTypemappedKind(field.kind) and _current_typemap[
+ GetFullMojomNameForKind(field.kind)]["non_copyable_non_movable"]
+ for field in struct.fields):
+ return [StructConstructor(struct.fields, [])]
+
+ param_counts = [0]
+ for version in struct.versions:
+ if param_counts[-1] != version.num_fields:
+ param_counts.append(version.num_fields)
+
+ ordinal_fields = sorted(struct.fields, key=lambda field: field.ordinal)
+ return (StructConstructor(struct.fields, ordinal_fields[:param_count])
+ for param_count in param_counts)
+
+
def GetContainerValidateParamsCtorArgs(kind):
if mojom.IsStringKind(kind):
expected_num_elements = 0
@@ -378,7 +579,8 @@ def GetContainerValidateParamsCtorArgs(kind):
element_validate_params = GetNewContainerValidateParams(kind.kind)
if mojom.IsEnumKind(kind.kind):
enum_validate_func = ("%s::Validate" %
- GetQualifiedNameForKind(kind.kind, internal=True))
+ GetQualifiedNameForKind(kind.kind, internal=True,
+ flatten_nested_kind=True))
else:
enum_validate_func = "nullptr"
@@ -403,57 +605,143 @@ def GetNewContainerValidateParams(kind):
class Generator(generator.Generator):
cpp_filters = {
+ "all_enum_values": AllEnumValues,
"constant_value": ConstantValue,
+ "contains_handles_or_interfaces": mojom.ContainsHandlesOrInterfaces,
+ "contains_move_only_members": ContainsMoveOnlyMembers,
"cpp_wrapper_param_type": GetCppWrapperParamType,
+ "cpp_data_view_type": GetCppDataViewType,
"cpp_field_type": GetCppFieldType,
"cpp_union_field_type": GetCppUnionFieldType,
"cpp_pod_type": GetCppPodType,
"cpp_union_getter_return_type": GetUnionGetterReturnType,
+ "cpp_union_trait_getter_return_type": GetUnionTraitGetterReturnType,
"cpp_wrapper_type": GetCppWrapperType,
"default_value": DefaultValue,
"expression_to_text": ExpressionToText,
+ "format_constant_declaration": FormatConstantDeclaration,
"get_container_validate_params_ctor_args":
- GetContainerValidateParamsCtorArgs,
+ GetContainerValidateParamsCtorArgs,
"get_name_for_kind": GetNameForKind,
"get_pad": pack.GetPad,
"get_qualified_name_for_kind": GetQualifiedNameForKind,
"has_callbacks": mojom.HasCallbacks,
"has_sync_methods": mojom.HasSyncMethods,
+ "requires_context_for_data_view": RequiresContextForDataView,
"should_inline": ShouldInlineStruct,
"should_inline_union": ShouldInlineUnion,
"is_array_kind": mojom.IsArrayKind,
"is_enum_kind": mojom.IsEnumKind,
"is_integral_kind": mojom.IsIntegralKind,
"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_hashable": IsHashableKind,
"is_map_kind": mojom.IsMapKind,
"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": IsTypemappedKind,
"is_union_kind": mojom.IsUnionKind,
"passes_associated_kinds": mojom.PassesAssociatedKinds,
- "struct_size": lambda ps: ps.GetTotalSize() + _HEADER_SIZE,
+ "struct_constructors": GetStructConstructors,
"stylize_method": generator.StudlyCapsToCamel,
"under_to_camel": generator.UnderToCamel,
"unmapped_type_for_serializer": GetUnmappedTypeForSerializer,
+ "wtf_hash_fn_name_for_enum": GetWtfHashFnNameForEnum,
}
def GetExtraTraitsHeaders(self):
extra_headers = set()
- for entry in self.typemap.itervalues():
- extra_headers.update(entry.get("traits_headers", []))
- return list(extra_headers)
+ for typemap in self._GetAllUsedTypemaps():
+ extra_headers.update(typemap.get("traits_headers", []))
+ return sorted(extra_headers)
+
+ def _GetAllUsedTypemaps(self):
+ """Returns the typemaps for types needed for serialization in this module.
+
+ A type is needed for serialization if it is contained by a struct or union
+ defined in this module, is a parameter of a message in an interface in
+ this module or is contained within another type needed for serialization.
+ """
+ used_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)):
+ pass
+ elif mojom.IsArrayKind(kind):
+ AddKind(kind.kind)
+ elif mojom.IsMapKind(kind):
+ AddKind(kind.key_kind)
+ AddKind(kind.value_kind)
+ else:
+ name = GetFullMojomNameForKind(kind)
+ if name in seen_types:
+ return
+ seen_types.add(name)
+
+ typemap = _current_typemap.get(name, None)
+ if typemap:
+ used_typemaps.append(typemap)
+ if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
+ for field in kind.fields:
+ AddKind(field.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 + (method.response_parameters or []):
+ AddKind(parameter.kind)
+
+ return used_typemaps
def GetExtraPublicHeaders(self):
- extra_headers = set()
- for entry in self.typemap.itervalues():
- extra_headers.update(entry.get("public_headers", []))
- return list(extra_headers)
+ 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)
+
+ types = set(GetFullMojomNameForKind(typename)
+ for typename in
+ self.module.structs + all_enums + self.module.unions)
+ headers = set()
+ for typename, typemap in self.typemap.iteritems():
+ if typename in types:
+ headers.update(typemap.get("public_headers", []))
+ return sorted(headers)
+
+ def _GetDirectlyUsedKinds(self):
+ for struct in self.module.structs + self.module.unions:
+ for field in struct.fields:
+ yield field.kind
+
+ for interface in self.module.interfaces:
+ for method in interface.methods:
+ for param in method.parameters + (method.response_parameters or []):
+ yield param.kind
def GetJinjaExports(self):
+ structs = self.GetStructs()
+ interfaces = self.GetInterfaces()
+ all_enums = list(self.module.enums)
+ for struct in structs:
+ all_enums.extend(struct.enums)
+ for interface in interfaces:
+ all_enums.extend(interface.enums)
+
return {
"module": self.module,
"namespace": self.module.namespace,
@@ -461,14 +749,17 @@ class Generator(generator.Generator):
"imports": self.module.imports,
"kinds": self.module.kinds,
"enums": self.module.enums,
- "structs": self.GetStructs(),
+ "all_enums": all_enums,
+ "structs": structs,
"unions": self.GetUnions(),
- "interfaces": self.GetInterfaces(),
+ "interfaces": interfaces,
"variant": self.variant,
"extra_traits_headers": self.GetExtraTraitsHeaders(),
"extra_public_headers": self.GetExtraPublicHeaders(),
"for_blink": self.for_blink,
- "use_new_wrapper_types": self.use_new_wrapper_types,
+ "use_once_callback": self.use_once_callback,
+ "export_attribute": self.export_attribute,
+ "export_header": self.export_header,
}
@staticmethod
@@ -483,27 +774,45 @@ class Generator(generator.Generator):
def GenerateModuleHeader(self):
return self.GetJinjaExports()
- @UseJinja("module-internal.h.tmpl")
- def GenerateModuleInternalHeader(self):
- return self.GetJinjaExports()
-
@UseJinja("module.cc.tmpl")
def GenerateModuleSource(self):
return self.GetJinjaExports()
+ @UseJinja("module-shared.h.tmpl")
+ def GenerateModuleSharedHeader(self):
+ return self.GetJinjaExports()
+
+ @UseJinja("module-shared-internal.h.tmpl")
+ def GenerateModuleSharedInternalHeader(self):
+ return self.GetJinjaExports()
+
+ @UseJinja("module-shared.cc.tmpl")
+ def GenerateModuleSharedSource(self):
+ return self.GetJinjaExports()
+
def GenerateFiles(self, args):
- global _current_typemap
- _current_typemap = self.typemap
- global _for_blink
- _for_blink = self.for_blink
- global _use_new_wrapper_types
- _use_new_wrapper_types = self.use_new_wrapper_types
- global _variant
- _variant = self.variant
- suffix = "-%s" % self.variant if self.variant else ""
- self.Write(self.GenerateModuleHeader(),
- self.MatchMojomFilePath("%s%s.h" % (self.module.name, suffix)))
- self.Write(self.GenerateModuleInternalHeader(),
- self.MatchMojomFilePath("%s%s-internal.h" % (self.module.name, suffix)))
- self.Write(self.GenerateModuleSource(),
- self.MatchMojomFilePath("%s%s.cc" % (self.module.name, suffix)))
+ if self.generate_non_variant_code:
+ self.Write(self.GenerateModuleSharedHeader(),
+ self.MatchMojomFilePath("%s-shared.h" % self.module.name))
+ self.Write(
+ self.GenerateModuleSharedInternalHeader(),
+ self.MatchMojomFilePath("%s-shared-internal.h" % self.module.name))
+ self.Write(self.GenerateModuleSharedSource(),
+ self.MatchMojomFilePath("%s-shared.cc" % self.module.name))
+ else:
+ global _current_typemap
+ _current_typemap = self.typemap
+ global _for_blink
+ _for_blink = self.for_blink
+ global _use_once_callback
+ _use_once_callback = self.use_once_callback
+ global _variant
+ _variant = self.variant
+ global _export_attribute
+ _export_attribute = self.export_attribute
+ suffix = "-%s" % self.variant if self.variant else ""
+ self.Write(self.GenerateModuleHeader(),
+ self.MatchMojomFilePath("%s%s.h" % (self.module.name, suffix)))
+ self.Write(
+ self.GenerateModuleSource(),
+ self.MatchMojomFilePath("%s%s.cc" % (self.module.name, suffix)))
diff --git a/mojo/public/tools/bindings/generators/mojom_java_generator.py b/mojo/public/tools/bindings/generators/mojom_java_generator.py
index 481efbc..9265b3a 100644
--- a/mojo/public/tools/bindings/generators/mojom_java_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_java_generator.py
@@ -10,8 +10,8 @@ import contextlib
import os
import re
import shutil
+import sys
import tempfile
-import zipfile
from jinja2 import contextfilter
@@ -20,6 +20,12 @@ import mojom.generate.generator as generator
import mojom.generate.module as mojom
from mojom.generate.template_expander import UseJinja
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir,
+ os.pardir, os.pardir, os.pardir, os.pardir,
+ 'build', 'android', 'gyp'))
+
+from util import build_utils
+
GENERATOR_PREFIX = 'java'
@@ -219,8 +225,8 @@ def GetPackage(module):
return ParseStringAttribute(module.attributes['JavaPackage'])
# Default package.
if module.namespace:
- return 'org.chromium.mojom.' + module.namespace
- return 'org.chromium.mojom'
+ return 'org.chromium.' + module.namespace
+ return 'org.chromium'
def GetNameForKind(context, kind):
def _GetNameHierachy(kind):
@@ -397,14 +403,6 @@ def TempDir():
finally:
shutil.rmtree(dirname)
-def ZipContentInto(root, zip_filename):
- with zipfile.ZipFile(zip_filename, 'w') as zip_file:
- for dirname, _, files in os.walk(root):
- for filename in files:
- path = os.path.join(dirname, filename)
- path_in_archive = os.path.relpath(path, root)
- zip_file.write(path, path_in_archive)
-
class Generator(generator.Generator):
java_filters = {
@@ -533,7 +531,7 @@ class Generator(generator.Generator):
with TempDir() as temp_java_root:
self.output_dir = os.path.join(temp_java_root, package_path)
self.DoGenerateFiles();
- ZipContentInto(temp_java_root, zip_filename)
+ build_utils.ZipDir(zip_filename, temp_java_root)
if args.java_output_directory:
# If requested, generate the java files directly into indicated directory.
diff --git a/mojo/public/tools/bindings/generators/mojom_js_generator.py b/mojo/public/tools/bindings/generators/mojom_js_generator.py
index e9a4883..0eedb31 100644
--- a/mojo/public/tools/bindings/generators/mojom_js_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_js_generator.py
@@ -37,9 +37,13 @@ _kind_to_javascript_default_value = {
def JavaScriptType(kind):
+ name = []
if kind.imported_from:
- return kind.imported_from["unique_name"] + "." + kind.name
- return kind.name
+ name.append(kind.imported_from["unique_name"])
+ if kind.parent_kind:
+ name.append(kind.parent_kind.name)
+ name.append(kind.name)
+ return ".".join(name)
def JavaScriptDefaultValue(field):
@@ -58,9 +62,10 @@ def JavaScriptDefaultValue(field):
return "null"
if mojom.IsMapKind(field.kind):
return "null"
- if mojom.IsInterfaceKind(field.kind) or \
- mojom.IsInterfaceRequestKind(field.kind):
- return _kind_to_javascript_default_value[mojom.MSGPIPE]
+ if mojom.IsInterfaceKind(field.kind):
+ return "new %sPtr()" % JavaScriptType(field.kind)
+ if mojom.IsInterfaceRequestKind(field.kind):
+ return "new bindings.InterfaceRequest()"
if mojom.IsAssociatedKind(field.kind):
return "null"
if mojom.IsEnumKind(field.kind):
@@ -120,16 +125,19 @@ def CodecType(kind):
element_type = ElementCodecType(kind.kind)
return "new codec.%s(%s%s)" % (array_type, element_type, array_length)
if mojom.IsInterfaceKind(kind):
- return "codec.%s" % ("NullableInterface" if mojom.IsNullableKind(kind)
- else "Interface")
+ return "new codec.%s(%sPtr)" % (
+ "NullableInterface" if mojom.IsNullableKind(kind) else "Interface",
+ JavaScriptType(kind))
if mojom.IsInterfaceRequestKind(kind):
- return CodecType(mojom.MSGPIPE)
+ return "codec.%s" % (
+ "NullableInterfaceRequest" if mojom.IsNullableKind(kind)
+ else "InterfaceRequest")
if mojom.IsAssociatedInterfaceKind(kind):
return "codec.AssociatedInterfaceNotSupported"
if mojom.IsAssociatedInterfaceRequestKind(kind):
return "codec.AssociatedInterfaceRequestNotSupported"
if mojom.IsEnumKind(kind):
- return _kind_to_codec_type[mojom.INT32]
+ return "new codec.Enum(%s)" % JavaScriptType(kind)
if mojom.IsMapKind(kind):
map_type = "NullableMapOf" if mojom.IsNullableKind(kind) else "MapOf"
key_type = ElementCodecType(kind.key_kind)
@@ -141,9 +149,10 @@ def CodecType(kind):
def ElementCodecType(kind):
return "codec.PackedBool" if mojom.IsBoolKind(kind) else CodecType(kind)
+
def JavaScriptDecodeSnippet(kind):
if (kind in mojom.PRIMITIVES or mojom.IsUnionKind(kind) or
- mojom.IsInterfaceKind(kind) or mojom.IsAssociatedKind(kind)):
+ mojom.IsAnyInterfaceKind(kind)):
return "decodeStruct(%s)" % CodecType(kind)
if mojom.IsStructKind(kind):
return "decodeStructPointer(%s)" % JavaScriptType(kind)
@@ -156,8 +165,6 @@ def JavaScriptDecodeSnippet(kind):
return "decodeArrayPointer(%s)" % CodecType(kind.kind)
if mojom.IsUnionKind(kind):
return "decodeUnion(%s)" % CodecType(kind)
- if mojom.IsInterfaceRequestKind(kind):
- return JavaScriptDecodeSnippet(mojom.MSGPIPE)
if mojom.IsEnumKind(kind):
return JavaScriptDecodeSnippet(mojom.INT32)
raise Exception("No decode snippet for %s" % kind)
@@ -165,7 +172,7 @@ def JavaScriptDecodeSnippet(kind):
def JavaScriptEncodeSnippet(kind):
if (kind in mojom.PRIMITIVES or mojom.IsUnionKind(kind) or
- mojom.IsInterfaceKind(kind) or mojom.IsAssociatedKind(kind)):
+ mojom.IsAnyInterfaceKind(kind)):
return "encodeStruct(%s, " % CodecType(kind)
if mojom.IsUnionKind(kind):
return "encodeStruct(%s, " % JavaScriptType(kind)
@@ -178,8 +185,6 @@ def JavaScriptEncodeSnippet(kind):
return "encodeArrayPointer(codec.PackedBool, ";
if mojom.IsArrayKind(kind):
return "encodeArrayPointer(%s, " % CodecType(kind.kind)
- if mojom.IsInterfaceRequestKind(kind):
- return JavaScriptEncodeSnippet(mojom.MSGPIPE)
if mojom.IsEnumKind(kind):
return JavaScriptEncodeSnippet(mojom.INT32)
raise Exception("No encode snippet for %s" % kind)
@@ -228,6 +233,9 @@ def JavaScriptValidateArrayParams(field):
expected_dimension_sizes)
+def JavaScriptValidateEnumParams(field):
+ return JavaScriptType(field.kind)
+
def JavaScriptValidateStructParams(field):
nullable = JavaScriptNullableParam(field)
struct_type = JavaScriptType(field.kind)
@@ -248,42 +256,6 @@ def JavaScriptValidateMapParams(field):
(nullable, keys_type, values_type, values_nullable)
-def JavaScriptValidateStringParams(field):
- nullable = JavaScriptNullableParam(field)
- return "%s" % (nullable)
-
-
-def JavaScriptValidateHandleParams(field):
- nullable = JavaScriptNullableParam(field)
- return "%s" % (nullable)
-
-def JavaScriptValidateInterfaceParams(field):
- return JavaScriptValidateHandleParams(field)
-
-def JavaScriptProxyMethodParameterValue(parameter):
- name = parameter.name;
- if (mojom.IsInterfaceKind(parameter.kind)):
- type = JavaScriptType(parameter.kind)
- return "core.isHandle(%s) ? %s : connection.bindImpl" \
- "(%s, %s)" % (name, name, name, type)
- if (mojom.IsInterfaceRequestKind(parameter.kind)):
- type = JavaScriptType(parameter.kind.kind)
- return "core.isHandle(%s) ? %s : connection.bindProxy" \
- "(%s, %s)" % (name, name, name, type)
- return name;
-
-
-def JavaScriptStubMethodParameterValue(parameter):
- name = parameter.name;
- if (mojom.IsInterfaceKind(parameter.kind)):
- type = JavaScriptType(parameter.kind)
- return "connection.bindHandleToProxy(%s, %s)" % (name, type)
- if (mojom.IsInterfaceRequestKind(parameter.kind)):
- type = JavaScriptType(parameter.kind.kind)
- return "connection.bindHandleToStub(%s, %s)" % (name, type)
- return name;
-
-
def TranslateConstants(token):
if isinstance(token, (mojom.EnumValue, mojom.NamedValue)):
# Both variable and enum constants are constructed like:
@@ -316,6 +288,9 @@ def ExpressionToText(value):
def IsArrayPointerField(field):
return mojom.IsArrayKind(field.kind)
+def IsEnumField(field):
+ return mojom.IsEnumKind(field.kind)
+
def IsStringPointerField(field):
return mojom.IsStringKind(field.kind)
@@ -331,38 +306,55 @@ def IsHandleField(field):
def IsInterfaceField(field):
return mojom.IsInterfaceKind(field.kind)
+def IsInterfaceRequestField(field):
+ return mojom.IsInterfaceRequestKind(field.kind)
+
def IsUnionField(field):
return mojom.IsUnionKind(field.kind)
+def IsBoolField(field):
+ return mojom.IsBoolKind(field.kind)
+
+def IsObjectField(field):
+ return mojom.IsObjectKind(field.kind)
+
+def IsAnyHandleOrInterfaceField(field):
+ return mojom.IsAnyHandleOrInterfaceKind(field.kind)
+
+def IsEnumField(field):
+ return mojom.IsEnumKind(field.kind)
+
class Generator(generator.Generator):
js_filters = {
- "default_value": JavaScriptDefaultValue,
- "payload_size": JavaScriptPayloadSize,
"decode_snippet": JavaScriptDecodeSnippet,
+ "default_value": JavaScriptDefaultValue,
"encode_snippet": JavaScriptEncodeSnippet,
- "union_decode_snippet": JavaScriptUnionDecodeSnippet,
- "union_encode_snippet": JavaScriptUnionEncodeSnippet,
"expression_to_text": ExpressionToText,
"field_offset": JavaScriptFieldOffset,
"has_callbacks": mojom.HasCallbacks,
+ "is_any_handle_or_interface_field": IsAnyHandleOrInterfaceField,
"is_array_pointer_field": IsArrayPointerField,
+ "is_bool_field": IsBoolField,
+ "is_enum_field": IsEnumField,
+ "is_handle_field": IsHandleField,
+ "is_interface_field": IsInterfaceField,
+ "is_interface_request_field": IsInterfaceRequestField,
"is_map_pointer_field": IsMapPointerField,
- "is_struct_pointer_field": IsStructPointerField,
+ "is_object_field": IsObjectField,
"is_string_pointer_field": IsStringPointerField,
+ "is_struct_pointer_field": IsStructPointerField,
"is_union_field": IsUnionField,
- "is_handle_field": IsHandleField,
- "is_interface_field": IsInterfaceField,
"js_type": JavaScriptType,
- "js_proxy_method_parameter_value": JavaScriptProxyMethodParameterValue,
- "js_stub_method_parameter_value": JavaScriptStubMethodParameterValue,
+ "payload_size": JavaScriptPayloadSize,
"stylize_method": generator.StudlyCapsToCamel,
+ "union_decode_snippet": JavaScriptUnionDecodeSnippet,
+ "union_encode_snippet": JavaScriptUnionEncodeSnippet,
"validate_array_params": JavaScriptValidateArrayParams,
- "validate_handle_params": JavaScriptValidateHandleParams,
- "validate_interface_params": JavaScriptValidateInterfaceParams,
+ "validate_enum_params": JavaScriptValidateEnumParams,
"validate_map_params": JavaScriptValidateMapParams,
- "validate_string_params": JavaScriptValidateStringParams,
+ "validate_nullable_params": JavaScriptNullableParam,
"validate_struct_params": JavaScriptValidateStructParams,
"validate_union_params": JavaScriptValidateUnionParams,
}
diff --git a/mojo/public/tools/bindings/generators/run_cpp_generator.py b/mojo/public/tools/bindings/generators/run_cpp_generator.py
deleted file mode 100755
index 4c6f597..0000000
--- a/mojo/public/tools/bindings/generators/run_cpp_generator.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-import ast
-import os
-import sys
-
-script_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.insert(0, os.path.join(script_dir, os.pardir, "pylib"))
-
-from mojom.generate.data
-import mojom_cpp_generator
-
-def ReadDict(file):
- with open(file, 'r') as f:
- s = f.read()
- dict = ast.literal_eval(s)
- return dict
-
-dict = ReadDict(sys.argv[1])
-module = mojom.generate.data.ModuleFromData(dict)
-dir = None
-if len(sys.argv) > 2:
- dir = sys.argv[2]
-cpp = mojom_cpp_generator.Generator(module, ".", dir)
-cpp.GenerateFiles([])
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni
index d6f4f17..2466636 100644
--- a/mojo/public/tools/bindings/mojom.gni
+++ b/mojo/public/tools/bindings/mojom.gni
@@ -2,6 +2,18 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+declare_args() {
+ # Indicates whether typemapping should be supported in this build
+ # configuration. This may be disabled when building external projects which
+ # depend on //mojo but which do not need/want all of the Chromium tree
+ # dependencies that come with typemapping.
+ #
+ # Note that (perhaps obviously) a huge amount of Chromium code will not build
+ # with typemapping disabled, so it is never valid to set this to |false| in
+ # any Chromium build configuration.
+ enable_mojom_typemapping = true
+}
+
mojom_generator_root = "//mojo/public/tools/bindings"
mojom_generator_script = "$mojom_generator_root/mojom_bindings_generator.py"
mojom_generator_sources = [
@@ -12,42 +24,79 @@ mojom_generator_sources = [
"$mojom_generator_root/pylib/mojom/error.py",
"$mojom_generator_root/pylib/mojom/generate/__init__.py",
"$mojom_generator_root/pylib/mojom/generate/constant_resolver.py",
- "$mojom_generator_root/pylib/mojom/generate/data.py",
"$mojom_generator_root/pylib/mojom/generate/generator.py",
"$mojom_generator_root/pylib/mojom/generate/module.py",
"$mojom_generator_root/pylib/mojom/generate/pack.py",
"$mojom_generator_root/pylib/mojom/generate/template_expander.py",
+ "$mojom_generator_root/pylib/mojom/generate/translate.py",
"$mojom_generator_root/pylib/mojom/parse/__init__.py",
"$mojom_generator_root/pylib/mojom/parse/ast.py",
"$mojom_generator_root/pylib/mojom/parse/lexer.py",
"$mojom_generator_root/pylib/mojom/parse/parser.py",
- "$mojom_generator_root/pylib/mojom/parse/translate.py",
"$mojom_generator_script",
]
-if (!is_ios) {
- _bindings_configuration_files = [
- "//mojo/public/tools/bindings/chromium_bindings_configuration.gni",
- "//mojo/public/tools/bindings/blink_bindings_configuration.gni",
- ]
-} else {
- _bindings_configuration_files =
- [ "//mojo/public/tools/bindings/chromium_bindings_configuration.gni" ]
-}
-_bindings_configurations = []
-foreach(config_file, _bindings_configuration_files) {
- _bindings_configurations += [ read_file(config_file, "scope") ]
-}
-foreach(configuration, _bindings_configurations) {
- foreach(typemap, configuration.typemaps) {
+if (enable_mojom_typemapping) {
+ if (!is_ios) {
+ _bindings_configuration_files = [
+ "//mojo/public/tools/bindings/chromium_bindings_configuration.gni",
+ "//mojo/public/tools/bindings/blink_bindings_configuration.gni",
+ ]
+ } else {
+ _bindings_configuration_files =
+ [ "//mojo/public/tools/bindings/chromium_bindings_configuration.gni" ]
+ }
+ _bindings_configurations = []
+ foreach(config_file, _bindings_configuration_files) {
+ _bindings_configurations += [ read_file(config_file, "scope") ]
+ }
+ foreach(configuration, _bindings_configurations) {
# Check that the mojom field of each typemap refers to a mojom that exists.
- read_file(typemap.mojom, "")
+ foreach(typemap, configuration.typemaps) {
+ _typemap_config = {
+ }
+ _typemap_config = typemap.config
+ read_file(_typemap_config.mojom, "")
+ }
+ if (is_mac && defined(configuration.typemaps_mac)) {
+ foreach(typemap, configuration.typemaps_mac) {
+ _typemap_config = {
+ }
+ _typemap_config = typemap.config
+ read_file(_typemap_config.mojom, "")
+ }
+ }
}
+} else {
+ _bindings_configuration_files = []
+ _bindings_configurations = [
+ {
+ typemaps = []
+ },
+ {
+ variant = "blink"
+ for_blink = true
+ typemaps = []
+ },
+ ]
}
-# Generate C++/JavaScript/Java source files from mojom files. The output files
-# will go under the generated file directory tree with the same path as each
-# input file.
+# Generates targets for building C++, JavaScript and Java bindings from mojom
+# files. The output files will go under the generated file directory tree with
+# the same path as each input file.
+#
+# Other targets should depend on one of these generated targets (where "foo"
+# is the target name):
+#
+# foo
+# C++ and Javascript bindings. Other mojom targets should also depend on
+# this target.
+#
+# foo_blink
+# C++ bindings using Blink standard types.
+#
+# foo_java
+# Java bindings.
#
# Parameters:
#
@@ -70,20 +119,78 @@ foreach(configuration, _bindings_configurations) {
#
# visibility (optional)
#
-# use_new_wrapper_types (optional)
-# If set to true, mojom array/map/string will be mapped to STL (for
-# chromium variant) or WTF (for blink) types. Otherwise, they will be
-# mapped to mojo::Array/Map/String/etc.
+# visibility_blink (optional)
+# The value to use for visibility for the blink variant. If unset,
+# |visibility| is used.
+#
+# use_once_callback (optional)
+# If set to true, generated classes will use base::OnceCallback instead of
+# base::RepeatingCallback.
# Default value is false.
-# TODO(yzshen):
-# - flip the flag and make use_new_wrapper_types=true the default;
-# - convert all users to use the new mode;
-# - remove support for the old mode.
+# TODO(dcheng):
+# - Convert everything to use OnceCallback.
+# - Remove support for the old mode.
+#
+# cpp_only (optional)
+# If set to true, only the C++ bindings targets will be generated.
+#
+# The following parameters are used to support the component build. They are
+# needed so that bindings which are linked with a component can use the same
+# export settings for classes. The first three are for the chromium variant, and
+# the last three are for the blink variant.
+# export_class_attribute (optional)
+# The attribute to add to the class declaration. e.g. "CONTENT_EXPORT"
+# export_define (optional)
+# A define to be added to the source_set which is needed by the export
+# header. e.g. "CONTENT_IMPLEMENTATION=1"
+# export_header (optional)
+# A header to be added to the generated bindings to support the component
+# build. e.g. "content/common/content_export.h"
+# export_class_attribute_blink (optional)
+# export_define_blink (optional)
+# export_header_blink (optional)
+# These three parameters are the blink variants of the previous 3.
+#
+# The following parameters are used to correct component build dependencies.
+# They are needed so mojom-mojom dependencies follow the rule that dependencies
+# on a source set in another component are replaced by a dependency on the
+# containing component. The first two are for the chromium variant; the other
+# two are for the blink variant.
+# overridden_deps (optional)
+# The list of mojom deps to be overridden.
+# component_deps (optional)
+# The list of component deps to add to replace overridden_deps.
+# overridden_deps_blink (optional)
+# component_deps_blink (optional)
+# These two parameters are the blink variants of the previous two.
template("mojom") {
assert(
defined(invoker.sources) || defined(invoker.deps) ||
defined(invoker.public_deps),
"\"sources\" or \"deps\" must be defined for the $target_name template.")
+ if (defined(invoker.export_class_attribute) ||
+ defined(invoker.export_define) || defined(invoker.export_header)) {
+ assert(defined(invoker.export_class_attribute))
+ assert(defined(invoker.export_define))
+ assert(defined(invoker.export_header))
+ }
+ if (defined(invoker.export_class_attribute_blink) ||
+ defined(invoker.export_define_blink) ||
+ defined(invoker.export_header_blink)) {
+ assert(defined(invoker.export_class_attribute_blink))
+ assert(defined(invoker.export_define_blink))
+ assert(defined(invoker.export_header_blink))
+ }
+ if (defined(invoker.overridden_deps) || defined(invoker.component_deps)) {
+ assert(defined(invoker.overridden_deps))
+ assert(defined(invoker.component_deps))
+ }
+
+ if (defined(invoker.overridden_deps_blink) ||
+ defined(invoker.component_deps_blink)) {
+ assert(defined(invoker.overridden_deps_blink))
+ assert(defined(invoker.component_deps_blink))
+ }
all_deps = []
if (defined(invoker.deps)) {
@@ -107,8 +214,89 @@ template("mojom") {
}
}
+ # Generate code that is shared by different variants.
+ if (defined(invoker.sources)) {
+ common_generator_args = [
+ "--use_bundled_pylibs",
+ "generate",
+ "{{source}}",
+ "-d",
+ rebase_path("//", root_build_dir),
+ "-I",
+ rebase_path("//", root_build_dir),
+ "-o",
+ rebase_path(root_gen_dir),
+ "--bytecode_path",
+ rebase_path("$root_gen_dir/mojo/public/tools/bindings"),
+ ]
+
+ if (defined(invoker.import_dirs)) {
+ foreach(import_dir, invoker.import_dirs) {
+ common_generator_args += [
+ "-I",
+ rebase_path(import_dir, root_build_dir),
+ ]
+ }
+ }
+
+ generator_shared_cpp_outputs = [
+ "{{source_gen_dir}}/{{source_name_part}}.mojom-shared-internal.h",
+ "{{source_gen_dir}}/{{source_name_part}}.mojom-shared.cc",
+ "{{source_gen_dir}}/{{source_name_part}}.mojom-shared.h",
+ ]
+ generator_shared_target_name = "${target_name}_shared__generator"
+ action_foreach(generator_shared_target_name) {
+ script = mojom_generator_script
+ inputs = mojom_generator_sources
+ sources = invoker.sources
+ deps = [
+ "//mojo/public/tools/bindings:precompile_templates",
+ ]
+ outputs = generator_shared_cpp_outputs
+ args = common_generator_args
+ args += [
+ "--generate_non_variant_code",
+ "-g",
+ "c++",
+ ]
+ depfile = "{{source_gen_dir}}/${generator_shared_target_name}_{{source_name_part}}.d"
+ args += [
+ "--depfile",
+ depfile,
+ "--depfile_target",
+ "{{source_gen_dir}}/{{source_name_part}}.mojom-shared-internal.h",
+ ]
+ }
+ }
+
+ shared_cpp_sources_suffix = "shared_cpp_sources"
+ shared_cpp_sources_target_name = "${target_name}_${shared_cpp_sources_suffix}"
+ source_set(shared_cpp_sources_target_name) {
+ if (defined(invoker.testonly)) {
+ testonly = invoker.testonly
+ }
+ deps = []
+ if (defined(invoker.sources)) {
+ sources =
+ process_file_template(invoker.sources, generator_shared_cpp_outputs)
+ deps += [ ":$generator_shared_target_name" ]
+ }
+ public_deps = []
+ foreach(d, all_deps) {
+ # Resolve the name, so that a target //mojo/something becomes
+ # //mojo/something:something and we can append shared_cpp_sources_suffix
+ # to get the cpp dependency name.
+ full_name = get_label_info("$d", "label_no_toolchain")
+ public_deps += [ "${full_name}_${shared_cpp_sources_suffix}" ]
+ }
+ }
+
+ # Generate code for variants.
foreach(bindings_configuration, _bindings_configurations) {
cpp_only = false
+ if (defined(invoker.cpp_only)) {
+ cpp_only = invoker.cpp_only
+ }
variant_suffix = ""
if (defined(bindings_configuration.variant)) {
variant = bindings_configuration.variant
@@ -119,9 +307,6 @@ template("mojom") {
type_mappings_path =
"$target_gen_dir/${target_name}${variant_suffix}__type_mappings"
active_typemaps = []
- cpp_sources_suffix = "cpp_sources"
- cpp_sources_target_name =
- "${target_name}${variant_suffix}_${cpp_sources_suffix}"
enabled_sources = []
if (defined(invoker.sources)) {
generator_cpp_outputs = []
@@ -134,7 +319,6 @@ template("mojom") {
generator_cpp_outputs += [
"{{source_gen_dir}}/{{source_name_part}}.mojom${variant_dash_suffix}.cc",
"{{source_gen_dir}}/{{source_name_part}}.mojom${variant_dash_suffix}.h",
- "{{source_gen_dir}}/{{source_name_part}}.mojom${variant_dash_suffix}-internal.h",
]
enabled_sources = []
if (defined(bindings_configuration.blacklist)) {
@@ -155,10 +339,23 @@ template("mojom") {
foreach(source, enabled_sources) {
# TODO(sammc): Use a map instead of a linear scan when GN supports maps.
foreach(typemap, bindings_configuration.typemaps) {
- if (get_path_info(source, "abspath") == typemap.mojom) {
+ _typemap_config = {
+ }
+ _typemap_config = typemap.config
+ if (get_path_info(source, "abspath") == _typemap_config.mojom) {
active_typemaps += [ typemap ]
}
}
+ if (is_mac && defined(bindings_configuration.typemaps_mac)) {
+ foreach(typemap, bindings_configuration.typemaps_mac) {
+ _typemap_config = {
+ }
+ _typemap_config = typemap.config
+ if (get_path_info(source, "abspath") == _typemap_config.mojom) {
+ active_typemaps += [ typemap ]
+ }
+ }
+ }
}
if (!cpp_only) {
@@ -178,28 +375,7 @@ template("mojom") {
]
outputs = generator_cpp_outputs + generator_java_outputs +
generator_js_outputs
- args = [
- "--use_bundled_pylibs",
- "generate",
- "{{source}}",
- "-d",
- rebase_path("//", root_build_dir),
- "-I",
- rebase_path("//", root_build_dir),
- "-o",
- rebase_path(root_gen_dir),
- "--bytecode_path",
- rebase_path("$root_gen_dir/mojo/public/tools/bindings"),
- ]
-
- if (defined(invoker.import_dirs)) {
- foreach(import_dir, invoker.import_dirs) {
- args += [
- "-I",
- rebase_path(import_dir, root_build_dir),
- ]
- }
- }
+ args = common_generator_args
if (cpp_only) {
args += [
@@ -219,6 +395,14 @@ template("mojom") {
bindings_configuration.variant,
]
}
+ depfile =
+ "{{source_gen_dir}}/${generator_target_name}_{{source_name_part}}.d"
+ args += [
+ "--depfile",
+ depfile,
+ "--depfile_target",
+ "{{source_gen_dir}}/{{source_name_part}}.mojom${variant_dash_suffix}.cc",
+ ]
args += [
"--typemap",
@@ -228,11 +412,27 @@ template("mojom") {
if (defined(bindings_configuration.for_blink) &&
bindings_configuration.for_blink) {
args += [ "--for_blink" ]
+ if (defined(invoker.export_class_attribute_blink)) {
+ args += [
+ "--export_attribute",
+ invoker.export_class_attribute_blink,
+ "--export_header",
+ invoker.export_header_blink,
+ ]
+ }
+ } else {
+ if (defined(invoker.export_class_attribute)) {
+ args += [
+ "--export_attribute",
+ invoker.export_class_attribute,
+ "--export_header",
+ invoker.export_header,
+ ]
+ }
}
- if (defined(invoker.use_new_wrapper_types) &&
- invoker.use_new_wrapper_types) {
- args += [ "--use_new_wrapper_types" ]
+ if (defined(invoker.use_once_callback) && invoker.use_once_callback) {
+ args += [ "--use_once_callback" ]
}
}
}
@@ -272,27 +472,39 @@ template("mojom") {
# line length limitations.
typemap_description = []
foreach(typemap, active_typemaps) {
+ _typemap_config = {
+ }
+ _typemap_config = typemap.config
typemap_description += [ "--start-typemap" ]
- if (defined(typemap.public_headers)) {
- foreach(value, typemap.public_headers) {
+ if (defined(_typemap_config.public_headers)) {
+ foreach(value, _typemap_config.public_headers) {
typemap_description += [ "public_headers=$value" ]
}
}
- if (defined(typemap.traits_headers)) {
- foreach(value, typemap.traits_headers) {
+ if (defined(_typemap_config.traits_headers)) {
+ foreach(value, _typemap_config.traits_headers) {
typemap_description += [ "traits_headers=$value" ]
}
}
- foreach(value, typemap.type_mappings) {
+ foreach(value, _typemap_config.type_mappings) {
typemap_description += [ "type_mappings=$value" ]
}
+
+ # The typemap configuration files are not actually used as inputs here
+ # but this establishes a necessary build dependency to ensure that
+ # typemap changes force a rebuild of affected targets.
+ inputs += [ typemap.filename ]
}
args += typemap_description
}
}
source_set("${target_name}${variant_suffix}") {
- if (defined(invoker.visibility)) {
+ if (defined(bindings_configuration.for_blink) &&
+ bindings_configuration.for_blink &&
+ defined(invoker.visibility_blink)) {
+ visibility = invoker.visibility_blink
+ } else if (defined(invoker.visibility)) {
visibility = invoker.visibility
}
if (defined(invoker.testonly)) {
@@ -301,69 +513,81 @@ template("mojom") {
if (defined(invoker.sources) && !defined(bindings_configuration.variant)) {
data = process_file_template(enabled_sources, generator_js_outputs)
}
-
- public_deps = [
- ":${cpp_sources_target_name}",
- "//mojo/public/cpp/bindings",
- ]
- if (defined(invoker.deps)) {
- public_deps += invoker.deps
- }
- if (defined(invoker.public_deps)) {
- public_deps += invoker.public_deps
- }
-
- deps = []
- if (defined(invoker.sources)) {
- public_deps += [ ":$generator_target_name" ]
- }
- }
-
- # The generated C++ source files. The main reason to introduce this target
- # is so that mojo/public/cpp/bindings can depend on mojom interfaces without
- # circular dependencies. It means that the target is missing the dependency
- # on mojo/public/cpp/bindings. No external targets should depend directly on
- # this target *except* mojo/public/cpp/bindings and other *_cpp_sources
- # targets.
- source_set(cpp_sources_target_name) {
+ defines = []
if (defined(invoker.testonly)) {
testonly = invoker.testonly
}
+ if (defined(invoker.export_define)) {
+ defines += [ invoker.export_define ]
+ }
+ if (defined(invoker.export_define_blink)) {
+ defines += [ invoker.export_define_blink ]
+ }
if (enabled_sources != []) {
sources = process_file_template(enabled_sources, generator_cpp_outputs)
}
deps = [
"//mojo/public/cpp/bindings:struct_traits",
"//mojo/public/interfaces/bindings:bindings__generator",
+ "//mojo/public/interfaces/bindings:bindings_shared__generator",
]
- if (enabled_sources != []) {
- deps += [ ":$generator_target_name" ]
- }
public_deps = [
+ ":$shared_cpp_sources_target_name",
"//base",
+ "//mojo/public/cpp/bindings",
]
+ if (enabled_sources != []) {
+ public_deps += [ ":$generator_target_name" ]
+ }
foreach(d, all_deps) {
# Resolve the name, so that a target //mojo/something becomes
- # //mojo/something:something and we can append cpp_sources_suffix to
+ # //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}${variant_suffix}_${cpp_sources_suffix}" ]
+ public_deps += [ "${full_name}${variant_suffix}" ]
+ }
+ if (defined(bindings_configuration.for_blink) &&
+ bindings_configuration.for_blink) {
+ if (defined(invoker.overridden_deps_blink)) {
+ foreach(d, invoker.overridden_deps_blink) {
+ # 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}${variant_suffix}" ]
+ }
+ public_deps += invoker.component_deps_blink
+ }
+ } else {
+ if (defined(invoker.overridden_deps)) {
+ foreach(d, invoker.overridden_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}${variant_suffix}" ]
+ }
+ public_deps += invoker.component_deps
+ }
}
foreach(typemap, active_typemaps) {
- if (defined(typemap.public_headers)) {
- sources += typemap.public_headers
+ _typemap_config = {
+ }
+ _typemap_config = typemap.config
+ if (defined(_typemap_config.public_headers)) {
+ sources += _typemap_config.public_headers
}
- if (defined(typemap.traits_headers)) {
- sources += typemap.traits_headers
+ if (defined(_typemap_config.traits_headers)) {
+ sources += _typemap_config.traits_headers
}
- if (defined(typemap.sources)) {
- sources += typemap.sources
+ if (defined(_typemap_config.sources)) {
+ sources += _typemap_config.sources
}
- if (defined(typemap.public_deps)) {
- public_deps += typemap.public_deps
+ if (defined(_typemap_config.public_deps)) {
+ public_deps += _typemap_config.public_deps
}
- if (defined(typemap.deps)) {
- deps += typemap.deps
+ if (defined(_typemap_config.deps)) {
+ deps += _typemap_config.deps
}
}
if (defined(bindings_configuration.for_blink) &&
@@ -405,8 +629,8 @@ template("mojom") {
android_library(java_target_name) {
deps = [
"//base:base_java",
- "//mojo/public/java:bindings",
- "//mojo/public/java:system",
+ "//mojo/public/java:bindings_java",
+ "//mojo/public/java:system_java",
]
foreach(d, all_deps) {
diff --git a/mojo/public/tools/bindings/mojom_bindings_generator.py b/mojo/public/tools/bindings/mojom_bindings_generator.py
index 12196ba..3a0b6fc 100755
--- a/mojo/public/tools/bindings/mojom_bindings_generator.py
+++ b/mojo/public/tools/bindings/mojom_bindings_generator.py
@@ -37,10 +37,9 @@ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
from mojom.error import Error
import mojom.fileutil as fileutil
-from mojom.generate.data import OrderedModuleFromData
+from mojom.generate import translate
from mojom.generate import template_expander
from mojom.parse.parser import Parse
-from mojom.parse.translate import Translate
_BUILTIN_GENERATORS = {
@@ -102,6 +101,12 @@ def FindImportFile(rel_dir, file_name, search_rel_dirs):
class MojomProcessor(object):
+ """Parses mojom files and creates ASTs for them.
+
+ Attributes:
+ _processed_files: {Dict[str, mojom.generate.module.Module]} Mapping from
+ relative mojom filename paths to the module AST for that mojom file.
+ """
def __init__(self, should_generate):
self._should_generate = should_generate
self._processed_files = {}
@@ -136,20 +141,18 @@ class MojomProcessor(object):
tree = self._parsed_files[rel_filename.path]
dirname, name = os.path.split(rel_filename.path)
- mojom = Translate(tree, name)
- if args.debug_print_intermediate:
- pprint.PrettyPrinter().pprint(mojom)
# Process all our imports first and collect the module object for each.
# We use these to generate proper type info.
- for import_data in mojom['imports']:
+ imports = {}
+ for parsed_imp in tree.import_list:
rel_import_file = FindImportFile(
RelativePath(dirname, rel_filename.source_root),
- import_data['filename'], args.import_directories)
- import_data['module'] = self._GenerateModule(
+ parsed_imp.import_filename, args.import_directories)
+ imports[parsed_imp.import_filename] = self._GenerateModule(
args, remaining_args, generator_modules, rel_import_file)
- module = OrderedModuleFromData(mojom)
+ module = translate.OrderedModule(tree, name, imports)
# Set the path as relative to the source root.
module.path = rel_filename.relative_path()
@@ -163,7 +166,10 @@ class MojomProcessor(object):
module, args.output_dir, typemap=self._typemap.get(language, {}),
variant=args.variant, bytecode_path=args.bytecode_path,
for_blink=args.for_blink,
- use_new_wrapper_types=args.use_new_wrapper_types)
+ use_once_callback=args.use_once_callback,
+ export_attribute=args.export_attribute,
+ export_header=args.export_header,
+ generate_non_variant_code=args.generate_non_variant_code)
filtered_args = []
if hasattr(generator_module, 'GENERATOR_PREFIX'):
prefix = '--' + generator_module.GENERATOR_PREFIX + '_'
@@ -190,7 +196,7 @@ class MojomProcessor(object):
with open(rel_filename.path) as f:
source = f.read()
except IOError as e:
- print "%s: Error: %s" % (e.rel_filename.path, e.strerror) + \
+ print "%s: Error: %s" % (rel_filename.path, e.strerror) + \
MakeImportStackMessage(imported_filename_stack + [rel_filename.path])
sys.exit(1)
@@ -230,6 +236,12 @@ def _Generate(args, remaining_args):
processor.LoadTypemaps(set(args.typemaps))
for filename in args.filename:
processor.ProcessFile(args, remaining_args, generator_modules, filename)
+ if args.depfile:
+ assert args.depfile_target
+ with open(args.depfile, 'w') as f:
+ f.write('%s: %s' % (
+ args.depfile_target,
+ ' '.join(processor._parsed_files.keys())))
return 0
@@ -258,9 +270,6 @@ def main():
generate_parser.add_argument("-o", "--output_dir", dest="output_dir",
default=".",
help="output directory for generated files")
- generate_parser.add_argument("--debug_print_intermediate",
- action="store_true",
- help="print the intermediate representation")
generate_parser.add_argument("-g", "--generators",
dest="generators_string",
metavar="GENERATORS",
@@ -286,9 +295,25 @@ def main():
help="Use WTF types as generated types for mojo "
"string/array/map.")
generate_parser.add_argument(
- "--use_new_wrapper_types", action="store_true",
- help="Map mojom array/map/string to STL (for chromium variant) or WTF "
- "(for blink variant) types directly.")
+ "--use_once_callback", action="store_true",
+ help="Use base::OnceCallback instead of base::RepeatingCallback.")
+ generate_parser.add_argument(
+ "--export_attribute", type=str, default="",
+ help="Optional attribute to specify on class declaration to export it "
+ "for the component build.")
+ generate_parser.add_argument(
+ "--export_header", type=str, default="",
+ help="Optional header to include in the generated headers to support the "
+ "component build.")
+ generate_parser.add_argument(
+ "--generate_non_variant_code", action="store_true",
+ help="Generate code that is shared by different variants.")
+ generate_parser.add_argument(
+ "--depfile", type=str,
+ help="A file into which the list of input files will be written.")
+ generate_parser.add_argument(
+ "--depfile_target", type=str,
+ help="The target name to use in the depfile.")
generate_parser.set_defaults(func=_Generate)
precompile_parser = subparsers.add_parser("precompile",
diff --git a/mojo/public/tools/bindings/mojom_list_outputs.py b/mojo/public/tools/bindings/mojom_list_outputs.py
deleted file mode 100755
index 267bd80..0000000
--- a/mojo/public/tools/bindings/mojom_list_outputs.py
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import argparse
-import os.path
-import sys
-
-def main():
- parser = argparse.ArgumentParser(
- description="GYP helper script for mapping mojoms => generated outputs.")
- parser.add_argument("--basedir", required=True)
- parser.add_argument("--variant", required=True)
- parser.add_argument("mojom", nargs="*")
-
- args = parser.parse_args()
-
- variant = args.variant if args.variant != "none" else None
-
- for mojom in args.mojom:
- full = os.path.join("<(SHARED_INTERMEDIATE_DIR)", args.basedir, mojom)
- base, ext = os.path.splitext(full)
-
- # Ignore non-mojom files.
- if ext != ".mojom":
- continue
-
- # Fix filename escaping issues on Windows.
- base = base.replace("\\", "/")
- if variant:
- print base + ".mojom-%s.cc" % variant
- print base + ".mojom-%s.h" % variant
- print base + ".mojom-%s-internal.h" % variant
- else:
- print base + ".mojom.cc"
- print base + ".mojom.h"
- print base + ".mojom-internal.h"
- print base + ".mojom.js"
-
- return 0
-
-if __name__ == "__main__":
- sys.exit(main())
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/data.py b/mojo/public/tools/bindings/pylib/mojom/generate/data.py
deleted file mode 100644
index 9ceb2e9..0000000
--- a/mojo/public/tools/bindings/pylib/mojom/generate/data.py
+++ /dev/null
@@ -1,530 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# TODO(vtl): "data" is a pretty vague name. Rename it?
-
-import copy
-
-import module as mojom
-
-# This module provides a mechanism to turn mojom Modules to dictionaries and
-# back again. This can be used to persist a mojom Module created progromatically
-# or to read a dictionary from code or a file.
-# Example:
-# test_dict = {
-# 'name': 'test',
-# 'namespace': 'testspace',
-# 'structs': [{
-# 'name': 'teststruct',
-# 'fields': [
-# {'name': 'testfield1', 'kind': 'i32'},
-# {'name': 'testfield2', 'kind': 'a:i32', 'ordinal': 42}]}],
-# 'interfaces': [{
-# 'name': 'Server',
-# 'methods': [{
-# 'name': 'Foo',
-# 'parameters': [{
-# 'name': 'foo', 'kind': 'i32'},
-# {'name': 'bar', 'kind': 'a:x:teststruct'}],
-# 'ordinal': 42}]}]
-# }
-# test_module = data.ModuleFromData(test_dict)
-
-# Used to create a subclass of str that supports sorting by index, to make
-# pretty printing maintain the order.
-def istr(index, string):
- class IndexedString(str):
- def __lt__(self, other):
- return self.__index__ < other.__index__
-
- rv = IndexedString(string)
- rv.__index__ = index
- return rv
-
-def AddOptional(dictionary, key, value):
- if value is not None:
- dictionary[key] = value;
-
-builtin_values = frozenset([
- "double.INFINITY",
- "double.NEGATIVE_INFINITY",
- "double.NAN",
- "float.INFINITY",
- "float.NEGATIVE_INFINITY",
- "float.NAN"])
-
-def IsBuiltinValue(value):
- return value in builtin_values
-
-def LookupKind(kinds, spec, scope):
- """Tries to find which Kind a spec refers to, given the scope in which its
- referenced. Starts checking from the narrowest scope to most general. For
- example, given a struct field like
- Foo.Bar x;
- Foo.Bar could refer to the type 'Bar' in the 'Foo' namespace, or an inner
- type 'Bar' in the struct 'Foo' in the current namespace.
-
- |scope| is a tuple that looks like (namespace, struct/interface), referring
- to the location where the type is referenced."""
- if spec.startswith('x:'):
- name = spec[2:]
- for i in xrange(len(scope), -1, -1):
- test_spec = 'x:'
- if i > 0:
- test_spec += '.'.join(scope[:i]) + '.'
- test_spec += name
- kind = kinds.get(test_spec)
- if kind:
- return kind
-
- return kinds.get(spec)
-
-def LookupValue(values, 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 name:
- name = '%s.%s' % (kind.spec.split(':', 1)[1], name)
- for i in reversed(xrange(len(scope) + 1)):
- test_spec = '.'.join(scope[:i])
- if test_spec:
- test_spec += '.'
- test_spec += name
- value = values.get(test_spec)
- if value:
- return value
-
- return values.get(name)
-
-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
-
-def KindToData(kind):
- return kind.spec
-
-def KindFromData(kinds, data, scope):
- kind = LookupKind(kinds, data, scope)
- if kind:
- return kind
-
- if data.startswith('?'):
- kind = KindFromData(kinds, data[1:], scope).MakeNullableKind()
- elif data.startswith('a:'):
- kind = mojom.Array(KindFromData(kinds, data[2:], scope))
- elif data.startswith('asso:'):
- inner_kind = KindFromData(kinds, data[5:], scope)
- if isinstance(inner_kind, mojom.InterfaceRequest):
- kind = mojom.AssociatedInterfaceRequest(inner_kind)
- else:
- kind = mojom.AssociatedInterface(inner_kind)
- elif data.startswith('a'):
- colon = data.find(':')
- length = int(data[1:colon])
- kind = mojom.Array(KindFromData(kinds, data[colon+1:], scope), length)
- elif data.startswith('r:'):
- kind = mojom.InterfaceRequest(KindFromData(kinds, data[2:], scope))
- elif data.startswith('m['):
- # Isolate the two types from their brackets.
-
- # It is not allowed to use map as key, so there shouldn't be nested ']'s
- # inside the key type spec.
- key_end = data.find(']')
- assert key_end != -1 and key_end < len(data) - 1
- assert data[key_end+1] == '[' and data[-1] == ']'
-
- first_kind = data[2:key_end]
- second_kind = data[key_end+2:-1]
-
- kind = mojom.Map(KindFromData(kinds, first_kind, scope),
- KindFromData(kinds, second_kind, scope))
- else:
- kind = mojom.Kind(data)
-
- kinds[data] = kind
- return kind
-
-def KindFromImport(original_kind, imported_from):
- """Used with 'import module' - clones the kind imported from the given
- module's namespace. Only used with Structs, Unions, Interfaces and Enums."""
- kind = copy.copy(original_kind)
- # |shared_definition| is used to store various properties (see
- # |AddSharedProperty()| in module.py), including |imported_from|. We don't
- # want the copy to share these with the original, so copy it if necessary.
- if hasattr(original_kind, 'shared_definition'):
- kind.shared_definition = copy.copy(original_kind.shared_definition)
- kind.imported_from = imported_from
- return kind
-
-def ImportFromData(module, data):
- import_module = data['module']
-
- import_item = {}
- import_item['module_name'] = import_module.name
- import_item['namespace'] = import_module.namespace
- import_item['module'] = import_module
-
- # Copy the struct kinds from our imports into the current module.
- importable_kinds = (mojom.Struct, mojom.Union, mojom.Enum, mojom.Interface)
- for kind in import_module.kinds.itervalues():
- if (isinstance(kind, importable_kinds) and
- kind.imported_from is None):
- kind = KindFromImport(kind, import_item)
- module.kinds[kind.spec] = kind
- # Ditto for values.
- for value in import_module.values.itervalues():
- if value.imported_from is None:
- # Values don't have shared definitions (since they're not nullable), so no
- # need to do anything special.
- value = copy.copy(value)
- value.imported_from = import_item
- module.values[value.GetSpec()] = value
-
- return import_item
-
-def StructToData(struct):
- data = {
- istr(0, 'name'): struct.name,
- istr(1, 'fields'): map(FieldToData, struct.fields),
- # TODO(yzshen): EnumToData() and ConstantToData() are missing.
- istr(2, 'enums'): [],
- istr(3, 'constants'): []
- }
- AddOptional(data, istr(4, 'attributes'), struct.attributes)
- return data
-
-def StructFromData(module, data):
- struct = mojom.Struct(module=module)
- struct.name = data['name']
- struct.native_only = data['native_only']
- struct.spec = 'x:' + module.namespace + '.' + struct.name
- module.kinds[struct.spec] = struct
- if struct.native_only:
- struct.enums = []
- struct.constants = []
- struct.fields_data = []
- else:
- struct.enums = map(lambda enum:
- EnumFromData(module, enum, struct), data['enums'])
- struct.constants = map(lambda constant:
- ConstantFromData(module, constant, struct), data['constants'])
- # Stash fields data here temporarily.
- struct.fields_data = data['fields']
- struct.attributes = data.get('attributes')
-
- # Enforce that a [Native] attribute is set to make native-only struct
- # declarations more explicit.
- if struct.native_only:
- if not struct.attributes or not struct.attributes.get('Native', False):
- raise Exception("Native-only struct declarations must include a " +
- "Native attribute.")
-
- return struct
-
-def UnionToData(union):
- data = {
- istr(0, 'name'): union.name,
- istr(1, 'fields'): map(FieldToData, union.fields)
- }
- AddOptional(data, istr(2, 'attributes'), union.attributes)
- return data
-
-def UnionFromData(module, data):
- union = mojom.Union(module=module)
- union.name = data['name']
- union.spec = 'x:' + module.namespace + '.' + union.name
- module.kinds[union.spec] = union
- # Stash fields data here temporarily.
- union.fields_data = data['fields']
- union.attributes = data.get('attributes')
- return union
-
-def FieldToData(field):
- data = {
- istr(0, 'name'): field.name,
- istr(1, 'kind'): KindToData(field.kind)
- }
- AddOptional(data, istr(2, 'ordinal'), field.ordinal)
- AddOptional(data, istr(3, 'default'), field.default)
- AddOptional(data, istr(4, 'attributes'), field.attributes)
- return data
-
-def StructFieldFromData(module, data, struct):
- field = mojom.StructField()
- PopulateField(field, module, data, struct)
- return field
-
-def UnionFieldFromData(module, data, union):
- field = mojom.UnionField()
- PopulateField(field, module, data, union)
- return field
-
-def PopulateField(field, module, data, parent):
- field.name = data['name']
- field.kind = KindFromData(
- module.kinds, data['kind'], (module.namespace, parent.name))
- field.ordinal = data.get('ordinal')
- field.default = FixupExpression(
- module, data.get('default'), (module.namespace, parent.name), field.kind)
- field.attributes = data.get('attributes')
-
-def ParameterToData(parameter):
- data = {
- istr(0, 'name'): parameter.name,
- istr(1, 'kind'): parameter.kind.spec
- }
- AddOptional(data, istr(2, 'ordinal'), parameter.ordinal)
- AddOptional(data, istr(3, 'default'), parameter.default)
- AddOptional(data, istr(4, 'attributes'), parameter.attributes)
- return data
-
-def ParameterFromData(module, data, interface):
- parameter = mojom.Parameter()
- parameter.name = data['name']
- parameter.kind = KindFromData(
- module.kinds, data['kind'], (module.namespace, interface.name))
- parameter.ordinal = data.get('ordinal')
- parameter.default = data.get('default')
- parameter.attributes = data.get('attributes')
- return parameter
-
-def MethodToData(method):
- data = {
- istr(0, 'name'): method.name,
- istr(1, 'parameters'): map(ParameterToData, method.parameters)
- }
- if method.response_parameters is not None:
- data[istr(2, 'response_parameters')] = map(
- ParameterToData, method.response_parameters)
- AddOptional(data, istr(3, 'ordinal'), method.ordinal)
- AddOptional(data, istr(4, 'attributes'), method.attributes)
- return data
-
-def MethodFromData(module, data, interface):
- method = mojom.Method(interface, data['name'], ordinal=data.get('ordinal'))
- method.parameters = map(lambda parameter:
- ParameterFromData(module, parameter, interface), data['parameters'])
- if data.has_key('response_parameters'):
- method.response_parameters = map(
- lambda parameter: ParameterFromData(module, parameter, interface),
- data['response_parameters'])
- method.attributes = data.get('attributes')
-
- # Enforce that only methods with response can have a [Sync] attribute.
- if method.sync and method.response_parameters is None:
- raise Exception("Only methods with response can include a [Sync] "
- "attribute. If no response parameters are needed, you "
- "could use an empty response parameter list, i.e., "
- "\"=> ()\".")
-
- return method
-
-def InterfaceToData(interface):
- data = {
- istr(0, 'name'): interface.name,
- istr(1, 'methods'): map(MethodToData, interface.methods),
- # TODO(yzshen): EnumToData() and ConstantToData() are missing.
- istr(2, 'enums'): [],
- istr(3, 'constants'): []
- }
- AddOptional(data, istr(4, 'attributes'), interface.attributes)
- return data
-
-def InterfaceFromData(module, data):
- interface = mojom.Interface(module=module)
- interface.name = data['name']
- interface.spec = 'x:' + module.namespace + '.' + interface.name
- module.kinds[interface.spec] = interface
- interface.enums = map(lambda enum:
- EnumFromData(module, enum, interface), data['enums'])
- interface.constants = map(lambda constant:
- ConstantFromData(module, constant, interface), data['constants'])
- # Stash methods data here temporarily.
- interface.methods_data = data['methods']
- interface.attributes = data.get('attributes')
- return interface
-
-def EnumFieldFromData(module, enum, data, parent_kind):
- field = mojom.EnumField()
- field.name = data['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, data.get('value'), (module.namespace, parent_kind.name), enum)
- else:
- field.value = FixupExpression(
- module, data.get('value'), (module.namespace, ), enum)
- field.attributes = data.get('attributes')
- value = mojom.EnumValue(module, enum, field)
- module.values[value.GetSpec()] = value
- return field
-
-def ResolveNumericEnumValues(enum_fields):
- """
- Given a reference to a list of mojom.EnumField, resolves and assigns their
- values to EnumField.numeric_value.
- """
-
- # map of <name> -> integral value
- resolved_enum_values = {}
- prev_value = -1
- 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 type(field.value) is str:
- prev_value = int(field.value, 0)
-
- # Reference to a previous enum value (e.g: INIT = BEGIN).
- elif type(field.value) is mojom.EnumValue:
- prev_value = resolved_enum_values[field.value.name]
- else:
- raise Exception("Unresolved enum value.")
-
- resolved_enum_values[field.name] = prev_value
- field.numeric_value = prev_value
-
-def EnumFromData(module, data, parent_kind):
- enum = mojom.Enum(module=module)
- enum.name = data['name']
- enum.native_only = data['native_only']
- name = enum.name
- if parent_kind:
- name = parent_kind.name + '.' + name
- enum.spec = 'x:%s.%s' % (module.namespace, name)
- enum.parent_kind = parent_kind
- enum.attributes = data.get('attributes')
- if enum.native_only:
- enum.fields = []
- else:
- enum.fields = map(
- lambda field: EnumFieldFromData(module, enum, field, parent_kind),
- data['fields'])
- ResolveNumericEnumValues(enum.fields)
-
- module.kinds[enum.spec] = enum
-
- # Enforce that a [Native] attribute is set to make native-only enum
- # declarations more explicit.
- if enum.native_only:
- if not enum.attributes or not enum.attributes.get('Native', False):
- raise Exception("Native-only enum declarations must include a " +
- "Native attribute.")
-
- return enum
-
-def ConstantFromData(module, data, parent_kind):
- constant = mojom.Constant()
- constant.name = data['name']
- if parent_kind:
- scope = (module.namespace, parent_kind.name)
- else:
- scope = (module.namespace, )
- # TODO(mpcomplete): maybe we should only support POD kinds.
- constant.kind = KindFromData(module.kinds, data['kind'], scope)
- constant.parent_kind = parent_kind
- constant.value = FixupExpression(module, data.get('value'), scope, None)
-
- value = mojom.ConstantValue(module, parent_kind, constant)
- module.values[value.GetSpec()] = value
- return constant
-
-def ModuleToData(module):
- data = {
- istr(0, 'name'): module.name,
- istr(1, 'namespace'): module.namespace,
- # TODO(yzshen): Imports information is missing.
- istr(2, 'imports'): [],
- istr(3, 'structs'): map(StructToData, module.structs),
- istr(4, 'unions'): map(UnionToData, module.unions),
- istr(5, 'interfaces'): map(InterfaceToData, module.interfaces),
- # TODO(yzshen): EnumToData() and ConstantToData() are missing.
- istr(6, 'enums'): [],
- istr(7, 'constants'): []
- }
- AddOptional(data, istr(8, 'attributes'), module.attributes)
- return data
-
-def ModuleFromData(data):
- module = mojom.Module()
- module.kinds = {}
- for kind in mojom.PRIMITIVES:
- module.kinds[kind.spec] = kind
-
- module.values = {}
-
- module.name = data['name']
- module.namespace = data['namespace']
- # Imports must come first, because they add to module.kinds which is used
- # by by the others.
- module.imports = map(
- lambda import_data: ImportFromData(module, import_data),
- data['imports'])
- module.attributes = data.get('attributes')
-
- # First pass collects kinds.
- module.enums = map(
- lambda enum: EnumFromData(module, enum, None), data['enums'])
- module.structs = map(
- lambda struct: StructFromData(module, struct), data['structs'])
- module.unions = map(
- lambda union: UnionFromData(module, union), data.get('unions', []))
- module.interfaces = map(
- lambda interface: InterfaceFromData(module, interface),
- data['interfaces'])
- module.constants = map(
- lambda constant: ConstantFromData(module, constant, None),
- data['constants'])
-
- # Second pass expands fields and methods. This allows fields and parameters
- # to refer to kinds defined anywhere in the mojom.
- for struct in module.structs:
- struct.fields = map(lambda field:
- StructFieldFromData(module, field, struct), struct.fields_data)
- del struct.fields_data
- for union in module.unions:
- union.fields = map(lambda field:
- UnionFieldFromData(module, field, union), union.fields_data)
- del union.fields_data
- for interface in module.interfaces:
- interface.methods = map(lambda method:
- MethodFromData(module, method, interface), interface.methods_data)
- del interface.methods_data
-
- return module
-
-def OrderedModuleFromData(data):
- """Convert Mojom IR to a module.
-
- Args:
- data: The Mojom IR as a dict.
-
- Returns:
- A mojom.generate.module.Module object.
- """
- module = ModuleFromData(data)
- for interface in module.interfaces:
- next_ordinal = 0
- for method in interface.methods:
- if method.ordinal is None:
- method.ordinal = next_ordinal
- next_ordinal = method.ordinal + 1
- return module
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/data_tests.py b/mojo/public/tools/bindings/pylib/mojom/generate/data_tests.py
deleted file mode 100644
index 096554c..0000000
--- a/mojo/public/tools/bindings/pylib/mojom/generate/data_tests.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import sys
-
-import data
-import test_support
-
-EXPECT_EQ = test_support.EXPECT_EQ
-EXPECT_TRUE = test_support.EXPECT_TRUE
-RunTest = test_support.RunTest
-
-
-def DeepEquals(d1, d2):
- if d1 == d2:
- return True
- if d2.__class__ != d2.__class__:
- return False
- if isinstance(d1, dict):
- if set(d1.keys()) != set(d2.keys()):
- return False
- for key in d1.keys():
- if not DeepEquals(d1[key], d2[key]):
- return False
- return True
- if isinstance(d1, (list, tuple)):
- if len(d1) != len(d2):
- return False
- for i in range(len(d1)):
- if not DeepEquals(d1[i], d2[i]):
- return False
- return True
- return False
-
-
-test_dict = {
- 'name': 'test',
- 'namespace': 'testspace',
- 'structs': [{
- 'name': 'teststruct',
- 'fields': [
- {'name': 'testfield1', 'kind': 'i32'},
- {'name': 'testfield2', 'kind': 'a:i32', 'ordinal': 42}]}],
- 'interfaces': [{
- 'name': 'Server',
- 'client': None,
- 'methods': [{
- 'name': 'Foo',
- 'parameters': [
- {'name': 'foo', 'kind': 'i32'},
- {'name': 'bar', 'kind': 'a:x:teststruct'}],
- 'ordinal': 42}]}]
-}
-
-
-def TestRead():
- module = data.ModuleFromData(test_dict)
- return test_support.TestTestModule(module)
-
-
-def TestWrite():
- module = test_support.BuildTestModule()
- d = data.ModuleToData(module)
- return EXPECT_TRUE(DeepEquals(test_dict, d))
-
-
-def TestWriteRead():
- module1 = test_support.BuildTestModule()
-
- dict1 = data.ModuleToData(module1)
- module2 = data.ModuleFromData(dict1)
- return EXPECT_TRUE(test_support.ModulesAreEqual(module1, module2))
-
-
-def Main(args):
- errors = 0
- errors += RunTest(TestWriteRead)
- errors += RunTest(TestRead)
- errors += RunTest(TestWrite)
-
- return errors
-
-
-if __name__ == '__main__':
- sys.exit(Main(sys.argv[1:]))
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/generator.py b/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
index ccb8363..e4ab373 100644
--- a/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
@@ -37,15 +37,19 @@ class Generator(object):
# Pass |output_dir| to emit files to disk. Omit |output_dir| to echo all
# files to stdout.
def __init__(self, module, output_dir=None, typemap=None, variant=None,
- bytecode_path=None, for_blink=False,
- use_new_wrapper_types=False):
+ bytecode_path=None, for_blink=False, use_once_callback=False,
+ export_attribute=None, export_header=None,
+ generate_non_variant_code=False):
self.module = module
self.output_dir = output_dir
self.typemap = typemap or {}
self.variant = variant
self.bytecode_path = bytecode_path
self.for_blink = for_blink
- self.use_new_wrapper_types = use_new_wrapper_types
+ self.use_once_callback = use_once_callback
+ self.export_attribute = export_attribute
+ self.export_header = export_header
+ self.generate_non_variant_code = generate_non_variant_code
def GetStructsFromMethods(self):
result = []
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/mojo/public/tools/bindings/pylib/mojom/generate/module.py
index 2775b6c..3a5f188 100644
--- a/mojo/public/tools/bindings/pylib/mojom/generate/module.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/module.py
@@ -294,6 +294,20 @@ class UnionField(Field): pass
class Struct(ReferenceKind):
+ """A struct with typed fields.
+
+ Attributes:
+ name: {str} The name of the struct type.
+ native_only: {bool} Does the struct have a body (i.e. any fields) or is it
+ purely a native struct.
+ module: {Module} The defining module.
+ imported_from: {dict} Information about where this union was
+ imported from.
+ fields: {List[StructField]} The members of the struct.
+ attributes: {dict} Additional information about the struct, such as
+ if it's a native struct.
+ """
+
ReferenceKind.AddSharedProperty('name')
ReferenceKind.AddSharedProperty('native_only')
ReferenceKind.AddSharedProperty('module')
@@ -425,14 +439,9 @@ class Map(ReferenceKind):
']')
if IsNullableKind(key_kind):
raise Exception("Nullable kinds cannot be keys in maps.")
- if IsStructKind(key_kind):
- # TODO(erg): It would sometimes be nice if we could key on struct
- # values. However, what happens if the struct has a handle in it? Or
- # non-copyable data like an array?
- raise Exception("Structs cannot be keys in maps.")
if IsAnyHandleKind(key_kind):
raise Exception("Handles cannot be keys in maps.")
- if IsInterfaceKind(key_kind):
+ if IsAnyInterfaceKind(key_kind):
raise Exception("Interfaces cannot be keys in maps.")
if IsArrayKind(key_kind):
raise Exception("Arrays cannot be keys in maps.")
@@ -681,6 +690,10 @@ def IsFloatKind(kind):
return kind.spec == FLOAT.spec
+def IsDoubleKind(kind):
+ return kind.spec == DOUBLE.spec
+
+
def IsIntegralKind(kind):
return (kind.spec == BOOL.spec or
kind.spec == INT8.spec or
@@ -771,22 +784,24 @@ def IsPointerKind(kind):
IsMapKind(kind))
-# Please note that interface is not considered as handle kind, since it is an
-# aggregate type consisting of a handle and a version number.
+# Please note that it doesn't include any interface kind.
def IsAnyHandleKind(kind):
return (IsGenericHandleKind(kind) or
IsDataPipeConsumerKind(kind) or
IsDataPipeProducerKind(kind) or
IsMessagePipeKind(kind) or
- IsSharedBufferKind(kind) or
- IsInterfaceRequestKind(kind))
+ IsSharedBufferKind(kind))
-def IsAnyHandleOrInterfaceKind(kind):
- return (IsAnyHandleKind(kind) or IsInterfaceKind(kind) or
+def IsAnyInterfaceKind(kind):
+ return (IsInterfaceKind(kind) or IsInterfaceRequestKind(kind) or
IsAssociatedKind(kind))
+def IsAnyHandleOrInterfaceKind(kind):
+ return IsAnyHandleKind(kind) or IsAnyInterfaceKind(kind)
+
+
def IsAssociatedKind(kind):
return (IsAssociatedInterfaceKind(kind) or
IsAssociatedInterfaceRequestKind(kind))
@@ -838,3 +853,39 @@ def HasSyncMethods(interface):
if method.sync:
return True
return False
+
+
+def ContainsHandlesOrInterfaces(kind):
+ """Check if the kind contains any handles.
+
+ This check is recursive so it checks all struct fields, containers elements,
+ etc.
+
+ Args:
+ struct: {Kind} The kind to check.
+
+ Returns:
+ {bool}: True if the kind contains handles.
+ """
+ # We remember the types we already checked to avoid infinite recursion when
+ # checking recursive (or mutually recursive) types:
+ checked = set()
+ def Check(kind):
+ if kind.spec in checked:
+ return False
+ checked.add(kind.spec)
+ if IsStructKind(kind):
+ return any(Check(field.kind) for field in kind.fields)
+ elif IsUnionKind(kind):
+ return any(Check(field.kind) for field in kind.fields)
+ elif IsAnyHandleKind(kind):
+ return True
+ elif IsAnyInterfaceKind(kind):
+ return True
+ elif IsArrayKind(kind):
+ return Check(kind.kind)
+ elif IsMapKind(kind):
+ return Check(kind.key_kind) or Check(kind.value_kind)
+ else:
+ return False
+ return Check(kind)
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py b/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py
index 9ea6cf8..66f8954 100644
--- a/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py
@@ -2,8 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# Based on:
-# http://src.chromium.org/viewvc/blink/trunk/Source/build/scripts/template_expander.py
+# Based on third_party/WebKit/Source/build/scripts/template_expander.py.
import imp
import os.path
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/translate.py b/mojo/public/tools/bindings/pylib/mojom/generate/translate.py
new file mode 100644
index 0000000..ffad744
--- /dev/null
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/translate.py
@@ -0,0 +1,639 @@
+# 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.
+
+"""Convert parse tree to AST.
+
+This module converts the parse tree to the AST we use for code generation. The
+main entry point is OrderedModule, which gets passed the parser
+representation of a mojom file. When called it's assumed that all imports have
+already been parsed and converted to ASTs before.
+"""
+
+import copy
+import re
+
+import module as mojom
+from mojom.parse import ast
+
+def _DuplicateName(values):
+ """Returns the 'name' of the first entry in |values| whose 'name' has already
+ been encountered. If there are no duplicates, returns None."""
+ names = set()
+ for value in values:
+ if value.name in names:
+ return value.name
+ names.add(value.name)
+ return None
+
+def _ElemsOfType(elems, elem_type, scope):
+ """Find all elements of the given type.
+
+ Args:
+ elems: {Sequence[Any]} Sequence of elems.
+ elem_type: {Type[C]} Extract all elems of this type.
+ scope: {str} The name of the surrounding scope (e.g. struct
+ definition). Used in error messages.
+
+ Returns:
+ {List[C]} All elems of matching type.
+ """
+ assert isinstance(elem_type, type)
+ result = [elem for elem in elems if isinstance(elem, elem_type)]
+ duplicate_name = _DuplicateName(result)
+ if duplicate_name:
+ raise Exception('Names in mojom must be unique within a scope. The name '
+ '"%s" is used more than once within the scope "%s".' %
+ (duplicate_name, scope))
+ return result
+
+def _MapKind(kind):
+ map_to_kind = {'bool': 'b',
+ 'int8': 'i8',
+ 'int16': 'i16',
+ 'int32': 'i32',
+ 'int64': 'i64',
+ 'uint8': 'u8',
+ 'uint16': 'u16',
+ 'uint32': 'u32',
+ 'uint64': 'u64',
+ 'float': 'f',
+ 'double': 'd',
+ 'string': 's',
+ 'handle': 'h',
+ 'handle<data_pipe_consumer>': 'h:d:c',
+ 'handle<data_pipe_producer>': 'h:d:p',
+ 'handle<message_pipe>': 'h:m',
+ 'handle<shared_buffer>': 'h:s'}
+ if kind.endswith('?'):
+ base_kind = _MapKind(kind[0:-1])
+ # NOTE: This doesn't rule out enum types. Those will be detected later, when
+ # cross-reference is established.
+ reference_kinds = ('m', 's', 'h', 'a', 'r', 'x', 'asso')
+ if re.split('[^a-z]', base_kind, 1)[0] not in reference_kinds:
+ raise Exception(
+ 'A type (spec "%s") cannot be made nullable' % base_kind)
+ return '?' + base_kind
+ if kind.endswith('}'):
+ lbracket = kind.rfind('{')
+ value = kind[0:lbracket]
+ return 'm[' + _MapKind(kind[lbracket+1:-1]) + '][' + _MapKind(value) + ']'
+ if kind.endswith(']'):
+ lbracket = kind.rfind('[')
+ typename = kind[0:lbracket]
+ return 'a' + kind[lbracket+1:-1] + ':' + _MapKind(typename)
+ if kind.endswith('&'):
+ return 'r:' + _MapKind(kind[0:-1])
+ if kind.startswith('asso<'):
+ assert kind.endswith('>')
+ return 'asso:' + _MapKind(kind[5:-1])
+ if kind in map_to_kind:
+ return map_to_kind[kind]
+ return 'x:' + kind
+
+def _AttributeListToDict(attribute_list):
+ if attribute_list is None:
+ return None
+ assert isinstance(attribute_list, ast.AttributeList)
+ # TODO(vtl): Check for duplicate keys here.
+ return dict([(attribute.key, attribute.value)
+ for attribute in attribute_list])
+
+builtin_values = frozenset([
+ "double.INFINITY",
+ "double.NEGATIVE_INFINITY",
+ "double.NAN",
+ "float.INFINITY",
+ "float.NEGATIVE_INFINITY",
+ "float.NAN"])
+
+def _IsBuiltinValue(value):
+ return value in builtin_values
+
+def _LookupKind(kinds, spec, scope):
+ """Tries to find which Kind a spec refers to, given the scope in which its
+ referenced. Starts checking from the narrowest scope to most general. For
+ example, given a struct field like
+ Foo.Bar x;
+ Foo.Bar could refer to the type 'Bar' in the 'Foo' namespace, or an inner
+ type 'Bar' in the struct 'Foo' in the current namespace.
+
+ |scope| is a tuple that looks like (namespace, struct/interface), referring
+ to the location where the type is referenced."""
+ if spec.startswith('x:'):
+ name = spec[2:]
+ for i in xrange(len(scope), -1, -1):
+ test_spec = 'x:'
+ if i > 0:
+ test_spec += '.'.join(scope[:i]) + '.'
+ test_spec += name
+ kind = kinds.get(test_spec)
+ if kind:
+ return kind
+
+ return kinds.get(spec)
+
+def _LookupValue(values, 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 name:
+ name = '%s.%s' % (kind.spec.split(':', 1)[1], name)
+ for i in reversed(xrange(len(scope) + 1)):
+ test_spec = '.'.join(scope[:i])
+ if test_spec:
+ test_spec += '.'
+ test_spec += name
+ value = values.get(test_spec)
+ if value:
+ return value
+
+ return values.get(name)
+
+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
+
+def _Kind(kinds, spec, scope):
+ """Convert a type name into a mojom.Kind object.
+
+ As a side-effect this function adds the result to 'kinds'.
+
+ Args:
+ kinds: {Dict[str, mojom.Kind]} All known kinds up to this point, indexed by
+ their names.
+ spec: {str} A name uniquely identifying a type.
+ scope: {Tuple[str, str]} A tuple that looks like (namespace,
+ struct/interface), referring to the location where the type is
+ referenced.
+
+ Returns:
+ {mojom.Kind} The type corresponding to 'spec'.
+ """
+ kind = _LookupKind(kinds, spec, scope)
+ if kind:
+ return kind
+
+ if spec.startswith('?'):
+ kind = _Kind(kinds, spec[1:], scope).MakeNullableKind()
+ elif spec.startswith('a:'):
+ kind = mojom.Array(_Kind(kinds, spec[2:], scope))
+ elif spec.startswith('asso:'):
+ inner_kind = _Kind(kinds, spec[5:], scope)
+ if isinstance(inner_kind, mojom.InterfaceRequest):
+ kind = mojom.AssociatedInterfaceRequest(inner_kind)
+ else:
+ kind = mojom.AssociatedInterface(inner_kind)
+ elif spec.startswith('a'):
+ colon = spec.find(':')
+ length = int(spec[1:colon])
+ kind = mojom.Array(_Kind(kinds, spec[colon+1:], scope), length)
+ elif spec.startswith('r:'):
+ kind = mojom.InterfaceRequest(_Kind(kinds, spec[2:], scope))
+ elif spec.startswith('m['):
+ # Isolate the two types from their brackets.
+
+ # It is not allowed to use map as key, so there shouldn't be nested ']'s
+ # inside the key type spec.
+ key_end = spec.find(']')
+ assert key_end != -1 and key_end < len(spec) - 1
+ assert spec[key_end+1] == '[' and spec[-1] == ']'
+
+ first_kind = spec[2:key_end]
+ second_kind = spec[key_end+2:-1]
+
+ kind = mojom.Map(_Kind(kinds, first_kind, scope),
+ _Kind(kinds, second_kind, scope))
+ else:
+ kind = mojom.Kind(spec)
+
+ kinds[spec] = kind
+ return kind
+
+def _KindFromImport(original_kind, imported_from):
+ """Used with 'import module' - clones the kind imported from the given
+ module's namespace. Only used with Structs, Unions, Interfaces and Enums."""
+ kind = copy.copy(original_kind)
+ # |shared_definition| is used to store various properties (see
+ # |AddSharedProperty()| in module.py), including |imported_from|. We don't
+ # want the copy to share these with the original, so copy it if necessary.
+ if hasattr(original_kind, 'shared_definition'):
+ kind.shared_definition = copy.copy(original_kind.shared_definition)
+ kind.imported_from = imported_from
+ return kind
+
+def _Import(module, import_module):
+ import_item = {}
+ import_item['module_name'] = import_module.name
+ import_item['namespace'] = import_module.namespace
+ import_item['module'] = import_module
+
+ # Copy the struct kinds from our imports into the current module.
+ importable_kinds = (mojom.Struct, mojom.Union, mojom.Enum, mojom.Interface)
+ for kind in import_module.kinds.itervalues():
+ if (isinstance(kind, importable_kinds) and
+ kind.imported_from is None):
+ kind = _KindFromImport(kind, import_item)
+ module.kinds[kind.spec] = kind
+ # Ditto for values.
+ for value in import_module.values.itervalues():
+ if value.imported_from is None:
+ # Values don't have shared definitions (since they're not nullable), so no
+ # need to do anything special.
+ value = copy.copy(value)
+ value.imported_from = import_item
+ module.values[value.GetSpec()] = value
+
+ return import_item
+
+def _Struct(module, parsed_struct):
+ """
+ Args:
+ module: {mojom.Module} Module currently being constructed.
+ parsed_struct: {ast.Struct} Parsed struct.
+
+ Returns:
+ {mojom.Struct} AST struct.
+ """
+ struct = mojom.Struct(module=module)
+ struct.name = parsed_struct.name
+ struct.native_only = parsed_struct.body is None
+ struct.spec = 'x:' + module.namespace + '.' + struct.name
+ module.kinds[struct.spec] = struct
+ if struct.native_only:
+ struct.enums = []
+ struct.constants = []
+ struct.fields_data = []
+ else:
+ struct.enums = map(
+ lambda enum: _Enum(module, enum, struct),
+ _ElemsOfType(parsed_struct.body, ast.Enum, parsed_struct.name))
+ struct.constants = map(
+ lambda constant: _Constant(module, constant, struct),
+ _ElemsOfType(parsed_struct.body, ast.Const, parsed_struct.name))
+ # Stash fields parsed_struct here temporarily.
+ struct.fields_data = _ElemsOfType(
+ parsed_struct.body, ast.StructField, parsed_struct.name)
+ struct.attributes = _AttributeListToDict(parsed_struct.attribute_list)
+
+ # Enforce that a [Native] attribute is set to make native-only struct
+ # declarations more explicit.
+ if struct.native_only:
+ if not struct.attributes or not struct.attributes.get('Native', False):
+ raise Exception("Native-only struct declarations must include a " +
+ "Native attribute.")
+
+ return struct
+
+def _Union(module, parsed_union):
+ """
+ Args:
+ module: {mojom.Module} Module currently being constructed.
+ parsed_union: {ast.Union} Parsed union.
+
+ Returns:
+ {mojom.Union} AST union.
+ """
+ union = mojom.Union(module=module)
+ union.name = parsed_union.name
+ union.spec = 'x:' + module.namespace + '.' + union.name
+ module.kinds[union.spec] = union
+ # Stash fields parsed_union here temporarily.
+ union.fields_data = _ElemsOfType(
+ parsed_union.body, ast.UnionField, parsed_union.name)
+ union.attributes = _AttributeListToDict(parsed_union.attribute_list)
+ return union
+
+def _StructField(module, parsed_field, struct):
+ """
+ Args:
+ module: {mojom.Module} Module currently being constructed.
+ parsed_field: {ast.StructField} Parsed struct field.
+ struct: {mojom.Struct} Struct this field belongs to.
+
+ Returns:
+ {mojom.StructField} AST struct field.
+ """
+ field = mojom.StructField()
+ field.name = parsed_field.name
+ field.kind = _Kind(
+ module.kinds, _MapKind(parsed_field.typename),
+ (module.namespace, struct.name))
+ field.ordinal = parsed_field.ordinal.value if parsed_field.ordinal else None
+ field.default = _FixupExpression(
+ module, parsed_field.default_value, (module.namespace, struct.name),
+ field.kind)
+ field.attributes = _AttributeListToDict(parsed_field.attribute_list)
+ return field
+
+def _UnionField(module, parsed_field, union):
+ """
+ Args:
+ module: {mojom.Module} Module currently being constructed.
+ parsed_field: {ast.UnionField} Parsed union field.
+ union: {mojom.Union} Union this fields belong to.
+
+ Returns:
+ {mojom.UnionField} AST union.
+ """
+ field = mojom.UnionField()
+ field.name = parsed_field.name
+ field.kind = _Kind(
+ module.kinds, _MapKind(parsed_field.typename),
+ (module.namespace, union.name))
+ field.ordinal = parsed_field.ordinal.value if parsed_field.ordinal else None
+ field.default = _FixupExpression(
+ module, None, (module.namespace, union.name), field.kind)
+ field.attributes = _AttributeListToDict(parsed_field.attribute_list)
+ return field
+
+def _Parameter(module, parsed_param, interface):
+ """
+ Args:
+ module: {mojom.Module} Module currently being constructed.
+ parsed_param: {ast.Parameter} Parsed parameter.
+ union: {mojom.Interface} Interface this parameter belongs to.
+
+ Returns:
+ {mojom.Parameter} AST parameter.
+ """
+ parameter = mojom.Parameter()
+ parameter.name = parsed_param.name
+ parameter.kind = _Kind(
+ module.kinds, _MapKind(parsed_param.typename),
+ (module.namespace, interface.name))
+ parameter.ordinal = (
+ parsed_param.ordinal.value if parsed_param.ordinal else None)
+ parameter.default = None # TODO(tibell): We never have these. Remove field?
+ parameter.attributes = _AttributeListToDict(parsed_param.attribute_list)
+ return parameter
+
+def _Method(module, parsed_method, interface):
+ """
+ Args:
+ module: {mojom.Module} Module currently being constructed.
+ parsed_method: {ast.Method} Parsed method.
+ interface: {mojom.Interface} Interface this method belongs to.
+
+ Returns:
+ {mojom.Method} AST method.
+ """
+ method = mojom.Method(
+ interface, parsed_method.name,
+ ordinal=parsed_method.ordinal.value if parsed_method.ordinal else None)
+ method.parameters = map(
+ lambda parameter: _Parameter(module, parameter, interface),
+ parsed_method.parameter_list)
+ if parsed_method.response_parameter_list is not None:
+ method.response_parameters = map(
+ lambda parameter: _Parameter(module, parameter, interface),
+ parsed_method.response_parameter_list)
+ method.attributes = _AttributeListToDict(parsed_method.attribute_list)
+
+ # Enforce that only methods with response can have a [Sync] attribute.
+ if method.sync and method.response_parameters is None:
+ raise Exception("Only methods with response can include a [Sync] "
+ "attribute. If no response parameters are needed, you "
+ "could use an empty response parameter list, i.e., "
+ "\"=> ()\".")
+
+ return method
+
+def _Interface(module, parsed_iface):
+ """
+ Args:
+ module: {mojom.Module} Module currently being constructed.
+ parsed_iface: {ast.Interface} Parsed interface.
+
+ Returns:
+ {mojom.Interface} AST interface.
+ """
+ interface = mojom.Interface(module=module)
+ interface.name = parsed_iface.name
+ interface.spec = 'x:' + module.namespace + '.' + interface.name
+ module.kinds[interface.spec] = interface
+ interface.enums = map(
+ lambda enum: _Enum(module, enum, interface),
+ _ElemsOfType(parsed_iface.body, ast.Enum, parsed_iface.name))
+ interface.constants = map(
+ lambda constant: _Constant(module, constant, interface),
+ _ElemsOfType(parsed_iface.body, ast.Const, parsed_iface.name))
+ # Stash methods parsed_iface here temporarily.
+ interface.methods_data = _ElemsOfType(
+ parsed_iface.body, ast.Method, parsed_iface.name)
+ interface.attributes = _AttributeListToDict(parsed_iface.attribute_list)
+ return interface
+
+def _EnumField(module, enum, parsed_field, parent_kind):
+ """
+ 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.name = parsed_field.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.namespace, parent_kind.name), enum)
+ else:
+ field.value = _FixupExpression(
+ module, parsed_field.value, (module.namespace, ), enum)
+ field.attributes = _AttributeListToDict(parsed_field.attribute_list)
+ value = mojom.EnumValue(module, enum, field)
+ module.values[value.GetSpec()] = value
+ return field
+
+def _ResolveNumericEnumValues(enum_fields):
+ """
+ Given a reference to a list of mojom.EnumField, resolves and assigns their
+ values to EnumField.numeric_value.
+ """
+
+ # map of <name> -> integral value
+ resolved_enum_values = {}
+ prev_value = -1
+ 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 type(field.value) is str:
+ prev_value = int(field.value, 0)
+
+ # Reference to a previous enum value (e.g: INIT = BEGIN).
+ elif type(field.value) is mojom.EnumValue:
+ prev_value = resolved_enum_values[field.value.name]
+ else:
+ raise Exception("Unresolved enum value.")
+
+ resolved_enum_values[field.name] = prev_value
+ field.numeric_value = prev_value
+
+def _Enum(module, parsed_enum, parent_kind):
+ """
+ Args:
+ module: {mojom.Module} Module currently being constructed.
+ parsed_enum: {ast.Enum} Parsed enum.
+
+ Returns:
+ {mojom.Enum} AST enum.
+ """
+ enum = mojom.Enum(module=module)
+ enum.name = parsed_enum.name
+ enum.native_only = parsed_enum.enum_value_list is None
+ name = enum.name
+ if parent_kind:
+ name = parent_kind.name + '.' + name
+ enum.spec = 'x:%s.%s' % (module.namespace, name)
+ enum.parent_kind = parent_kind
+ enum.attributes = _AttributeListToDict(parsed_enum.attribute_list)
+ if enum.native_only:
+ enum.fields = []
+ else:
+ enum.fields = map(
+ lambda field: _EnumField(module, enum, field, parent_kind),
+ parsed_enum.enum_value_list)
+ _ResolveNumericEnumValues(enum.fields)
+
+ module.kinds[enum.spec] = enum
+
+ # Enforce that a [Native] attribute is set to make native-only enum
+ # declarations more explicit.
+ if enum.native_only:
+ if not enum.attributes or not enum.attributes.get('Native', False):
+ raise Exception("Native-only enum declarations must include a " +
+ "Native attribute.")
+
+ return enum
+
+def _Constant(module, parsed_const, parent_kind):
+ """
+ Args:
+ module: {mojom.Module} Module currently being constructed.
+ parsed_const: {ast.Const} Parsed constant.
+
+ Returns:
+ {mojom.Constant} AST constant.
+ """
+ constant = mojom.Constant()
+ constant.name = parsed_const.name
+ if parent_kind:
+ scope = (module.namespace, parent_kind.name)
+ else:
+ scope = (module.namespace, )
+ # 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)
+
+ value = mojom.ConstantValue(module, parent_kind, constant)
+ module.values[value.GetSpec()] = value
+ return constant
+
+def _Module(tree, name, imports):
+ """
+ Args:
+ tree: {ast.Mojom} The parse tree.
+ name: {str} The mojom filename, excluding the path.
+ imports: {Dict[str, mojom.Module]} Mapping from filenames, as they appear in
+ the import list, to already processed modules. Used to process imports.
+
+ Returns:
+ {mojom.Module} An AST for the mojom.
+ """
+ module = mojom.Module()
+ module.kinds = {}
+ for kind in mojom.PRIMITIVES:
+ module.kinds[kind.spec] = kind
+
+ module.values = {}
+
+ module.name = name
+ module.namespace = tree.module.name[1] if tree.module else ''
+ # Imports must come first, because they add to module.kinds which is used
+ # by by the others.
+ module.imports = [
+ _Import(module, imports[imp.import_filename])
+ for imp in tree.import_list]
+ if tree.module and tree.module.attribute_list:
+ assert isinstance(tree.module.attribute_list, ast.AttributeList)
+ # TODO(vtl): Check for duplicate keys here.
+ module.attributes = dict((attribute.key, attribute.value)
+ for attribute in tree.module.attribute_list)
+
+ # First pass collects kinds.
+ module.enums = map(
+ lambda enum: _Enum(module, enum, None),
+ _ElemsOfType(tree.definition_list, ast.Enum, name))
+ module.structs = map(
+ lambda struct: _Struct(module, struct),
+ _ElemsOfType(tree.definition_list, ast.Struct, name))
+ module.unions = map(
+ lambda union: _Union(module, union),
+ _ElemsOfType(tree.definition_list, ast.Union, name))
+ module.interfaces = map(
+ lambda interface: _Interface(module, interface),
+ _ElemsOfType(tree.definition_list, ast.Interface, name))
+ module.constants = map(
+ lambda constant: _Constant(module, constant, None),
+ _ElemsOfType(tree.definition_list, ast.Const, name))
+
+ # Second pass expands fields and methods. This allows fields and parameters
+ # to refer to kinds defined anywhere in the mojom.
+ for struct in module.structs:
+ struct.fields = map(lambda field:
+ _StructField(module, field, struct), struct.fields_data)
+ del struct.fields_data
+ for union in module.unions:
+ union.fields = map(lambda field:
+ _UnionField(module, field, union), union.fields_data)
+ del union.fields_data
+ for interface in module.interfaces:
+ interface.methods = map(lambda method:
+ _Method(module, method, interface), interface.methods_data)
+ del interface.methods_data
+
+ return module
+
+def OrderedModule(tree, name, imports):
+ """Convert parse tree to AST module.
+
+ Args:
+ tree: {ast.Mojom} The parse tree.
+ name: {str} The mojom filename, excluding the path.
+ imports: {Dict[str, mojom.Module]} Mapping from filenames, as they appear in
+ the import list, to already processed modules. Used to process imports.
+
+ Returns:
+ {mojom.Module} An AST for the mojom.
+ """
+ module = _Module(tree, name, imports)
+ for interface in module.interfaces:
+ next_ordinal = 0
+ for method in interface.methods:
+ if method.ordinal is None:
+ method.ordinal = next_ordinal
+ next_ordinal = method.ordinal + 1
+ return module
diff --git a/mojo/public/tools/bindings/pylib/mojom/parse/parser.py b/mojo/public/tools/bindings/pylib/mojom/parse/parser.py
index 5cf20fe..868fb45 100644
--- a/mojo/public/tools/bindings/pylib/mojom/parse/parser.py
+++ b/mojo/public/tools/bindings/pylib/mojom/parse/parser.py
@@ -346,7 +346,7 @@ class Parser(object):
p[0] = ast.Ordinal(value, filename=self.filename, lineno=p.lineno(1))
def p_enum_1(self, p):
- """enum : attribute_section ENUM NAME LBRACE nonempty_enum_value_list \
+ """enum : attribute_section ENUM NAME LBRACE enum_value_list \
RBRACE SEMI
| attribute_section ENUM NAME LBRACE nonempty_enum_value_list \
COMMA RBRACE SEMI"""
@@ -358,6 +358,14 @@ class Parser(object):
p[0] = ast.Enum(p[3], p[1], None, filename=self.filename,
lineno=p.lineno(2))
+ def p_enum_value_list_1(self, p):
+ """enum_value_list : """
+ p[0] = ast.EnumValueList()
+
+ def p_enum_value_list_2(self, p):
+ """enum_value_list : nonempty_enum_value_list"""
+ p[0] = p[1]
+
def p_nonempty_enum_value_list_1(self, p):
"""nonempty_enum_value_list : enum_value"""
p[0] = ast.EnumValueList(p[1])
diff --git a/mojo/public/tools/bindings/pylib/mojom/parse/translate.py b/mojo/public/tools/bindings/pylib/mojom/parse/translate.py
deleted file mode 100644
index 66e8443..0000000
--- a/mojo/public/tools/bindings/pylib/mojom/parse/translate.py
+++ /dev/null
@@ -1,236 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Translates parse tree to Mojom IR."""
-
-import re
-
-from . import ast
-
-
-def _DuplicateName(values):
- """Returns the 'name' of the first entry in |values| whose 'name' has already
- been encountered. If there are no duplicates, returns None."""
- names = set()
- for value in values:
- if value['name'] in names:
- return value['name']
- names.add(value['name'])
- return None
-
-def _MapTreeForType(func, tree, type_to_map, scope):
- assert isinstance(type_to_map, type)
- if not tree:
- return []
- result = [func(subtree)
- for subtree in tree if isinstance(subtree, type_to_map)]
- duplicate_name = _DuplicateName(result)
- if duplicate_name:
- raise Exception('Names in mojom must be unique within a scope. The name '
- '"%s" is used more than once within the scope "%s".' %
- (duplicate_name, scope))
- return result
-
-def _MapKind(kind):
- map_to_kind = {'bool': 'b',
- 'int8': 'i8',
- 'int16': 'i16',
- 'int32': 'i32',
- 'int64': 'i64',
- 'uint8': 'u8',
- 'uint16': 'u16',
- 'uint32': 'u32',
- 'uint64': 'u64',
- 'float': 'f',
- 'double': 'd',
- 'string': 's',
- 'handle': 'h',
- 'handle<data_pipe_consumer>': 'h:d:c',
- 'handle<data_pipe_producer>': 'h:d:p',
- 'handle<message_pipe>': 'h:m',
- 'handle<shared_buffer>': 'h:s'}
- if kind.endswith('?'):
- base_kind = _MapKind(kind[0:-1])
- # NOTE: This doesn't rule out enum types. Those will be detected later, when
- # cross-reference is established.
- reference_kinds = ('m', 's', 'h', 'a', 'r', 'x', 'asso')
- if re.split('[^a-z]', base_kind, 1)[0] not in reference_kinds:
- raise Exception(
- 'A type (spec "%s") cannot be made nullable' % base_kind)
- return '?' + base_kind
- if kind.endswith('}'):
- lbracket = kind.rfind('{')
- value = kind[0:lbracket]
- return 'm[' + _MapKind(kind[lbracket+1:-1]) + '][' + _MapKind(value) + ']'
- if kind.endswith(']'):
- lbracket = kind.rfind('[')
- typename = kind[0:lbracket]
- return 'a' + kind[lbracket+1:-1] + ':' + _MapKind(typename)
- if kind.endswith('&'):
- return 'r:' + _MapKind(kind[0:-1])
- if kind.startswith('asso<'):
- assert kind.endswith('>')
- return 'asso:' + _MapKind(kind[5:-1])
- if kind in map_to_kind:
- return map_to_kind[kind]
- return 'x:' + kind
-
-def _AddOptional(dictionary, key, value):
- if value is not None:
- dictionary[key] = value;
-
-def _AttributeListToDict(attribute_list):
- if attribute_list is None:
- return None
- assert isinstance(attribute_list, ast.AttributeList)
- # TODO(vtl): Check for duplicate keys here.
- return dict([(attribute.key, attribute.value)
- for attribute in attribute_list])
-
-def _EnumToDict(enum):
- def EnumValueToDict(enum_value):
- assert isinstance(enum_value, ast.EnumValue)
- data = {'name': enum_value.name}
- _AddOptional(data, 'value', enum_value.value)
- _AddOptional(data, 'attributes',
- _AttributeListToDict(enum_value.attribute_list))
- return data
-
- assert isinstance(enum, ast.Enum)
- data = {'name': enum.name,
- 'native_only': enum.enum_value_list is None }
- if not data['native_only']:
- data.update({'fields': map(EnumValueToDict, enum.enum_value_list)})
- _AddOptional(data, 'attributes', _AttributeListToDict(enum.attribute_list))
- return data
-
-def _ConstToDict(const):
- assert isinstance(const, ast.Const)
- return {'name': const.name,
- 'kind': _MapKind(const.typename),
- 'value': const.value}
-
-
-class _MojomBuilder(object):
- def __init__(self):
- self.mojom = {}
-
- def Build(self, tree, name):
- def StructToDict(struct):
- def StructFieldToDict(struct_field):
- assert isinstance(struct_field, ast.StructField)
- data = {'name': struct_field.name,
- 'kind': _MapKind(struct_field.typename)}
- _AddOptional(data, 'ordinal',
- struct_field.ordinal.value
- if struct_field.ordinal else None)
- _AddOptional(data, 'default', struct_field.default_value)
- _AddOptional(data, 'attributes',
- _AttributeListToDict(struct_field.attribute_list))
- return data
-
- assert isinstance(struct, ast.Struct)
- data = {'name': struct.name,
- 'native_only': struct.body is None}
- if not data['native_only']:
- data.update({
- 'fields': _MapTreeForType(StructFieldToDict, struct.body,
- ast.StructField, struct.name),
- 'enums': _MapTreeForType(_EnumToDict, struct.body, ast.Enum,
- struct.name),
- 'constants': _MapTreeForType(_ConstToDict, struct.body,
- ast.Const, struct.name)})
- _AddOptional(data, 'attributes',
- _AttributeListToDict(struct.attribute_list))
- return data
-
- def UnionToDict(union):
- def UnionFieldToDict(union_field):
- assert isinstance(union_field, ast.UnionField)
- data = {'name': union_field.name,
- 'kind': _MapKind(union_field.typename)}
- _AddOptional(data, 'ordinal',
- union_field.ordinal.value
- if union_field.ordinal else None)
- _AddOptional(data, 'attributes',
- _AttributeListToDict(union_field.attribute_list))
- return data
-
- assert isinstance(union, ast.Union)
- data = {'name': union.name,
- 'fields': _MapTreeForType(UnionFieldToDict, union.body,
- ast.UnionField, union.name)}
- _AddOptional(data, 'attributes',
- _AttributeListToDict(union.attribute_list))
- return data
-
- def InterfaceToDict(interface):
- def MethodToDict(method):
- def ParameterToDict(param):
- assert isinstance(param, ast.Parameter)
- data = {'name': param.name,
- 'kind': _MapKind(param.typename)}
- _AddOptional(data, 'ordinal',
- param.ordinal.value if param.ordinal else None)
- _AddOptional(data, 'attributes',
- _AttributeListToDict(param.attribute_list))
- return data
-
- assert isinstance(method, ast.Method)
- data = {'name': method.name,
- 'parameters': map(ParameterToDict, method.parameter_list)}
- if method.response_parameter_list is not None:
- data['response_parameters'] = map(ParameterToDict,
- method.response_parameter_list)
- _AddOptional(data, 'ordinal',
- method.ordinal.value if method.ordinal else None)
- _AddOptional(data, 'attributes',
- _AttributeListToDict(method.attribute_list))
- return data
-
- assert isinstance(interface, ast.Interface)
- data = {'name': interface.name,
- 'methods': _MapTreeForType(MethodToDict, interface.body,
- ast.Method, interface.name),
- 'enums': _MapTreeForType(_EnumToDict, interface.body, ast.Enum,
- interface.name),
- 'constants': _MapTreeForType(_ConstToDict, interface.body,
- ast.Const, interface.name)}
- _AddOptional(data, 'attributes',
- _AttributeListToDict(interface.attribute_list))
- return data
-
- assert isinstance(tree, ast.Mojom)
- self.mojom['name'] = name
- self.mojom['namespace'] = tree.module.name[1] if tree.module else ''
- self.mojom['imports'] = \
- [{'filename': imp.import_filename} for imp in tree.import_list]
- self.mojom['structs'] = \
- _MapTreeForType(StructToDict, tree.definition_list, ast.Struct, name)
- self.mojom['unions'] = \
- _MapTreeForType(UnionToDict, tree.definition_list, ast.Union, name)
- self.mojom['interfaces'] = \
- _MapTreeForType(InterfaceToDict, tree.definition_list, ast.Interface,
- name)
- self.mojom['enums'] = \
- _MapTreeForType(_EnumToDict, tree.definition_list, ast.Enum, name)
- self.mojom['constants'] = \
- _MapTreeForType(_ConstToDict, tree.definition_list, ast.Const, name)
- _AddOptional(self.mojom, 'attributes',
- _AttributeListToDict(tree.module.attribute_list)
- if tree.module else None)
- return self.mojom
-
-
-def Translate(tree, name):
- """Translate AST to Mojom IR.
-
- Args:
- tree: The AST as a mojom.parse.ast.Mojom object.
- name: The filename as a str.
-
- Returns:
- The Mojom IR as a dict.
- """
- return _MojomBuilder().Build(tree, name)
diff --git a/mojo/public/tools/gn/zip.py b/mojo/public/tools/gn/zip.py
index 0d4960f..adc9cb1 100755
--- a/mojo/public/tools/gn/zip.py
+++ b/mojo/public/tools/gn/zip.py
@@ -20,25 +20,30 @@ sys.path.append(os.path.join(os.path.dirname(__file__),
"build"))
import gn_helpers
+sys.path.append(os.path.join(os.path.dirname(__file__),
+ os.pardir, os.pardir, os.pardir, os.pardir,
+ 'build', 'android', 'gyp'))
+from util import build_utils
+
+
def DoZip(inputs, link_inputs, zip_inputs, output, base_dir):
files = []
with zipfile.ZipFile(output, 'w', zipfile.ZIP_DEFLATED) as outfile:
for f in inputs:
file_name = os.path.relpath(f, base_dir)
files.append(file_name)
- outfile.write(f, file_name)
+ build_utils.AddToZipHermetic(outfile, file_name, f)
for f in link_inputs:
realf = os.path.realpath(f) # Resolve symlinks.
file_name = os.path.relpath(realf, base_dir)
files.append(file_name)
- outfile.write(realf, file_name)
+ build_utils.AddToZipHermetic(outfile, file_name, realf)
for zf_name in zip_inputs:
with zipfile.ZipFile(zf_name, 'r') as zf:
for f in zf.namelist():
if f not in files:
files.append(f)
- with zf.open(f) as zff:
- outfile.writestr(f, zff.read())
+ build_utils.AddToZipHermetic(outfile, f, data=zf.read(f))
def main():
diff --git a/mojo/public/tools/manifest/manifest_collator.py b/mojo/public/tools/manifest/manifest_collator.py
deleted file mode 100755
index 9a6d0e9..0000000
--- a/mojo/public/tools/manifest/manifest_collator.py
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-""" A collator for Mojo Application Manifests """
-
-import argparse
-import json
-import os
-import shutil
-import sys
-import urlparse
-
-eater_relative = '../../../../../tools/json_comment_eater'
-eater_relative = os.path.join(os.path.abspath(__file__), eater_relative)
-sys.path.insert(0, os.path.normpath(eater_relative))
-try:
- import json_comment_eater
-finally:
- sys.path.pop(0)
-
-def ParseJSONFile(filename):
- with open(filename) as json_file:
- try:
- return json.loads(json_comment_eater.Nom(json_file.read()))
- except ValueError:
- print "%s is not a valid JSON document" % filename
- return None
-
-def MergeDicts(left, right):
- for k, v in right.iteritems():
- if k not in left:
- left[k] = v
- else:
- if isinstance(v, dict):
- assert isinstance(left[k], dict)
- MergeDicts(left[k], v)
- elif isinstance(v, list):
- assert isinstance(left[k], list)
- left[k].extend(v)
- else:
- raise "Refusing to merge conflicting non-collection values."
- return left
-
-
-def MergeBaseManifest(parent, base):
- MergeDicts(parent["capabilities"], base["capabilities"])
-
- if "applications" in base:
- if "applications" not in parent:
- parent["applications"] = []
- parent["applications"].extend(base["applications"])
-
- if "process-group" in base:
- parent["process-group"] = base["process-group"]
-
-
-def main():
- parser = argparse.ArgumentParser(
- description="Collate Mojo application manifests.")
- parser.add_argument("--parent")
- parser.add_argument("--output")
- parser.add_argument("--application-name")
- parser.add_argument("--base-manifest", default=None)
- args, children = parser.parse_known_args()
-
- parent = ParseJSONFile(args.parent)
- if parent == None:
- return 1
-
- if args.base_manifest:
- base = ParseJSONFile(args.base_manifest)
- if base == None:
- return 1
- MergeBaseManifest(parent, base)
-
- app_path = parent['name'].split(':')[1]
- if app_path.startswith('//'):
- raise ValueError("Application name path component '%s' must not start " \
- "with //" % app_path)
-
- if args.application_name != app_path:
- raise ValueError("Application name '%s' specified in build file does not " \
- "match application name '%s' specified in manifest." %
- (args.application_name, app_path))
-
- applications = []
- for child in children:
- application = ParseJSONFile(child)
- if application == None:
- return 1
- applications.append(application)
-
- if len(applications) > 0:
- parent['applications'] = applications
-
- with open(args.output, 'w') as output_file:
- json.dump(parent, output_file)
-
- return 0
-
-if __name__ == "__main__":
- sys.exit(main())
diff --git a/mojo/public/tools/prepend.py b/mojo/public/tools/prepend.py
deleted file mode 100755
index de70a82..0000000
--- a/mojo/public/tools/prepend.py
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-Prepends a given file with a given line. This can be used to add a shebang line
-to a generated file.
-"""
-
-import optparse
-import os
-import shutil
-import sys
-
-
-def main():
- parser = optparse.OptionParser()
- parser.add_option('--input', help='The file to prepend the line to.')
- parser.add_option('--line', help='The line to be prepended.')
- parser.add_option('--output', help='The output file.')
-
- options, _ = parser.parse_args()
- input_path = options.input
- output_path = options.output
- line = options.line
-
- # Warning - this reads all of the input file into memory.
- with open(output_path, 'w') as output_file:
- output_file.write(line + '\n')
- with open(input_path, 'r') as input_file:
- shutil.copyfileobj(input_file, output_file)
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/third_party/catapult/devil/devil/android/perf/cache_control.py b/third_party/catapult/devil/devil/android/perf/cache_control.py
index 7bd0a4e..15d536d 100644
--- a/third_party/catapult/devil/devil/android/perf/cache_control.py
+++ b/third_party/catapult/devil/devil/android/perf/cache_control.py
@@ -13,4 +13,3 @@ class CacheControl(object):
"""Drops the filesystem ram caches for performance testing."""
self._device.RunShellCommand('sync', as_root=True)
self._device.WriteFile(CacheControl._DROP_CACHES, '3', as_root=True)
-
diff --git a/third_party/catapult/devil/devil/android/perf/thermal_throttle.py b/third_party/catapult/devil/devil/android/perf/thermal_throttle.py
index 9aad4bb..2741e14 100644
--- a/third_party/catapult/devil/devil/android/perf/thermal_throttle.py
+++ b/third_party/catapult/devil/devil/android/perf/thermal_throttle.py
@@ -129,4 +129,3 @@ class ThermalThrottle(object):
serial_number, btemp, degree_symbol)
return has_been_throttled
-