From 627f4f4ec29191d02998358a0b9d8896547ffca1 Mon Sep 17 00:00:00 2001 From: "keybuk@chromium.org" Date: Wed, 12 Jun 2013 14:47:32 +0000 Subject: Bluetooth: drop "Experimental" from Chrome OS backend BUG=221813 TEST=device_unittests Review URL: https://chromiumcodereview.appspot.com/14932007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@205777 0039d316-1c4b-4281-b951-d872f2087c98 --- .../dbus/bluetooth_profile_service_provider.cc | 262 +++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 chromeos/dbus/bluetooth_profile_service_provider.cc (limited to 'chromeos/dbus/bluetooth_profile_service_provider.cc') diff --git a/chromeos/dbus/bluetooth_profile_service_provider.cc b/chromeos/dbus/bluetooth_profile_service_provider.cc new file mode 100644 index 0000000..dda9714 --- /dev/null +++ b/chromeos/dbus/bluetooth_profile_service_provider.cc @@ -0,0 +1,262 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/dbus/bluetooth_profile_service_provider.h" + +#include + +#include "base/bind.h" +#include "base/chromeos/chromeos_version.h" +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "base/threading/platform_thread.h" +#include "chromeos/dbus/fake_bluetooth_profile_service_provider.h" +#include "dbus/bus.h" +#include "dbus/exported_object.h" +#include "dbus/message.h" +#include "dbus/object_path.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +namespace chromeos { + +// The BluetoothProfileServiceProvider implementation used in production. +class BluetoothProfileServiceProviderImpl + : public BluetoothProfileServiceProvider { + public: + BluetoothProfileServiceProviderImpl(dbus::Bus* bus, + const dbus::ObjectPath& object_path, + Delegate* delegate) + : origin_thread_id_(base::PlatformThread::CurrentId()), + bus_(bus), + delegate_(delegate), + object_path_(object_path), + weak_ptr_factory_(this) { + VLOG(1) << "Creating Bluetooth Profile: " << object_path_.value(); + + exported_object_ = bus_->GetExportedObject(object_path_); + + exported_object_->ExportMethod( + bluetooth_profile::kBluetoothProfileInterface, + bluetooth_profile::kRelease, + base::Bind(&BluetoothProfileServiceProviderImpl::Release, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothProfileServiceProviderImpl::OnExported, + weak_ptr_factory_.GetWeakPtr())); + + exported_object_->ExportMethod( + bluetooth_profile::kBluetoothProfileInterface, + bluetooth_profile::kNewConnection, + base::Bind(&BluetoothProfileServiceProviderImpl::NewConnection, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothProfileServiceProviderImpl::OnExported, + weak_ptr_factory_.GetWeakPtr())); + + exported_object_->ExportMethod( + bluetooth_profile::kBluetoothProfileInterface, + bluetooth_profile::kRequestDisconnection, + base::Bind(&BluetoothProfileServiceProviderImpl::RequestDisconnection, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothProfileServiceProviderImpl::OnExported, + weak_ptr_factory_.GetWeakPtr())); + + exported_object_->ExportMethod( + bluetooth_profile::kBluetoothProfileInterface, + bluetooth_profile::kCancel, + base::Bind(&BluetoothProfileServiceProviderImpl::Cancel, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothProfileServiceProviderImpl::OnExported, + weak_ptr_factory_.GetWeakPtr())); + } + + virtual ~BluetoothProfileServiceProviderImpl() { + VLOG(1) << "Cleaning up Bluetooth Profile: " << object_path_.value(); + + // Unregister the object path so we can reuse with a new agent. + bus_->UnregisterExportedObject(object_path_); + } + + private: + // Returns true if the current thread is on the origin thread. + bool OnOriginThread() { + return base::PlatformThread::CurrentId() == origin_thread_id_; + } + + // Called by dbus:: when the profile is unregistered from the Bluetooth + // daemon, generally by our request. + void Release(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { + DCHECK(OnOriginThread()); + DCHECK(delegate_); + + delegate_->Release(); + + response_sender.Run(dbus::Response::FromMethodCall(method_call)); + } + + // Called by dbus:: when the Bluetooth daemon establishes a new connection + // to the profile. + void NewConnection(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { + DCHECK(OnOriginThread()); + DCHECK(delegate_); + + dbus::MessageReader reader(method_call); + dbus::ObjectPath device_path; + scoped_ptr fd(new dbus::FileDescriptor()); + dbus::MessageReader array_reader(NULL); + if (!reader.PopObjectPath(&device_path) || + !reader.PopFileDescriptor(fd.get()) || + !reader.PopArray(&array_reader)) { + LOG(WARNING) << "NewConnection called with incorrect paramters: " + << method_call->ToString(); + return; + } + + Delegate::Options options; + while (array_reader.HasMoreData()) { + dbus::MessageReader dict_entry_reader(NULL); + std::string key; + if (!array_reader.PopDictEntry(&dict_entry_reader) || + !dict_entry_reader.PopString(&key)) { + LOG(WARNING) << "NewConnection called with incorrect paramters: " + << method_call->ToString(); + } else { + if (key == bluetooth_profile::kVersionProperty) + dict_entry_reader.PopVariantOfUint16(&options.version); + else if (key == bluetooth_profile::kFeaturesProperty) + dict_entry_reader.PopVariantOfUint16(&options.features); + } + } + + Delegate::ConfirmationCallback callback = base::Bind( + &BluetoothProfileServiceProviderImpl::OnConfirmation, + weak_ptr_factory_.GetWeakPtr(), + method_call, + response_sender); + + delegate_->NewConnection(device_path, fd.Pass(), options, callback); + } + + // Called by dbus:: when the Bluetooth daemon is about to disconnect the + // profile. + void RequestDisconnection( + dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { + DCHECK(OnOriginThread()); + DCHECK(delegate_); + + dbus::MessageReader reader(method_call); + dbus::ObjectPath device_path; + if (!reader.PopObjectPath(&device_path)) { + LOG(WARNING) << "RequestDisconnection called with incorrect paramters: " + << method_call->ToString(); + return; + } + + Delegate::ConfirmationCallback callback = base::Bind( + &BluetoothProfileServiceProviderImpl::OnConfirmation, + weak_ptr_factory_.GetWeakPtr(), + method_call, + response_sender); + + delegate_->RequestDisconnection(device_path, callback); + } + + // Called by dbus:: when the request failed before a reply was returned + // from the device. + void Cancel(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { + DCHECK(OnOriginThread()); + DCHECK(delegate_); + + delegate_->Cancel(); + + response_sender.Run(dbus::Response::FromMethodCall(method_call)); + } + + // Called by dbus:: when a method is exported. + void OnExported(const std::string& interface_name, + const std::string& method_name, + bool success) { + LOG_IF(WARNING, !success) << "Failed to export " + << interface_name << "." << method_name; + } + + // Called by the Delegate in response to a method requiring confirmation. + void OnConfirmation(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender, + Delegate::Status status) { + DCHECK(OnOriginThread()); + + switch (status) { + case Delegate::SUCCESS: { + response_sender.Run(dbus::Response::FromMethodCall(method_call)); + break; + } + case Delegate::REJECTED: { + response_sender.Run( + dbus::ErrorResponse::FromMethodCall( + method_call, bluetooth_profile::kErrorRejected, "rejected") + .PassAs()); + break; + } + case Delegate::CANCELLED: { + response_sender.Run( + dbus::ErrorResponse::FromMethodCall( + method_call, bluetooth_profile::kErrorCanceled, "canceled") + .PassAs()); + break; + } + default: + NOTREACHED() << "Unexpected status code from delegate: " << status; + } + } + + // Origin thread (i.e. the UI thread in production). + base::PlatformThreadId origin_thread_id_; + + // D-Bus bus object is exported on, not owned by this object and must + // outlive it. + dbus::Bus* bus_; + + // All incoming method calls are passed on to the Delegate and a callback + // passed to generate the reply. |delegate_| is generally the object that + // owns this one, and must outlive it. + Delegate* delegate_; + + // D-Bus object path of object we are exporting, kept so we can unregister + // again in our destructor. + dbus::ObjectPath object_path_; + + // D-Bus object we are exporting, owned by this object. + scoped_refptr exported_object_; + + // Weak pointer factory for generating 'this' pointers that might live longer + // than we do. + // Note: This should remain the last member so it'll be destroyed and + // invalidate its weak pointers before any other members are destroyed. + base::WeakPtrFactory weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothProfileServiceProviderImpl); +}; + +BluetoothProfileServiceProvider::BluetoothProfileServiceProvider() { +} + +BluetoothProfileServiceProvider::~BluetoothProfileServiceProvider() { +} + +// static +BluetoothProfileServiceProvider* BluetoothProfileServiceProvider::Create( + dbus::Bus* bus, + const dbus::ObjectPath& object_path, + Delegate* delegate) { + if (base::chromeos::IsRunningOnChromeOS()) { + return new BluetoothProfileServiceProviderImpl(bus, object_path, delegate); + } else { + return new FakeBluetoothProfileServiceProvider(object_path, delegate); + } +} + +} // namespace chromeos -- cgit v1.1