OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 "chromeos/dbus/bluetooth_profile_service_provider.h" | |
6 | |
7 | |
8 #include "base/bind.h" | |
9 #include "base/logging.h" | |
10 #include "base/memory/ref_counted.h" | |
11 #include "base/threading/platform_thread.h" | |
12 #include "chromeos/dbus/dbus_thread_manager.h" | |
13 #include "chromeos/dbus/fake_bluetooth_profile_service_provider.h" | |
14 #include "dbus/exported_object.h" | |
15 #include "dbus/message.h" | |
16 #include "third_party/cros_system_api/dbus/service_constants.h" | |
17 | |
18 namespace chromeos { | |
19 | |
20 // The BluetoothProfileServiceProvider implementation used in production. | |
21 class BluetoothProfileServiceProviderImpl | |
22 : public BluetoothProfileServiceProvider { | |
23 public: | |
24 BluetoothProfileServiceProviderImpl(dbus::Bus* bus, | |
25 const dbus::ObjectPath& object_path, | |
26 Delegate* delegate) | |
27 : origin_thread_id_(base::PlatformThread::CurrentId()), | |
28 bus_(bus), | |
29 delegate_(delegate), | |
30 object_path_(object_path), | |
31 weak_ptr_factory_(this) { | |
32 VLOG(1) << "Creating Bluetooth Profile: " << object_path_.value(); | |
33 | |
34 exported_object_ = bus_->GetExportedObject(object_path_); | |
35 | |
36 exported_object_->ExportMethod( | |
37 bluetooth_profile::kBluetoothProfileInterface, | |
38 bluetooth_profile::kRelease, | |
39 base::Bind(&BluetoothProfileServiceProviderImpl::Release, | |
40 weak_ptr_factory_.GetWeakPtr()), | |
41 base::Bind(&BluetoothProfileServiceProviderImpl::OnExported, | |
42 weak_ptr_factory_.GetWeakPtr())); | |
43 | |
44 exported_object_->ExportMethod( | |
45 bluetooth_profile::kBluetoothProfileInterface, | |
46 bluetooth_profile::kNewConnection, | |
47 base::Bind(&BluetoothProfileServiceProviderImpl::NewConnection, | |
48 weak_ptr_factory_.GetWeakPtr()), | |
49 base::Bind(&BluetoothProfileServiceProviderImpl::OnExported, | |
50 weak_ptr_factory_.GetWeakPtr())); | |
51 | |
52 exported_object_->ExportMethod( | |
53 bluetooth_profile::kBluetoothProfileInterface, | |
54 bluetooth_profile::kRequestDisconnection, | |
55 base::Bind(&BluetoothProfileServiceProviderImpl::RequestDisconnection, | |
56 weak_ptr_factory_.GetWeakPtr()), | |
57 base::Bind(&BluetoothProfileServiceProviderImpl::OnExported, | |
58 weak_ptr_factory_.GetWeakPtr())); | |
59 | |
60 exported_object_->ExportMethod( | |
61 bluetooth_profile::kBluetoothProfileInterface, | |
62 bluetooth_profile::kCancel, | |
63 base::Bind(&BluetoothProfileServiceProviderImpl::Cancel, | |
64 weak_ptr_factory_.GetWeakPtr()), | |
65 base::Bind(&BluetoothProfileServiceProviderImpl::OnExported, | |
66 weak_ptr_factory_.GetWeakPtr())); | |
67 } | |
68 | |
69 ~BluetoothProfileServiceProviderImpl() override { | |
70 VLOG(1) << "Cleaning up Bluetooth Profile: " << object_path_.value(); | |
71 | |
72 // Unregister the object path so we can reuse with a new agent. | |
73 bus_->UnregisterExportedObject(object_path_); | |
74 } | |
75 | |
76 private: | |
77 // Returns true if the current thread is on the origin thread. | |
78 bool OnOriginThread() { | |
79 return base::PlatformThread::CurrentId() == origin_thread_id_; | |
80 } | |
81 | |
82 // Called by dbus:: when the profile is unregistered from the Bluetooth | |
83 // daemon, generally by our request. | |
84 void Release(dbus::MethodCall* method_call, | |
85 dbus::ExportedObject::ResponseSender response_sender) { | |
86 DCHECK(OnOriginThread()); | |
87 DCHECK(delegate_); | |
88 | |
89 delegate_->Released(); | |
90 | |
91 response_sender.Run(dbus::Response::FromMethodCall(method_call)); | |
92 } | |
93 | |
94 // Called by dbus:: when the Bluetooth daemon establishes a new connection | |
95 // to the profile. | |
96 void NewConnection(dbus::MethodCall* method_call, | |
97 dbus::ExportedObject::ResponseSender response_sender) { | |
98 DCHECK(OnOriginThread()); | |
99 DCHECK(delegate_); | |
100 | |
101 dbus::MessageReader reader(method_call); | |
102 dbus::ObjectPath device_path; | |
103 scoped_ptr<dbus::FileDescriptor> fd(new dbus::FileDescriptor()); | |
104 dbus::MessageReader array_reader(NULL); | |
105 if (!reader.PopObjectPath(&device_path) || | |
106 !reader.PopFileDescriptor(fd.get()) || | |
107 !reader.PopArray(&array_reader)) { | |
108 LOG(WARNING) << "NewConnection called with incorrect paramters: " | |
109 << method_call->ToString(); | |
110 return; | |
111 } | |
112 | |
113 Delegate::Options options; | |
114 while (array_reader.HasMoreData()) { | |
115 dbus::MessageReader dict_entry_reader(NULL); | |
116 std::string key; | |
117 if (!array_reader.PopDictEntry(&dict_entry_reader) || | |
118 !dict_entry_reader.PopString(&key)) { | |
119 LOG(WARNING) << "NewConnection called with incorrect paramters: " | |
120 << method_call->ToString(); | |
121 } else { | |
122 if (key == bluetooth_profile::kVersionProperty) | |
123 dict_entry_reader.PopVariantOfUint16(&options.version); | |
124 else if (key == bluetooth_profile::kFeaturesProperty) | |
125 dict_entry_reader.PopVariantOfUint16(&options.features); | |
126 } | |
127 } | |
128 | |
129 Delegate::ConfirmationCallback callback = base::Bind( | |
130 &BluetoothProfileServiceProviderImpl::OnConfirmation, | |
131 weak_ptr_factory_.GetWeakPtr(), | |
132 method_call, | |
133 response_sender); | |
134 | |
135 delegate_->NewConnection(device_path, fd.Pass(), options, callback); | |
136 } | |
137 | |
138 // Called by dbus:: when the Bluetooth daemon is about to disconnect the | |
139 // profile. | |
140 void RequestDisconnection( | |
141 dbus::MethodCall* method_call, | |
142 dbus::ExportedObject::ResponseSender response_sender) { | |
143 DCHECK(OnOriginThread()); | |
144 DCHECK(delegate_); | |
145 | |
146 dbus::MessageReader reader(method_call); | |
147 dbus::ObjectPath device_path; | |
148 if (!reader.PopObjectPath(&device_path)) { | |
149 LOG(WARNING) << "RequestDisconnection called with incorrect paramters: " | |
150 << method_call->ToString(); | |
151 return; | |
152 } | |
153 | |
154 Delegate::ConfirmationCallback callback = base::Bind( | |
155 &BluetoothProfileServiceProviderImpl::OnConfirmation, | |
156 weak_ptr_factory_.GetWeakPtr(), | |
157 method_call, | |
158 response_sender); | |
159 | |
160 delegate_->RequestDisconnection(device_path, callback); | |
161 } | |
162 | |
163 // Called by dbus:: when the request failed before a reply was returned | |
164 // from the device. | |
165 void Cancel(dbus::MethodCall* method_call, | |
166 dbus::ExportedObject::ResponseSender response_sender) { | |
167 DCHECK(OnOriginThread()); | |
168 DCHECK(delegate_); | |
169 | |
170 delegate_->Cancel(); | |
171 | |
172 response_sender.Run(dbus::Response::FromMethodCall(method_call)); | |
173 } | |
174 | |
175 // Called by dbus:: when a method is exported. | |
176 void OnExported(const std::string& interface_name, | |
177 const std::string& method_name, | |
178 bool success) { | |
179 LOG_IF(WARNING, !success) << "Failed to export " | |
180 << interface_name << "." << method_name; | |
181 } | |
182 | |
183 // Called by the Delegate in response to a method requiring confirmation. | |
184 void OnConfirmation(dbus::MethodCall* method_call, | |
185 dbus::ExportedObject::ResponseSender response_sender, | |
186 Delegate::Status status) { | |
187 DCHECK(OnOriginThread()); | |
188 | |
189 switch (status) { | |
190 case Delegate::SUCCESS: { | |
191 response_sender.Run(dbus::Response::FromMethodCall(method_call)); | |
192 break; | |
193 } | |
194 case Delegate::REJECTED: { | |
195 response_sender.Run(dbus::ErrorResponse::FromMethodCall( | |
196 method_call, bluetooth_profile::kErrorRejected, "rejected")); | |
197 break; | |
198 } | |
199 case Delegate::CANCELLED: { | |
200 response_sender.Run(dbus::ErrorResponse::FromMethodCall( | |
201 method_call, bluetooth_profile::kErrorCanceled, "canceled")); | |
202 break; | |
203 } | |
204 default: | |
205 NOTREACHED() << "Unexpected status code from delegate: " << status; | |
206 } | |
207 } | |
208 | |
209 // Origin thread (i.e. the UI thread in production). | |
210 base::PlatformThreadId origin_thread_id_; | |
211 | |
212 // D-Bus bus object is exported on, not owned by this object and must | |
213 // outlive it. | |
214 dbus::Bus* bus_; | |
215 | |
216 // All incoming method calls are passed on to the Delegate and a callback | |
217 // passed to generate the reply. |delegate_| is generally the object that | |
218 // owns this one, and must outlive it. | |
219 Delegate* delegate_; | |
220 | |
221 // D-Bus object path of object we are exporting, kept so we can unregister | |
222 // again in our destructor. | |
223 dbus::ObjectPath object_path_; | |
224 | |
225 // D-Bus object we are exporting, owned by this object. | |
226 scoped_refptr<dbus::ExportedObject> exported_object_; | |
227 | |
228 // Weak pointer factory for generating 'this' pointers that might live longer | |
229 // than we do. | |
230 // Note: This should remain the last member so it'll be destroyed and | |
231 // invalidate its weak pointers before any other members are destroyed. | |
232 base::WeakPtrFactory<BluetoothProfileServiceProviderImpl> weak_ptr_factory_; | |
233 | |
234 DISALLOW_COPY_AND_ASSIGN(BluetoothProfileServiceProviderImpl); | |
235 }; | |
236 | |
237 BluetoothProfileServiceProvider::BluetoothProfileServiceProvider() { | |
238 } | |
239 | |
240 BluetoothProfileServiceProvider::~BluetoothProfileServiceProvider() { | |
241 } | |
242 | |
243 // static | |
244 BluetoothProfileServiceProvider* BluetoothProfileServiceProvider::Create( | |
245 dbus::Bus* bus, | |
246 const dbus::ObjectPath& object_path, | |
247 Delegate* delegate) { | |
248 if (!DBusThreadManager::Get()->IsUsingStub(DBusClientBundle::BLUETOOTH)) { | |
249 return new BluetoothProfileServiceProviderImpl(bus, object_path, delegate); | |
250 } else { | |
251 return new FakeBluetoothProfileServiceProvider(object_path, delegate); | |
252 } | |
253 } | |
254 | |
255 } // namespace chromeos | |
OLD | NEW |