summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorblundell <blundell@chromium.org>2015-01-29 09:36:11 -0800
committerCommit bot <commit-bot@chromium.org>2015-01-29 17:37:14 +0000
commit29cbd973babcdcddc9df43f492088fa69795874e (patch)
tree022390ea53b2af5e2d8cd0bbe1d45d674ab1de32
parent931d092bc54acfd92322f4d28a3d1c401f76c181 (diff)
downloadchromium_src-29cbd973babcdcddc9df43f492088fa69795874e.zip
chromium_src-29cbd973babcdcddc9df43f492088fa69795874e.tar.gz
chromium_src-29cbd973babcdcddc9df43f492088fa69795874e.tar.bz2
Update mojo sdk to rev 126532ce21c5c3c55a1e1693731411cb60169efd
Update HTMLViewer for de-clienting of Shell. Update ServiceRegistryTest.java for de-clienting of MathCalculator. NOPRESUBMIT=true Review URL: https://codereview.chromium.org/883843002 Cr-Commit-Position: refs/heads/master@{#313729}
-rw-r--r--content/public/android/javatests/src/org/chromium/content/browser/ServiceRegistryTest.java118
-rw-r--r--mojo/application/application_runner_chromium.cc12
-rw-r--r--mojo/application/application_test_main_chromium.cc8
-rw-r--r--mojo/services/content_handler/public/interfaces/BUILD.gn8
-rw-r--r--mojo/services/content_handler/public/interfaces/content_handler.mojom4
-rw-r--r--mojo/services/html_viewer/html_viewer.cc21
-rw-r--r--mojo/services/native_viewport/public/interfaces/native_viewport.mojom18
-rw-r--r--mojo/services/navigation/public/interfaces/BUILD.gn8
-rw-r--r--mojo/services/public/js/application.js38
-rw-r--r--mojo/services/public/js/service_provider.js26
-rw-r--r--mojo/services/public/js/shell.js26
-rw-r--r--mojo/services/view_manager/public/cpp/DEPS8
-rw-r--r--mojo/services/view_manager/public/cpp/lib/BUILD.gn23
-rw-r--r--mojo/services/view_manager/public/cpp/lib/DEPS15
-rw-r--r--mojo/services/view_manager/public/cpp/lib/view.cc33
-rw-r--r--mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.cc23
-rw-r--r--mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.h2
-rw-r--r--mojo/services/view_manager/public/cpp/lib/view_private.cc1
-rw-r--r--mojo/services/view_manager/public/cpp/lib/view_private.h5
-rw-r--r--mojo/services/view_manager/public/cpp/tests/BUILD.gn12
-rw-r--r--mojo/services/view_manager/public/cpp/tests/DEPS13
-rw-r--r--mojo/services/view_manager/public/cpp/tests/view_manager_test_suite.cc (renamed from mojo/services/view_manager/public/cpp/lib/view_manager_test_suite.cc)2
-rw-r--r--mojo/services/view_manager/public/cpp/tests/view_manager_test_suite.h (renamed from mojo/services/view_manager/public/cpp/lib/view_manager_test_suite.h)6
-rw-r--r--mojo/services/view_manager/public/cpp/tests/view_manager_unittest.cc6
-rw-r--r--mojo/services/view_manager/public/cpp/tests/view_manager_unittests.cc (renamed from mojo/services/view_manager/public/cpp/lib/view_manager_unittests.cc)2
-rw-r--r--mojo/services/view_manager/public/cpp/view.h2
-rw-r--r--mojo/services/view_manager/public/cpp/view_observer.h5
-rw-r--r--mojo/services/view_manager/public/interfaces/view_manager.mojom7
-rw-r--r--third_party/mojo/src/mojo/edk/embedder/BUILD.gn22
-rw-r--r--third_party/mojo/src/mojo/edk/embedder/master_process_delegate.h47
-rw-r--r--third_party/mojo/src/mojo/edk/embedder/slave_process_delegate.h36
-rw-r--r--third_party/mojo/src/mojo/edk/system/BUILD.gn7
-rw-r--r--third_party/mojo/src/mojo/edk/system/connection_manager.h105
-rw-r--r--third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc501
-rw-r--r--third_party/mojo/src/mojo/edk/system/master_connection_manager.cc572
-rw-r--r--third_party/mojo/src/mojo/edk/system/master_connection_manager.h141
-rw-r--r--third_party/mojo/src/mojo/edk/system/message_in_transit.cc16
-rw-r--r--third_party/mojo/src/mojo/edk/system/message_in_transit.h16
-rw-r--r--third_party/mojo/src/mojo/edk/system/message_pipe_dispatcher_unittest.cc7
-rw-r--r--third_party/mojo/src/mojo/edk/system/simple_dispatcher_unittest.cc7
-rw-r--r--third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc316
-rw-r--r--third_party/mojo/src/mojo/edk/system/slave_connection_manager.h160
-rw-r--r--third_party/mojo/src/mojo/public/VERSION2
-rw-r--r--third_party/mojo/src/mojo/public/cpp/application/BUILD.gn3
-rw-r--r--third_party/mojo/src/mojo/public/cpp/application/application_impl.h32
-rw-r--r--third_party/mojo/src/mojo/public/cpp/application/application_test_base.h7
-rw-r--r--third_party/mojo/src/mojo/public/cpp/application/lib/application_impl.cc49
-rw-r--r--third_party/mojo/src/mojo/public/cpp/application/lib/application_runner.cc5
-rw-r--r--third_party/mojo/src/mojo/public/cpp/application/lib/application_test_base.cc97
-rw-r--r--third_party/mojo/src/mojo/public/cpp/application/lib/application_test_main.cc4
-rw-r--r--third_party/mojo/src/mojo/public/cpp/bindings/binding.h7
-rw-r--r--third_party/mojo/src/mojo/public/cpp/bindings/callback.h18
-rw-r--r--third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h100
-rw-r--r--third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h79
-rw-r--r--third_party/mojo/src/mojo/public/cpp/bindings/lib/map_internal.h2
-rw-r--r--third_party/mojo/src/mojo/public/cpp/bindings/lib/template_util.h2
-rw-r--r--third_party/mojo/src/mojo/public/cpp/bindings/map.h74
-rw-r--r--third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h2
-rw-r--r--third_party/mojo/src/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc126
-rw-r--r--third_party/mojo/src/mojo/public/cpp/system/buffer.h28
-rw-r--r--third_party/mojo/src/mojo/public/cpp/system/data_pipe.h25
-rw-r--r--third_party/mojo/src/mojo/public/cpp/system/functions.h16
-rw-r--r--third_party/mojo/src/mojo/public/cpp/system/handle.h17
-rw-r--r--third_party/mojo/src/mojo/public/cpp/system/macros.h10
-rw-r--r--third_party/mojo/src/mojo/public/cpp/system/message_pipe.h28
-rw-r--r--third_party/mojo/src/mojo/public/dart/application.dart18
-rw-r--r--third_party/mojo/src/mojo/public/dart/bindings.dart4
-rw-r--r--third_party/mojo/src/mojo/public/dart/src/application.dart121
-rw-r--r--third_party/mojo/src/mojo/public/dart/src/codec.dart18
-rw-r--r--third_party/mojo/src/mojo/public/dart/src/event_stream.dart9
-rw-r--r--third_party/mojo/src/mojo/public/dart/src/proxy.dart (renamed from third_party/mojo/src/mojo/public/dart/src/client.dart)10
-rw-r--r--third_party/mojo/src/mojo/public/dart/src/service_provider.dart39
-rw-r--r--third_party/mojo/src/mojo/public/dart/src/stub.dart (renamed from third_party/mojo/src/mojo/public/dart/src/interface.dart)23
-rw-r--r--third_party/mojo/src/mojo/public/go/bindings/decoder.go315
-rw-r--r--third_party/mojo/src/mojo/public/go/bindings/encoder.go319
-rw-r--r--third_party/mojo/src/mojo/public/go/bindings/message.go164
-rw-r--r--third_party/mojo/src/mojo/public/interfaces/application/application.mojom3
-rw-r--r--third_party/mojo/src/mojo/public/interfaces/application/shell.mojom2
-rw-r--r--third_party/mojo/src/mojo/public/interfaces/bindings/tests/math_calculator.mojom11
-rw-r--r--third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ConnectionErrorHandler.java2
-rw-r--r--third_party/mojo/src/mojo/public/js/bindings.js30
-rw-r--r--third_party/mojo/src/mojo/public/js/connection.js77
-rw-r--r--third_party/mojo/src/mojo/public/mojo_sdk.gni4
-rw-r--r--third_party/mojo/src/mojo/public/platform/nacl/mojo_initial_handle.h14
-rwxr-xr-xthird_party/mojo/src/mojo/public/sky/convert_amd_modules_to_sky.py2
-rw-r--r--third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl17
-rw-r--r--third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl10
-rw-r--r--third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl4
-rw-r--r--third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl6
-rw-r--r--third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl2
-rw-r--r--third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl4
-rw-r--r--third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl173
-rw-r--r--third_party/mojo/src/mojo/public/tools/bindings/generators/js_templates/module.sky.tmpl12
-rw-r--r--third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py11
-rw-r--r--third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_js_generator.py16
-rw-r--r--third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/parse/ast.py38
-rw-r--r--third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/parse/parser.py42
-rw-r--r--third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py272
-rw-r--r--third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/parse/translate_unittest.py6
99 files changed, 4219 insertions, 717 deletions
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ServiceRegistryTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ServiceRegistryTest.java
index b0746b5..d076896 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ServiceRegistryTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ServiceRegistryTest.java
@@ -10,9 +10,9 @@ import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.content.browser.ServiceRegistry.ImplementationFactory;
import org.chromium.content_shell.ShellMojoTestUtils;
import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.mojo.bindings.ConnectionErrorHandler;
import org.chromium.mojo.bindings.InterfaceRequest;
import org.chromium.mojo.bindings.test.mojom.math.Calculator;
-import org.chromium.mojo.bindings.test.mojom.math.CalculatorUi;
import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojo.system.Pair;
@@ -33,10 +33,33 @@ public class ServiceRegistryTest extends ContentShellTestBase {
private final Core mCore = CoreImpl.getInstance();
private long mNativeTestEnvironment;
+ static class CalcConnectionErrorHandler implements ConnectionErrorHandler {
+
+ MojoException mLastMojoException;
+
+ @Override
+ public void onConnectionError(MojoException e) {
+ mLastMojoException = e;
+ }
+ }
+
+ static class CalcCallback implements Calculator.AddResponse, Calculator.MultiplyResponse {
+
+ double mResult = 0.0;
+
+ @Override
+ public void call(Double result) {
+ mResult = result;
+ }
+
+ public double getResult() {
+ return mResult;
+ }
+ }
+
static class CalculatorImpl implements Calculator {
double mResult = 0.0;
- CalculatorUi mClient;
@Override
public void close() {}
@@ -45,26 +68,21 @@ public class ServiceRegistryTest extends ContentShellTestBase {
public void onConnectionError(MojoException e) {}
@Override
- public void clear() {
+ public void clear(ClearResponse callback) {
mResult = 0.0;
- mClient.output(mResult);
+ callback.call(mResult);
}
@Override
- public void add(double value) {
+ public void add(double value, AddResponse callback) {
mResult += value;
- mClient.output(mResult);
+ callback.call(mResult);
}
@Override
- public void multiply(double value) {
+ public void multiply(double value, MultiplyResponse callback) {
mResult *= value;
- mClient.output(mResult);
- }
-
- @Override
- public void setClient(CalculatorUi client) {
- mClient = client;
+ callback.call(mResult);
}
}
@@ -76,24 +94,6 @@ public class ServiceRegistryTest extends ContentShellTestBase {
}
}
- static class CalculatorUiImpl implements CalculatorUi {
-
- double mOutput = 0.0;
- MojoException mLastMojoException;
-
- @Override
- public void close() {}
-
- @Override
- public void onConnectionError(MojoException e) {
- mLastMojoException = e;
- }
-
- @Override
- public void output(double value) {
- mOutput = value;
- }
- }
@Override
protected void setUp() throws Exception {
@@ -126,22 +126,25 @@ public class ServiceRegistryTest extends ContentShellTestBase {
// Add the Calculator service.
serviceRegistryA.addService(Calculator.MANAGER, new CalculatorFactory());
- // Create an instance of CalculatorUi and request a Calculator service for it.
- CalculatorUiImpl calculatorUi = new CalculatorUiImpl();
Pair<Calculator.Proxy, InterfaceRequest<Calculator>> requestPair =
- Calculator.MANAGER.getInterfaceRequest(mCore, calculatorUi);
+ Calculator.MANAGER.getInterfaceRequest(mCore);
+
mCloseablesToClose.add(requestPair.first);
serviceRegistryB.connectToRemoteService(Calculator.MANAGER, requestPair.second);
// Perform a few operations on the Calculator.
Calculator.Proxy calculator = requestPair.first;
- calculator.add(21);
- calculator.multiply(2);
+ CalcConnectionErrorHandler errorHandler = new CalcConnectionErrorHandler();
+ calculator.setErrorHandler(errorHandler);
+ CalcCallback callback = new CalcCallback();
+
+ calculator.add(21, callback);
+ ShellMojoTestUtils.runLoop(RUN_LOOP_TIMEOUT_MS);
+ assertEquals(21.0, callback.getResult());
- // Spin the message loop and verify the results.
- assertEquals(0.0, calculatorUi.mOutput);
+ calculator.multiply(2, callback);
ShellMojoTestUtils.runLoop(RUN_LOOP_TIMEOUT_MS);
- assertEquals(42.0, calculatorUi.mOutput);
+ assertEquals(42.0, callback.getResult());
}
/**
@@ -155,39 +158,46 @@ public class ServiceRegistryTest extends ContentShellTestBase {
ServiceRegistry serviceRegistryB = registryPair.second;
// Request the Calculator service before it is added.
- CalculatorUiImpl calculatorUi = new CalculatorUiImpl();
Pair<Calculator.Proxy, InterfaceRequest<Calculator>> requestPair =
- Calculator.MANAGER.getInterfaceRequest(mCore, calculatorUi);
- mCloseablesToClose.add(requestPair.first);
+ Calculator.MANAGER.getInterfaceRequest(mCore);
+ Calculator.Proxy calculator = requestPair.first;
+ CalcConnectionErrorHandler errorHandler = new CalcConnectionErrorHandler();
+ calculator.setErrorHandler(errorHandler);
+ mCloseablesToClose.add(calculator);
serviceRegistryB.connectToRemoteService(Calculator.MANAGER, requestPair.second);
// Spin the message loop and verify that an error occured.
- assertNull(calculatorUi.mLastMojoException);
+ assertNull(errorHandler.mLastMojoException);
ShellMojoTestUtils.runLoop(RUN_LOOP_TIMEOUT_MS);
- assertNotNull(calculatorUi.mLastMojoException);
+ assertNotNull(errorHandler.mLastMojoException);
// Add the Calculator service and request it again.
- calculatorUi.mLastMojoException = null;
+ errorHandler.mLastMojoException = null;
serviceRegistryA.addService(Calculator.MANAGER, new CalculatorFactory());
- requestPair = Calculator.MANAGER.getInterfaceRequest(mCore, calculatorUi);
- mCloseablesToClose.add(requestPair.first);
+ requestPair = Calculator.MANAGER.getInterfaceRequest(mCore);
+ calculator = requestPair.first;
+ errorHandler = new CalcConnectionErrorHandler();
+ mCloseablesToClose.add(calculator);
serviceRegistryB.connectToRemoteService(Calculator.MANAGER, requestPair.second);
// Spin the message loop and verify that no error occured.
- assertNull(calculatorUi.mLastMojoException);
+ assertNull(errorHandler.mLastMojoException);
ShellMojoTestUtils.runLoop(RUN_LOOP_TIMEOUT_MS);
- assertNull(calculatorUi.mLastMojoException);
+ assertNull(errorHandler.mLastMojoException);
// Remove the Calculator service and request it again.
- calculatorUi.mLastMojoException = null;
+ errorHandler.mLastMojoException = null;
serviceRegistryA.removeService(Calculator.MANAGER);
- requestPair = Calculator.MANAGER.getInterfaceRequest(mCore, calculatorUi);
- mCloseablesToClose.add(requestPair.first);
+ requestPair = Calculator.MANAGER.getInterfaceRequest(mCore);
+ calculator = requestPair.first;
+ errorHandler = new CalcConnectionErrorHandler();
+ calculator.setErrorHandler(errorHandler);
+ mCloseablesToClose.add(calculator);
serviceRegistryB.connectToRemoteService(Calculator.MANAGER, requestPair.second);
// Spin the message loop and verify that an error occured.
- assertNull(calculatorUi.mLastMojoException);
+ assertNull(errorHandler.mLastMojoException);
ShellMojoTestUtils.runLoop(RUN_LOOP_TIMEOUT_MS);
- assertNotNull(calculatorUi.mLastMojoException);
+ assertNotNull(errorHandler.mLastMojoException);
}
}
diff --git a/mojo/application/application_runner_chromium.cc b/mojo/application/application_runner_chromium.cc
index ed6d013..069ff90 100644
--- a/mojo/application/application_runner_chromium.cc
+++ b/mojo/application/application_runner_chromium.cc
@@ -10,8 +10,8 @@
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "mojo/common/message_pump_mojo.h"
-#include "third_party/mojo/src/mojo/public/cpp/application/application_delegate.h"
-#include "third_party/mojo/src/mojo/public/cpp/application/application_impl.h"
+#include "mojo/public/cpp/application/application_delegate.h"
+#include "mojo/public/cpp/application/application_impl.h"
namespace mojo {
@@ -37,14 +37,13 @@ void ApplicationRunnerChromium::set_message_loop_type(
message_loop_type_ = type;
}
-MojoResult ApplicationRunnerChromium::Run(MojoHandle shell_handle) {
+MojoResult ApplicationRunnerChromium::Run(
+ MojoHandle application_request_handle) {
DCHECK(!has_run_);
has_run_ = true;
base::CommandLine::Init(0, NULL);
-#if !defined(COMPONENT_BUILD)
base::AtExitManager at_exit;
-#endif
#ifndef NDEBUG
base::debug::EnableInProcessStackDumping();
@@ -58,7 +57,8 @@ MojoResult ApplicationRunnerChromium::Run(MojoHandle shell_handle) {
loop.reset(new base::MessageLoop(message_loop_type_));
ApplicationImpl impl(delegate_.get(),
- MakeScopedHandle(MessagePipeHandle(shell_handle)));
+ MakeRequest<Application>(MakeScopedHandle(
+ MessagePipeHandle(application_request_handle))));
loop->Run();
}
delegate_.reset();
diff --git a/mojo/application/application_test_main_chromium.cc b/mojo/application/application_test_main_chromium.cc
index 33c4084..e6df84f 100644
--- a/mojo/application/application_test_main_chromium.cc
+++ b/mojo/application/application_test_main_chromium.cc
@@ -3,12 +3,12 @@
// found in the LICENSE file.
#include "base/at_exit.h"
-#include "third_party/mojo/src/mojo/public/c/system/main.h"
-#include "third_party/mojo/src/mojo/public/cpp/application/application_test_base.h"
+#include "mojo/public/c/system/main.h"
+#include "mojo/public/cpp/application/application_test_base.h"
-MojoResult MojoMain(MojoHandle shell_handle) {
+MojoResult MojoMain(MojoHandle handle) {
// An AtExitManager instance is needed to construct message loops.
base::AtExitManager at_exit;
- return mojo::test::RunAllTests(shell_handle);
+ return mojo::test::RunAllTests(handle);
}
diff --git a/mojo/services/content_handler/public/interfaces/BUILD.gn b/mojo/services/content_handler/public/interfaces/BUILD.gn
index cb38d83..5016c65 100644
--- a/mojo/services/content_handler/public/interfaces/BUILD.gn
+++ b/mojo/services/content_handler/public/interfaces/BUILD.gn
@@ -12,8 +12,14 @@ mojom("interfaces") {
import_dirs = [ get_path_info("../../../", "abspath") ]
+ if (defined(network_service_root)) {
+ import_dirs += [ network_service_root ]
+ } else {
+ network_service_root = "../../.."
+ }
+
deps = [
- "../../../network/public/interfaces",
+ "$network_service_root/network/public/interfaces",
]
mojo_sdk_deps = [ "mojo/public/interfaces/application" ]
diff --git a/mojo/services/content_handler/public/interfaces/content_handler.mojom b/mojo/services/content_handler/public/interfaces/content_handler.mojom
index c56410e..39ddfea 100644
--- a/mojo/services/content_handler/public/interfaces/content_handler.mojom
+++ b/mojo/services/content_handler/public/interfaces/content_handler.mojom
@@ -4,9 +4,9 @@
module mojo;
-import "mojo/public/interfaces/application/shell.mojom";
+import "mojo/public/interfaces/application/application.mojom";
import "network/public/interfaces/url_loader.mojom";
interface ContentHandler {
- StartApplication(Shell shell, URLResponse response);
+ StartApplication(Application& application, URLResponse response);
};
diff --git a/mojo/services/html_viewer/html_viewer.cc b/mojo/services/html_viewer/html_viewer.cc
index 06df351..73f3045 100644
--- a/mojo/services/html_viewer/html_viewer.cc
+++ b/mojo/services/html_viewer/html_viewer.cc
@@ -23,6 +23,7 @@
#include "third_party/mojo/src/mojo/public/cpp/application/application_impl.h"
#include "third_party/mojo/src/mojo/public/cpp/application/connect.h"
#include "third_party/mojo/src/mojo/public/cpp/application/interface_factory_impl.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
#if !defined(COMPONENT_BUILD)
#include "base/i18n/icu_util.h"
@@ -59,24 +60,24 @@ class HTMLViewer;
class HTMLViewerApplication : public mojo::Application {
public:
- HTMLViewerApplication(ShellPtr shell,
+ HTMLViewerApplication(InterfaceRequest<Application> request,
URLResponsePtr response,
scoped_refptr<base::MessageLoopProxy> compositor_thread,
WebMediaPlayerFactory* web_media_player_factory)
: url_(response->url),
- shell_(shell.Pass()),
+ binding_(this, request.Pass()),
initial_response_(response.Pass()),
compositor_thread_(compositor_thread),
- web_media_player_factory_(web_media_player_factory) {
- shell_.set_client(this);
+ web_media_player_factory_(web_media_player_factory) {}
+
+ void Initialize(ShellPtr shell, Array<String> args) override {
ServiceProviderPtr service_provider;
+ shell_ = shell.Pass();
shell_->ConnectToApplication("mojo:network_service",
GetProxy(&service_provider), nullptr);
ConnectToService(service_provider.get(), &network_service_);
}
- void Initialize(Array<String> args) override {}
-
void AcceptConnection(const String& requestor_url,
InterfaceRequest<ServiceProvider> services,
ServiceProviderPtr exposed_services) override {
@@ -113,6 +114,7 @@ class HTMLViewerApplication : public mojo::Application {
}
String url_;
+ mojo::StrongBinding<mojo::Application> binding_;
ShellPtr shell_;
mojo::NetworkServicePtr network_service_;
URLResponsePtr initial_response_;
@@ -130,8 +132,11 @@ class ContentHandlerImpl : public mojo::InterfaceImpl<ContentHandler> {
private:
// Overridden from ContentHandler:
- void StartApplication(ShellPtr shell, URLResponsePtr response) override {
- new HTMLViewerApplication(shell.Pass(), response.Pass(), compositor_thread_,
+ void StartApplication(InterfaceRequest<mojo::Application> request,
+ URLResponsePtr response) override {
+ new HTMLViewerApplication(request.Pass(),
+ response.Pass(),
+ compositor_thread_,
web_media_player_factory_);
}
diff --git a/mojo/services/native_viewport/public/interfaces/native_viewport.mojom b/mojo/services/native_viewport/public/interfaces/native_viewport.mojom
index 72d3c9d..75757c2 100644
--- a/mojo/services/native_viewport/public/interfaces/native_viewport.mojom
+++ b/mojo/services/native_viewport/public/interfaces/native_viewport.mojom
@@ -14,26 +14,26 @@ struct ViewportMetrics {
float device_pixel_ratio = 1.0;
};
-[Client=NativeViewportClient]
interface NativeViewport {
// TODO(sky): having a create function is awkward. Should there be a factory
// to create the NativeViewport that takes the size?
- Create(Size size) => (uint64 native_viewport_id);
+ Create(Size size) => (uint64 native_viewport_id, ViewportMetrics metrics);
+
Show();
Hide();
Close();
SetSize(Size size);
SubmittedFrame(SurfaceId surface_id);
SetEventDispatcher(NativeViewportEventDispatcher dispatcher);
+
+ // The initial viewport metrics will be sent in the reply to the Create
+ // method. Call RequestMetrics() to receive updates when the viewport metrics
+ // change. The reply will be sent when the viewport metrics are different from
+ // the values last sent, so to receive continuous updates call this method
+ // again after receiving the callback.
+ RequestMetrics() => (ViewportMetrics metrics);
};
interface NativeViewportEventDispatcher {
OnEvent(Event event) => ();
};
-
-interface NativeViewportClient {
- // OnMetricsAvailable() is sent at least once after the callback from Create()
- // is called.
- OnMetricsChanged(ViewportMetrics metrics);
- OnDestroyed();
-};
diff --git a/mojo/services/navigation/public/interfaces/BUILD.gn b/mojo/services/navigation/public/interfaces/BUILD.gn
index 9b396e7..da9fc70 100644
--- a/mojo/services/navigation/public/interfaces/BUILD.gn
+++ b/mojo/services/navigation/public/interfaces/BUILD.gn
@@ -12,7 +12,13 @@ mojom("interfaces") {
import_dirs = [ get_path_info("../../../", "abspath") ]
+ if (defined(network_service_root)) {
+ import_dirs += [ network_service_root ]
+ } else {
+ network_service_root = "../../.."
+ }
+
deps = [
- "../../../network/public/interfaces",
+ "$network_service_root/network/public/interfaces",
]
}
diff --git a/mojo/services/public/js/application.js b/mojo/services/public/js/application.js
index ed41628..d4aa1e6 100644
--- a/mojo/services/public/js/application.js
+++ b/mojo/services/public/js/application.js
@@ -4,30 +4,41 @@
define("mojo/services/public/js/application", [
"mojo/public/js/bindings",
+ "mojo/public/js/core",
+ "mojo/public/js/connection",
"mojo/public/js/threading",
+ "mojo/public/interfaces/application/application.mojom",
"mojo/services/public/js/service_provider",
"mojo/services/public/js/shell",
-], function(bindings, threading, serviceProvider, shell) {
+], function(bindings, core, connection, threading, applicationMojom, serviceProvider, shell) {
+ const ApplicationInterface = applicationMojom.Application;
const ProxyBindings = bindings.ProxyBindings;
const ServiceProvider = serviceProvider.ServiceProvider;
const Shell = shell.Shell;
class Application {
- constructor(shellHandle, url) {
+ constructor(appRequestHandle, url) {
this.url = url;
this.serviceProviders = [];
this.exposedServiceProviders = [];
- this.shellHandle_ = shellHandle;
- this.shell = new Shell(shellHandle, {
- initialize: this.initialize.bind(this),
- acceptConnection: this.doAcceptConnection.bind(this),
- });
+ this.appRequestHandle_ = appRequestHandle;
+ this.appStub_ =
+ connection.bindHandleToStub(appRequestHandle, ApplicationInterface);
+ bindings.StubBindings(this.appStub_).delegate = {
+ initialize: this.doInitialize.bind(this),
+ acceptConnection: this.doAcceptConnection.bind(this),
+ };
}
- initialize(args) {
+ doInitialize(shellProxy, args) {
+ this.shellProxy_ = shellProxy;
+ this.shell = new Shell(shellProxy);
+ this.initialize(args);
}
+ initialize(args) {}
+
// The mojom signature of this function is:
// AcceptConnection(string requestor_url,
// ServiceProvider&? services,
@@ -39,23 +50,20 @@ define("mojo/services/public/js/application", [
doAcceptConnection(requestorUrl, servicesRequest, exposedServicesProxy) {
// Construct a new js ServiceProvider that can make outgoing calls on
// exposedServicesProxy.
- var serviceProvider = new ServiceProvider(exposedServicesProxy);
+ var serviceProvider =
+ new ServiceProvider(servicesRequest, exposedServicesProxy);
this.serviceProviders.push(serviceProvider);
-
- // Then associate incoming calls with the serviceProvider.
- ProxyBindings(servicesRequest).setLocalDelegate(serviceProvider);
-
this.acceptConnection(requestorUrl, serviceProvider);
}
- acceptConnection(requestorUrl, serviceProvider) {
- }
+ acceptConnection(requestorUrl, serviceProvider) {}
quit() {
this.serviceProviders.forEach(function(sp) {
sp.close();
});
this.shell.close();
+ core.close(this.appRequestHandle_);
threading.quit();
}
}
diff --git a/mojo/services/public/js/service_provider.js b/mojo/services/public/js/service_provider.js
index 9566583..a6a81ca 100644
--- a/mojo/services/public/js/service_provider.js
+++ b/mojo/services/public/js/service_provider.js
@@ -18,10 +18,12 @@ define("mojo/services/public/js/service_provider", [
}
class ServiceProvider {
- constructor(service) {
- this.proxy = service;
+ constructor(servicesRequest, exposedServicesProxy) {
+ this.proxy = exposedServicesProxy;
this.providers_ = new Map(); // serviceName => see provideService() below
this.pendingRequests_ = new Map(); // serviceName => serviceHandle
+ if (servicesRequest)
+ StubBindings(servicesRequest).delegate = this;
}
// Incoming requests
@@ -34,11 +36,10 @@ define("mojo/services/public/js/service_provider", [
this.pendingRequests_.set(serviceName, serviceHandle);
return;
}
- var proxy = connection.bindProxyHandle(
- serviceHandle, provider.service, provider.service.client);
- if (ProxyBindings(proxy).local)
- ProxyBindings(proxy).setLocalDelegate(new provider.factory(proxy));
- provider.connections.push(ProxyBindings(proxy).connection);
+
+ var stub = connection.bindHandleToStub(serviceHandle, provider.service);
+ StubBindings(stub).delegate = new provider.factory();
+ provider.connections.push(StubBindings(stub).connection);
}
provideService(service, factory) {
@@ -66,12 +67,11 @@ define("mojo/services/public/js/service_provider", [
if (!clientImpl && interfaceObject.client)
throw new Error("Client implementation must be provided");
- var remoteProxy;
- var clientFactory = function(x) {remoteProxy = x; return clientImpl;};
- var messagePipeHandle = connection.bindProxyClient(
- clientFactory, interfaceObject.client, interfaceObject);
- this.proxy.connectToService(interfaceObject.name, messagePipeHandle);
- return remoteProxy;
+ var serviceProxy;
+ var serviceHandle = connection.bindProxy(
+ function(sp) {serviceProxy = sp;}, interfaceObject);
+ this.proxy.connectToService(interfaceObject.name, serviceHandle);
+ return serviceProxy;
};
close() {
diff --git a/mojo/services/public/js/shell.js b/mojo/services/public/js/shell.js
index 9fc8552..e6c2dee 100644
--- a/mojo/services/public/js/shell.js
+++ b/mojo/services/public/js/shell.js
@@ -8,8 +8,8 @@ define("mojo/services/public/js/shell", [
"mojo/public/js/connection",
"mojo/public/interfaces/application/shell.mojom",
"mojo/public/interfaces/application/service_provider.mojom",
- "mojo/services/public/js/service_provider",
-], function(bindings, core, connection, shellMojom, spMojom, sp) {
+ "mojo/services/public/js/service_provider","console",
+], function(bindings, core, connection, shellMojom, spMojom, sp, console) {
const ProxyBindings = bindings.ProxyBindings;
const StubBindings = bindings.StubBindings;
@@ -18,13 +18,8 @@ define("mojo/services/public/js/shell", [
const ShellInterface = shellMojom.Shell;
class Shell {
- constructor(shellHandle, app) {
- this.shellHandle = shellHandle;
- this.proxy = connection.bindProxyHandle(
- shellHandle, ShellInterface.client, ShellInterface);
-
- ProxyBindings(this.proxy).setLocalDelegate(app);
- // TODO: call this serviceProviders_
+ constructor(shellProxy) {
+ this.shellProxy = shellProxy;
this.applications_ = new Map();
}
@@ -33,11 +28,12 @@ define("mojo/services/public/js/shell", [
if (application)
return application;
- this.proxy.connectToApplication(url, function(services) {
- application = new ServiceProvider(services);
- }, function() {
- return application;
- });
+ var application = new ServiceProvider();
+ this.shellProxy.connectToApplication(url,
+ function(services) {
+ application.proxy = services;
+ },
+ application);
this.applications_.set(url, application);
return application;
}
@@ -50,8 +46,8 @@ define("mojo/services/public/js/shell", [
this.applications_.forEach(function(application, url) {
application.close();
});
+ ProxyBindings(this.shellProxy).close();
this.applications_.clear();
- core.close(this.shellHandle);
}
}
diff --git a/mojo/services/view_manager/public/cpp/DEPS b/mojo/services/view_manager/public/cpp/DEPS
index 84b6bb7..c08c2c8 100644
--- a/mojo/services/view_manager/public/cpp/DEPS
+++ b/mojo/services/view_manager/public/cpp/DEPS
@@ -1,8 +1,14 @@
include_rules = [
- "!base",
"+geometry/public",
"+input_events/public",
"+surfaces/public",
"+view_manager/public",
"+window_manager/public",
+
+ # TODO(blundell): Eliminate these dependencies. crbug.com/451403
+ "!base/basictypes.h",
+ "!base/bind.h",
+ "!base/compiler_specific.h",
+ "!base/memory/scoped_ptr.h",
+ "!base/observer_list.h",
]
diff --git a/mojo/services/view_manager/public/cpp/lib/BUILD.gn b/mojo/services/view_manager/public/cpp/lib/BUILD.gn
deleted file mode 100644
index 2090455..0000000
--- a/mojo/services/view_manager/public/cpp/lib/BUILD.gn
+++ /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.
-
-import("//build/config/ui.gni")
-
-source_set("run_unittests") {
- testonly = true
- sources = [
- "view_manager_test_suite.cc",
- "view_manager_test_suite.h",
- "view_manager_unittests.cc",
- ]
-
- deps = [
- "//base",
- "//base/test:test_support",
- ]
-
- if (use_x11) {
- deps += [ "//ui/gfx/x" ]
- }
-}
diff --git a/mojo/services/view_manager/public/cpp/lib/DEPS b/mojo/services/view_manager/public/cpp/lib/DEPS
index d4de534..f36ebc7 100644
--- a/mojo/services/view_manager/public/cpp/lib/DEPS
+++ b/mojo/services/view_manager/public/cpp/lib/DEPS
@@ -1,11 +1,10 @@
include_rules = [
"+mojo/services/window_manager/public",
-]
-specific_include_rules = {
- "view_manager_test_suite.cc": [
- "!mojo/services/native_viewport/native_viewport.h",
- "!ui/gfx",
- "!ui/gl",
- ],
-}
+ # TODO(blundell): Eliminate these dependencies. crbug.com/451403
+ "!base/callback.h",
+ "!base/memory/scoped_vector.h",
+ "!base/memory/weak_ptr.h",
+ "!base/message_loop/message_loop.h",
+ "!base/stl_util.h",
+]
diff --git a/mojo/services/view_manager/public/cpp/lib/view.cc b/mojo/services/view_manager/public/cpp/lib/view.cc
index 929eec4..f7e7784 100644
--- a/mojo/services/view_manager/public/cpp/lib/view.cc
+++ b/mojo/services/view_manager/public/cpp/lib/view.cc
@@ -5,6 +5,7 @@
#include "view_manager/public/cpp/view.h"
#include <set>
+#include <string>
#include "mojo/public/cpp/application/service_provider_impl.h"
#include "view_manager/public/cpp/lib/view_manager_client_impl.h"
@@ -247,6 +248,18 @@ void View::SetSharedProperty(const std::string& name,
properties_.erase(it);
}
+ // TODO: add test coverage of this (450303).
+ if (manager_) {
+ Array<uint8_t> transport_value;
+ if (value) {
+ transport_value.resize(value->size());
+ if (value->size())
+ memcpy(&transport_value.front(), &(value->front()), value->size());
+ }
+ static_cast<ViewManagerClientImpl*>(manager_)->SetProperty(
+ id_, name, transport_value.Pass());
+ }
+
FOR_EACH_OBSERVER(
ViewObserver, observers_,
OnViewSharedPropertyChanged(this, name, old_value_ptr, value));
@@ -369,10 +382,20 @@ void View::Embed(const String& url,
////////////////////////////////////////////////////////////////////////////////
// View, protected:
+namespace {
+
+ViewportMetricsPtr CreateEmptyViewportMetrics() {
+ ViewportMetricsPtr metrics = ViewportMetrics::New();
+ metrics->size = Size::New();
+ return metrics;
+}
+}
+
View::View()
: manager_(NULL),
id_(static_cast<Id>(-1)),
parent_(NULL),
+ viewport_metrics_(CreateEmptyViewportMetrics()),
visible_(true),
drawn_(false) {
}
@@ -412,6 +435,7 @@ View::View(ViewManager* manager, Id id)
: manager_(manager),
id_(id),
parent_(nullptr),
+ viewport_metrics_(CreateEmptyViewportMetrics()),
visible_(false),
drawn_(false) {
}
@@ -476,6 +500,15 @@ void View::LocalSetBounds(const Rect& old_bounds,
bounds_ = new_bounds;
}
+void View::LocalSetViewportMetrics(const ViewportMetrics& old_metrics,
+ const ViewportMetrics& new_metrics) {
+ // TODO(eseidel): We could check old_metrics against viewport_metrics_.
+ viewport_metrics_ = new_metrics.Clone();
+ FOR_EACH_OBSERVER(
+ ViewObserver, observers_,
+ OnViewViewportMetricsChanged(this, old_metrics, new_metrics));
+}
+
void View::LocalSetDrawn(bool value) {
if (drawn_ == value)
return;
diff --git a/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.cc b/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.cc
index 78daeb3..595e039 100644
--- a/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.cc
+++ b/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.cc
@@ -36,7 +36,8 @@ View* AddViewToViewManager(ViewManagerClientImpl* client,
private_view.set_id(view_data->view_id);
private_view.set_visible(view_data->visible);
private_view.set_drawn(view_data->drawn);
- private_view.set_viewport_metrics(view_data->viewport_metrics.Pass());
+ private_view.LocalSetViewportMetrics(ViewportMetrics(),
+ *view_data->viewport_metrics);
private_view.set_properties(
view_data->properties.To<std::map<std::string, std::vector<uint8_t>>>());
client->AddView(view);
@@ -296,6 +297,26 @@ void ViewManagerClientImpl::OnViewBoundsChanged(Id view_id,
ViewPrivate(view).LocalSetBounds(*old_bounds, *new_bounds);
}
+namespace {
+
+void SetViewportMetricsOnDecendants(View* root,
+ const ViewportMetrics& old_metrics,
+ const ViewportMetrics& new_metrics) {
+ ViewPrivate(root).LocalSetViewportMetrics(old_metrics, new_metrics);
+ const View::Children& children = root->children();
+ for (size_t i = 0; i < children.size(); ++i)
+ SetViewportMetricsOnDecendants(children[i], old_metrics, new_metrics);
+}
+}
+
+void ViewManagerClientImpl::OnViewViewportMetricsChanged(
+ ViewportMetricsPtr old_metrics,
+ ViewportMetricsPtr new_metrics) {
+ View* view = GetRoot();
+ if (view)
+ SetViewportMetricsOnDecendants(view, *old_metrics, *new_metrics);
+}
+
void ViewManagerClientImpl::OnViewHierarchyChanged(
Id view_id,
Id new_parent_id,
diff --git a/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.h b/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.h
index c8ae5c4..2405229 100644
--- a/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.h
+++ b/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.h
@@ -103,6 +103,8 @@ class ViewManagerClientImpl : public ViewManager,
void OnViewBoundsChanged(Id view_id,
RectPtr old_bounds,
RectPtr new_bounds) override;
+ void OnViewViewportMetricsChanged(ViewportMetricsPtr old_metrics,
+ ViewportMetricsPtr new_metrics) override;
void OnViewHierarchyChanged(Id view_id,
Id new_parent_id,
Id old_parent_id,
diff --git a/mojo/services/view_manager/public/cpp/lib/view_private.cc b/mojo/services/view_manager/public/cpp/lib/view_private.cc
index 395aacf..20232e8 100644
--- a/mojo/services/view_manager/public/cpp/lib/view_private.cc
+++ b/mojo/services/view_manager/public/cpp/lib/view_private.cc
@@ -8,6 +8,7 @@ namespace mojo {
ViewPrivate::ViewPrivate(View* view)
: view_(view) {
+ CHECK(view);
}
ViewPrivate::~ViewPrivate() {
diff --git a/mojo/services/view_manager/public/cpp/lib/view_private.h b/mojo/services/view_manager/public/cpp/lib/view_private.h
index 964e6e5..1c54567 100644
--- a/mojo/services/view_manager/public/cpp/lib/view_private.h
+++ b/mojo/services/view_manager/public/cpp/lib/view_private.h
@@ -39,8 +39,9 @@ class ViewPrivate {
view_->properties_ = data;
}
- void set_viewport_metrics(ViewportMetricsPtr viewport_metrics) {
- view_->viewport_metrics_ = viewport_metrics.Pass();
+ void LocalSetViewportMetrics(const ViewportMetrics& old_metrics,
+ const ViewportMetrics& new_metrics) {
+ view_->LocalSetViewportMetrics(new_metrics, new_metrics);
}
void LocalDestroy() {
diff --git a/mojo/services/view_manager/public/cpp/tests/BUILD.gn b/mojo/services/view_manager/public/cpp/tests/BUILD.gn
index 2cbcf43..e912084 100644
--- a/mojo/services/view_manager/public/cpp/tests/BUILD.gn
+++ b/mojo/services/view_manager/public/cpp/tests/BUILD.gn
@@ -7,23 +7,27 @@ import("//testing/test.gni")
test("mojo_view_manager_lib_unittests") {
sources = [
- "view_unittest.cc",
+ "view_manager_test_suite.cc",
+ "view_manager_test_suite.h",
"view_manager_unittest.cc",
+ "view_manager_unittests.cc",
+ "view_unittest.cc",
]
deps = [
"//base",
"//base/test:test_support",
- "//mojo/converters/geometry",
- "//mojo/environment:chromium",
"//mojo/public/cpp/application",
"//mojo/services/geometry/public/cpp",
"//mojo/services/geometry/public/interfaces",
"//mojo/services/view_manager/public/cpp",
- "//mojo/services/view_manager/public/cpp/lib:run_unittests",
"//mojo/services/view_manager/public/interfaces",
"//shell/application_manager",
"//shell:test_support",
"//testing/gtest",
]
+
+ if (use_x11) {
+ deps += [ "//ui/gfx/x" ]
+ }
}
diff --git a/mojo/services/view_manager/public/cpp/tests/DEPS b/mojo/services/view_manager/public/cpp/tests/DEPS
index af27b9a..0f9ddb4 100644
--- a/mojo/services/view_manager/public/cpp/tests/DEPS
+++ b/mojo/services/view_manager/public/cpp/tests/DEPS
@@ -1,5 +1,16 @@
include_rules = [
+ "+mojo/services/geometry/public",
+
+ # TODO(blundell): Determine whether to eliminate these dependencies or move
+ # the tests outside of view_manager's public code. crbug.com/451403
+ "!base/auto_reset.h",
+ "!base/bind.h",
+ "!base/i18n/icu_util.h",
+ "!base/logging.h",
+ "!base/strings/stringprintf.h",
+ "!base/test/launcher/unit_test_launcher.h",
+ "!base/test/test_suite.h",
"!shell/application_manager",
"!shell/shell_test_helper.h",
- "+mojo/services/geometry/public",
+ "!ui/gfx/x/x11_connection.h",
]
diff --git a/mojo/services/view_manager/public/cpp/lib/view_manager_test_suite.cc b/mojo/services/view_manager/public/cpp/tests/view_manager_test_suite.cc
index 93a221e..2bfdd1e 100644
--- a/mojo/services/view_manager/public/cpp/lib/view_manager_test_suite.cc
+++ b/mojo/services/view_manager/public/cpp/tests/view_manager_test_suite.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "mojo/services/view_manager/public/cpp/lib/view_manager_test_suite.h"
+#include "mojo/services/view_manager/public/cpp/tests/view_manager_test_suite.h"
#include "base/i18n/icu_util.h"
diff --git a/mojo/services/view_manager/public/cpp/lib/view_manager_test_suite.h b/mojo/services/view_manager/public/cpp/tests/view_manager_test_suite.h
index ec5bb88..ef81661 100644
--- a/mojo/services/view_manager/public/cpp/lib/view_manager_test_suite.h
+++ b/mojo/services/view_manager/public/cpp/tests/view_manager_test_suite.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_SERVICES_VIEW_MANAGER_PUBLIC_CPP_LIB_VIEW_MANAGER_TEST_SUITE_H_
-#define MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_LIB_VIEW_MANAGER_TEST_SUITE_H_
+#ifndef MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_SUITE_H_
+#define MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_SUITE_H_
#include "base/test/test_suite.h"
@@ -23,4 +23,4 @@ class ViewManagerTestSuite : public base::TestSuite {
} // namespace mojo
-#endif // MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_LIB_VIEW_MANAGER_TEST_SUITE_H_
+#endif // MOJO_SERVICES_VIEW_MANAGER_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_SUITE_H_
diff --git a/mojo/services/view_manager/public/cpp/tests/view_manager_unittest.cc b/mojo/services/view_manager/public/cpp/tests/view_manager_unittest.cc
index d9e4db8..bc69464 100644
--- a/mojo/services/view_manager/public/cpp/tests/view_manager_unittest.cc
+++ b/mojo/services/view_manager/public/cpp/tests/view_manager_unittest.cc
@@ -63,11 +63,11 @@ class ConnectApplicationLoader : public ApplicationLoader,
// Overridden from ApplicationLoader:
void Load(ApplicationManager* manager,
const GURL& url,
- ScopedMessagePipeHandle shell_handle,
+ InterfaceRequest<Application> application_request,
LoadCallback callback) override {
- ASSERT_TRUE(shell_handle.is_valid());
+ ASSERT_TRUE(application_request.is_pending());
scoped_ptr<ApplicationImpl> app(
- new ApplicationImpl(this, shell_handle.Pass()));
+ new ApplicationImpl(this, application_request.Pass()));
apps_.push_back(app.release());
}
diff --git a/mojo/services/view_manager/public/cpp/lib/view_manager_unittests.cc b/mojo/services/view_manager/public/cpp/tests/view_manager_unittests.cc
index 1d8bd98..95a7b5c 100644
--- a/mojo/services/view_manager/public/cpp/lib/view_manager_unittests.cc
+++ b/mojo/services/view_manager/public/cpp/tests/view_manager_unittests.cc
@@ -4,7 +4,7 @@
#include "base/bind.h"
#include "base/test/launcher/unit_test_launcher.h"
-#include "mojo/services/view_manager/public/cpp/lib/view_manager_test_suite.h"
+#include "mojo/services/view_manager/public/cpp/tests/view_manager_test_suite.h"
int main(int argc, char** argv) {
mojo::ViewManagerTestSuite test_suite(argc, argv);
diff --git a/mojo/services/view_manager/public/cpp/view.h b/mojo/services/view_manager/public/cpp/view.h
index 1215a3b..07bc5b0 100644
--- a/mojo/services/view_manager/public/cpp/view.h
+++ b/mojo/services/view_manager/public/cpp/view.h
@@ -153,6 +153,8 @@ class View {
// Returns true if the order actually changed.
bool LocalReorder(View* relative, OrderDirection direction);
void LocalSetBounds(const Rect& old_bounds, const Rect& new_bounds);
+ void LocalSetViewportMetrics(const ViewportMetrics& old_metrics,
+ const ViewportMetrics& new_metrics);
void LocalSetDrawn(bool drawn);
// Methods implementing visibility change notifications. See ViewObserver
diff --git a/mojo/services/view_manager/public/cpp/view_observer.h b/mojo/services/view_manager/public/cpp/view_observer.h
index 4c0ba87..7430566 100644
--- a/mojo/services/view_manager/public/cpp/view_observer.h
+++ b/mojo/services/view_manager/public/cpp/view_observer.h
@@ -56,6 +56,11 @@ class ViewObserver {
const Rect& old_bounds,
const Rect& new_bounds) {}
+ virtual void OnViewViewportMetricsChanged(View* view,
+ const ViewportMetrics& old_bounds,
+ const ViewportMetrics& new_bounds) {
+ }
+
virtual void OnCaptureChanged(View* gained_capture, View* lost_capture) {}
virtual void OnViewFocusChanged(View* gained_focus, View* lost_focus) {}
virtual void OnViewActivationChanged(View* gained_active, View* lost_active) {
diff --git a/mojo/services/view_manager/public/interfaces/view_manager.mojom b/mojo/services/view_manager/public/interfaces/view_manager.mojom
index 55552f8..23238d5 100644
--- a/mojo/services/view_manager/public/interfaces/view_manager.mojom
+++ b/mojo/services/view_manager/public/interfaces/view_manager.mojom
@@ -159,6 +159,11 @@ interface ViewManagerClient {
mojo.Rect old_bounds,
mojo.Rect new_bounds);
+ // Invoked when the viewport metrics for the view have changed.
+ // Clients are expected to propagate this to the view tree.
+ OnViewViewportMetricsChanged(mojo.ViewportMetrics old_metrics,
+ mojo.ViewportMetrics new_metrics);
+
// Invoked when a change is done to the hierarchy. A value of 0 is used to
// identify a null view. For example, if the old_parent is NULL, 0 is
// supplied.
@@ -173,7 +178,7 @@ interface ViewManagerClient {
// Invoked when the order of views within a parent changes.
OnViewReordered(uint32 view_id,
uint32 relative_view_id,
- OrderDirection direction);
+ OrderDirection direction);
// Invoked when a view is deleted.
OnViewDeleted(uint32 view);
diff --git a/third_party/mojo/src/mojo/edk/embedder/BUILD.gn b/third_party/mojo/src/mojo/edk/embedder/BUILD.gn
index d9a6e69..5eb77d7 100644
--- a/third_party/mojo/src/mojo/edk/embedder/BUILD.gn
+++ b/third_party/mojo/src/mojo/edk/embedder/BUILD.gn
@@ -35,6 +35,7 @@ mojo_edk_source_set("embedder") {
mojo_edk_configs = [ "mojo/edk/system:system_config" ]
public_deps = [
+ ":delegates",
":platform",
]
@@ -90,6 +91,27 @@ mojo_edk_source_set("platform") {
}
}
+mojo_edk_source_set("delegates") {
+ # This isn't really a standalone target; it must be linked into the
+ # mojo_system_impl component.
+ visibility = [ ":embedder" ]
+
+ mojo_edk_visibility = [ "mojo/edk/system" ]
+
+ sources = [
+ "master_process_delegate.h",
+ "slave_process_delegate.h",
+ ]
+
+ defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
+
+ mojo_edk_configs = [ "mojo/edk/system:system_config" ]
+
+ deps = [
+ "//base",
+ ]
+}
+
mojo_edk_source_set("embedder_unittests") {
testonly = true
mojo_edk_visibility = [ "mojo/edk/system:mojo_system_unittests" ]
diff --git a/third_party/mojo/src/mojo/edk/embedder/master_process_delegate.h b/third_party/mojo/src/mojo/edk/embedder/master_process_delegate.h
new file mode 100644
index 0000000..13791f4
--- /dev/null
+++ b/third_party/mojo/src/mojo/edk/embedder/master_process_delegate.h
@@ -0,0 +1,47 @@
+// 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_MASTER_PROCESS_DELEGATE_H_
+#define MOJO_EDK_EMBEDDER_MASTER_PROCESS_DELEGATE_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "mojo/edk/system/system_impl_export.h"
+
+namespace mojo {
+namespace embedder {
+
+// An interface for containers of slave process information, to be used by
+// |MasterProcessDelegate| (below).
+class MOJO_SYSTEM_IMPL_EXPORT SlaveInfo {
+ public:
+ SlaveInfo() {}
+ virtual ~SlaveInfo() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SlaveInfo);
+};
+
+// An interface for the master process delegate (which lives in the master
+// process).
+class MOJO_SYSTEM_IMPL_EXPORT MasterProcessDelegate {
+ public:
+ // Called when contact with the slave process specified by |slave_info| has
+ // been lost.
+ // TODO(vtl): Obviously, there needs to be a suitable embedder API for
+ // connecting to a process. What will it be? Mention that here once it exists.
+ virtual void OnSlaveDisconnect(scoped_ptr<SlaveInfo> slave_info) = 0;
+
+ protected:
+ MasterProcessDelegate() {}
+ virtual ~MasterProcessDelegate() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MasterProcessDelegate);
+};
+
+} // namespace embedder
+} // namespace mojo
+
+#endif // MOJO_EDK_EMBEDDER_MASTER_PROCESS_DELEGATE_H_
diff --git a/third_party/mojo/src/mojo/edk/embedder/slave_process_delegate.h b/third_party/mojo/src/mojo/edk/embedder/slave_process_delegate.h
new file mode 100644
index 0000000..1c55a7a
--- /dev/null
+++ b/third_party/mojo/src/mojo/edk/embedder/slave_process_delegate.h
@@ -0,0 +1,36 @@
+// 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_SLAVE_PROCESS_DELEGATE_H_
+#define MOJO_EDK_EMBEDDER_SLAVE_PROCESS_DELEGATE_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "mojo/edk/system/system_impl_export.h"
+
+namespace mojo {
+namespace embedder {
+
+// An interface for the slave process delegate (which lives in each slave
+// process).
+class MOJO_SYSTEM_IMPL_EXPORT SlaveProcessDelegate {
+ public:
+ // Called when contact with the master process has been lost.
+ // TODO(vtl): Obviously, there needs to be a suitable embedder API for
+ // connecting to the master process. What will it be? Mention that here once
+ // it exists.
+ virtual void OnMasterDisconnect() = 0;
+
+ protected:
+ SlaveProcessDelegate() {}
+ virtual ~SlaveProcessDelegate() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SlaveProcessDelegate);
+};
+
+} // namespace embedder
+} // namespace mojo
+
+#endif // MOJO_EDK_EMBEDDER_SLAVE_PROCESS_DELEGATE_H_
diff --git a/third_party/mojo/src/mojo/edk/system/BUILD.gn b/third_party/mojo/src/mojo/edk/system/BUILD.gn
index 67310c8..12fa225 100644
--- a/third_party/mojo/src/mojo/edk/system/BUILD.gn
+++ b/third_party/mojo/src/mojo/edk/system/BUILD.gn
@@ -39,6 +39,7 @@ component("system") {
"channel_manager.h",
"configuration.cc",
"configuration.h",
+ "connection_manager.h",
"core.cc",
"core.h",
"data_pipe.cc",
@@ -62,6 +63,8 @@ component("system") {
"local_message_pipe_endpoint.h",
"mapping_table.cc",
"mapping_table.h",
+ "master_connection_manager.cc",
+ "master_connection_manager.h",
"memory.cc",
"memory.h",
"message_in_transit.cc",
@@ -87,6 +90,8 @@ component("system") {
"shared_buffer_dispatcher.h",
"simple_dispatcher.cc",
"simple_dispatcher.h",
+ "slave_connection_manager.cc",
+ "slave_connection_manager.h",
"transport_data.cc",
"transport_data.h",
"unique_identifier.cc",
@@ -104,6 +109,7 @@ component("system") {
public_deps = [
"../embedder",
+ "../embedder:delegates",
"../embedder:platform",
"../../public/c/system",
]
@@ -139,6 +145,7 @@ test("mojo_system_unittests") {
"channel_endpoint_id_unittest.cc",
"channel_manager_unittest.cc",
"channel_unittest.cc",
+ "connection_manager_unittest.cc",
"core_test_base.cc",
"core_test_base.h",
"core_unittest.cc",
diff --git a/third_party/mojo/src/mojo/edk/system/connection_manager.h b/third_party/mojo/src/mojo/edk/system/connection_manager.h
new file mode 100644
index 0000000..fede7a5
--- /dev/null
+++ b/third_party/mojo/src/mojo/edk/system/connection_manager.h
@@ -0,0 +1,105 @@
+// 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_SYSTEM_CONNECTION_MANAGER_H_
+#define MOJO_EDK_SYSTEM_CONNECTION_MANAGER_H_
+
+#include "base/macros.h"
+#include "mojo/edk/system/unique_identifier.h"
+
+namespace mojo {
+
+namespace embedder {
+class ScopedPlatformHandle;
+} // namespace embedder
+
+namespace system {
+
+// (Temporary, unique) identifiers for connections, used as they are being
+// brought up:
+typedef UniqueIdentifier ConnectionIdentifier;
+
+// Identifiers for processes (note that these are not OS process IDs):
+typedef uint64_t ProcessIdentifier;
+const ProcessIdentifier kInvalidProcessIdentifier = 0;
+
+// |ConnectionManager| is an interface for the system that allows "connections"
+// (i.e., native "pipes") to be established between different processes.
+//
+// The starting point for establishing such a connection is that the two
+// processes (not necessarily distinct) are provided with a common
+// |ConnectionIdentifier|, and also some (probably indirect, temporary) way of
+// communicating.
+//
+// (The usual case for this are processes A, B, C, with connections A <-> B <->
+// C, with the goal being to establish a direct connection A <-> C. Process B
+// generates a |ConnectionIdentifier| that it transmits to A and C, and serves
+// as an intermediary until A and C are directly connected.)
+//
+// To establish such a connection, each process calls |AllowConnect()| with the
+// common |ConnectionIdentifier|. Each process then informs the other process
+// that it has done so. Once a process knows that both processes have called
+// |AllowConnect()|, it proceeds to call |Connect()|.
+//
+// On success, if the two processes are in fact distinct, |Connect()| provides a
+// native (platform) handle for a "pipe" that connects/will connect the two
+// processes. (If they are in fact the same process, success will simply yield
+// no valid handle, to indicate this case.)
+//
+// Additionally, on success |Connect()| also provides a unique identifier for
+// the peer process. In this way, processes may recognize when they already have
+// a direct connection and reuse that, disposing of the new one provided by
+// |Connect()|. (TODO(vtl): This is somewhat wasteful, but removes the need to
+// handle various race conditions, and for the "master" process -- see below --
+// to track connection teardowns.)
+//
+// Implementation notes: We implement this using a "star topology", with a
+// single trusted "master" (broker) process and an arbitrary number of untrusted
+// "slave" (client) processes. The former is implemented by
+// |MasterConnectionManager| (master_connection_manager.*) and the latter by
+// |SlaveConnectionManager| (slave_connection_manager.*). Each slave is
+// connected to the master by a special dedicated |RawChannel|, on which it does
+// synchronous IPC (note, however, that the master should never block on any
+// slave).
+class ConnectionManager {
+ public:
+ // All of these methods return true on success or false on failure. Failure is
+ // obviously fatal for the establishment of a particular connection, but
+ // should not be treated as fatal to the process. Failure may, e.g., be caused
+ // by a misbehaving (malicious) untrusted peer process.
+
+ // TODO(vtl): Add a "get my own process identifier" method?
+
+ // Allows a process who makes the identical call (with equal |connection_id|)
+ // to connect to the calling process. (On success, there will be a "pending
+ // connection" for the given |connection_id| for the calling process.)
+ virtual bool AllowConnect(const ConnectionIdentifier& connection_id) = 0;
+
+ // Cancels a pending connection for the calling process. (Note that this may
+ // fail even if |AllowConnect()| succeeded; regardless, |Connect()| should not
+ // be called.)
+ virtual bool CancelConnect(const ConnectionIdentifier& connection_id) = 0;
+
+ // Connects a pending connection; to be called only after both parties have
+ // called |AllowConnect()|. On success, |peer_process_identifier| is set to an
+ // unique identifier for the peer process, and if the peer process is not the
+ // same as the calling process then |*platform_handle| is set to a suitable
+ // native handle connecting the two parties (if the two parties are the same
+ // process, then |*platform_handle| is reset to be invalid).
+ virtual bool Connect(const ConnectionIdentifier& connection_id,
+ ProcessIdentifier* peer_process_identifier,
+ embedder::ScopedPlatformHandle* platform_handle) = 0;
+
+ protected:
+ ConnectionManager() {}
+ virtual ~ConnectionManager() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConnectionManager);
+};
+
+} // namespace system
+} // namespace mojo
+
+#endif // MOJO_EDK_SYSTEM_CONNECTION_MANAGER_H_
diff --git a/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc b/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc
new file mode 100644
index 0000000..f46c386
--- /dev/null
+++ b/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc
@@ -0,0 +1,501 @@
+// 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.
+
+// This is really a unit test for |MasterConnectionManager| and
+// |SlaveConnectionManager| (since they need to be tested together).
+
+#include "mojo/edk/system/connection_manager.h"
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_checker.h"
+#include "mojo/edk/embedder/master_process_delegate.h"
+#include "mojo/edk/embedder/platform_channel_pair.h"
+#include "mojo/edk/embedder/slave_process_delegate.h"
+#include "mojo/edk/system/master_connection_manager.h"
+#include "mojo/edk/system/slave_connection_manager.h"
+#include "mojo/edk/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace system {
+namespace {
+
+bool ArePlatformHandlesConnected(const embedder::PlatformHandle& h1,
+ const embedder::PlatformHandle& h2) {
+ const uint32_t w1 = 0xdeadbeef;
+ size_t num_bytes = 0;
+ if (!mojo::test::BlockingWrite(h1, &w1, sizeof(w1), &num_bytes) ||
+ num_bytes != sizeof(w1))
+ return false;
+ uint32_t r = 0;
+ num_bytes = 0;
+ if (!mojo::test::BlockingRead(h2, &r, sizeof(r), &num_bytes) ||
+ num_bytes != sizeof(r))
+ return false;
+ if (r != w1)
+ return false;
+
+ const uint32_t w2 = 0xfeedface;
+ num_bytes = 0;
+ if (!mojo::test::BlockingWrite(h1, &w2, sizeof(w2), &num_bytes) ||
+ num_bytes != sizeof(w2))
+ return false;
+ r = 0;
+ num_bytes = 0;
+ if (!mojo::test::BlockingRead(h2, &r, sizeof(r), &num_bytes) ||
+ num_bytes != sizeof(r))
+ return false;
+ if (r != w2)
+ return false;
+
+ return true;
+}
+
+class TestSlaveInfo : public embedder::SlaveInfo {
+ public:
+ explicit TestSlaveInfo(const std::string& name) : name_(name) {}
+ ~TestSlaveInfo() override { CHECK(thread_checker_.CalledOnValidThread()); }
+
+ const std::string& name() const { return name_; }
+
+ private:
+ base::ThreadChecker thread_checker_;
+ std::string name_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestSlaveInfo);
+};
+
+// Connects the given |slave| (with the given |slave_process_delegate| to the
+// given master, creating and using a |TestSlaveInfo| with the given
+// |slave_name|.
+void ConnectSlave(MasterConnectionManager* master,
+ embedder::SlaveProcessDelegate* slave_process_delegate,
+ SlaveConnectionManager* slave,
+ const std::string& slave_name) {
+ embedder::PlatformChannelPair platform_channel_pair;
+ master->AddSlave(make_scoped_ptr(new TestSlaveInfo(slave_name)),
+ platform_channel_pair.PassServerHandle());
+ slave->Init(slave_process_delegate, platform_channel_pair.PassClientHandle());
+}
+
+class MockMasterProcessDelegate : public embedder::MasterProcessDelegate {
+ public:
+ MockMasterProcessDelegate()
+ : current_run_loop_(), on_slave_disconnect_calls_(0) {}
+ ~MockMasterProcessDelegate() override {}
+
+ void RunUntilNotified() {
+ CHECK(!current_run_loop_);
+ base::RunLoop run_loop;
+ current_run_loop_ = &run_loop;
+ run_loop.Run();
+ current_run_loop_ = nullptr;
+ }
+
+ unsigned on_slave_disconnect_calls() const {
+ return on_slave_disconnect_calls_;
+ }
+ const std::string& last_slave_disconnect_name() const {
+ return last_slave_disconnect_name_;
+ }
+
+ // |embedder::MasterProcessDelegate| implementation:
+ void OnSlaveDisconnect(scoped_ptr<embedder::SlaveInfo> slave_info) override {
+ CHECK(thread_checker_.CalledOnValidThread());
+ on_slave_disconnect_calls_++;
+ last_slave_disconnect_name_ =
+ static_cast<TestSlaveInfo*>(slave_info.get())->name();
+ DVLOG(1) << "Disconnected from slave process "
+ << last_slave_disconnect_name_;
+ slave_info.reset();
+
+ if (current_run_loop_)
+ current_run_loop_->Quit();
+ }
+
+ private:
+ base::ThreadChecker thread_checker_;
+ base::RunLoop* current_run_loop_;
+
+ unsigned on_slave_disconnect_calls_;
+ std::string last_slave_disconnect_name_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockMasterProcessDelegate);
+};
+
+class MockSlaveProcessDelegate : public embedder::SlaveProcessDelegate {
+ public:
+ MockSlaveProcessDelegate()
+ : current_run_loop_(), on_master_disconnect_calls_(0) {}
+ ~MockSlaveProcessDelegate() override {}
+
+ void RunUntilNotified() {
+ CHECK(!current_run_loop_);
+ base::RunLoop run_loop;
+ current_run_loop_ = &run_loop;
+ run_loop.Run();
+ current_run_loop_ = nullptr;
+ }
+
+ unsigned on_master_disconnect_calls() const {
+ return on_master_disconnect_calls_;
+ }
+
+ // |embedder::SlaveProcessDelegate| implementation:
+ void OnMasterDisconnect() override {
+ CHECK(thread_checker_.CalledOnValidThread());
+ on_master_disconnect_calls_++;
+ DVLOG(1) << "Disconnected from master process";
+
+ if (current_run_loop_)
+ current_run_loop_->Quit();
+ }
+
+ private:
+ base::ThreadChecker thread_checker_;
+ base::RunLoop* current_run_loop_;
+
+ unsigned on_master_disconnect_calls_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockSlaveProcessDelegate);
+};
+
+class ConnectionManagerTest : public testing::Test {
+ protected:
+ ConnectionManagerTest() {}
+ ~ConnectionManagerTest() override {}
+
+ base::MessageLoop& message_loop() { return message_loop_; }
+ MockMasterProcessDelegate& master_process_delegate() {
+ return master_process_delegate_;
+ }
+
+ private:
+ base::MessageLoop message_loop_;
+ MockMasterProcessDelegate master_process_delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConnectionManagerTest);
+};
+
+TEST_F(ConnectionManagerTest, BasicConnectSlaves) {
+ MasterConnectionManager master;
+ master.Init(&master_process_delegate());
+
+ MockSlaveProcessDelegate slave1_process_delegate;
+ SlaveConnectionManager slave1;
+ ConnectSlave(&master, &slave1_process_delegate, &slave1, "slave1");
+
+ MockSlaveProcessDelegate slave2_process_delegate;
+ SlaveConnectionManager slave2;
+ ConnectSlave(&master, &slave2_process_delegate, &slave2, "slave2");
+
+ ConnectionIdentifier connection_id = ConnectionIdentifier::Generate();
+ EXPECT_TRUE(slave1.AllowConnect(connection_id));
+ EXPECT_TRUE(slave2.AllowConnect(connection_id));
+
+ ProcessIdentifier peer1;
+ embedder::ScopedPlatformHandle h1;
+ EXPECT_TRUE(slave1.Connect(connection_id, &peer1, &h1));
+ EXPECT_TRUE(h1.is_valid());
+ ProcessIdentifier peer2;
+ embedder::ScopedPlatformHandle h2;
+ EXPECT_TRUE(slave2.Connect(connection_id, &peer2, &h2));
+ EXPECT_TRUE(h2.is_valid());
+
+ // TODO(vtl): If/when I add the ability to get one's own process identifier,
+ // there'll be more we can check.
+ EXPECT_NE(peer1, peer2);
+ EXPECT_TRUE(ArePlatformHandlesConnected(h1.get(), h2.get()));
+
+ // The process manager shouldn't have gotten any notifications yet. (Spin the
+ // message loop to make sure none were enqueued.)
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0u, master_process_delegate().on_slave_disconnect_calls());
+
+ slave1.Shutdown();
+
+ // |OnSlaveDisconnect()| should be called once.
+ master_process_delegate().RunUntilNotified();
+ EXPECT_EQ(1u, master_process_delegate().on_slave_disconnect_calls());
+ EXPECT_EQ("slave1", master_process_delegate().last_slave_disconnect_name());
+
+ slave2.Shutdown();
+
+ // |OnSlaveDisconnect()| should be called again.
+ master_process_delegate().RunUntilNotified();
+ EXPECT_EQ(2u, master_process_delegate().on_slave_disconnect_calls());
+ EXPECT_EQ("slave2", master_process_delegate().last_slave_disconnect_name());
+
+ master.Shutdown();
+
+ // None of the above should result in |OnMasterDisconnect()| being called.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0u, slave1_process_delegate.on_master_disconnect_calls());
+ EXPECT_EQ(0u, slave2_process_delegate.on_master_disconnect_calls());
+}
+
+TEST_F(ConnectionManagerTest, ShutdownMasterBeforeSlave) {
+ MasterConnectionManager master;
+ master.Init(&master_process_delegate());
+
+ MockSlaveProcessDelegate slave_process_delegate;
+ SlaveConnectionManager slave;
+ ConnectSlave(&master, &slave_process_delegate, &slave, "slave");
+
+ // The process manager shouldn't have gotten any notifications yet. (Spin the
+ // message loop to make sure none were enqueued.)
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0u, master_process_delegate().on_slave_disconnect_calls());
+
+ master.Shutdown();
+
+ // |OnSlaveDisconnect()| should be called.
+ master_process_delegate().RunUntilNotified();
+ EXPECT_EQ(1u, master_process_delegate().on_slave_disconnect_calls());
+ EXPECT_EQ("slave", master_process_delegate().last_slave_disconnect_name());
+
+ // |OnMasterDisconnect()| should also be (or have been) called.
+ slave_process_delegate.RunUntilNotified();
+ EXPECT_EQ(1u, slave_process_delegate.on_master_disconnect_calls());
+
+ slave.Shutdown();
+}
+
+TEST_F(ConnectionManagerTest, SlaveCancelConnect) {
+ MasterConnectionManager master;
+ master.Init(&master_process_delegate());
+
+ MockSlaveProcessDelegate slave1_process_delegate;
+ SlaveConnectionManager slave1;
+ ConnectSlave(&master, &slave1_process_delegate, &slave1, "slave1");
+
+ MockSlaveProcessDelegate slave2_process_delegate;
+ SlaveConnectionManager slave2;
+ ConnectSlave(&master, &slave2_process_delegate, &slave2, "slave2");
+
+ ConnectionIdentifier connection_id = ConnectionIdentifier::Generate();
+ EXPECT_TRUE(slave1.AllowConnect(connection_id));
+ EXPECT_TRUE(slave2.AllowConnect(connection_id));
+
+ EXPECT_TRUE(slave1.CancelConnect(connection_id));
+ ProcessIdentifier peer2;
+ embedder::ScopedPlatformHandle h2;
+ EXPECT_FALSE(slave2.Connect(connection_id, &peer2, &h2));
+ EXPECT_FALSE(h2.is_valid());
+
+ slave1.Shutdown();
+ slave2.Shutdown();
+ master.Shutdown();
+}
+
+// Tests that pending connections are removed on error.
+TEST_F(ConnectionManagerTest, ErrorRemovePending) {
+ MasterConnectionManager master;
+ master.Init(&master_process_delegate());
+
+ MockSlaveProcessDelegate slave1_process_delegate;
+ SlaveConnectionManager slave1;
+ ConnectSlave(&master, &slave1_process_delegate, &slave1, "slave1");
+
+ MockSlaveProcessDelegate slave2_process_delegate;
+ SlaveConnectionManager slave2;
+ ConnectSlave(&master, &slave2_process_delegate, &slave2, "slave2");
+
+ ConnectionIdentifier connection_id = ConnectionIdentifier::Generate();
+ EXPECT_TRUE(slave1.AllowConnect(connection_id));
+ EXPECT_TRUE(slave2.AllowConnect(connection_id));
+
+ slave1.Shutdown();
+
+ // |OnSlaveDisconnect()| should be called. After it's called, this means that
+ // the disconnect has been detected and handled, including the removal of the
+ // pending connection.
+ master_process_delegate().RunUntilNotified();
+ EXPECT_EQ(1u, master_process_delegate().on_slave_disconnect_calls());
+
+ ProcessIdentifier peer2;
+ embedder::ScopedPlatformHandle h2;
+ EXPECT_FALSE(slave2.Connect(connection_id, &peer2, &h2));
+ EXPECT_FALSE(h2.is_valid());
+
+ slave2.Shutdown();
+ master.Shutdown();
+}
+
+TEST_F(ConnectionManagerTest, ConnectSlaveToSelf) {
+ MasterConnectionManager master;
+ master.Init(&master_process_delegate());
+
+ MockSlaveProcessDelegate slave_process_delegate;
+ SlaveConnectionManager slave;
+ ConnectSlave(&master, &slave_process_delegate, &slave, "slave");
+
+ ConnectionIdentifier connection_id = ConnectionIdentifier::Generate();
+ EXPECT_TRUE(slave.AllowConnect(connection_id));
+ EXPECT_TRUE(slave.AllowConnect(connection_id));
+
+ // Currently, the connect-to-self case is signalled by the master not sending
+ // back a handle.
+ ProcessIdentifier peer1;
+ embedder::ScopedPlatformHandle h1;
+ EXPECT_TRUE(slave.Connect(connection_id, &peer1, &h1));
+ EXPECT_FALSE(h1.is_valid());
+ ProcessIdentifier peer2;
+ embedder::ScopedPlatformHandle h2;
+ EXPECT_TRUE(slave.Connect(connection_id, &peer2, &h2));
+ EXPECT_FALSE(h2.is_valid());
+
+ EXPECT_EQ(peer1, peer2);
+
+ slave.Shutdown();
+ master.Shutdown();
+}
+
+TEST_F(ConnectionManagerTest, ConnectSlavesTwice) {
+ MasterConnectionManager master;
+ master.Init(&master_process_delegate());
+
+ MockSlaveProcessDelegate slave1_process_delegate;
+ SlaveConnectionManager slave1;
+ ConnectSlave(&master, &slave1_process_delegate, &slave1, "slave1");
+
+ MockSlaveProcessDelegate slave2_process_delegate;
+ SlaveConnectionManager slave2;
+ ConnectSlave(&master, &slave2_process_delegate, &slave2, "slave2");
+
+ ConnectionIdentifier connection_id = ConnectionIdentifier::Generate();
+ EXPECT_TRUE(slave1.AllowConnect(connection_id));
+ EXPECT_TRUE(slave2.AllowConnect(connection_id));
+
+ ProcessIdentifier peer1;
+ embedder::ScopedPlatformHandle h1;
+ EXPECT_TRUE(slave1.Connect(connection_id, &peer1, &h1));
+ ProcessIdentifier peer2;
+ embedder::ScopedPlatformHandle h2;
+ EXPECT_TRUE(slave2.Connect(connection_id, &peer2, &h2));
+
+ EXPECT_NE(peer1, peer2);
+ EXPECT_TRUE(ArePlatformHandlesConnected(h1.get(), h2.get()));
+
+ // Currently, the master doesn't detect the case of connecting a pair of
+ // slaves that are already connected. (Doing so would require more careful
+ // tracking and is prone to races -- especially if we want slaves to be able
+ // to tear down no-longer-needed connections.) But the slaves should be able
+ // to do the tracking themselves (using the peer process identifiers).
+ connection_id = ConnectionIdentifier::Generate();
+ EXPECT_TRUE(slave1.AllowConnect(connection_id));
+ EXPECT_TRUE(slave2.AllowConnect(connection_id));
+
+ h1.reset();
+ h2.reset();
+ ProcessIdentifier second_peer2;
+ EXPECT_TRUE(slave2.Connect(connection_id, &second_peer2, &h2));
+ ProcessIdentifier second_peer1;
+ EXPECT_TRUE(slave1.Connect(connection_id, &second_peer1, &h1));
+
+ EXPECT_EQ(peer1, second_peer1);
+ EXPECT_EQ(peer2, second_peer2);
+ EXPECT_TRUE(ArePlatformHandlesConnected(h1.get(), h2.get()));
+
+ slave2.Shutdown();
+ slave1.Shutdown();
+ master.Shutdown();
+}
+
+TEST_F(ConnectionManagerTest, ConnectMasterToSlave) {
+ MasterConnectionManager master;
+ master.Init(&master_process_delegate());
+
+ MockSlaveProcessDelegate slave_process_delegate;
+ SlaveConnectionManager slave;
+ ConnectSlave(&master, &slave_process_delegate, &slave, "slave");
+
+ ConnectionIdentifier connection_id = ConnectionIdentifier::Generate();
+ EXPECT_TRUE(master.AllowConnect(connection_id));
+ EXPECT_TRUE(slave.AllowConnect(connection_id));
+
+ ProcessIdentifier master_peer;
+ embedder::ScopedPlatformHandle master_h;
+ EXPECT_TRUE(master.Connect(connection_id, &master_peer, &master_h));
+ EXPECT_TRUE(master_h.is_valid());
+ ProcessIdentifier slave_peer;
+ embedder::ScopedPlatformHandle slave_h;
+ EXPECT_TRUE(slave.Connect(connection_id, &slave_peer, &slave_h));
+ EXPECT_TRUE(slave_h.is_valid());
+
+ EXPECT_NE(master_peer, slave_peer);
+ EXPECT_TRUE(ArePlatformHandlesConnected(master_h.get(), slave_h.get()));
+
+ slave.Shutdown();
+ master.Shutdown();
+}
+
+TEST_F(ConnectionManagerTest, ConnectMasterToSelf) {
+ MasterConnectionManager master;
+ master.Init(&master_process_delegate());
+
+ ConnectionIdentifier connection_id = ConnectionIdentifier::Generate();
+ EXPECT_TRUE(master.AllowConnect(connection_id));
+ EXPECT_TRUE(master.AllowConnect(connection_id));
+
+ // Currently, the connect-to-self case is signalled by the master not sending
+ // back a handle.
+ ProcessIdentifier peer1;
+ embedder::ScopedPlatformHandle h1;
+ EXPECT_TRUE(master.Connect(connection_id, &peer1, &h1));
+ EXPECT_FALSE(h1.is_valid());
+ ProcessIdentifier peer2;
+ embedder::ScopedPlatformHandle h2;
+ EXPECT_TRUE(master.Connect(connection_id, &peer2, &h2));
+ EXPECT_FALSE(h2.is_valid());
+
+ EXPECT_EQ(peer1, peer2);
+
+ master.Shutdown();
+}
+
+TEST_F(ConnectionManagerTest, MasterCancelConnect) {
+ MasterConnectionManager master;
+ master.Init(&master_process_delegate());
+
+ MockSlaveProcessDelegate slave_process_delegate;
+ SlaveConnectionManager slave;
+ ConnectSlave(&master, &slave_process_delegate, &slave, "slave");
+
+ ConnectionIdentifier connection_id = ConnectionIdentifier::Generate();
+ EXPECT_TRUE(master.AllowConnect(connection_id));
+ EXPECT_TRUE(slave.AllowConnect(connection_id));
+
+ EXPECT_TRUE(master.CancelConnect(connection_id));
+ ProcessIdentifier peer;
+ embedder::ScopedPlatformHandle h;
+ EXPECT_FALSE(slave.Connect(connection_id, &peer, &h));
+ EXPECT_FALSE(h.is_valid());
+
+ slave.Shutdown();
+ master.Shutdown();
+}
+
+TEST_F(ConnectionManagerTest, AddSlaveThenImmediateShutdown) {
+ MasterConnectionManager master;
+ master.Init(&master_process_delegate());
+
+ MockSlaveProcessDelegate slave_process_delegate;
+ SlaveConnectionManager slave;
+ embedder::PlatformChannelPair platform_channel_pair;
+ master.AddSlave(make_scoped_ptr(new TestSlaveInfo("slave")),
+ platform_channel_pair.PassServerHandle());
+ master.Shutdown();
+ // Since we never initialized |slave|, we don't have to shut it down.
+}
+
+} // namespace
+} // namespace system
+} // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc b/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc
new file mode 100644
index 0000000..b78dfb6
--- /dev/null
+++ b/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc
@@ -0,0 +1,572 @@
+// 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/system/master_connection_manager.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "mojo/edk/embedder/master_process_delegate.h"
+#include "mojo/edk/embedder/platform_channel_pair.h"
+#include "mojo/edk/embedder/platform_handle_vector.h"
+#include "mojo/edk/system/message_in_transit.h"
+#include "mojo/edk/system/raw_channel.h"
+#include "mojo/edk/system/transport_data.h"
+
+namespace mojo {
+namespace system {
+
+const ProcessIdentifier kFirstProcessIdentifier = 1;
+const ProcessIdentifier kMasterProcessIdentifier =
+ static_cast<ProcessIdentifier>(-1);
+
+// MasterConnectionManager::Helper ---------------------------------------------
+
+// |MasterConnectionManager::Helper| is not thread-safe, and must only be used
+// on its |owner_|'s private thread.
+class MasterConnectionManager::Helper : public RawChannel::Delegate {
+ public:
+ Helper(MasterConnectionManager* owner,
+ ProcessIdentifier process_identifier,
+ scoped_ptr<embedder::SlaveInfo> slave_info,
+ embedder::ScopedPlatformHandle platform_handle);
+ ~Helper() override;
+
+ void Init();
+ scoped_ptr<embedder::SlaveInfo> Shutdown();
+
+ private:
+ // |RawChannel::Delegate| methods:
+ void OnReadMessage(
+ const MessageInTransit::View& message_view,
+ embedder::ScopedPlatformHandleVectorPtr platform_handles) override;
+ void OnError(Error error) override;
+
+ // Handles an error that's fatal to this object. Note that this probably
+ // results in |Shutdown()| being called (in the nested context) and then this
+ // object being destroyed.
+ void FatalError();
+
+ MasterConnectionManager* const owner_;
+ const ProcessIdentifier process_identifier_;
+ scoped_ptr<embedder::SlaveInfo> slave_info_;
+ scoped_ptr<RawChannel> raw_channel_;
+
+ DISALLOW_COPY_AND_ASSIGN(Helper);
+};
+
+MasterConnectionManager::Helper::Helper(
+ MasterConnectionManager* owner,
+ ProcessIdentifier process_identifier,
+ scoped_ptr<embedder::SlaveInfo> slave_info,
+ embedder::ScopedPlatformHandle platform_handle)
+ : owner_(owner),
+ process_identifier_(process_identifier),
+ slave_info_(slave_info.Pass()),
+ raw_channel_(RawChannel::Create(platform_handle.Pass())) {
+}
+
+MasterConnectionManager::Helper::~Helper() {
+ DCHECK(!slave_info_);
+}
+
+void MasterConnectionManager::Helper::Init() {
+ raw_channel_->Init(this);
+}
+
+scoped_ptr<embedder::SlaveInfo> MasterConnectionManager::Helper::Shutdown() {
+ raw_channel_->Shutdown();
+ raw_channel_.reset();
+ return slave_info_.Pass();
+}
+
+void MasterConnectionManager::Helper::OnReadMessage(
+ const MessageInTransit::View& message_view,
+ embedder::ScopedPlatformHandleVectorPtr platform_handles) {
+ if (message_view.type() != MessageInTransit::kTypeConnectionManager) {
+ LOG(ERROR) << "Invalid message type " << message_view.type();
+ FatalError(); // WARNING: This destroys us.
+ return;
+ }
+
+ // Currently, all the messages simply have a |ConnectionIdentifier| as data.
+ if (message_view.num_bytes() != sizeof(ConnectionIdentifier)) {
+ LOG(ERROR) << "Invalid message size " << message_view.num_bytes();
+ FatalError(); // WARNING: This destroys us.
+ return;
+ }
+
+ // And none of them should have any platform handles attached.
+ if (message_view.transport_data_buffer()) {
+ LOG(ERROR) << "Invalid message with transport data";
+ FatalError(); // WARNING: This destroys us.
+ return;
+ }
+
+ const ConnectionIdentifier* connection_id =
+ reinterpret_cast<const ConnectionIdentifier*>(message_view.bytes());
+ bool result;
+ ProcessIdentifier peer_process_identifier = kInvalidProcessIdentifier;
+ embedder::ScopedPlatformHandle platform_handle;
+ uint32_t num_bytes = 0;
+ const void* bytes = nullptr;
+ switch (message_view.subtype()) {
+ case MessageInTransit::kSubtypeConnectionManagerAllowConnect:
+ result = owner_->AllowConnectImpl(process_identifier_, *connection_id);
+ break;
+ case MessageInTransit::kSubtypeConnectionManagerCancelConnect:
+ result = owner_->CancelConnectImpl(process_identifier_, *connection_id);
+ break;
+ case MessageInTransit::kSubtypeConnectionManagerConnect:
+ result = owner_->ConnectImpl(process_identifier_, *connection_id,
+ &peer_process_identifier, &platform_handle);
+ // Success acks for "connect" have the peer process identifier as data
+ // (and maybe also a platform handle).
+ if (result) {
+ num_bytes = static_cast<uint32_t>(sizeof(peer_process_identifier));
+ bytes = &peer_process_identifier;
+ }
+ break;
+ default:
+ LOG(ERROR) << "Invalid message subtype " << message_view.subtype();
+ FatalError(); // WARNING: This destroys us.
+ return;
+ }
+
+ scoped_ptr<MessageInTransit> response(new MessageInTransit(
+ MessageInTransit::kTypeConnectionManagerAck,
+ result ? MessageInTransit::kSubtypeConnectionManagerAckSuccess
+ : MessageInTransit::kSubtypeConnectionManagerAckFailure,
+ num_bytes, bytes));
+
+ if (platform_handle.is_valid()) {
+ // Only success acks for "connect" *may* have a platform handle attached.
+ DCHECK(result);
+ DCHECK_EQ(message_view.subtype(),
+ MessageInTransit::kSubtypeConnectionManagerConnect);
+
+ embedder::ScopedPlatformHandleVectorPtr platform_handles(
+ new embedder::PlatformHandleVector());
+ platform_handles->push_back(platform_handle.release());
+ response->SetTransportData(
+ make_scoped_ptr(new TransportData(platform_handles.Pass())));
+ }
+
+ if (!raw_channel_->WriteMessage(response.Pass())) {
+ LOG(ERROR) << "WriteMessage failed";
+ FatalError(); // WARNING: This destroys us.
+ return;
+ }
+}
+
+void MasterConnectionManager::Helper::OnError(Error /*error*/) {
+ // Every error (read or write) is fatal (for that particular connection). Read
+ // errors are fatal since no more commands will be received from that
+ // connection. Write errors are fatal since it is no longer possible to send
+ // responses.
+ FatalError(); // WARNING: This destroys us.
+}
+
+void MasterConnectionManager::Helper::FatalError() {
+ owner_->OnError(process_identifier_); // WARNING: This destroys us.
+}
+
+// MasterConnectionManager::PendingConnectionInfo ------------------------------
+
+struct MasterConnectionManager::PendingConnectionInfo {
+ // States:
+ // - This is created upon a first "allow connect" (with |first| set
+ // immediately). We then wait for a second "allow connect".
+ // - After the second "allow connect" (and |second| is set), we wait for
+ // "connects" from both |first| and |second|.
+ // - We may then receive "connect" from either |first| or |second|, at which
+ // which point it remains to wait for "connect" from the other.
+ // I.e., the valid state transitions are:
+ // AWAITING_SECOND_ALLOW_CONNECT -> AWAITING_CONNECTS_FROM_BOTH
+ // -> {AWAITING_CONNECT_FROM_FIRST,AWAITING_CONNECT_FROM_SECOND}
+ enum State {
+ AWAITING_SECOND_ALLOW_CONNECT,
+ AWAITING_CONNECTS_FROM_BOTH,
+ AWAITING_CONNECT_FROM_FIRST,
+ AWAITING_CONNECT_FROM_SECOND
+ };
+
+ explicit PendingConnectionInfo(ProcessIdentifier first)
+ : state(AWAITING_SECOND_ALLOW_CONNECT),
+ first(first),
+ second(kInvalidProcessIdentifier) {
+ DCHECK_NE(first, kInvalidProcessIdentifier);
+ }
+ ~PendingConnectionInfo() {}
+
+ State state;
+
+ ProcessIdentifier first;
+ ProcessIdentifier second;
+
+ // Valid in AWAITING_CONNECT_FROM_{FIRST, SECOND} states.
+ embedder::ScopedPlatformHandle remaining_handle;
+};
+
+// MasterConnectionManager -----------------------------------------------------
+
+MasterConnectionManager::MasterConnectionManager()
+ : creation_thread_task_runner_(base::MessageLoop::current()->task_runner()),
+ master_process_delegate_(),
+ private_thread_("MasterConnectionManagerPrivateThread"),
+ next_process_identifier_(kFirstProcessIdentifier) {
+ DCHECK(creation_thread_task_runner_);
+ AssertOnCreationThread(); // Just make sure this assertion works correctly.
+}
+
+MasterConnectionManager::~MasterConnectionManager() {
+ AssertOnCreationThread();
+ DCHECK(!master_process_delegate_);
+ DCHECK(!private_thread_.message_loop());
+ DCHECK(helpers_.empty());
+ DCHECK(pending_connections_.empty());
+}
+
+void MasterConnectionManager::Init(
+ embedder::MasterProcessDelegate* master_process_delegate) {
+ AssertOnCreationThread();
+ DCHECK(master_process_delegate);
+ DCHECK(!master_process_delegate_);
+ DCHECK(!private_thread_.message_loop());
+
+ master_process_delegate_ = master_process_delegate;
+ CHECK(private_thread_.StartWithOptions(
+ base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
+}
+
+void MasterConnectionManager::Shutdown() {
+ AssertOnCreationThread();
+ DCHECK(master_process_delegate_);
+ DCHECK(private_thread_.message_loop());
+
+ // The |Stop()| will actually finish all posted tasks.
+ private_thread_.message_loop()->PostTask(
+ FROM_HERE, base::Bind(&MasterConnectionManager::ShutdownOnPrivateThread,
+ base::Unretained(this)));
+ private_thread_.Stop();
+ DCHECK(helpers_.empty());
+ DCHECK(pending_connections_.empty());
+ master_process_delegate_ = nullptr;
+}
+
+void MasterConnectionManager::AddSlave(
+ scoped_ptr<embedder::SlaveInfo> slave_info,
+ embedder::ScopedPlatformHandle platform_handle) {
+ // We don't really care if |slave_info| is non-null or not.
+ DCHECK(platform_handle.is_valid());
+ AssertNotOnPrivateThread();
+
+ // We have to wait for the task to be executed, in case someone calls
+ // |AddSlave()| followed immediately by |Shutdown()|.
+ base::WaitableEvent event(false, false);
+ private_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&MasterConnectionManager::AddSlaveOnPrivateThread,
+ base::Unretained(this), base::Passed(&slave_info),
+ base::Passed(&platform_handle), base::Unretained(&event)));
+ event.Wait();
+}
+
+bool MasterConnectionManager::AllowConnect(
+ const ConnectionIdentifier& connection_id) {
+ AssertNotOnPrivateThread();
+ return AllowConnectImpl(kMasterProcessIdentifier, connection_id);
+}
+
+bool MasterConnectionManager::CancelConnect(
+ const ConnectionIdentifier& connection_id) {
+ AssertNotOnPrivateThread();
+ return CancelConnectImpl(kMasterProcessIdentifier, connection_id);
+}
+
+bool MasterConnectionManager::Connect(
+ const ConnectionIdentifier& connection_id,
+ ProcessIdentifier* peer_process_identifier,
+ embedder::ScopedPlatformHandle* platform_handle) {
+ AssertNotOnPrivateThread();
+ return ConnectImpl(kMasterProcessIdentifier, connection_id,
+ peer_process_identifier, platform_handle);
+}
+
+bool MasterConnectionManager::AllowConnectImpl(
+ ProcessIdentifier process_identifier,
+ const ConnectionIdentifier& connection_id) {
+ DCHECK_NE(process_identifier, kInvalidProcessIdentifier);
+
+ base::AutoLock locker(lock_);
+
+ auto it = pending_connections_.find(connection_id);
+ if (it == pending_connections_.end()) {
+ pending_connections_[connection_id] =
+ new PendingConnectionInfo(process_identifier);
+ // TODO(vtl): Track process identifier -> pending connections also (so these
+ // can be removed efficiently if that process disconnects).
+ DVLOG(1) << "New pending connection ID " << connection_id
+ << ": AllowConnect() from first process identifier "
+ << process_identifier;
+ return true;
+ }
+
+ PendingConnectionInfo* info = it->second;
+ if (info->state == PendingConnectionInfo::AWAITING_SECOND_ALLOW_CONNECT) {
+ info->state = PendingConnectionInfo::AWAITING_CONNECTS_FROM_BOTH;
+ info->second = process_identifier;
+ DVLOG(1) << "Pending connection ID " << connection_id
+ << ": AllowConnect() from second process identifier "
+ << process_identifier;
+ return true;
+ }
+
+ // Someone's behaving badly, but we don't know who (it might not be the
+ // caller).
+ LOG(ERROR) << "AllowConnect() from process " << process_identifier
+ << " for connection ID " << connection_id << " already in state "
+ << info->state;
+ pending_connections_.erase(it);
+ delete info;
+ return false;
+}
+
+bool MasterConnectionManager::CancelConnectImpl(
+ ProcessIdentifier process_identifier,
+ const ConnectionIdentifier& connection_id) {
+ DCHECK_NE(process_identifier, kInvalidProcessIdentifier);
+
+ base::AutoLock locker(lock_);
+
+ auto it = pending_connections_.find(connection_id);
+ if (it == pending_connections_.end()) {
+ // Not necessarily the caller's fault, and not necessarily an error.
+ DVLOG(1) << "CancelConnect() from process " << process_identifier
+ << " for connection ID " << connection_id
+ << " which is not (or no longer) pending";
+ return true;
+ }
+
+ PendingConnectionInfo* info = it->second;
+ if (process_identifier != info->first && process_identifier != info->second) {
+ LOG(ERROR) << "CancelConnect() from process " << process_identifier
+ << " for connection ID " << connection_id
+ << " which is neither connectee";
+ return false;
+ }
+
+ // Just erase it. The other side may also try to cancel, in which case it'll
+ // "fail" in the first if statement above (we assume that connection IDs never
+ // collide, so there's no need to carefully track both sides).
+ pending_connections_.erase(it);
+ delete info;
+ return true;
+}
+
+bool MasterConnectionManager::ConnectImpl(
+ ProcessIdentifier process_identifier,
+ const ConnectionIdentifier& connection_id,
+ ProcessIdentifier* peer_process_identifier,
+ embedder::ScopedPlatformHandle* platform_handle) {
+ DCHECK_NE(process_identifier, kInvalidProcessIdentifier);
+ DCHECK(peer_process_identifier);
+ DCHECK(platform_handle);
+ DCHECK(!platform_handle->is_valid()); // Not technically wrong, but unlikely.
+
+ base::AutoLock locker(lock_);
+
+ auto it = pending_connections_.find(connection_id);
+ if (it == pending_connections_.end()) {
+ // Not necessarily the caller's fault.
+ LOG(ERROR) << "Connect() from process " << process_identifier
+ << " for connection ID " << connection_id
+ << " which is not pending";
+ return false;
+ }
+
+ PendingConnectionInfo* info = it->second;
+ if (info->state == PendingConnectionInfo::AWAITING_CONNECTS_FROM_BOTH) {
+ DCHECK(!info->remaining_handle.is_valid());
+
+ if (process_identifier == info->first) {
+ info->state = PendingConnectionInfo::AWAITING_CONNECT_FROM_SECOND;
+ *peer_process_identifier = info->second;
+ } else if (process_identifier == info->second) {
+ info->state = PendingConnectionInfo::AWAITING_CONNECT_FROM_FIRST;
+ *peer_process_identifier = info->first;
+ } else {
+ LOG(ERROR) << "Connect() from process " << process_identifier
+ << " for connection ID " << connection_id
+ << " which is neither connectee";
+ return false;
+ }
+
+ if (info->first == info->second) {
+ platform_handle->reset();
+ DCHECK(!info->remaining_handle.is_valid());
+ } else {
+ embedder::PlatformChannelPair platform_channel_pair;
+ *platform_handle = platform_channel_pair.PassServerHandle();
+ DCHECK(platform_handle->is_valid());
+ info->remaining_handle = platform_channel_pair.PassClientHandle();
+ DCHECK(info->remaining_handle.is_valid());
+ }
+ DVLOG(1) << "Connection ID " << connection_id
+ << ": first Connect() from process identifier "
+ << process_identifier;
+ return true;
+ }
+
+ ProcessIdentifier remaining_connectee;
+ ProcessIdentifier peer;
+ if (info->state == PendingConnectionInfo::AWAITING_CONNECT_FROM_FIRST) {
+ remaining_connectee = info->first;
+ peer = info->second;
+ } else if (info->state ==
+ PendingConnectionInfo::AWAITING_CONNECT_FROM_SECOND) {
+ remaining_connectee = info->second;
+ peer = info->first;
+ } else {
+ // Someone's behaving badly, but we don't know who (it might not be the
+ // caller).
+ LOG(ERROR) << "Connect() from process " << process_identifier
+ << " for connection ID " << connection_id << " in state "
+ << info->state;
+ pending_connections_.erase(it);
+ delete info;
+ return false;
+ }
+
+ if (process_identifier != remaining_connectee) {
+ LOG(ERROR) << "Connect() from process " << process_identifier
+ << " for connection ID " << connection_id
+ << " which is not the remaining connectee";
+ pending_connections_.erase(it);
+ delete info;
+ return false;
+ }
+
+ *peer_process_identifier = peer;
+ *platform_handle = info->remaining_handle.Pass();
+ DCHECK((info->first == info->second) ^ platform_handle->is_valid());
+ pending_connections_.erase(it);
+ delete info;
+ DVLOG(1) << "Connection ID " << connection_id
+ << ": second Connect() from process identifier "
+ << process_identifier;
+ return true;
+}
+
+void MasterConnectionManager::ShutdownOnPrivateThread() {
+ AssertOnPrivateThread();
+
+ if (!pending_connections_.empty()) {
+ DVLOG(1) << "Shutting down with connections pending";
+ for (auto& p : pending_connections_)
+ delete p.second;
+ pending_connections_.clear();
+ }
+
+ if (!helpers_.empty()) {
+ DVLOG(1) << "Shutting down with slaves still connected";
+ for (auto& p : helpers_) {
+ scoped_ptr<embedder::SlaveInfo> slave_info = p.second->Shutdown();
+ delete p.second;
+ CallOnSlaveDisconnect(slave_info.Pass());
+ }
+ helpers_.clear();
+ }
+}
+
+void MasterConnectionManager::AddSlaveOnPrivateThread(
+ scoped_ptr<embedder::SlaveInfo> slave_info,
+ embedder::ScopedPlatformHandle platform_handle,
+ base::WaitableEvent* event) {
+ DCHECK(platform_handle.is_valid());
+ DCHECK(event);
+ AssertOnPrivateThread();
+
+ CHECK_NE(next_process_identifier_, kMasterProcessIdentifier);
+ ProcessIdentifier process_identifier = next_process_identifier_;
+ next_process_identifier_++;
+
+ scoped_ptr<Helper> helper(new Helper(
+ this, process_identifier, slave_info.Pass(), platform_handle.Pass()));
+ helper->Init();
+
+ DCHECK(helpers_.find(process_identifier) == helpers_.end());
+ helpers_[process_identifier] = helper.release();
+
+ DVLOG(1) << "Added process identifier " << process_identifier;
+ event->Signal();
+}
+
+void MasterConnectionManager::OnError(ProcessIdentifier process_identifier) {
+ DCHECK_NE(process_identifier, kInvalidProcessIdentifier);
+ AssertOnPrivateThread();
+
+ auto it = helpers_.find(process_identifier);
+ DCHECK(it != helpers_.end());
+ Helper* helper = it->second;
+ scoped_ptr<embedder::SlaveInfo> slave_info = helper->Shutdown();
+ helpers_.erase(it);
+ delete helper;
+
+ {
+ base::AutoLock locker(lock_);
+
+ // TODO(vtl): This isn't very efficient.
+ for (auto it = pending_connections_.begin();
+ it != pending_connections_.end();) {
+ if (it->second->first == process_identifier ||
+ it->second->second == process_identifier) {
+ auto it_to_erase = it;
+ ++it;
+ delete it_to_erase->second;
+ pending_connections_.erase(it_to_erase);
+ } else {
+ ++it;
+ }
+ }
+ }
+
+ CallOnSlaveDisconnect(slave_info.Pass());
+}
+
+void MasterConnectionManager::CallOnSlaveDisconnect(
+ scoped_ptr<embedder::SlaveInfo> slave_info) {
+ AssertOnPrivateThread();
+ DCHECK(master_process_delegate_);
+ creation_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&embedder::MasterProcessDelegate::OnSlaveDisconnect,
+ base::Unretained(master_process_delegate_),
+ base::Passed(&slave_info)));
+}
+
+void MasterConnectionManager::AssertOnCreationThread() const {
+ DCHECK(base::MessageLoop::current());
+ DCHECK_EQ(base::MessageLoop::current()->task_runner(),
+ creation_thread_task_runner_);
+}
+
+void MasterConnectionManager::AssertNotOnPrivateThread() const {
+ // This should only be called after |Init()| and before |Shutdown()|. (If not,
+ // the subsequent |DCHECK_NE()| is invalid, since the current thread may not
+ // have a message loop.)
+ DCHECK(private_thread_.message_loop());
+ DCHECK_NE(base::MessageLoop::current(), private_thread_.message_loop());
+}
+
+void MasterConnectionManager::AssertOnPrivateThread() const {
+ // This should only be called after |Init()| and before |Shutdown()|.
+ DCHECK(private_thread_.message_loop());
+ DCHECK_EQ(base::MessageLoop::current(), private_thread_.message_loop());
+}
+
+} // namespace system
+} // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/system/master_connection_manager.h b/third_party/mojo/src/mojo/edk/system/master_connection_manager.h
new file mode 100644
index 0000000..dcec9c2
--- /dev/null
+++ b/third_party/mojo/src/mojo/edk/system/master_connection_manager.h
@@ -0,0 +1,141 @@
+// 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_SYSTEM_MASTER_CONNECTION_MANAGER_H_
+#define MOJO_EDK_SYSTEM_MASTER_CONNECTION_MANAGER_H_
+
+#include <stdint.h>
+
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread.h"
+#include "mojo/edk/embedder/scoped_platform_handle.h"
+#include "mojo/edk/system/connection_manager.h"
+#include "mojo/edk/system/system_impl_export.h"
+
+namespace base {
+class TaskRunner;
+class WaitableEvent;
+}
+
+namespace mojo {
+
+namespace embedder {
+class MasterProcessDelegate;
+class SlaveInfo;
+}
+
+namespace system {
+
+// The |ConnectionManager| implementation for the master process.
+//
+// Objects of this class must be created, initialized (via |Init()|), shut down
+// (via |Shutdown()|), and destroyed on the same thread (the "creation thread").
+// Otherwise, its public methods are thread-safe (except that they may not be
+// called from its internal, private thread).
+class MOJO_SYSTEM_IMPL_EXPORT MasterConnectionManager
+ : public ConnectionManager {
+ public:
+ // Note: None of the public methods may be called from |private_thread_|.
+
+ MasterConnectionManager();
+ ~MasterConnectionManager() override;
+
+ // No other methods may be called until after this has been called.
+ // |master_process_delegate| must stay alive at least until after |Shutdown()|
+ // has been called; its methods will be called on this object's creation
+ // thread.
+ void Init(embedder::MasterProcessDelegate* master_process_delegate);
+
+ // No other methods may be called after this is (or while it is being) called.
+ void Shutdown();
+
+ // Adds a slave process and sets up/tracks a connection to that slave (using
+ // |platform_handle|). (|slave_info| is used by the caller/implementation of
+ // |embedder::MasterProcessDelegate| to track this process; ownership of
+ // |slave_info| will be returned to the delegate via |OnSlaveDisconnect()|,
+ // which will always be called for each slave, assuming proper shutdown.)
+ void AddSlave(scoped_ptr<embedder::SlaveInfo> slave_info,
+ embedder::ScopedPlatformHandle platform_handle);
+
+ // |ConnectionManager| methods:
+ bool AllowConnect(const ConnectionIdentifier& connection_id) override;
+ bool CancelConnect(const ConnectionIdentifier& connection_id) override;
+ bool Connect(const ConnectionIdentifier& connection_id,
+ ProcessIdentifier* peer_process_identifier,
+ embedder::ScopedPlatformHandle* platform_handle) override;
+
+ private:
+ class Helper;
+
+ // These should be thread-safe and may be called on any thread, including
+ // |private_thread_|:
+ bool AllowConnectImpl(ProcessIdentifier process_identifier,
+ const ConnectionIdentifier& connection_id);
+ bool CancelConnectImpl(ProcessIdentifier process_identifier,
+ const ConnectionIdentifier& connection_id);
+ bool ConnectImpl(ProcessIdentifier process_identifier,
+ const ConnectionIdentifier& connection_id,
+ ProcessIdentifier* peer_process_identifier,
+ embedder::ScopedPlatformHandle* platform_handle);
+
+ // These should only be called on |private_thread_|:
+ void ShutdownOnPrivateThread();
+ // Signals |*event| on completion.
+ void AddSlaveOnPrivateThread(scoped_ptr<embedder::SlaveInfo> slave_info,
+ embedder::ScopedPlatformHandle platform_handle,
+ base::WaitableEvent* event);
+ // Called by |Helper::OnError()|.
+ void OnError(ProcessIdentifier process_identifier);
+ // Posts a call to |master_process_delegate_->OnSlaveDisconnect()|.
+ void CallOnSlaveDisconnect(scoped_ptr<embedder::SlaveInfo> slave_info);
+
+ // Asserts that the current thread is the creation thread. (This actually
+ // checks the current message loop, which is what we depend on, not the thread
+ // per se.)
+ void AssertOnCreationThread() const;
+
+ // Asserts that the current thread is *not* |private_thread_| (no-op if
+ // DCHECKs are not enabled). This should only be called while
+ // |private_thread_| is alive (i.e., after |Init()| but before |Shutdown()|).
+ void AssertNotOnPrivateThread() const;
+
+ // Asserts that the current thread is |private_thread_| (no-op if DCHECKs are
+ // not enabled). This should only be called while |private_thread_| is alive
+ // (i.e., after |Init()| but before |Shutdown()|).
+ void AssertOnPrivateThread() const;
+
+ const scoped_refptr<base::TaskRunner> creation_thread_task_runner_;
+
+ // This is set in |Init()| before |private_thread_| exists and only cleared in
+ // |Shutdown()| after |private_thread_| is dead. Thus it's safe to "use" on
+ // |private_thread_|. (Note that |master_process_delegate_| may only be called
+ // from the creation thread.)
+ embedder::MasterProcessDelegate* master_process_delegate_;
+
+ // This is a private I/O thread on which this class does the bulk of its work.
+ // It is started in |Init()| and terminated in |Shutdown()|.
+ base::Thread private_thread_;
+
+ // The following members are only accessed on |private_thread_|:
+ ProcessIdentifier next_process_identifier_;
+ base::hash_map<ProcessIdentifier, Helper*> helpers_; // Owns its values.
+
+ // Protects the members below (except in the constructor, |Init()|,
+ // |Shutdown()|/|ShutdownOnPrivateThread()|, and the destructor).
+ base::Lock lock_;
+
+ struct PendingConnectionInfo;
+ base::hash_map<ConnectionIdentifier, PendingConnectionInfo*>
+ pending_connections_; // Owns its values.
+
+ DISALLOW_COPY_AND_ASSIGN(MasterConnectionManager);
+};
+
+} // namespace system
+} // namespace mojo
+
+#endif // MOJO_EDK_SYSTEM_MASTER_CONNECTION_MANAGER_H_
diff --git a/third_party/mojo/src/mojo/edk/system/message_in_transit.cc b/third_party/mojo/src/mojo/edk/system/message_in_transit.cc
index 68919f2..9e38064 100644
--- a/third_party/mojo/src/mojo/edk/system/message_in_transit.cc
+++ b/third_party/mojo/src/mojo/edk/system/message_in_transit.cc
@@ -20,6 +20,11 @@ STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type
MessageInTransit::kTypeChannel;
STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type
MessageInTransit::kTypeRawChannel;
+STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type
+ MessageInTransit::kTypeConnectionManager;
+STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type
+ MessageInTransit::kTypeConnectionManagerAck;
+
STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
MessageInTransit::kSubtypeEndpointData;
STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
@@ -30,6 +35,17 @@ STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
MessageInTransit::kSubtypeChannelRemoveEndpointAck;
STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
MessageInTransit::kSubtypeRawChannelPosixExtraPlatformHandles;
+STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
+ MessageInTransit::kSubtypeConnectionManagerAllowConnect;
+STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
+ MessageInTransit::kSubtypeConnectionManagerCancelConnect;
+STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
+ MessageInTransit::kSubtypeConnectionManagerConnect;
+STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
+ MessageInTransit::kSubtypeConnectionManagerAckFailure;
+STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
+ MessageInTransit::kSubtypeConnectionManagerAckSuccess;
+
STATIC_CONST_MEMBER_DEFINITION const size_t MessageInTransit::kMessageAlignment;
struct MessageInTransit::PrivateStructForCompileAsserts {
diff --git a/third_party/mojo/src/mojo/edk/system/message_in_transit.h b/third_party/mojo/src/mojo/edk/system/message_in_transit.h
index 023362a..9f118f9 100644
--- a/third_party/mojo/src/mojo/edk/system/message_in_transit.h
+++ b/third_party/mojo/src/mojo/edk/system/message_in_transit.h
@@ -50,6 +50,11 @@ class MOJO_SYSTEM_IMPL_EXPORT MessageInTransit {
static const Type kTypeChannel = 1;
// Messages that are consumed by the |RawChannel| (implementation).
static const Type kTypeRawChannel = 2;
+ // |ConnectionManager| implementations also use |RawChannel|s.
+ // Messages sent to a |MasterConnectionManager|.
+ static const Type kTypeConnectionManager = 3;
+ // Messages sent by a |MasterConnectionManager| (all responses).
+ static const Type kTypeConnectionManagerAck = 4;
typedef uint16_t Subtype;
// Subtypes for type |kTypeEndpoint|:
@@ -58,9 +63,18 @@ class MOJO_SYSTEM_IMPL_EXPORT MessageInTransit {
static const Subtype kSubtypeChannelAttachAndRunEndpoint = 0;
static const Subtype kSubtypeChannelRemoveEndpoint = 1;
static const Subtype kSubtypeChannelRemoveEndpointAck = 2;
-
// Subtypes for type |kTypeRawChannel|:
static const Subtype kSubtypeRawChannelPosixExtraPlatformHandles = 0;
+ // Subtypes for type |kTypeConnectionManager| (the message data is always a
+ // buffer containing the connection ID):
+ static const Subtype kSubtypeConnectionManagerAllowConnect = 0;
+ static const Subtype kSubtypeConnectionManagerCancelConnect = 1;
+ static const Subtype kSubtypeConnectionManagerConnect = 2;
+ // Subtypes for type |kTypeConnectionManagerAck| (failure acks never have any
+ // message contents; success acks for "connect" always have a
+ // |ProcessIdentifier| as data and *may* have a platform handle attached):
+ static const Subtype kSubtypeConnectionManagerAckFailure = 0;
+ static const Subtype kSubtypeConnectionManagerAckSuccess = 1;
// Messages (the header and data) must always be aligned to a multiple of this
// quantity (which must be a power of 2).
diff --git a/third_party/mojo/src/mojo/edk/system/message_pipe_dispatcher_unittest.cc b/third_party/mojo/src/mojo/edk/system/message_pipe_dispatcher_unittest.cc
index 2f97b29..b5562b0 100644
--- a/third_party/mojo/src/mojo/edk/system/message_pipe_dispatcher_unittest.cc
+++ b/third_party/mojo/src/mojo/edk/system/message_pipe_dispatcher_unittest.cc
@@ -340,8 +340,13 @@ TEST(MessagePipeDispatcherTest, BasicClosed) {
}
}
+#if defined(OS_WIN)
// http://crbug.com/396386
-TEST(MessagePipeDispatcherTest, DISABLED_BasicThreaded) {
+#define MAYBE_BasicThreaded DISABLED_BasicThreaded
+#else
+#define MAYBE_BasicThreaded BasicThreaded
+#endif
+TEST(MessagePipeDispatcherTest, MAYBE_BasicThreaded) {
test::Stopwatch stopwatch;
int32_t buffer[1];
const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer));
diff --git a/third_party/mojo/src/mojo/edk/system/simple_dispatcher_unittest.cc b/third_party/mojo/src/mojo/edk/system/simple_dispatcher_unittest.cc
index 7d5edcb..b8e57e9 100644
--- a/third_party/mojo/src/mojo/edk/system/simple_dispatcher_unittest.cc
+++ b/third_party/mojo/src/mojo/edk/system/simple_dispatcher_unittest.cc
@@ -325,8 +325,13 @@ TEST(SimpleDispatcherTest, BasicClosed) {
// Don't need to remove waiters from closed dispatchers.
}
+#if defined(OS_WIN)
// http://crbug.com/396393
-TEST(SimpleDispatcherTest, DISABLED_BasicThreaded) {
+#define MAYBE_BasicThreaded DISABLED_BasicThreaded
+#else
+#define MAYBE_BasicThreaded BasicThreaded
+#endif
+TEST(SimpleDispatcherTest, MAYBE_BasicThreaded) {
test::Stopwatch stopwatch;
bool did_wait;
MojoResult result;
diff --git a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc
new file mode 100644
index 0000000..2427823
--- /dev/null
+++ b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc
@@ -0,0 +1,316 @@
+// 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/system/slave_connection_manager.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "mojo/edk/system/message_in_transit.h"
+
+namespace mojo {
+namespace system {
+
+// SlaveConnectionManager ------------------------------------------------------
+
+SlaveConnectionManager::SlaveConnectionManager()
+ : creation_thread_task_runner_(base::MessageLoop::current()->task_runner()),
+ slave_process_delegate_(),
+ private_thread_("SlaveConnectionManagerPrivateThread"),
+ awaiting_ack_type_(NOT_AWAITING_ACK),
+ ack_result_(),
+ ack_peer_process_identifier_(),
+ ack_platform_handle_(),
+ event_(false, false) { // Auto-reset, not initially signalled.
+ DCHECK(creation_thread_task_runner_);
+ AssertOnCreationThread(); // Just make sure this assertion works correctly.
+}
+
+SlaveConnectionManager::~SlaveConnectionManager() {
+ AssertOnCreationThread();
+ DCHECK(!slave_process_delegate_);
+ DCHECK(!private_thread_.message_loop());
+ DCHECK_EQ(awaiting_ack_type_, NOT_AWAITING_ACK);
+ DCHECK(!ack_result_);
+ DCHECK(!ack_peer_process_identifier_);
+ DCHECK(!ack_platform_handle_);
+}
+
+void SlaveConnectionManager::Init(
+ embedder::SlaveProcessDelegate* slave_process_delegate,
+ embedder::ScopedPlatformHandle platform_handle) {
+ AssertOnCreationThread();
+ DCHECK(slave_process_delegate);
+ DCHECK(platform_handle.is_valid());
+ DCHECK(!slave_process_delegate_);
+ DCHECK(!private_thread_.message_loop());
+
+ slave_process_delegate_ = slave_process_delegate;
+ CHECK(private_thread_.StartWithOptions(
+ base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
+ private_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&SlaveConnectionManager::InitOnPrivateThread,
+ base::Unretained(this), base::Passed(&platform_handle)));
+ event_.Wait();
+}
+
+void SlaveConnectionManager::Shutdown() {
+ AssertOnCreationThread();
+ DCHECK(slave_process_delegate_);
+ DCHECK(private_thread_.message_loop());
+
+ // The |Stop()| will actually finish all posted tasks.
+ private_thread_.message_loop()->PostTask(
+ FROM_HERE, base::Bind(&SlaveConnectionManager::ShutdownOnPrivateThread,
+ base::Unretained(this)));
+ private_thread_.Stop();
+ slave_process_delegate_ = nullptr;
+}
+
+bool SlaveConnectionManager::AllowConnect(
+ const ConnectionIdentifier& connection_id) {
+ AssertNotOnPrivateThread();
+
+ base::AutoLock locker(lock_);
+ bool result = false;
+ private_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&SlaveConnectionManager::AllowConnectOnPrivateThread,
+ base::Unretained(this), connection_id, &result));
+ event_.Wait();
+ return result;
+}
+
+bool SlaveConnectionManager::CancelConnect(
+ const ConnectionIdentifier& connection_id) {
+ AssertNotOnPrivateThread();
+
+ base::AutoLock locker(lock_);
+ bool result = false;
+ private_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&SlaveConnectionManager::CancelConnectOnPrivateThread,
+ base::Unretained(this), connection_id, &result));
+ event_.Wait();
+ return result;
+}
+
+bool SlaveConnectionManager::Connect(
+ const ConnectionIdentifier& connection_id,
+ ProcessIdentifier* peer_process_identifier,
+ embedder::ScopedPlatformHandle* platform_handle) {
+ AssertNotOnPrivateThread();
+
+ base::AutoLock locker(lock_);
+ bool result = false;
+ private_thread_.message_loop()->PostTask(
+ FROM_HERE, base::Bind(&SlaveConnectionManager::ConnectOnPrivateThread,
+ base::Unretained(this), connection_id, &result,
+ peer_process_identifier, platform_handle));
+ event_.Wait();
+ return result;
+}
+
+void SlaveConnectionManager::InitOnPrivateThread(
+ embedder::ScopedPlatformHandle platform_handle) {
+ AssertOnPrivateThread();
+
+ raw_channel_ = RawChannel::Create(platform_handle.Pass());
+ raw_channel_->Init(this);
+ event_.Signal();
+}
+
+void SlaveConnectionManager::ShutdownOnPrivateThread() {
+ AssertOnPrivateThread();
+
+ CHECK_EQ(awaiting_ack_type_, NOT_AWAITING_ACK);
+ if (raw_channel_) {
+ raw_channel_->Shutdown();
+ raw_channel_.reset();
+ }
+}
+
+void SlaveConnectionManager::AllowConnectOnPrivateThread(
+ const ConnectionIdentifier& connection_id,
+ bool* result) {
+ DCHECK(result);
+ AssertOnPrivateThread();
+ // This should only posted (from another thread, to |private_thread_|) with
+ // the lock held (until this thread triggers |event_|).
+ DCHECK(!lock_.Try());
+ DCHECK_EQ(awaiting_ack_type_, NOT_AWAITING_ACK);
+
+ DVLOG(1) << "Sending AllowConnect: connection ID " << connection_id;
+ if (!raw_channel_->WriteMessage(make_scoped_ptr(new MessageInTransit(
+ MessageInTransit::kTypeConnectionManager,
+ MessageInTransit::kSubtypeConnectionManagerAllowConnect,
+ sizeof(connection_id), &connection_id)))) {
+ // Don't tear things down; possibly we'll still read some messages.
+ *result = false;
+ event_.Signal();
+ return;
+ }
+ awaiting_ack_type_ = AWAITING_ACCEPT_CONNECT_ACK;
+ ack_result_ = result;
+}
+
+void SlaveConnectionManager::CancelConnectOnPrivateThread(
+ const ConnectionIdentifier& connection_id,
+ bool* result) {
+ DCHECK(result);
+ AssertOnPrivateThread();
+ // This should only posted (from another thread, to |private_thread_|) with
+ // the lock held (until this thread triggers |event_|).
+ DCHECK(!lock_.Try());
+ DCHECK_EQ(awaiting_ack_type_, NOT_AWAITING_ACK);
+
+ DVLOG(1) << "Sending CancelConnect: connection ID " << connection_id;
+ if (!raw_channel_->WriteMessage(make_scoped_ptr(new MessageInTransit(
+ MessageInTransit::kTypeConnectionManager,
+ MessageInTransit::kSubtypeConnectionManagerCancelConnect,
+ sizeof(connection_id), &connection_id)))) {
+ // Don't tear things down; possibly we'll still read some messages.
+ *result = false;
+ event_.Signal();
+ return;
+ }
+ awaiting_ack_type_ = AWAITING_CANCEL_CONNECT_ACK;
+ ack_result_ = result;
+}
+
+void SlaveConnectionManager::ConnectOnPrivateThread(
+ const ConnectionIdentifier& connection_id,
+ bool* result,
+ ProcessIdentifier* peer_process_identifier,
+ embedder::ScopedPlatformHandle* platform_handle) {
+ DCHECK(result);
+ DCHECK(platform_handle);
+ DCHECK(!platform_handle->is_valid()); // Not technically wrong, but unlikely.
+ AssertOnPrivateThread();
+ // This should only posted (from another thread, to |private_thread_|) with
+ // the lock held (until this thread triggers |event_|).
+ DCHECK(!lock_.Try());
+ DCHECK_EQ(awaiting_ack_type_, NOT_AWAITING_ACK);
+
+ DVLOG(1) << "Sending Connect: connection ID " << connection_id;
+ if (!raw_channel_->WriteMessage(make_scoped_ptr(new MessageInTransit(
+ MessageInTransit::kTypeConnectionManager,
+ MessageInTransit::kSubtypeConnectionManagerConnect,
+ sizeof(connection_id), &connection_id)))) {
+ // Don't tear things down; possibly we'll still read some messages.
+ *result = false;
+ platform_handle->reset();
+ event_.Signal();
+ return;
+ }
+ awaiting_ack_type_ = AWAITING_CONNECT_ACK;
+ ack_result_ = result;
+ ack_peer_process_identifier_ = peer_process_identifier;
+ ack_platform_handle_ = platform_handle;
+}
+
+void SlaveConnectionManager::OnReadMessage(
+ const MessageInTransit::View& message_view,
+ embedder::ScopedPlatformHandleVectorPtr platform_handles) {
+ AssertOnPrivateThread();
+
+ // Set |*ack_result_| to false by default.
+ *ack_result_ = false;
+
+ // Note: Since we should be able to trust the master, simply crash (i.e.,
+ // |CHECK()|-fail) if it sends us something invalid.
+
+ // Unsolicited message.
+ CHECK_NE(awaiting_ack_type_, NOT_AWAITING_ACK);
+ // Bad message type.
+ CHECK_EQ(message_view.type(), MessageInTransit::kTypeConnectionManagerAck);
+
+ size_t num_bytes = message_view.num_bytes();
+ size_t num_platform_handles = platform_handles ? platform_handles->size() : 0;
+
+ if (message_view.subtype() ==
+ MessageInTransit::kSubtypeConnectionManagerAckFailure) {
+ // Failure acks never have any contents.
+ CHECK_EQ(num_bytes, 0u);
+ CHECK_EQ(num_platform_handles, 0u);
+ // Leave |*ack_result_| false.
+ } else if (message_view.subtype() ==
+ MessageInTransit::kSubtypeConnectionManagerAckSuccess) {
+ if (awaiting_ack_type_ == AWAITING_ACCEPT_CONNECT_ACK ||
+ awaiting_ack_type_ == AWAITING_CANCEL_CONNECT_ACK) {
+ // Success acks for "accept/cancel connect" have no contents.
+ CHECK_EQ(num_bytes, 0u);
+ CHECK_EQ(num_platform_handles, 0u);
+ *ack_result_ = true;
+ DCHECK(!ack_peer_process_identifier_);
+ DCHECK(!ack_platform_handle_);
+ } else {
+ DCHECK_EQ(awaiting_ack_type_, AWAITING_CONNECT_ACK);
+ // Success acks for "connect" always have a |ProcessIdentifier| as data,
+ // and *maybe* one platform handle.
+ CHECK_EQ(num_bytes, sizeof(ProcessIdentifier));
+ CHECK_LE(num_platform_handles, 1u);
+ *ack_result_ = true;
+ *ack_peer_process_identifier_ =
+ *reinterpret_cast<const ProcessIdentifier*>(message_view.bytes());
+ if (num_platform_handles > 0) {
+ ack_platform_handle_->reset(platform_handles->at(0));
+ platform_handles->at(0) = embedder::PlatformHandle();
+ } else {
+ ack_platform_handle_->reset();
+ }
+ }
+ } else {
+ // Bad message subtype.
+ CHECK(false);
+ }
+
+ awaiting_ack_type_ = NOT_AWAITING_ACK;
+ ack_result_ = nullptr;
+ ack_peer_process_identifier_ = nullptr;
+ ack_platform_handle_ = nullptr;
+ event_.Signal();
+}
+
+void SlaveConnectionManager::OnError(Error error) {
+ AssertOnPrivateThread();
+
+ // Ignore write errors, since we may still have some messages to read.
+ if (error == RawChannel::Delegate::ERROR_WRITE)
+ return;
+
+ raw_channel_->Shutdown();
+ raw_channel_.reset();
+
+ DCHECK(slave_process_delegate_);
+ creation_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&embedder::SlaveProcessDelegate::OnMasterDisconnect,
+ base::Unretained(slave_process_delegate_)));
+}
+
+void SlaveConnectionManager::AssertOnCreationThread() const {
+ DCHECK(base::MessageLoop::current());
+ DCHECK_EQ(base::MessageLoop::current()->task_runner(),
+ creation_thread_task_runner_);
+}
+
+void SlaveConnectionManager::AssertNotOnPrivateThread() const {
+ // This should only be called after |Init()| and before |Shutdown()|. (If not,
+ // the subsequent |DCHECK_NE()| is invalid, since the current thread may not
+ // have a message loop.)
+ DCHECK(private_thread_.message_loop());
+ DCHECK_NE(base::MessageLoop::current(), private_thread_.message_loop());
+}
+
+void SlaveConnectionManager::AssertOnPrivateThread() const {
+ // This should only be called after |Init()| and before |Shutdown()|.
+ DCHECK(private_thread_.message_loop());
+ DCHECK_EQ(base::MessageLoop::current(), private_thread_.message_loop());
+}
+
+} // namespace system
+} // namespace mojo
diff --git a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h
new file mode 100644
index 0000000..e773448
--- /dev/null
+++ b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h
@@ -0,0 +1,160 @@
+// 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_SYSTEM_SLAVE_CONNECTION_MANAGER_H_
+#define MOJO_EDK_SYSTEM_SLAVE_CONNECTION_MANAGER_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "mojo/edk/embedder/scoped_platform_handle.h"
+#include "mojo/edk/embedder/slave_process_delegate.h"
+#include "mojo/edk/system/connection_manager.h"
+#include "mojo/edk/system/raw_channel.h"
+#include "mojo/edk/system/system_impl_export.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace mojo {
+
+namespace embedder {
+class SlaveProcessDelegate;
+}
+
+namespace system {
+
+// The |ConnectionManager| implementation for slave processes.
+//
+// Objects of this class must created, initialized (via |Init()|), shut down
+// (via |Shutdown()|), and destroyed on the same thread (the "creation thread").
+// Otherwise, its public methods are thread-safe (except that they may not be
+// called from its internal, private thread).
+class MOJO_SYSTEM_IMPL_EXPORT SlaveConnectionManager
+ : public ConnectionManager,
+ public RawChannel::Delegate {
+ public:
+ // Note: None of the public methods may be called from |private_thread_|.
+
+ SlaveConnectionManager();
+ ~SlaveConnectionManager() override;
+
+ // No other methods may be called until after this has been called.
+ // |slave_process_delegate| must stay alive at least until after |Shutdown()|
+ // has been called; its methods will be called on this object's creation
+ // thread.
+ void Init(embedder::SlaveProcessDelegate* slave_process_delegate,
+ embedder::ScopedPlatformHandle platform_handle);
+
+ // No other methods may be called after this is (or while it is being) called.
+ void Shutdown();
+
+ // |ConnectionManager| methods:
+ bool AllowConnect(const ConnectionIdentifier& connection_id) override;
+ bool CancelConnect(const ConnectionIdentifier& connection_id) override;
+ bool Connect(const ConnectionIdentifier& connection_id,
+ ProcessIdentifier* peer_process_identifier,
+ embedder::ScopedPlatformHandle* platform_handle) override;
+
+ private:
+ // These should only be called on |private_thread_|:
+ void InitOnPrivateThread(embedder::ScopedPlatformHandle platform_handle);
+ void ShutdownOnPrivateThread();
+ void AllowConnectOnPrivateThread(const ConnectionIdentifier& connection_id,
+ bool* result);
+ void CancelConnectOnPrivateThread(const ConnectionIdentifier& connection_id,
+ bool* result);
+ void ConnectOnPrivateThread(const ConnectionIdentifier& connection_id,
+ bool* result,
+ ProcessIdentifier* peer_process_identifier,
+ embedder::ScopedPlatformHandle* platform_handle);
+
+ // |RawChannel::Delegate| methods (only called on |private_thread_|):
+ void OnReadMessage(
+ const MessageInTransit::View& message_view,
+ embedder::ScopedPlatformHandleVectorPtr platform_handles) override;
+ void OnError(Error error) override;
+
+ // Asserts that the current thread is the creation thread. (This actually
+ // checks the current message loop, which is what we depend on, not the thread
+ // per se.)
+ void AssertOnCreationThread() const;
+
+ // Asserts that the current thread is *not* |private_thread_| (no-op if
+ // DCHECKs are not enabled). This should only be called while
+ // |private_thread_| is alive (i.e., after |Init()| but before |Shutdown()|).
+ void AssertNotOnPrivateThread() const;
+
+ // Asserts that the current thread is |private_thread_| (no-op if DCHECKs are
+ // not enabled). This should only be called while |private_thread_| is alive
+ // (i.e., after |Init()| but before |Shutdown()|).
+ void AssertOnPrivateThread() const;
+
+ const scoped_refptr<base::TaskRunner> creation_thread_task_runner_;
+
+ // These is set in |Init()| before |private_thread_| exists and only cleared
+ // in |Shutdown()| after |private_thread_| is dead. Thus it's safe to "use" on
+ // |private_thread_|. (Note that |slave_process_delegate_| may only be called
+ // from the creation thread.)
+ embedder::SlaveProcessDelegate* slave_process_delegate_;
+
+ // This is a private I/O thread on which this class does the bulk of its work.
+ // It is started in |Init()| and terminated in |Shutdown()|.
+ // TODO(vtl): This isn't really necessary.
+ base::Thread private_thread_;
+
+ // Only accessed on |private_thread_|:
+ scoped_ptr<RawChannel> raw_channel_;
+ enum AwaitingAckType {
+ NOT_AWAITING_ACK,
+ AWAITING_ACCEPT_CONNECT_ACK,
+ AWAITING_CANCEL_CONNECT_ACK,
+ AWAITING_CONNECT_ACK
+ };
+ AwaitingAckType awaiting_ack_type_;
+ bool* ack_result_;
+ // Used only when waiting for the ack to "connect":
+ ProcessIdentifier* ack_peer_process_identifier_;
+ embedder::ScopedPlatformHandle* ack_platform_handle_;
+
+ // The (synchronous) |ConnectionManager| methods are implemented in the
+ // following way (T is any thread other than |private_thread_|):
+ //
+ // On thread T:
+ // 1. |F()| is called, where F is one of the |ConnectionManager| methods.
+ // 2. |lock_| is acquired.
+ // 3. |FImpl()| is posted to |private_thread_|.
+ // 4. |event_| is waited on (while holding |lock_|!).
+ //
+ // On |private_thread_| (all with |lock_| held!):
+ // 4.1. |FImpl()| is executed, writes an "F" message to |raw_channel_|, and
+ // sets |awaiting_ack_type_| appropriately (it must not be "set"
+ // before).
+ // 4.2. [Control returns to |private_thread_|'s message loop.]
+ // 4.3. Eventually, |raw_channel_| calls |OnReadMessage()| with a message,
+ // which must be response (|awaiting_ack_type_| must still be set).
+ // 4.4. |*ack_result_| and possibly |*ack_platform_handle_| are written to.
+ // |awaiting_ack_type_| is "unset".
+ // 4.5. |event_| is triggered.
+ //
+ // Back on thread T:
+ // 6. |lock_| is released.
+ // 7. [Return from |F()|.]
+ //
+ // TODO(vtl): This is all a hack. It'd really suffice to have a version of
+ // |RawChannel| with fully synchronous reading and writing.
+ base::Lock lock_;
+ base::WaitableEvent event_;
+
+ DISALLOW_COPY_AND_ASSIGN(SlaveConnectionManager);
+};
+
+} // namespace system
+} // namespace mojo
+
+#endif // MOJO_EDK_SYSTEM_SLAVE_CONNECTION_MANAGER_H_
diff --git a/third_party/mojo/src/mojo/public/VERSION b/third_party/mojo/src/mojo/public/VERSION
index 928bc42..55ad309 100644
--- a/third_party/mojo/src/mojo/public/VERSION
+++ b/third_party/mojo/src/mojo/public/VERSION
@@ -1 +1 @@
-a85a2cea82d816de115e15253742b0f88a9924eb \ No newline at end of file
+126532ce21c5c3c55a1e1693731411cb60169efd \ No newline at end of file
diff --git a/third_party/mojo/src/mojo/public/cpp/application/BUILD.gn b/third_party/mojo/src/mojo/public/cpp/application/BUILD.gn
index 8741c694..05708c7 100644
--- a/third_party/mojo/src/mojo/public/cpp/application/BUILD.gn
+++ b/third_party/mojo/src/mojo/public/cpp/application/BUILD.gn
@@ -64,6 +64,7 @@ mojo_sdk_source_set("test_support") {
"mojo/public/cpp/bindings",
"mojo/public/cpp/environment",
"mojo/public/cpp/system",
+ "mojo/public/interfaces/application",
]
}
@@ -82,8 +83,10 @@ mojo_sdk_source_set("test_support_standalone") {
]
mojo_sdk_deps = [
+ "mojo/public/interfaces/application",
"mojo/public/cpp/environment:standalone",
"mojo/public/cpp/system",
"mojo/public/cpp/utility",
+ "mojo/public/interfaces/application",
]
}
diff --git a/third_party/mojo/src/mojo/public/cpp/application/application_impl.h b/third_party/mojo/src/mojo/public/cpp/application/application_impl.h
index 430a124..bb92307 100644
--- a/third_party/mojo/src/mojo/public/cpp/application/application_impl.h
+++ b/third_party/mojo/src/mojo/public/cpp/application/application_impl.h
@@ -50,11 +50,10 @@ class ApplicationDelegate;
// app.AddService<BarImpl>(&context);
//
//
-class ApplicationImpl : public InterfaceImpl<Application> {
+class ApplicationImpl : public Application {
public:
ApplicationImpl(ApplicationDelegate* delegate,
- ScopedMessagePipeHandle shell_handle);
- ApplicationImpl(ApplicationDelegate* delegate, MojoHandle shell_handle);
+ InterfaceRequest<Application> request);
~ApplicationImpl() override;
Shell* shell() const { return shell_.get(); }
@@ -74,32 +73,36 @@ class ApplicationImpl : public InterfaceImpl<Application> {
ConnectToApplication(application_url)->ConnectToService(ptr);
}
- // Wait for the ShellPtr's Initialize message.
- bool WaitForInitialize();
+ // Application implementation.
+ void Initialize(ShellPtr shell, Array<String> args) override;
- // Unbind the shell from this application and return its handle.
- ScopedMessagePipeHandle UnbindShell();
+ // Block until the Application is initialized, if it is not already.
+ void WaitForInitialize();
- // Application implementation.
- void Initialize(Array<String> args) override;
+ // Unbinds the Shell and Application connections. Must be called after
+ // Initialize.
+ void UnbindConnections(InterfaceRequest<Application>* application_request,
+ ShellPtr* shell);
// Quits the main run loop for this application.
static void Terminate();
+ protected:
+ // Application implementation.
+ void AcceptConnection(const String& requestor_url,
+ InterfaceRequest<ServiceProvider> services,
+ ServiceProviderPtr exposed_services) override;
+
private:
class ShellPtrWatcher;
- void BindShell(ScopedMessagePipeHandle shell_handle);
void ClearConnections();
+
void OnShellError() {
ClearConnections();
Terminate();
}
- // Application implementation.
- void AcceptConnection(const String& requestor_url,
- InterfaceRequest<ServiceProvider> services,
- ServiceProviderPtr exposed_services) override;
void RequestQuit() override;
typedef std::vector<internal::ServiceRegistry*> ServiceRegistryList;
@@ -108,6 +111,7 @@ class ApplicationImpl : public InterfaceImpl<Application> {
ServiceRegistryList incoming_service_registries_;
ServiceRegistryList outgoing_service_registries_;
ApplicationDelegate* delegate_;
+ Binding<Application> binding_;
ShellPtr shell_;
ShellPtrWatcher* shell_watch_;
std::vector<std::string> args_;
diff --git a/third_party/mojo/src/mojo/public/cpp/application/application_test_base.h b/third_party/mojo/src/mojo/public/cpp/application/application_test_base.h
index bdf2f8b..10763be 100644
--- a/third_party/mojo/src/mojo/public/cpp/application/application_test_base.h
+++ b/third_party/mojo/src/mojo/public/cpp/application/application_test_base.h
@@ -9,6 +9,7 @@
#include "mojo/public/cpp/bindings/array.h"
#include "mojo/public/cpp/bindings/string.h"
#include "mojo/public/cpp/system/macros.h"
+#include "mojo/public/interfaces/application/application.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
@@ -22,7 +23,7 @@ const Array<String>& Args();
// Run all application tests. This must be called after the environment is
// initialized, to support construction of a default run loop.
-MojoResult RunAllTests(MojoHandle shell_handle);
+MojoResult RunAllTests(MojoHandle application_request_handle);
// A GTEST base class for application testing executed in mojo_shell.
class ApplicationTestBase : public testing::Test {
@@ -36,10 +37,6 @@ class ApplicationTestBase : public testing::Test {
// Get the ApplicationDelegate for the application to be tested.
virtual ApplicationDelegate* GetApplicationDelegate();
- // A testing::Test::SetUp helper to override the application command
- // line arguments.
- void SetUpWithArgs(const Array<String>& args);
-
// testing::Test:
void SetUp() override;
void TearDown() override;
diff --git a/third_party/mojo/src/mojo/public/cpp/application/lib/application_impl.cc b/third_party/mojo/src/mojo/public/cpp/application/lib/application_impl.cc
index 894060d..4d1f8dc 100644
--- a/third_party/mojo/src/mojo/public/cpp/application/lib/application_impl.cc
+++ b/third_party/mojo/src/mojo/public/cpp/application/lib/application_impl.cc
@@ -25,15 +25,11 @@ class ApplicationImpl::ShellPtrWatcher : public ErrorHandler {
};
ApplicationImpl::ApplicationImpl(ApplicationDelegate* delegate,
- ScopedMessagePipeHandle shell_handle)
- : initialized_(false), delegate_(delegate), shell_watch_(nullptr) {
- BindShell(shell_handle.Pass());
-}
-
-ApplicationImpl::ApplicationImpl(ApplicationDelegate* delegate,
- MojoHandle shell_handle)
- : initialized_(false), delegate_(delegate), shell_watch_(nullptr) {
- BindShell(MakeScopedHandle(MessagePipeHandle(shell_handle)));
+ InterfaceRequest<Application> request)
+ : initialized_(false),
+ delegate_(delegate),
+ binding_(this, request.Pass()),
+ shell_watch_(nullptr) {
}
bool ApplicationImpl::HasArg(const std::string& arg) const {
@@ -60,7 +56,7 @@ ApplicationImpl::~ApplicationImpl() {
ApplicationConnection* ApplicationImpl::ConnectToApplication(
const String& application_url) {
- MOJO_CHECK(initialized_);
+ MOJO_CHECK(shell_);
ServiceProviderPtr local_services;
InterfaceRequest<ServiceProvider> local_request = GetProxy(&local_services);
ServiceProviderPtr remote_services;
@@ -76,29 +72,24 @@ ApplicationConnection* ApplicationImpl::ConnectToApplication(
return registry;
}
-bool ApplicationImpl::WaitForInitialize() {
- MOJO_CHECK(!initialized_);
- bool result = shell_.WaitForIncomingMethodCall();
- MOJO_CHECK(initialized_ || !result);
- return result;
-}
-
-ScopedMessagePipeHandle ApplicationImpl::UnbindShell() {
- return shell_.PassMessagePipe();
-}
-
-void ApplicationImpl::Initialize(Array<String> args) {
- MOJO_CHECK(!initialized_);
- initialized_ = true;
+void ApplicationImpl::Initialize(ShellPtr shell, Array<String> args) {
+ shell_ = shell.Pass();
+ shell_watch_ = new ShellPtrWatcher(this);
+ shell_.set_error_handler(shell_watch_);
args_ = args.To<std::vector<std::string>>();
delegate_->Initialize(this);
}
-void ApplicationImpl::BindShell(ScopedMessagePipeHandle shell_handle) {
- shell_watch_ = new ShellPtrWatcher(this);
- shell_.Bind(shell_handle.Pass());
- shell_.set_client(this);
- shell_.set_error_handler(shell_watch_);
+void ApplicationImpl::WaitForInitialize() {
+ if (!shell_)
+ binding_.WaitForIncomingMethodCall();
+}
+
+void ApplicationImpl::UnbindConnections(
+ InterfaceRequest<Application>* application_request,
+ ShellPtr* shell) {
+ *application_request = binding_.Unbind();
+ shell->Bind(shell_.PassMessagePipe());
}
void ApplicationImpl::AcceptConnection(
diff --git a/third_party/mojo/src/mojo/public/cpp/application/lib/application_runner.cc b/third_party/mojo/src/mojo/public/cpp/application/lib/application_runner.cc
index dec74489..0737dc7 100644
--- a/third_party/mojo/src/mojo/public/cpp/application/lib/application_runner.cc
+++ b/third_party/mojo/src/mojo/public/cpp/application/lib/application_runner.cc
@@ -23,11 +23,12 @@ ApplicationRunner::~ApplicationRunner() {
assert(!delegate_);
}
-MojoResult ApplicationRunner::Run(MojoHandle shell_handle) {
+MojoResult ApplicationRunner::Run(MojoHandle app_request_handle) {
Environment env;
{
RunLoop loop;
- ApplicationImpl app(delegate_, shell_handle);
+ ApplicationImpl app(delegate_, MakeRequest<Application>(MakeScopedHandle(
+ MessagePipeHandle(app_request_handle))));
loop.Run();
}
diff --git a/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_base.cc b/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_base.cc
index 20a60a1..72058a4 100644
--- a/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_base.cc
+++ b/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_base.cc
@@ -4,33 +4,27 @@
#include "mojo/public/cpp/application/application_test_base.h"
-#include "mojo/public/cpp/application/application_delegate.h"
#include "mojo/public/cpp/application/application_impl.h"
+#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/environment/environment.h"
#include "mojo/public/cpp/system/message_pipe.h"
+#include "mojo/public/interfaces/application/application.mojom.h"
namespace mojo {
namespace test {
namespace {
-
-// This shell handle is shared by multiple test application instances.
-MessagePipeHandle g_shell_handle;
// Share the application command-line arguments with multiple application tests.
Array<String> g_args;
-ScopedMessagePipeHandle PassShellHandle() {
- MOJO_CHECK(g_shell_handle.is_valid());
- ScopedMessagePipeHandle scoped_handle(g_shell_handle);
- g_shell_handle = MessagePipeHandle();
- return scoped_handle.Pass();
-}
+// Application request handle passed from the shell in MojoMain, stored in
+// between SetUp()/TearDown() so we can (re-)intialize new ApplicationImpls.
+InterfaceRequest<Application> g_application_request;
-void SetShellHandle(ScopedMessagePipeHandle handle) {
- MOJO_CHECK(handle.is_valid());
- MOJO_CHECK(!g_shell_handle.is_valid());
- g_shell_handle = handle.release();
-}
+// Shell pointer passed in the initial mojo.Application.Initialize() call,
+// stored in between initial setup and the first test and between SetUp/TearDown
+// calls so we can (re-)initialize new ApplicationImpls.
+ShellPtr g_shell;
void InitializeArgs(int argc, std::vector<const char*> argv) {
MOJO_CHECK(g_args.is_null());
@@ -40,38 +34,71 @@ void InitializeArgs(int argc, std::vector<const char*> argv) {
}
}
+class ShellAndArgumentGrabber : public Application {
+ public:
+ ShellAndArgumentGrabber(Array<String>* args,
+ InterfaceRequest<Application> application_request)
+ : args_(args), binding_(this, application_request.Pass()) {}
+
+ void WaitForInitialize() {
+ // Initialize is always the first call made on Application.
+ binding_.WaitForIncomingMethodCall();
+ }
+
+ private:
+ // Application implementation.
+ void Initialize(ShellPtr shell, Array<String> args) override {
+ *args_ = args.Pass();
+ g_application_request = binding_.Unbind();
+ g_shell = shell.Pass();
+ }
+
+ void AcceptConnection(const String& requestor_url,
+ InterfaceRequest<ServiceProvider> services,
+ ServiceProviderPtr exposed_services) override {
+ MOJO_CHECK(false);
+ }
+
+ void RequestQuit() override { MOJO_CHECK(false); }
+
+ Array<String>* args_;
+ Binding<Application> binding_;
+};
+
} // namespace
const Array<String>& Args() {
return g_args;
}
-MojoResult RunAllTests(MojoHandle shell_handle) {
+MojoResult RunAllTests(MojoHandle application_request_handle) {
{
// This loop is used for init, and then destroyed before running tests.
Environment::InstantiateDefaultRunLoop();
- // Construct an ApplicationImpl just for the GTEST commandline arguments.
+ // Grab the shell handle and GTEST commandline arguments.
// GTEST command line arguments are supported amid application arguments:
// $ mojo_shell mojo:example_apptests
// --args-for='mojo:example_apptests arg1 --gtest_filter=foo arg2'
- mojo::ApplicationDelegate dummy_application_delegate;
- mojo::ApplicationImpl app(&dummy_application_delegate, shell_handle);
- MOJO_CHECK(app.WaitForInitialize());
+ Array<String> args;
+ ShellAndArgumentGrabber grabber(
+ &args, MakeRequest<Application>(MakeScopedHandle(
+ MessagePipeHandle(application_request_handle))));
+ grabber.WaitForInitialize();
+ MOJO_CHECK(g_shell);
+ MOJO_CHECK(g_application_request.is_pending());
// InitGoogleTest expects (argc + 1) elements, including a terminating null.
// It also removes GTEST arguments from |argv| and updates the |argc| count.
- const std::vector<std::string>& args = app.args();
MOJO_CHECK(args.size() <
static_cast<size_t>(std::numeric_limits<int>::max()));
int argc = static_cast<int>(args.size());
std::vector<const char*> argv(argc + 1);
for (int i = 0; i < argc; ++i)
- argv[i] = args[i].c_str();
+ argv[i] = args[i].get().c_str();
argv[argc] = nullptr;
testing::InitGoogleTest(&argc, const_cast<char**>(&(argv[0])));
- SetShellHandle(app.UnbindShell());
InitializeArgs(argc, argv);
Environment::DestroyDefaultRunLoop();
@@ -79,9 +106,9 @@ MojoResult RunAllTests(MojoHandle shell_handle) {
int result = RUN_ALL_TESTS();
- shell_handle = mojo::test::PassShellHandle().release().value();
- MojoResult close_result = MojoClose(shell_handle);
- MOJO_CHECK(close_result == MOJO_RESULT_OK);
+ // Shut down our message pipes before exiting.
+ (void)g_application_request.PassMessagePipe();
+ (void)g_shell.PassMessagePipe();
return (result == 0) ? MOJO_RESULT_OK : MOJO_RESULT_UNKNOWN;
}
@@ -96,26 +123,28 @@ ApplicationDelegate* ApplicationTestBase::GetApplicationDelegate() {
return &default_application_delegate_;
}
-void ApplicationTestBase::SetUpWithArgs(const Array<String>& args) {
+void ApplicationTestBase::SetUp() {
// A run loop is recommended for ApplicationImpl initialization and
// communication.
if (ShouldCreateDefaultRunLoop())
Environment::InstantiateDefaultRunLoop();
+ MOJO_CHECK(g_application_request.is_pending());
+ MOJO_CHECK(g_shell);
+
// New applications are constructed for each test to avoid persisting state.
application_impl_ = new ApplicationImpl(GetApplicationDelegate(),
- PassShellHandle());
+ g_application_request.Pass());
// Fake application initialization with the given command line arguments.
- application_impl_->Initialize(args.Clone());
-}
-
-void ApplicationTestBase::SetUp() {
- SetUpWithArgs(Args());
+ application_impl_->Initialize(g_shell.Pass(), g_args.Clone());
}
void ApplicationTestBase::TearDown() {
- SetShellHandle(application_impl_->UnbindShell());
+ MOJO_CHECK(!g_application_request.is_pending());
+ MOJO_CHECK(!g_shell);
+
+ application_impl_->UnbindConnections(&g_application_request, &g_shell);
delete application_impl_;
if (ShouldCreateDefaultRunLoop())
Environment::DestroyDefaultRunLoop();
diff --git a/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_main.cc b/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_main.cc
index 47f36e9..128d8ae 100644
--- a/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_main.cc
+++ b/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_main.cc
@@ -6,9 +6,9 @@
#include "mojo/public/cpp/application/application_test_base.h"
#include "mojo/public/cpp/environment/environment.h"
-MojoResult MojoMain(MojoHandle shell_handle) {
+MojoResult MojoMain(MojoHandle handle) {
// An Environment instance is needed to construct run loops.
mojo::Environment environment;
- return mojo::test::RunAllTests(shell_handle);
+ return mojo::test::RunAllTests(handle);
}
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/binding.h b/third_party/mojo/src/mojo/public/cpp/bindings/binding.h
index 658b6a0..7b663c4 100644
--- a/third_party/mojo/src/mojo/public/cpp/bindings/binding.h
+++ b/third_party/mojo/src/mojo/public/cpp/bindings/binding.h
@@ -165,6 +165,13 @@ class Binding : public ErrorHandler {
internal_router_->CloseMessagePipe();
}
+ // 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.
+ InterfaceRequest<Interface> Unbind() {
+ return MakeRequest<Interface>(internal_router_->PassMessagePipe());
+ }
+
// Sets an error handler that will be called if a connection error occurs on
// the bound message pipe.
void set_error_handler(ErrorHandler* error_handler) {
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/callback.h b/third_party/mojo/src/mojo/public/cpp/bindings/callback.h
index d7bab16..b8bc423 100644
--- a/third_party/mojo/src/mojo/public/cpp/bindings/callback.h
+++ b/third_party/mojo/src/mojo/public/cpp/bindings/callback.h
@@ -14,27 +14,35 @@ namespace mojo {
template <typename Sig>
class Callback;
+// Represents a callback with any number of parameters and no return value. The
+// callback is executed by calling its Run() method. The callback may be "null",
+// meaning it does nothing.
template <typename... Args>
class Callback<void(Args...)> {
public:
+ // An interface that may be implemented to define the Run() method.
struct Runnable {
virtual ~Runnable() {}
virtual void Run(
+ // ForwardType ensures String is passed as a const reference.
typename internal::Callback_ParamTraits<Args>::ForwardType...)
const = 0;
};
+ // Constructs a "null" callback that does nothing.
Callback() {}
- // The Callback assumes ownership of |runnable|.
+ // Constructs a callback that will run |runnable|. The callback takes
+ // ownership of |runnable|.
explicit Callback(Runnable* runnable) : sink_(runnable) {}
- // Any class that is copy-constructable and has a compatible Run method may
- // be adapted to a Callback using this constructor.
+ // As above, but can take an object that isn't derived from Runnable, so long
+ // as it has a Run() method.
template <typename Sink>
Callback(const Sink& sink)
: sink_(new Adapter<Sink>(sink)) {}
+ // Executes the callback function, invoking Pass() on move-only types.
void Run(typename internal::Callback_ParamTraits<Args>::ForwardType... args)
const {
if (sink_.get())
@@ -43,9 +51,12 @@ class Callback<void(Args...)> {
bool is_null() const { return !sink_.get(); }
+ // Resets the callback to the "null" state.
void reset() { sink_.reset(); }
private:
+ // Adapts a class that has a Run() method but is not derived from Runnable to
+ // be callable by Callback.
template <typename Sink>
struct Adapter : public Runnable {
explicit Adapter(const Sink& sink) : sink(sink) {}
@@ -60,6 +71,7 @@ class Callback<void(Args...)> {
internal::SharedPtr<Runnable> sink_;
};
+// A specialization of Callback which takes no parameters.
typedef Callback<void()> Closure;
} // namespace mojo
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h b/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h
index a2ede4d..b7f1a4e 100644
--- a/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h
+++ b/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h
@@ -15,84 +15,112 @@
namespace mojo {
class ErrorHandler;
-// InterfacePtr represents a proxy to a remote instance of an interface.
+// 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
+// bound to a message pipe before the interface methods can be called.
+//
+// Can also route incoming calls to a local implementation of the
+// Interface::Client interface. To enable this, call the set_client() method.
+// Calls to the client interface will originate from the same thread that owns
+// this InterfacePtr.
+//
+// This class is thread hostile, as is the local proxy it manages. All calls to
+// this class or the proxy should be from the same thread that created it. If
+// you need to move the proxy to a different thread, extract the message pipe
+// using PassMessagePipe(), pass it to a different thread, and create a new
+// InterfacePtr from that thread.
template <typename Interface>
class InterfacePtr {
MOJO_MOVE_ONLY_TYPE(InterfacePtr)
public:
+ // Constructs an unbound InterfacePtr.
InterfacePtr() {}
InterfacePtr(decltype(nullptr)) {}
+ // Takes over the binding of another InterfacePtr.
InterfacePtr(InterfacePtr&& other) {
internal_state_.Swap(&other.internal_state_);
}
+
+ // Takes over the binding of another InterfacePtr, and closes any message pipe
+ // already bound to this pointer.
InterfacePtr& operator=(InterfacePtr&& other) {
reset();
internal_state_.Swap(&other.internal_state_);
return *this;
}
+ // Assigning nullptr to this class causes it to close the currently bound
+ // message pipe (if any) and returns the pointer to the unbound state.
InterfacePtr& operator=(decltype(nullptr)) {
reset();
return *this;
}
+ // Closes the bound message pipe (if any) on destruction.
~InterfacePtr() {}
+ // Binds the InterfacePtr to a message pipe that is connected to a remote
+ // implementation of Interface. The |waiter| is used for receiving
+ // notifications when there is data to read from the message pipe. For most
+ // callers, the default |waiter| will be sufficient.
+ void Bind(
+ ScopedMessagePipeHandle handle,
+ const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) {
+ reset();
+ internal_state_.Bind(handle.Pass(), waiter);
+ }
+
+ // Returns a raw pointer to the local proxy. Caller does not take ownership.
+ // Note that the local proxy is thread hostile, as stated above.
Interface* get() const { return internal_state_.instance(); }
+
+ // Functions like a pointer to Interface. Must already be bound.
Interface* operator->() const { return get(); }
Interface& operator*() const { return *get(); }
+ // Closes the bound message pipe (if any) and returns the pointer to the
+ // unbound state.
void reset() {
State doomed;
internal_state_.Swap(&doomed);
}
- // Blocks the current thread for the first incoming method call, i.e., either
- // a call to a client method or a callback method. Returns |true| if a method
- // has been called, |false| in case of error. It must only be called on a
- // bound object.
+ // Blocks the current thread until the next incoming call to a client method
+ // or callback arrives, or until an error occurs. Returns |true| if a call
+ // arrived, or |false| in case of error.
+ //
+ // This method may only be called after the InterfacePtr has been bound to a
+ // message pipe.
bool WaitForIncomingMethodCall() {
return internal_state_.WaitForIncomingMethodCall();
}
- // This method configures the InterfacePtr<..> to be a proxy to a remote
- // object on the other end of the given pipe.
- //
- // The proxy is bound to the current thread, which means its methods may
- // only be called on the current thread.
- //
- // To move a bound InterfacePtr<..> to another thread, call PassMessagePipe().
- // Then create a new InterfacePtr<..> on another thread, and bind the new
- // InterfacePtr<..> to the message pipe on that thread.
- void Bind(
- ScopedMessagePipeHandle handle,
- const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) {
- reset();
- internal_state_.Bind(handle.Pass(), waiter);
- }
-
- // The client interface may only be set after this InterfacePtr<..> is bound.
+ // Enables routing of incoming method calls to a local implementation of the
+ // Interface::Client interface. Calls to |client| will come from the thread
+ // that owns this InterfacePtr.
void set_client(typename Interface::Client* client) {
internal_state_.set_client(client);
}
- // This method may be called to query if the underlying pipe has encountered
- // an error. If true, this means method calls made on this interface will be
- // dropped (and may have already been dropped) on the floor.
+ // Indicates whether the message pipe has encountered an error. 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(); }
- // This method may be called to register an ErrorHandler to observe a
- // connection error on the underlying pipe. It must only be called on a bound
- // object.
- // The callback runs asynchronously from the current message loop.
+ // Registers a handler to receive error notifications. The handler will be
+ // called from the thread that owns this InterfacePtr.
+ //
+ // This method may only be called after the InterfacePtr has been bound to a
+ // message pipe.
void set_error_handler(ErrorHandler* error_handler) {
internal_state_.set_error_handler(error_handler);
}
- // Returns the underlying message pipe handle (if any) and resets the
- // InterfacePtr<..> to its uninitialized state. This method is helpful if you
- // need to move a proxy to another thread. See related notes for Bind.
+ // Unbinds the InterfacePtr and return the previously bound message pipe (if
+ // any). This method may be used to move the proxy to a different thread (see
+ // class comments for details).
ScopedMessagePipeHandle PassMessagePipe() {
State state;
internal_state_.Swap(&state);
@@ -120,11 +148,9 @@ class InterfacePtr {
mutable State internal_state_;
};
-// Takes a handle to the proxy end-point of a pipe. On the other end is
-// presumed to be an interface implementation of type |Interface|. Returns a
-// generated proxy to that interface, which may be used on the current thread.
-// It is valid to call set_client on the returned InterfacePtr<..> to set an
-// instance of Interface::Client.
+// If the specified message pipe handle is valid, returns an InterfacePtr bound
+// to it. Otherwise, returns an unbound InterfacePtr. The specified |waiter|
+// will be used as in the InterfacePtr::Bind() method.
template <typename Interface>
InterfacePtr<Interface> MakeProxy(
ScopedMessagePipeHandle handle,
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h b/third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h
index 0b89103..488b679 100644
--- a/third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h
+++ b/third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h
@@ -9,35 +9,53 @@
namespace mojo {
-// Used in methods that return instances of remote objects.
+// Represents a request from a remote client for an implementation of Interface
+// over a specified message pipe. The implementor of the interface should
+// remove the message pipe by calling PassMessagePipe() and bind it to the
+// implementation. If this is not done, the InterfaceRequest will automatically
+// close the pipe on destruction. Can also represent the absence of a request
+// if the client did not provide a message pipe.
template <typename Interface>
class InterfaceRequest {
MOJO_MOVE_ONLY_TYPE(InterfaceRequest)
public:
+ // Constructs an empty InterfaceRequest, representing that the client is not
+ // requesting an implementation of Interface.
InterfaceRequest() {}
-
InterfaceRequest(decltype(nullptr)) {}
+
+ // Takes the message pipe from another InterfaceRequest.
InterfaceRequest(InterfaceRequest&& other) { handle_ = other.handle_.Pass(); }
- InterfaceRequest& operator=(decltype(nullptr)) {
- handle_.reset();
- return *this;
- }
InterfaceRequest& operator=(InterfaceRequest&& other) {
handle_ = other.handle_.Pass();
return *this;
}
- // Returns true if the request has yet to be completed.
- bool is_pending() const { return handle_.is_valid(); }
+ // Assigning to nullptr resets the InterfaceRequest to an empty state,
+ // closing the message pipe currently bound to it (if any).
+ InterfaceRequest& operator=(decltype(nullptr)) {
+ handle_.reset();
+ return *this;
+ }
+ // Binds the request to a message pipe over which Interface is to be
+ // requested. If the request is already bound to a message pipe, the current
+ // message pipe will be closed.
void Bind(ScopedMessagePipeHandle handle) { handle_ = handle.Pass(); }
+ // Indicates whether the request currently contains a valid message pipe.
+ bool is_pending() const { return handle_.is_valid(); }
+
+ // Removes the message pipe from the request and returns it.
ScopedMessagePipeHandle PassMessagePipe() { return handle_.Pass(); }
private:
ScopedMessagePipeHandle handle_;
};
+// Makes an InterfaceRequest bound to the specified message pipe. If |handle|
+// is empty or invalid, the resulting InterfaceRequest will represent the
+// absence of a request.
template <typename Interface>
InterfaceRequest<Interface> MakeRequest(ScopedMessagePipeHandle handle) {
InterfaceRequest<Interface> request;
@@ -45,23 +63,48 @@ InterfaceRequest<Interface> MakeRequest(ScopedMessagePipeHandle handle) {
return request.Pass();
}
-// Used to construct a request that synchronously binds an InterfacePtr<..>,
-// making it immediately usable upon return. The resulting request object may
-// then be later bound to an InterfaceImpl<..> via BindToRequest.
+// Creates a new message pipe over which Interface is to be served. Binds the
+// specified InterfacePtr to one end of the message pipe, and returns an
+// InterfaceRequest bound to the other. The InterfacePtr should be passed to
+// the client, and the InterfaceRequest should be passed to whatever will
+// provide the implementation. The implementation should typically be bound to
+// the InterfaceRequest using the Binding or StrongBinding classes. The client
+// may begin to issue calls even before an implementation has been bound, since
+// messages sent over the pipe will just queue up until they are consumed by
+// the implementation.
+//
+// Example #1: Requesting a remote implementation of an interface.
+// ===============================================================
//
// Given the following interface:
//
-// interface Foo {
-// CreateBar(Bar& bar);
+// interface Database {
+// OpenTable(Table& table);
// }
//
-// The caller of CreateBar would have code similar to the following:
+// The client would have code similar to the following:
+//
+// DatabasePtr database = ...; // Connect to database.
+// TablePtr table;
+// database->OpenTable(GetProxy(&table));
+//
+// Upon return from GetProxy, |table| is ready to have methods called on it.
+//
+// Example #2: Registering a local implementation with a remote service.
+// =====================================================================
+//
+// Given the following interface
+// interface Collector {
+// RegisterSource(Source source);
+// }
//
-// InterfacePtr<Foo> foo = ...;
-// InterfacePtr<Bar> bar;
-// foo->CreateBar(GetProxy(&bar));
+// The client would have code similar to the following:
//
-// Upon return from CreateBar, |bar| is ready to have methods called on it.
+// CollectorPtr collector = ...; // Connect to Collector.
+// SourcePtr source;
+// InterfaceRequest<Source> source_request = GetProxy(&source);
+// collector->RegisterSource(source.Pass());
+// CreateSource(source_request.Pass()); // Create implementation locally.
//
template <typename Interface>
InterfaceRequest<Interface> GetProxy(InterfacePtr<Interface>* ptr) {
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_internal.h b/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_internal.h
index f006cd0..8afc18c 100644
--- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_internal.h
+++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/map_internal.h
@@ -16,6 +16,7 @@ namespace internal {
template <typename Key, typename Value, bool kValueIsMoveOnlyType>
struct MapTraits {};
+// Defines traits of a map for which Value is not a move-only type.
template <typename Key, typename Value>
struct MapTraits<Key, Value, false> {
// Map keys can't be move only types.
@@ -105,6 +106,7 @@ struct MapTraits<Key, Value, false> {
}
};
+// Defines traits of a map for which Value is a move-only type.
template <typename Key, typename Value>
struct MapTraits<Key, Value, true> {
// Map keys can't be move only types.
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/template_util.h b/third_party/mojo/src/mojo/public/cpp/bindings/lib/template_util.h
index c221a54..2edbf5c 100644
--- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/template_util.h
+++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/template_util.h
@@ -60,11 +60,13 @@ struct IsMoveOnlyType {
sizeof(Test<T>(0)) == sizeof(YesType) && !IsConst<T>::value;
};
+// Returns a reference to |t| when T is not a move-only type.
template <typename T>
typename EnableIf<!IsMoveOnlyType<T>::value, T>::type& Forward(T& t) {
return t;
}
+// Returns the result of t.Pass() when T is a move-only type.
template <typename T>
typename EnableIf<IsMoveOnlyType<T>::value, T>::type Forward(T& t) {
return t.Pass();
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/map.h b/third_party/mojo/src/mojo/public/cpp/bindings/map.h
index 5149bb0..8ac183f 100644
--- a/third_party/mojo/src/mojo/public/cpp/bindings/map.h
+++ b/third_party/mojo/src/mojo/public/cpp/bindings/map.h
@@ -11,6 +11,15 @@
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 Key, typename Value>
class Map {
MOJO_MOVE_ONLY_TYPE(Map)
@@ -39,6 +48,8 @@ class Map {
Map() : 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) {
MOJO_DCHECK(keys.size() == values.size());
Traits::InitializeFrom(&map_, keys.Pass(), values.Pass());
@@ -52,16 +63,21 @@ class Map {
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);
}
+ // Destroys the contents of the Map and leaves it in the null state.
void reset() {
if (!map_.empty()) {
Traits::Finalize(&map_);
@@ -72,40 +88,57 @@ class Map {
bool is_null() const { return is_null_; }
+ // Indicates the number of keys in the map.
size_t size() const { return map_.size(); }
- // Used to mark an empty map as non-null for serialization purposes.
void mark_non_null() { is_null_ = false; }
- // 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.
+ // Inserts a key-value pair into the map, moving the value by calling its
+ // Pass() method if it is a move-only type. Like std::map, this does not
+ // insert |value| if |key| is already a member of the map.
void insert(KeyForwardType key, ValueForwardType value) {
is_null_ = false;
Traits::Insert(&map_, key, value);
}
+ // Returns a reference to the value associated with the specified key,
+ // crashing the process if the key is not present in the map.
ValueRefType at(KeyForwardType key) { return Traits::at(&map_, key); }
ValueConstRefType at(KeyForwardType key) const {
return Traits::at(&map_, 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).
ValueRefType operator[](KeyForwardType key) {
is_null_ = false;
return Traits::GetOrInsert(&map_, key);
}
+ // 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);
}
- // This moves all values in the map to a set of parallel arrays. This action
- // is destructive because we can have move-only objects as values; therefore
- // we can't have copy semantics here.
+ // 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 passed by calling their Pass() method. Either way, the
+ // Map will be left in a null state.
void DecomposeMapTo(mojo::Array<Key>* keys, mojo::Array<Value>* values) {
Traits::Decompose(&map_, keys, values);
Traits::Finalize(&map_);
@@ -113,9 +146,11 @@ class Map {
is_null_ = true;
}
- // Please note that calling this method will fail compilation if the value
- // type cannot be cloned (which usually means that it is a Mojo handle type or
- // a type contains Mojo handles).
+ // Returns a new Map that contains a copy of the contents of this map. If the
+ // values are of a type that is designated move-only, they will be cloned
+ // using the Clone() method of the type. Please note that calling this method
+ // will fail compilation if the value type cannot be cloned (which usually
+ // means that it is a Mojo handle type or a type that contains Mojo handles).
Map Clone() const {
Map result;
result.is_null_ = is_null_;
@@ -123,6 +158,13 @@ class Map {
return result.Pass();
}
+ // Indicates whether the contents of this map are equal to those of another
+ // Map (including nullness). Keys are compared by the != operator. Values are
+ // compared as follows:
+ // - Map, Array, Struct, or StructPtr values are compared by their Equals()
+ // method.
+ // - ScopedHandleBase-derived types are compared by their handles.
+ // - Values of other types are compared by their "==" operator.
bool Equals(const Map& other) const {
if (is_null() != other.is_null())
return false;
@@ -141,6 +183,7 @@ class Map {
return true;
}
+ // A read-only iterator for Map.
class ConstMapIterator {
public:
ConstMapIterator(
@@ -148,6 +191,7 @@ class Map {
ValueStorageType>::const_iterator& it)
: it_(it) {}
+ // Returns a const reference to the key and value.
KeyConstRefType GetKey() { return Traits::GetKey(it_); }
ValueConstRefType GetValue() { return Traits::GetValue(it_); }
@@ -166,10 +210,13 @@ class Map {
typename std::map<KeyStorageType, ValueStorageType>::const_iterator it_;
};
- // Provide read-only iteration over map members.
+ // Provide read-only iteration over map members in a way similar to STL
+ // collections.
ConstMapIterator begin() const { return ConstMapIterator(map_.begin()); }
ConstMapIterator end() const { return ConstMapIterator(map_.end()); }
+ // Returns the iterator pointing to the entry for |key|, if present, or else
+ // returns end().
ConstMapIterator find(KeyForwardType key) const {
return ConstMapIterator(map_.find(key));
}
@@ -178,6 +225,9 @@ class Map {
typedef std::map<KeyStorageType, ValueStorageType> 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:
@@ -190,6 +240,8 @@ class Map {
bool is_null_;
};
+// 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,
@@ -207,6 +259,8 @@ struct TypeConverter<Map<MojoKey, MojoValue>, std::map<STLKey, STLValue>> {
}
};
+// 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,
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h b/third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h
index 0cd4f03..7caf54a 100644
--- a/third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h
+++ b/third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h
@@ -45,6 +45,8 @@ namespace mojo {
// };
template <typename Interface>
class StrongBinding : public ErrorHandler {
+ MOJO_MOVE_ONLY_TYPE(StrongBinding)
+
public:
explicit StrongBinding(Interface* impl) : binding_(impl) {
binding_.set_error_handler(this);
diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc b/third_party/mojo/src/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
index f90dc3d..ded5888 100644
--- a/third_party/mojo/src/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
+++ b/third_party/mojo/src/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
@@ -27,34 +27,59 @@ class ErrorObserver : public ErrorHandler {
bool encountered_error_;
};
+template <typename Method, typename Class>
+class RunnableImpl {
+ public:
+ RunnableImpl(Method method, Class instance)
+ : method_(method), instance_(instance) {}
+ template <typename... Args>
+ void Run(Args... args) const {
+ (instance_->*method_)(args...);
+ }
+
+ private:
+ Method method_;
+ Class instance_;
+};
+
+template <typename Method, typename Class>
+RunnableImpl<Method, Class> MakeRunnable(Method method, Class object) {
+ return RunnableImpl<Method, Class>(method, object);
+}
+
+typedef mojo::Callback<void(double)> CalcCallback;
+
class MathCalculatorImpl : public InterfaceImpl<math::Calculator> {
public:
~MathCalculatorImpl() override {}
MathCalculatorImpl() : total_(0.0) {}
- void Clear() override { client()->Output(total_); }
+ void Clear(const CalcCallback& callback) override {
+ total_ = 0.0;
+ callback.Run(total_);
+ }
- void Add(double value) override {
+ void Add(double value, const CalcCallback& callback) override {
total_ += value;
- client()->Output(total_);
+ callback.Run(total_);
}
- void Multiply(double value) override {
+ void Multiply(double value, const CalcCallback& callback) override {
total_ *= value;
- client()->Output(total_);
+ callback.Run(total_);
}
private:
double total_;
};
-class MathCalculatorUIImpl : public math::CalculatorUI {
+class MathCalculatorUI {
public:
- explicit MathCalculatorUIImpl(math::CalculatorPtr calculator)
- : calculator_(calculator.Pass()), output_(0.0) {
- calculator_.set_client(this);
- }
+ explicit MathCalculatorUI(math::CalculatorPtr calculator)
+ : calculator_(calculator.Pass()),
+ output_(0.0),
+ callback_(MakeRunnable(&MathCalculatorUI::Output, this)) {}
bool WaitForIncomingMethodCall() {
return calculator_.WaitForIncomingMethodCall();
@@ -62,59 +87,60 @@ class MathCalculatorUIImpl : public math::CalculatorUI {
bool encountered_error() const { return calculator_.encountered_error(); }
- void Add(double value) { calculator_->Add(value); }
+ void Add(double value) { calculator_->Add(value, callback_); }
- void Subtract(double value) { calculator_->Add(-value); }
+ void Subtract(double value) { calculator_->Add(-value, callback_); }
- void Multiply(double value) { calculator_->Multiply(value); }
+ void Multiply(double value) { calculator_->Multiply(value, callback_); }
- void Divide(double value) { calculator_->Multiply(1.0 / value); }
+ void Divide(double value) { calculator_->Multiply(1.0 / value, callback_); }
double GetOutput() const { return output_; }
private:
- // math::CalculatorUI implementation:
- void Output(double value) override { output_ = value; }
+ void Output(double output) { output_ = output; }
math::CalculatorPtr calculator_;
double output_;
+ Callback<void(double)> callback_;
};
-class SelfDestructingMathCalculatorUIImpl : public math::CalculatorUI {
+class SelfDestructingMathCalculatorUI {
public:
- explicit SelfDestructingMathCalculatorUIImpl(math::CalculatorPtr calculator)
+ explicit SelfDestructingMathCalculatorUI(math::CalculatorPtr calculator)
: calculator_(calculator.Pass()), nesting_level_(0) {
++num_instances_;
- calculator_.set_client(this);
}
void BeginTest(bool nested) {
nesting_level_ = nested ? 2 : 1;
- calculator_->Add(1.0);
+ calculator_->Add(
+ 1.0, MakeRunnable(&SelfDestructingMathCalculatorUI::Output, this));
}
static int num_instances() { return num_instances_; }
- private:
- ~SelfDestructingMathCalculatorUIImpl() override { --num_instances_; }
-
- void Output(double value) override {
+ void Output(double value) {
if (--nesting_level_ > 0) {
// Add some more and wait for re-entrant call to Output!
- calculator_->Add(1.0);
+ calculator_->Add(
+ 1.0, MakeRunnable(&SelfDestructingMathCalculatorUI::Output, this));
RunLoop::current()->RunUntilIdle();
} else {
delete this;
}
}
+ private:
+ ~SelfDestructingMathCalculatorUI() { --num_instances_; }
+
math::CalculatorPtr calculator_;
int nesting_level_;
static int num_instances_;
};
// static
-int SelfDestructingMathCalculatorUIImpl::num_instances_ = 0;
+int SelfDestructingMathCalculatorUI::num_instances_ = 0;
class ReentrantServiceImpl : public InterfaceImpl<sample::Service> {
public:
@@ -157,7 +183,7 @@ TEST_F(InterfacePtrTest, EndToEnd) {
BindToProxy(new MathCalculatorImpl(), &calc);
// Suppose this is instantiated in a process that has pipe1_.
- MathCalculatorUIImpl calculator_ui(calc.Pass());
+ MathCalculatorUI calculator_ui(calc.Pass());
calculator_ui.Add(2.0);
calculator_ui.Multiply(5.0);
@@ -172,7 +198,7 @@ TEST_F(InterfacePtrTest, EndToEnd_Synchronous) {
MathCalculatorImpl* impl = BindToProxy(new MathCalculatorImpl(), &calc);
// Suppose this is instantiated in a process that has pipe1_.
- MathCalculatorUIImpl calculator_ui(calc.Pass());
+ MathCalculatorUI calculator_ui(calc.Pass());
EXPECT_EQ(0.0, calculator_ui.GetOutput());
@@ -230,7 +256,7 @@ TEST_F(InterfacePtrTest, EncounteredError) {
math::CalculatorPtr proxy;
MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy);
- MathCalculatorUIImpl calculator_ui(proxy.Pass());
+ MathCalculatorUI calculator_ui(proxy.Pass());
calculator_ui.Add(2.0);
PumpMessages();
@@ -259,7 +285,7 @@ TEST_F(InterfacePtrTest, EncounteredErrorCallback) {
ErrorObserver error_observer;
proxy.set_error_handler(&error_observer);
- MathCalculatorUIImpl calculator_ui(proxy.Pass());
+ MathCalculatorUI calculator_ui(proxy.Pass());
calculator_ui.Add(2.0);
PumpMessages();
@@ -297,30 +323,30 @@ TEST_F(InterfacePtrTest, DestroyInterfacePtrOnClientMethod) {
math::CalculatorPtr proxy;
BindToProxy(new MathCalculatorImpl(), &proxy);
- EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
+ EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances());
- SelfDestructingMathCalculatorUIImpl* impl =
- new SelfDestructingMathCalculatorUIImpl(proxy.Pass());
+ SelfDestructingMathCalculatorUI* impl =
+ new SelfDestructingMathCalculatorUI(proxy.Pass());
impl->BeginTest(false);
PumpMessages();
- EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
+ EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances());
}
TEST_F(InterfacePtrTest, NestedDestroyInterfacePtrOnClientMethod) {
math::CalculatorPtr proxy;
BindToProxy(new MathCalculatorImpl(), &proxy);
- EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
+ EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances());
- SelfDestructingMathCalculatorUIImpl* impl =
- new SelfDestructingMathCalculatorUIImpl(proxy.Pass());
+ SelfDestructingMathCalculatorUI* impl =
+ new SelfDestructingMathCalculatorUI(proxy.Pass());
impl->BeginTest(true);
PumpMessages();
- EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
+ EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances());
}
TEST_F(InterfacePtrTest, ReentrantWaitForIncomingMethodCall) {
@@ -348,16 +374,16 @@ class StrongMathCalculatorImpl : public math::Calculator, public ErrorHandler {
~StrongMathCalculatorImpl() override { *destroyed_ = true; }
// math::Calculator implementation.
- void Clear() override { binding_.client()->Output(total_); }
+ void Clear(const CalcCallback& callback) override { callback.Run(total_); }
- void Add(double value) override {
+ void Add(double value, const CalcCallback& callback) override {
total_ += value;
- binding_.client()->Output(total_);
+ callback.Run(total_);
}
- void Multiply(double value) override {
+ void Multiply(double value, const CalcCallback& callback) override {
total_ *= value;
- binding_.client()->Output(total_);
+ callback.Run(total_);
}
// ErrorHandler implementation.
@@ -387,7 +413,7 @@ TEST(StrongConnectorTest, Math) {
{
// Suppose this is instantiated in a process that has the other end of the
// message pipe.
- MathCalculatorUIImpl calculator_ui(calc.Pass());
+ MathCalculatorUI calculator_ui(calc.Pass());
calculator_ui.Add(2.0);
calculator_ui.Multiply(5.0);
@@ -419,16 +445,16 @@ class WeakMathCalculatorImpl : public math::Calculator, public ErrorHandler {
}
~WeakMathCalculatorImpl() override { *destroyed_ = true; }
- void Clear() override { binding_.client()->Output(total_); }
+ void Clear(const CalcCallback& callback) override { callback.Run(total_); }
- void Add(double value) override {
+ void Add(double value, const CalcCallback& callback) override {
total_ += value;
- binding_.client()->Output(total_);
+ callback.Run(total_);
}
- void Multiply(double value) override {
+ void Multiply(double value, const CalcCallback& callback) override {
total_ *= value;
- binding_.client()->Output(total_);
+ callback.Run(total_);
}
// ErrorHandler implementation.
@@ -457,7 +483,7 @@ TEST(WeakConnectorTest, Math) {
{
// Suppose this is instantiated in a process that has the other end of the
// message pipe.
- MathCalculatorUIImpl calculator_ui(calc.Pass());
+ MathCalculatorUI calculator_ui(calc.Pass());
calculator_ui.Add(2.0);
calculator_ui.Multiply(5.0);
diff --git a/third_party/mojo/src/mojo/public/cpp/system/buffer.h b/third_party/mojo/src/mojo/public/cpp/system/buffer.h
index 6817297..9458c0a 100644
--- a/third_party/mojo/src/mojo/public/cpp/system/buffer.h
+++ b/third_party/mojo/src/mojo/public/cpp/system/buffer.h
@@ -2,6 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This file provides a C++ wrapping around the Mojo C API for shared buffers,
+// replacing the prefix of "Mojo" with a "mojo" namespace, and using more
+// strongly-typed representations of |MojoHandle|s.
+//
+// Please see "mojo/public/c/system/buffer.h" for complete documentation of the
+// API.
+
#ifndef MOJO_PUBLIC_CPP_SYSTEM_BUFFER_H_
#define MOJO_PUBLIC_CPP_SYSTEM_BUFFER_H_
@@ -13,8 +20,8 @@
namespace mojo {
-// SharedBufferHandle ----------------------------------------------------------
-
+// A strongly-typed representation of a |MojoHandle| referring to a shared
+// buffer.
class SharedBufferHandle : public Handle {
public:
SharedBufferHandle() {}
@@ -30,6 +37,8 @@ typedef ScopedHandleBase<SharedBufferHandle> ScopedSharedBufferHandle;
static_assert(sizeof(ScopedSharedBufferHandle) == sizeof(SharedBufferHandle),
"Bad size for C++ ScopedSharedBufferHandle");
+// Creates a shared buffer. See |MojoCreateSharedBuffer()| for complete
+// documentation.
inline MojoResult CreateSharedBuffer(
const MojoCreateSharedBufferOptions* options,
uint64_t num_bytes,
@@ -44,10 +53,17 @@ inline MojoResult CreateSharedBuffer(
return rv;
}
+// Duplicates a handle to a buffer, most commonly so that the buffer can be
+// shared with other applications. See |MojoDuplicateBufferHandle()| for
+// complete documentation.
+//
+// TODO(ggowan): Rename this to DuplicateBufferHandle since it is making another
+// handle to the same buffer, not duplicating the buffer itself.
+//
// TODO(vtl): This (and also the functions below) are templatized to allow for
// future/other buffer types. A bit "safer" would be to overload this function
-// manually. (The template enforces that the in and out handles to be of the
-// same type.)
+// manually. (The template enforces that the in and out handles be of the same
+// type.)
template <class BufferHandleType>
inline MojoResult DuplicateBuffer(
BufferHandleType buffer,
@@ -63,6 +79,8 @@ inline MojoResult DuplicateBuffer(
return rv;
}
+// Maps a part of a buffer (specified by |buffer|, |offset|, and |num_bytes|)
+// into memory. See |MojoMapBuffer()| for complete documentation.
template <class BufferHandleType>
inline MojoResult MapBuffer(BufferHandleType buffer,
uint64_t offset,
@@ -73,6 +91,8 @@ inline MojoResult MapBuffer(BufferHandleType buffer,
return MojoMapBuffer(buffer.value(), offset, num_bytes, pointer, flags);
}
+// Unmaps a part of a buffer that was previously mapped with |MapBuffer()|.
+// See |MojoUnmapBuffer()| for complete documentation.
inline MojoResult UnmapBuffer(void* pointer) {
assert(pointer);
return MojoUnmapBuffer(pointer);
diff --git a/third_party/mojo/src/mojo/public/cpp/system/data_pipe.h b/third_party/mojo/src/mojo/public/cpp/system/data_pipe.h
index 5d3396c..c451cff 100644
--- a/third_party/mojo/src/mojo/public/cpp/system/data_pipe.h
+++ b/third_party/mojo/src/mojo/public/cpp/system/data_pipe.h
@@ -2,6 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This file provides a C++ wrapping around the Mojo C API for data pipes,
+// replacing the prefix of "Mojo" with a "mojo" namespace, and using more
+// strongly-typed representations of |MojoHandle|s.
+//
+// Please see "mojo/public/c/system/data_pipe.h" for complete documentation of
+// the API.
+
#ifndef MOJO_PUBLIC_CPP_SYSTEM_DATA_PIPE_H_
#define MOJO_PUBLIC_CPP_SYSTEM_DATA_PIPE_H_
@@ -13,8 +20,8 @@
namespace mojo {
-// DataPipeProducerHandle and DataPipeConsumerHandle ---------------------------
-
+// A strongly-typed representation of a |MojoHandle| to the producer end of a
+// data pipe.
class DataPipeProducerHandle : public Handle {
public:
DataPipeProducerHandle() {}
@@ -31,6 +38,8 @@ static_assert(sizeof(ScopedDataPipeProducerHandle) ==
sizeof(DataPipeProducerHandle),
"Bad size for C++ ScopedDataPipeProducerHandle");
+// A strongly-typed representation of a |MojoHandle| to the consumer end of a
+// data pipe.
class DataPipeConsumerHandle : public Handle {
public:
DataPipeConsumerHandle() {}
@@ -47,6 +56,8 @@ static_assert(sizeof(ScopedDataPipeConsumerHandle) ==
sizeof(DataPipeConsumerHandle),
"Bad size for C++ ScopedDataPipeConsumerHandle");
+// Creates a new data pipe. See |MojoCreateDataPipe()| for complete
+// documentation.
inline MojoResult CreateDataPipe(
const MojoCreateDataPipeOptions* options,
ScopedDataPipeProducerHandle* data_pipe_producer,
@@ -65,6 +76,7 @@ inline MojoResult CreateDataPipe(
return rv;
}
+// Writes to a data pipe. See |MojoWriteData| for complete documentation.
inline MojoResult WriteDataRaw(DataPipeProducerHandle data_pipe_producer,
const void* elements,
uint32_t* num_bytes,
@@ -72,6 +84,8 @@ inline MojoResult WriteDataRaw(DataPipeProducerHandle data_pipe_producer,
return MojoWriteData(data_pipe_producer.value(), elements, num_bytes, flags);
}
+// Begins a two-phase write to a data pipe. See |MojoBeginWriteData()| for
+// complete documentation.
inline MojoResult BeginWriteDataRaw(DataPipeProducerHandle data_pipe_producer,
void** buffer,
uint32_t* buffer_num_bytes,
@@ -80,11 +94,14 @@ inline MojoResult BeginWriteDataRaw(DataPipeProducerHandle data_pipe_producer,
data_pipe_producer.value(), buffer, buffer_num_bytes, flags);
}
+// Completes a two-phase write to a data pipe. See |MojoEndWriteData()| for
+// complete documentation.
inline MojoResult EndWriteDataRaw(DataPipeProducerHandle data_pipe_producer,
uint32_t num_bytes_written) {
return MojoEndWriteData(data_pipe_producer.value(), num_bytes_written);
}
+// Reads from a data pipe. See |MojoReadData()| for complete documentation.
inline MojoResult ReadDataRaw(DataPipeConsumerHandle data_pipe_consumer,
void* elements,
uint32_t* num_bytes,
@@ -92,6 +109,8 @@ inline MojoResult ReadDataRaw(DataPipeConsumerHandle data_pipe_consumer,
return MojoReadData(data_pipe_consumer.value(), elements, num_bytes, flags);
}
+// Begins a two-phase read from a data pipe. See |MojoBeginReadData()| for
+// complete documentation.
inline MojoResult BeginReadDataRaw(DataPipeConsumerHandle data_pipe_consumer,
const void** buffer,
uint32_t* buffer_num_bytes,
@@ -100,6 +119,8 @@ inline MojoResult BeginReadDataRaw(DataPipeConsumerHandle data_pipe_consumer,
data_pipe_consumer.value(), buffer, buffer_num_bytes, flags);
}
+// Completes a two-phase read from a data pipe. See |MojoEndReadData()| for
+// complete documentation.
inline MojoResult EndReadDataRaw(DataPipeConsumerHandle data_pipe_consumer,
uint32_t num_bytes_read) {
return MojoEndReadData(data_pipe_consumer.value(), num_bytes_read);
diff --git a/third_party/mojo/src/mojo/public/cpp/system/functions.h b/third_party/mojo/src/mojo/public/cpp/system/functions.h
index d73d27a..9cfe316 100644
--- a/third_party/mojo/src/mojo/public/cpp/system/functions.h
+++ b/third_party/mojo/src/mojo/public/cpp/system/functions.h
@@ -2,6 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This file provides a C++ wrapping around the standalone functions of the Mojo
+// C API, replacing the prefix of "Mojo" with a "mojo" namespace.
+//
+// Please see "mojo/public/c/system/functions.h" for complete documentation of
+// the API.
+
#ifndef MOJO_PUBLIC_CPP_SYSTEM_FUNCTIONS_H_
#define MOJO_PUBLIC_CPP_SYSTEM_FUNCTIONS_H_
@@ -9,12 +15,18 @@
namespace mojo {
-// Standalone functions --------------------------------------------------------
-
+// Returns the current |MojoTimeTicks| value. See |MojoGetTimeTicksNow()| for
+// complete documentation.
inline MojoTimeTicks GetTimeTicksNow() {
return MojoGetTimeTicksNow();
}
+// The C++ wrappers for |MojoWait()| and |MojoWaitMany()| are defined in
+// "handle.h".
+// TODO(ggowan): Consider making the C and C++ APIs more consistent in the
+// organization of the functions into different header files (since in the C
+// API, those functions are defined in "functions.h").
+
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_SYSTEM_FUNCTIONS_H_
diff --git a/third_party/mojo/src/mojo/public/cpp/system/handle.h b/third_party/mojo/src/mojo/public/cpp/system/handle.h
index 0c5adc7..45624bc 100644
--- a/third_party/mojo/src/mojo/public/cpp/system/handle.h
+++ b/third_party/mojo/src/mojo/public/cpp/system/handle.h
@@ -61,23 +61,8 @@ namespace mojo {
// |ScopedHandleBase<SharedBufferHandle>|) as an "out" parameter.
//
// An exception are some of the |...Raw()| functions. E.g., |CloseRaw()| takes a
-// |Handle|, leaving the user to discard the handle.
+// |Handle|, leaving the user to discard the wrapper.
//
-// More significantly, |WriteMessageRaw()| exposes the full API complexity of
-// |MojoWriteMessage()| (but doesn't require any extra overhead). It takes a raw
-// array of |Handle|s as input, and takes ownership of them (i.e., invalidates
-// them) on *success* (but not on failure). There are a number of reasons for
-// this. First, C++03 |std::vector|s cannot contain the move-only
-// |Scoped...Handle|s. Second, |std::vector|s impose extra overhead
-// (necessitating heap-allocation of the buffer). Third, |std::vector|s wouldn't
-// provide the desired level of flexibility/safety: a vector of handles would
-// have to be all of the same type (probably |Handle|/|ScopedHandle|). Fourth,
-// it's expected to not be used directly, but instead be used by generated
-// bindings.
-//
-// Other |...Raw()| functions expose similar rough edges, e.g., dealing with raw
-// pointers (and lengths) instead of taking |std::vector|s or similar.
-
// ScopedHandleBase ------------------------------------------------------------
// Scoper for the actual handle types defined further below. It's move-only,
diff --git a/third_party/mojo/src/mojo/public/cpp/system/macros.h b/third_party/mojo/src/mojo/public/cpp/system/macros.h
index f2bd0bc..8c79989 100644
--- a/third_party/mojo/src/mojo/public/cpp/system/macros.h
+++ b/third_party/mojo/src/mojo/public/cpp/system/macros.h
@@ -2,15 +2,15 @@
// 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_MACROS_H_
-#define MOJO_PUBLIC_CPP_SYSTEM_MACROS_H_
-
-#include "mojo/public/c/system/macros.h"
-
// Define a set of C++ specific macros.
// Mojo C++ API users can assume that mojo/public/cpp/system/macros.h
// includes mojo/public/c/system/macros.h.
+#ifndef MOJO_PUBLIC_CPP_SYSTEM_MACROS_H_
+#define MOJO_PUBLIC_CPP_SYSTEM_MACROS_H_
+
+#include "mojo/public/c/system/macros.h" // Symbols exposed.
+
// A macro to disallow the copy constructor and operator= functions.
// This should be used in the private: declarations for a class.
#define MOJO_DISALLOW_COPY_AND_ASSIGN(TypeName) \
diff --git a/third_party/mojo/src/mojo/public/cpp/system/message_pipe.h b/third_party/mojo/src/mojo/public/cpp/system/message_pipe.h
index b41469e..e7a1e35 100644
--- a/third_party/mojo/src/mojo/public/cpp/system/message_pipe.h
+++ b/third_party/mojo/src/mojo/public/cpp/system/message_pipe.h
@@ -2,6 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This file provides a C++ wrapping around the Mojo C API for message pipes,
+// replacing the prefix of "Mojo" with a "mojo" namespace, and using more
+// strongly-typed representations of |MojoHandle|s.
+//
+// Please see "mojo/public/c/system/message_pipe.h" for complete documentation
+// of the API.
+
#ifndef MOJO_PUBLIC_CPP_SYSTEM_MESSAGE_PIPE_H_
#define MOJO_PUBLIC_CPP_SYSTEM_MESSAGE_PIPE_H_
@@ -13,8 +20,8 @@
namespace mojo {
-// MessagePipeHandle -----------------------------------------------------------
-
+// A strongly-typed representation of a |MojoHandle| to one end of a message
+// pipe.
class MessagePipeHandle : public Handle {
public:
MessagePipeHandle() {}
@@ -30,6 +37,8 @@ typedef ScopedHandleBase<MessagePipeHandle> ScopedMessagePipeHandle;
static_assert(sizeof(ScopedMessagePipeHandle) == sizeof(MessagePipeHandle),
"Bad size for C++ ScopedMessagePipeHandle");
+// Creates a message pipe. See |MojoCreateMessagePipe()| for complete
+// documentation.
inline MojoResult CreateMessagePipe(const MojoCreateMessagePipeOptions* options,
ScopedMessagePipeHandle* message_pipe0,
ScopedMessagePipeHandle* message_pipe1) {
@@ -46,9 +55,16 @@ inline MojoResult CreateMessagePipe(const MojoCreateMessagePipeOptions* options,
return rv;
}
-// These "raw" versions fully expose the underlying API, but don't help with
-// ownership of handles (especially when writing messages).
-// TODO(vtl): Write "baked" versions.
+// The following "...Raw" versions fully expose the underlying API, and don't
+// help with ownership of handles (especially when writing messages). It is
+// expected that in most cases these methods will be called through generated
+// bindings anyway.
+// TODO(vtl): Write friendlier versions of these functions (using scoped
+// handles and/or vectors) if there is a demonstrated need for them.
+
+// Writes to a message pipe. If handles are attached, on success the handles
+// will no longer be valid (the receiver will receive equivalent, but logically
+// different, handles). See |MojoWriteMessage()| for complete documentation.
inline MojoResult WriteMessageRaw(MessagePipeHandle message_pipe,
const void* bytes,
uint32_t num_bytes,
@@ -59,6 +75,8 @@ inline MojoResult WriteMessageRaw(MessagePipeHandle message_pipe,
message_pipe.value(), bytes, num_bytes, handles, num_handles, flags);
}
+// Reads from a message pipe. See |MojoReadMessage()| for complete
+// documentation.
inline MojoResult ReadMessageRaw(MessagePipeHandle message_pipe,
void* bytes,
uint32_t* num_bytes,
diff --git a/third_party/mojo/src/mojo/public/dart/application.dart b/third_party/mojo/src/mojo/public/dart/application.dart
new file mode 100644
index 0000000..80cc144
--- /dev/null
+++ b/third_party/mojo/src/mojo/public/dart/application.dart
@@ -0,0 +1,18 @@
+// 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.
+
+library application;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:mojo_bindings' as bindings;
+import 'dart:mojo_core' as core;
+import 'dart:typed_data';
+
+import 'package:mojo/public/interfaces/application/application.mojom.dart' as application_mojom;
+import 'package:mojo/public/interfaces/application/service_provider.mojom.dart' as service_provider;
+import 'package:mojo/public/interfaces/application/shell.mojom.dart' as shell_mojom;
+
+part 'src/application.dart';
+part 'src/service_provider.dart';
diff --git a/third_party/mojo/src/mojo/public/dart/bindings.dart b/third_party/mojo/src/mojo/public/dart/bindings.dart
index 0637737..ef481a1 100644
--- a/third_party/mojo/src/mojo/public/dart/bindings.dart
+++ b/third_party/mojo/src/mojo/public/dart/bindings.dart
@@ -9,8 +9,8 @@ import 'dart:convert';
import 'dart:mojo_core' as core;
import 'dart:typed_data';
-part 'src/client.dart';
part 'src/codec.dart';
-part 'src/interface.dart';
part 'src/message.dart';
+part 'src/proxy.dart';
part 'src/struct.dart';
+part 'src/stub.dart';
diff --git a/third_party/mojo/src/mojo/public/dart/src/application.dart b/third_party/mojo/src/mojo/public/dart/src/application.dart
new file mode 100644
index 0000000..55002f5e
--- /dev/null
+++ b/third_party/mojo/src/mojo/public/dart/src/application.dart
@@ -0,0 +1,121 @@
+// 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.
+
+part of application;
+
+class _ApplicationImpl extends application_mojom.Application {
+ shell_mojom.ShellProxy shell;
+ Application _application;
+
+ _ApplicationImpl(
+ Application application, core.MojoMessagePipeEndpoint endpoint)
+ : _application = application, super(endpoint) {
+ super.delegate = this;
+ }
+
+ _ApplicationImpl.fromHandle(Application application, core.MojoHandle handle)
+ : _application = application, super.fromHandle(handle) {
+ super.delegate = this;
+ }
+
+ void initialize(shell_mojom.ShellProxy shellProxy, List<String> args) {
+ assert(shell == null);
+ shell = shellProxy;
+ _application.initialize(args);
+ }
+
+ void acceptConnection(
+ String requestorUrl,
+ service_provider.ServiceProviderStub services,
+ service_provider.ServiceProviderProxy exposedServices) =>
+ _application._acceptConnection(requestorUrl, services, exposedServices);
+
+ void requestQuit() => _application._requestQuitAndClose();
+
+ void close() => shell.close();
+}
+
+// TODO(zra): Better documentation and examples.
+// To implement, do the following:
+// - Optionally override acceptConnection() if services are to be provided.
+// The override should assign a factory function to the passed in
+// ServiceProvider's |factory| field, and then call listen on the
+// ServiceProvider. The factory function should take a MojoMessagePipeEndpoint
+// and return an object that implements the requested interface.
+// - Optionally override initialize() where needed.
+// - Optionally override requestClose() to clean up state specific to your
+// application.
+// To use an Application:
+// - Call listen() on a newly created Application to begin providing services.
+// - Call connectToService() to request services from the Shell.
+// - Call close() to close connections to any requested ServiceProviders and the
+// Shell.
+abstract class Application {
+ _ApplicationImpl _applicationImpl;
+ List<service_provider.ServiceProviderProxy> _proxies;
+ List<ServiceProvider> _serviceProviders;
+
+ Application(core.MojoMessagePipeEndpoint endpoint) {
+ _proxies = [];
+ _serviceProviders = [];
+ _applicationImpl = new _ApplicationImpl(this, endpoint);
+ }
+
+ Application.fromHandle(core.MojoHandle appHandle) {
+ _proxies = [];
+ _serviceProviders = [];
+ _applicationImpl = new _ApplicationImpl.fromHandle(this, appHandle);
+ }
+
+ void initialize(List<String> args) {}
+
+ void connectToService(String url, bindings.Proxy proxy) {
+ assert(!proxy.isBound);
+ var endpoint = _connectToServiceHelper(url, proxy.name);
+ proxy.bind(endpoint);
+ }
+
+ void requestQuit() {}
+
+ listen() => _applicationImpl.listen();
+
+ void _requestQuitAndClose() {
+ requestQuit();
+ close();
+ }
+
+ void close() {
+ assert(_applicationImpl != null);
+ _proxies.forEach((c) => c.close());
+ _proxies.clear();
+ _serviceProviders.forEach((sp) => sp.close());
+ _serviceProviders.clear();
+ _applicationImpl.close();
+ }
+
+ void _acceptConnection(
+ String requestorUrl,
+ service_provider.ServiceProviderStub services,
+ service_provider.ServiceProviderProxy exposedServices) {
+ var serviceProvider = new ServiceProvider(services, exposedServices);
+ _serviceProviders.add(serviceProvider);
+ acceptConnection(requestorUrl, serviceProvider);
+ }
+
+ void acceptConnection(String requestorUrl, ServiceProvider serviceProvider) {}
+
+ core.MojoMessagePipeEndpoint _connectToServiceHelper(
+ String url, String service) {
+ var applicationPipe = new core.MojoMessagePipe();
+ var proxyEndpoint = applicationPipe.endpoints[0];
+ var applicationEndpoint = applicationPipe.endpoints[1];
+ var serviceProviderProxy =
+ new service_provider.ServiceProviderProxy.unbound();
+ _applicationImpl.shell.connectToApplication(
+ url, serviceProviderProxy, null);
+ serviceProviderProxy.connectToService(service, applicationEndpoint);
+ _proxies.add(serviceProviderProxy);
+ return proxyEndpoint;
+ }
+}
diff --git a/third_party/mojo/src/mojo/public/dart/src/codec.dart b/third_party/mojo/src/mojo/public/dart/src/codec.dart
index d5f5b90..7ad8370 100644
--- a/third_party/mojo/src/mojo/public/dart/src/codec.dart
+++ b/third_party/mojo/src/mojo/public/dart/src/codec.dart
@@ -56,7 +56,7 @@ class Encoder {
Encoder._fromBuffer(_EncoderBuffer buffer) :
_buffer = buffer,
- _base = buffer.extent;
+ _base = buffer.extent;
Encoder getEncoderAtOffset(DataHeader dataHeader) {
var result = new Encoder._fromBuffer(_buffer);
@@ -154,7 +154,7 @@ class Encoder {
core.MojoSharedBuffer value, int offset, bool nullable) =>
encodeHandle(value != null ? value.handle : null, offset, nullable);
- void encodeInterface(Interface interface, int offset, bool nullable) {
+ void encodeInterface(Stub interface, int offset, bool nullable) {
if (interface == null) {
encodeInvalideHandle(offset, nullable);
return;
@@ -164,7 +164,7 @@ class Encoder {
encodeMessagePipeHandle(pipe.endpoints[1], offset, nullable);
}
- void encodeInterfaceRequest(Client client, int offset, bool nullable) {
+ void encodeInterfaceRequest(Proxy client, int offset, bool nullable) {
if (client == null) {
encodeInvalideHandle(offset, nullable);
return;
@@ -371,7 +371,7 @@ class Encoder {
value, offset, nullability, expectedLength);
void encodeInterfaceRequestArray(
- List<Client> value,
+ List<Proxy> value,
int offset,
int nullability,
int expectedLength) =>
@@ -380,7 +380,7 @@ class Encoder {
value, offset, nullability, expectedLength);
void encodeInterfaceArray(
- List<Interface> value,
+ List<Stub> value,
int offset,
int nullability,
int expectedLength) =>
@@ -507,13 +507,13 @@ class Decoder {
core.MojoSharedBuffer decodeSharedBufferHandle(int offset, bool nullable) =>
new core.MojoSharedBuffer(decodeHandle(offset, nullable));
- Client decodeServiceInterface(
+ Proxy decodeServiceInterface(
int offset, bool nullable, Function clientFactory) {
var endpoint = decodeMessagePipeHandle(offset, nullable);
return endpoint.handle.isValid ? clientFactory(endpoint) : null;
}
- Interface decodeInterfaceRequest(
+ Stub decodeInterfaceRequest(
int offset, bool nullable, Function interfaceFactory) {
var endpoint = decodeMessagePipeHandle(offset, nullable);
return endpoint.handle.isValid ? interfaceFactory(endpoint) : null;
@@ -699,7 +699,7 @@ class Decoder {
_handleArrayDecodeHelper((d, o, n) => d.decodeSharedBufferHandle(o, n),
offset, nullability, expectedLength);
- List<Interface> decodeInterfaceRequestArray(
+ List<Stub> decodeInterfaceRequestArray(
int offset,
int nullability,
int expectedLength,
@@ -708,7 +708,7 @@ class Decoder {
(d, o, n) => d.decodeInterfaceRequest(o, n, interfaceFactory),
offset, nullability, expectedLength);
- List<Client> decodeServiceInterfaceArray(
+ List<Proxy> decodeServiceInterfaceArray(
int offset,
int nullability,
int expectedLength,
diff --git a/third_party/mojo/src/mojo/public/dart/src/event_stream.dart b/third_party/mojo/src/mojo/public/dart/src/event_stream.dart
index 7016b31..610285a 100644
--- a/third_party/mojo/src/mojo/public/dart/src/event_stream.dart
+++ b/third_party/mojo/src/mojo/public/dart/src/event_stream.dart
@@ -16,7 +16,7 @@ class MojoEventStream extends Stream<int> {
// events.
SendPort _sendPort;
- // The receive port on which we listen and receive events from the handle
+ // The receive port on which we listen and receive events from the handle
// watcher.
ReceivePort _receivePort;
@@ -118,8 +118,11 @@ class MojoEventStream extends Stream<int> {
String toString() => "$_handle";
}
+abstract class Listener {
+ StreamSubscription<List<int>> listen();
+}
-class MojoEventStreamListener {
+class MojoEventStreamListener implements Listener {
MojoMessagePipeEndpoint _endpoint;
MojoEventStream _eventStream;
bool _isOpen = false;
@@ -155,7 +158,7 @@ class MojoEventStreamListener {
_isOpen = false;
}
- StreamSubscription<int> listen() {
+ StreamSubscription<List<int>> listen() {
_isOpen = true;
return _eventStream.listen((List<int> event) {
var signalsWatched = new MojoHandleSignals(event[0]);
diff --git a/third_party/mojo/src/mojo/public/dart/src/client.dart b/third_party/mojo/src/mojo/public/dart/src/proxy.dart
index f8ec73c..f662f3a 100644
--- a/third_party/mojo/src/mojo/public/dart/src/client.dart
+++ b/third_party/mojo/src/mojo/public/dart/src/proxy.dart
@@ -4,19 +4,19 @@
part of bindings;
-abstract class Client extends core.MojoEventStreamListener {
+abstract class Proxy extends core.MojoEventStreamListener {
Map<int, Completer> _completerMap;
int _nextId = 0;
- Client(core.MojoMessagePipeEndpoint endpoint) :
+ Proxy(core.MojoMessagePipeEndpoint endpoint) :
_completerMap = {},
super(endpoint);
- Client.fromHandle(core.MojoHandle handle) :
+ Proxy.fromHandle(core.MojoHandle handle) :
_completerMap = {},
super.fromHandle(handle);
- Client.unbound() :
+ Proxy.unbound() :
_completerMap = {},
super.unbound();
@@ -37,7 +37,7 @@ abstract class Client extends core.MojoEventStreamListener {
}
void handleWrite() {
- throw 'Unexpected write signal in client.';
+ throw 'Unexpected write signal in proxy.';
}
void sendMessage(Struct message, int name) {
diff --git a/third_party/mojo/src/mojo/public/dart/src/service_provider.dart b/third_party/mojo/src/mojo/public/dart/src/service_provider.dart
new file mode 100644
index 0000000..deac6bc
--- /dev/null
+++ b/third_party/mojo/src/mojo/public/dart/src/service_provider.dart
@@ -0,0 +1,39 @@
+// 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.
+
+part of application;
+
+typedef core.Listener ListenerFactory(core.MojoMessagePipeEndpoint endpoint);
+
+class ServiceProvider extends service_provider.ServiceProvider {
+ ListenerFactory factory;
+
+ service_provider.ServiceProviderProxy _proxy;
+
+ ServiceProvider(
+ service_provider.ServiceProviderStub services,
+ [service_provider.ServiceProviderProxy exposedServices = null])
+ : _proxy = exposedServices,
+ super.fromStub(services) {
+ delegate = this;
+ }
+
+ connectToService(String interfaceName, core.MojoMessagePipeEndpoint pipe) =>
+ factory(pipe).listen();
+
+ requestService(String name, bindings.Proxy clientImpl) {
+ assert(_proxy != null);
+ assert(!clientImpl.isBound);
+ var pipe = new core.MojoMessagePipe();
+ clientImpl.bind(pipe.endpoints[0]);
+ _proxy.connectToService(name, pipe.endpoints[1]);
+ }
+
+ close() {
+ if (_proxy != null) {
+ _proxy.close();
+ _proxy = null;
+ }
+ }
+}
diff --git a/third_party/mojo/src/mojo/public/dart/src/interface.dart b/third_party/mojo/src/mojo/public/dart/src/stub.dart
index 0e73214..b4ab293 100644
--- a/third_party/mojo/src/mojo/public/dart/src/interface.dart
+++ b/third_party/mojo/src/mojo/public/dart/src/stub.dart
@@ -4,15 +4,15 @@
part of bindings;
-abstract class Interface extends core.MojoEventStreamListener {
+abstract class Stub extends core.MojoEventStreamListener {
int _outstandingResponseFutures = 0;
bool _isClosing = false;
- Interface(core.MojoMessagePipeEndpoint endpoint) : super(endpoint);
+ Stub(core.MojoMessagePipeEndpoint endpoint) : super(endpoint);
- Interface.fromHandle(core.MojoHandle handle) : super.fromHandle(handle);
+ Stub.fromHandle(core.MojoHandle handle) : super.fromHandle(handle);
- Interface.unbound() : super.unbound();
+ Stub.unbound() : super.unbound();
Future<Message> handleMessage(ServiceMessage message);
@@ -85,19 +85,4 @@ abstract class Interface extends core.MojoEventStreamListener {
var header = new MessageHeader.withRequestId(name, flags, id);
return response.serializeWithHeader(header);
}
-
- void sendMessage(Struct message, int name) {
- var header = new MessageHeader(name);
- var serviceMessage = message.serializeWithHeader(header);
- endpoint.write(serviceMessage.buffer,
- serviceMessage.buffer.lengthInBytes,
- serviceMessage.handles);
- if (!endpoint.status.isOk) {
- throw "message pipe write failed: ${endpoint.status}";
- }
- }
-
- Future sendMessageWithRequestId(Struct response, int name, int id) {
- throw "The client interface should not expect a response";
- }
}
diff --git a/third_party/mojo/src/mojo/public/go/bindings/decoder.go b/third_party/mojo/src/mojo/public/go/bindings/decoder.go
new file mode 100644
index 0000000..2dccd0a
--- /dev/null
+++ b/third_party/mojo/src/mojo/public/go/bindings/decoder.go
@@ -0,0 +1,315 @@
+// 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.
+
+package bindings
+
+import (
+ "encoding/binary"
+ "fmt"
+ "math"
+
+ "mojo/public/go/system"
+)
+
+// Decoder is a helper to decode mojo complex elements from mojo archive format.
+type Decoder struct {
+ // Buffer containing data to decode.
+ buf []byte
+
+ // Index of the first unclaimed byte in buf.
+ end int
+
+ // Array containing handles to decode.
+ handles []system.UntypedHandle
+
+ // The first unclaimed handle index.
+ nextHandle int
+
+ // A stack of encoding states matching current one-level value stack
+ // of the decoding data structure.
+ stateStack []encodingState
+}
+
+// NewDecoder returns a decoder that will decode structured data from provided
+// byte array and with handles.
+func NewDecoder(bytes []byte, handles []system.UntypedHandle) *Decoder {
+ return &Decoder{buf: bytes, handles: handles}
+}
+
+// claimData claims a block of |size| bytes for a one-level value.
+func (d *Decoder) claimData(size int) error {
+ if d.end+size > len(d.buf) {
+ return fmt.Errorf("data buffer is too small")
+ }
+ d.end += size
+ return nil
+}
+
+func (d *Decoder) claimHandle(index int) (system.UntypedHandle, error) {
+ if index >= len(d.handles) {
+ return nil, fmt.Errorf("trying to access non present handle")
+ }
+ if index < d.nextHandle {
+ return nil, fmt.Errorf("trying to access handle out of order")
+ }
+ d.nextHandle = index + 1
+ return d.handles[index], nil
+}
+
+func (d *Decoder) popState() {
+ if len(d.stateStack) != 0 {
+ d.stateStack = d.stateStack[:len(d.stateStack)-1]
+ }
+}
+
+func (d *Decoder) pushState(header DataHeader, elementBitSize uint32) error {
+ oldEnd := d.end
+ if err := d.claimData(int(header.Size - dataHeaderSize)); err != nil {
+ return err
+ }
+ d.stateStack = append(d.stateStack, encodingState{
+ offset: oldEnd,
+ limit: d.end,
+ elementBitSize: elementBitSize,
+ elements: header.Elements,
+ })
+ return nil
+}
+
+// state returns state of the top-level value.
+func (d *Decoder) state() *encodingState {
+ if len(d.stateStack) == 0 {
+ return nil
+ }
+ return &d.stateStack[len(d.stateStack)-1]
+}
+
+// StartArray starts decoding an array and reads its data header,
+// returning number of elements declared in data header.
+// Note: it doesn't read a pointer to the encoded array.
+// Call |Finish()| after reading all array elements.
+func (d *Decoder) StartArray(elementBitSize uint32) (uint32, error) {
+ header, err := d.readDataHeader()
+ if err != nil {
+ return 0, err
+ }
+ if got, want := int(header.Size), dataHeaderSize+bytesForBits(uint64(header.Elements)*uint64(elementBitSize)); got < want {
+ return 0, fmt.Errorf("data header size is too small: is %d, but should be at least %d", got, want)
+ }
+ if err := d.pushState(header, elementBitSize); err != nil {
+ return 0, err
+ }
+ return header.Elements, nil
+}
+
+// StartMap starts decoding a map and reads its data header.
+// Note: it doesn't read a pointer to the encoded map.
+// Call |Finish()| after reading keys array and values array.
+func (d *Decoder) StartMap() error {
+ header, err := d.readDataHeader()
+ if err != nil {
+ return err
+ }
+ if header != mapHeader {
+ return fmt.Errorf("invalid map header: %v", header)
+ }
+ if err := d.pushState(header, pointerBitSize); err != nil {
+ return err
+ }
+ return nil
+}
+
+// StartArray starts decoding a struct and reads its data header,
+// returning number of fields declared in data header.
+// Note: it doesn't read a pointer to the encoded struct.
+// Call |Finish()| after reading all fields.
+func (d *Decoder) StartStruct() (uint32, error) {
+ header, err := d.readDataHeader()
+ if err != nil {
+ return 0, err
+ }
+ if header.Size < dataHeaderSize {
+ return 0, fmt.Errorf("data header size is too small: is %d, but should be at least %d", header.Size, dataHeaderSize)
+ }
+ if err := d.pushState(header, 0); err != nil {
+ return 0, err
+ }
+ return header.Elements, nil
+}
+
+func (d *Decoder) readDataHeader() (DataHeader, error) {
+ if err := d.claimData(dataHeaderSize); err != nil {
+ return DataHeader{}, err
+ }
+ oldEnd := d.end - dataHeaderSize
+ header := DataHeader{
+ Size: binary.LittleEndian.Uint32(d.buf[oldEnd:]),
+ Elements: binary.LittleEndian.Uint32(d.buf[oldEnd+4:]),
+ }
+ return header, nil
+}
+
+// Finish indicates the decoder that you have finished reading elements of
+// a one-level value.
+func (d *Decoder) Finish() error {
+ if d.state() == nil {
+ return fmt.Errorf("state stack is empty")
+ }
+ if d.state().elementBitSize != 0 && d.state().elementsProcessed != d.state().elements {
+ return fmt.Errorf("unexpected number of elements read: defined in header %d, but read %d", d.state().elements, d.state().elementsProcessed)
+ }
+ d.popState()
+ return nil
+}
+
+// ReadBool reads a bool value.
+func (d *Decoder) ReadBool() (bool, error) {
+ if err := ensureElementBitSizeAndCapacity(d.state(), 1); err != nil {
+ return false, err
+ }
+ value := ((d.buf[d.state().offset] >> d.state().bitOffset) & 1) == 1
+ d.state().skipBits(1)
+ d.state().elementsProcessed++
+ return value, nil
+}
+
+// ReadInt8 reads an int8 value.
+func (d *Decoder) ReadInt8() (int8, error) {
+ value, err := d.ReadUint8()
+ return int8(value), err
+}
+
+// ReadUint8 reads an uint8 value.
+func (d *Decoder) ReadUint8() (uint8, error) {
+ if err := ensureElementBitSizeAndCapacity(d.state(), 8); err != nil {
+ return 0, err
+ }
+ value := d.buf[d.state().offset]
+ d.state().skipBytes(1)
+ d.state().elementsProcessed++
+ return value, nil
+}
+
+// ReadInt16 reads an int16 value.
+func (d *Decoder) ReadInt16() (int16, error) {
+ value, err := d.ReadUint16()
+ return int16(value), err
+}
+
+// ReadUint16 reads an uint16 value.
+func (d *Decoder) ReadUint16() (uint16, error) {
+ if err := ensureElementBitSizeAndCapacity(d.state(), 16); err != nil {
+ return 0, err
+ }
+ d.state().offset = align(d.state().offset, 2)
+ value := binary.LittleEndian.Uint16(d.buf[d.state().offset:])
+ d.state().skipBytes(2)
+ d.state().elementsProcessed++
+ return value, nil
+}
+
+// ReadInt32 reads an int32 value.
+func (d *Decoder) ReadInt32() (int32, error) {
+ value, err := d.ReadUint32()
+ return int32(value), err
+}
+
+// ReadUint32 reads an uint32 value.
+func (d *Decoder) ReadUint32() (uint32, error) {
+ if err := ensureElementBitSizeAndCapacity(d.state(), 32); err != nil {
+ return 0, err
+ }
+ d.state().offset = align(d.state().offset, 4)
+ value := binary.LittleEndian.Uint32(d.buf[d.state().offset:])
+ d.state().skipBytes(4)
+ d.state().elementsProcessed++
+ return value, nil
+}
+
+// ReadInt64 reads an int64 value.
+func (d *Decoder) ReadInt64() (int64, error) {
+ value, err := d.ReadUint64()
+ return int64(value), err
+}
+
+// ReadUint64 reads an uint64 value.
+func (d *Decoder) ReadUint64() (uint64, error) {
+ if err := ensureElementBitSizeAndCapacity(d.state(), 64); err != nil {
+ return 0, err
+ }
+ d.state().offset = align(d.state().offset, 8)
+ value := binary.LittleEndian.Uint64(d.buf[d.state().offset:])
+ d.state().skipBytes(8)
+ d.state().elementsProcessed++
+ return value, nil
+}
+
+// ReadFloat32 reads a float32 value.
+func (d *Decoder) ReadFloat32() (float32, error) {
+ bits, err := d.ReadUint32()
+ return math.Float32frombits(bits), err
+}
+
+// ReadFloat64 reads a float64 value.
+func (d *Decoder) ReadFloat64() (float64, error) {
+ bits, err := d.ReadUint64()
+ return math.Float64frombits(bits), err
+}
+
+// ReadString reads a string value. It doesn't read a pointer to the encoded
+// string.
+func (d *Decoder) ReadString() (string, error) {
+ length, err := d.StartArray(8)
+ if err != nil {
+ return "", err
+ }
+ var bytes []byte
+ for i := uint32(0); i < length; i++ {
+ b, err := d.ReadUint8()
+ if err != nil {
+ return "", err
+ }
+ bytes = append(bytes, b)
+ }
+ if err := d.Finish(); err != nil {
+ return "", err
+ }
+ return string(bytes), nil
+}
+
+// ReadPointer reads a pointer and reassigns first unclaimed byte index if the
+// pointer is not null.
+func (d *Decoder) ReadPointer() (uint64, error) {
+ oldEnd := d.state().offset
+ pointer, err := d.ReadUint64()
+ if err != nil {
+ return pointer, err
+ }
+ if pointer == 0 {
+ return pointer, nil
+ }
+
+ newEnd := uint64(oldEnd) + pointer
+ if newEnd >= uint64(len(d.buf)) {
+ return 0, fmt.Errorf("trying to access out of range memory")
+ }
+ if newEnd < uint64(d.end) {
+ return 0, fmt.Errorf("trying to access memory out of order")
+ }
+ if newEnd%8 != 0 {
+ return 0, fmt.Errorf("incorrect pointer data alignment: %d", newEnd)
+ }
+ d.claimData(d.end - int(newEnd))
+ return pointer, nil
+}
+
+// ReadMessagePipeHandle reads a message pipe handle.
+func (d *Decoder) ReadMessagePipeHandle() (system.MessagePipeHandle, error) {
+ handleIndex, err := d.ReadUint32()
+ if err != nil {
+ return nil, err
+ }
+ untypedHandle, err := d.claimHandle(int(handleIndex))
+ return untypedHandle.ToMessagePipeHandle(), err
+}
diff --git a/third_party/mojo/src/mojo/public/go/bindings/encoder.go b/third_party/mojo/src/mojo/public/go/bindings/encoder.go
new file mode 100644
index 0000000..210d9b0
--- /dev/null
+++ b/third_party/mojo/src/mojo/public/go/bindings/encoder.go
@@ -0,0 +1,319 @@
+// 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.
+
+package bindings
+
+import (
+ "encoding/binary"
+ "fmt"
+ "math"
+
+ "mojo/public/go/system"
+)
+
+// encodingState has information required to encode/decode a one-level value.
+type encodingState struct {
+ // Index of the first unprocessed byte.
+ offset int
+
+ // Index of the first unprocessed bit of buffer[offset] byte.
+ bitOffset uint32
+
+ // Index of the first byte after the claimed buffer block for the current
+ // one-level value.
+ limit int
+
+ // Element size in bits of the current one-level array, 0 for other types.
+ elementBitSize uint32
+
+ // Number of elements declared in the data header for the current one-level
+ // value.
+ elements uint32
+
+ // Number of elements already encoded/decoded of the current one-level
+ // value.
+ elementsProcessed uint32
+}
+
+func (s *encodingState) skipBits(count uint32) {
+ s.bitOffset += count
+ s.offset += int(s.bitOffset >> 3) // equal to s.bitOffset / 8
+ s.bitOffset &= 7 // equal to s.bitOffset % 8
+}
+
+func (s *encodingState) skipBytes(count int) {
+ s.bitOffset = 0
+ s.offset += count
+}
+
+// Encoder is a helper to encode mojo complex elements into mojo archive format.
+type Encoder struct {
+ // Buffer containing encoded data.
+ buf []byte
+
+ // Index of the first unclaimed byte in buf.
+ end int
+
+ // Array containing encoded handles.
+ handles []system.UntypedHandle
+
+ // A stack of encoder states matching current one-level value stack
+ // of the encoding data structure.
+ stateStack []encodingState
+}
+
+func align(size, alignment int) int {
+ return ((size - 1) | (alignment - 1)) + 1
+}
+
+// bytesForBits returns minimum number of bytes required to store provided
+// number of bits.
+func bytesForBits(bits uint64) int {
+ return int((bits + 7) / 8)
+}
+
+func ensureElementBitSizeAndCapacity(state *encodingState, bitSize uint32) error {
+ if state == nil {
+ return fmt.Errorf("empty state stack")
+ }
+ if state.elementBitSize > 0 && state.elementBitSize != bitSize {
+ return fmt.Errorf("unexpected element bit size: expected %d, but got %d", state.elementBitSize, bitSize)
+ }
+ if state.elementsProcessed >= state.elements {
+ return fmt.Errorf("can't process more than elements defined in header(%d)", state.elements)
+ }
+ byteSize := bytesForBits(uint64(state.bitOffset + bitSize))
+ if align(state.offset+byteSize, byteSize) > state.limit {
+ return fmt.Errorf("buffer size limit exceeded")
+ }
+ return nil
+}
+
+// claimData claims a block of |size| bytes for a one-level value, resizing
+// buffer if needed.
+func (e *Encoder) claimData(size int) {
+ e.end += size
+ if e.end < len(e.buf) {
+ return
+ }
+ newLen := e.end
+ if l := 2 * len(e.buf); newLen < l {
+ newLen = l
+ }
+ tmp := make([]byte, newLen)
+ copy(tmp, e.buf)
+ e.buf = tmp
+}
+
+func (e *Encoder) popState() {
+ if len(e.stateStack) != 0 {
+ e.stateStack = e.stateStack[:len(e.stateStack)-1]
+ }
+}
+
+func (e *Encoder) pushState(header DataHeader, elementBitSize uint32) {
+ oldEnd := e.end
+ e.claimData(align(int(header.Size), defaultAlignment))
+ e.stateStack = append(e.stateStack, encodingState{
+ offset: oldEnd,
+ limit: e.end,
+ elementBitSize: elementBitSize,
+ elements: header.Elements,
+ })
+ e.writeDataHeader(header)
+}
+
+// state returns encoder state of the top-level value.
+func (e *Encoder) state() *encodingState {
+ if len(e.stateStack) == 0 {
+ return nil
+ }
+ return &e.stateStack[len(e.stateStack)-1]
+}
+
+// NewEncoder returns a new instance of encoder.
+func NewEncoder() *Encoder {
+ return &Encoder{}
+}
+
+// StartArray starts encoding an array and writes its data header.
+// Note: it doesn't write a pointer to the encoded array.
+// Call |Finish()| after writing all array elements.
+func (e *Encoder) StartArray(length, elementBitSize uint32) {
+ dataSize := dataHeaderSize + bytesForBits(uint64(length)*uint64(elementBitSize))
+ header := DataHeader{uint32(dataSize), length}
+ e.pushState(header, elementBitSize)
+}
+
+// StartMap starts encoding a map and writes its data header.
+// Note: it doesn't write a pointer to the encoded map.
+// Call |Finish()| after writing keys array and values array.
+func (e *Encoder) StartMap() {
+ e.pushState(mapHeader, pointerBitSize)
+}
+
+// StartStruct starts encoding a struct and writes its data header.
+// Note: it doesn't write a pointer to the encoded struct.
+// Call |Finish()| after writing all fields.
+func (e *Encoder) StartStruct(size, numFields uint32) {
+ dataSize := dataHeaderSize + int(size)
+ header := DataHeader{uint32(dataSize), numFields}
+ e.pushState(header, 0)
+}
+
+func (e *Encoder) writeDataHeader(header DataHeader) {
+ binary.LittleEndian.PutUint32(e.buf[e.state().offset:], header.Size)
+ binary.LittleEndian.PutUint32(e.buf[e.state().offset+4:], header.Elements)
+ e.state().offset += 8
+}
+
+// Finish indicates the encoder that you have finished writing elements of
+// a one-level value.
+func (e *Encoder) Finish() error {
+ if e.state() == nil {
+ return fmt.Errorf("state stack is empty")
+ }
+ if e.state().elementsProcessed != e.state().elements {
+ return fmt.Errorf("unexpected number of elements written: defined in header %d, but written %d", e.state().elements, e.state().elementsProcessed)
+ }
+ e.popState()
+ return nil
+}
+
+// Data returns an encoded message with attached handles.
+// Call this method after finishing encoding of a value.
+func (e *Encoder) Data() ([]byte, []system.UntypedHandle, error) {
+ if len(e.stateStack) != 0 {
+ return nil, nil, fmt.Errorf("can't return data when encoder has non-empty state stack")
+ }
+ return e.buf[:e.end], e.handles, nil
+}
+
+// WriteBool writes a bool value.
+func (e *Encoder) WriteBool(value bool) error {
+ if err := ensureElementBitSizeAndCapacity(e.state(), 1); err != nil {
+ return err
+ }
+ if value {
+ e.buf[e.state().offset] |= 1 << e.state().bitOffset
+ }
+ e.state().skipBits(1)
+ e.state().elementsProcessed++
+ return nil
+}
+
+// WriteBool writes an int8 value.
+func (e *Encoder) WriteInt8(value int8) error {
+ return e.WriteUint8(uint8(value))
+}
+
+// WriteUint8 writes an uint8 value.
+func (e *Encoder) WriteUint8(value uint8) error {
+ if err := ensureElementBitSizeAndCapacity(e.state(), 8); err != nil {
+ return err
+ }
+ e.buf[e.state().offset] = value
+ e.state().skipBytes(1)
+ e.state().elementsProcessed++
+ return nil
+}
+
+// WriteInt16 writes an int16 value.
+func (e *Encoder) WriteInt16(value int16) error {
+ return e.WriteUint16(uint16(value))
+}
+
+// WriteUint16 writes an uint16 value.
+func (e *Encoder) WriteUint16(value uint16) error {
+ if err := ensureElementBitSizeAndCapacity(e.state(), 16); err != nil {
+ return err
+ }
+ e.state().offset = align(e.state().offset, 2)
+ binary.LittleEndian.PutUint16(e.buf[e.state().offset:], value)
+ e.state().skipBytes(2)
+ e.state().elementsProcessed++
+ return nil
+}
+
+// WriteInt32 writes an int32 value.
+func (e *Encoder) WriteInt32(value int32) error {
+ return e.WriteUint32(uint32(value))
+}
+
+// WriteUint32 writes an uint32 value.
+func (e *Encoder) WriteUint32(value uint32) error {
+ if err := ensureElementBitSizeAndCapacity(e.state(), 32); err != nil {
+ return err
+ }
+ e.state().offset = align(e.state().offset, 4)
+ binary.LittleEndian.PutUint32(e.buf[e.state().offset:], value)
+ e.state().skipBytes(4)
+ e.state().elementsProcessed++
+ return nil
+}
+
+// WriteInt64 writes an int64 value.
+func (e *Encoder) WriteInt64(value int64) error {
+ return e.WriteUint64(uint64(value))
+}
+
+// WriteUint64 writes an uint64 value.
+func (e *Encoder) WriteUint64(value uint64) error {
+ if err := ensureElementBitSizeAndCapacity(e.state(), 64); err != nil {
+ return err
+ }
+ e.state().offset = align(e.state().offset, 8)
+ binary.LittleEndian.PutUint64(e.buf[e.state().offset:], value)
+ e.state().skipBytes(8)
+ e.state().elementsProcessed++
+ return nil
+}
+
+// WriteFloat32 writes a float32 value.
+func (e *Encoder) WriteFloat32(value float32) error {
+ return e.WriteUint32(math.Float32bits(value))
+}
+
+// WriteFloat64 writes a float64 value.
+func (e *Encoder) WriteFloat64(value float64) error {
+ return e.WriteUint64(math.Float64bits(value))
+}
+
+// WriteNullPointer writes a null pointer.
+func (e *Encoder) WriteNullPointer() error {
+ return e.WriteUint64(0)
+}
+
+// WriteString writes a string value. It doesn't write a pointer to the encoded
+// string.
+func (e *Encoder) WriteString(value string) error {
+ bytes := []byte(value)
+ e.StartArray(uint32(len(bytes)), 8)
+ for _, b := range bytes {
+ if err := e.WriteUint8(b); err != nil {
+ return err
+ }
+ }
+ return e.Finish()
+}
+
+// WritePointer writes a pointer to first unclaimed byte index.
+func (e *Encoder) WritePointer() error {
+ return e.WriteUint64(uint64(e.end - e.state().offset))
+}
+
+// WriteInvalidHandle an invalid handle.
+func (e *Encoder) WriteInvalidHandle() error {
+ return e.WriteInt32(-1)
+}
+
+// WriteHandle writes a handle and invalidates the passed handle object.
+func (e *Encoder) WriteHandle(handle system.Handle) error {
+ if !handle.IsValid() {
+ return fmt.Errorf("can't write an invalid handle")
+ }
+ UntypedHandle := handle.ToUntypedHandle()
+ e.handles = append(e.handles, UntypedHandle)
+ return e.WriteUint32(uint32(len(e.handles) - 1))
+}
diff --git a/third_party/mojo/src/mojo/public/go/bindings/message.go b/third_party/mojo/src/mojo/public/go/bindings/message.go
new file mode 100644
index 0000000..786ec47
--- /dev/null
+++ b/third_party/mojo/src/mojo/public/go/bindings/message.go
@@ -0,0 +1,164 @@
+// 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.
+
+package bindings
+
+import (
+ "fmt"
+
+ "mojo/public/go/system"
+)
+
+const (
+ // Flag for a header of a simple message.
+ MessageNoFlag = 0
+
+ // Flag for a header of a message that expected a response.
+ MessageExpectsResponseFlag = 1 << 0
+
+ // Flag for a header of a message that is a response.
+ MessageIsResponseFlag = 1 << 1
+
+ dataHeaderSize = 8
+ defaultAlignment = 8
+ pointerBitSize = 64
+)
+
+var mapHeader DataHeader
+
+func init() {
+ mapHeader = DataHeader{24, 2}
+}
+
+// Payload is an interface implemented by a mojo struct that can encode/decode
+// itself into mojo archive format.
+type Payload interface {
+ Encode(encoder *Encoder) error
+ Decode(decoder *Decoder) error
+}
+
+// DataHeader is a header for a mojo complex element.
+type DataHeader struct {
+ Size uint32
+ Elements uint32
+}
+
+// MessageHeader is a header information for a message.
+type MessageHeader struct {
+ Type uint32
+ Flags uint32
+ RequestId uint64
+}
+
+func (h *MessageHeader) Encode(encoder *Encoder) error {
+ encoder.StartStruct(h.dataSize(), h.numFields())
+ if err := encoder.WriteUint32(h.Type); err != nil {
+ return err
+ }
+ if err := encoder.WriteUint32(h.Flags); err != nil {
+ return err
+ }
+ if h.RequestId != 0 {
+ if err := encoder.WriteUint64(h.RequestId); err != nil {
+ return err
+ }
+ }
+ return encoder.Finish()
+}
+
+func (h *MessageHeader) Decode(decoder *Decoder) error {
+ numFields, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ if numFields < 2 || numFields > 3 {
+ return fmt.Errorf("Invalid message header: it should have 2 or 3 fileds, but has %d", numFields)
+ }
+ if h.Type, err = decoder.ReadUint32(); err != nil {
+ return err
+ }
+ if h.Flags, err = decoder.ReadUint32(); err != nil {
+ return err
+ }
+ if numFields == 3 {
+ if h.Flags != MessageExpectsResponseFlag && h.Flags != MessageIsResponseFlag {
+ return fmt.Errorf("Message header flags(%v) should be MessageExpectsResponseFlag or MessageIsResponseFlag", h.Flags)
+ }
+ if h.RequestId, err = decoder.ReadUint64(); err != nil {
+ return err
+ }
+ } else {
+ if h.Flags != MessageNoFlag {
+ return fmt.Errorf("Message header flags(%v) should be MessageNoFlag", h.Flags)
+ }
+ }
+ return decoder.Finish()
+}
+
+func (h *MessageHeader) dataSize() uint32 {
+ var size uint32
+ size = 2 * 4
+ if h.RequestId != 0 {
+ size += 8
+ }
+ return size
+}
+
+func (h *MessageHeader) numFields() uint32 {
+ if h.RequestId != 0 {
+ return 3
+ } else {
+ return 2
+ }
+}
+
+// Message is a a raw message to be sent/received from a message pipe handle
+// which contains a message header.
+type Message struct {
+ Header MessageHeader
+ Bytes []byte
+ Handles []system.UntypedHandle
+ Payload []byte
+}
+
+func newMessage(header MessageHeader, bytes []byte, handles []system.UntypedHandle) *Message {
+ return &Message{header, bytes, handles, bytes[header.dataSize()+dataHeaderSize:]}
+}
+
+// DecodePayload decodes the provided payload from the message.
+func (m *Message) DecodePayload(payload Payload) error {
+ decoder := NewDecoder(m.Payload, m.Handles)
+ if err := payload.Decode(decoder); err != nil {
+ return err
+ }
+ return nil
+}
+
+// EncodeMessage returns a message with provided header that has provided
+// payload encoded in mojo archive format.
+func EncodeMessage(header MessageHeader, payload Payload) (*Message, error) {
+ encoder := NewEncoder()
+ if err := header.Encode(encoder); err != nil {
+ return nil, err
+ }
+ if err := payload.Encode(encoder); err != nil {
+ return nil, err
+ }
+ if bytes, handles, err := encoder.Data(); err != nil {
+ return nil, err
+ } else {
+ return newMessage(header, bytes, handles), nil
+ }
+}
+
+// ParseMessage parses message header from byte buffer with attached handles
+// and returnes parsed message.
+func ParseMessage(bytes []byte, handles []system.UntypedHandle) (*Message, error) {
+ decoder := NewDecoder(bytes, []system.UntypedHandle{})
+ var header MessageHeader
+ if err := header.Decode(decoder); err != nil {
+ return nil, err
+ }
+ return newMessage(header, bytes, handles), nil
+}
diff --git a/third_party/mojo/src/mojo/public/interfaces/application/application.mojom b/third_party/mojo/src/mojo/public/interfaces/application/application.mojom
index b1508a8e..cffcb1f 100644
--- a/third_party/mojo/src/mojo/public/interfaces/application/application.mojom
+++ b/third_party/mojo/src/mojo/public/interfaces/application/application.mojom
@@ -5,6 +5,7 @@
module mojo;
import "mojo/public/interfaces/application/service_provider.mojom";
+import "mojo/public/interfaces/application/shell.mojom";
// This is the primary interface implemented by every Mojo application. It
// allows the application to receive its startup arguments from the shell, and
@@ -13,7 +14,7 @@ interface Application {
// Initializes the application with the specified arguments. This method is
// guaranteed to be called before any other method is called, and will only be
// called once.
- Initialize(array<string>? args);
+ Initialize(Shell shell, array<string>? args);
// Called when another application (identified by |requestor_url|) attempts to
// open a connection to this application.
diff --git a/third_party/mojo/src/mojo/public/interfaces/application/shell.mojom b/third_party/mojo/src/mojo/public/interfaces/application/shell.mojom
index 7804b9f..6fc0cca 100644
--- a/third_party/mojo/src/mojo/public/interfaces/application/shell.mojom
+++ b/third_party/mojo/src/mojo/public/interfaces/application/shell.mojom
@@ -4,12 +4,10 @@
module mojo;
-import "mojo/public/interfaces/application/application.mojom";
import "mojo/public/interfaces/application/service_provider.mojom";
// An interface through which a Mojo application may communicate with the Mojo
// system and request connections to other applications.
-[Client=Application]
interface Shell {
// Establishes a connection with another application (identified by
// |application_url|) through which the calling application and the other
diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/math_calculator.mojom b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/math_calculator.mojom
index f99bb07..7d1b171 100644
--- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/math_calculator.mojom
+++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/math_calculator.mojom
@@ -5,13 +5,8 @@
[JavaPackage="org.chromium.mojo.bindings.test.mojom.math"]
module math;
-[Client=CalculatorUI]
interface Calculator {
- Clear@0();
- Add@1(double value@0);
- Multiply@2(double value@0);
-};
-
-interface CalculatorUI {
- Output@0(double value@0);
+ Clear@0() => (double value@0);
+ Add@1(double value@0) => (double value@0);
+ Multiply@2(double value@0) => (double value@0);
};
diff --git a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ConnectionErrorHandler.java b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ConnectionErrorHandler.java
index abb0bdf..f601fb8 100644
--- a/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ConnectionErrorHandler.java
+++ b/third_party/mojo/src/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ConnectionErrorHandler.java
@@ -10,6 +10,6 @@ import org.chromium.mojo.system.MojoException;
* A {@link ConnectionErrorHandler} is notified of an error happening while using the bindings over
* message pipes.
*/
-interface ConnectionErrorHandler {
+public interface ConnectionErrorHandler {
public void onConnectionError(MojoException e);
}
diff --git a/third_party/mojo/src/mojo/public/js/bindings.js b/third_party/mojo/src/mojo/public/js/bindings.js
index 5f85860..44aa9f4 100644
--- a/third_party/mojo/src/mojo/public/js/bindings.js
+++ b/third_party/mojo/src/mojo/public/js/bindings.js
@@ -4,7 +4,8 @@
define("mojo/public/js/bindings", [
"mojo/public/js/router",
-], function(router) {
+ "mojo/public/js/core",
+], function(router, core) {
var Router = router.Router;
@@ -17,10 +18,12 @@ define("mojo/public/js/bindings", [
this.receiver = receiver;
}
+ // 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;
@@ -28,12 +31,31 @@ define("mojo/public/js/bindings", [
throw new Error("no stub object");
}
+ function connectionHandle(connection) {
+ return connection &&
+ connection.router &&
+ connection.router.connector_ &&
+ connection.router.connector_.handle_;
+ }
+
+ ProxyProperties.prototype.close = function() {
+ var handle = connectionHandle(this.connection);
+ if (handle)
+ core.close(handle);
+ }
+
// Public stub class properties that are managed at runtime by the JS
// bindings. See StubBindings below.
function StubProperties(delegate) {
this.delegate = delegate;
}
+ StubProperties.prototype.close = function() {
+ var handle = connectionHandle(this.connection);
+ if (handle)
+ core.close(handle);
+ }
+
// The base class for generated proxy classes.
function ProxyBase(receiver) {
this[kProxyProperties] = new ProxyProperties(receiver);
@@ -48,6 +70,9 @@ define("mojo/public/js/bindings", [
this[kStubProperties] = new StubProperties(delegate);
}
+ // TODO(hansmuller): remove everything except the connection property doc
+ // after 'Client=' has been removed from Mojom.
+
// 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.
@@ -71,6 +96,9 @@ define("mojo/public/js/bindings", [
return (proxy instanceof ProxyBase) ? proxy[kProxyProperties] : proxy;
}
+ // TODO(hansmuller): remove the remote doc after 'Client=' has been
+ // removed from Mojom.
+
// 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.
diff --git a/third_party/mojo/src/mojo/public/js/connection.js b/third_party/mojo/src/mojo/public/js/connection.js
index 3976efd..223e711 100644
--- a/third_party/mojo/src/mojo/public/js/connection.js
+++ b/third_party/mojo/src/mojo/public/js/connection.js
@@ -73,6 +73,7 @@ define("mojo/public/js/connection", [
TestConnection.prototype = Object.create(Connection.prototype);
+ // TODO(hansmuller): remove when Shell.mojom loses its client.
function createOpenConnection(
messagePipeHandle, client, localInterface, remoteInterface) {
var stubClass = (localInterface && localInterface.stubClass) || EmptyStub;
@@ -95,6 +96,7 @@ define("mojo/public/js/connection", [
return connection;
}
+ // TODO(hansmuller): remove when Shell.mojom loses its client.
// Return a message pipe handle.
function bindProxyClient(clientImpl, localInterface, remoteInterface) {
var messagePipe = core.createMessagePipe();
@@ -106,6 +108,7 @@ define("mojo/public/js/connection", [
return messagePipe.handle1;
}
+ // TODO(hansmuller): remove when Shell.mojom loses its client.
// Return a proxy.
function bindProxyHandle(proxyHandle, localInterface, remoteInterface) {
if (!core.isHandle(proxyHandle))
@@ -116,10 +119,84 @@ define("mojo/public/js/connection", [
return connection.remote;
}
+ // 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. The stub delegates to impl. Used by generated code for
+ // outgoing interface parameters: the caller specifies impl, and the generated
+ // code sends the handle returned by this function.
+ function bindImpl(impl, 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 (impl)
+ StubBindings(stub).delegate = impl;
+
+ 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;
+ }
+
var exports = {};
exports.Connection = Connection;
exports.TestConnection = TestConnection;
+
+ // TODO(hansmuller): remove these when Shell.mojom loses its client.
exports.bindProxyHandle = bindProxyHandle;
exports.bindProxyClient = bindProxyClient;
+
+ exports.bindProxy = bindProxy;
+ exports.bindImpl = bindImpl;
+ exports.bindHandleToProxy = bindHandleToProxy;
+ exports.bindHandleToStub = bindHandleToStub;
return exports;
});
diff --git a/third_party/mojo/src/mojo/public/mojo_sdk.gni b/third_party/mojo/src/mojo/public/mojo_sdk.gni
index 6ac3e94..8ab7c7d 100644
--- a/third_party/mojo/src/mojo/public/mojo_sdk.gni
+++ b/third_party/mojo/src/mojo/public/mojo_sdk.gni
@@ -70,6 +70,10 @@ template("mojo_sdk_source_set") {
defines = invoker.defines
}
+ if (defined(invoker.libs)) {
+ libs = invoker.libs
+ }
+
public_configs =
[ rebase_path("mojo/public/build/config:mojo_sdk", ".", mojo_root) ]
if (defined(invoker.public_configs)) {
diff --git a/third_party/mojo/src/mojo/public/platform/nacl/mojo_initial_handle.h b/third_party/mojo/src/mojo/public/platform/nacl/mojo_initial_handle.h
new file mode 100644
index 0000000..2d7bc4f
--- /dev/null
+++ b/third_party/mojo/src/mojo/public/platform/nacl/mojo_initial_handle.h
@@ -0,0 +1,14 @@
+// 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_PLATFORM_NACL_MOJO_INTIIAL_HANDLE_H_
+#define MOJO_PUBLIC_PLATFORM_NACL_MOJO_INTIIAL_HANDLE_H_
+
+#include "mojo/public/c/system/types.h"
+
+// Provides a MojoHandle that allows untrusted code to communicate with Mojo
+// interfaces outside the sandbox or in other processes.
+MojoResult _MojoGetInitialHandle(MojoHandle* out_handle);
+
+#endif // MOJO_PUBLIC_PLATFORM_NACL_MOJO_INTIIAL_HANDLE_H_
diff --git a/third_party/mojo/src/mojo/public/sky/convert_amd_modules_to_sky.py b/third_party/mojo/src/mojo/public/sky/convert_amd_modules_to_sky.py
index ddff565..906bc05 100755
--- a/third_party/mojo/src/mojo/public/sky/convert_amd_modules_to_sky.py
+++ b/third_party/mojo/src/mojo/public/sky/convert_amd_modules_to_sky.py
@@ -7,7 +7,7 @@ import argparse
import sys
import re
-IMPORT_TEMPLATE = '<import src="/%s.sky" as="%s" />'
+IMPORT_TEMPLATE = '<import src="/gen/%s.sky" as="%s" />'
PREAMBLE_TEMPLATE = '<script>'
POSTAMBLE_TEMPLATE = ' module.exports = exports;\n</script>'
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl
index 30d20d8..25c01bb 100644
--- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl
+++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl
@@ -14,19 +14,19 @@ class {{interface.name}} {
public:
static const char* Name_;
- typedef {{interface.name}}Proxy Proxy_;
- typedef {{interface.name}}Stub Stub_;
+ using Proxy_ = {{interface.name}}Proxy;
+ using Stub_ = {{interface.name}}Stub;
- typedef {{interface.name}}RequestValidator RequestValidator_;
+ using RequestValidator_ = {{interface.name}}RequestValidator;
{%- if interface|has_callbacks %}
- typedef {{interface.name}}ResponseValidator ResponseValidator_;
+ using ResponseValidator_ = {{interface.name}}ResponseValidator;
{%- else %}
- typedef mojo::PassThroughFilter ResponseValidator_;
+ using ResponseValidator_ = mojo::PassThroughFilter;
{%- endif %}
{% if interface.client %}
- typedef {{interface.client}} Client;
+ using Client = {{interface.client}};
{% else %}
- typedef mojo::NoInterface Client;
+ using Client = mojo::NoInterface;
{% endif %}
{#--- Constants #}
@@ -44,6 +44,9 @@ class {{interface.name}} {
virtual ~{{interface.name}}() {}
{%- for method in interface.methods %}
+{% if method.response_parameters != None %}
+ using {{method.name}}Callback = {{interface_macros.declare_callback(method)}};
+{%- endif %}
virtual void {{method.name}}({{interface_macros.declare_request_params("", method)}}) = 0;
{%- endfor %}
};
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
index fdbe8ca..2b45808 100644
--- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
+++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
@@ -104,12 +104,12 @@ class {{class_name}}_{{method.name}}_ForwardToCallback
: public mojo::MessageReceiver {
public:
{{class_name}}_{{method.name}}_ForwardToCallback(
- const {{interface_macros.declare_callback(method)}}& callback)
+ const {{class_name}}::{{method.name}}Callback& callback)
: callback_(callback) {
}
virtual bool Accept(mojo::Message* message) override;
private:
- {{interface_macros.declare_callback(method)}} callback_;
+ {{class_name}}::{{method.name}}Callback callback_;
MOJO_DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ForwardToCallback);
};
bool {{class_name}}_{{method.name}}_ForwardToCallback::Accept(
@@ -175,7 +175,7 @@ void {{proxy_name}}::{{method.name}}(
{%- set params_description =
"%s.%s response"|format(interface.name, method.name) %}
class {{class_name}}_{{method.name}}_ProxyToResponder
- : public {{interface_macros.declare_callback(method)}}::Runnable {
+ : public {{class_name}}::{{method.name}}Callback::Runnable {
public:
virtual ~{{class_name}}_{{method.name}}_ProxyToResponder() {
delete responder_;
@@ -257,10 +257,10 @@ bool {{class_name}}Stub::AcceptWithResponder(
message->mutable_payload());
params->DecodePointersAndHandles(message->mutable_handles());
- {{interface_macros.declare_callback(method)}}::Runnable* runnable =
+ {{class_name}}::{{method.name}}Callback::Runnable* runnable =
new {{class_name}}_{{method.name}}_ProxyToResponder(
message->request_id(), responder);
- {{interface_macros.declare_callback(method)}} callback(runnable);
+ {{class_name}}::{{method.name}}Callback callback(runnable);
{{alloc_params(method.parameters)|indent(6)}}
// A null |sink_| typically means there is a missing call to
// InterfacePtr::set_client().
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
index fbefce2..7644b2e 100644
--- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
+++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
@@ -17,7 +17,7 @@ mojo::Callback<void(
{%- macro declare_request_params(prefix, method) -%}
{{declare_params(prefix, method.parameters)}}
{%- if method.response_parameters != None -%}
-{%- if method.parameters %}, {% endif %}
-const {{declare_callback(method)}}& callback
+{%- if method.parameters %}, {% endif -%}
+const {{method.name}}Callback& callback
{%- endif -%}
{%- endmacro -%}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
index 3da6c32..25449b7 100644
--- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
+++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
@@ -40,16 +40,16 @@ extern const {{constant.kind|cpp_pod_type}} {{constant.name}};
{#--- Interface Forward Declarations -#}
{% for interface in interfaces %}
class {{interface.name}};
-typedef mojo::InterfacePtr<{{interface.name}}> {{interface.name}}Ptr;
+using {{interface.name}}Ptr = mojo::InterfacePtr<{{interface.name}}>;
{% endfor %}
{#--- Struct Forward Declarations -#}
{% for struct in structs %}
class {{struct.name}};
{% if struct|should_inline %}
-typedef mojo::InlinedStructPtr<{{struct.name}}> {{struct.name}}Ptr;
+using {{struct.name}}Ptr = mojo::InlinedStructPtr<{{struct.name}}>;
{% else %}
-typedef mojo::StructPtr<{{struct.name}}> {{struct.name}}Ptr;
+using {{struct.name}}Ptr = mojo::StructPtr<{{struct.name}}>;
{% endif %}
{% endfor %}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
index 25b39b3..ebcba7b 100644
--- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
+++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
@@ -1,7 +1,7 @@
class {{struct.name}} {
public:
- typedef internal::{{struct.name}}_Data Data_;
+ using Data_ = internal::{{struct.name}}_Data;
{#--- Constants #}
{%- for constant in struct.constants %}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl
index 91ea7cf..0420c8d 100644
--- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl
+++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl
@@ -1,7 +1,7 @@
class {{union.name}} {
public:
- typedef internal::{{union.name}}_Data Data_;
- typedef Data_::{{union.name}}_Tag Tag;
+ using Data_ = internal::{{union.name}}_Data;
+ using Tag = Data_::{{union.name}}_Tag;
static {{union.name}}Ptr New();
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl
index 0289345..952c0dc 100644
--- a/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl
+++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl
@@ -2,58 +2,61 @@
const int k{{interface|name}}_{{method|name}}_name = {{method.ordinal}};
{%- endfor %}
-abstract class {{interface|name}}Calls {
- void sendMessage(bindings.Struct message, int name);
- Future sendMessageWithRequestId(bindings.Struct message, int name, int id);
+abstract class {{interface|name}} implements core.Listener {
+ static const String name = '{{namespace|replace(".","::")}}::{{interface|name}}';
+ {{interface|name}}Stub stub;
+
+ {{interface|name}}(core.MojoMessagePipeEndpoint endpoint) :
+ stub = new {{interface|name}}Stub(endpoint);
+
+ {{interface|name}}.fromHandle(core.MojoHandle handle) :
+ stub = new {{interface|name}}Stub.fromHandle(handle);
+
+ {{interface|name}}.fromStub(this.stub);
+
+ {{interface|name}}.unbound() :
+ stub = new {{interface|name}}Stub.unbound();
+
+ void close() => stub.close();
+
+ StreamSubscription<int> listen() => stub.listen();
+
+ {{interface|name}} get delegate => stub.delegate;
+ set delegate({{interface|name}} d) {
+ stub.delegate = d;
+ }
{%- for method in interface.methods %}
{%- if method.response_parameters == None %}
- void call{{method|name|upper_camel_case}}(
-{%- for parameter in method.parameters -%}
- {{parameter.kind|dart_type}} {{parameter|name}}{% if not loop.last %}, {% endif %}
-{%- endfor -%}
-{%- set request_struct = method|struct_from_method %}
- ) {
- var params = new {{request_struct|name}}();
-{%- for parameter in method.parameters %}
- params.{{parameter|name}} = {{parameter|name}};
-{%- endfor %}
- sendMessage(params, k{{interface|name}}_{{method|name}}_name);
- }
-{% else %}
+ void {{method|name}}(
+ {%- for parameter in method.parameters -%}
+ {{parameter.kind|dart_type}} {{parameter|name}}{% if not loop.last %}, {% endif %}
+ {%- endfor -%}
+ );
+{%- else %}
{%- set response_struct = method|response_struct_from_method %}
- Future<{{response_struct|name}}> call{{method|name|upper_camel_case}}(
-{%- for parameter in method.parameters -%}
+ Future<{{response_struct|name}}> {{method|name}}(
+ {%- for parameter in method.parameters -%}
{{parameter.kind|dart_type}} {{parameter|name}},
-{%- endfor -%}
-{%- set request_struct = method|struct_from_method %}
- [int requestId = -1]
- ) {
- var params = new {{request_struct|name}}();
-{%- for parameter in method.parameters %}
- params.{{parameter|name}} = {{parameter|name}};
-{%- endfor %}
- return sendMessageWithRequestId(
- params,
- k{{interface|name}}_{{method|name}}_name,
- requestId,
- bindings.MessageHeader.kMessageExpectsResponse);
- }
+ {%- endfor -%}
+ [Function responseFactory = null]);
{%- endif %}
{%- endfor %}
}
-class {{interface|name}}Client extends bindings.Client with {{interface|name}}Calls {
- {{interface|name}}Client(core.MojoMessagePipeEndpoint endpoint) : super(endpoint);
+class {{interface|name}}Proxy extends bindings.Proxy implements {{interface|name}} {
+ {{interface|name}}Proxy(core.MojoMessagePipeEndpoint endpoint) : super(endpoint);
- {{interface|name}}Client.fromHandle(core.MojoHandle handle) :
+ {{interface|name}}Proxy.fromHandle(core.MojoHandle handle) :
super.fromHandle(handle);
- {{interface|name}}Client.unbound() : super.unbound();
+ {{interface|name}}Proxy.unbound() : super.unbound();
+
+ String get name => {{interface|name}}.name;
- static {{interface|name}}Client newFromEndpoint(
+ static {{interface|name}}Proxy newFromEndpoint(
core.MojoMessagePipeEndpoint endpoint) =>
- new {{interface|name}}Client(endpoint);
+ new {{interface|name}}Proxy(endpoint);
void handleResponse(bindings.ServiceMessage message) {
switch (message.header.type) {
@@ -77,45 +80,61 @@ class {{interface|name}}Client extends bindings.Client with {{interface|name}}Ca
break;
}
}
+
+{%- for method in interface.methods %}
+{%- if method.response_parameters == None %}
+ void {{method|name}}(
+{%- for parameter in method.parameters -%}
+ {{parameter.kind|dart_type}} {{parameter|name}}{% if not loop.last %}, {% endif %}
+{%- endfor -%}
+{%- set request_struct = method|struct_from_method -%}
+ ) {
+ var params = new {{request_struct|name}}();
+{%- for parameter in method.parameters %}
+ params.{{parameter|name}} = {{parameter|name}};
+{%- endfor %}
+ sendMessage(params, k{{interface|name}}_{{method|name}}_name);
+ }
+{% else %}
+{%- set response_struct = method|response_struct_from_method %}
+{%- set request_struct = method|struct_from_method %}
+ Future<{{response_struct|name}}> {{method|name}}(
+{%- for parameter in method.parameters -%}
+ {{parameter.kind|dart_type}} {{parameter|name}},
+{%- endfor -%}
+ [Function responseFactory = null]) {
+ var params = new {{request_struct|name}}();
+{%- for parameter in method.parameters %}
+ params.{{parameter|name}} = {{parameter|name}};
+{%- endfor %}
+ return sendMessageWithRequestId(
+ params,
+ k{{interface|name}}_{{method|name}}_name,
+ -1,
+ bindings.MessageHeader.kMessageExpectsResponse);
+ }
+{%- endif %}
+{%- endfor %}
}
-{#--- TODO(zra): Remove Interface suffix from the name of this class.
- This is tricky because some mojom files have interfaces named both
- X and XClient. This leads to an XClient for the Client of X, and an
- XClient for the Interface of XClient, which conflict with eachother. #}
-class {{interface|name}}Interface extends bindings.Interface
-{% if interface.client != None -%}
-with {{imported_from[interface.client]}}{{interface.client|upper_camel_case}}Calls
-{% endif -%} {
- {{interface|name}}Interface _delegate = null;
+class {{interface|name}}Stub extends bindings.Stub {
+ {{interface|name}} _delegate = null;
- {{interface|name}}Interface(core.MojoMessagePipeEndpoint endpoint) : super(endpoint);
+ {{interface|name}}Stub(core.MojoMessagePipeEndpoint endpoint) : super(endpoint);
- {{interface|name}}Interface.fromHandle(core.MojoHandle handle) :
+ {{interface|name}}Stub.fromHandle(core.MojoHandle handle) :
super.fromHandle(handle);
- {{interface|name}}Interface.unbound() : super.unbound();
+ {{interface|name}}Stub.unbound() : super.unbound();
- static {{interface|name}}Interface newFromEndpoint(
+ static {{interface|name}}Stub newFromEndpoint(
core.MojoMessagePipeEndpoint endpoint) =>
- new {{interface|name}}Interface(endpoint);
+ new {{interface|name}}Stub(endpoint);
- static const String name = '{{namespace|replace(".","::")}}::{{interface|name}}';
+ static const String name = {{interface|name}}.name;
{% for method in interface.methods %}
-{%- if method.response_parameters == None %}
- void {{method|name}}(
- {%- for parameter in method.parameters -%}
- {{parameter.kind|dart_type}} {{parameter|name}}{% if not loop.last %}, {% endif %}
- {%- endfor -%}
- ) {
- assert(_delegate != null);
- _delegate.{{method|name}}(
- {%- for parameter in method.parameters -%}
- {{parameter|name}}{% if not loop.last %}, {% endif %}
- {%- endfor %});
- }
-{%- else %}
+{%- if method.response_parameters != None %}
{%- set response_struct = method|response_struct_from_method %}
{{response_struct|name}} _{{response_struct|name}}Factory(
{%- for param in method.response_parameters -%}
@@ -128,23 +147,11 @@ with {{imported_from[interface.client]}}{{interface.client|upper_camel_case}}Cal
{%- endfor %}
return result;
}
-
- Future<{{response_struct|name}}> {{method|name}}(
- {%- for parameter in method.parameters -%}
- {{parameter.kind|dart_type}} {{parameter|name}},
- {%- endfor -%}
- Function responseFactory) {
- assert(_delegate != null);
- return _delegate.{{method|name}}(
- {%- for parameter in method.parameters -%}
- {{parameter|name}},
- {%- endfor %}
- responseFactory);
- }
{%- endif %}
{%- endfor %}
Future<bindings.Message> handleMessage(bindings.ServiceMessage message) {
+ assert(_delegate != null);
switch (message.header.type) {
{%- for method in interface.methods %}
{%- set request_struct = method|struct_from_method %}
@@ -152,14 +159,14 @@ with {{imported_from[interface.client]}}{{interface.client|upper_camel_case}}Cal
var params = {{request_struct|name}}.deserialize(
message.payload);
{%- if method.response_parameters == None %}
- {{method|name}}(
+ _delegate.{{method|name}}(
{%- for parameter in method.parameters -%}
params.{{parameter|name}}{% if not loop.last %}, {% endif %}
{%- endfor -%}
);
{%- else %}
{%- set response_struct = method|response_struct_from_method %}
- return {{method|name}}(
+ return _delegate.{{method|name}}(
{%- for parameter in method.parameters -%}
params.{{parameter|name}},
{%- endfor -%}
@@ -182,8 +189,8 @@ with {{imported_from[interface.client]}}{{interface.client|upper_camel_case}}Cal
return null;
}
- {{interface|name}}Interface get delegate => _delegate;
- set delegate({{interface|name}}Interface d) {
+ {{interface|name}} get delegate => _delegate;
+ set delegate({{interface|name}} d) {
assert(_delegate == null);
_delegate = d;
}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/js_templates/module.sky.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/js_templates/module.sky.tmpl
index 78cdf3f..878cd20 100644
--- a/third_party/mojo/src/mojo/public/tools/bindings/generators/js_templates/module.sky.tmpl
+++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/js_templates/module.sky.tmpl
@@ -2,13 +2,13 @@
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
-<import src="/mojo/public/sky/bindings.sky" as="bindings" />
-<import src="/mojo/public/sky/codec.sky" as="codec" />
-<import src="/mojo/public/sky/connection.sky" as="connection" />
-<import src="/mojo/public/sky/core.sky" as="core" />
-<import src="/mojo/public/sky/validator.sky" as="validator" />
+<import src="/gen/mojo/public/sky/bindings.sky" as="bindings" />
+<import src="/gen/mojo/public/sky/codec.sky" as="codec" />
+<import src="/gen/mojo/public/sky/connection.sky" as="connection" />
+<import src="/gen/mojo/public/sky/core.sky" as="core" />
+<import src="/gen/mojo/public/sky/validator.sky" as="validator" />
{%- for import in imports %}
-<import src="/{{import.module.path}}.sky" as="{{import.unique_name}}" />
+<import src="/gen/{{import.module.path}}.sky" as="{{import.unique_name}}" />
{%- endfor %}
<script>
{%- include "module_definition.tmpl" %}
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py
index 9862943..3251095 100644
--- a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py
+++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py
@@ -253,13 +253,13 @@ def AppendDecodeParams(initial_params, kind, bit):
else:
params.append(GetDartTrueFalse(mojom.IsNullableKind(kind)))
if mojom.IsInterfaceKind(kind):
- params.append('%sClient.newFromEndpoint' % GetDartType(kind))
+ params.append('%sProxy.newFromEndpoint' % GetDartType(kind))
if mojom.IsArrayKind(kind) and mojom.IsInterfaceKind(kind.kind):
- params.append('%sClient.newFromEndpoint' % GetDartType(kind.kind))
+ params.append('%sProxy.newFromEndpoint' % GetDartType(kind.kind))
if mojom.IsInterfaceRequestKind(kind):
- params.append('%sInterface.newFromEndpoint' % GetDartType(kind.kind))
+ params.append('%sStub.newFromEndpoint' % GetDartType(kind.kind))
if mojom.IsArrayKind(kind) and mojom.IsInterfaceRequestKind(kind.kind):
- params.append('%sInterface.newFromEndpoint' % GetDartType(kind.kind.kind))
+ params.append('%sStub.newFromEndpoint' % GetDartType(kind.kind.kind))
if mojom.IsArrayKind(kind):
params.append(GetArrayExpectedLength(kind))
return params
@@ -381,7 +381,6 @@ class Generator(generator.Generator):
'interface_response_name': GetInterfaceResponseName,
'response_struct_from_method': GetResponseStructFromMethod,
'struct_from_method': GetStructFromMethod,
- 'upper_camel_case': UpperCamelCase,
'struct_size': lambda ps: ps.GetTotalSize() + _HEADER_SIZE,
}
@@ -420,7 +419,7 @@ class Generator(generator.Generator):
unique_name = simple_name + str(counter)
used_names.add(unique_name)
- each_import["unique_name"] = unique_name
+ each_import["unique_name"] = unique_name + '_mojom'
counter += 1
return self.module.imports
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_js_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_js_generator.py
index 7aaeaa2..fd1407e 100644
--- a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_js_generator.py
+++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_js_generator.py
@@ -223,30 +223,30 @@ def JavaScriptValidateHandleParams(packed_field):
return "%s, %s" % (field_offset, nullable)
-
-
def JavaScriptProxyMethodParameterValue(parameter):
name = parameter.name;
if (IsInterfaceParameter(parameter)):
type = JavaScriptType(parameter.kind)
- return "core.isHandle(%s) ? %s : connection.bindProxyClient" \
- "(%s, %s, %s.client)" % (name, name, name, type, type)
+ return "core.isHandle(%s) ? %s : connection.bindImpl" \
+ "(%s, %s)" % (name, name, name, type)
if (IsInterfaceRequestParameter(parameter)):
type = JavaScriptType(parameter.kind.kind)
- return "core.isHandle(%s) ? %s : connection.bindProxyClient" \
- "(%s, %s.client, %s)" % (name, name, name, type, type)
+ return "core.isHandle(%s) ? %s : connection.bindProxy" \
+ "(%s, %s)" % (name, name, name, type)
return name;
+
def JavaScriptStubMethodParameterValue(parameter):
name = parameter.name;
if (IsInterfaceParameter(parameter)):
type = JavaScriptType(parameter.kind)
- return "connection.bindProxyHandle(%s, %s.client, %s)" % (name, type, type)
+ return "connection.bindHandleToProxy(%s, %s)" % (name, type)
if (IsInterfaceRequestParameter(parameter)):
type = JavaScriptType(parameter.kind.kind)
- return "connection.bindProxyHandle(%s, %s, %s.client)" % (name, type, type)
+ 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:
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/parse/ast.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/parse/ast.py
index e1fa4f8..ffb44e0 100644
--- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/parse/ast.py
+++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/parse/ast.py
@@ -136,28 +136,34 @@ class Const(Definition):
class Enum(Definition):
"""Represents an enum definition."""
- def __init__(self, name, enum_value_list, **kwargs):
+ def __init__(self, name, attribute_list, enum_value_list, **kwargs):
+ assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert isinstance(enum_value_list, EnumValueList)
super(Enum, self).__init__(name, **kwargs)
+ self.attribute_list = attribute_list
self.enum_value_list = enum_value_list
def __eq__(self, other):
return super(Enum, self).__eq__(other) and \
+ self.attribute_list == other.attribute_list and \
self.enum_value_list == other.enum_value_list
class EnumValue(Definition):
"""Represents a definition of an enum value."""
- def __init__(self, name, value, **kwargs):
+ def __init__(self, name, attribute_list, value, **kwargs):
# The optional value is either an int (which is current a string) or a
# "wrapped identifier".
+ assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert value is None or isinstance(value, (str, tuple))
super(EnumValue, self).__init__(name, **kwargs)
+ self.attribute_list = attribute_list
self.value = value
def __eq__(self, other):
return super(EnumValue, self).__eq__(other) and \
+ self.attribute_list == other.attribute_list and \
self.value == other.value
@@ -206,19 +212,22 @@ class Interface(Definition):
class Method(Definition):
"""Represents a method definition."""
- def __init__(self, name, ordinal, parameter_list, response_parameter_list,
- **kwargs):
+ def __init__(self, name, attribute_list, ordinal, parameter_list,
+ response_parameter_list, **kwargs):
+ assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert ordinal is None or isinstance(ordinal, Ordinal)
assert isinstance(parameter_list, ParameterList)
assert response_parameter_list is None or \
isinstance(response_parameter_list, ParameterList)
super(Method, self).__init__(name, **kwargs)
+ self.attribute_list = attribute_list
self.ordinal = ordinal
self.parameter_list = parameter_list
self.response_parameter_list = response_parameter_list
def __eq__(self, other):
return super(Method, self).__eq__(other) and \
+ self.attribute_list == other.attribute_list and \
self.ordinal == other.ordinal and \
self.parameter_list == other.parameter_list and \
self.response_parameter_list == other.response_parameter_list
@@ -287,18 +296,21 @@ class Ordinal(NodeBase):
class Parameter(NodeBase):
"""Represents a method request or response parameter."""
- def __init__(self, name, ordinal, typename, **kwargs):
+ def __init__(self, name, attribute_list, ordinal, typename, **kwargs):
assert isinstance(name, str)
+ assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert ordinal is None or isinstance(ordinal, Ordinal)
assert isinstance(typename, str)
super(Parameter, self).__init__(**kwargs)
self.name = name
+ self.attribute_list = attribute_list
self.ordinal = ordinal
self.typename = typename
def __eq__(self, other):
return super(Parameter, self).__eq__(other) and \
self.name == other.name and \
+ self.attribute_list == other.attribute_list and \
self.ordinal == other.ordinal and \
self.typename == other.typename
@@ -328,20 +340,24 @@ class Struct(Definition):
class StructField(Definition):
"""Represents a struct field definition."""
- def __init__(self, name, ordinal, typename, default_value, **kwargs):
+ def __init__(self, name, attribute_list, ordinal, typename, default_value,
+ **kwargs):
assert isinstance(name, str)
+ assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert ordinal is None or isinstance(ordinal, Ordinal)
assert isinstance(typename, str)
# The optional default value is currently either a value as a string or a
# "wrapped identifier".
assert default_value is None or isinstance(default_value, (str, tuple))
super(StructField, self).__init__(name, **kwargs)
+ self.attribute_list = attribute_list
self.ordinal = ordinal
self.typename = typename
self.default_value = default_value
def __eq__(self, other):
return super(StructField, self).__eq__(other) and \
+ self.attribute_list == other.attribute_list and \
self.ordinal == other.ordinal and \
self.typename == other.typename and \
self.default_value == other.default_value
@@ -357,28 +373,34 @@ class StructBody(NodeListBase):
class Union(Definition):
"""Represents a union definition."""
- def __init__(self, name, body, **kwargs):
+ def __init__(self, name, attribute_list, body, **kwargs):
+ assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert isinstance(body, UnionBody)
super(Union, self).__init__(name, **kwargs)
+ self.attribute_list = attribute_list
self.body = body
def __eq__(self, other):
return super(Union, self).__eq__(other) and \
+ self.attribute_list == other.attribute_list and \
self.body == other.body
class UnionField(Definition):
- def __init__(self, name, ordinal, typename, **kwargs):
+ def __init__(self, name, attribute_list, ordinal, typename, **kwargs):
assert isinstance(name, str)
+ assert attribute_list is None or isinstance(attribute_list, AttributeList)
assert ordinal is None or isinstance(ordinal, Ordinal)
assert isinstance(typename, str)
super(UnionField, self).__init__(name, **kwargs)
+ self.attribute_list = attribute_list
self.ordinal = ordinal
self.typename = typename
def __eq__(self, other):
return super(UnionField, self).__eq__(other) and \
+ self.attribute_list == other.attribute_list and \
self.ordinal == other.ordinal and \
self.typename == other.typename
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/parse/parser.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/parse/parser.py
index 4225f0a..dc9d097 100644
--- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/parse/parser.py
+++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/parse/parser.py
@@ -171,12 +171,12 @@ class Parser(object):
p[0].Append(p[2])
def p_struct_field(self, p):
- """struct_field : typename NAME ordinal default SEMI"""
- p[0] = ast.StructField(p[2], p[3], p[1], p[4])
+ """struct_field : attribute_section typename NAME ordinal default SEMI"""
+ p[0] = ast.StructField(p[3], p[1], p[4], p[2], p[5])
def p_union(self, p):
- """union : UNION NAME LBRACE union_body RBRACE SEMI"""
- p[0] = ast.Union(p[2], p[4])
+ """union : attribute_section UNION NAME LBRACE union_body RBRACE SEMI"""
+ p[0] = ast.Union(p[3], p[1], p[5])
def p_union_body_1(self, p):
"""union_body : """
@@ -188,8 +188,8 @@ class Parser(object):
p[1].Append(p[2])
def p_union_field(self, p):
- """union_field : typename NAME ordinal SEMI"""
- p[0] = ast.UnionField(p[2], p[3], p[1])
+ """union_field : attribute_section typename NAME ordinal SEMI"""
+ p[0] = ast.UnionField(p[3], p[1], p[4], p[2])
def p_default_1(self, p):
"""default : """
@@ -224,8 +224,9 @@ class Parser(object):
p[0] = p[3]
def p_method(self, p):
- """method : NAME ordinal LPAREN parameter_list RPAREN response SEMI"""
- p[0] = ast.Method(p[1], p[2], p[4], p[6])
+ """method : attribute_section NAME ordinal LPAREN parameter_list RPAREN \
+ response SEMI"""
+ p[0] = ast.Method(p[2], p[1], p[3], p[5], p[7])
def p_parameter_list_1(self, p):
"""parameter_list : """
@@ -245,9 +246,9 @@ class Parser(object):
p[0].Append(p[3])
def p_parameter(self, p):
- """parameter : typename NAME ordinal"""
- p[0] = ast.Parameter(p[2], p[3], p[1],
- filename=self.filename, lineno=p.lineno(2))
+ """parameter : attribute_section typename NAME ordinal"""
+ p[0] = ast.Parameter(p[3], p[1], p[4], p[2],
+ filename=self.filename, lineno=p.lineno(3))
def p_typename(self, p):
"""typename : nonnullable_typename QSTN
@@ -322,9 +323,12 @@ class Parser(object):
p[0] = ast.Ordinal(value, filename=self.filename, lineno=p.lineno(1))
def p_enum(self, p):
- """enum : ENUM NAME LBRACE nonempty_enum_value_list RBRACE SEMI
- | ENUM NAME LBRACE nonempty_enum_value_list COMMA RBRACE SEMI"""
- p[0] = ast.Enum(p[2], p[4], filename=self.filename, lineno=p.lineno(1))
+ """enum : attribute_section ENUM NAME LBRACE nonempty_enum_value_list \
+ RBRACE SEMI
+ | attribute_section ENUM NAME LBRACE nonempty_enum_value_list \
+ COMMA RBRACE SEMI"""
+ p[0] = ast.Enum(p[3], p[1], p[5], filename=self.filename,
+ lineno=p.lineno(2))
def p_nonempty_enum_value_list_1(self, p):
"""nonempty_enum_value_list : enum_value"""
@@ -336,11 +340,11 @@ class Parser(object):
p[0].Append(p[3])
def p_enum_value(self, p):
- """enum_value : NAME
- | NAME EQUALS int
- | NAME EQUALS identifier_wrapped"""
- p[0] = ast.EnumValue(p[1], p[3] if len(p) == 4 else None,
- filename=self.filename, lineno=p.lineno(1))
+ """enum_value : attribute_section NAME
+ | attribute_section NAME EQUALS int
+ | attribute_section NAME EQUALS identifier_wrapped"""
+ p[0] = ast.EnumValue(p[2], p[1], p[4] if len(p) == 5 else None,
+ filename=self.filename, lineno=p.lineno(2))
def p_const(self, p):
"""const : CONST typename NAME EQUALS constant SEMI"""
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py
index 65c2fca..d3f8907 100644
--- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py
+++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py
@@ -146,8 +146,8 @@ class ParserTest(unittest.TestCase):
'MyStruct',
None,
ast.StructBody(
- [ast.StructField('a', None, 'int32', None),
- ast.StructField('b', None, 'double', None)]))])
+ [ast.StructField('a', None, None, 'int32', None),
+ ast.StructField('b', None, None, 'double', None)]))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
def testSimpleStructWithoutModule(self):
@@ -166,8 +166,8 @@ class ParserTest(unittest.TestCase):
'MyStruct',
None,
ast.StructBody(
- [ast.StructField('a', None, 'int32', None),
- ast.StructField('b', None, 'double', None)]))])
+ [ast.StructField('a', None, None, 'int32', None),
+ ast.StructField('b', None, None, 'double', None)]))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
def testValidStructDefinitions(self):
@@ -189,10 +189,12 @@ class ParserTest(unittest.TestCase):
None,
ast.StructBody(
[ast.Enum('MyEnum',
- ast.EnumValueList(ast.EnumValue('VALUE', None))),
+ None,
+ ast.EnumValueList(
+ ast.EnumValue('VALUE', None, None))),
ast.Const('kMyConst', 'double', '1.23'),
- ast.StructField('a', None, 'int32', None),
- ast.StructField('b', None, 'SomeOtherStruct', None)]))])
+ ast.StructField('a', None, None, 'int32', None),
+ ast.StructField('b', None, None, 'SomeOtherStruct', None)]))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
def testInvalidStructDefinitions(self):
@@ -344,18 +346,20 @@ class ParserTest(unittest.TestCase):
ast.ImportList(),
[ast.Enum(
'MyEnum1',
- ast.EnumValueList([ast.EnumValue('VALUE1', None),
- ast.EnumValue('VALUE2', None)])),
+ None,
+ ast.EnumValueList([ast.EnumValue('VALUE1', None, None),
+ ast.EnumValue('VALUE2', None, None)])),
ast.Enum(
'MyEnum2',
- ast.EnumValueList([ast.EnumValue('VALUE1', '-1'),
- ast.EnumValue('VALUE2', '0'),
- ast.EnumValue('VALUE3', '+987'),
- ast.EnumValue('VALUE4', '0xAF12'),
- ast.EnumValue('VALUE5', '-0x09bcd'),
- ast.EnumValue('VALUE6', ('IDENTIFIER',
+ None,
+ ast.EnumValueList([ast.EnumValue('VALUE1', None, '-1'),
+ ast.EnumValue('VALUE2', None, '0'),
+ ast.EnumValue('VALUE3', None, '+987'),
+ ast.EnumValue('VALUE4', None, '0xAF12'),
+ ast.EnumValue('VALUE5', None, '-0x09bcd'),
+ ast.EnumValue('VALUE6', None, ('IDENTIFIER',
'VALUE5')),
- ast.EnumValue('VALUE7', None)]))])
+ ast.EnumValue('VALUE7', None, None)]))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
def testInvalidEnumInitializers(self):
@@ -406,7 +410,7 @@ class ParserTest(unittest.TestCase):
'MyStruct', None,
ast.StructBody(
[ast.Const('kNumber', 'int8', '-1'),
- ast.StructField('number', ast.Ordinal(0), 'int8',
+ ast.StructField('number', None, ast.Ordinal(0), 'int8',
('IDENTIFIER', 'kNumber'))]))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
@@ -452,14 +456,14 @@ class ParserTest(unittest.TestCase):
'MyStruct',
None,
ast.StructBody(
- [ast.StructField('a0', ast.Ordinal(0), 'int32', None),
- ast.StructField('a1', ast.Ordinal(1), 'int32', None),
- ast.StructField('a2', ast.Ordinal(2), 'int32', None),
- ast.StructField('a9', ast.Ordinal(9), 'int32', None),
- ast.StructField('a10', ast.Ordinal(10), 'int32', None),
- ast.StructField('a11', ast.Ordinal(11), 'int32', None),
- ast.StructField('a29', ast.Ordinal(29), 'int32', None),
- ast.StructField('a1234567890', ast.Ordinal(1234567890),
+ [ast.StructField('a0', None, ast.Ordinal(0), 'int32', None),
+ ast.StructField('a1', None, ast.Ordinal(1), 'int32', None),
+ ast.StructField('a2', None, ast.Ordinal(2), 'int32', None),
+ ast.StructField('a9', None, ast.Ordinal(9), 'int32', None),
+ ast.StructField('a10', None, ast.Ordinal(10), 'int32', None),
+ ast.StructField('a11', None, ast.Ordinal(11), 'int32', None),
+ ast.StructField('a29', None, ast.Ordinal(29), 'int32', None),
+ ast.StructField('a1234567890', None, ast.Ordinal(1234567890),
'int32', None)]))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
@@ -542,7 +546,7 @@ class ParserTest(unittest.TestCase):
[ast.Struct(
'MyStruct',
None,
- ast.StructBody(ast.StructField('a', None, 'int32', None)))])
+ ast.StructBody(ast.StructField('a', None, None, 'int32', None)))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
def testValidHandleTypes(self):
@@ -566,11 +570,14 @@ class ParserTest(unittest.TestCase):
'MyStruct',
None,
ast.StructBody(
- [ast.StructField('a', None, 'handle', None),
- ast.StructField('b', None, 'handle<data_pipe_consumer>', None),
- ast.StructField('c', None, 'handle<data_pipe_producer>', None),
- ast.StructField('d', None, 'handle<message_pipe>', None),
- ast.StructField('e', None, 'handle<shared_buffer>', None)]))])
+ [ast.StructField('a', None, None, 'handle', None),
+ ast.StructField('b', None, None, 'handle<data_pipe_consumer>',
+ None),
+ ast.StructField('c', None, None, 'handle<data_pipe_producer>',
+ None),
+ ast.StructField('d', None, None, 'handle<message_pipe>', None),
+ ast.StructField('e', None, None, 'handle<shared_buffer>',
+ None)]))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
def testInvalidHandleType(self):
@@ -625,29 +632,29 @@ class ParserTest(unittest.TestCase):
'MyStruct',
None,
ast.StructBody(
- [ast.StructField('a0', None, 'int16', '0'),
- ast.StructField('a1', None, 'uint16', '0x0'),
- ast.StructField('a2', None, 'uint16', '0x00'),
- ast.StructField('a3', None, 'uint16', '0x01'),
- ast.StructField('a4', None, 'uint16', '0xcd'),
- ast.StructField('a5' , None, 'int32', '12345'),
- ast.StructField('a6', None, 'int64', '-12345'),
- ast.StructField('a7', None, 'int64', '+12345'),
- ast.StructField('a8', None, 'uint32', '0x12cd3'),
- ast.StructField('a9', None, 'uint32', '-0x12cD3'),
- ast.StructField('a10', None, 'uint32', '+0x12CD3'),
- ast.StructField('a11', None, 'bool', 'true'),
- ast.StructField('a12', None, 'bool', 'false'),
- ast.StructField('a13', None, 'float', '1.2345'),
- ast.StructField('a14', None, 'float', '-1.2345'),
- ast.StructField('a15', None, 'float', '+1.2345'),
- ast.StructField('a16', None, 'float', '123.'),
- ast.StructField('a17', None, 'float', '.123'),
- ast.StructField('a18', None, 'double', '1.23E10'),
- ast.StructField('a19', None, 'double', '1.E-10'),
- ast.StructField('a20', None, 'double', '.5E+10'),
- ast.StructField('a21', None, 'double', '-1.23E10'),
- ast.StructField('a22', None, 'double', '+.123E10')]))])
+ [ast.StructField('a0', None, None, 'int16', '0'),
+ ast.StructField('a1', None, None, 'uint16', '0x0'),
+ ast.StructField('a2', None, None, 'uint16', '0x00'),
+ ast.StructField('a3', None, None, 'uint16', '0x01'),
+ ast.StructField('a4', None, None, 'uint16', '0xcd'),
+ ast.StructField('a5' , None, None, 'int32', '12345'),
+ ast.StructField('a6', None, None, 'int64', '-12345'),
+ ast.StructField('a7', None, None, 'int64', '+12345'),
+ ast.StructField('a8', None, None, 'uint32', '0x12cd3'),
+ ast.StructField('a9', None, None, 'uint32', '-0x12cD3'),
+ ast.StructField('a10', None, None, 'uint32', '+0x12CD3'),
+ ast.StructField('a11', None, None, 'bool', 'true'),
+ ast.StructField('a12', None, None, 'bool', 'false'),
+ ast.StructField('a13', None, None, 'float', '1.2345'),
+ ast.StructField('a14', None, None, 'float', '-1.2345'),
+ ast.StructField('a15', None, None, 'float', '+1.2345'),
+ ast.StructField('a16', None, None, 'float', '123.'),
+ ast.StructField('a17', None, None, 'float', '.123'),
+ ast.StructField('a18', None, None, 'double', '1.23E10'),
+ ast.StructField('a19', None, None, 'double', '1.E-10'),
+ ast.StructField('a20', None, None, 'double', '.5E+10'),
+ ast.StructField('a21', None, None, 'double', '-1.23E10'),
+ ast.StructField('a22', None, None, 'double', '+.123E10')]))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
def testValidFixedSizeArray(self):
@@ -668,12 +675,12 @@ class ParserTest(unittest.TestCase):
'MyStruct',
None,
ast.StructBody(
- [ast.StructField('normal_array', None, 'int32[]', None),
- ast.StructField('fixed_size_array_one_entry', None, 'int32[1]',
- None),
- ast.StructField('fixed_size_array_ten_entries', None,
+ [ast.StructField('normal_array', None, None, 'int32[]', None),
+ ast.StructField('fixed_size_array_one_entry', None, None,
+ 'int32[1]', None),
+ ast.StructField('fixed_size_array_ten_entries', None, None,
'int32[10]', None),
- ast.StructField('nested_arrays', None,
+ ast.StructField('nested_arrays', None, None,
'int32[1][][2]', None)]))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
@@ -688,7 +695,8 @@ class ParserTest(unittest.TestCase):
'MyStruct',
None,
ast.StructBody(
- ast.StructField('nested_array', None, 'int32[][]', None)))])
+ ast.StructField('nested_array', None, None, 'int32[][]',
+ None)))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
def testInvalidFixedArraySize(self):
@@ -738,7 +746,7 @@ class ParserTest(unittest.TestCase):
'MyStruct',
None,
ast.StructBody(
- [ast.StructField('data', None, 'uint8{string}', None)]))])
+ [ast.StructField('data', None, None, 'uint8{string}', None)]))])
self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1)
source2 = "interface MyInterface { MyMethod(map<string, uint8> a); };"
@@ -752,8 +760,9 @@ class ParserTest(unittest.TestCase):
ast.Method(
'MyMethod',
None,
+ None,
ast.ParameterList(
- ast.Parameter('a', None, 'uint8{string}')),
+ ast.Parameter('a', None, None, 'uint8{string}')),
None)))])
self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2)
@@ -765,7 +774,8 @@ class ParserTest(unittest.TestCase):
'MyStruct',
None,
ast.StructBody(
- [ast.StructField('data', None, 'uint8[]{string}', None)]))])
+ [ast.StructField('data', None, None, 'uint8[]{string}',
+ None)]))])
self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3)
def testValidMethod(self):
@@ -782,7 +792,8 @@ class ParserTest(unittest.TestCase):
ast.Method(
'MyMethod',
None,
- ast.ParameterList(ast.Parameter('a', None, 'int32')),
+ None,
+ ast.ParameterList(ast.Parameter('a', None, None, 'int32')),
None)))])
self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1)
@@ -801,14 +812,16 @@ class ParserTest(unittest.TestCase):
ast.InterfaceBody(
[ast.Method(
'MyMethod1',
+ None,
ast.Ordinal(0),
- ast.ParameterList([ast.Parameter('a', ast.Ordinal(0),
+ ast.ParameterList([ast.Parameter('a', None, ast.Ordinal(0),
'int32'),
- ast.Parameter('b', ast.Ordinal(1),
+ ast.Parameter('b', None, ast.Ordinal(1),
'int64')]),
None),
ast.Method(
'MyMethod2',
+ None,
ast.Ordinal(1),
ast.ParameterList(),
ast.ParameterList())]))])
@@ -829,9 +842,11 @@ class ParserTest(unittest.TestCase):
ast.Method(
'MyMethod',
None,
- ast.ParameterList(ast.Parameter('a', None, 'string')),
- ast.ParameterList([ast.Parameter('a', None, 'int32'),
- ast.Parameter('b', None, 'bool')]))))])
+ None,
+ ast.ParameterList(ast.Parameter('a', None, None, 'string')),
+ ast.ParameterList([ast.Parameter('a', None, None, 'int32'),
+ ast.Parameter('b', None, None,
+ 'bool')]))))])
self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3)
def testInvalidMethods(self):
@@ -879,13 +894,17 @@ class ParserTest(unittest.TestCase):
None,
ast.InterfaceBody(
[ast.Enum('MyEnum',
- ast.EnumValueList(ast.EnumValue('VALUE', None))),
+ None,
+ ast.EnumValueList(
+ ast.EnumValue('VALUE', None, None))),
ast.Const('kMyConst', 'int32', '123'),
ast.Method(
'MyMethod',
None,
- ast.ParameterList(ast.Parameter('x', None, 'int32')),
- ast.ParameterList(ast.Parameter('y', None, 'MyEnum')))]))])
+ None,
+ ast.ParameterList(ast.Parameter('x', None, None, 'int32')),
+ ast.ParameterList(ast.Parameter('y', None, None,
+ 'MyEnum')))]))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
def testInvalidInterfaceDefinitions(self):
@@ -967,6 +986,67 @@ class ParserTest(unittest.TestCase):
ast.StructBody())])
self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3)
+ # Various places that attribute list is allowed.
+ source4 = """\
+ [Attr0=0] module my_module;
+
+ [Attr1=1] struct MyStruct {
+ [Attr2=2] int32 a;
+ };
+ [Attr3=3] union MyUnion {
+ [Attr4=4] int32 a;
+ };
+ [Attr5=5] enum MyEnum {
+ [Attr6=6] a
+ };
+ [Attr7=7] interface MyInterface {
+ [Attr8=8] MyMethod([Attr9=9] int32 a) => ([Attr10=10] bool b);
+ };
+ """
+ expected4 = ast.Mojom(
+ ast.Module(('IDENTIFIER', 'my_module'),
+ ast.AttributeList([ast.Attribute("Attr0", 0)])),
+ ast.ImportList(),
+ [ast.Struct(
+ 'MyStruct',
+ ast.AttributeList(ast.Attribute("Attr1", 1)),
+ ast.StructBody(
+ ast.StructField(
+ 'a', ast.AttributeList([ast.Attribute("Attr2", 2)]),
+ None, 'int32', None))),
+ ast.Union(
+ 'MyUnion',
+ ast.AttributeList(ast.Attribute("Attr3", 3)),
+ ast.UnionBody(
+ ast.UnionField(
+ 'a', ast.AttributeList([ast.Attribute("Attr4", 4)]), None,
+ 'int32'))),
+ ast.Enum(
+ 'MyEnum',
+ ast.AttributeList(ast.Attribute("Attr5", 5)),
+ ast.EnumValueList(
+ ast.EnumValue(
+ 'VALUE', ast.AttributeList([ast.Attribute("Attr6", 6)]),
+ None))),
+ ast.Interface(
+ 'MyInterface',
+ ast.AttributeList(ast.Attribute("Attr7", 7)),
+ ast.InterfaceBody(
+ ast.Method(
+ 'MyMethod',
+ ast.AttributeList(ast.Attribute("Attr8", 8)),
+ None,
+ ast.ParameterList(
+ ast.Parameter(
+ 'a', ast.AttributeList([ast.Attribute("Attr9", 9)]),
+ None, 'int32')),
+ ast.ParameterList(
+ ast.Parameter(
+ 'b',
+ ast.AttributeList([ast.Attribute("Attr10", 10)]),
+ None, 'bool')))))])
+ self.assertEquals(parser.Parse(source4, "my_file.mojom"), expected4)
+
# TODO(vtl): Boolean attributes don't work yet. (In fact, we just |eval()|
# literal (non-name) values, which is extremely dubious.)
@@ -1100,22 +1180,23 @@ class ParserTest(unittest.TestCase):
'MyStruct',
None,
ast.StructBody(
- [ast.StructField('a', None, 'int32?', None),
- ast.StructField('b', None, 'string?', None),
- ast.StructField('c', None, 'int32[]?', None),
- ast.StructField('d', None, 'string?[]?', None),
- ast.StructField('e', None, 'int32[]?[]?', None),
- ast.StructField('f', None, 'int32[1]?', None),
- ast.StructField('g', None, 'string?[1]?', None),
- ast.StructField('h', None, 'some_struct?', None),
- ast.StructField('i', None, 'handle?', None),
- ast.StructField('j', None, 'handle<data_pipe_consumer>?',
+ [ast.StructField('a', None, None,'int32?', None),
+ ast.StructField('b', None, None,'string?', None),
+ ast.StructField('c', None, None,'int32[]?', None),
+ ast.StructField('d', None, None,'string?[]?', None),
+ ast.StructField('e', None, None,'int32[]?[]?', None),
+ ast.StructField('f', None, None,'int32[1]?', None),
+ ast.StructField('g', None, None,'string?[1]?', None),
+ ast.StructField('h', None, None,'some_struct?', None),
+ ast.StructField('i', None, None,'handle?', None),
+ ast.StructField('j', None, None,'handle<data_pipe_consumer>?',
+ None),
+ ast.StructField('k', None, None,'handle<data_pipe_producer>?',
None),
- ast.StructField('k', None, 'handle<data_pipe_producer>?',
+ ast.StructField('l', None, None,'handle<message_pipe>?', None),
+ ast.StructField('m', None, None,'handle<shared_buffer>?',
None),
- ast.StructField('l', None, 'handle<message_pipe>?', None),
- ast.StructField('m', None, 'handle<shared_buffer>?', None),
- ast.StructField('n', None, 'some_interface&?', None)]))])
+ ast.StructField('n', None, None,'some_interface&?', None)]))])
self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
def testInvalidNullableTypes(self):
@@ -1168,9 +1249,10 @@ class ParserTest(unittest.TestCase):
ast.ImportList(),
[ast.Union(
'MyUnion',
+ None,
ast.UnionBody([
- ast.UnionField('a', None, 'int32'),
- ast.UnionField('b', None, 'double')
+ ast.UnionField('a', None, None, 'int32'),
+ ast.UnionField('b', None, None, 'double')
]))])
actual = parser.Parse(source, "my_file.mojom")
self.assertEquals(actual, expected)
@@ -1190,9 +1272,10 @@ class ParserTest(unittest.TestCase):
ast.ImportList(),
[ast.Union(
'MyUnion',
+ None,
ast.UnionBody([
- ast.UnionField('a', ast.Ordinal(10), 'int32'),
- ast.UnionField('b', ast.Ordinal(30), 'double')
+ ast.UnionField('a', None, ast.Ordinal(10), 'int32'),
+ ast.UnionField('b', None, ast.Ordinal(30), 'double')
]))])
actual = parser.Parse(source, "my_file.mojom")
self.assertEquals(actual, expected)
@@ -1211,8 +1294,9 @@ class ParserTest(unittest.TestCase):
ast.ImportList(),
[ast.Union(
'MyUnion',
+ None,
ast.UnionBody([
- ast.UnionField('s', None, 'SomeStruct')
+ ast.UnionField('s', None, None, 'SomeStruct')
]))])
actual = parser.Parse(source, "my_file.mojom")
self.assertEquals(actual, expected)
@@ -1231,8 +1315,9 @@ class ParserTest(unittest.TestCase):
ast.ImportList(),
[ast.Union(
'MyUnion',
+ None,
ast.UnionBody([
- ast.UnionField('a', None, 'int32[]')
+ ast.UnionField('a', None, None, 'int32[]')
]))])
actual = parser.Parse(source, "my_file.mojom")
self.assertEquals(actual, expected)
@@ -1251,8 +1336,9 @@ class ParserTest(unittest.TestCase):
ast.ImportList(),
[ast.Union(
'MyUnion',
+ None,
ast.UnionBody([
- ast.UnionField('m', None, 'string{int32}')
+ ast.UnionField('m', None, None, 'string{int32}')
]))])
actual = parser.Parse(source, "my_file.mojom")
self.assertEquals(actual, expected)
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/parse/translate_unittest.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/parse/translate_unittest.py
index 9f2d985..20704dc 100644
--- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/parse/translate_unittest.py
+++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/parse/translate_unittest.py
@@ -49,9 +49,9 @@ class TranslateTest(unittest.TestCase):
tree = ast.Mojom(
None,
ast.ImportList(),
- [ast.Union("SomeUnion", ast.UnionBody(
- [ast.UnionField("a", None, "int32"),
- ast.UnionField("b", None, "string")]))])
+ [ast.Union("SomeUnion", None, ast.UnionBody(
+ [ast.UnionField("a", None, None, "int32"),
+ ast.UnionField("b", None, None, "string")]))])
expected = [{
"name": "SomeUnion",
"fields": [