1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "mojo/dbus/dbus_external_service.h"
6
7#include "base/bind.h"
8#include "base/callback.h"
9#include "base/logging.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/message_loop/message_loop_proxy.h"
12#include "dbus/bus.h"
13#include "dbus/exported_object.h"
14#include "dbus/file_descriptor.h"
15#include "dbus/message.h"
16#include "dbus/object_path.h"
17#include "mojo/embedder/channel_init.h"
18#include "mojo/public/cpp/bindings/error_handler.h"
19#include "mojo/shell/external_service.mojom.h"
20
21namespace mojo {
22
23DBusExternalServiceBase::DBusExternalServiceBase(
24    const std::string& service_name)
25    : service_name_(service_name),
26      exported_object_(NULL) {
27}
28DBusExternalServiceBase::~DBusExternalServiceBase() {}
29
30void DBusExternalServiceBase::Start() {
31  InitializeDBus();
32  ExportMethods();
33  TakeDBusServiceOwnership();
34  DVLOG(1) << "External service started";
35}
36
37void DBusExternalServiceBase::ConnectChannel(
38    dbus::MethodCall* method_call,
39    dbus::ExportedObject::ResponseSender sender) {
40  dbus::MessageReader reader(method_call);
41  dbus::FileDescriptor wrapped_fd;
42  if (!reader.PopFileDescriptor(&wrapped_fd)) {
43    sender.Run(
44        dbus::ErrorResponse::FromMethodCall(
45            method_call,
46            "org.chromium.Mojo.BadHandle",
47            "Invalid FD.").PassAs<dbus::Response>());
48    return;
49  }
50  wrapped_fd.CheckValidity();
51  channel_init_.reset(new mojo::embedder::ChannelInit);
52  mojo::ScopedMessagePipeHandle message_pipe =
53      channel_init_->Init(wrapped_fd.TakeValue(),
54                          base::MessageLoopProxy::current());
55  CHECK(message_pipe.is_valid());
56
57  Connect(message_pipe.Pass());
58  sender.Run(dbus::Response::FromMethodCall(method_call));
59}
60
61void DBusExternalServiceBase::ExportMethods() {
62  CHECK(exported_object_);
63  CHECK(exported_object_->ExportMethodAndBlock(
64      kMojoDBusInterface, kMojoDBusConnectMethod,
65      base::Bind(&DBusExternalServiceBase::ConnectChannel,
66                 base::Unretained(this))));
67}
68
69void DBusExternalServiceBase::InitializeDBus() {
70  CHECK(!bus_.get());
71  dbus::Bus::Options options;
72  options.bus_type = dbus::Bus::SESSION;
73  bus_ = new dbus::Bus(options);
74  CHECK(bus_->Connect());
75  CHECK(bus_->SetUpAsyncOperations());
76
77  exported_object_ =
78      bus_->GetExportedObject(dbus::ObjectPath(kMojoDBusImplPath));
79}
80
81void DBusExternalServiceBase::TakeDBusServiceOwnership() {
82  CHECK(bus_->RequestOwnershipAndBlock(
83      service_name_,
84      dbus::Bus::REQUIRE_PRIMARY_ALLOW_REPLACEMENT))
85      << "Unable to take ownership of " << service_name_;
86}
87
88}  // namespace mojo
89