mojo: Rename lite JS bindings

See https://docs.google.com/document/d/1RB1F4ym02avbwuLMEQ_un8CQ4bPMcfO7H8St5-NRmq0/edit#

Adds a "use_old_js_lite_bindings_names" variable whose default value is true.
A follow up CL will make its default false and change all current users of
the old names to manually set the flag to true.

Bug: 968369
Change-Id: I84cbe8824f15e9bf58339403481390ca29a98abe
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1686589
Reviewed-by: Ken Rockot <[email protected]>
Reviewed-by: Takuto Ikuta <[email protected]>
Reviewed-by: Matt Falkenhagen <[email protected]>
Reviewed-by: Dominick Ng <[email protected]>
Commit-Queue: Giovanni Ortuño Urquidi <[email protected]>
Cr-Commit-Position: refs/heads/master@{#675496}
diff --git a/BUILD.gn b/BUILD.gn
index ab7465f..309939b 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1013,6 +1013,7 @@
       ":layout_test_data_mojo_bindings_lite",
       "//content/shell:content_shell",
       "//content/test:mojo_web_test_bindings_js_data_deps",
+      "//content/test:mojo_web_test_old_names_bindings_js_data_deps",
       "//content/shell:mojo_bindings_js_data_deps",
       "//device/bluetooth/public/mojom:fake_bluetooth_interfaces_js_data_deps",
       "//device/vr/public/mojom:mojom_js_data_deps",
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index bb3b556..b0c5696 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -304,6 +304,7 @@
     "//content/shell/test_runner:test_runner",
     "//content/test:content_test_mojo_bindings",
     "//content/test:mojo_web_test_bindings",
+    "//content/test:mojo_web_test_old_names_bindings",
     "//content/test:test_support",
     "//content/test:web_test_support",
     "//device/bluetooth",
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 349d5c3f..66f317a1 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -640,11 +640,43 @@
   ]
 }
 
+mojom("mojo_web_test_helper_test") {
+  testonly = true
+  sources = [
+    "data/mojo_web_test_helper_test.mojom",
+  ]
+
+  # This mojom interface is exposed publicly to web tests which use
+  # prepackaged redistributable JS bindings. It is therefore not desirable to
+  # scramble these messages.
+  scramble_message_ids = false
+}
+
 mojom("mojo_web_test_bindings") {
   testonly = true
   sources = [
     "data/lite_js_test.mojom",
-    "data/mojo_web_test_helper_test.mojom",
+  ]
+
+  public_deps = [
+    ":mojo_web_test_helper_test",
+  ]
+
+  # This mojom interface is exposed publicly to web tests which use
+  # prepackaged redistributable JS bindings. It is therefore not desirable to
+  # scramble these messages.
+  scramble_message_ids = false
+  use_old_js_lite_bindings_names = false
+}
+
+mojom("mojo_web_test_old_names_bindings") {
+  testonly = true
+  sources = [
+    "data/lite_js_old_names_test.mojom",
+  ]
+
+  public_deps = [
+    ":mojo_web_test_helper_test",
   ]
 
   # This mojom interface is exposed publicly to web tests which use
diff --git a/content/test/data/lite_js_old_names_test.mojom b/content/test/data/lite_js_old_names_test.mojom
new file mode 100644
index 0000000..b1df7ae
--- /dev/null
+++ b/content/test/data/lite_js_old_names_test.mojom
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module lite_js_old_names_test.mojom;
+
+// Copy of lite_js_test.mojom that can be used in a separate target with a
+// different value for "use_old_js_lite_bindings_names".
+
+struct TestStruct {
+  int32 x;
+  const bool isValid = false;
+};
+
+union TestUnion {
+  int32 x;
+  TestStruct s;
+};
+
+// An interface whose definition covers various types of message signatures in
+// order to exercise the lite JS mojom bindings.
+interface TestMessageTarget {
+  // Zero arguments, no reply.
+  Poke();
+
+  // Zero-argument request, zero-argument reply.
+  Ping() => ();
+
+  // Request and reply both with arguments.
+  Repeat(string? message, array<int32>? numbers)
+      => (string? message, array<int32>? numbers);
+
+  Flatten(array<TestStruct> values) => (array<int32> values);
+  FlattenUnions(array<TestUnion> unions) => (array<int32> x, array<int32> s);
+
+  RequestSubinterface(Subinterface& request, SubinterfaceClient client);
+};
+
+interface Subinterface {
+  Push(int32 value);
+  Flush();
+};
+
+interface SubinterfaceClient {
+  DidFlush(array<int32> values);
+};
+
diff --git a/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl
index 4109319..389b57cd2 100644
--- a/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl
@@ -18,15 +18,15 @@
 {% endmacro %}
 
 {%  if generate_closure_exports -%}
-goog.provide('{{module.namespace}}.{{interface.name}}');
+goog.provide('{{module.namespace}}.{{interface.name}}{{primitives_names.receiver}}');
 goog.provide('{{module.namespace}}.{{interface.name}}CallbackRouter');
 goog.provide('{{module.namespace}}.{{interface.name}}Interface');
-goog.provide('{{module.namespace}}.{{interface.name}}Proxy');
-goog.provide('{{module.namespace}}.{{interface.name}}Request');
+goog.provide('{{module.namespace}}.{{interface.name}}{{primitives_names.remote}}');
+goog.provide('{{module.namespace}}.{{interface.name}}{{primitives_names.pending_receiver}}');
 {% endif %}
 
 /** @export */
-{{module.namespace}}.{{interface.name}}Request = class {
+{{module.namespace}}.{{interface.name}}{{primitives_names.pending_receiver}} = class {
   /** @param {!MojoHandle} handle */
   constructor(handle) {
     /** @public {!MojoHandle} */
@@ -52,19 +52,19 @@
  * @export
  * @implements { {{module.namespace}}.{{interface.name}}Interface }
  */
-{{module.namespace}}.{{interface.name}}Proxy = class {
+{{module.namespace}}.{{interface.name}}{{primitives_names.remote}} = class {
   /** @param {MojoHandle=} opt_handle */
   constructor(opt_handle) {
     /**
-     * @private {!mojo.internal.interfaceSupport.InterfaceRemoteBase<!{{module.namespace}}.{{interface.name}}Request>}
+     * @private {!mojo.internal.interfaceSupport.InterfaceRemoteBase<!{{module.namespace}}.{{interface.name}}{{primitives_names.pending_receiver}}>}
      */
     this.proxy =
         new mojo.internal.interfaceSupport.InterfaceRemoteBase(
-          {{module.namespace}}.{{interface.name}}Request,
+          {{module.namespace}}.{{interface.name}}{{primitives_names.pending_receiver}},
           opt_handle);
 
     /**
-     * @public {!mojo.internal.interfaceSupport.InterfaceRemoteBaseWrapper<!{{module.namespace}}.{{interface.name}}Request>}
+     * @public {!mojo.internal.interfaceSupport.InterfaceRemoteBaseWrapper<!{{module.namespace}}.{{interface.name}}{{primitives_names.pending_receiver}}>}
      */
     this.$ = new mojo.internal.interfaceSupport.InterfaceRemoteBaseWrapper(this.proxy);
 
@@ -109,17 +109,17 @@
  *
  * @export
  */
-{{module.namespace}}.{{interface.name}} = class {
+{{module.namespace}}.{{interface.name}}{{primitives_names.receiver}} = class {
   /**
    * @param {!{{module.namespace}}.{{interface.name}}Interface } impl
    */
   constructor(impl) {
-    /** @private {!mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal<!{{module.namespace}}.{{interface.name}}Proxy>} */
+    /** @private {!mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal<!{{module.namespace}}.{{interface.name}}{{primitives_names.remote}}>} */
     this.helper_internal_ = new mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal(
-        {{module.namespace}}.{{interface.name}}Proxy);
+        {{module.namespace}}.{{interface.name}}{{primitives_names.remote}});
 
     /**
-     * @public {!mojo.internal.interfaceSupport.InterfaceReceiverHelper<!{{module.namespace}}.{{interface.name}}Proxy>}
+     * @public {!mojo.internal.interfaceSupport.InterfaceReceiverHelper<!{{module.namespace}}.{{interface.name}}{{primitives_names.remote}}>}
      */
     this.$ = new mojo.internal.interfaceSupport.InterfaceReceiverHelper(this.helper_internal_);
 
@@ -140,6 +140,7 @@
     this.onConnectionError = this.helper_internal_.getConnectionErrorEventRouter();
   }
 
+  {% if use_old_names -%}
   /**
    * Returns a proxy for this interface which sends messages to the browser.
    * The browser must have an interface request binder registered for this
@@ -154,6 +155,14 @@
                        proxy.$.bindNewPipeAndPassReceiver().handle);
     return proxy;
   }
+
+  /**
+   * @return {!string}
+   */
+  static get $interfaceName() {
+    return "{{mojom_namespace}}.{{interface.name}}";
+  }
+  {% endif %}
 };
 
 {#--- Enums #}
@@ -164,12 +173,36 @@
             enum) }}
 {%-  endfor %}
 
+{% if not use_old_names -%}
+
 /**
- * @const {string}
- * @export
+ *  @export
  */
-{{module.namespace}}.{{interface.name}}.$interfaceName =
-    '{{mojom_namespace}}.{{interface.name}}';
+{{module.namespace}}.{{interface.name}} = class {
+  /**
+   * @return {!string}
+   */
+  static get $interfaceName() {
+    return "{{mojom_namespace}}.{{interface.name}}";
+  }
+
+  /**
+   * Returns a remote for this interface which sends messages to the browser.
+   * The browser must have an interface request binder registered for this
+   * interface and accessible to the calling document's frame.
+   *
+   * @return {!{{module.namespace}}.{{interface.name}}Remote}
+   * @export
+   */
+  static getRemote() {
+    let remote = new {{module.namespace}}.{{interface.name}}Remote;
+    Mojo.bindInterface(this.$interfaceName,
+                       remote.$.bindNewPipeAndPassReceiver().handle);
+    return remote;
+  }
+};
+
+{% endif %}
 
 /**
  * An object which receives request messages for the {{interface.name}}
@@ -182,10 +215,10 @@
 {{module.namespace}}.{{interface.name}}CallbackRouter = class {
   constructor() {
     this.helper_internal_ = new mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal(
-      {{module.namespace}}.{{interface.name}}Proxy);
+      {{module.namespace}}.{{interface.name}}{{primitives_names.remote}});
 
     /**
-     * @public {!mojo.internal.interfaceSupport.InterfaceReceiverHelper<!{{module.namespace}}.{{interface.name}}Proxy>}
+     * @public {!mojo.internal.interfaceSupport.InterfaceReceiverHelper<!{{module.namespace}}.{{interface.name}}{{primitives_names.remote}}>}
      */
     this.$ = new mojo.internal.interfaceSupport.InterfaceReceiverHelper(this.helper_internal_);
 
diff --git a/mojo/public/tools/bindings/generators/mojom_js_generator.py b/mojo/public/tools/bindings/generators/mojom_js_generator.py
index 19a94f2..eb8d3b6 100644
--- a/mojo/public/tools/bindings/generators/mojom_js_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_js_generator.py
@@ -264,7 +264,9 @@
       "unions": self.module.unions,
       "generate_fuzzing": self.generate_fuzzing,
       "generate_closure_exports": for_compile,
-    }
+      "use_old_names": self.use_old_js_lite_bindings_names,
+      "primitives_names": self._GetPrimitivesNames(),
+   }
 
   @staticmethod
   def GetTemplatePrefix():
@@ -339,15 +341,15 @@
   def _GenerateExterns(self):
     return self._GetParameters()
 
-  @UseJinja("lite/mojom-lite.js.tmpl")
-  def _GenerateLiteBindings(self):
-    return self._GetParameters()
-
   @UseJinja("lite/mojom.html.tmpl")
   def _GenerateLiteHtml(self):
     return self._GetParameters()
 
   @UseJinja("lite/mojom-lite.js.tmpl")
+  def _GenerateLiteBindings(self):
+    return self._GetParameters()
+
+  @UseJinja("lite/mojom-lite.js.tmpl")
   def _GenerateLiteBindingsForCompile(self):
     return self._GetParameters(for_compile=True)
 
@@ -368,7 +370,7 @@
       self.Write(self._GenerateLiteHtml(), "%s.html" % self.module.path)
       self.Write(self._GenerateLiteBindings(), "%s-lite.js" % self.module.path)
       self.Write(self._GenerateLiteBindingsForCompile(),
-          "%s-lite-for-compile.js" % self.module.path)
+                 "%s-lite-for-compile.js" % self.module.path)
 
   def _SetUniqueNameForImports(self):
     used_names = set()
@@ -464,9 +466,9 @@
         mojom.IsEnumKind(kind)):
       return name
     if mojom.IsInterfaceKind(kind) or mojom.IsPendingRemoteKind(kind):
-      return name + "Proxy"
+      return name + self._GetPrimitivesNames()["remote"]
     if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind):
-      return name + "Request"
+      return name + self._GetPrimitivesNames()["pending_receiver"]
     # TODO(calamity): Support associated interfaces properly.
     if (mojom.IsAssociatedInterfaceKind(kind) or
         mojom.IsPendingAssociatedRemoteKind(kind)):
@@ -561,17 +563,21 @@
         mojom.IsEnumKind(kind)):
       return "%sSpec.$" % name
     if mojom.IsInterfaceKind(kind) or mojom.IsPendingRemoteKind(kind):
-      return "mojo.internal.InterfaceProxy(%sProxy)" % name
+      remote_name = name + self._GetPrimitivesNames()["remote"]
+      return "mojo.internal.InterfaceProxy(%s)" % remote_name
     if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind):
-      return "mojo.internal.InterfaceRequest(%sRequest)" % name
+      request_name = name + self._GetPrimitivesNames()["pending_receiver"]
+      return "mojo.internal.InterfaceRequest(%s)" % request_name
     if (mojom.IsAssociatedInterfaceKind(kind) or
         mojom.IsPendingAssociatedRemoteKind(kind)):
+      remote_name = name + self._GetPrimitivesNames()["remote"]
       # TODO(rockot): Implement associated interfaces.
-      return "mojo.internal.AssociatedInterfaceProxy(%sProxy)" % (
-          name)
+      return "mojo.internal.AssociatedInterfaceProxy(%s)" % (
+          remote_name)
     if (mojom.IsAssociatedInterfaceRequestKind(kind) or
         mojom.IsPendingAssociatedReceiverKind(kind)):
-      return "mojo.internal.AssociatedInterfaceRequest(%s)" % name
+      request_name = name + self._GetPrimitivesNames()["pending_receiver"]
+      return "mojo.internal.AssociatedInterfaceRequest(%s)" % request_name
 
     return name
 
@@ -810,6 +816,20 @@
 
     return self._ExpressionToText(token)
 
+  def _GetPrimitivesNames(self):
+    if self.use_old_js_lite_bindings_names:
+      return {
+          "remote": "Proxy",
+          "receiver": "",
+          "pending_receiver": "Request",
+      }
+    else:
+      return {
+          "remote": "Remote",
+          "receiver": "Receiver",
+          "pending_receiver": "PendingReceiver",
+      }
+
   def _GenerateHtmlImports(self):
     result = []
     for full_import in self.module.imports:
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni
index 8310a1bc..36b5c9b 100644
--- a/mojo/public/tools/bindings/mojom.gni
+++ b/mojo/public/tools/bindings/mojom.gni
@@ -282,6 +282,10 @@
 #       correct dependency order. Note that this only has an effect if
 #       the |enable_mojom_closure_compile| global arg is set to |true| as well.
 #
+#   use_old_js_lite_bindings_names (optional)
+#       Use old names i.e. FooProxy, Foo, getProxy(), etc. instead of the new
+#       names i.e. FooRemote, FooReceiver, getRemote(), etc.
+#
 # The following parameters are used to support the component build. They are
 # needed so that bindings which are linked with a component can use the same
 # export settings for classes. The first three are for the chromium variant, and
@@ -1267,6 +1271,11 @@
         if (generate_fuzzing) {
           args += [ "--generate_fuzzing" ]
         }
+
+        if (!defined(invoker.use_old_js_lite_bindings_names) ||
+            invoker.use_old_js_lite_bindings_names) {
+          args += [ "--use_old_js_lite_bindings_names" ]
+        }
       }
     }
 
diff --git a/mojo/public/tools/bindings/mojom_bindings_generator.py b/mojo/public/tools/bindings/mojom_bindings_generator.py
index 72f23d86..d8a2118e 100755
--- a/mojo/public/tools/bindings/mojom_bindings_generator.py
+++ b/mojo/public/tools/bindings/mojom_bindings_generator.py
@@ -214,6 +214,7 @@
             variant=args.variant, bytecode_path=args.bytecode_path,
             for_blink=args.for_blink,
             js_bindings_mode=args.js_bindings_mode,
+            use_old_js_lite_bindings_names=args.use_old_js_lite_bindings_names,
             export_attribute=args.export_attribute,
             export_header=args.export_header,
             generate_non_variant_code=args.generate_non_variant_code,
@@ -466,6 +467,11 @@
       "be \"new\" to generate new-style lite JS bindings in addition to the "
       "old, or \"old\" to only generate old bindings.")
   generate_parser.add_argument(
+      "--use_old_js_lite_bindings_names", action="store_true",
+      help="This option only affects the JavaScript bindings. Specifying this "
+      "argument causes the generated new-style lite JS bindings to use the old"
+      "names for primitives e.g. Foo, FooProxy, getProxy(), etc.")
+  generate_parser.add_argument(
       "--export_attribute", default="",
       help="Optional attribute to specify on class declaration to export it "
       "for the component build.")
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/generator.py b/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
index fe4fce2..6487635 100644
--- a/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
@@ -165,7 +165,9 @@
   # files to stdout.
   def __init__(self, module, output_dir=None, typemap=None, variant=None,
                bytecode_path=None, for_blink=False,
-               js_bindings_mode="new", export_attribute=None,
+               js_bindings_mode="new",
+               use_old_js_lite_bindings_names=False,
+               export_attribute=None,
                export_header=None, generate_non_variant_code=False,
                support_lazy_serialization=False, disallow_native_types=False,
                disallow_interfaces=False, generate_message_ids=False,
@@ -177,6 +179,7 @@
     self.bytecode_path = bytecode_path
     self.for_blink = for_blink
     self.js_bindings_mode = js_bindings_mode
+    self.use_old_js_lite_bindings_names = use_old_js_lite_bindings_names
     self.export_attribute = export_attribute
     self.export_header = export_header
     self.generate_non_variant_code = generate_non_variant_code
diff --git a/third_party/blink/web_tests/mojo/bindings-lite-old-names.html b/third_party/blink/web_tests/mojo/bindings-lite-old-names.html
new file mode 100644
index 0000000..9c63bcb
--- /dev/null
+++ b/third_party/blink/web_tests/mojo/bindings-lite-old-names.html
@@ -0,0 +1,209 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings_lite.js"></script>
+<script src="file:///gen/content/test/data/lite_js_old_names_test.mojom-lite.js"></script>
+<script>
+'use strict';
+
+const kTestMessage = 'hello there';
+const kTestNumbers = [0, 1, 1, 2, 3, 5, 8, 13, 21];
+
+class TargetImpl {
+  constructor() {
+    this.numPokes = 0;
+    this.target = new liteJsOldNamesTest.mojom.TestMessageTarget(this);
+  }
+
+  poke() { this.numPokes++; }
+  ping() { return Promise.resolve(); }
+  repeat(message, numbers) { return {message: message, numbers: numbers}; }
+  flatten(values) {}
+  flattenUnions(unions) {}
+  requestSubinterface(request, client) {}
+}
+
+promise_test(() => {
+  let impl = new TargetImpl;
+  let proxy = impl.target.$.createProxy();
+  proxy.poke();
+  return proxy.ping().then(() => {
+    assert_equals(impl.numPokes, 1);
+  });
+}, 'messages with replies return Promises that resolve on reply received');
+
+promise_test(() => {
+  let impl = new TargetImpl;
+  let proxy = impl.target.$.createProxy();
+  return proxy.repeat(kTestMessage, kTestNumbers)
+              .then(reply => {
+                assert_equals(reply.message, kTestMessage);
+                assert_array_equals(reply.numbers, kTestNumbers);
+              });
+}, 'implementations can reply with multiple reply arguments');
+
+promise_test(async (t) => {
+  const impl = new TargetImpl;
+  const proxy = impl.target.$.createProxy();
+
+  await proxy.ping();
+  proxy.$.close();
+
+  await promise_rejects(t, new Error(), proxy.ping());
+}, 'after the pipe is closed all future calls should fail');
+
+promise_test(async (t) => {
+  const impl = new TargetImpl;
+  const proxy = impl.target.$.createProxy();
+
+  // None of these promises should successfully resolve because we are
+  // immediately closing the pipe.
+  const promises = []
+  for (let i = 0; i < 10; i++) {
+    promises.push(proxy.ping());
+  }
+
+  proxy.$.close();
+
+  for (const promise of promises) {
+    await promise_rejects(t, new Error(), promise);
+  }
+}, 'closing the pipe drops any pending messages');
+
+promise_test(() => {
+  let impl = new TargetImpl;
+
+  // Intercept any browser-bound request for TestMessageTarget and bind it
+  // instead to the local |impl| object.
+  let interceptor = new MojoInterfaceInterceptor(
+    liteJsOldNamesTest.mojom.TestMessageTarget.$interfaceName);
+  interceptor.oninterfacerequest = e => {
+    impl.target.$.bindHandle(e.handle);
+  }
+  interceptor.start();
+
+  let proxy = liteJsOldNamesTest.mojom.TestMessageTarget.getProxy();
+  proxy.poke();
+
+  return proxy.ping().then(() => {
+    assert_equals(impl.numPokes, 1);
+  });
+}, 'getProxy() attempts to send requests to the frame host');
+
+promise_test(() => {
+  let router = new liteJsOldNamesTest.mojom.TestMessageTargetCallbackRouter;
+  let proxy = router.$.createProxy();
+  return new Promise(resolve => {
+    router.poke.addListener(resolve);
+    proxy.poke();
+  });
+}, 'basic generated CallbackRouter behavior works as intended');
+
+promise_test(() => {
+  let router = new liteJsOldNamesTest.mojom.TestMessageTargetCallbackRouter;
+  let proxy = router.$.createProxy();
+  let numPokes = 0;
+  router.poke.addListener(() => ++numPokes);
+  router.ping.addListener(() => Promise.resolve());
+  proxy.poke();
+  return proxy.ping().then(() => assert_equals(numPokes, 1));
+}, 'CallbackRouter listeners can reply to messages');
+
+promise_test(() => {
+  let router = new liteJsOldNamesTest.mojom.TestMessageTargetCallbackRouter;
+  let proxy = router.$.createProxy();
+  router.repeat.addListener(
+    (message, numbers) => ({message: message, numbers: numbers}));
+  return proxy.repeat(kTestMessage, kTestNumbers)
+              .then(reply => {
+                assert_equals(reply.message, kTestMessage);
+                assert_array_equals(reply.numbers, kTestNumbers);
+              });
+}, 'CallbackRouter listeners can reply with multiple reply arguments');
+
+promise_test(() => {
+  let targetRouter = new liteJsOldNamesTest.mojom.TestMessageTargetCallbackRouter;
+  let targetProxy = targetRouter.$.createProxy();
+  let subinterfaceRouter = new liteJsOldNamesTest.mojom.SubinterfaceCallbackRouter;
+  targetRouter.requestSubinterface.addListener((request, client) => {
+    let values = [];
+    subinterfaceRouter.$.bindHandle(request.handle);
+    subinterfaceRouter.push.addListener(value => values.push(value));
+    subinterfaceRouter.flush.addListener(() => {
+      client.didFlush(values);
+      values = [];
+    });
+  });
+
+  let clientRouter = new liteJsOldNamesTest.mojom.SubinterfaceClientCallbackRouter;
+  let subinterfaceProxy = new liteJsOldNamesTest.mojom.SubinterfaceProxy;
+  targetProxy.requestSubinterface(
+    subinterfaceProxy.$.createRequest(), clientRouter.$.createProxy());
+  return new Promise(resolve => {
+    clientRouter.didFlush.addListener(values => {
+      assert_array_equals(values, kTestNumbers);
+      resolve();
+    });
+
+    kTestNumbers.forEach(n => subinterfaceProxy.push(n));
+    subinterfaceProxy.flush();
+  });
+}, 'can send and receive interface requests and proxies');
+
+promise_test(() => {
+  const targetRouter = new liteJsOldNamesTest.mojom.TestMessageTargetCallbackRouter;
+  const targetProxy = targetRouter.$.createProxy();
+  targetRouter.flatten.addListener(values => ({values: values.map(v => v.x)}));
+  return targetProxy.flatten([{x: 1}, {x: 2}, {x: 3}]).then(reply => {
+    assert_array_equals(reply.values, [1, 2, 3]);
+  });
+}, 'regression test for complex array serialization');
+
+promise_test(() => {
+  const targetRouter = new liteJsOldNamesTest.mojom.TestMessageTargetCallbackRouter;
+  const targetProxy = targetRouter.$.createProxy();
+  targetRouter.flattenUnions.addListener(unions => {
+    return {x: unions.filter(u => u.x !== undefined).map(u => u.x),
+            s: unions.filter(u => u.s !== undefined).map(u => u.s.x)};
+  });
+
+  return targetProxy.flattenUnions(
+    [{x: 1}, {x: 2}, {s: {x: 3}}, {s: {x: 4}}, {x: 5}, {s: {x: 6}}])
+                    .then(reply => {
+                      assert_array_equals(reply.x, [1, 2, 5]);
+                      assert_array_equals(reply.s, [3, 4, 6]);
+                    });
+}, 'can serialize and deserialize unions');
+
+promise_test(() => {
+  let impl = new TargetImpl;
+  let proxy = impl.target.$.createProxy();
+
+  // Poke a bunch of times. These should never race with the assertion below,
+  // because the |flushForTesting| request/response is ordered against other
+  // messages on |proxy|.
+  const kNumPokes = 100;
+  for (let i = 0; i < kNumPokes; ++i)
+    proxy.poke();
+  return proxy.$.flushForTesting().then(() => {
+    assert_equals(impl.numPokes, kNumPokes);
+  });
+}, 'can use generated flushForTesting API for synchronization in tests');
+
+promise_test(async(t) => {
+  const impl = new TargetImpl;
+  const proxy = impl.target.$.createProxy();
+  const disconnectPromise = new Promise(resolve => impl.target.onConnectionError.addListener(resolve));
+  proxy.$.close();
+  return disconnectPromise;
+}, 'InterfaceTarget connection error handler runs when set on an Interface object');
+
+promise_test(() => {
+  const router = new liteJsOldNamesTest.mojom.TestMessageTargetCallbackRouter;
+  const proxy = router.$.createProxy();
+  const disconnectPromise = new Promise(resolve => router.onConnectionError.addListener(resolve));
+  proxy.$.close();
+  return disconnectPromise;
+}, 'InterfaceTarget connection error handler runs when set on an InterfaceCallbackRouter object');
+
+</script>
diff --git a/third_party/blink/web_tests/mojo/bindings-lite.html b/third_party/blink/web_tests/mojo/bindings-lite.html
index 5026483..8e5af734 100644
--- a/third_party/blink/web_tests/mojo/bindings-lite.html
+++ b/third_party/blink/web_tests/mojo/bindings-lite.html
@@ -12,7 +12,7 @@
 class TargetImpl {
   constructor() {
     this.numPokes = 0;
-    this.target = new liteJsTest.mojom.TestMessageTarget(this);
+    this.target = new liteJsTest.mojom.TestMessageTargetReceiver(this);
   }
 
   poke() { this.numPokes++; }
@@ -25,17 +25,17 @@
 
 promise_test(() => {
   let impl = new TargetImpl;
-  let proxy = impl.target.$.createProxy();
-  proxy.poke();
-  return proxy.ping().then(() => {
+  let remote = impl.target.$.bindNewPipeAndPassRemote();
+  remote.poke();
+  return remote.ping().then(() => {
     assert_equals(impl.numPokes, 1);
   });
 }, 'messages with replies return Promises that resolve on reply received');
 
 promise_test(() => {
   let impl = new TargetImpl;
-  let proxy = impl.target.$.createProxy();
-  return proxy.repeat(kTestMessage, kTestNumbers)
+  let remote = impl.target.$.bindNewPipeAndPassRemote();
+  return remote.repeat(kTestMessage, kTestNumbers)
       .then(reply => {
         assert_equals(reply.message, kTestMessage);
         assert_array_equals(reply.numbers, kTestNumbers);
@@ -44,26 +44,26 @@
 
 promise_test(async (t) => {
   const impl = new TargetImpl;
-  const proxy = impl.target.$.createProxy();
+  const remote = impl.target.$.bindNewPipeAndPassRemote();
 
-  await proxy.ping();
-  proxy.$.close();
+  await remote.ping();
+  remote.$.close();
 
-  await promise_rejects(t, new Error(), proxy.ping());
+  await promise_rejects(t, new Error(), remote.ping());
 }, 'after the pipe is closed all future calls should fail');
 
 promise_test(async (t) => {
   const impl = new TargetImpl;
-  const proxy = impl.target.$.createProxy();
+  const remote = impl.target.$.bindNewPipeAndPassRemote();
 
   // None of these promises should successfully resolve because we are
   // immediately closing the pipe.
   const promises = []
   for (let i = 0; i < 10; i++) {
-    promises.push(proxy.ping());
+    promises.push(remote.ping());
   }
 
-  proxy.$.close();
+  remote.$.close();
 
   for (const promise of promises) {
     await promise_rejects(t, new Error(), promise);
@@ -82,38 +82,38 @@
   }
   interceptor.start();
 
-  let proxy = liteJsTest.mojom.TestMessageTarget.getProxy();
-  proxy.poke();
-  return proxy.ping().then(() => {
+  let remote = liteJsTest.mojom.TestMessageTarget.getRemote();
+  remote.poke();
+  return remote.ping().then(() => {
     assert_equals(impl.numPokes, 1);
   });
-}, 'getProxy() attempts to send requests to the frame host');
+}, 'getRemote() attempts to send requests to the frame host');
 
 promise_test(() => {
   let router = new liteJsTest.mojom.TestMessageTargetCallbackRouter;
-  let proxy = router.$.createProxy();
+  let remote = router.$.bindNewPipeAndPassRemote();
   return new Promise(resolve => {
     router.poke.addListener(resolve);
-    proxy.poke();
+    remote.poke();
   });
 }, 'basic generated CallbackRouter behavior works as intended');
 
 promise_test(() => {
   let router = new liteJsTest.mojom.TestMessageTargetCallbackRouter;
-  let proxy = router.$.createProxy();
+  let remote = router.$.bindNewPipeAndPassRemote();
   let numPokes = 0;
   router.poke.addListener(() => ++numPokes);
   router.ping.addListener(() => Promise.resolve());
-  proxy.poke();
-  return proxy.ping().then(() => assert_equals(numPokes, 1));
+  remote.poke();
+  return remote.ping().then(() => assert_equals(numPokes, 1));
 }, 'CallbackRouter listeners can reply to messages');
 
 promise_test(() => {
   let router = new liteJsTest.mojom.TestMessageTargetCallbackRouter;
-  let proxy = router.$.createProxy();
+  let remote = router.$.bindNewPipeAndPassRemote();
   router.repeat.addListener(
       (message, numbers) => ({message: message, numbers: numbers}));
-  return proxy.repeat(kTestMessage, kTestNumbers)
+  return remote.repeat(kTestMessage, kTestNumbers)
       .then(reply => {
         assert_equals(reply.message, kTestMessage);
         assert_array_equals(reply.numbers, kTestNumbers);
@@ -122,7 +122,7 @@
 
 promise_test(() => {
   let targetRouter = new liteJsTest.mojom.TestMessageTargetCallbackRouter;
-  let targetProxy = targetRouter.$.createProxy();
+  let targetRemote = targetRouter.$.bindNewPipeAndPassRemote();
   let subinterfaceRouter = new liteJsTest.mojom.SubinterfaceCallbackRouter;
   targetRouter.requestSubinterface.addListener((request, client) => {
     let values = [];
@@ -135,38 +135,39 @@
   });
 
   let clientRouter = new liteJsTest.mojom.SubinterfaceClientCallbackRouter;
-  let subinterfaceProxy = new liteJsTest.mojom.SubinterfaceProxy;
-  targetProxy.requestSubinterface(
-      subinterfaceProxy.$.createRequest(), clientRouter.$.createProxy());
+  let subinterfaceRemote = new liteJsTest.mojom.SubinterfaceRemote;
+  targetRemote.requestSubinterface(
+    subinterfaceRemote.$.bindNewPipeAndPassReceiver(),
+    clientRouter.$.bindNewPipeAndPassRemote());
   return new Promise(resolve => {
     clientRouter.didFlush.addListener(values => {
       assert_array_equals(values, kTestNumbers);
       resolve();
     });
 
-    kTestNumbers.forEach(n => subinterfaceProxy.push(n));
-    subinterfaceProxy.flush();
+    kTestNumbers.forEach(n => subinterfaceRemote.push(n));
+    subinterfaceRemote.flush();
   });
 }, 'can send and receive interface requests and proxies');
 
 promise_test(() => {
   const targetRouter = new liteJsTest.mojom.TestMessageTargetCallbackRouter;
-  const targetProxy = targetRouter.$.createProxy();
+  const targetRemote = targetRouter.$.bindNewPipeAndPassRemote();
   targetRouter.flatten.addListener(values => ({values: values.map(v => v.x)}));
-  return targetProxy.flatten([{x: 1}, {x: 2}, {x: 3}]).then(reply => {
+  return targetRemote.flatten([{x: 1}, {x: 2}, {x: 3}]).then(reply => {
     assert_array_equals(reply.values, [1, 2, 3]);
   });
 }, 'regression test for complex array serialization');
 
 promise_test(() => {
   const targetRouter = new liteJsTest.mojom.TestMessageTargetCallbackRouter;
-  const targetProxy = targetRouter.$.createProxy();
+  const targetRemote = targetRouter.$.bindNewPipeAndPassRemote();
   targetRouter.flattenUnions.addListener(unions => {
     return {x: unions.filter(u => u.x !== undefined).map(u => u.x),
             s: unions.filter(u => u.s !== undefined).map(u => u.s.x)};
   });
 
-  return targetProxy.flattenUnions(
+  return targetRemote.flattenUnions(
       [{x: 1}, {x: 2}, {s: {x: 3}}, {s: {x: 4}}, {x: 5}, {s: {x: 6}}])
       .then(reply => {
     assert_array_equals(reply.x, [1, 2, 5]);
@@ -176,32 +177,32 @@
 
 promise_test(() => {
   let impl = new TargetImpl;
-  let proxy = impl.target.$.createProxy();
+  let remote = impl.target.$.bindNewPipeAndPassRemote();
 
   // Poke a bunch of times. These should never race with the assertion below,
   // because the |flushForTesting| request/response is ordered against other
-  // messages on |proxy|.
+  // messages on |remote|.
   const kNumPokes = 100;
   for (let i = 0; i < kNumPokes; ++i)
-    proxy.poke();
-  return proxy.$.flushForTesting().then(() => {
+    remote.poke();
+  return remote.$.flushForTesting().then(() => {
     assert_equals(impl.numPokes, kNumPokes);
   });
 }, 'can use generated flushForTesting API for synchronization in tests');
 
 promise_test(async(t) => {
   const impl = new TargetImpl;
-  const proxy = impl.target.$.createProxy();
+  const remote = impl.target.$.bindNewPipeAndPassRemote();
   const disconnectPromise = new Promise(resolve => impl.target.onConnectionError.addListener(resolve));
-  proxy.$.close();
+  remote.$.close();
   return disconnectPromise;
 }, 'InterfaceTarget connection error handler runs when set on an Interface object');
 
 promise_test(() => {
   const router = new liteJsTest.mojom.TestMessageTargetCallbackRouter;
-  const proxy = router.$.createProxy();
+  const remote = router.$.bindNewPipeAndPassRemote();
   const disconnectPromise = new Promise(resolve => router.onConnectionError.addListener(resolve));
-  proxy.$.close();
+  remote.$.close();
   return disconnectPromise;
   }, 'InterfaceTarget connection error handler runs when set on an InterfaceCallbackRouter object');