MIDI ArcBridge proxy mojo interface.
ARC MIDI uses this to connect to the midis daemon running in
Chrome OS. It takes a Mojo connection request over the ArcBridge,
and then uses D-Bus (for sending across a message handle) to initiate
a Mojo connection with that daemon. The daemon then returns a 2nd Mojo
interface (with the actual Midis client calls) back to the proxy,
which in turn sends it to the Android side. At present, the Connect()
call which should return the 2nd Mojo interface handle has not yet
been implemented.
It retains the initial Mojo connection with the daemon is maintained,
for future ARC sessions, and tears down when the daemon dies.
This implementation is a based on the similar implementation used by
ArcOemCrypto.
BUG=chromium:701005
Change-Id: Icc8c937f743ddcc3deca85446c303408b17ec759
Reviewed-on: https://chromium-review.googlesource.com/638913
Commit-Queue: Prashant Malani <pmalani@google.com>
Reviewed-by: Greg Kerr <kerrnel@chromium.org>
Reviewed-by: Luis Hector Chavez <lhchavez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#501170}
diff --git a/chrome/browser/chromeos/arc/arc_service_launcher.cc b/chrome/browser/chromeos/arc/arc_service_launcher.cc
index 7df20e9..9104ca1 100644
--- a/chrome/browser/chromeos/arc/arc_service_launcher.cc
+++ b/chrome/browser/chromeos/arc/arc_service_launcher.cc
@@ -49,6 +49,7 @@
#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
#include "components/arc/lock_screen/arc_lock_screen_bridge.h"
#include "components/arc/metrics/arc_metrics_service.h"
+#include "components/arc/midis/arc_midis_bridge.h"
#include "components/arc/net/arc_net_host_impl.h"
#include "components/arc/obb_mounter/arc_obb_mounter_bridge.h"
#include "components/arc/power/arc_power_bridge.h"
@@ -146,6 +147,7 @@
ArcKioskBridge::GetForBrowserContext(profile);
ArcLockScreenBridge::GetForBrowserContext(profile);
ArcMetricsService::GetForBrowserContext(profile);
+ ArcMidisBridge::GetForBrowserContext(profile);
ArcNetHostImpl::GetForBrowserContext(profile);
ArcNotificationManager::GetForBrowserContext(profile);
ArcObbMounterBridge::GetForBrowserContext(profile);
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index 65e46991..20a8b24 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -43,6 +43,8 @@
"lock_screen/arc_lock_screen_bridge.h",
"metrics/arc_metrics_service.cc",
"metrics/arc_metrics_service.h",
+ "midis/arc_midis_bridge.cc",
+ "midis/arc_midis_bridge.h",
"net/arc_net_host_impl.cc",
"net/arc_net_host_impl.h",
"obb_mounter/arc_obb_mounter_bridge.cc",
@@ -150,6 +152,7 @@
"common/kiosk.mojom",
"common/lock_screen.mojom",
"common/metrics.mojom",
+ "common/midis.mojom",
"common/net.mojom",
"common/notifications.mojom",
"common/obb_mounter.mojom",
diff --git a/components/arc/arc_bridge_host_impl.cc b/components/arc/arc_bridge_host_impl.cc
index 872e410..7a19c67 100644
--- a/components/arc/arc_bridge_host_impl.cc
+++ b/components/arc/arc_bridge_host_impl.cc
@@ -170,6 +170,11 @@
OnInstanceReady(arc_bridge_service_->metrics(), std::move(metrics_ptr));
}
+void ArcBridgeHostImpl::OnMidisInstanceReady(
+ mojom::MidisInstancePtr midis_ptr) {
+ OnInstanceReady(arc_bridge_service_->midis(), std::move(midis_ptr));
+}
+
void ArcBridgeHostImpl::OnNetInstanceReady(mojom::NetInstancePtr net_ptr) {
OnInstanceReady(arc_bridge_service_->net(), std::move(net_ptr));
}
diff --git a/components/arc/arc_bridge_host_impl.h b/components/arc/arc_bridge_host_impl.h
index 9e79bee..bbab05e 100644
--- a/components/arc/arc_bridge_host_impl.h
+++ b/components/arc/arc_bridge_host_impl.h
@@ -64,6 +64,7 @@
void OnLockScreenInstanceReady(
mojom::LockScreenInstancePtr lock_screen_ptr) override;
void OnMetricsInstanceReady(mojom::MetricsInstancePtr metrics_ptr) override;
+ void OnMidisInstanceReady(mojom::MidisInstancePtr midis_ptr) override;
void OnNetInstanceReady(mojom::NetInstancePtr net_ptr) override;
void OnNotificationsInstanceReady(
mojom::NotificationsInstancePtr notifications_ptr) override;
diff --git a/components/arc/arc_bridge_service.h b/components/arc/arc_bridge_service.h
index 2c446c4f..c503382 100644
--- a/components/arc/arc_bridge_service.h
+++ b/components/arc/arc_bridge_service.h
@@ -30,6 +30,7 @@
class KioskInstance;
class LockScreenInstance;
class MetricsInstance;
+class MidisInstance;
class NetInstance;
class NotificationsInstance;
class ObbMounterInstance;
@@ -88,6 +89,7 @@
return &lock_screen_;
}
InstanceHolder<mojom::MetricsInstance>* metrics() { return &metrics_; }
+ InstanceHolder<mojom::MidisInstance>* midis() { return &midis_; }
InstanceHolder<mojom::NetInstance>* net() { return &net_; }
InstanceHolder<mojom::NotificationsInstance>* notifications() {
return ¬ifications_;
@@ -136,6 +138,7 @@
InstanceHolder<mojom::KioskInstance> kiosk_;
InstanceHolder<mojom::LockScreenInstance> lock_screen_;
InstanceHolder<mojom::MetricsInstance> metrics_;
+ InstanceHolder<mojom::MidisInstance> midis_;
InstanceHolder<mojom::NetInstance> net_;
InstanceHolder<mojom::NotificationsInstance> notifications_;
InstanceHolder<mojom::ObbMounterInstance> obb_mounter_;
diff --git a/components/arc/common/arc_bridge.mojom b/components/arc/common/arc_bridge.mojom
index 160c87bd0..86872309 100644
--- a/components/arc/common/arc_bridge.mojom
+++ b/components/arc/common/arc_bridge.mojom
@@ -20,6 +20,7 @@
import "kiosk.mojom";
import "lock_screen.mojom";
import "metrics.mojom";
+import "midis.mojom";
import "net.mojom";
import "notifications.mojom";
import "obb_mounter.mojom";
@@ -37,9 +38,9 @@
import "volume_mounter.mojom";
import "wallpaper.mojom";
-// Next MinVersion: 30
+// Next MinVersion: 31
// Deprecated method IDs: 101, 105
-// Next method ID: 135
+// Next method ID: 136
interface ArcBridgeHost {
// Keep the entries alphabetical. In order to do so without breaking
// compatibility with the ARC instance, explicitly assign each interface a
@@ -100,6 +101,9 @@
// Notifies Chrome that the MetricsInstance interface is ready.
[MinVersion=10] OnMetricsInstanceReady@116(MetricsInstance instance_ptr);
+ // Notifies Chrome that the MidisInstance interface is ready.
+ [MinVersion=30] OnMidisInstanceReady@135(MidisInstance instance_ptr);
+
// Notifies Chrome that the NetInstance interface is ready.
[MinVersion=5] OnNetInstanceReady@108(NetInstance instance_ptr);
diff --git a/components/arc/common/midis.mojom b/components/arc/common/midis.mojom
new file mode 100644
index 0000000..a0ca2ff9
--- /dev/null
+++ b/components/arc/common/midis.mojom
@@ -0,0 +1,28 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines the mojo interface between Android, Chrome and the
+// Chrome OS daemon for the MIDI implementation used in ARC.
+
+module arc.mojom;
+
+// This interface is needed to get the actual MidisManager interface handle.
+// Next Method ID: 1
+interface MidisHost {
+ // This is used by a client to register with midis and is used to connect
+ // the client handle with the server and vice-versa.
+ // Once implemented, this call will have two arguments:
+ // - a pointer to server interface handle (used to call server functions).
+ // - a handle to the client interface (used to call client routines on
+ // device related events like (dis)connections).
+ // It is currently a stub.
+ Connect@0();
+};
+
+// MidisInstance is implemented in the ARC MIDI JNI code that
+// runs in Android and handles the Android side of the ArcBridge connection.
+// Next Method ID: 1
+interface MidisInstance {
+ Init@0(MidisHost host_ptr);
+};
diff --git a/components/arc/midis/arc_midis_bridge.cc b/components/arc/midis/arc_midis_bridge.cc
new file mode 100644
index 0000000..2aa3d79d
--- /dev/null
+++ b/components/arc/midis/arc_midis_bridge.cc
@@ -0,0 +1,116 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/arc/midis/arc_midis_bridge.h"
+
+#include "base/bind.h"
+#include "base/memory/singleton.h"
+#include "chromeos/dbus/arc_midis_client.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "components/arc/arc_bridge_service.h"
+#include "components/arc/arc_browser_context_keyed_service_factory_base.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/outgoing_broker_client_invitation.h"
+#include "mojo/edk/embedder/platform_channel_pair.h"
+#include "mojo/edk/embedder/scoped_platform_handle.h"
+
+namespace arc {
+namespace {
+
+// Singleton factory for ArcMidisBridge
+class ArcMidisBridgeFactory
+ : public internal::ArcBrowserContextKeyedServiceFactoryBase<
+ ArcMidisBridge,
+ ArcMidisBridgeFactory> {
+ public:
+ // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
+ static constexpr const char* kName = "ArcMidisBridgeFactory";
+
+ static ArcMidisBridgeFactory* GetInstance() {
+ return base::Singleton<ArcMidisBridgeFactory>::get();
+ }
+
+ private:
+ friend base::DefaultSingletonTraits<ArcMidisBridgeFactory>;
+ ArcMidisBridgeFactory() = default;
+ ~ArcMidisBridgeFactory() override = default;
+};
+
+} // namespace
+
+// static
+ArcMidisBridge* ArcMidisBridge::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return ArcMidisBridgeFactory::GetForBrowserContext(context);
+}
+
+ArcMidisBridge::ArcMidisBridge(content::BrowserContext* context,
+ ArcBridgeService* bridge_service)
+ : arc_bridge_service_(bridge_service), binding_(this), weak_factory_(this) {
+ arc_bridge_service_->midis()->AddObserver(this);
+}
+
+ArcMidisBridge::~ArcMidisBridge() {
+ arc_bridge_service_->midis()->RemoveObserver(this);
+}
+
+void ArcMidisBridge::OnInstanceReady() {
+ DVLOG(1) << "ArcMidisBridge::OnInstanceReady() called.";
+ mojom::MidisInstance* midis_instance =
+ ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->midis(), Init);
+ DCHECK(midis_instance);
+
+ DVLOG(1) << "Calling Init on the other side of MidisInstance.";
+ mojom::MidisHostPtr host_proxy;
+ binding_.Bind(mojo::MakeRequest(&host_proxy));
+ midis_instance->Init(std::move(host_proxy));
+ binding_.set_connection_error_handler(base::Bind(
+ &mojo::Binding<MidisHost>::Close, base::Unretained(&binding_)));
+}
+
+void ArcMidisBridge::OnBootstrapMojoConnection(
+ chromeos::DBusMethodCallStatus result) {
+ if (result != chromeos::DBUS_METHOD_CALL_SUCCESS) {
+ LOG(ERROR) << "ArcMidisBridge had a failure in D-Bus with the daemon.";
+ midis_host_ptr_.reset();
+ return;
+ }
+ DVLOG(1) << "ArcMidisBridge succeeded with Mojo bootstrapping.";
+ midis_host_ptr_->Connect();
+}
+
+void ArcMidisBridge::Connect() {
+ DVLOG(1) << "ArcMidisBridge::Connect called.";
+ if (midis_host_ptr_.is_bound()) {
+ DVLOG(1) << "Re-using bootstrap connection for MidisService Connect.";
+ midis_host_ptr_->Connect();
+ return;
+ }
+ DVLOG(1) << "Bootstrapping the Midis connection via D-Bus.";
+ mojo::edk::OutgoingBrokerClientInvitation invitation;
+ mojo::edk::PlatformChannelPair channel_pair;
+ mojo::ScopedMessagePipeHandle server_pipe =
+ invitation.AttachMessagePipe("arc-midis-pipe");
+ invitation.Send(
+ base::kNullProcessHandle,
+ mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy,
+ channel_pair.PassServerHandle()));
+ mojo::edk::ScopedPlatformHandle child_handle =
+ channel_pair.PassClientHandle();
+ base::ScopedFD fd(child_handle.release().handle);
+
+ midis_host_ptr_.Bind(
+ mojo::InterfacePtrInfo<mojom::MidisHost>(std::move(server_pipe), 0u));
+ DVLOG(1) << "Bound remote MidisHost interface to pipe.";
+ midis_host_ptr_.set_connection_error_handler(
+ base::Bind(&mojo::InterfacePtr<mojom::MidisHost>::reset,
+ base::Unretained(&midis_host_ptr_)));
+ chromeos::DBusThreadManager::Get()
+ ->GetArcMidisClient()
+ ->BootstrapMojoConnection(
+ std::move(fd), base::Bind(&ArcMidisBridge::OnBootstrapMojoConnection,
+ weak_factory_.GetWeakPtr()));
+}
+
+} // namespace arc
diff --git a/components/arc/midis/arc_midis_bridge.h b/components/arc/midis/arc_midis_bridge.h
new file mode 100644
index 0000000..a816eece
--- /dev/null
+++ b/components/arc/midis/arc_midis_bridge.h
@@ -0,0 +1,59 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_ARC_MIDIS_ARC_MIDIS_BRIDGE_H_
+#define COMPONENTS_ARC_MIDIS_ARC_MIDIS_BRIDGE_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "chromeos/dbus/dbus_method_call_status.h"
+#include "components/arc/common/midis.mojom.h"
+#include "components/arc/instance_holder.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace content {
+class BrowserContext;
+} // namespace content
+
+namespace arc {
+
+class ArcBridgeService;
+
+class ArcMidisBridge : public KeyedService,
+ public InstanceHolder<mojom::MidisInstance>::Observer,
+ public mojom::MidisHost {
+ public:
+ // Returns singleton instance for the given BrowserContext,
+ // or nullptr if the browser |context| is not allowed to use ARC.
+ static ArcMidisBridge* GetForBrowserContext(content::BrowserContext* context);
+
+ ArcMidisBridge(content::BrowserContext* context,
+ ArcBridgeService* bridge_service);
+ ~ArcMidisBridge() override;
+
+ // Overridden from InstanceHolder<mojom::MidisInstance>::Observer:
+ void OnInstanceReady() override;
+
+ // Midis Mojo host interface
+ void Connect() override;
+
+ private:
+ void OnBootstrapMojoConnection(chromeos::DBusMethodCallStatus result);
+
+ ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager.
+ mojo::Binding<mojom::MidisHost> binding_;
+ mojom::MidisHostPtr midis_host_ptr_;
+
+ // WeakPtrFactory to use for callbacks.
+ base::WeakPtrFactory<ArcMidisBridge> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ArcMidisBridge);
+};
+
+} // namespace arc
+
+#endif // COMPONENTS_ARC_MIDIS_ARC_MIDIS_BRIDGE_H_