[remoting host] Implement a mojo interface broker and use it for WebAuthnProxy

This is a different take from crrev.com/c/3236834 on resolving the
issue of only one isolated connection being allowed per server-client
pair.

This CL:

1. introduces a new PendingRemote/PendingReceiver broker interface and
   implements it on ChromotingHost
2. Introduces a ChromotingHostServicesClient class to allow the client
   to easily connect to the server
3. Makes WebAuthnProxy use the new interface for binding, instead of
   maintaining its own isolated connection.

Bug: 1225870
Change-Id: I4a85666b70439f10008c0bc879429e5435b710ce
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3246467
Commit-Queue: Yuwei Huang <[email protected]>
Reviewed-by: Alex Gough <[email protected]>
Reviewed-by: Joe Downing <[email protected]>
Cr-Commit-Position: refs/heads/main@{#937618}
diff --git a/remoting/host/chromoting_host_services_client.cc b/remoting/host/chromoting_host_services_client.cc
new file mode 100644
index 0000000..6f6e687
--- /dev/null
+++ b/remoting/host/chromoting_host_services_client.cc
@@ -0,0 +1,67 @@
+// Copyright 2021 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 "remoting/host/chromoting_host_services_client.h"
+
+#include "base/bind.h"
+#include "base/sequence_checker.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/system/isolated_connection.h"
+#include "remoting/host/ipc_constants.h"
+#include "remoting/host/mojom/chromoting_host_services.mojom.h"
+
+namespace remoting {
+
+ChromotingHostServicesClient::ChromotingHostServicesClient()
+    : server_name_(GetChromotingHostServicesServerName()) {}
+
+ChromotingHostServicesClient::~ChromotingHostServicesClient() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+mojom::ChromotingHostServices* ChromotingHostServicesClient::Get() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!const_cast<ChromotingHostServicesClient*>(this)->EnsureConnection()) {
+    return nullptr;
+  }
+
+  return remote_.get();
+}
+
+bool ChromotingHostServicesClient::EnsureConnection() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (remote_.is_bound()) {
+    return true;
+  }
+
+  auto endpoint = mojo::NamedPlatformChannel::ConnectToServer(server_name_);
+  if (!endpoint.is_valid()) {
+    LOG(WARNING) << "Cannot connect to IPC through server name " << server_name_
+                 << ". Endpoint is invalid.";
+    return false;
+  }
+  connection_ = std::make_unique<mojo::IsolatedConnection>();
+  mojo::PendingRemote<mojom::ChromotingHostServices> pending_remote(
+      connection_->Connect(std::move(endpoint)), /* version= */ 0);
+  if (!pending_remote.is_valid()) {
+    LOG(WARNING) << "Invalid message pipe.";
+    connection_.reset();
+    return false;
+  }
+  remote_.Bind(std::move(pending_remote));
+  remote_.set_disconnect_handler(base::BindOnce(
+      &ChromotingHostServicesClient::OnDisconnected, base::Unretained(this)));
+  return true;
+}
+
+void ChromotingHostServicesClient::OnDisconnected() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  remote_.reset();
+  connection_.reset();
+}
+
+}  // namespace remoting