1e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// found in the LICENSE file.
4e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
5e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "chromeos/dbus/bluetooth_gatt_service_service_provider.h"
6e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
7e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/bind.h"
8e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/logging.h"
9e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/memory/ref_counted.h"
10e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/memory/weak_ptr.h"
11e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/threading/platform_thread.h"
126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chromeos/dbus/dbus_thread_manager.h"
13e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "chromeos/dbus/fake_bluetooth_gatt_service_service_provider.h"
14e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "dbus/exported_object.h"
15e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "dbus/message.h"
16e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "third_party/cros_system_api/dbus/service_constants.h"
17e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
18e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochnamespace chromeos {
19e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochnamespace {
20e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst char kErrorInvalidArgs[] =
21e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    "org.freedesktop.DBus.Error.InvalidArgs";
22e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst char kErrorPropertyReadOnly[] =
23e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    "org.freedesktop.DBus.Error.PropertyReadOnly";
24e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}  // namespace
25e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
26e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// The BluetoothGattServiceServiceProvider implementation used in production.
27e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochclass BluetoothGattServiceServiceProviderImpl
28e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    : public BluetoothGattServiceServiceProvider {
29e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch public:
30e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  BluetoothGattServiceServiceProviderImpl(
31e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      dbus::Bus* bus,
32e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      const dbus::ObjectPath& object_path,
33e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      const std::string& uuid,
34e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      const std::vector<dbus::ObjectPath>& includes)
35e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      : origin_thread_id_(base::PlatformThread::CurrentId()),
36e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        uuid_(uuid),
37e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        includes_(includes),
38e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        bus_(bus),
39e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        object_path_(object_path),
40e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        weak_ptr_factory_(this) {
41e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    VLOG(1) << "Creating Bluetooth GATT service: " << object_path_.value()
42e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch            << " UUID: " << uuid;
43e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    DCHECK(!uuid_.empty());
44e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    DCHECK(object_path_.IsValid());
45e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    DCHECK(bus_);
46e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
47e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    exported_object_ = bus_->GetExportedObject(object_path_);
48e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
49e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    exported_object_->ExportMethod(
50e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        dbus::kDBusPropertiesInterface,
51e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        dbus::kDBusPropertiesGet,
52e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        base::Bind(&BluetoothGattServiceServiceProviderImpl::Get,
53e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                   weak_ptr_factory_.GetWeakPtr()),
54e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        base::Bind(&BluetoothGattServiceServiceProviderImpl::OnExported,
55e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                   weak_ptr_factory_.GetWeakPtr()));
56e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
57e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    exported_object_->ExportMethod(
58e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        dbus::kDBusPropertiesInterface,
59e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        dbus::kDBusPropertiesSet,
60e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        base::Bind(&BluetoothGattServiceServiceProviderImpl::Set,
61e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                   weak_ptr_factory_.GetWeakPtr()),
62e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        base::Bind(&BluetoothGattServiceServiceProviderImpl::OnExported,
63e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                   weak_ptr_factory_.GetWeakPtr()));
64e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
65e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    exported_object_->ExportMethod(
66e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        dbus::kDBusPropertiesInterface,
67e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        dbus::kDBusPropertiesGetAll,
68e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        base::Bind(&BluetoothGattServiceServiceProviderImpl::GetAll,
69e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                   weak_ptr_factory_.GetWeakPtr()),
70e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        base::Bind(&BluetoothGattServiceServiceProviderImpl::OnExported,
71e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                   weak_ptr_factory_.GetWeakPtr()));
72e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
73e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
74e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  virtual ~BluetoothGattServiceServiceProviderImpl() {
75e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    VLOG(1) << "Cleaning up Bluetooth GATT service: " << object_path_.value();
76e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    bus_->UnregisterExportedObject(object_path_);
77e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
78e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
79e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch private:
80e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Returns true if the current thread is on the origin thread.
81e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  bool OnOriginThread() {
82e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    return base::PlatformThread::CurrentId() == origin_thread_id_;
83e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
84e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
85e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Called by dbus:: when the Bluetooth daemon fetches a single property of
86e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // the service.
87e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  void Get(dbus::MethodCall* method_call,
88e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch           dbus::ExportedObject::ResponseSender response_sender) {
89e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    VLOG(2) << "BluetoothGattServiceServiceProvider::Get: "
90e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch            << object_path_.value();
91e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    DCHECK(OnOriginThread());
92e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
93e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    dbus::MessageReader reader(method_call);
94e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
95e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    std::string interface_name;
96e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    std::string property_name;
97e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (!reader.PopString(&interface_name) ||
98e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        !reader.PopString(&property_name) ||
99e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        reader.HasMoreData()) {
100e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      scoped_ptr<dbus::ErrorResponse> error_response =
101e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          dbus::ErrorResponse::FromMethodCall(
102e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch              method_call, kErrorInvalidArgs, "Expected 'ss'.");
103e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      response_sender.Run(error_response.PassAs<dbus::Response>());
104e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      return;
105e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
106e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
107e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // Only the GATT service interface is allowed.
108e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (interface_name !=
109e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        bluetooth_gatt_service::kBluetoothGattServiceInterface) {
110e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      scoped_ptr<dbus::ErrorResponse> error_response =
111e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          dbus::ErrorResponse::FromMethodCall(
112e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch              method_call, kErrorInvalidArgs,
113e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch              "No such interface: '" + interface_name + "'.");
114e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      response_sender.Run(error_response.PassAs<dbus::Response>());
115e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      return;
116e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
117e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
118e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // Return error if |property_name| is unknown.
119e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (property_name != bluetooth_gatt_service::kUUIDProperty &&
120e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        property_name != bluetooth_gatt_service::kIncludesProperty) {
121e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      scoped_ptr<dbus::ErrorResponse> error_response =
122e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          dbus::ErrorResponse::FromMethodCall(
123e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch              method_call, kErrorInvalidArgs,
124e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch              "No such property: '" + property_name + "'.");
125e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      response_sender.Run(error_response.PassAs<dbus::Response>());
126e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      return;
127e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
128e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
129e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    scoped_ptr<dbus::Response> response =
130e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        dbus::Response::FromMethodCall(method_call);
131e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    dbus::MessageWriter writer(response.get());
132e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    dbus::MessageWriter variant_writer(NULL);
133e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
134e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (property_name == bluetooth_gatt_service::kUUIDProperty) {
135e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      writer.OpenVariant("s", &variant_writer);
136e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      variant_writer.AppendString(uuid_);
137e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      writer.CloseContainer(&variant_writer);
138e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    } else {
139e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      writer.OpenVariant("ao", &variant_writer);
140e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      variant_writer.AppendArrayOfObjectPaths(includes_);
141e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      writer.CloseContainer(&variant_writer);
142e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
143e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
144e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    response_sender.Run(response.Pass());
145e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
146e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
147e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Called by dbus:: when the Bluetooth daemon sets a single property of the
148e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // service.
149e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  void Set(dbus::MethodCall* method_call,
150e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch           dbus::ExportedObject::ResponseSender response_sender) {
151e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    VLOG(2) << "BluetoothGattServiceServiceProvider::Set: "
152e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch            << object_path_.value();
153e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    DCHECK(OnOriginThread());
154e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
155e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // All of the properties on this interface are read-only, so just return
156e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // error.
157e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    scoped_ptr<dbus::ErrorResponse> error_response =
158e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        dbus::ErrorResponse::FromMethodCall(
159e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch            method_call, kErrorPropertyReadOnly,
160e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch            "All properties are read-only.");
161e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    response_sender.Run(error_response.PassAs<dbus::Response>());
162e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
163e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
164e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Called by dbus:: when the Bluetooth daemon fetches all properties of the
165e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // service.
166e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  void GetAll(dbus::MethodCall* method_call,
167e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch              dbus::ExportedObject::ResponseSender response_sender) {
168e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    VLOG(2) << "BluetoothGattServiceServiceProvider::GetAll: "
169e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch            << object_path_.value();
170e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    DCHECK(OnOriginThread());
171e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
172e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    dbus::MessageReader reader(method_call);
173e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
174e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    std::string interface_name;
175e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (!reader.PopString(&interface_name) || reader.HasMoreData()) {
176e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      scoped_ptr<dbus::ErrorResponse> error_response =
177e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          dbus::ErrorResponse::FromMethodCall(
178e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch              method_call, kErrorInvalidArgs, "Expected 's'.");
179e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      response_sender.Run(error_response.PassAs<dbus::Response>());
180e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      return;
181e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
182e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
183e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // Only the GATT service interface is allowed.
184e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (interface_name !=
185e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        bluetooth_gatt_service::kBluetoothGattServiceInterface) {
186e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      scoped_ptr<dbus::ErrorResponse> error_response =
187e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          dbus::ErrorResponse::FromMethodCall(
188e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch              method_call, kErrorInvalidArgs,
189e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch              "No such interface: '" + interface_name + "'.");
190e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      response_sender.Run(error_response.PassAs<dbus::Response>());
191e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      return;
192e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
193e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
194e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    scoped_ptr<dbus::Response> response =
195e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        dbus::Response::FromMethodCall(method_call);
196e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    dbus::MessageWriter writer(response.get());
197e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    dbus::MessageWriter array_writer(NULL);
198e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    dbus::MessageWriter dict_entry_writer(NULL);
199e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    dbus::MessageWriter variant_writer(NULL);
200e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
201e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    writer.OpenArray("{sv}", &array_writer);
202e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
203e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    array_writer.OpenDictEntry(&dict_entry_writer);
204e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    dict_entry_writer.AppendString(bluetooth_gatt_service::kUUIDProperty);
205e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    dict_entry_writer.AppendVariantOfString(uuid_);
206e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    array_writer.CloseContainer(&dict_entry_writer);
207e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
208e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    array_writer.OpenDictEntry(&dict_entry_writer);
209e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    dict_entry_writer.AppendString(bluetooth_gatt_service::kIncludesProperty);
210e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    dict_entry_writer.OpenVariant("ao", &variant_writer);
211e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    variant_writer.AppendArrayOfObjectPaths(includes_);
212e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    dict_entry_writer.CloseContainer(&variant_writer);
213e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    array_writer.CloseContainer(&dict_entry_writer);
214e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
215e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    writer.CloseContainer(&array_writer);
216e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
217e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    response_sender.Run(response.Pass());
218e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
219e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
220e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Called by dbus:: when a method is exported.
221e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  void OnExported(const std::string& interface_name,
222e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                  const std::string& method_name,
223e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                  bool success) {
224e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    LOG_IF(WARNING, !success) << "Failed to export "
225e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                              << interface_name << "." << method_name;
226e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
227e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
228e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Origin thread (i.e. the UI thread in production).
229e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  base::PlatformThreadId origin_thread_id_;
230e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
231e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // 128-bit service UUID of this object.
232e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  std::string uuid_;
233e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
234e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // List of object paths that represent other exported GATT services that are
235e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // included from this service.
236e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  std::vector<dbus::ObjectPath> includes_;
237e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
238e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // D-Bus bus object is exported on, not owned by this object and must
239e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // outlive it.
240e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  dbus::Bus* bus_;
241e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
242e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // D-Bus object path of object we are exporting, kept so we can unregister
243e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // again in our destructor.
244e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  dbus::ObjectPath object_path_;
245e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
246e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // D-Bus object we are exporting, owned by this object.
247e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  scoped_refptr<dbus::ExportedObject> exported_object_;
248e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
249e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Weak pointer factory for generating 'this' pointers that might live longer
250e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // than we do.
251e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Note: This should remain the last member so it'll be destroyed and
252e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // invalidate its weak pointers before any other members are destroyed.
253e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  base::WeakPtrFactory<BluetoothGattServiceServiceProviderImpl>
254e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      weak_ptr_factory_;
255e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
256e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DISALLOW_COPY_AND_ASSIGN(BluetoothGattServiceServiceProviderImpl);
257e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch};
258e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
259e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochBluetoothGattServiceServiceProvider::BluetoothGattServiceServiceProvider() {
260e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
261e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
262e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochBluetoothGattServiceServiceProvider::~BluetoothGattServiceServiceProvider() {
263e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
264e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
265e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// static
266e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochBluetoothGattServiceServiceProvider*
267e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochBluetoothGattServiceServiceProvider::Create(
268e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    dbus::Bus* bus,
269e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const dbus::ObjectPath& object_path,
270e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const std::string& uuid,
271e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const std::vector<dbus::ObjectPath>& includes) {
2721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!DBusThreadManager::Get()->IsUsingStub(DBusClientBundle::BLUETOOTH)) {
273e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    return new BluetoothGattServiceServiceProviderImpl(
274e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        bus, object_path, uuid, includes);
275e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
276e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  return new FakeBluetoothGattServiceServiceProvider(
277e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      object_path, uuid, includes);
278e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
279e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
280e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}  // namespace chromeos
281