diff options
author | keybuk@chromium.org <keybuk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-30 21:45:44 +0000 |
---|---|---|
committer | keybuk@chromium.org <keybuk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-30 21:45:44 +0000 |
commit | 559a9a4fd35509a6acd6a10bb463230e1512eb1b (patch) | |
tree | daf57ec754c68bb97e060b18a17893487a4bda60 /chrome/browser | |
parent | 0bb29bdceb67aab9bb19599380938d2cd6f60306 (diff) | |
download | chromium_src-559a9a4fd35509a6acd6a10bb463230e1512eb1b.zip chromium_src-559a9a4fd35509a6acd6a10bb463230e1512eb1b.tar.gz chromium_src-559a9a4fd35509a6acd6a10bb463230e1512eb1b.tar.bz2 |
Move methods from chrome.bluetooth to chrome.bluetoothSocket
The updateSocket(), setSocketPaused(), send(), getSocket() and
getSockets() are moved to chrome.bluetoothSocket, renaming as necessary,
with the old implementation replaced by a stub that returns an error.
When un-paused sockets generate chrome.bluetoothSocket.onReceive and
chrome.bluetoothSocket.onReceiveError events instead of the old events
which are now unused.
Also implements chrome.bluetoothSocket.create() and close() to complete
the lifetime of the socket.
Since BluetoothSocket is self-contained, and does not need references to
the adapter or observer methods, BluetoothSocketEventDispatcher changes
from being a refcounted object to BrowserContextKeyedAPI, matching the
sockets API.
BUG=349475,364581
Review URL: https://codereview.chromium.org/252673004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@267344 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/extensions/api/bluetooth/bluetooth_api.cc | 257 | ||||
-rw-r--r-- | chrome/browser/extensions/api/bluetooth/bluetooth_api.h | 116 | ||||
-rw-r--r-- | chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.cc | 59 | ||||
-rw-r--r-- | chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h | 20 | ||||
-rw-r--r-- | chrome/browser/extensions/api/bluetooth/bluetooth_socket_event_dispatcher.h | 81 | ||||
-rw-r--r-- | chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.cc | 355 | ||||
-rw-r--r-- | chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.h | 170 | ||||
-rw-r--r-- | chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_event_dispatcher.cc (renamed from chrome/browser/extensions/api/bluetooth/bluetooth_socket_event_dispatcher.cc) | 100 | ||||
-rw-r--r-- | chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h | 94 | ||||
-rw-r--r-- | chrome/browser/extensions/browser_context_keyed_service_factories.cc | 2 |
10 files changed, 744 insertions, 510 deletions
diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc b/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc index 52c631e..77128f8 100644 --- a/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc +++ b/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc @@ -10,7 +10,6 @@ #include "base/memory/ref_counted.h" #include "chrome/browser/extensions/api/bluetooth/bluetooth_api_utils.h" #include "chrome/browser/extensions/api/bluetooth/bluetooth_event_router.h" -#include "chrome/browser/extensions/api/bluetooth/bluetooth_socket_event_dispatcher.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/extensions/api/bluetooth.h" #include "chrome/common/extensions/api/bluetooth/bluetooth_manifest_data.h" @@ -60,7 +59,6 @@ const char kProfileAlreadyRegistered[] = "This profile has already been registered"; const char kProfileNotFound[] = "Profile not found: invalid uuid"; const char kProfileRegistrationFailed[] = "Profile registration failed"; -const char kSocketNotFoundError[] = "Socket not found: invalid socket id"; const char kStartDiscoveryFailed[] = "Starting discovery failed"; const char kStopDiscoveryFailed[] = "Failed to stop discovery"; @@ -70,42 +68,6 @@ extensions::BluetoothEventRouter* GetEventRouter(BrowserContext* context) { return extensions::BluetoothAPI::Get(context)->event_router(); } -linked_ptr<bluetooth::Socket> CreateSocketInfo(int socket_id, - BluetoothApiSocket* socket) { - DCHECK(BrowserThread::CurrentlyOn(BluetoothApiSocket::kThreadId)); - linked_ptr<bluetooth::Socket> socket_info(new bluetooth::Socket()); - // This represents what we know about the socket, and does not call through - // to the system. - socket_info->id = socket_id; - if (!socket->name().empty()) { - socket_info->name.reset(new std::string(socket->name())); - } - socket_info->persistent = socket->persistent(); - if (socket->buffer_size() > 0) { - socket_info->buffer_size.reset(new int(socket->buffer_size())); - } - socket_info->paused = socket->paused(); - socket_info->device.address = socket->device_address(); - socket_info->uuid = socket->uuid().canonical_value(); - - return socket_info; -} - -void SetSocketProperties(extensions::BluetoothApiSocket* socket, - bluetooth::SocketProperties* properties) { - if (properties->name.get()) { - socket->set_name(*properties->name.get()); - } - if (properties->persistent.get()) { - socket->set_persistent(*properties->persistent.get()); - } - if (properties->buffer_size.get()) { - // buffer size is validated when issuing the actual Recv operation - // on the socket. - socket->set_buffer_size(*properties->buffer_size.get()); - } -} - static void DispatchConnectionEventWorker( void* browser_context_id, const std::string& extension_id, @@ -188,15 +150,6 @@ scoped_refptr<BluetoothAPI::SocketData> BluetoothAPI::socket_data() { return socket_data_; } -scoped_refptr<api::BluetoothSocketEventDispatcher> -BluetoothAPI::socket_event_dispatcher() { - if (!socket_event_dispatcher_) { - socket_event_dispatcher_ = new api::BluetoothSocketEventDispatcher( - browser_context_, socket_data()); - } - return socket_event_dispatcher_; -} - void BluetoothAPI::Shutdown() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); EventRouter::Get(browser_context_)->UnregisterObserver(this); @@ -296,38 +249,6 @@ void BluetoothAPI::RegisterSocketWithAdapterUI( namespace api { -BluetoothSocketApiFunction::BluetoothSocketApiFunction() {} - -BluetoothSocketApiFunction::~BluetoothSocketApiFunction() {} - -bool BluetoothSocketApiFunction::RunImpl() { - if (!PrePrepare() || !Prepare()) { - return false; - } - AsyncWorkStart(); - return true; -} - -bool BluetoothSocketApiFunction::PrePrepare() { - socket_data_ = BluetoothAPI::Get(browser_context())->socket_data(); - socket_event_dispatcher_ = - BluetoothAPI::Get(browser_context())->socket_event_dispatcher(); - return socket_data_ && socket_event_dispatcher_; -} - -void BluetoothSocketApiFunction::AsyncWorkStart() { - Work(); - AsyncWorkCompleted(); -} - -void BluetoothSocketApiFunction::Work() {} - -void BluetoothSocketApiFunction::AsyncWorkCompleted() { - SendResponse(Respond()); -} - -bool BluetoothSocketApiFunction::Respond() { return error_.empty(); } - BluetoothGetAdapterStateFunction::~BluetoothGetAdapterStateFunction() {} bool BluetoothGetAdapterStateFunction::DoWork( @@ -553,170 +474,40 @@ void BluetoothConnectFunction::OnErrorCallback(const std::string& error) { SendResponse(false); } -BluetoothDisconnectFunction::BluetoothDisconnectFunction() {} - -BluetoothDisconnectFunction::~BluetoothDisconnectFunction() {} - -bool BluetoothDisconnectFunction::Prepare() { - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - params_ = Disconnect::Params::Create(*args_); - EXTENSION_FUNCTION_VALIDATE(params_.get() != NULL); - return true; -} - -void BluetoothDisconnectFunction::AsyncWorkStart() { - DCHECK(BrowserThread::CurrentlyOn(work_thread_id())); - BluetoothApiSocket* socket = - socket_data_->Get(extension_id(), params_->options.socket_id); - if (!socket) { - error_ = kSocketNotFoundError; - return; - } - socket->Disconnect(base::Bind(&BluetoothDisconnectFunction::OnSuccess, this)); -} - -void BluetoothDisconnectFunction::OnSuccess() { - DCHECK(BrowserThread::CurrentlyOn(work_thread_id())); - socket_data_->Remove(extension_id(), params_->options.socket_id); - results_ = bluetooth::Disconnect::Results::Create(); - AsyncWorkCompleted(); -} - -BluetoothSendFunction::BluetoothSendFunction() : io_buffer_size_(0) {} - -BluetoothSendFunction::~BluetoothSendFunction() {} - -bool BluetoothSendFunction::Prepare() { - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - params_ = Send::Params::Create(*args_); - EXTENSION_FUNCTION_VALIDATE(params_.get() != NULL); - io_buffer_size_ = params_->data.size(); - io_buffer_ = new net::WrappedIOBuffer(params_->data.data()); - return true; -} - -void BluetoothSendFunction::AsyncWorkStart() { - DCHECK(BrowserThread::CurrentlyOn(work_thread_id())); - BluetoothApiSocket* socket = - socket_data_->Get(extension_id(), params_->socket_id); - if (!socket) { - error_ = kSocketNotFoundError; - return; - } - socket->Send(io_buffer_, - io_buffer_size_, - base::Bind(&BluetoothSendFunction::OnSendSuccess, this), - base::Bind(&BluetoothSendFunction::OnSendError, this)); -} - -void BluetoothSendFunction::OnSendSuccess(int bytes_sent) { - DCHECK(BrowserThread::CurrentlyOn(work_thread_id())); - results_ = Send::Results::Create(bytes_sent); - AsyncWorkCompleted(); -} - -void BluetoothSendFunction::OnSendError(const std::string& message) { - DCHECK(BrowserThread::CurrentlyOn(work_thread_id())); - error_ = message; - AsyncWorkCompleted(); -} - -BluetoothUpdateSocketFunction::BluetoothUpdateSocketFunction() {} - -BluetoothUpdateSocketFunction::~BluetoothUpdateSocketFunction() {} - -bool BluetoothUpdateSocketFunction::Prepare() { - params_ = bluetooth::UpdateSocket::Params::Create(*args_); - EXTENSION_FUNCTION_VALIDATE(params_.get()); - return true; -} - -void BluetoothUpdateSocketFunction::Work() { - BluetoothApiSocket* socket = - socket_data_->Get(extension_id(), params_->socket_id); - if (!socket) { - error_ = kSocketNotFoundError; - return; - } - - SetSocketProperties(socket, ¶ms_.get()->properties); - results_ = bluetooth::UpdateSocket::Results::Create(); +bool BluetoothDisconnectFunction::RunImpl() { + // TODO(keybuk): Remove. + SetError("Removed. Use chrome.bluetoothSocket.disconnect() instead."); + return false; } -BluetoothSetSocketPausedFunction::BluetoothSetSocketPausedFunction() {} - -BluetoothSetSocketPausedFunction::~BluetoothSetSocketPausedFunction() {} - -bool BluetoothSetSocketPausedFunction::Prepare() { - params_ = bluetooth::SetSocketPaused::Params::Create(*args_); - EXTENSION_FUNCTION_VALIDATE(params_.get()); - return true; +bool BluetoothSendFunction::RunImpl() { + // TODO(keybuk): Remove. + SetError("Removed. Use chrome.bluetoothSocket.send() instead."); + return false; } -void BluetoothSetSocketPausedFunction::Work() { - BluetoothApiSocket* socket = - socket_data_->Get(extension_id(), params_->socket_id); - if (!socket) { - error_ = kSocketNotFoundError; - return; - } - - if (socket->paused() != params_->paused) { - socket->set_paused(params_->paused); - if (!params_->paused) { - socket_event_dispatcher_->OnSocketResume(extension_->id(), - params_->socket_id); - } - } - - results_ = bluetooth::SetSocketPaused::Results::Create(); +bool BluetoothUpdateSocketFunction::RunImpl() { + // TODO(keybuk): Remove. + SetError("Removed. Use chrome.bluetoothSocket.update() instead."); + return false; } -BluetoothGetSocketFunction::BluetoothGetSocketFunction() {} - -BluetoothGetSocketFunction::~BluetoothGetSocketFunction() {} - -bool BluetoothGetSocketFunction::Prepare() { - params_ = bluetooth::GetSocket::Params::Create(*args_); - EXTENSION_FUNCTION_VALIDATE(params_.get()); - return true; +bool BluetoothSetSocketPausedFunction::RunImpl() { + // TODO(keybuk): Remove. + SetError("Removed. Use chrome.bluetoothSocket.setPaused() instead."); + return false; } -void BluetoothGetSocketFunction::Work() { - BluetoothApiSocket* socket = - socket_data_->Get(extension_id(), params_->socket_id); - if (!socket) { - error_ = kSocketNotFoundError; - return; - } - - linked_ptr<bluetooth::Socket> socket_info = - CreateSocketInfo(params_->socket_id, socket); - results_ = bluetooth::GetSocket::Results::Create(*socket_info); +bool BluetoothGetSocketFunction::RunImpl() { + // TODO(keybuk): Remove. + SetError("Removed. Use chrome.bluetoothSocket.getInfo() instead."); + return false; } -BluetoothGetSocketsFunction::BluetoothGetSocketsFunction() {} - -BluetoothGetSocketsFunction::~BluetoothGetSocketsFunction() {} - -bool BluetoothGetSocketsFunction::Prepare() { return true; } - -void BluetoothGetSocketsFunction::Work() { - std::vector<linked_ptr<bluetooth::Socket> > socket_infos; - base::hash_set<int>* resource_ids = - socket_data_->GetResourceIds(extension_id()); - if (resource_ids != NULL) { - for (base::hash_set<int>::iterator it = resource_ids->begin(); - it != resource_ids->end(); - ++it) { - int socket_id = *it; - BluetoothApiSocket* socket = socket_data_->Get(extension_id(), socket_id); - if (socket) { - socket_infos.push_back(CreateSocketInfo(socket_id, socket)); - } - } - } - results_ = bluetooth::GetSockets::Results::Create(socket_infos); +bool BluetoothGetSocketsFunction::RunImpl() { + // TODO(keybuk): Remove. + SetError("Removed. Use chrome.bluetoothSocket.getSockets() instead."); + return false; } void BluetoothSetOutOfBandPairingDataFunction::OnSuccessCallback() { diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_api.h b/chrome/browser/extensions/api/bluetooth/bluetooth_api.h index 8cfa295..9ce771e 100644 --- a/chrome/browser/extensions/api/bluetooth/bluetooth_api.h +++ b/chrome/browser/extensions/api/bluetooth/bluetooth_api.h @@ -70,7 +70,6 @@ class BluetoothAPI : public BrowserContextKeyedAPI, BluetoothEventRouter* event_router(); scoped_refptr<SocketData> socket_data(); - scoped_refptr<api::BluetoothSocketEventDispatcher> socket_event_dispatcher(); // KeyedService implementation. virtual void Shutdown() OVERRIDE; @@ -105,41 +104,10 @@ class BluetoothAPI : public BrowserContextKeyedAPI, // Created lazily on first access. scoped_ptr<BluetoothEventRouter> event_router_; scoped_refptr<SocketData> socket_data_; - scoped_refptr<api::BluetoothSocketEventDispatcher> socket_event_dispatcher_; }; namespace api { -class BluetoothSocketEventDispatcher; - -// Base class for methods dealing with BluetoothSocketApi and -// ApiResourceManager<BluetoothSocketApi>. -class BluetoothSocketApiFunction : public UIThreadExtensionFunction { - public: - BluetoothSocketApiFunction(); - - protected: - virtual ~BluetoothSocketApiFunction(); - - // ExtensionFunction::RunImpl() - virtual bool RunImpl() OVERRIDE; - - bool PrePrepare(); - bool Respond(); - void AsyncWorkCompleted(); - - virtual bool Prepare() = 0; - virtual void Work(); - virtual void AsyncWorkStart(); - - content::BrowserThread::ID work_thread_id() const { - return BluetoothApiSocket::kThreadId; - } - - scoped_refptr<BluetoothAPI::SocketData> socket_data_; - scoped_refptr<api::BluetoothSocketEventDispatcher> socket_event_dispatcher_; -}; - class BluetoothGetAdapterStateFunction : public BluetoothExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("bluetooth.getAdapterState", @@ -219,107 +187,71 @@ class BluetoothConnectFunction : public BluetoothExtensionFunction { void OnErrorCallback(const std::string& error); }; -class BluetoothDisconnectFunction : public BluetoothSocketApiFunction { +class BluetoothDisconnectFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("bluetooth.disconnect", BLUETOOTH_DISCONNECT) - BluetoothDisconnectFunction(); protected: - virtual ~BluetoothDisconnectFunction(); + virtual ~BluetoothDisconnectFunction() {} - // AsyncApiFunction: - virtual bool Prepare() OVERRIDE; - virtual void AsyncWorkStart() OVERRIDE; - - private: - void OnSuccess(); - - scoped_ptr<bluetooth::Disconnect::Params> params_; + // UIThreadExtensionFunction: + virtual bool RunImpl() OVERRIDE; }; -class BluetoothSendFunction : public BluetoothSocketApiFunction { +class BluetoothSendFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("bluetooth.send", BLUETOOTH_WRITE) - BluetoothSendFunction(); protected: - virtual ~BluetoothSendFunction(); + virtual ~BluetoothSendFunction() {} - // AsyncApiFunction: - virtual bool Prepare() OVERRIDE; - virtual void AsyncWorkStart() OVERRIDE; - - private: - void OnSendSuccess(int bytes_sent); - void OnSendError(const std::string& message); - - scoped_ptr<bluetooth::Send::Params> params_; - scoped_refptr<net::IOBuffer> io_buffer_; - size_t io_buffer_size_; + // UIThreadExtensionFunction: + virtual bool RunImpl() OVERRIDE; }; -class BluetoothUpdateSocketFunction : public BluetoothSocketApiFunction { +class BluetoothUpdateSocketFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("bluetooth.updateSocket", BLUETOOTH_UPDATE_SOCKET) - BluetoothUpdateSocketFunction(); protected: - virtual ~BluetoothUpdateSocketFunction(); + virtual ~BluetoothUpdateSocketFunction() {} - // AsyncApiFunction: - virtual bool Prepare() OVERRIDE; - virtual void Work() OVERRIDE; - - private: - scoped_ptr<bluetooth::UpdateSocket::Params> params_; + // UIThreadExtensionFunction: + virtual bool RunImpl() OVERRIDE; }; -class BluetoothSetSocketPausedFunction : public BluetoothSocketApiFunction { +class BluetoothSetSocketPausedFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("bluetooth.setSocketPaused", BLUETOOTH_SET_SOCKET_PAUSED) - BluetoothSetSocketPausedFunction(); protected: - virtual ~BluetoothSetSocketPausedFunction(); - - // AsyncApiFunction: - virtual bool Prepare() OVERRIDE; - virtual void Work() OVERRIDE; + virtual ~BluetoothSetSocketPausedFunction() {} - private: - scoped_ptr<bluetooth::SetSocketPaused::Params> params_; + // UIThreadExtensionFunction: + virtual bool RunImpl() OVERRIDE; }; -class BluetoothGetSocketFunction : public BluetoothSocketApiFunction { +class BluetoothGetSocketFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("bluetooth.getSocket", BLUETOOTH_GET_SOCKET) - BluetoothGetSocketFunction(); - protected: - virtual ~BluetoothGetSocketFunction(); - - // AsyncApiFunction: - virtual bool Prepare() OVERRIDE; - virtual void Work() OVERRIDE; + virtual ~BluetoothGetSocketFunction() {} - private: - scoped_ptr<bluetooth::GetSocket::Params> params_; + // UIThreadExtensionFunction: + virtual bool RunImpl() OVERRIDE; }; -class BluetoothGetSocketsFunction : public BluetoothSocketApiFunction { +class BluetoothGetSocketsFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("bluetooth.getSockets", BLUETOOTH_GET_SOCKETS) - BluetoothGetSocketsFunction(); - protected: - virtual ~BluetoothGetSocketsFunction(); + virtual ~BluetoothGetSocketsFunction() {} - // AsyncApiFunction: - virtual bool Prepare() OVERRIDE; - virtual void Work() OVERRIDE; + // UIThreadExtensionFunction: + virtual bool RunImpl() OVERRIDE; }; class BluetoothGetLocalOutOfBandPairingDataFunction diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.cc b/chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.cc index e818152..2be7f3e 100644 --- a/chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.cc +++ b/chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.cc @@ -7,6 +7,12 @@ #include "device/bluetooth/bluetooth_socket.h" #include "net/base/io_buffer.h" +namespace { + +const char kSocketNotConnectedError[] = "Socket not connected"; + +} // namespace + namespace extensions { // static @@ -21,6 +27,15 @@ ApiResourceManager<BluetoothApiSocket>::GetFactoryInstance() { return g_server_factory.Pointer(); } +BluetoothApiSocket::BluetoothApiSocket(const std::string& owner_extension_id) + : ApiResource(owner_extension_id), + persistent_(false), + buffer_size_(0), + paused_(false), + connected_(false) { + DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); +} + BluetoothApiSocket::BluetoothApiSocket( const std::string& owner_extension_id, scoped_refptr<device::BluetoothSocket> socket, @@ -32,17 +47,25 @@ BluetoothApiSocket::BluetoothApiSocket( uuid_(uuid), persistent_(false), buffer_size_(0), - paused_(true) { + paused_(true), + connected_(true) { DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); } BluetoothApiSocket::~BluetoothApiSocket() { DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); - socket_->Close(); + if (socket_.get()) + socket_->Close(); } void BluetoothApiSocket::Disconnect(const base::Closure& success_callback) { DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); + + if (!socket_.get() || !IsConnected()) { + success_callback.Run(); + return; + } + socket_->Disconnect(success_callback); } @@ -54,8 +77,15 @@ bool BluetoothApiSocket::IsPersistent() const { void BluetoothApiSocket::Receive( int count, const ReceiveCompletionCallback& success_callback, - const ReceiveErrorCompletionCallback& error_callback) { + const ErrorCompletionCallback& error_callback) { DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); + + if (!socket_.get() || !IsConnected()) { + error_callback.Run(BluetoothApiSocket::kNotConnected, + kSocketNotConnectedError); + return; + } + socket_->Receive(count, success_callback, base::Bind(&OnSocketReceiveError, error_callback)); @@ -63,7 +93,7 @@ void BluetoothApiSocket::Receive( // static void BluetoothApiSocket::OnSocketReceiveError( - const ReceiveErrorCompletionCallback& error_callback, + const ErrorCompletionCallback& error_callback, device::BluetoothSocket::ErrorReason reason, const std::string& message) { DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); @@ -89,7 +119,26 @@ void BluetoothApiSocket::Send(scoped_refptr<net::IOBuffer> buffer, const SendCompletionCallback& success_callback, const ErrorCompletionCallback& error_callback) { DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); - socket_->Send(buffer, buffer_size, success_callback, error_callback); + + if (!socket_.get() || !IsConnected()) { + error_callback.Run(BluetoothApiSocket::kNotConnected, + kSocketNotConnectedError); + return; + } + + socket_->Send(buffer, + buffer_size, + success_callback, + base::Bind(&OnSocketSendError, error_callback)); +} + +// static +void BluetoothApiSocket::OnSocketSendError( + const ErrorCompletionCallback& error_callback, + const std::string& message) { + DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); + error_callback.Run(BluetoothApiSocket::kSystemError, message); + } } // namespace extensions diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h b/chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h index 02b0bbd..965cc51 100644 --- a/chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h +++ b/chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h @@ -23,16 +23,15 @@ namespace extensions { // class. All methods must be called on the |kThreadId| thread. class BluetoothApiSocket : public ApiResource { public: - enum ErrorReason { kSystemError, kIOPending, kDisconnected }; + enum ErrorReason { kSystemError, kNotConnected, kIOPending, kDisconnected }; typedef base::Callback<void(int)> SendCompletionCallback; typedef base::Callback<void(int, scoped_refptr<net::IOBuffer> io_buffer)> ReceiveCompletionCallback; - typedef base::Callback<void(const std::string& error_message)> - ErrorCompletionCallback; typedef base::Callback<void(ErrorReason, const std::string& error_message)> - ReceiveErrorCompletionCallback; + ErrorCompletionCallback; + explicit BluetoothApiSocket(const std::string& owner_extension_id); BluetoothApiSocket(const std::string& owner_extension_id, scoped_refptr<device::BluetoothSocket> socket, const std::string& device_address, @@ -49,7 +48,7 @@ class BluetoothApiSocket : public ApiResource { // |kIOPending| error. virtual void Receive(int count, const ReceiveCompletionCallback& success_callback, - const ReceiveErrorCompletionCallback& error_callback); + const ErrorCompletionCallback& error_callback); // Sends |buffer| to the socket and calls |success_callback| when data has // been successfully sent. |buffer_size| is the numberof bytes contained in @@ -80,6 +79,8 @@ class BluetoothApiSocket : public ApiResource { bool paused() const { return paused_; } void set_paused(bool paused) { paused_ = paused; } + bool IsConnected() const { return connected_; } + // Platform specific implementations of |BluetoothSocket| require being called // on the UI thread. static const content::BrowserThread::ID kThreadId = @@ -90,10 +91,14 @@ class BluetoothApiSocket : public ApiResource { static const char* service_name() { return "BluetoothApiSocketManager"; } static void OnSocketReceiveError( - const ReceiveErrorCompletionCallback& error_callback, + const ErrorCompletionCallback& error_callback, device::BluetoothSocket::ErrorReason reason, const std::string& message); + static void OnSocketSendError( + const ErrorCompletionCallback& error_callback, + const std::string& message); + // The underlying device socket instance. scoped_refptr<device::BluetoothSocket> socket_; @@ -117,6 +122,9 @@ class BluetoothApiSocket : public ApiResource { // more data - see bluetooth.idl. bool paused_; + // Flag indicating whether a socket is connected. + bool connected_; + DISALLOW_COPY_AND_ASSIGN(BluetoothApiSocket); }; diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_socket_event_dispatcher.h b/chrome/browser/extensions/api/bluetooth/bluetooth_socket_event_dispatcher.h deleted file mode 100644 index 9f0c2a5..0000000 --- a/chrome/browser/extensions/api/bluetooth/bluetooth_socket_event_dispatcher.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2014 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. - -#ifndef CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_BLUETOOTH_SOCKET_EVENT_DISPATCHER_H_ -#define CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_BLUETOOTH_SOCKET_EVENT_DISPATCHER_H_ - -#include "chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h" -#include "extensions/browser/api/api_resource_manager.h" -#include "extensions/browser/browser_context_keyed_api_factory.h" - -namespace content { -class BrowserContext; -} - -namespace extensions { -struct Event; -class BluetoothApiSocket; -} - -namespace extensions { -namespace api { - -// Dispatch events related to "bluetooth" sockets from callback on native socket -// instances. There is one instance per browser context. -class BluetoothSocketEventDispatcher - : public base::RefCountedThreadSafe<BluetoothSocketEventDispatcher> { - public: - typedef ApiResourceManager<BluetoothApiSocket>::ApiResourceData SocketData; - explicit BluetoothSocketEventDispatcher( - content::BrowserContext* context, - scoped_refptr<SocketData> socket_data); - - // Socket is active again, start receiving data from it. - void OnSocketResume(const std::string& extension_id, int socket_id); - - private: - friend class base::RefCountedThreadSafe<BluetoothSocketEventDispatcher>; - virtual ~BluetoothSocketEventDispatcher(); - - // base::Bind supports methods with up to 6 parameters. ReceiveParams is used - // as a workaround that limitation for invoking StartReceive. - struct ReceiveParams { - ReceiveParams(); - ~ReceiveParams(); - - std::string extension_id; - int socket_id; - }; - - // Start a receive and register a callback. - void StartReceive(const ReceiveParams& params); - - // Called when socket receive data. - void ReceiveCallback(const ReceiveParams& params, - int bytes_read, - scoped_refptr<net::IOBuffer> io_buffer); - - // Called when socket receive data. - void ReceiveErrorCallback(const ReceiveParams& params, - BluetoothApiSocket::ErrorReason error_reason, - const std::string& error); - - // Post an extension event from IO to UI thread - void PostEvent(const ReceiveParams& params, scoped_ptr<Event> event); - - // Dispatch an extension event on to EventRouter instance on UI thread. - void DispatchEvent(const std::string& extension_id, scoped_ptr<Event> event); - - // Usually FILE thread (except for unit testing). - content::BrowserThread::ID thread_id_; - void* browser_context_id_; - scoped_refptr<SocketData> socket_data_; - - DISALLOW_COPY_AND_ASSIGN(BluetoothSocketEventDispatcher); -}; - -} // namespace api -} // namespace extensions - -#endif // CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_BLUETOOTH_SOCKET_EVENT_DISPATCHER_H_ diff --git a/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.cc b/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.cc index 9ecdca5..0fd43f5 100644 --- a/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.cc +++ b/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.cc @@ -4,25 +4,208 @@ #include "chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.h" +#include "chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h" +#include "chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "net/base/io_buffer.h" + +using content::BrowserThread; +using extensions::BluetoothApiSocket; +using extensions::api::bluetooth_socket::SocketInfo; +using extensions::api::bluetooth_socket::SocketProperties; + +namespace { + +const char kSocketNotFoundError[] = "Socket not found"; + +linked_ptr<SocketInfo> CreateSocketInfo(int socket_id, + BluetoothApiSocket* socket) { + DCHECK(BrowserThread::CurrentlyOn(BluetoothApiSocket::kThreadId)); + linked_ptr<SocketInfo> socket_info(new SocketInfo()); + // This represents what we know about the socket, and does not call through + // to the system. + socket_info->socket_id = socket_id; + if (!socket->name().empty()) { + socket_info->name.reset(new std::string(socket->name())); + } + socket_info->persistent = socket->persistent(); + if (socket->buffer_size() > 0) { + socket_info->buffer_size.reset(new int(socket->buffer_size())); + } + socket_info->paused = socket->paused(); + socket_info->connected = socket->IsConnected(); + + // TODO(keybuk): These should not be present if socket isn't connected or + // listening. + socket_info->address.reset(new std::string(socket->device_address())); + socket_info->uuid.reset(new std::string(socket->uuid().canonical_value())); + + return socket_info; +} + +void SetSocketProperties(BluetoothApiSocket* socket, + SocketProperties* properties) { + if (properties->name.get()) { + socket->set_name(*properties->name.get()); + } + if (properties->persistent.get()) { + socket->set_persistent(*properties->persistent.get()); + } + if (properties->buffer_size.get()) { + // buffer size is validated when issuing the actual Recv operation + // on the socket. + socket->set_buffer_size(*properties->buffer_size.get()); + } +} + +} // namespace + namespace extensions { namespace api { -bool BluetoothSocketCreateFunction::RunImpl() { - // TODO(keybuk): Implement. - SetError("Not yet implemented."); - return false; +BluetoothSocketAsyncApiFunction::BluetoothSocketAsyncApiFunction() {} + +BluetoothSocketAsyncApiFunction::~BluetoothSocketAsyncApiFunction() {} + +bool BluetoothSocketAsyncApiFunction::RunImpl() { + if (!PrePrepare() || !Prepare()) { + return false; + } + AsyncWorkStart(); + return true; } -bool BluetoothSocketUpdateFunction::RunImpl() { - // TODO(keybuk): Implement. - SetError("Not yet implemented."); - return false; +bool BluetoothSocketAsyncApiFunction::PrePrepare() { + manager_ = ApiResourceManager<BluetoothApiSocket>::Get(browser_context()); + DCHECK(manager_) + << "There is no socket manager. " + "If this assertion is failing during a test, then it is likely that " + "TestExtensionSystem is failing to provide an instance of " + "ApiResourceManager<BluetoothApiSocket>."; + return manager_ != NULL; } -bool BluetoothSocketSetPausedFunction::RunImpl() { - // TODO(keybuk): Implement. - SetError("Not yet implemented."); - return false; +bool BluetoothSocketAsyncApiFunction::Respond() { return error_.empty(); } + +void BluetoothSocketAsyncApiFunction::AsyncWorkCompleted() { + SendResponse(Respond()); +} + +void BluetoothSocketAsyncApiFunction::Work() {} + +void BluetoothSocketAsyncApiFunction::AsyncWorkStart() { + Work(); + AsyncWorkCompleted(); +} + +int BluetoothSocketAsyncApiFunction::AddSocket(BluetoothApiSocket* socket) { + return manager_->Add(socket); +} + +content::BrowserThread::ID +BluetoothSocketAsyncApiFunction::work_thread_id() const { + return BluetoothApiSocket::kThreadId; +} + +BluetoothApiSocket* BluetoothSocketAsyncApiFunction::GetSocket( + int api_resource_id) { + return manager_->Get(extension_id(), api_resource_id); +} + +void BluetoothSocketAsyncApiFunction::RemoveSocket(int api_resource_id) { + manager_->Remove(extension_id(), api_resource_id); +} + +base::hash_set<int>* BluetoothSocketAsyncApiFunction::GetSocketIds() { + return manager_->GetResourceIds(extension_id()); +} + +BluetoothSocketCreateFunction::BluetoothSocketCreateFunction() {} + +BluetoothSocketCreateFunction::~BluetoothSocketCreateFunction() {} + +bool BluetoothSocketCreateFunction::Prepare() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + params_ = bluetooth_socket::Create::Params::Create(*args_); + EXTENSION_FUNCTION_VALIDATE(params_.get()); + return true; +} + +void BluetoothSocketCreateFunction::Work() { + DCHECK(BrowserThread::CurrentlyOn(work_thread_id())); + + BluetoothApiSocket* socket = new BluetoothApiSocket(extension_id()); + + bluetooth_socket::SocketProperties* properties = + params_.get()->properties.get(); + if (properties) { + SetSocketProperties(socket, properties); + } + + bluetooth_socket::CreateInfo create_info; + create_info.socket_id = AddSocket(socket); + results_ = bluetooth_socket::Create::Results::Create(create_info); + AsyncWorkCompleted(); +} + +BluetoothSocketUpdateFunction::BluetoothSocketUpdateFunction() {} + +BluetoothSocketUpdateFunction::~BluetoothSocketUpdateFunction() {} + +bool BluetoothSocketUpdateFunction::Prepare() { + params_ = bluetooth_socket::Update::Params::Create(*args_); + EXTENSION_FUNCTION_VALIDATE(params_.get()); + return true; +} + +void BluetoothSocketUpdateFunction::Work() { + BluetoothApiSocket* socket = GetSocket(params_->socket_id); + if (!socket) { + error_ = kSocketNotFoundError; + return; + } + + SetSocketProperties(socket, ¶ms_.get()->properties); + results_ = bluetooth_socket::Update::Results::Create(); +} + +BluetoothSocketSetPausedFunction::BluetoothSocketSetPausedFunction() + : socket_event_dispatcher_(NULL) {} + +BluetoothSocketSetPausedFunction::~BluetoothSocketSetPausedFunction() {} + +bool BluetoothSocketSetPausedFunction::Prepare() { + params_ = bluetooth_socket::SetPaused::Params::Create(*args_); + EXTENSION_FUNCTION_VALIDATE(params_.get()); + + socket_event_dispatcher_ = + BluetoothSocketEventDispatcher::Get(browser_context()); + DCHECK(socket_event_dispatcher_) + << "There is no socket event dispatcher. " + "If this assertion is failing during a test, then it is likely that " + "TestExtensionSystem is failing to provide an instance of " + "BluetoothSocketEventDispatcher."; + return socket_event_dispatcher_ != NULL; +} + +void BluetoothSocketSetPausedFunction::Work() { + BluetoothApiSocket* socket = GetSocket(params_->socket_id); + if (!socket) { + error_ = kSocketNotFoundError; + return; + } + + if (socket->paused() != params_->paused) { + socket->set_paused(params_->paused); + if (!params_->paused) { + socket_event_dispatcher_->OnSocketResume(extension_id(), + params_->socket_id); + } + } + + results_ = bluetooth_socket::SetPaused::Results::Create(); } bool BluetoothSocketListenUsingRfcommFunction::RunImpl() { @@ -49,34 +232,142 @@ bool BluetoothSocketConnectFunction::RunImpl() { return false; } -bool BluetoothSocketDisconnectFunction::RunImpl() { - // TODO(keybuk): Implement. - SetError("Not yet implemented."); - return false; +BluetoothSocketDisconnectFunction::BluetoothSocketDisconnectFunction() {} + +BluetoothSocketDisconnectFunction::~BluetoothSocketDisconnectFunction() {} + +bool BluetoothSocketDisconnectFunction::Prepare() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + params_ = bluetooth_socket::Disconnect::Params::Create(*args_); + EXTENSION_FUNCTION_VALIDATE(params_.get()); + return true; } -bool BluetoothSocketCloseFunction::RunImpl() { - // TODO(keybuk): Implement. - SetError("Not yet implemented."); - return false; +void BluetoothSocketDisconnectFunction::AsyncWorkStart() { + DCHECK(BrowserThread::CurrentlyOn(work_thread_id())); + BluetoothApiSocket* socket = GetSocket(params_->socket_id); + if (!socket) { + error_ = kSocketNotFoundError; + return; + } + + socket->Disconnect(base::Bind(&BluetoothSocketDisconnectFunction::OnSuccess, + this)); } -bool BluetoothSocketSendFunction::RunImpl() { - // TODO(keybuk): Implement. - SetError("Not yet implemented."); - return false; +void BluetoothSocketDisconnectFunction::OnSuccess() { + DCHECK(BrowserThread::CurrentlyOn(work_thread_id())); + results_ = bluetooth_socket::Disconnect::Results::Create(); + AsyncWorkCompleted(); } -bool BluetoothSocketGetInfoFunction::RunImpl() { - // TODO(keybuk): Implement. - SetError("Not yet implemented."); - return false; +BluetoothSocketCloseFunction::BluetoothSocketCloseFunction() {} + +BluetoothSocketCloseFunction::~BluetoothSocketCloseFunction() {} + +bool BluetoothSocketCloseFunction::Prepare() { + params_ = bluetooth_socket::Close::Params::Create(*args_); + EXTENSION_FUNCTION_VALIDATE(params_.get()); + return true; } -bool BluetoothSocketGetSocketsFunction::RunImpl() { - // TODO(keybuk): Implement. - SetError("Not yet implemented."); - return false; +void BluetoothSocketCloseFunction::Work() { + BluetoothApiSocket* socket = GetSocket(params_->socket_id); + if (!socket) { + error_ = kSocketNotFoundError; + return; + } + + RemoveSocket(params_->socket_id); + results_ = bluetooth_socket::Close::Results::Create(); +} + +BluetoothSocketSendFunction::BluetoothSocketSendFunction() + : io_buffer_size_(0) {} + +BluetoothSocketSendFunction::~BluetoothSocketSendFunction() {} + +bool BluetoothSocketSendFunction::Prepare() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + params_ = bluetooth_socket::Send::Params::Create(*args_); + EXTENSION_FUNCTION_VALIDATE(params_.get()); + + io_buffer_size_ = params_->data.size(); + io_buffer_ = new net::WrappedIOBuffer(params_->data.data()); + return true; +} + +void BluetoothSocketSendFunction::AsyncWorkStart() { + DCHECK(BrowserThread::CurrentlyOn(work_thread_id())); + BluetoothApiSocket* socket = GetSocket(params_->socket_id); + if (!socket) { + error_ = kSocketNotFoundError; + return; + } + + socket->Send(io_buffer_, + io_buffer_size_, + base::Bind(&BluetoothSocketSendFunction::OnSuccess, this), + base::Bind(&BluetoothSocketSendFunction::OnError, this)); +} + +void BluetoothSocketSendFunction::OnSuccess(int bytes_sent) { + DCHECK(BrowserThread::CurrentlyOn(work_thread_id())); + results_ = bluetooth_socket::Send::Results::Create(bytes_sent); + AsyncWorkCompleted(); +} + +void BluetoothSocketSendFunction::OnError( + BluetoothApiSocket::ErrorReason reason, + const std::string& message) { + DCHECK(BrowserThread::CurrentlyOn(work_thread_id())); + error_ = message; + AsyncWorkCompleted(); +} + +BluetoothSocketGetInfoFunction::BluetoothSocketGetInfoFunction() {} + +BluetoothSocketGetInfoFunction::~BluetoothSocketGetInfoFunction() {} + +bool BluetoothSocketGetInfoFunction::Prepare() { + params_ = bluetooth_socket::GetInfo::Params::Create(*args_); + EXTENSION_FUNCTION_VALIDATE(params_.get()); + return true; +} + +void BluetoothSocketGetInfoFunction::Work() { + BluetoothApiSocket* socket = GetSocket(params_->socket_id); + if (!socket) { + error_ = kSocketNotFoundError; + return; + } + + linked_ptr<bluetooth_socket::SocketInfo> socket_info = + CreateSocketInfo(params_->socket_id, socket); + results_ = bluetooth_socket::GetInfo::Results::Create(*socket_info); +} + +BluetoothSocketGetSocketsFunction::BluetoothSocketGetSocketsFunction() {} + +BluetoothSocketGetSocketsFunction::~BluetoothSocketGetSocketsFunction() {} + +bool BluetoothSocketGetSocketsFunction::Prepare() { return true; } + +void BluetoothSocketGetSocketsFunction::Work() { + std::vector<linked_ptr<bluetooth_socket::SocketInfo> > socket_infos; + base::hash_set<int>* resource_ids = GetSocketIds(); + if (resource_ids != NULL) { + for (base::hash_set<int>::iterator it = resource_ids->begin(); + it != resource_ids->end(); + ++it) { + int socket_id = *it; + BluetoothApiSocket* socket = GetSocket(socket_id); + if (socket) { + socket_infos.push_back(CreateSocketInfo(socket_id, socket)); + } + } + } + results_ = bluetooth_socket::GetSockets::Results::Create(socket_infos); } } // namespace api diff --git a/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.h b/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.h index 02f7937..c7cd376 100644 --- a/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.h +++ b/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.h @@ -5,44 +5,113 @@ #ifndef CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_SOCKET_BLUETOOTH_SOCKET_API_H_ #define CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_SOCKET_BLUETOOTH_SOCKET_API_H_ +#include <string> + +#include "base/containers/hash_tables.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h" +#include "chrome/common/extensions/api/bluetooth_socket.h" +#include "extensions/browser/api/api_resource_manager.h" +#include "extensions/browser/api/async_api_function.h" #include "extensions/browser/extension_function.h" #include "extensions/browser/extension_function_histogram_value.h" +namespace net { +class IOBuffer; +} + namespace extensions { + namespace api { -class BluetoothSocketCreateFunction : public UIThreadExtensionFunction { +class BluetoothSocketEventDispatcher; + +// Asynchronous API function that performs its work on the BluetoothApiSocket +// thread while providing methods to manage resources of that class. This +// follows the pattern of AsyncApiFunction, but does not derive from it, +// because BluetoothApiSocket methods must be called on the UI Thread. +class BluetoothSocketAsyncApiFunction : public UIThreadExtensionFunction { public: - DECLARE_EXTENSION_FUNCTION("bluetoothSocket.create", BLUETOOTHSOCKET_CREATE); + BluetoothSocketAsyncApiFunction(); protected: - virtual ~BluetoothSocketCreateFunction() {} + virtual ~BluetoothSocketAsyncApiFunction(); - // UIThreadExtensionFunction override: + // UIThreadExtensionFunction: virtual bool RunImpl() OVERRIDE; + + bool PrePrepare(); + bool Respond(); + void AsyncWorkCompleted(); + + virtual bool Prepare() = 0; + virtual void Work(); + virtual void AsyncWorkStart(); + + content::BrowserThread::ID work_thread_id() const; + + int AddSocket(BluetoothApiSocket* socket); + BluetoothApiSocket* GetSocket(int api_resource_id); + void RemoveSocket(int api_resource_id); + base::hash_set<int>* GetSocketIds(); + + private: + ApiResourceManager<BluetoothApiSocket>* manager_; +}; + +class BluetoothSocketCreateFunction : public BluetoothSocketAsyncApiFunction { + public: + DECLARE_EXTENSION_FUNCTION("bluetoothSocket.create", BLUETOOTHSOCKET_CREATE); + + BluetoothSocketCreateFunction(); + + protected: + virtual ~BluetoothSocketCreateFunction(); + + // BluetoothSocketAsyncApiFunction: + virtual bool Prepare() OVERRIDE; + virtual void Work() OVERRIDE; + + private: + scoped_ptr<bluetooth_socket::Create::Params> params_; }; -class BluetoothSocketUpdateFunction : public UIThreadExtensionFunction { +class BluetoothSocketUpdateFunction : public BluetoothSocketAsyncApiFunction { public: DECLARE_EXTENSION_FUNCTION("bluetoothSocket.update", BLUETOOTHSOCKET_UPDATE); + BluetoothSocketUpdateFunction(); + protected: - virtual ~BluetoothSocketUpdateFunction() {} + virtual ~BluetoothSocketUpdateFunction(); - // UIThreadExtensionFunction override: - virtual bool RunImpl() OVERRIDE; + // BluetoothSocketAsyncApiFunction: + virtual bool Prepare() OVERRIDE; + virtual void Work() OVERRIDE; + + private: + scoped_ptr<bluetooth_socket::Update::Params> params_; }; -class BluetoothSocketSetPausedFunction : public UIThreadExtensionFunction { +class BluetoothSocketSetPausedFunction + : public BluetoothSocketAsyncApiFunction { public: DECLARE_EXTENSION_FUNCTION("bluetoothSocket.setPaused", BLUETOOTHSOCKET_SETPAUSED); + BluetoothSocketSetPausedFunction(); + protected: - virtual ~BluetoothSocketSetPausedFunction() {} + virtual ~BluetoothSocketSetPausedFunction(); - // UIThreadExtensionFunction override: - virtual bool RunImpl() OVERRIDE; + // BluetoothSocketAsyncApiFunction: + virtual bool Prepare() OVERRIDE; + virtual void Work() OVERRIDE; + + private: + scoped_ptr<bluetooth_socket::SetPaused::Params> params_; + BluetoothSocketEventDispatcher* socket_event_dispatcher_; }; class BluetoothSocketListenUsingRfcommFunction @@ -96,62 +165,99 @@ class BluetoothSocketConnectFunction : public UIThreadExtensionFunction { virtual bool RunImpl() OVERRIDE; }; -class BluetoothSocketDisconnectFunction : public UIThreadExtensionFunction { +class BluetoothSocketDisconnectFunction + : public BluetoothSocketAsyncApiFunction { public: DECLARE_EXTENSION_FUNCTION("bluetoothSocket.disconnect", BLUETOOTHSOCKET_DISCONNECT); + BluetoothSocketDisconnectFunction(); + protected: - virtual ~BluetoothSocketDisconnectFunction() {} + virtual ~BluetoothSocketDisconnectFunction(); - // UIThreadExtensionFunction override: - virtual bool RunImpl() OVERRIDE; + // BluetoothSocketAsyncApiFunction: + virtual bool Prepare() OVERRIDE; + virtual void AsyncWorkStart() OVERRIDE; + + private: + virtual void OnSuccess(); + + scoped_ptr<bluetooth_socket::Disconnect::Params> params_; }; -class BluetoothSocketCloseFunction : public UIThreadExtensionFunction { +class BluetoothSocketCloseFunction : public BluetoothSocketAsyncApiFunction { public: DECLARE_EXTENSION_FUNCTION("bluetoothSocket.close", BLUETOOTHSOCKET_CLOSE); + BluetoothSocketCloseFunction(); + protected: - virtual ~BluetoothSocketCloseFunction() {} + virtual ~BluetoothSocketCloseFunction(); - // UIThreadExtensionFunction override: - virtual bool RunImpl() OVERRIDE; + // BluetoothSocketAsyncApiFunction: + virtual bool Prepare() OVERRIDE; + virtual void Work() OVERRIDE; + + private: + scoped_ptr<bluetooth_socket::Close::Params> params_; }; -class BluetoothSocketSendFunction : public UIThreadExtensionFunction { +class BluetoothSocketSendFunction : public BluetoothSocketAsyncApiFunction { public: DECLARE_EXTENSION_FUNCTION("bluetoothSocket.send", BLUETOOTHSOCKET_SEND); + BluetoothSocketSendFunction(); + protected: - virtual ~BluetoothSocketSendFunction() {} + virtual ~BluetoothSocketSendFunction(); - // UIThreadExtensionFunction override: - virtual bool RunImpl() OVERRIDE; + // BluetoothSocketAsyncApiFunction: + virtual bool Prepare() OVERRIDE; + virtual void AsyncWorkStart() OVERRIDE; + + private: + void OnSuccess(int bytes_sent); + void OnError(BluetoothApiSocket::ErrorReason reason, + const std::string& message); + + scoped_ptr<bluetooth_socket::Send::Params> params_; + scoped_refptr<net::IOBuffer> io_buffer_; + size_t io_buffer_size_; }; -class BluetoothSocketGetInfoFunction : public UIThreadExtensionFunction { +class BluetoothSocketGetInfoFunction : public BluetoothSocketAsyncApiFunction { public: DECLARE_EXTENSION_FUNCTION("bluetoothSocket.getInfo", BLUETOOTHSOCKET_GETINFO); + BluetoothSocketGetInfoFunction(); + protected: - virtual ~BluetoothSocketGetInfoFunction() {} + virtual ~BluetoothSocketGetInfoFunction(); - // UIThreadExtensionFunction override: - virtual bool RunImpl() OVERRIDE; + // BluetoothSocketAsyncApiFunction: + virtual bool Prepare() OVERRIDE; + virtual void Work() OVERRIDE; + + private: + scoped_ptr<bluetooth_socket::GetInfo::Params> params_; }; -class BluetoothSocketGetSocketsFunction : public UIThreadExtensionFunction { +class BluetoothSocketGetSocketsFunction + : public BluetoothSocketAsyncApiFunction { public: DECLARE_EXTENSION_FUNCTION("bluetoothSocket.getSockets", BLUETOOTHSOCKET_GETSOCKETS); + BluetoothSocketGetSocketsFunction(); + protected: - virtual ~BluetoothSocketGetSocketsFunction() {} + virtual ~BluetoothSocketGetSocketsFunction(); - // UIThreadExtensionFunction override: - virtual bool RunImpl() OVERRIDE; + // BluetoothSocketAsyncApiFunction: + virtual bool Prepare() OVERRIDE; + virtual void Work() OVERRIDE; }; } // namespace api diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_socket_event_dispatcher.cc b/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_event_dispatcher.cc index 6429ed474..2d7f539 100644 --- a/chrome/browser/extensions/api/bluetooth/bluetooth_socket_event_dispatcher.cc +++ b/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_event_dispatcher.cc @@ -2,32 +2,37 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/extensions/api/bluetooth/bluetooth_socket_event_dispatcher.h" +#include "chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h" -#include "chrome/common/extensions/api/bluetooth.h" +#include "chrome/common/extensions/api/bluetooth_socket.h" #include "extensions/browser/event_router.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" namespace { -namespace bluetooth = extensions::api::bluetooth; +namespace bluetooth_socket = extensions::api::bluetooth_socket; using extensions::BluetoothApiSocket; int kDefaultBufferSize = 4096; -bluetooth::ReceiveError MapErrorReason(BluetoothApiSocket::ErrorReason value) { +bluetooth_socket::ReceiveError MapErrorReason( + BluetoothApiSocket::ErrorReason value) { switch (value) { case BluetoothApiSocket::kDisconnected: - return bluetooth::RECEIVE_ERROR_DISCONNECTED; + return bluetooth_socket::RECEIVE_ERROR_DISCONNECTED; + case BluetoothApiSocket::kNotConnected: + // kNotConnected is impossible since a socket has to be connected to be + // able to call Receive() on it. + // fallthrough case BluetoothApiSocket::kIOPending: // kIOPending is not relevant to apps, as BluetoothSocketEventDispatcher // handles this specific error. // fallthrough default: - return bluetooth::RECEIVE_ERROR_SYSTEM_ERROR; + return bluetooth_socket::RECEIVE_ERROR_SYSTEM_ERROR; } } @@ -38,12 +43,38 @@ namespace api { using content::BrowserThread; +static base::LazyInstance< + BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher> > g_factory = + LAZY_INSTANCE_INITIALIZER; + +// static +BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>* +BluetoothSocketEventDispatcher::GetFactoryInstance() { + return g_factory.Pointer(); +} + +// static +BluetoothSocketEventDispatcher* BluetoothSocketEventDispatcher::Get( + content::BrowserContext* context) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + return BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>::Get( + context); +} + BluetoothSocketEventDispatcher::BluetoothSocketEventDispatcher( - content::BrowserContext* context, - scoped_refptr<SocketData> socket_data) + content::BrowserContext* context) : thread_id_(BluetoothApiSocket::kThreadId), - browser_context_id_(context), - socket_data_(socket_data) {} + browser_context_(context) { + ApiResourceManager<BluetoothApiSocket>* manager = + ApiResourceManager<BluetoothApiSocket>::Get(browser_context_); + DCHECK(manager) + << "There is no socket manager. " + "If this assertion is failing during a test, then it is likely that " + "TestExtensionSystem is failing to provide an instance of " + "ApiResourceManager<BluetoothApiSocket>."; + sockets_ = manager->data_; +} BluetoothSocketEventDispatcher::~BluetoothSocketEventDispatcher() {} @@ -57,16 +88,21 @@ void BluetoothSocketEventDispatcher::OnSocketResume( DCHECK(BrowserThread::CurrentlyOn(thread_id_)); ReceiveParams params; + params.thread_id = thread_id_; + params.browser_context_id = browser_context_; params.extension_id = extension_id; + params.sockets = sockets_; params.socket_id = socket_id; + StartReceive(params); } +// static void BluetoothSocketEventDispatcher::StartReceive(const ReceiveParams& params) { - DCHECK(BrowserThread::CurrentlyOn(thread_id_)); + DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); BluetoothApiSocket* socket = - socket_data_->Get(params.extension_id, params.socket_id); + params.sockets->Get(params.extension_id, params.socket_id); if (!socket) { // This can happen if the socket is closed while our callback is active. return; @@ -84,39 +120,42 @@ void BluetoothSocketEventDispatcher::StartReceive(const ReceiveParams& params) { socket->Receive( buffer_size, base::Bind( - &BluetoothSocketEventDispatcher::ReceiveCallback, this, params), + &BluetoothSocketEventDispatcher::ReceiveCallback, params), base::Bind( - &BluetoothSocketEventDispatcher::ReceiveErrorCallback, this, params)); + &BluetoothSocketEventDispatcher::ReceiveErrorCallback, params)); } +// static void BluetoothSocketEventDispatcher::ReceiveCallback( const ReceiveParams& params, int bytes_read, scoped_refptr<net::IOBuffer> io_buffer) { - DCHECK(BrowserThread::CurrentlyOn(thread_id_)); + DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); // Dispatch "onReceive" event. - bluetooth::ReceiveInfo receive_info; + bluetooth_socket::ReceiveInfo receive_info; receive_info.socket_id = params.socket_id; receive_info.data = std::string(io_buffer->data(), bytes_read); - scoped_ptr<base::ListValue> args = bluetooth::OnReceive::Create(receive_info); + scoped_ptr<base::ListValue> args = + bluetooth_socket::OnReceive::Create(receive_info); scoped_ptr<Event> event( - new Event(bluetooth::OnReceive::kEventName, args.Pass())); + new Event(bluetooth_socket::OnReceive::kEventName, args.Pass())); PostEvent(params, event.Pass()); // Post a task to delay the read until the socket is available, as // calling StartReceive at this point would error with ERR_IO_PENDING. BrowserThread::PostTask( - thread_id_, + params.thread_id, FROM_HERE, - base::Bind(&BluetoothSocketEventDispatcher::StartReceive, this, params)); + base::Bind(&BluetoothSocketEventDispatcher::StartReceive, params)); } +// static void BluetoothSocketEventDispatcher::ReceiveErrorCallback( const ReceiveParams& params, BluetoothApiSocket::ErrorReason error_reason, const std::string& error) { - DCHECK(BrowserThread::CurrentlyOn(thread_id_)); + DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); if (error_reason == BluetoothApiSocket::kIOPending) { // This happens when resuming a socket which already had an active "read" @@ -127,45 +166,48 @@ void BluetoothSocketEventDispatcher::ReceiveErrorCallback( // Dispatch "onReceiveError" event but don't start another read to avoid // potential infinite reads if we have a persistent network error. - bluetooth::ReceiveErrorInfo receive_error_info; + bluetooth_socket::ReceiveErrorInfo receive_error_info; receive_error_info.socket_id = params.socket_id; receive_error_info.error_message = error; receive_error_info.error = MapErrorReason(error_reason); scoped_ptr<base::ListValue> args = - bluetooth::OnReceiveError::Create(receive_error_info); + bluetooth_socket::OnReceiveError::Create(receive_error_info); scoped_ptr<Event> event( - new Event(bluetooth::OnReceiveError::kEventName, args.Pass())); + new Event(bluetooth_socket::OnReceiveError::kEventName, args.Pass())); PostEvent(params, event.Pass()); // Since we got an error, the socket is now "paused" until the application // "resumes" it. BluetoothApiSocket* socket = - socket_data_->Get(params.extension_id, params.socket_id); + params.sockets->Get(params.extension_id, params.socket_id); if (socket) { socket->set_paused(true); } } +// static void BluetoothSocketEventDispatcher::PostEvent(const ReceiveParams& params, scoped_ptr<Event> event) { - DCHECK(BrowserThread::CurrentlyOn(thread_id_)); + DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, - base::Bind(&BluetoothSocketEventDispatcher::DispatchEvent, - this, + base::Bind(&DispatchEvent, + params.browser_context_id, params.extension_id, base::Passed(event.Pass()))); } +// static void BluetoothSocketEventDispatcher::DispatchEvent( + void* browser_context_id, const std::string& extension_id, scoped_ptr<Event> event) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); content::BrowserContext* context = - reinterpret_cast<content::BrowserContext*>(browser_context_id_); + reinterpret_cast<content::BrowserContext*>(browser_context_id); if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context)) return; diff --git a/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h b/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h new file mode 100644 index 0000000..81fdfca --- /dev/null +++ b/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h @@ -0,0 +1,94 @@ +// Copyright 2014 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. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_SOCKET_BLUETOOTH_SOCKET_EVENT_DISPATCHER_H_ +#define CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_SOCKET_BLUETOOTH_SOCKET_EVENT_DISPATCHER_H_ + +#include "chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h" +#include "extensions/browser/api/api_resource_manager.h" +#include "extensions/browser/browser_context_keyed_api_factory.h" + +namespace content { +class BrowserContext; +} + +namespace extensions { +struct Event; +class BluetoothApiSocket; +} + +namespace extensions { +namespace api { + +// Dispatch events related to "bluetooth" sockets from callback on native socket +// instances. There is one instance per browser context. +class BluetoothSocketEventDispatcher + : public BrowserContextKeyedAPI, + public base::SupportsWeakPtr<BluetoothSocketEventDispatcher> { + public: + explicit BluetoothSocketEventDispatcher(content::BrowserContext* context); + virtual ~BluetoothSocketEventDispatcher(); + + // Socket is active again, start receiving data from it. + void OnSocketResume(const std::string& extension_id, int socket_id); + + // BrowserContextKeyedAPI implementation. + static BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>* + GetFactoryInstance(); + + // Convenience method to get the SocketEventDispatcher for a profile. + static BluetoothSocketEventDispatcher* Get(content::BrowserContext* context); + + private: + typedef ApiResourceManager<BluetoothApiSocket>::ApiResourceData SocketData; + friend class BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>; + // BrowserContextKeyedAPI implementation. + static const char* service_name() { return "BluetoothSocketEventDispatcher"; } + static const bool kServiceHasOwnInstanceInIncognito = true; + static const bool kServiceIsNULLWhileTesting = true; + + // base::Bind supports methods with up to 6 parameters. ReceiveParams is used + // as a workaround that limitation for invoking StartReceive. + struct ReceiveParams { + ReceiveParams(); + ~ReceiveParams(); + + content::BrowserThread::ID thread_id; + void* browser_context_id; + std::string extension_id; + scoped_refptr<SocketData> sockets; + int socket_id; + }; + + // Start a receive and register a callback. + static void StartReceive(const ReceiveParams& params); + + // Called when socket receive data. + static void ReceiveCallback(const ReceiveParams& params, + int bytes_read, + scoped_refptr<net::IOBuffer> io_buffer); + + // Called when socket receive data. + static void ReceiveErrorCallback(const ReceiveParams& params, + BluetoothApiSocket::ErrorReason error_reason, + const std::string& error); + + // Post an extension event from IO to UI thread + static void PostEvent(const ReceiveParams& params, scoped_ptr<Event> event); + + // Dispatch an extension event on to EventRouter instance on UI thread. + static void DispatchEvent(void* browser_context_id, + const std::string& extension_id, + scoped_ptr<Event> event); + + // Usually FILE thread (except for unit testing). + content::BrowserThread::ID thread_id_; + content::BrowserContext* const browser_context_; + scoped_refptr<SocketData> sockets_; +}; + +} // namespace api +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_SOCKET_BLUETOOTH_SOCKET_EVENT_DISPATCHER_H_ diff --git a/chrome/browser/extensions/browser_context_keyed_service_factories.cc b/chrome/browser/extensions/browser_context_keyed_service_factories.cc index 8a79b26..c9f3c43 100644 --- a/chrome/browser/extensions/browser_context_keyed_service_factories.cc +++ b/chrome/browser/extensions/browser_context_keyed_service_factories.cc @@ -11,6 +11,7 @@ #include "chrome/browser/extensions/api/bluetooth/bluetooth_api.h" #include "chrome/browser/extensions/api/bluetooth/bluetooth_private_api.h" #include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.h" +#include "chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h" #include "chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h" #include "chrome/browser/extensions/api/bookmarks/bookmarks_api.h" #include "chrome/browser/extensions/api/braille_display_private/braille_display_private_api.h" @@ -163,6 +164,7 @@ void EnsureBrowserContextKeyedServiceFactoriesBuilt() { #endif TokenCacheServiceFactory::GetInstance(); extensions::ExtensionGCMAppHandler::GetFactoryInstance(); + extensions::api::BluetoothSocketEventDispatcher::GetFactoryInstance(); } } // namespace chrome_extensions |