OSDN Git Service

Initial DBus transport support
authorJakub Pawlowski <jpawlowski@google.com>
Mon, 31 Oct 2016 19:56:12 +0000 (12:56 -0700)
committerJakub Pawlowski <jpawlowski@google.com>
Tue, 6 Jun 2017 19:04:28 +0000 (19:04 +0000)
This patch adds initial support for DBus transport on Linux. It exposes
initial implementation of Adapter that can be Enabled and Disabled. One
can also introspect the interface to find the exposed methods. Further
patches will extend it's functionality.

Test: ninja -C out/Default -j 40
Change-Id: I173cc752b8d8aaa8706ed36f75f5a043cc987b1a

build/secondary/third_party/libchrome/BUILD.gn
service/BUILD.gn
service/daemon.cc
service/ipc/dbus/bluetooth_adapter.cc [new file with mode: 0644]
service/ipc/dbus/bluetooth_adapter.h [new file with mode: 0644]
service/ipc/dbus/ipc_handler_dbus.cc [new file with mode: 0644]
service/ipc/dbus/ipc_handler_dbus.h [new file with mode: 0644]
service/ipc/dbus/org.fluoride.BluetoothAdapter.xml [new file with mode: 0644]
service/ipc/ipc_manager.cc
service/ipc/ipc_manager.h

index fc58cb6..d0d94b2 100644 (file)
@@ -201,6 +201,20 @@ source_set("base_sources") {
     "base/tracking_info.cc",
     "base/values.cc",
     "base/vlog.cc",
+
+    "dbus/bus.cc",
+    "dbus/dbus_statistics.cc",
+    "dbus/exported_object.cc",
+    "dbus/file_descriptor.cc",
+    "dbus/message.cc",
+    "dbus/object_manager.cc",
+    "dbus/object_path.cc",
+    "dbus/object_proxy.cc",
+    "dbus/property.cc",
+    "dbus/scoped_dbus_error.cc",
+    "dbus/string_util.cc",
+    "dbus/util.cc",
+    "dbus/values_util.cc"
   ]
 
   defines = [
@@ -219,7 +233,13 @@ source_set("base_sources") {
     "//third_party/libevent",
     "//third_party/libevent/include",
     "//third_party/libchrome/base",
+    "//third_party/libchrome/dbus",
     "//third_party/modp_b64",
+
+    # paths to dbus headers, can be obtained by "pkg-config --cflags dbus-1"
+    #TODO(jpawlowski) use pkg-config script like build/config/linux/pkg_config.gni
+    "/usr/include/dbus-1.0/",
+    "/usr/lib/x86_64-linux-gnu/dbus-1.0/include",
   ]
 }
 
@@ -228,6 +248,11 @@ config("libchrome_config") {
   include_dirs = [
     "//third_party/googletest/googletest/include",
     "//third_party/libchrome",
+
+    # paths to dbus headers, can be obtained by "pkg-config --cflags dbus-1"
+    #TODO(jpawlowski) use pkg-config script like build/config/linux/pkg_config.gni
+    "/usr/include/dbus-1.0/",
+    "/usr/lib/x86_64-linux-gnu/dbus-1.0/include",
  ]
 }
 
@@ -252,6 +277,7 @@ static_library("base") {
     "-levent",
     "-levent_core",
     "-lpthread",
+    "-ldbus-1",
   ]
 
   public_configs = [ ":libchrome_config" ]
index e156c72..ba49728 100644 (file)
@@ -35,6 +35,8 @@ source_set("service") {
     "gatt_server_old.cc",
     "hal/bluetooth_gatt_interface.cc",
     "hal/bluetooth_interface.cc",
+    "ipc/dbus/bluetooth_adapter.cc",
+    "ipc/dbus/ipc_handler_dbus.cc",
     "hal/fake_bluetooth_gatt_interface.cc",
     "hal/fake_bluetooth_interface.cc",
     "ipc/ipc_handler.cc",
index bc022d2..48d098c 100644 (file)
@@ -86,10 +86,20 @@ class DaemonImpl : public Daemon {
         LOG(ERROR) << "Failed to set up UNIX domain-socket IPCManager";
         return false;
       }
-    } else if (!ipc_manager_->Start(ipc::IPCManager::TYPE_BINDER, nullptr)) {
+      return true;
+    }
+
+#if !defined(OS_GENERIC)
+    if (!ipc_manager_->Start(ipc::IPCManager::TYPE_BINDER, nullptr)) {
       LOG(ERROR) << "Failed to set up Binder IPCManager";
       return false;
     }
+#else
+    if (!ipc_manager_->Start(ipc::IPCManager::TYPE_DBUS, nullptr)) {
+      LOG(ERROR) << "Failed to set up DBus IPCManager";
+      return false;
+    }
+#endif
 
     return true;
   }
diff --git a/service/ipc/dbus/bluetooth_adapter.cc b/service/ipc/dbus/bluetooth_adapter.cc
new file mode 100644 (file)
index 0000000..171fef0
--- /dev/null
@@ -0,0 +1,107 @@
+//
+//  Copyright (C) 2016 The Android Open Source Project
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+
+#include "service/ipc/dbus/bluetooth_adapter.h"
+#include <base/files/file_util.h>
+#include <base/logging.h>
+#include "service/common/bluetooth/util/address_helper.h"
+#include "service/hal/bluetooth_interface.h"
+
+using ::dbus::Bus;
+using ::dbus::ExportedObject;
+using ::dbus::MethodCall;
+using ::dbus::MessageWriter;
+using ::dbus::Response;
+using ::dbus::ObjectPath;
+using ::dbus::ErrorResponse;
+
+namespace {
+
+const std::string kBluetoothAdapterInterface = "org.fluoride.BluetoothAdapter";
+const std::string kEnable = "Enable";
+const std::string kDisable = "Disable";
+const std::string kBluetoothAdapter = "org.fluoride.BluetoothAdapter";
+const std::string kBluetoothAdapterPath = "/org/fluoride/BluetoothAdapter";
+
+// TODO(jpawlowski): right now xml interface files are in service/ipc/dbus/
+// folder.  Make a script to move them into /usr/share/dbus-1/interfaces
+const char kBindingsPath[] =
+    "/usr/share/dbus-1/interfaces/org.fluoride.BluetoothAdapter.xml";
+const char kDBusIntrospectMethod[] = "Introspect";
+
+}  // namespace
+
+namespace ipc {
+namespace dbus {
+
+BluetoothAdapter::BluetoothAdapter(scoped_refptr<Bus> bus,
+                                   bluetooth::Adapter* adapter)
+    : adapter_(adapter) {
+  exported_object_ = bus->GetExportedObject(ObjectPath(kBluetoothAdapterPath));
+
+  CHECK(exported_object_->ExportMethodAndBlock(
+      kBluetoothAdapterInterface, kEnable,
+      base::Bind(&BluetoothAdapter::Enable, base::Unretained(this))));
+
+  CHECK(exported_object_->ExportMethodAndBlock(
+      kBluetoothAdapterInterface, kDisable,
+      base::Bind(&BluetoothAdapter::Disable, base::Unretained(this))));
+
+  CHECK(exported_object_->ExportMethodAndBlock(
+      DBUS_INTERFACE_INTROSPECTABLE, kDBusIntrospectMethod,
+      base::Bind(&BluetoothAdapter::Introspect, base::Unretained(this))));
+
+  CHECK(bus->RequestOwnershipAndBlock(kBluetoothAdapter, Bus::REQUIRE_PRIMARY))
+      << "Unable to take ownership of " << kBluetoothAdapter
+      << ". Make sure you have proper busconfig file "
+         "/etc/dbus-1/system.d/org.fluoride.conf";
+}
+
+void BluetoothAdapter::Enable(MethodCall* method_call,
+                              ExportedObject::ResponseSender response_sender) {
+  VLOG(1) << __func__;
+  adapter_->Enable(false);
+  response_sender.Run(Response::FromMethodCall(method_call));
+}
+
+void BluetoothAdapter::Disable(MethodCall* method_call,
+                               ExportedObject::ResponseSender response_sender) {
+  VLOG(1) << __func__;
+  adapter_->Disable();
+  response_sender.Run(Response::FromMethodCall(method_call));
+}
+
+void BluetoothAdapter::Introspect(
+    MethodCall* method_call, ExportedObject::ResponseSender response_sender) {
+  VLOG(1) << __func__;
+
+  std::string output;
+  if (!base::ReadFileToString(base::FilePath(kBindingsPath), &output)) {
+    PLOG(ERROR) << "Can't read XML bindings from disk:";
+    response_sender.Run(ErrorResponse::FromMethodCall(
+        method_call, "Can't read XML bindings from disk.", ""));
+  }
+  std::unique_ptr<Response> response(Response::FromMethodCall(method_call));
+  MessageWriter writer(response.get());
+  writer.AppendString(output);
+
+  response_sender.Run(std::move(response));
+}
+
+BluetoothAdapter::~BluetoothAdapter() {}
+
+}  // namespace dbus
+}  // namespace ipc
diff --git a/service/ipc/dbus/bluetooth_adapter.h b/service/ipc/dbus/bluetooth_adapter.h
new file mode 100644 (file)
index 0000000..1d8dd8f
--- /dev/null
@@ -0,0 +1,56 @@
+//
+//  Copyright (C) 2016 The Android Open Source Project
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+
+#pragma once
+
+#include "service/adapter.h"
+
+#include <base/memory/ref_counted.h>
+#include <dbus/bus.h>
+#include <dbus/exported_object.h>
+#include <dbus/message.h>
+#include <dbus/object_path.h>
+#include <dbus/property.h>
+
+using ::dbus::Bus;
+using ::dbus::ExportedObject;
+using ::dbus::MethodCall;
+
+namespace ipc {
+namespace dbus {
+
+class BluetoothAdapter {
+ public:
+  explicit BluetoothAdapter(scoped_refptr<Bus> bus,
+                            bluetooth::Adapter* adapter);
+  virtual ~BluetoothAdapter();
+
+  void Enable(MethodCall* method_call,
+              ExportedObject::ResponseSender response_sender);
+
+  void Disable(MethodCall* method_call,
+               ExportedObject::ResponseSender response_sender);
+
+  void Introspect(MethodCall* method_call,
+                  ExportedObject::ResponseSender response_sender);
+
+ private:
+  ExportedObject* exported_object_;
+  bluetooth::Adapter* adapter_;
+};
+
+}  // namespace dbus
+}  // namespace ipc
diff --git a/service/ipc/dbus/ipc_handler_dbus.cc b/service/ipc/dbus/ipc_handler_dbus.cc
new file mode 100644 (file)
index 0000000..ff7ff43
--- /dev/null
@@ -0,0 +1,67 @@
+//
+//  Copyright (C) 2016 The Android Open Source Project
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+
+#include "service/ipc/dbus/ipc_handler_dbus.h"
+
+#include <base/bind.h>
+#include <base/threading/thread_task_runner_handle.h>
+#include <dbus/bus.h>
+#include "service/daemon.h"
+#include "service/ipc/dbus/bluetooth_adapter.h"
+
+using dbus::Bus;
+
+namespace ipc {
+
+IPCHandlerDBus::IPCHandlerDBus(bluetooth::Adapter* adapter,
+                               IPCManager::Delegate* delegate)
+    : IPCHandler(adapter, delegate) {}
+
+IPCHandlerDBus::~IPCHandlerDBus() {}
+
+bool IPCHandlerDBus::Run() {
+  LOG(INFO) << __func__;
+
+  dbus_thread_ = new base::Thread("D-Bus Thread");
+  base::Thread::Options thread_options;
+  thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
+  dbus_thread_->StartWithOptions(thread_options);
+
+  dbus_thread_->task_runner()->PostTask(
+      FROM_HERE, base::Bind(&IPCHandlerDBus::InitDbus, base::Unretained(this)));
+
+  return true;
+}
+
+void IPCHandlerDBus::InitDbus() {
+  LOG(INFO) << __func__;
+
+  Bus::Options bus_options;
+  bus_options.bus_type = Bus::SYSTEM;
+  bus_options.connection_type = Bus::PRIVATE;
+  bus_options.dbus_task_runner = base::ThreadTaskRunnerHandle::Get();
+
+  scoped_refptr<Bus> bus_ = new Bus(bus_options);
+
+  ipc::dbus::BluetoothAdapter* bluetooth_adapter =
+      new ipc::dbus::BluetoothAdapter(bus_, adapter());
+
+  LOG(INFO) << __func__ << ": all services added";
+}
+
+void IPCHandlerDBus::Stop() { dbus_thread_->Stop(); }
+
+}  // namespace ipc
diff --git a/service/ipc/dbus/ipc_handler_dbus.h b/service/ipc/dbus/ipc_handler_dbus.h
new file mode 100644 (file)
index 0000000..03f7720
--- /dev/null
@@ -0,0 +1,48 @@
+//
+//  Copyright (C) 2016 The Android Open Source Project
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+#pragma once
+
+#include <base/threading/thread.h>
+#include "service/ipc/ipc_handler.h"
+#include "service/ipc/ipc_manager.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}  // namespace base
+
+namespace ipc {
+
+// Implements a DBus based IPCHandler
+class IPCHandlerDBus : public IPCHandler {
+ public:
+  IPCHandlerDBus(bluetooth::Adapter* adapter, IPCManager::Delegate* delegate);
+  ~IPCHandlerDBus() override;
+
+  void InitDbus();
+
+  // IPCHandler overrides:
+  bool Run() override;
+  void Stop() override;
+
+ private:
+  base::Thread* dbus_thread_;
+
+  IPCHandlerDBus() = default;
+
+  DISALLOW_COPY_AND_ASSIGN(IPCHandlerDBus);
+};
+
+}  // namespace ipc
diff --git a/service/ipc/dbus/org.fluoride.BluetoothAdapter.xml b/service/ipc/dbus/org.fluoride.BluetoothAdapter.xml
new file mode 100644 (file)
index 0000000..4a718e6
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="/org/chromium/SessionManager"
+      xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
+
+  <!--
+      org.fluoride.BluetoothAdapter:
+      @short_description: Bluetooth adapter manager.
+
+      Interface for user bluetooth adapter. Right now allows only to enable
+      and disable the adapter.
+  -->
+  <interface name="org.fluoride.BluetoothAdapter">
+    <!--
+        Enable:
+
+        Enable the bluetooth adapter.
+    -->
+    <method name="Enable"></method>
+
+    <!--
+        Disable:
+
+        Disable the bluetooth adapter.
+    -->
+    <method name="Disable"></method>
+  </interface>
+</node>
\ No newline at end of file
index 74c53bc..71dc6c7 100644 (file)
@@ -18,6 +18,8 @@
 
 #if !defined(OS_GENERIC)
 #include "service/ipc/binder/ipc_handler_binder.h"
+#else
+#include "service/ipc/dbus/ipc_handler_dbus.h"
 #endif  // !defined(OS_GENERIC)
 #include "service/ipc/ipc_handler_linux.h"
 
@@ -32,6 +34,7 @@ IPCManager::~IPCManager() {
   // holding a reference to them. Instead, explicitly stop them here.
   if (BinderStarted()) binder_handler_->Stop();
   if (LinuxStarted()) linux_handler_->Stop();
+  if (DBusStarted()) dbus_handler_->Stop();
 }
 
 bool IPCManager::Start(Type type, Delegate* delegate) {
@@ -48,6 +51,7 @@ bool IPCManager::Start(Type type, Delegate* delegate) {
         return false;
       }
       return true;
+
 #if !defined(OS_GENERIC)
     case TYPE_BINDER:
       if (BinderStarted()) {
@@ -61,7 +65,21 @@ bool IPCManager::Start(Type type, Delegate* delegate) {
         return false;
       }
       return true;
+#else
+    case TYPE_DBUS:
+      if (DBusStarted()) {
+        LOG(ERROR) << "IPCManagerDBus already started.";
+        return false;
+      }
+
+      dbus_handler_ = new IPCHandlerDBus(adapter_, delegate);
+      if (!dbus_handler_->Run()) {
+        dbus_handler_ = nullptr;
+        return false;
+      }
+      return true;
 #endif  // !defined(OS_GENERIC)
+
     default:
       LOG(ERROR) << "Unsupported IPC type given: " << type;
   }
@@ -73,4 +91,6 @@ bool IPCManager::BinderStarted() const { return binder_handler_.get(); }
 
 bool IPCManager::LinuxStarted() const { return linux_handler_.get(); }
 
+bool IPCManager::DBusStarted() const { return dbus_handler_.get(); }
+
 }  // namespace ipc
index c0ade0e..bf0967c 100644 (file)
@@ -37,8 +37,9 @@ class IPCManager {
  public:
   // Possible IPC types.
   enum Type {
-    TYPE_LINUX,  // IPC based on a Linux sequential packet domain socket
-    TYPE_BINDER  // IPC based on the Binder
+    TYPE_LINUX,   // IPC based on a Linux sequential packet domain socket
+    TYPE_BINDER,  // IPC based on the Binder
+    TYPE_DBUS     // IPC based on the DBus
   };
 
   // Interface for observing events from an IPC mechanism. These methods will be
@@ -81,6 +82,7 @@ class IPCManager {
   // Returns true if an IPC type has been initialized.
   bool BinderStarted() const;
   bool LinuxStarted() const;
+  bool DBusStarted() const;
 
  private:
   IPCManager() = default;
@@ -89,6 +91,7 @@ class IPCManager {
   // owned by us.
   scoped_refptr<IPCHandler> binder_handler_;
   scoped_refptr<IPCHandler> linux_handler_;
+  scoped_refptr<IPCHandler> dbus_handler_;
 
   // The Bluetooth adapter instance. This is owned by Daemon so we keep a raw
   // pointer to it.