iioservice: Add SensorDbus & Remove SensorClient in libiioservice_ipc

This commit adds SensorServerDbus and SensorClientDbus that help
iioservice and sensor clients bootstrap mojo connection and connect to
SensorHalDispatcher in Chromium. It also removes SensorClient, an
unnecessary SensorHalClient implementation, as sensor clients can easily
implement the interface themselves.

BUG=chromium:1006141
TEST=builds and run on iioservice and iioservice_simpleclient.

Change-Id: I12d624da945e143320ebfad32dab60549d064e71
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2483720
Reviewed-by: Gwendal Grignou <gwendal@chromium.org>
Tested-by: Cheng-Hao Yang <chenghaoyang@chromium.org>
Commit-Queue: Cheng-Hao Yang <chenghaoyang@chromium.org>
diff --git a/iioservice/README.md b/iioservice/README.md
index cdc8399..cac5494 100644
--- a/iioservice/README.md
+++ b/iioservice/README.md
@@ -1,13 +1,15 @@
 # Chrome OS Iio Service
 
-The repository hosts the core Chrome OS platform iioservice components, including:
+The repository hosts the core Chrome OS platform iioservice components,
+including:
 
 - Mojo IPC library for clients to connect to iioservice
 
 ## Mojo IPC library
 
-This library provides mojo interfaces to connect to sensor_dispatcher and
-iioservice, and C++ utility functions and classes to establish mojo channels.
+This library provides mojo interfaces and SensorServerDbus and SensorClientDbus
+to help iioservice and sensor clients bootstrap Mojo connection and connect to
+SensorHalDispatcher in Chromium.
 
 ## Daemon iioservice
 
diff --git a/iioservice/libiioservice_ipc/BUILD.gn b/iioservice/libiioservice_ipc/BUILD.gn
index 1fe0658..9a85c83 100644
--- a/iioservice/libiioservice_ipc/BUILD.gn
+++ b/iioservice/libiioservice_ipc/BUILD.gn
@@ -19,7 +19,11 @@
 }
 
 shared_library("libiioservice_ipc") {
-  sources = [ "//iioservice/libiioservice_ipc/sensor_client.cc" ]
+  sources = [
+    "//iioservice/libiioservice_ipc/sensor_client_dbus.cc",
+    "//iioservice/libiioservice_ipc/sensor_dbus.cc",
+    "//iioservice/libiioservice_ipc/sensor_server_dbus.cc",
+  ]
   output_name = "libiioservice_ipc"
   include_dirs = [
     "//iioservice",
diff --git a/iioservice/libiioservice_ipc/sensor_client.cc b/iioservice/libiioservice_ipc/sensor_client.cc
deleted file mode 100644
index 5d42064..0000000
--- a/iioservice/libiioservice_ipc/sensor_client.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2020 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "iioservice/libiioservice_ipc/sensor_client.h"
-
-#include <memory>
-#include <utility>
-
-#include <mojo/core/embedder/embedder.h>
-
-#include "iioservice/include/common.h"
-#include "iioservice/include/constants.h"
-
-namespace iioservice {
-
-// static
-void SensorClient::SensorClientDeleter(SensorClient* client) {
-  if (client == nullptr)
-    return;
-
-  if (!client->ipc_task_runner_->RunsTasksInCurrentSequence()) {
-    client->ipc_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&SensorClient::SensorClientDeleter, client));
-    return;
-  }
-
-  delete client;
-}
-
-// static
-SensorClient::ScopedSensorClient SensorClient::Create(
-    scoped_refptr<base::SequencedTaskRunner> ipc_task_runner,
-    mojo::PendingReceiver<cros::mojom::SensorHalClient> pending_receiver,
-    SensorServiceReceivedCallback sensor_service_received_callback,
-    ClientOnFailureCallback client_on_failure_callback) {
-  DCHECK(ipc_task_runner->RunsTasksInCurrentSequence());
-
-  ScopedSensorClient client(
-      new SensorClient(ipc_task_runner, std::move(pending_receiver),
-                       std::move(sensor_service_received_callback),
-                       std::move(client_on_failure_callback)),
-      SensorClientDeleter);
-
-  return client;
-}
-
-void SensorClient::SetUpChannel(
-    mojo::PendingRemote<cros::mojom::SensorService> sensor_service_ptr) {
-  DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
-
-  LOGF(INFO) << "Received SensorService from sensor HAL dispatcher";
-
-  sensor_service_received_callback_.Run(std::move(sensor_service_ptr));
-}
-
-SensorClient::SensorClient(
-    scoped_refptr<base::SequencedTaskRunner> ipc_task_runner,
-    mojo::PendingReceiver<cros::mojom::SensorHalClient> pending_receiver,
-    SensorServiceReceivedCallback sensor_service_received_callback,
-    ClientOnFailureCallback client_on_failure_callback)
-    : ipc_task_runner_(ipc_task_runner),
-      receiver_(this),
-      sensor_service_received_callback_(
-          std::move(sensor_service_received_callback)),
-      client_on_failure_callback_(std::move(client_on_failure_callback)) {
-  DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
-
-  receiver_.Bind(std::move(pending_receiver), ipc_task_runner_);
-  receiver_.set_disconnect_handler(
-      base::BindOnce(&SensorClient::OnClientError, base::Unretained(this)));
-  LOGF(INFO) << "Connected to broker";
-}
-
-void SensorClient::OnClientError() {
-  DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(receiver_.is_bound());
-  DCHECK(!client_on_failure_callback_.is_null());
-
-  LOGF(ERROR) << "Connection to broker lost";
-  receiver_.reset();
-  std::move(client_on_failure_callback_).Run();
-}
-
-}  // namespace iioservice
diff --git a/iioservice/libiioservice_ipc/sensor_client.h b/iioservice/libiioservice_ipc/sensor_client.h
deleted file mode 100644
index 4125c24..0000000
--- a/iioservice/libiioservice_ipc/sensor_client.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2020 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IIOSERVICE_LIBIIOSERVICE_IPC_SENSOR_CLIENT_H_
-#define IIOSERVICE_LIBIIOSERVICE_IPC_SENSOR_CLIENT_H_
-
-#include <memory>
-
-#include <base/bind.h>
-#include <base/sequenced_task_runner.h>
-#include <mojo/public/cpp/bindings/receiver.h>
-
-#include "mojo/cros_sensor_service.mojom.h"
-#include "mojo/sensor.mojom.h"
-
-#include "iioservice/include/export.h"
-
-namespace iioservice {
-
-// A helper class to connect to Chromium via dbus and wait for
-// mojo::PendingRemote<SensorService> connecting to iioservice.
-// Upon disconnection errors from iioservice, the user doesn't need to do
-// anything except for waiting a new remote's arrival again.
-class IIOSERVICE_EXPORT SensorClient final
-    : public cros::mojom::SensorHalClient {
- public:
-  using SensorServiceReceivedCallback = base::RepeatingCallback<void(
-      mojo::PendingRemote<cros::mojom::SensorService>)>;
-  using ClientOnFailureCallback = base::OnceCallback<void()>;
-
-  static void SensorClientDeleter(SensorClient* client);
-  using ScopedSensorClient =
-      std::unique_ptr<SensorClient, decltype(&SensorClientDeleter)>;
-
-  // Create a SensorClient instance by providing a task runner for mojo IPC, a
-  // callback to receive SensorService remote from |SetUpChannel|, and a
-  // callback to abort when an error occurs.
-  // Should be used on |ipc_task_runner|.
-  static ScopedSensorClient Create(
-      scoped_refptr<base::SequencedTaskRunner> ipc_task_runner,
-      mojo::PendingReceiver<cros::mojom::SensorHalClient> pending_receiver,
-      SensorServiceReceivedCallback sensor_service_received_callback,
-      ClientOnFailureCallback client_on_failure_callback);
-
-  // Implementation of cros::mojom::SensorHalClient. Called by sensor HAL
-  // dispatcher to provide the SensorService interface.
-  void SetUpChannel(mojo::PendingRemote<cros::mojom::SensorService>
-                        sensor_service_ptr) override;
-
- private:
-  SensorClient(
-      scoped_refptr<base::SequencedTaskRunner> ipc_task_runner,
-      mojo::PendingReceiver<cros::mojom::SensorHalClient> pending_receiver,
-      SensorServiceReceivedCallback sensor_service_received_callback,
-      ClientOnFailureCallback client_on_failure_callback);
-
-  void OnClientError();
-
-  scoped_refptr<base::SequencedTaskRunner> ipc_task_runner_;
-
-  mojo::Receiver<cros::mojom::SensorHalClient> receiver_;
-  SensorServiceReceivedCallback sensor_service_received_callback_;
-  ClientOnFailureCallback client_on_failure_callback_;
-
-  base::WeakPtrFactory<SensorClient> weak_factory_{this};
-};
-
-}  // namespace iioservice
-
-#endif  // IIOSERVICE_LIBIIOSERVICE_IPC_SENSOR_CLIENT_H_
diff --git a/iioservice/libiioservice_ipc/sensor_client_dbus.cc b/iioservice/libiioservice_ipc/sensor_client_dbus.cc
new file mode 100644
index 0000000..dcd70f7
--- /dev/null
+++ b/iioservice/libiioservice_ipc/sensor_client_dbus.cc
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "iioservice/libiioservice_ipc/sensor_client_dbus.h"
+
+#include <chromeos/dbus/service_constants.h>
+#include <dbus/object_proxy.h>
+
+namespace iioservice {
+
+void SensorClientDbus::BootstrapMojoConnection() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sensor_sequence_checker_);
+  DCHECK(sensor_bus_);
+
+  dbus::ObjectProxy* proxy = sensor_bus_->GetObjectProxy(
+      ::mojo_connection_service::kMojoConnectionServiceServiceName,
+      dbus::ObjectPath(
+          ::mojo_connection_service::kMojoConnectionServiceServicePath));
+
+  dbus::MethodCall method_call(
+      ::mojo_connection_service::kMojoConnectionServiceInterface,
+      ::mojo_connection_service::
+          kBootstrapMojoConnectionForSensorClientsMethod);
+  dbus::MessageWriter writer(&method_call);
+  proxy->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+                    base::BindOnce(&SensorClientDbus::OnBootstrapMojoResponse,
+                                   weak_factory_.GetWeakPtr()));
+}
+
+void SensorClientDbus::OnInvitationReceived(
+    mojo::IncomingInvitation invitation) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sensor_sequence_checker_);
+
+  // Bind primordial message pipe to a SensorHalClient implementation.
+  OnClientReceived(mojo::PendingReceiver<cros::mojom::SensorHalClient>(
+      invitation.ExtractMessagePipe(
+          ::mojo_connection_service::
+              kBootstrapMojoConnectionForSensorClientsChannelToken)));
+}
+
+}  // namespace iioservice
diff --git a/iioservice/libiioservice_ipc/sensor_client_dbus.h b/iioservice/libiioservice_ipc/sensor_client_dbus.h
new file mode 100644
index 0000000..3979c90
--- /dev/null
+++ b/iioservice/libiioservice_ipc/sensor_client_dbus.h
@@ -0,0 +1,36 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IIOSERVICE_LIBIIOSERVICE_IPC_SENSOR_CLIENT_DBUS_H_
+#define IIOSERVICE_LIBIIOSERVICE_IPC_SENSOR_CLIENT_DBUS_H_
+
+#include <base/memory/weak_ptr.h>
+
+#include "iioservice/include/export.h"
+#include "iioservice/libiioservice_ipc/sensor_dbus.h"
+#include "mojo/cros_sensor_service.mojom.h"
+
+namespace iioservice {
+
+class IIOSERVICE_EXPORT SensorClientDbus : public SensorDbus {
+ public:
+  virtual ~SensorClientDbus() = default;
+
+  void BootstrapMojoConnection() override;
+
+ protected:
+  SensorClientDbus() = default;
+
+  void OnInvitationReceived(mojo::IncomingInvitation invitation) override;
+
+  virtual void OnClientReceived(
+      mojo::PendingReceiver<cros::mojom::SensorHalClient> client) = 0;
+
+ private:
+  base::WeakPtrFactory<SensorClientDbus> weak_factory_{this};
+};
+
+}  // namespace iioservice
+
+#endif  // IIOSERVICE_LIBIIOSERVICE_IPC_SENSOR_CLIENT_DBUS_H_
diff --git a/iioservice/libiioservice_ipc/sensor_dbus.cc b/iioservice/libiioservice_ipc/sensor_dbus.cc
new file mode 100644
index 0000000..7b5df5d
--- /dev/null
+++ b/iioservice/libiioservice_ipc/sensor_dbus.cc
@@ -0,0 +1,74 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "iioservice/libiioservice_ipc/sensor_dbus.h"
+
+#include <utility>
+
+#include <base/bind.h>
+#include <base/files/file_util.h>
+#include <base/files/scoped_file.h>
+#include <base/threading/thread_task_runner_handle.h>
+#include <chromeos/dbus/service_constants.h>
+
+namespace iioservice {
+
+namespace {
+
+constexpr int kDelayBootstrapInMilliseconds = 1000;
+
+}
+
+void SensorDbus::SetBus(dbus::Bus* sensor_bus) {
+  sensor_bus_ = sensor_bus;
+}
+
+void SensorDbus::OnBootstrapMojoResponse(dbus::Response* response) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sensor_sequence_checker_);
+
+  if (!response) {
+    LOG(ERROR) << ::mojo_connection_service::kMojoConnectionServiceServiceName
+               << " D-Bus call failed";
+    ReconnectMojoWithDelay();
+    return;
+  }
+
+  base::ScopedFD file_handle;
+  dbus::MessageReader reader(response);
+
+  if (!reader.PopFileDescriptor(&file_handle)) {
+    LOG(ERROR) << "Couldn't extract file descriptor from D-Bus call";
+    ReconnectMojoWithDelay();
+    return;
+  }
+
+  if (!file_handle.is_valid()) {
+    LOG(ERROR) << "ScopedFD extracted from D-Bus call was invalid (i.e. empty)";
+    ReconnectMojoWithDelay();
+    return;
+  }
+
+  if (!base::SetCloseOnExec(file_handle.get())) {
+    PLOG(ERROR) << "Failed setting FD_CLOEXEC on file descriptor";
+    ReconnectMojoWithDelay();
+    return;
+  }
+
+  // Connect to mojo in the requesting process.
+  OnInvitationReceived(
+      mojo::IncomingInvitation::Accept(mojo::PlatformChannelEndpoint(
+          mojo::PlatformHandle(std::move(file_handle)))));
+}
+
+void SensorDbus::ReconnectMojoWithDelay() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sensor_sequence_checker_);
+
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&SensorDbus::BootstrapMojoConnection,
+                     weak_factory_.GetWeakPtr()),
+      base::TimeDelta::FromMilliseconds(kDelayBootstrapInMilliseconds));
+}
+
+}  // namespace iioservice
diff --git a/iioservice/libiioservice_ipc/sensor_dbus.h b/iioservice/libiioservice_ipc/sensor_dbus.h
new file mode 100644
index 0000000..73af94f
--- /dev/null
+++ b/iioservice/libiioservice_ipc/sensor_dbus.h
@@ -0,0 +1,45 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IIOSERVICE_LIBIIOSERVICE_IPC_SENSOR_DBUS_H_
+#define IIOSERVICE_LIBIIOSERVICE_IPC_SENSOR_DBUS_H_
+
+#include <base/memory/weak_ptr.h>
+#include <base/sequence_checker.h>
+#include <dbus/bus.h>
+#include <dbus/message.h>
+#include <mojo/public/cpp/system/invitation.h>
+
+#include "iioservice/include/export.h"
+
+namespace iioservice {
+
+class IIOSERVICE_EXPORT SensorDbus {
+ public:
+  virtual ~SensorDbus() = default;
+
+  // |SetBus| before using |BootstrapMojoConnection|.
+  void SetBus(dbus::Bus* sensor_bus);
+
+  virtual void BootstrapMojoConnection() = 0;
+
+ protected:
+  SensorDbus() = default;
+
+  void OnBootstrapMojoResponse(dbus::Response* response);
+  virtual void ReconnectMojoWithDelay();
+
+  virtual void OnInvitationReceived(mojo::IncomingInvitation invitation) = 0;
+
+  dbus::Bus* sensor_bus_;
+
+  SEQUENCE_CHECKER(sensor_sequence_checker_);
+
+ private:
+  base::WeakPtrFactory<SensorDbus> weak_factory_{this};
+};
+
+}  // namespace iioservice
+
+#endif  // IIOSERVICE_LIBIIOSERVICE_IPC_SENSOR_DBUS_H_
diff --git a/iioservice/libiioservice_ipc/sensor_server_dbus.cc b/iioservice/libiioservice_ipc/sensor_server_dbus.cc
new file mode 100644
index 0000000..b47e890
--- /dev/null
+++ b/iioservice/libiioservice_ipc/sensor_server_dbus.cc
@@ -0,0 +1,41 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "iioservice/libiioservice_ipc/sensor_server_dbus.h"
+
+#include <chromeos/dbus/service_constants.h>
+#include <dbus/object_proxy.h>
+
+namespace iioservice {
+
+void SensorServerDbus::BootstrapMojoConnection() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sensor_sequence_checker_);
+  DCHECK(sensor_bus_);
+
+  dbus::ObjectProxy* proxy = sensor_bus_->GetObjectProxy(
+      ::mojo_connection_service::kMojoConnectionServiceServiceName,
+      dbus::ObjectPath(
+          ::mojo_connection_service::kMojoConnectionServiceServicePath));
+
+  dbus::MethodCall method_call(
+      ::mojo_connection_service::kMojoConnectionServiceInterface,
+      ::mojo_connection_service::kBootstrapMojoConnectionForIioServiceMethod);
+  dbus::MessageWriter writer(&method_call);
+  proxy->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+                    base::BindOnce(&SensorServerDbus::OnBootstrapMojoResponse,
+                                   weak_factory_.GetWeakPtr()));
+}
+
+void SensorServerDbus::OnInvitationReceived(
+    mojo::IncomingInvitation invitation) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sensor_sequence_checker_);
+
+  // Bind primordial message pipe to a SensorHalServer implementation.
+  OnServerReceived(mojo::PendingReceiver<cros::mojom::SensorHalServer>(
+      invitation.ExtractMessagePipe(
+          ::mojo_connection_service::
+              kBootstrapMojoConnectionForIioServiceChannelToken)));
+}
+
+}  // namespace iioservice
diff --git a/iioservice/libiioservice_ipc/sensor_server_dbus.h b/iioservice/libiioservice_ipc/sensor_server_dbus.h
new file mode 100644
index 0000000..2e62893
--- /dev/null
+++ b/iioservice/libiioservice_ipc/sensor_server_dbus.h
@@ -0,0 +1,36 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IIOSERVICE_LIBIIOSERVICE_IPC_SENSOR_SERVER_DBUS_H_
+#define IIOSERVICE_LIBIIOSERVICE_IPC_SENSOR_SERVER_DBUS_H_
+
+#include <base/memory/weak_ptr.h>
+
+#include "iioservice/include/export.h"
+#include "iioservice/libiioservice_ipc/sensor_dbus.h"
+#include "mojo/cros_sensor_service.mojom.h"
+
+namespace iioservice {
+
+class IIOSERVICE_EXPORT SensorServerDbus : public SensorDbus {
+ public:
+  virtual ~SensorServerDbus() = default;
+
+  void BootstrapMojoConnection() override;
+
+ protected:
+  SensorServerDbus() = default;
+
+  void OnInvitationReceived(mojo::IncomingInvitation invitation) override;
+
+  virtual void OnServerReceived(
+      mojo::PendingReceiver<cros::mojom::SensorHalServer> server) = 0;
+
+ private:
+  base::WeakPtrFactory<SensorServerDbus> weak_factory_{this};
+};
+
+}  // namespace iioservice
+
+#endif  // IIOSERVICE_LIBIIOSERVICE_IPC_SENSOR_SERVER_DBUS_H_