Bug 1038645: Asynchronous starting and stopping of profile managers (under bluetooth2/), r=btian

Profile managers use the new class |BluetoothProfileResultHandler|
to signal the result of initializing of cleaning up operations to
|BluetoothServiceBluedroid|. |BluetoothServiceBluedroid| proceeds
once all profile handlers have finished.

Future patches will build upon this patch to create completely
asynchronous profile managers.
This commit is contained in:
Thomas Zimmermann 2014-07-22 13:53:27 +02:00
parent 506b43c91f
commit 9b1bbedfbc
6 changed files with 172 additions and 21 deletions

View File

@ -28,6 +28,18 @@
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothProfileController;
class BluetoothProfileResultHandler
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BluetoothProfileResultHandler);
virtual ~BluetoothProfileResultHandler() { }
virtual void OnError(nsresult aResult) { }
virtual void Init() { }
virtual void Deinit() { }
};
class BluetoothProfileManagerBase : public nsIObserver
{
public:

View File

@ -500,13 +500,25 @@ static btrc_callbacks_t sBtAvrcpCallbacks = {
*/
// static
void
BluetoothA2dpManager::InitA2dpInterface()
BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
{
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
NS_ENSURE_TRUE_VOID(btInf);
if (!btInf) {
BT_LOGR("Error: Bluetooth interface not available");
if (aRes) {
aRes->OnError(NS_ERROR_FAILURE);
}
return;
}
sBtA2dpInterface = btInf->GetBluetoothA2dpInterface();
NS_ENSURE_TRUE_VOID(sBtA2dpInterface);
if (!sBtA2dpInterface) {
BT_LOGR("Error: Bluetooth A2DP interface not available");
if (aRes) {
aRes->OnError(NS_ERROR_FAILURE);
}
return;
}
int ret = sBtA2dpInterface->Init(&sBtA2dpCallbacks);
if (ret != BT_STATUS_SUCCESS) {
@ -515,13 +527,23 @@ BluetoothA2dpManager::InitA2dpInterface()
#if ANDROID_VERSION > 17
sBtAvrcpInterface = btInf->GetBluetoothAvrcpInterface();
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
if (!sBtAvrcpInterface) {
BT_LOGR("Error: Bluetooth AVRCP interface not available");
if (aRes) {
aRes->OnError(NS_ERROR_FAILURE);
}
return;
}
ret = sBtAvrcpInterface->Init(&sBtAvrcpCallbacks);
if (ret != BT_STATUS_SUCCESS) {
BT_LOGR("Warning: failed to init avrcp module");
}
#endif
if (aRes) {
aRes->Init();
}
}
BluetoothA2dpManager::~BluetoothA2dpManager()
@ -597,7 +619,7 @@ BluetoothA2dpManager::Get()
// static
void
BluetoothA2dpManager::DeinitA2dpInterface()
BluetoothA2dpManager::DeinitA2dpInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
@ -611,6 +633,9 @@ BluetoothA2dpManager::DeinitA2dpInterface()
sBtAvrcpInterface = nullptr;
}
#endif
if (aRes) {
aRes->Deinit();
}
}
void

View File

@ -30,8 +30,8 @@ public:
};
static BluetoothA2dpManager* Get();
static void InitA2dpInterface();
static void DeinitA2dpInterface();
static void InitA2dpInterface(BluetoothProfileResultHandler* aRes);
static void DeinitA2dpInterface(BluetoothProfileResultHandler* aRes);
virtual ~BluetoothA2dpManager();
// A2DP-specific functions

View File

@ -152,12 +152,54 @@ public:
}
};
/* |ProfileDeinitResultHandler| collects the results of all profile
* result handlers and calls |Proceed| after all results handlers
* have been run.
*/
class ProfileDeinitResultHandler MOZ_FINAL
: public BluetoothProfileResultHandler
{
public:
ProfileDeinitResultHandler(unsigned char aNumProfiles)
: mNumProfiles(aNumProfiles)
{
MOZ_ASSERT(mNumProfiles);
}
void Deinit() MOZ_OVERRIDE
{
if (!(--mNumProfiles)) {
Proceed();
}
}
void OnError(nsresult aResult) MOZ_OVERRIDE
{
if (!(--mNumProfiles)) {
Proceed();
}
}
private:
void Proceed() const
{
sBtInterface->Cleanup(nullptr);
}
unsigned char mNumProfiles;
};
class CleanupTask MOZ_FINAL : public nsRunnable
{
public:
NS_IMETHOD
Run()
{
static void (* const sDeinitManager[])(BluetoothProfileResultHandler*) = {
BluetoothHfpManager::DeinitHfpInterface,
BluetoothA2dpManager::DeinitA2dpInterface
};
MOZ_ASSERT(NS_IsMainThread());
// Return error if BluetoothService is unavailable
@ -185,9 +227,12 @@ public:
bs->DistributeSignal(signal);
// Cleanup bluetooth interfaces after BT state becomes BT_STATE_OFF.
BluetoothHfpManager::DeinitHfpInterface();
BluetoothA2dpManager::DeinitA2dpInterface();
sBtInterface->Cleanup(nullptr);
nsRefPtr<ProfileDeinitResultHandler> res =
new ProfileDeinitResultHandler(MOZ_ARRAY_LENGTH(sDeinitManager));
for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sDeinitManager); ++i) {
sDeinitManager[i](res);
}
return NS_OK;
}
@ -765,19 +810,64 @@ public:
}
};
/* |ProfileInitResultHandler| collects the results of all profile
* result handlers and calls |Proceed| after all results handlers
* have been run.
*/
class ProfileInitResultHandler MOZ_FINAL
: public BluetoothProfileResultHandler
{
public:
ProfileInitResultHandler(unsigned char aNumProfiles)
: mNumProfiles(aNumProfiles)
{
MOZ_ASSERT(mNumProfiles);
}
void Init() MOZ_OVERRIDE
{
if (!(--mNumProfiles)) {
Proceed();
}
}
void OnError(nsresult aResult) MOZ_OVERRIDE
{
if (!(--mNumProfiles)) {
Proceed();
}
}
private:
void Proceed() const
{
sBtInterface->Enable(new EnableResultHandler());
}
unsigned char mNumProfiles;
};
class InitResultHandler MOZ_FINAL : public BluetoothResultHandler
{
public:
void Init() MOZ_OVERRIDE
{
static void (* const sInitManager[])(BluetoothProfileResultHandler*) = {
BluetoothHfpManager::InitHfpInterface,
BluetoothA2dpManager::InitA2dpInterface
};
MOZ_ASSERT(NS_IsMainThread());
// Register all the bluedroid callbacks before enable() get called
// It is required to register a2dp callbacks before a2dp media task starts up.
// If any interface cannot be initialized, turn on bluetooth core anyway.
BluetoothHfpManager::InitHfpInterface();
BluetoothA2dpManager::InitA2dpInterface();
sBtInterface->Enable(new EnableResultHandler());
nsRefPtr<ProfileInitResultHandler> res =
new ProfileInitResultHandler(MOZ_ARRAY_LENGTH(sInitManager));
for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sInitManager); ++i) {
sInitManager[i](res);
}
}
void OnError(int aStatus) MOZ_OVERRIDE

View File

@ -430,10 +430,16 @@ BluetoothHfpManager::Init()
// static
void
BluetoothHfpManager::InitHfpInterface()
BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes)
{
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
NS_ENSURE_TRUE_VOID(btInf);
if (!btInf) {
BT_LOGR("Error: Bluetooth interface not available");
if (aRes) {
aRes->OnError(NS_ERROR_FAILURE);
}
return;
}
if (sBluetoothHfpInterface) {
sBluetoothHfpInterface->Cleanup();
@ -442,11 +448,26 @@ BluetoothHfpManager::InitHfpInterface()
BluetoothHandsfreeInterface *interface =
btInf->GetBluetoothHandsfreeInterface();
NS_ENSURE_TRUE_VOID(interface);
if (!interface) {
BT_LOGR("Error: Bluetooth Handsfree interface not available");
if (aRes) {
aRes->OnError(NS_ERROR_FAILURE);
}
return;
}
if (interface->Init(&sBluetoothHfpCallbacks) != BT_STATUS_SUCCESS) {
if (aRes) {
aRes->OnError(NS_ERROR_FAILURE);
}
return;
}
NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
interface->Init(&sBluetoothHfpCallbacks));
sBluetoothHfpInterface = interface;
if (aRes) {
aRes->Init();
}
}
BluetoothHfpManager::~BluetoothHfpManager()
@ -469,12 +490,15 @@ BluetoothHfpManager::~BluetoothHfpManager()
// static
void
BluetoothHfpManager::DeinitHfpInterface()
BluetoothHfpManager::DeinitHfpInterface(BluetoothProfileResultHandler* aRes)
{
if (sBluetoothHfpInterface) {
sBluetoothHfpInterface->Cleanup();
sBluetoothHfpInterface = nullptr;
}
if (aRes) {
aRes->Deinit();
}
}
//static

View File

@ -82,8 +82,8 @@ public:
static BluetoothHfpManager* Get();
virtual ~BluetoothHfpManager();
static void InitHfpInterface();
static void DeinitHfpInterface();
static void InitHfpInterface(BluetoothProfileResultHandler* aRes);
static void DeinitHfpInterface(BluetoothProfileResultHandler* aRes);
bool ConnectSco();
bool DisconnectSco();