• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_agent_service_provider.h"
6 
7 #include <string>
8 
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/sys_info.h"
13 #include "base/threading/platform_thread.h"
14 #include "chromeos/dbus/fake_bluetooth_agent_service_provider.h"
15 #include "dbus/bus.h"
16 #include "dbus/exported_object.h"
17 #include "dbus/message.h"
18 #include "dbus/object_path.h"
19 #include "third_party/cros_system_api/dbus/service_constants.h"
20 
21 namespace chromeos {
22 
23 // The BluetoothAgentServiceProvider implementation used in production.
24 class BluetoothAgentServiceProviderImpl
25     : public BluetoothAgentServiceProvider {
26  public:
BluetoothAgentServiceProviderImpl(dbus::Bus * bus,const dbus::ObjectPath & object_path,Delegate * delegate)27   BluetoothAgentServiceProviderImpl(dbus::Bus* bus,
28                                     const dbus::ObjectPath& object_path,
29                                     Delegate* delegate)
30       : origin_thread_id_(base::PlatformThread::CurrentId()),
31         bus_(bus),
32         delegate_(delegate),
33         object_path_(object_path),
34         weak_ptr_factory_(this) {
35     VLOG(1) << "Creating Bluetooth Agent: " << object_path_.value();
36 
37     exported_object_ = bus_->GetExportedObject(object_path_);
38 
39     exported_object_->ExportMethod(
40         bluetooth_agent::kBluetoothAgentInterface,
41         bluetooth_agent::kRelease,
42         base::Bind(&BluetoothAgentServiceProviderImpl::Release,
43                    weak_ptr_factory_.GetWeakPtr()),
44         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
45                    weak_ptr_factory_.GetWeakPtr()));
46 
47     exported_object_->ExportMethod(
48         bluetooth_agent::kBluetoothAgentInterface,
49         bluetooth_agent::kRequestPinCode,
50         base::Bind(&BluetoothAgentServiceProviderImpl::RequestPinCode,
51                    weak_ptr_factory_.GetWeakPtr()),
52         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
53                    weak_ptr_factory_.GetWeakPtr()));
54 
55     exported_object_->ExportMethod(
56         bluetooth_agent::kBluetoothAgentInterface,
57         bluetooth_agent::kDisplayPinCode,
58         base::Bind(&BluetoothAgentServiceProviderImpl::DisplayPinCode,
59                    weak_ptr_factory_.GetWeakPtr()),
60         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
61                    weak_ptr_factory_.GetWeakPtr()));
62 
63     exported_object_->ExportMethod(
64         bluetooth_agent::kBluetoothAgentInterface,
65         bluetooth_agent::kRequestPasskey,
66         base::Bind(&BluetoothAgentServiceProviderImpl::RequestPasskey,
67                    weak_ptr_factory_.GetWeakPtr()),
68         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
69                    weak_ptr_factory_.GetWeakPtr()));
70 
71     exported_object_->ExportMethod(
72         bluetooth_agent::kBluetoothAgentInterface,
73         bluetooth_agent::kDisplayPasskey,
74         base::Bind(&BluetoothAgentServiceProviderImpl::DisplayPasskey,
75                    weak_ptr_factory_.GetWeakPtr()),
76         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
77                    weak_ptr_factory_.GetWeakPtr()));
78 
79     exported_object_->ExportMethod(
80         bluetooth_agent::kBluetoothAgentInterface,
81         bluetooth_agent::kRequestConfirmation,
82         base::Bind(&BluetoothAgentServiceProviderImpl::RequestConfirmation,
83                    weak_ptr_factory_.GetWeakPtr()),
84         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
85                    weak_ptr_factory_.GetWeakPtr()));
86 
87     exported_object_->ExportMethod(
88         bluetooth_agent::kBluetoothAgentInterface,
89         bluetooth_agent::kRequestAuthorization,
90         base::Bind(&BluetoothAgentServiceProviderImpl::RequestAuthorization,
91                    weak_ptr_factory_.GetWeakPtr()),
92         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
93                    weak_ptr_factory_.GetWeakPtr()));
94 
95     exported_object_->ExportMethod(
96         bluetooth_agent::kBluetoothAgentInterface,
97         bluetooth_agent::kAuthorizeService,
98         base::Bind(&BluetoothAgentServiceProviderImpl::AuthorizeService,
99                    weak_ptr_factory_.GetWeakPtr()),
100         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
101                    weak_ptr_factory_.GetWeakPtr()));
102 
103     exported_object_->ExportMethod(
104         bluetooth_agent::kBluetoothAgentInterface,
105         bluetooth_agent::kCancel,
106         base::Bind(&BluetoothAgentServiceProviderImpl::Cancel,
107                    weak_ptr_factory_.GetWeakPtr()),
108         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
109                    weak_ptr_factory_.GetWeakPtr()));
110   }
111 
~BluetoothAgentServiceProviderImpl()112   virtual ~BluetoothAgentServiceProviderImpl() {
113     VLOG(1) << "Cleaning up Bluetooth Agent: " << object_path_.value();
114 
115     // Unregister the object path so we can reuse with a new agent.
116     bus_->UnregisterExportedObject(object_path_);
117   }
118 
119  private:
120   // Returns true if the current thread is on the origin thread.
OnOriginThread()121   bool OnOriginThread() {
122     return base::PlatformThread::CurrentId() == origin_thread_id_;
123   }
124 
125   // Called by dbus:: when the agent is unregistered from the Bluetooth
126   // daemon, generally at the end of a pairing request.
Release(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)127   void Release(dbus::MethodCall* method_call,
128                dbus::ExportedObject::ResponseSender response_sender) {
129     DCHECK(OnOriginThread());
130     DCHECK(delegate_);
131 
132     delegate_->Released();
133 
134     response_sender.Run(dbus::Response::FromMethodCall(method_call));
135   }
136 
137   // Called by dbus:: when the Bluetooth daemon requires a PIN Code for
138   // device authentication.
RequestPinCode(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)139   void RequestPinCode(dbus::MethodCall* method_call,
140                       dbus::ExportedObject::ResponseSender response_sender) {
141     DCHECK(OnOriginThread());
142     DCHECK(delegate_);
143 
144     dbus::MessageReader reader(method_call);
145     dbus::ObjectPath device_path;
146     if (!reader.PopObjectPath(&device_path)) {
147       LOG(WARNING) << "RequestPinCode called with incorrect paramters: "
148                    << method_call->ToString();
149       return;
150     }
151 
152     Delegate::PinCodeCallback callback = base::Bind(
153         &BluetoothAgentServiceProviderImpl::OnPinCode,
154         weak_ptr_factory_.GetWeakPtr(),
155         method_call,
156         response_sender);
157 
158     delegate_->RequestPinCode(device_path, callback);
159   }
160 
161   // Called by dbus:: when the Bluetooth daemon requires that the user
162   // enter a PIN Code into the remote device so that it may be
163   // authenticated.
DisplayPinCode(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)164   void DisplayPinCode(dbus::MethodCall* method_call,
165                       dbus::ExportedObject::ResponseSender response_sender) {
166     DCHECK(OnOriginThread());
167     DCHECK(delegate_);
168 
169     dbus::MessageReader reader(method_call);
170     dbus::ObjectPath device_path;
171     std::string pincode;
172     if (!reader.PopObjectPath(&device_path) ||
173         !reader.PopString(&pincode)) {
174       LOG(WARNING) << "DisplayPinCode called with incorrect paramters: "
175                    << method_call->ToString();
176       return;
177     }
178 
179     delegate_->DisplayPinCode(device_path, pincode);
180 
181     response_sender.Run(dbus::Response::FromMethodCall(method_call));
182   }
183 
184   // Called by dbus:: when the Bluetooth daemon requires a Passkey for
185   // device authentication.
RequestPasskey(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)186   void RequestPasskey(dbus::MethodCall* method_call,
187                       dbus::ExportedObject::ResponseSender response_sender) {
188     DCHECK(OnOriginThread());
189     DCHECK(delegate_);
190 
191     dbus::MessageReader reader(method_call);
192     dbus::ObjectPath device_path;
193     if (!reader.PopObjectPath(&device_path)) {
194       LOG(WARNING) << "RequestPasskey called with incorrect paramters: "
195                    << method_call->ToString();
196       return;
197     }
198 
199     Delegate::PasskeyCallback callback = base::Bind(
200         &BluetoothAgentServiceProviderImpl::OnPasskey,
201         weak_ptr_factory_.GetWeakPtr(),
202         method_call,
203         response_sender);
204 
205     delegate_->RequestPasskey(device_path, callback);
206   }
207 
208   // Called by dbus:: when the Bluetooth daemon requires that the user
209   // enter a Passkey into the remote device so that it may be
210   // authenticated.
DisplayPasskey(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)211   void DisplayPasskey(dbus::MethodCall* method_call,
212                       dbus::ExportedObject::ResponseSender response_sender) {
213     DCHECK(OnOriginThread());
214     DCHECK(delegate_);
215 
216     dbus::MessageReader reader(method_call);
217     dbus::ObjectPath device_path;
218     uint32 passkey;
219     uint16 entered;
220     if (!reader.PopObjectPath(&device_path) ||
221         !reader.PopUint32(&passkey) ||
222         !reader.PopUint16(&entered)) {
223       LOG(WARNING) << "DisplayPasskey called with incorrect paramters: "
224                    << method_call->ToString();
225       return;
226     }
227 
228     delegate_->DisplayPasskey(device_path, passkey, entered);
229 
230     response_sender.Run(dbus::Response::FromMethodCall(method_call));
231   }
232 
233   // Called by dbus:: when the Bluetooth daemon requires that the user
234   // confirm that a Passkey is displayed on the screen of the remote
235   // device so that it may be authenticated.
RequestConfirmation(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)236   void RequestConfirmation(
237       dbus::MethodCall* method_call,
238       dbus::ExportedObject::ResponseSender response_sender) {
239     DCHECK(OnOriginThread());
240     DCHECK(delegate_);
241 
242     dbus::MessageReader reader(method_call);
243     dbus::ObjectPath device_path;
244     uint32 passkey;
245     if (!reader.PopObjectPath(&device_path) ||
246         !reader.PopUint32(&passkey)) {
247       LOG(WARNING) << "RequestConfirmation called with incorrect paramters: "
248                    << method_call->ToString();
249       return;
250     }
251 
252     Delegate::ConfirmationCallback callback = base::Bind(
253         &BluetoothAgentServiceProviderImpl::OnConfirmation,
254         weak_ptr_factory_.GetWeakPtr(),
255         method_call,
256         response_sender);
257 
258     delegate_->RequestConfirmation(device_path, passkey, callback);
259   }
260 
261   // Called by dbus:: when the Bluetooth daemon requires that the user
262   // confirm an incoming just-works pairing.
RequestAuthorization(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)263   void RequestAuthorization(
264         dbus::MethodCall* method_call,
265         dbus::ExportedObject::ResponseSender response_sender) {
266     DCHECK(OnOriginThread());
267     DCHECK(delegate_);
268 
269     dbus::MessageReader reader(method_call);
270     dbus::ObjectPath device_path;
271     if (!reader.PopObjectPath(&device_path)) {
272       LOG(WARNING) << "RequestAuthorization called with incorrect paramters: "
273                    << method_call->ToString();
274       return;
275     }
276 
277     Delegate::ConfirmationCallback callback = base::Bind(
278         &BluetoothAgentServiceProviderImpl::OnConfirmation,
279         weak_ptr_factory_.GetWeakPtr(),
280         method_call,
281         response_sender);
282 
283     delegate_->RequestAuthorization(device_path, callback);
284   }
285 
286   // Called by dbus:: when the Bluetooth daemon requires that the user
287   // confirm that that a remote device is authorized to connect to a service
288   // UUID.
AuthorizeService(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)289   void AuthorizeService(dbus::MethodCall* method_call,
290                         dbus::ExportedObject::ResponseSender response_sender) {
291     DCHECK(OnOriginThread());
292     DCHECK(delegate_);
293 
294     dbus::MessageReader reader(method_call);
295     dbus::ObjectPath device_path;
296     std::string uuid;
297     if (!reader.PopObjectPath(&device_path) ||
298         !reader.PopString(&uuid)) {
299       LOG(WARNING) << "AuthorizeService called with incorrect paramters: "
300                    << method_call->ToString();
301       return;
302     }
303 
304     Delegate::ConfirmationCallback callback = base::Bind(
305         &BluetoothAgentServiceProviderImpl::OnConfirmation,
306         weak_ptr_factory_.GetWeakPtr(),
307         method_call,
308         response_sender);
309 
310     delegate_->AuthorizeService(device_path, uuid, callback);
311   }
312 
313   // Called by dbus:: when the request failed before a reply was returned
314   // from the device.
Cancel(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)315   void Cancel(dbus::MethodCall* method_call,
316               dbus::ExportedObject::ResponseSender response_sender) {
317     DCHECK(OnOriginThread());
318     DCHECK(delegate_);
319 
320     delegate_->Cancel();
321 
322     response_sender.Run(dbus::Response::FromMethodCall(method_call));
323   }
324 
325   // Called by dbus:: when a method is exported.
OnExported(const std::string & interface_name,const std::string & method_name,bool success)326   void OnExported(const std::string& interface_name,
327                   const std::string& method_name,
328                   bool success) {
329     LOG_IF(WARNING, !success) << "Failed to export "
330                               << interface_name << "." << method_name;
331   }
332 
333   // Called by the Delegate to response to a method requesting a PIN code.
OnPinCode(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender,Delegate::Status status,const std::string & pincode)334   void OnPinCode(dbus::MethodCall* method_call,
335                  dbus::ExportedObject::ResponseSender response_sender,
336                  Delegate::Status status,
337                  const std::string& pincode) {
338     DCHECK(OnOriginThread());
339 
340     switch (status) {
341       case Delegate::SUCCESS: {
342         scoped_ptr<dbus::Response> response(
343             dbus::Response::FromMethodCall(method_call));
344         dbus::MessageWriter writer(response.get());
345         writer.AppendString(pincode);
346         response_sender.Run(response.Pass());
347         break;
348       }
349       case Delegate::REJECTED: {
350         response_sender.Run(
351             dbus::ErrorResponse::FromMethodCall(
352                 method_call, bluetooth_agent::kErrorRejected, "rejected")
353             .PassAs<dbus::Response>());
354         break;
355       }
356       case Delegate::CANCELLED: {
357         response_sender.Run(
358             dbus::ErrorResponse::FromMethodCall(
359                 method_call, bluetooth_agent::kErrorCanceled, "canceled")
360             .PassAs<dbus::Response>());
361         break;
362       }
363       default:
364         NOTREACHED() << "Unexpected status code from delegate: " << status;
365     }
366   }
367 
368   // Called by the Delegate to response to a method requesting a Passkey.
OnPasskey(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender,Delegate::Status status,uint32 passkey)369   void OnPasskey(dbus::MethodCall* method_call,
370                  dbus::ExportedObject::ResponseSender response_sender,
371                  Delegate::Status status,
372                  uint32 passkey) {
373     DCHECK(OnOriginThread());
374 
375     switch (status) {
376       case Delegate::SUCCESS: {
377         scoped_ptr<dbus::Response> response(
378             dbus::Response::FromMethodCall(method_call));
379         dbus::MessageWriter writer(response.get());
380         writer.AppendUint32(passkey);
381         response_sender.Run(response.Pass());
382         break;
383       }
384       case Delegate::REJECTED: {
385         response_sender.Run(
386             dbus::ErrorResponse::FromMethodCall(
387                 method_call, bluetooth_agent::kErrorRejected, "rejected")
388             .PassAs<dbus::Response>());
389         break;
390       }
391       case Delegate::CANCELLED: {
392         response_sender.Run(
393             dbus::ErrorResponse::FromMethodCall(
394                 method_call, bluetooth_agent::kErrorCanceled, "canceled")
395             .PassAs<dbus::Response>());
396         break;
397       }
398       default:
399         NOTREACHED() << "Unexpected status code from delegate: " << status;
400     }
401   }
402 
403   // Called by the Delegate in response to a method requiring confirmation.
OnConfirmation(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender,Delegate::Status status)404   void OnConfirmation(dbus::MethodCall* method_call,
405                       dbus::ExportedObject::ResponseSender response_sender,
406                       Delegate::Status status) {
407     DCHECK(OnOriginThread());
408 
409     switch (status) {
410       case Delegate::SUCCESS: {
411         response_sender.Run(dbus::Response::FromMethodCall(method_call));
412         break;
413       }
414       case Delegate::REJECTED: {
415         response_sender.Run(
416             dbus::ErrorResponse::FromMethodCall(
417                 method_call, bluetooth_agent::kErrorRejected, "rejected")
418             .PassAs<dbus::Response>());
419         break;
420       }
421       case Delegate::CANCELLED: {
422         response_sender.Run(
423             dbus::ErrorResponse::FromMethodCall(
424                 method_call, bluetooth_agent::kErrorCanceled, "canceled")
425             .PassAs<dbus::Response>());
426         break;
427       }
428       default:
429         NOTREACHED() << "Unexpected status code from delegate: " << status;
430     }
431   }
432 
433   // Origin thread (i.e. the UI thread in production).
434   base::PlatformThreadId origin_thread_id_;
435 
436   // D-Bus bus object is exported on, not owned by this object and must
437   // outlive it.
438   dbus::Bus* bus_;
439 
440   // All incoming method calls are passed on to the Delegate and a callback
441   // passed to generate the reply. |delegate_| is generally the object that
442   // owns this one, and must outlive it.
443   Delegate* delegate_;
444 
445   // D-Bus object path of object we are exporting, kept so we can unregister
446   // again in our destructor.
447   dbus::ObjectPath object_path_;
448 
449   // D-Bus object we are exporting, owned by this object.
450   scoped_refptr<dbus::ExportedObject> exported_object_;
451 
452   // Weak pointer factory for generating 'this' pointers that might live longer
453   // than we do.
454   // Note: This should remain the last member so it'll be destroyed and
455   // invalidate its weak pointers before any other members are destroyed.
456   base::WeakPtrFactory<BluetoothAgentServiceProviderImpl> weak_ptr_factory_;
457 
458   DISALLOW_COPY_AND_ASSIGN(BluetoothAgentServiceProviderImpl);
459 };
460 
BluetoothAgentServiceProvider()461 BluetoothAgentServiceProvider::BluetoothAgentServiceProvider() {
462 }
463 
~BluetoothAgentServiceProvider()464 BluetoothAgentServiceProvider::~BluetoothAgentServiceProvider() {
465 }
466 
467 // static
Create(dbus::Bus * bus,const dbus::ObjectPath & object_path,Delegate * delegate)468 BluetoothAgentServiceProvider* BluetoothAgentServiceProvider::Create(
469     dbus::Bus* bus,
470     const dbus::ObjectPath& object_path,
471     Delegate* delegate) {
472   if (base::SysInfo::IsRunningOnChromeOS()) {
473     return new BluetoothAgentServiceProviderImpl(bus, object_path, delegate);
474   } else {
475     return new FakeBluetoothAgentServiceProvider(object_path, delegate);
476   }
477 }
478 
479 }  // namespace chromeos
480