diff options
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 |