Migrate chrome.bluetooth API backend to use device::BluetoothDiscoverySession.

Modified chrome.bluetooth API code to use the new discovery session API for
device discovery.

This CL is the same as r255262 which was reverted due to a memory leak. The leak
has been addressed in this patch.

BUG=346982,349942
TEST=1. Run unit_tests and browser_tests with LSan.
     2. Use multiple running extension instances with the bluetooth permission
        and check for the following behavior:
        - Only one session per extension. Calling chrome.bluetooth.stopDiscovery
          from one running app should fail if that app never called
          chrome.bluetooth.startDiscovery.
        - An app's discovery sessions should get cleaned up if that app crashes
          or unloads.
        - Use bt_console and run "power off". This should cause all discovery
          sessions that have been assigned to apps to get marked as inactive.
          Verify by requesting a new discovery session from apps, which should
          succeed.

Review URL: https://codereview.chromium.org/189463002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@255609 0039d316-1c4b-4281-b951-d872f2087c98
parent a2093312
...@@ -636,24 +636,18 @@ void BluetoothStartDiscoveryFunction::OnSuccessCallback() { ...@@ -636,24 +636,18 @@ void BluetoothStartDiscoveryFunction::OnSuccessCallback() {
void BluetoothStartDiscoveryFunction::OnErrorCallback() { void BluetoothStartDiscoveryFunction::OnErrorCallback() {
SetError(kStartDiscoveryFailed); SetError(kStartDiscoveryFailed);
GetEventRouter(browser_context())->SetResponsibleForDiscovery(false);
SendResponse(false); SendResponse(false);
GetEventRouter(browser_context())->OnListenerRemoved(); GetEventRouter(browser_context())->OnListenerRemoved();
} }
bool BluetoothStartDiscoveryFunction::DoWork( bool BluetoothStartDiscoveryFunction::DoWork(
scoped_refptr<BluetoothAdapter> adapter) { scoped_refptr<BluetoothAdapter> adapter) {
GetEventRouter(browser_context())->SetSendDiscoveryEvents(true);
// If this profile is already discovering devices, there should be nothing
// else to do.
if (!GetEventRouter(browser_context())->IsResponsibleForDiscovery()) {
GetEventRouter(browser_context())->SetResponsibleForDiscovery(true);
GetEventRouter(browser_context())->OnListenerAdded(); GetEventRouter(browser_context())->OnListenerAdded();
adapter->StartDiscovering( GetEventRouter(browser_context())->StartDiscoverySession(
adapter,
extension_id(),
base::Bind(&BluetoothStartDiscoveryFunction::OnSuccessCallback, this), base::Bind(&BluetoothStartDiscoveryFunction::OnSuccessCallback, this),
base::Bind(&BluetoothStartDiscoveryFunction::OnErrorCallback, this)); base::Bind(&BluetoothStartDiscoveryFunction::OnErrorCallback, this));
}
return true; return true;
} }
...@@ -665,19 +659,17 @@ void BluetoothStopDiscoveryFunction::OnSuccessCallback() { ...@@ -665,19 +659,17 @@ void BluetoothStopDiscoveryFunction::OnSuccessCallback() {
void BluetoothStopDiscoveryFunction::OnErrorCallback() { void BluetoothStopDiscoveryFunction::OnErrorCallback() {
SetError(kStopDiscoveryFailed); SetError(kStopDiscoveryFailed);
GetEventRouter(browser_context())->SetResponsibleForDiscovery(true);
SendResponse(false); SendResponse(false);
GetEventRouter(browser_context())->OnListenerRemoved(); GetEventRouter(browser_context())->OnListenerRemoved();
} }
bool BluetoothStopDiscoveryFunction::DoWork( bool BluetoothStopDiscoveryFunction::DoWork(
scoped_refptr<BluetoothAdapter> adapter) { scoped_refptr<BluetoothAdapter> adapter) {
GetEventRouter(browser_context())->SetSendDiscoveryEvents(false); GetEventRouter(browser_context())->StopDiscoverySession(
if (GetEventRouter(browser_context())->IsResponsibleForDiscovery()) { adapter,
adapter->StopDiscovering( extension_id(),
base::Bind(&BluetoothStopDiscoveryFunction::OnSuccessCallback, this), base::Bind(&BluetoothStopDiscoveryFunction::OnSuccessCallback, this),
base::Bind(&BluetoothStopDiscoveryFunction::OnErrorCallback, this)); base::Bind(&BluetoothStopDiscoveryFunction::OnErrorCallback, this));
}
return true; return true;
} }
......
...@@ -17,16 +17,19 @@ ...@@ -17,16 +17,19 @@
#include "device/bluetooth/bluetooth_out_of_band_pairing_data.h" #include "device/bluetooth/bluetooth_out_of_band_pairing_data.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h" #include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/bluetooth/test/mock_bluetooth_device.h" #include "device/bluetooth/test/mock_bluetooth_device.h"
#include "device/bluetooth/test/mock_bluetooth_discovery_session.h"
#include "device/bluetooth/test/mock_bluetooth_profile.h" #include "device/bluetooth/test/mock_bluetooth_profile.h"
#include "device/bluetooth/test/mock_bluetooth_socket.h" #include "device/bluetooth/test/mock_bluetooth_socket.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
using device::BluetoothAdapter; using device::BluetoothAdapter;
using device::BluetoothDevice; using device::BluetoothDevice;
using device::BluetoothDiscoverySession;
using device::BluetoothOutOfBandPairingData; using device::BluetoothOutOfBandPairingData;
using device::BluetoothProfile; using device::BluetoothProfile;
using device::MockBluetoothAdapter; using device::MockBluetoothAdapter;
using device::MockBluetoothDevice; using device::MockBluetoothDevice;
using device::MockBluetoothDiscoverySession;
using device::MockBluetoothProfile; using device::MockBluetoothProfile;
using extensions::Extension; using extensions::Extension;
...@@ -65,6 +68,17 @@ class BluetoothApiTest : public ExtensionApiTest { ...@@ -65,6 +68,17 @@ class BluetoothApiTest : public ExtensionApiTest {
false /* paired */, false /* connected */)); false /* paired */, false /* connected */));
} }
void DiscoverySessionCallback(
const BluetoothAdapter::DiscoverySessionCallback& callback,
const BluetoothAdapter::ErrorCallback& error_callback) {
if (mock_session_.get()) {
callback.Run(
scoped_ptr<BluetoothDiscoverySession>(mock_session_.release()));
return;
}
error_callback.Run();
}
template <class T> template <class T>
T* setupFunction(T* function) { T* setupFunction(T* function) {
function->set_extension(empty_extension_.get()); function->set_extension(empty_extension_.get());
...@@ -74,6 +88,7 @@ class BluetoothApiTest : public ExtensionApiTest { ...@@ -74,6 +88,7 @@ class BluetoothApiTest : public ExtensionApiTest {
protected: protected:
testing::StrictMock<MockBluetoothAdapter>* mock_adapter_; testing::StrictMock<MockBluetoothAdapter>* mock_adapter_;
scoped_ptr<testing::NiceMock<MockBluetoothDiscoverySession> > mock_session_;
scoped_ptr<testing::NiceMock<MockBluetoothDevice> > device1_; scoped_ptr<testing::NiceMock<MockBluetoothDevice> > device1_;
scoped_ptr<testing::NiceMock<MockBluetoothDevice> > device2_; scoped_ptr<testing::NiceMock<MockBluetoothDevice> > device2_;
scoped_ptr<testing::NiceMock<MockBluetoothProfile> > profile1_; scoped_ptr<testing::NiceMock<MockBluetoothProfile> > profile1_;
...@@ -129,18 +144,11 @@ static bool CallClosure(const base::Closure& callback) { ...@@ -129,18 +144,11 @@ static bool CallClosure(const base::Closure& callback) {
return true; return true;
} }
static void CallDiscoveryCallback( static void StopDiscoverySessionCallback(const base::Closure& callback,
const base::Closure& callback, const base::Closure& error_callback) {
const BluetoothAdapter::ErrorCallback& error_callback) {
callback.Run(); callback.Run();
} }
static void CallDiscoveryErrorCallback(
const base::Closure& callback,
const BluetoothAdapter::ErrorCallback& error_callback) {
error_callback.Run();
}
static void CallOutOfBandPairingDataCallback( static void CallOutOfBandPairingDataCallback(
const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback, const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback,
const BluetoothAdapter::ErrorCallback& error_callback) { const BluetoothAdapter::ErrorCallback& error_callback) {
...@@ -316,9 +324,12 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, SetOutOfBandPairingData) { ...@@ -316,9 +324,12 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, SetOutOfBandPairingData) {
} }
IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Discovery) { IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Discovery) {
// Try with a failure to start // Try with a failure to start. This will return an error as we haven't
EXPECT_CALL(*mock_adapter_, StartDiscovering(testing::_, testing::_)) // initialied a session object.
.WillOnce(testing::Invoke(CallDiscoveryErrorCallback)); EXPECT_CALL(*mock_adapter_, StartDiscoverySession(testing::_, testing::_))
.WillOnce(
testing::Invoke(this, &BluetoothApiTest::DiscoverySessionCallback));
// StartDiscovery failure will remove the adapter that is no longer used. // StartDiscovery failure will remove the adapter that is no longer used.
EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)); EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_));
scoped_refptr<api::BluetoothStartDiscoveryFunction> start_function; scoped_refptr<api::BluetoothStartDiscoveryFunction> start_function;
...@@ -327,19 +338,28 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Discovery) { ...@@ -327,19 +338,28 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Discovery) {
utils::RunFunctionAndReturnError(start_function.get(), "[]", browser())); utils::RunFunctionAndReturnError(start_function.get(), "[]", browser()));
ASSERT_FALSE(error.empty()); ASSERT_FALSE(error.empty());
// Reset for a successful start // Reset the adapter and initiate a discovery session. The ownership of the
// mock session will be passed to the event router.
ASSERT_FALSE(mock_session_.get());
SetUpMockAdapter(); SetUpMockAdapter();
EXPECT_CALL(*mock_adapter_, StartDiscovering(testing::_, testing::_))
.WillOnce(testing::Invoke(CallDiscoveryCallback));
// Create a mock session to be returned as a result. Get a handle to it as
// its ownership will be passed and |mock_session_| will be reset.
mock_session_.reset(new testing::NiceMock<MockBluetoothDiscoverySession>());
MockBluetoothDiscoverySession* session = mock_session_.get();
EXPECT_CALL(*mock_adapter_, StartDiscoverySession(testing::_, testing::_))
.WillOnce(
testing::Invoke(this, &BluetoothApiTest::DiscoverySessionCallback));
start_function = setupFunction(new api::BluetoothStartDiscoveryFunction); start_function = setupFunction(new api::BluetoothStartDiscoveryFunction);
(void) (void)
utils::RunFunctionAndReturnError(start_function.get(), "[]", browser()); utils::RunFunctionAndReturnError(start_function.get(), "[]", browser());
// Reset to try stopping // End the discovery session. The StopDiscovery function should succeed.
testing::Mock::VerifyAndClearExpectations(mock_adapter_); testing::Mock::VerifyAndClearExpectations(mock_adapter_);
EXPECT_CALL(*mock_adapter_, StopDiscovering(testing::_, testing::_)) EXPECT_CALL(*session, IsActive()).WillOnce(testing::Return(true));
.WillOnce(testing::Invoke(CallDiscoveryCallback)); EXPECT_CALL(*session, Stop(testing::_, testing::_))
.WillOnce(testing::Invoke(StopDiscoverySessionCallback));
// StopDiscovery success will remove the adapter that is no longer used. // StopDiscovery success will remove the adapter that is no longer used.
EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)); EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_));
scoped_refptr<api::BluetoothStopDiscoveryFunction> stop_function; scoped_refptr<api::BluetoothStopDiscoveryFunction> stop_function;
...@@ -347,10 +367,10 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Discovery) { ...@@ -347,10 +367,10 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Discovery) {
(void) utils::RunFunctionAndReturnSingleResult( (void) utils::RunFunctionAndReturnSingleResult(
stop_function.get(), "[]", browser()); stop_function.get(), "[]", browser());
// Reset to try stopping with an error // Reset the adapter. Simulate failure for stop discovery. The event router
// still owns the session. Make it appear inactive.
SetUpMockAdapter(); SetUpMockAdapter();
EXPECT_CALL(*mock_adapter_, StopDiscovering(testing::_, testing::_)) EXPECT_CALL(*session, IsActive()).WillOnce(testing::Return(false));
.WillOnce(testing::Invoke(CallDiscoveryErrorCallback));
EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)); EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_));
stop_function = setupFunction(new api::BluetoothStopDiscoveryFunction); stop_function = setupFunction(new api::BluetoothStopDiscoveryFunction);
error = error =
...@@ -360,10 +380,14 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Discovery) { ...@@ -360,10 +380,14 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Discovery) {
} }
IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DiscoveryCallback) { IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DiscoveryCallback) {
EXPECT_CALL(*mock_adapter_, StartDiscovering(testing::_, testing::_)) mock_session_.reset(new testing::NiceMock<MockBluetoothDiscoverySession>());
.WillOnce(testing::Invoke(CallDiscoveryCallback)); MockBluetoothDiscoverySession* session = mock_session_.get();
EXPECT_CALL(*mock_adapter_, StopDiscovering(testing::_, testing::_)) EXPECT_CALL(*mock_adapter_, StartDiscoverySession(testing::_, testing::_))
.WillOnce(testing::Invoke(CallDiscoveryCallback)); .WillOnce(
testing::Invoke(this, &BluetoothApiTest::DiscoverySessionCallback));
EXPECT_CALL(*session, IsActive()).WillOnce(testing::Return(true));
EXPECT_CALL(*session, Stop(testing::_, testing::_))
.WillOnce(testing::Invoke(StopDiscoverySessionCallback));
ResultCatcher catcher; ResultCatcher catcher;
catcher.RestrictToProfile(browser()->profile()); catcher.RestrictToProfile(browser()->profile());
...@@ -408,17 +432,22 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DiscoveryInProgress) { ...@@ -408,17 +432,22 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DiscoveryInProgress) {
ResultCatcher catcher; ResultCatcher catcher;
catcher.RestrictToProfile(browser()->profile()); catcher.RestrictToProfile(browser()->profile());
EXPECT_CALL(*mock_adapter_, StartDiscovering(testing::_, testing::_)) mock_session_.reset(new testing::NiceMock<MockBluetoothDiscoverySession>());
.WillOnce(testing::Invoke(CallDiscoveryCallback)); MockBluetoothDiscoverySession* session = mock_session_.get();
EXPECT_CALL(*mock_adapter_, StopDiscovering(testing::_, testing::_)) EXPECT_CALL(*mock_adapter_, StartDiscoverySession(testing::_, testing::_))
.WillOnce(testing::Invoke(CallDiscoveryCallback)); .WillOnce(
testing::Invoke(this, &BluetoothApiTest::DiscoverySessionCallback));
EXPECT_CALL(*session, IsActive()).WillOnce(testing::Return(true));
EXPECT_CALL(*session, Stop(testing::_, testing::_))
.WillOnce(testing::Invoke(StopDiscoverySessionCallback));
ExtensionTestMessageListener discovery_started("ready", true); ExtensionTestMessageListener discovery_started("ready", true);
ASSERT_TRUE(LoadExtension( ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("bluetooth/discovery_in_progress"))); test_data_dir_.AppendASCII("bluetooth/discovery_in_progress")));
EXPECT_TRUE(discovery_started.WaitUntilSatisfied()); EXPECT_TRUE(discovery_started.WaitUntilSatisfied());
// This should be received in addition to the cached device above. // Only this should be received. No additional notification should be sent for
// devices discovered before the discovery session started.
event_router()->DeviceAdded(mock_adapter_, device2_.get()); event_router()->DeviceAdded(mock_adapter_, device2_.get());
discovery_started.Reply("go"); discovery_started.Reply("go");
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h" #include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_device.h" #include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_discovery_session.h"
#include "device/bluetooth/bluetooth_profile.h" #include "device/bluetooth/bluetooth_profile.h"
#include "device/bluetooth/bluetooth_socket.h" #include "device/bluetooth/bluetooth_socket.h"
#include "extensions/browser/event_router.h" #include "extensions/browser/event_router.h"
...@@ -45,9 +46,7 @@ struct ExtensionBluetoothProfileRecord { ...@@ -45,9 +46,7 @@ struct ExtensionBluetoothProfileRecord {
ExtensionBluetoothEventRouter::ExtensionBluetoothEventRouter( ExtensionBluetoothEventRouter::ExtensionBluetoothEventRouter(
content::BrowserContext* context) content::BrowserContext* context)
: send_discovery_events_(false), : browser_context_(context),
responsible_for_discovery_(false),
browser_context_(context),
adapter_(NULL), adapter_(NULL),
num_event_listeners_(0), num_event_listeners_(0),
next_socket_id_(1), next_socket_id_(1),
...@@ -72,6 +71,11 @@ ExtensionBluetoothEventRouter::~ExtensionBluetoothEventRouter() { ...@@ -72,6 +71,11 @@ ExtensionBluetoothEventRouter::~ExtensionBluetoothEventRouter() {
++iter) { ++iter) {
iter->second.profile->Unregister(); iter->second.profile->Unregister();
} }
for (DiscoverySessionMap::iterator iter = discovery_session_map_.begin();
iter != discovery_session_map_.end();
++iter) {
delete iter->second;
}
} }
bool ExtensionBluetoothEventRouter::IsBluetoothSupported() const { bool ExtensionBluetoothEventRouter::IsBluetoothSupported() const {
...@@ -145,6 +149,50 @@ bool ExtensionBluetoothEventRouter::HasProfile(const std::string& uuid) const { ...@@ -145,6 +149,50 @@ bool ExtensionBluetoothEventRouter::HasProfile(const std::string& uuid) const {
return bluetooth_profile_map_.find(uuid) != bluetooth_profile_map_.end(); return bluetooth_profile_map_.find(uuid) != bluetooth_profile_map_.end();
} }
void ExtensionBluetoothEventRouter::StartDiscoverySession(
device::BluetoothAdapter* adapter,
const std::string& extension_id,
const base::Closure& callback,
const base::Closure& error_callback) {
if (adapter != adapter_.get()) {
error_callback.Run();
return;
}
DiscoverySessionMap::iterator iter =
discovery_session_map_.find(extension_id);
if (iter != discovery_session_map_.end() && iter->second->IsActive()) {
DVLOG(1) << "An active discovery session exists for extension.";
error_callback.Run();
return;
}
adapter->StartDiscoverySession(
base::Bind(&ExtensionBluetoothEventRouter::OnStartDiscoverySession,
weak_ptr_factory_.GetWeakPtr(),
extension_id,
callback),
error_callback);
}
void ExtensionBluetoothEventRouter::StopDiscoverySession(
device::BluetoothAdapter* adapter,
const std::string& extension_id,
const base::Closure& callback,
const base::Closure& error_callback) {
if (adapter != adapter_.get()) {
error_callback.Run();
return;
}
DiscoverySessionMap::iterator iter =
discovery_session_map_.find(extension_id);
if (iter == discovery_session_map_.end() || !iter->second->IsActive()) {
DVLOG(1) << "No active discovery session exists for extension.";
error_callback.Run();
return;
}
device::BluetoothDiscoverySession* session = iter->second;
session->Stop(callback, error_callback);
}
device::BluetoothProfile* ExtensionBluetoothEventRouter::GetProfile( device::BluetoothProfile* ExtensionBluetoothEventRouter::GetProfile(
const std::string& uuid) const { const std::string& uuid) const {
BluetoothProfileMap::const_iterator iter = bluetooth_profile_map_.find(uuid); BluetoothProfileMap::const_iterator iter = bluetooth_profile_map_.find(uuid);
...@@ -162,29 +210,6 @@ ExtensionBluetoothEventRouter::GetSocket(int id) { ...@@ -162,29 +210,6 @@ ExtensionBluetoothEventRouter::GetSocket(int id) {
return socket_entry->second.socket; return socket_entry->second.socket;
} }
void ExtensionBluetoothEventRouter::SetResponsibleForDiscovery(
bool responsible) {
responsible_for_discovery_ = responsible;
}
bool ExtensionBluetoothEventRouter::IsResponsibleForDiscovery() const {
return responsible_for_discovery_;
}
void ExtensionBluetoothEventRouter::SetSendDiscoveryEvents(bool should_send) {
// At the transition into sending devices, also send past devices that
// were discovered as they will not be discovered again.
if (should_send && !send_discovery_events_) {
for (DeviceList::const_iterator i = discovered_devices_.begin();
i != discovered_devices_.end(); ++i) {
DispatchDeviceEvent(extensions::event_names::kBluetoothOnDeviceDiscovered,
**i);
}
}
send_discovery_events_ = should_send;
}
void ExtensionBluetoothEventRouter::DispatchDeviceEvent( void ExtensionBluetoothEventRouter::DispatchDeviceEvent(
const std::string& event_name, const bluetooth::Device& device) { const std::string& event_name, const bluetooth::Device& device) {
scoped_ptr<base::ListValue> args(new base::ListValue()); scoped_ptr<base::ListValue> args(new base::ListValue());
...@@ -243,9 +268,19 @@ void ExtensionBluetoothEventRouter::AdapterDiscoveringChanged( ...@@ -243,9 +268,19 @@ void ExtensionBluetoothEventRouter::AdapterDiscoveringChanged(
} }
if (!discovering) { if (!discovering) {
send_discovery_events_ = false; // If any discovery sessions are inactive, clean them up.
responsible_for_discovery_ = false; DiscoverySessionMap active_session_map;
discovered_devices_.clear(); for (DiscoverySessionMap::iterator iter = discovery_session_map_.begin();
iter != discovery_session_map_.end();
++iter) {
device::BluetoothDiscoverySession* session = iter->second;
if (session->IsActive()) {
active_session_map[iter->first] = session;
continue;
}
delete session;
}
discovery_session_map_.swap(active_session_map);
} }
DispatchAdapterStateEvent(); DispatchAdapterStateEvent();
...@@ -259,17 +294,11 @@ void ExtensionBluetoothEventRouter::DeviceAdded( ...@@ -259,17 +294,11 @@ void ExtensionBluetoothEventRouter::DeviceAdded(
return; return;
} }
bluetooth::Device* extension_device = bluetooth::Device extension_device;
new bluetooth::Device(); bluetooth::BluetoothDeviceToApiDevice(*device, &extension_device);
bluetooth::BluetoothDeviceToApiDevice(
*device, extension_device);
discovered_devices_.push_back(extension_device);
if (!send_discovery_events_)
return;
DispatchDeviceEvent(extensions::event_names::kBluetoothOnDeviceDiscovered, DispatchDeviceEvent(extensions::event_names::kBluetoothOnDeviceDiscovered,
*extension_device); extension_device);
} }
void ExtensionBluetoothEventRouter::InitializeAdapterIfNeeded() { void ExtensionBluetoothEventRouter::InitializeAdapterIfNeeded() {
...@@ -331,6 +360,27 @@ void ExtensionBluetoothEventRouter::CleanUpForExtension( ...@@ -331,6 +360,27 @@ void ExtensionBluetoothEventRouter::CleanUpForExtension(
ReleaseSocket(socket_id); ReleaseSocket(socket_id);
} }
} }
// Remove any discovery session initiated by the extension.
DiscoverySessionMap::iterator session_iter =
discovery_session_map_.find(extension_id);
if (session_iter == discovery_session_map_.end())
return;
delete session_iter->second;
discovery_session_map_.erase(session_iter);
}
void ExtensionBluetoothEventRouter::OnStartDiscoverySession(
const std::string& extension_id,
const base::Closure& callback,
scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
// Clean up any existing session instance for the extension.
DiscoverySessionMap::iterator iter =
discovery_session_map_.find(extension_id);
if (iter != discovery_session_map_.end())
delete iter->second;
discovery_session_map_[extension_id] = discovery_session.release();
callback.Run();
} }
void ExtensionBluetoothEventRouter::Observe( void ExtensionBluetoothEventRouter::Observe(
......
...@@ -24,6 +24,7 @@ class BrowserContext; ...@@ -24,6 +24,7 @@ class BrowserContext;
namespace device { namespace device {
class BluetoothDevice; class BluetoothDevice;
class BluetoothDiscoverySession;
class BluetoothProfile; class BluetoothProfile;
} // namespace device } // namespace device
...@@ -81,6 +82,25 @@ class ExtensionBluetoothEventRouter ...@@ -81,6 +82,25 @@ class ExtensionBluetoothEventRouter
// registered. // registered.
bool HasProfile(const std::string& uuid) const; bool HasProfile(const std::string& uuid) const;
// Requests that a new device discovery session be initiated for extension
// with id |extension_id|. |callback| is called, if a session has been
// initiated. |error_callback| is called, if the adapter failed to initiate
// the session or if an active session already exists for the extension.
void StartDiscoverySession(device::BluetoothAdapter* adapter,
const std::string& extension_id,
const base::Closure& callback,
const base::Closure& error_callback);
// Requests that the active discovery session that belongs to the extension
// with id |extension_id| be terminated. |callback| is called, if the session
// successfully ended. |error_callback| is called, if the adapter failed to
// terminate the session or if no active discovery session exists for the
// extension.
void StopDiscoverySession(device::BluetoothAdapter* adapter,
const std::string& extension_id,
const base::Closure& callback,
const base::Closure& error_callback);
// Returns the BluetoothProfile that corresponds to |uuid|. It returns NULL // Returns the BluetoothProfile that corresponds to |uuid|. It returns NULL
// if the BluetoothProfile with |uuid| does not exist. // if the BluetoothProfile with |uuid| does not exist.
device::BluetoothProfile* GetProfile(const std::string& uuid) const; device::BluetoothProfile* GetProfile(const std::string& uuid) const;
...@@ -88,14 +108,6 @@ class ExtensionBluetoothEventRouter ...@@ -88,14 +108,6 @@ class ExtensionBluetoothEventRouter
// Get the BluetoothSocket corresponding to |id|. // Get the BluetoothSocket corresponding to |id|.
scoped_refptr<device::BluetoothSocket> GetSocket(int id); scoped_refptr<device::BluetoothSocket> GetSocket(int id);
// Sets whether this Profile is responsible for the discovering state of the
// adapter.
void SetResponsibleForDiscovery(bool responsible);
bool IsResponsibleForDiscovery() const;
// Sets whether or not DeviceAdded events will be dispatched to extensions.
void SetSendDiscoveryEvents(bool should_send);
// Dispatch an event that takes a device as a parameter to all renderers. // Dispatch an event that takes a device as a parameter to all renderers.
void DispatchDeviceEvent( void DispatchDeviceEvent(
const std::string& event_name, const std::string& event_name,
...@@ -127,15 +139,17 @@ class ExtensionBluetoothEventRouter ...@@ -127,15 +139,17 @@ class ExtensionBluetoothEventRouter
void SetAdapterForTest(device::BluetoothAdapter* adapter) { void SetAdapterForTest(device::BluetoothAdapter* adapter) {
adapter_ = adapter; adapter_ = adapter;
} }
private: private:
void InitializeAdapterIfNeeded(); void InitializeAdapterIfNeeded();
void InitializeAdapter(scoped_refptr<device::BluetoothAdapter> adapter); void InitializeAdapter(scoped_refptr<device::BluetoothAdapter> adapter);
void MaybeReleaseAdapter(); void MaybeReleaseAdapter();
void DispatchAdapterStateEvent(); void DispatchAdapterStateEvent();
void CleanUpForExtension(const std::string& extension_id); void CleanUpForExtension(const std::string& extension_id);
void OnStartDiscoverySession(
bool send_discovery_events_; const std::string& extension_id,
bool responsible_for_discovery_; const base::Closure& callback,
scoped_ptr<device::BluetoothDiscoverySession> discovery_session);
content::BrowserContext* browser_context_; content::BrowserContext* browser_context_;
scoped_refptr<device::BluetoothAdapter> adapter_; scoped_refptr<device::BluetoothAdapter> adapter_;
...@@ -150,15 +164,16 @@ class ExtensionBluetoothEventRouter ...@@ -150,15 +164,16 @@ class ExtensionBluetoothEventRouter
typedef std::map<int, ExtensionBluetoothSocketRecord> SocketMap; typedef std::map<int, ExtensionBluetoothSocketRecord> SocketMap;
SocketMap socket_map_; SocketMap socket_map_;
typedef ScopedVector<extensions::api::bluetooth::Device>
DeviceList;
DeviceList discovered_devices_;
// A map that maps uuids to ExtensionBluetoothProfileRecord. // A map that maps uuids to ExtensionBluetoothProfileRecord.
typedef std::map<std::string, ExtensionBluetoothProfileRecord> typedef std::map<std::string, ExtensionBluetoothProfileRecord>
BluetoothProfileMap; BluetoothProfileMap;
BluetoothProfileMap bluetooth_profile_map_; BluetoothProfileMap bluetooth_profile_map_;
// A map that maps extension ids to BluetoothDiscoverySession pointers.
typedef std::map<std::string, device::BluetoothDiscoverySession*>
DiscoverySessionMap;
DiscoverySessionMap discovery_session_map_;
content::NotificationRegistrar registrar_; content::NotificationRegistrar registrar_;
base::WeakPtrFactory<ExtensionBluetoothEventRouter> weak_ptr_factory_; base::WeakPtrFactory<ExtensionBluetoothEventRouter> weak_ptr_factory_;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
var kExpectedDeviceNames = ["d1", "d2"]; var kExpectedDeviceNames = ["d2"];
function testDiscovery() { function testDiscovery() {
chrome.test.assertEq(kExpectedDeviceNames.length, chrome.test.assertEq(kExpectedDeviceNames.length,
......
...@@ -123,6 +123,8 @@ ...@@ -123,6 +123,8 @@
'test/mock_bluetooth_adapter.h', 'test/mock_bluetooth_adapter.h',
'test/mock_bluetooth_device.cc', 'test/mock_bluetooth_device.cc',
'test/mock_bluetooth_device.h', 'test/mock_bluetooth_device.h',
'test/mock_bluetooth_discovery_session.cc',
'test/mock_bluetooth_discovery_session.h',
'test/mock_bluetooth_profile.cc', 'test/mock_bluetooth_profile.cc',
'test/mock_bluetooth_profile.h', 'test/mock_bluetooth_profile.h',
'test/mock_bluetooth_socket.cc', 'test/mock_bluetooth_socket.cc',
......
...@@ -113,7 +113,7 @@ void BluetoothAdapter::OnStartDiscoverySession( ...@@ -113,7 +113,7 @@ void BluetoothAdapter::OnStartDiscoverySession(
const DiscoverySessionCallback& callback) { const DiscoverySessionCallback& callback) {
VLOG(1) << "Discovery session started!"; VLOG(1) << "Discovery session started!";
scoped_ptr<BluetoothDiscoverySession> discovery_session( scoped_ptr<BluetoothDiscoverySession> discovery_session(
new BluetoothDiscoverySession(this)); new BluetoothDiscoverySession(scoped_refptr<BluetoothAdapter>(this)));
discovery_sessions_.insert(discovery_session.get()); discovery_sessions_.insert(discovery_session.get());
callback.Run(discovery_session.Pass()); callback.Run(discovery_session.Pass());
} }
......
...@@ -9,13 +9,21 @@ ...@@ -9,13 +9,21 @@
namespace device { namespace device {
BluetoothDiscoverySession::BluetoothDiscoverySession(BluetoothAdapter* adapter) BluetoothDiscoverySession::BluetoothDiscoverySession(
: active_(true), scoped_refptr<BluetoothAdapter> adapter)
adapter_(adapter), : active_(true), adapter_(adapter), weak_ptr_factory_(this) {
weak_ptr_factory_(this) { DCHECK(adapter_.get());
} }
BluetoothDiscoverySession::BluetoothDiscoverySession()
: active_(false), weak_ptr_factory_(this) {}
BluetoothDiscoverySession::~BluetoothDiscoverySession() { BluetoothDiscoverySession::~BluetoothDiscoverySession() {
// |adapter_| may be NULL if this instance was initialized as a mock.
if (!adapter_.get()) {
DCHECK(!active_);
return;
}
Stop(base::Bind(&base::DoNothing), base::Bind(&base::DoNothing)); Stop(base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
adapter_->DiscoverySessionDestroyed(this); adapter_->DiscoverySessionDestroyed(this);
} }
...@@ -28,11 +36,12 @@ void BluetoothDiscoverySession::Stop( ...@@ -28,11 +36,12 @@ void BluetoothDiscoverySession::Stop(
const base::Closure& callback, const base::Closure& callback,
const ErrorCallback& error_callback) { const ErrorCallback& error_callback) {
if (!active_) { if (!active_) {
LOG(ERROR) << "Discovery session not active. Cannot stop."; LOG(WARNING) << "Discovery session not active. Cannot stop.";
error_callback.Run(); error_callback.Run();
return; return;
} }
VLOG(1) << "Stopping device discovery session."; VLOG(1) << "Stopping device discovery session.";
DCHECK(adapter_.get());
adapter_->RemoveDiscoverySession( adapter_->RemoveDiscoverySession(
base::Bind(&BluetoothDiscoverySession::OnStop, base::Bind(&BluetoothDiscoverySession::OnStop,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(),
......
...@@ -58,10 +58,12 @@ class BluetoothDiscoverySession { ...@@ -58,10 +58,12 @@ class BluetoothDiscoverySession {
const ErrorCallback& error_callback); const ErrorCallback& error_callback);
protected: protected:
friend class BluetoothAdapter; BluetoothDiscoverySession(); // Called by mock.
explicit BluetoothDiscoverySession(BluetoothAdapter* adapter);
private: private:
friend class BluetoothAdapter;
explicit BluetoothDiscoverySession(scoped_refptr<BluetoothAdapter> adapter);
// Internal callback invoked when a call to Stop has succeeded. // Internal callback invoked when a call to Stop has succeeded.
void OnStop(const base::Closure& callback); void OnStop(const base::Closure& callback);
......
...@@ -14,4 +14,12 @@ MockBluetoothAdapter::MockBluetoothAdapter() { ...@@ -14,4 +14,12 @@ MockBluetoothAdapter::MockBluetoothAdapter() {
MockBluetoothAdapter::~MockBluetoothAdapter() {} MockBluetoothAdapter::~MockBluetoothAdapter() {}
void MockBluetoothAdapter::AddDiscoverySession(
const base::Closure& callback,
const ErrorCallback& error_callback) {}
void MockBluetoothAdapter::RemoveDiscoverySession(
const base::Closure& callback,
const ErrorCallback& error_callback) {}
} // namespace device } // namespace device
...@@ -52,6 +52,9 @@ class MockBluetoothAdapter : public BluetoothAdapter { ...@@ -52,6 +52,9 @@ class MockBluetoothAdapter : public BluetoothAdapter {
const base::Closure& callback, const base::Closure& callback,
const ErrorCallback& error_callback)); const ErrorCallback& error_callback));
MOCK_CONST_METHOD0(IsDiscovering, bool()); MOCK_CONST_METHOD0(IsDiscovering, bool());
MOCK_METHOD2(StartDiscoverySession,
void(const DiscoverySessionCallback& callback,
const ErrorCallback& error_callback));
MOCK_METHOD2(StartDiscovering, MOCK_METHOD2(StartDiscovering,
void(const base::Closure& callback, void(const base::Closure& callback,
const ErrorCallback& error_callback)); const ErrorCallback& error_callback));
...@@ -74,12 +77,10 @@ class MockBluetoothAdapter : public BluetoothAdapter { ...@@ -74,12 +77,10 @@ class MockBluetoothAdapter : public BluetoothAdapter {
MOCK_METHOD0(DefaultPairingDelegate, BluetoothDevice::PairingDelegate*()); MOCK_METHOD0(DefaultPairingDelegate, BluetoothDevice::PairingDelegate*());
protected: protected:
MOCK_METHOD2(AddDiscoverySession, virtual void AddDiscoverySession(const base::Closure& callback,
void(const base::Closure& callback, const ErrorCallback& error_callback);
const ErrorCallback& error_callback)); virtual void RemoveDiscoverySession(const base::Closure& callback,
MOCK_METHOD2(RemoveDiscoverySession, const ErrorCallback& error_callback);
void(const base::Closure& callback,
const ErrorCallback& error_callback));
virtual ~MockBluetoothAdapter(); virtual ~MockBluetoothAdapter();
MOCK_METHOD1(RemovePairingDelegateInternal, MOCK_METHOD1(RemovePairingDelegateInternal,
......
// 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.
#include "device/bluetooth/test/mock_bluetooth_discovery_session.h"
#include "device/bluetooth/bluetooth_adapter.h"
namespace device {
MockBluetoothDiscoverySession::MockBluetoothDiscoverySession() {}
MockBluetoothDiscoverySession::~MockBluetoothDiscoverySession() {}
} // namespace device
// 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 DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_DISCOVERY_SESSION_H_
#define DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_DISCOVERY_SESSION_H_
#include "base/callback.h"
#include "device/bluetooth/bluetooth_discovery_session.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace device {
class BluetoothAdapter;
class MockBluetoothDiscoverySession : public BluetoothDiscoverySession {
public:
MockBluetoothDiscoverySession();
virtual ~MockBluetoothDiscoverySession();
MOCK_CONST_METHOD0(IsActive, bool());
MOCK_METHOD2(Stop,
void(const base::Closure& callback,
const ErrorCallback& error_callback));
private:
DISALLOW_COPY_AND_ASSIGN(MockBluetoothDiscoverySession);
};
} // namespac device
#endif // DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_DISCOVERY_SESSION_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment