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/application/application.h"
19#include "mojo/public/cpp/bindings/error_handler.h"
20#include "mojo/public/interfaces/service_provider/service_provider.mojom.h"
21#include "mojo/shell/external_service.mojom.h"
22
23namespace mojo {
24
25DBusExternalServiceBase::DBusExternalServiceBase(
26    const std::string& service_name)
27    : service_name_(service_name),
28      exported_object_(NULL) {
29}
30DBusExternalServiceBase::~DBusExternalServiceBase() {}
31
32void DBusExternalServiceBase::Start() {
33  InitializeDBus();
34  ExportMethods();
35  TakeDBusServiceOwnership();
36  DVLOG(1) << "External service started";
37}
38
39void DBusExternalServiceBase::ConnectChannel(
40    dbus::MethodCall* method_call,
41    dbus::ExportedObject::ResponseSender sender) {
42  dbus::MessageReader reader(method_call);
43  dbus::FileDescriptor wrapped_fd;
44  if (!reader.PopFileDescriptor(&wrapped_fd)) {
45    sender.Run(
46        dbus::ErrorResponse::FromMethodCall(
47            method_call,
48            "org.chromium.Mojo.BadHandle",
49            "Invalid FD.").PassAs<dbus::Response>());
50    return;
51  }
52  wrapped_fd.CheckValidity();
53  channel_init_.reset(new mojo::embedder::ChannelInit);
54  mojo::ScopedMessagePipeHandle message_pipe =
55      channel_init_->Init(wrapped_fd.TakeValue(),
56                          base::MessageLoopProxy::current());
57  CHECK(message_pipe.is_valid());
58
59  Connect(message_pipe.Pass());
60  sender.Run(dbus::Response::FromMethodCall(method_call));
61}
62
63void DBusExternalServiceBase::ExportMethods() {
64  CHECK(exported_object_);
65  CHECK(exported_object_->ExportMethodAndBlock(
66      kMojoDBusInterface, kMojoDBusConnectMethod,
67      base::Bind(&DBusExternalServiceBase::ConnectChannel,
68                 base::Unretained(this))));
69}
70
71void DBusExternalServiceBase::InitializeDBus() {
72  CHECK(!bus_);
73  dbus::Bus::Options options;
74  options.bus_type = dbus::Bus::SESSION;
75  bus_ = new dbus::Bus(options);
76  CHECK(bus_->Connect());
77  CHECK(bus_->SetUpAsyncOperations());
78
79  exported_object_ =
80      bus_->GetExportedObject(dbus::ObjectPath(kMojoDBusImplPath));
81}
82
83void DBusExternalServiceBase::TakeDBusServiceOwnership() {
84  CHECK(bus_->RequestOwnershipAndBlock(
85      service_name_,
86      dbus::Bus::REQUIRE_PRIMARY_ALLOW_REPLACEMENT))
87      << "Unable to take ownership of " << service_name_;
88}
89
90}  // namespace mojo
91