Bug 815325 - Patch 1: Turning bluetooth on and off multiple times causes restart, r=echou
This commit is contained in:
@@ -54,6 +54,7 @@ namespace {
|
|||||||
StaticRefPtr<BluetoothService> gBluetoothService;
|
StaticRefPtr<BluetoothService> gBluetoothService;
|
||||||
|
|
||||||
bool gInShutdown = false;
|
bool gInShutdown = false;
|
||||||
|
bool gToggleInProgress = false;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IsMainProcess()
|
IsMainProcess()
|
||||||
@@ -156,16 +157,29 @@ public:
|
|||||||
{
|
{
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
|
|
||||||
if (mEnabled) {
|
/*
|
||||||
if (NS_FAILED(gBluetoothService->StartInternal())) {
|
* mEnabled: expected status of bluetooth
|
||||||
NS_WARNING("Bluetooth service failed to start!");
|
* gBluetoothService->IsEnabled(): real status of bluetooth
|
||||||
mEnabled = !mEnabled;
|
*
|
||||||
|
* When two values are the same, we don't switch on/off bluetooth,
|
||||||
|
* but we still do ToggleBtAck task.
|
||||||
|
*/
|
||||||
|
if (mEnabled == gBluetoothService->IsEnabled()) {
|
||||||
|
NS_WARNING("Bluetooth has already been enabled/disabled before.");
|
||||||
|
} else {
|
||||||
|
// Switch on/off bluetooth
|
||||||
|
if (mEnabled) {
|
||||||
|
if (NS_FAILED(gBluetoothService->StartInternal())) {
|
||||||
|
NS_WARNING("Bluetooth service failed to start!");
|
||||||
|
mEnabled = !mEnabled;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (NS_FAILED(gBluetoothService->StopInternal())) {
|
||||||
|
NS_WARNING("Bluetooth service failed to stop!");
|
||||||
|
mEnabled = !mEnabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (NS_FAILED(gBluetoothService->StopInternal())) {
|
|
||||||
NS_WARNING("Bluetooth service failed to stop!");
|
|
||||||
mEnabled = !mEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIRunnable> ackTask = new BluetoothService::ToggleBtAck(mEnabled);
|
nsCOMPtr<nsIRunnable> ackTask = new BluetoothService::ToggleBtAck(mEnabled);
|
||||||
if (NS_FAILED(NS_DispatchToMainThread(ackTask))) {
|
if (NS_FAILED(NS_DispatchToMainThread(ackTask))) {
|
||||||
@@ -213,6 +227,12 @@ NS_IMPL_ISUPPORTS1(BluetoothService::StartupTask, nsISettingsServiceCallback);
|
|||||||
|
|
||||||
NS_IMPL_ISUPPORTS1(BluetoothService, nsIObserver)
|
NS_IMPL_ISUPPORTS1(BluetoothService, nsIObserver)
|
||||||
|
|
||||||
|
bool
|
||||||
|
BluetoothService::IsToggling() const
|
||||||
|
{
|
||||||
|
return gToggleInProgress;
|
||||||
|
}
|
||||||
|
|
||||||
BluetoothService::~BluetoothService()
|
BluetoothService::~BluetoothService()
|
||||||
{
|
{
|
||||||
Cleanup();
|
Cleanup();
|
||||||
@@ -266,7 +286,6 @@ BluetoothService::Cleanup()
|
|||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||||
if (obs &&
|
if (obs &&
|
||||||
(NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) ||
|
(NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) ||
|
||||||
@@ -364,7 +383,6 @@ BluetoothService::StartStopBluetooth(bool aStart)
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
||||||
if (!mBluetoothCommandThread) {
|
if (!mBluetoothCommandThread) {
|
||||||
MOZ_ASSERT(!gInShutdown);
|
MOZ_ASSERT(!gInShutdown);
|
||||||
|
|
||||||
@@ -385,13 +403,6 @@ BluetoothService::SetEnabled(bool aEnabled)
|
|||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
if (aEnabled == mEnabled) {
|
|
||||||
// Nothing to do, maybe something failed.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mEnabled = aEnabled;
|
|
||||||
|
|
||||||
AutoInfallibleTArray<BluetoothParent*, 10> childActors;
|
AutoInfallibleTArray<BluetoothParent*, 10> childActors;
|
||||||
GetAllBluetoothActors(childActors);
|
GetAllBluetoothActors(childActors);
|
||||||
|
|
||||||
@@ -401,10 +412,12 @@ BluetoothService::SetEnabled(bool aEnabled)
|
|||||||
|
|
||||||
if (aEnabled) {
|
if (aEnabled) {
|
||||||
BluetoothManagerList::ForwardIterator iter(mLiveManagers);
|
BluetoothManagerList::ForwardIterator iter(mLiveManagers);
|
||||||
BluetoothSignalObserverList* ol;
|
|
||||||
nsString managerPath = NS_LITERAL_STRING("/");
|
nsString managerPath = NS_LITERAL_STRING("/");
|
||||||
|
|
||||||
// Re-register here after toggling due to table mBluetoothSignalObserverTable was cleared
|
/**
|
||||||
|
* Re-register managers since table mBluetoothSignalObserverTable was
|
||||||
|
* cleared after turned off bluetooth
|
||||||
|
*/
|
||||||
while (iter.HasMore()) {
|
while (iter.HasMore()) {
|
||||||
RegisterBluetoothSignalHandler(managerPath, (BluetoothSignalObserver*)iter.GetNext());
|
RegisterBluetoothSignalHandler(managerPath, (BluetoothSignalObserver*)iter.GetNext());
|
||||||
}
|
}
|
||||||
@@ -412,19 +425,40 @@ BluetoothService::SetEnabled(bool aEnabled)
|
|||||||
mBluetoothSignalObserverTable.Clear();
|
mBluetoothSignalObserverTable.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mEnabled: real status of bluetooth
|
||||||
|
* aEnabled: expected status of bluetooth
|
||||||
|
*/
|
||||||
|
if (mEnabled == aEnabled) {
|
||||||
|
/**
|
||||||
|
* The process of toggling should be over here, so we set gToggleInProgress
|
||||||
|
* back to false here. Note that, we don't fire onenabled/ondisabled in
|
||||||
|
* this case.
|
||||||
|
*/
|
||||||
|
NS_WARNING("Bluetooth has already been enabled/disabled before.\
|
||||||
|
Skip fire onenabled/ondisabled events here.");
|
||||||
|
gToggleInProgress = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mEnabled = aEnabled;
|
||||||
|
|
||||||
|
// Fire onenabled/ondisabled event for each BluetoothManager
|
||||||
BluetoothManagerList::ForwardIterator iter(mLiveManagers);
|
BluetoothManagerList::ForwardIterator iter(mLiveManagers);
|
||||||
while (iter.HasMore()) {
|
while (iter.HasMore()) {
|
||||||
if (NS_FAILED(iter.GetNext()->FireEnabledDisabledEvent(aEnabled))) {
|
if (NS_FAILED(iter.GetNext()->FireEnabledDisabledEvent(aEnabled))) {
|
||||||
NS_WARNING("FireEnabledDisabledEvent failed!");
|
NS_WARNING("FireEnabledDisabledEvent failed!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gToggleInProgress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
BluetoothService::HandleStartup()
|
BluetoothService::HandleStartup()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(!mSettingsCheckInProgress);
|
MOZ_ASSERT(!gToggleInProgress);
|
||||||
|
|
||||||
nsCOMPtr<nsISettingsService> settings =
|
nsCOMPtr<nsISettingsService> settings =
|
||||||
do_GetService("@mozilla.org/settingsService;1");
|
do_GetService("@mozilla.org/settingsService;1");
|
||||||
@@ -438,7 +472,7 @@ BluetoothService::HandleStartup()
|
|||||||
rv = settingsLock->Get(BLUETOOTH_ENABLED_SETTING, callback);
|
rv = settingsLock->Get(BLUETOOTH_ENABLED_SETTING, callback);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
mSettingsCheckInProgress = true;
|
gToggleInProgress = true;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,18 +481,16 @@ BluetoothService::HandleStartupSettingsCheck(bool aEnable)
|
|||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
if (!mSettingsCheckInProgress) {
|
|
||||||
// Somehow the enabled setting was changed before our first settings check
|
|
||||||
// completed. Don't do anything.
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(!IsEnabled());
|
|
||||||
|
|
||||||
if (aEnable) {
|
if (aEnable) {
|
||||||
return StartStopBluetooth(true);
|
return StartStopBluetooth(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since BLUETOOTH_ENABLED_SETTING is false, we don't have to turn on
|
||||||
|
* bluetooth here, and set gToggleInProgress back to false.
|
||||||
|
*/
|
||||||
|
gToggleInProgress = false;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,28 +550,14 @@ BluetoothService::HandleSettingsChanged(const nsAString& aData)
|
|||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mSettingsCheckInProgress) {
|
if (gToggleInProgress || value.toBoolean() == IsEnabled()) {
|
||||||
// Somehow the setting for bluetooth has been flipped before our first
|
|
||||||
// settings check completed. Flip this flag so that we ignore the result
|
|
||||||
// of that check whenever it finishes.
|
|
||||||
mSettingsCheckInProgress = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value.toBoolean() == IsEnabled()) {
|
|
||||||
// Nothing to do here.
|
// Nothing to do here.
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv;
|
gToggleInProgress = true;
|
||||||
|
|
||||||
if (IsEnabled()) {
|
nsresult rv = StartStopBluetooth(value.toBoolean());
|
||||||
rv = StartStopBluetooth(false);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = StartStopBluetooth(true);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|||||||
@@ -303,12 +303,14 @@ public:
|
|||||||
return mEnabled;
|
return mEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IsToggling() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BluetoothService()
|
BluetoothService()
|
||||||
: mEnabled(false)
|
: mEnabled(false)
|
||||||
, mSettingsCheckInProgress(false)
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
, mLastRequestedEnable(false)
|
, mLastRequestedEnable(false)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
mBluetoothSignalObserverTable.Init();
|
mBluetoothSignalObserverTable.Init();
|
||||||
@@ -398,7 +400,6 @@ protected:
|
|||||||
BluetoothManagerList mLiveManagers;
|
BluetoothManagerList mLiveManagers;
|
||||||
|
|
||||||
bool mEnabled;
|
bool mEnabled;
|
||||||
bool mSettingsCheckInProgress;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
bool mLastRequestedEnable;
|
bool mLastRequestedEnable;
|
||||||
|
|||||||
@@ -1428,6 +1428,16 @@ GetDefaultAdapterPath(BluetoothValue& aValue, nsString& aError)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BluetoothDBusService::IsReady()
|
||||||
|
{
|
||||||
|
if (!IsEnabled() || !mConnection || !gThreadConnection || IsToggling()) {
|
||||||
|
NS_WARNING("Bluetooth service is not ready yet!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
BluetoothDBusService::StartInternal()
|
BluetoothDBusService::StartInternal()
|
||||||
{
|
{
|
||||||
@@ -1607,14 +1617,17 @@ private:
|
|||||||
nsresult
|
nsresult
|
||||||
BluetoothDBusService::GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable)
|
BluetoothDBusService::GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable)
|
||||||
{
|
{
|
||||||
if (!mConnection || !gThreadConnection) {
|
NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
|
||||||
NS_ERROR("Bluetooth service not started yet!");
|
|
||||||
return NS_ERROR_FAILURE;
|
if (!IsReady()) {
|
||||||
|
BluetoothValue v;
|
||||||
|
nsString errorStr;
|
||||||
|
errorStr.AssignLiteral("Bluetooth service is not ready yet!");
|
||||||
|
DispatchBluetoothReply(aRunnable, v, errorStr);
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
|
|
||||||
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
|
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
|
||||||
|
|
||||||
nsRefPtr<nsRunnable> func(new DefaultAdapterPropertiesRunnable(runnable));
|
nsRefPtr<nsRunnable> func(new DefaultAdapterPropertiesRunnable(runnable));
|
||||||
if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) {
|
if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) {
|
||||||
NS_WARNING("Cannot dispatch firmware loading task!");
|
NS_WARNING("Cannot dispatch firmware loading task!");
|
||||||
@@ -1655,8 +1668,11 @@ nsresult
|
|||||||
BluetoothDBusService::StopDiscoveryInternal(const nsAString& aAdapterPath,
|
BluetoothDBusService::StopDiscoveryInternal(const nsAString& aAdapterPath,
|
||||||
BluetoothReplyRunnable* aRunnable)
|
BluetoothReplyRunnable* aRunnable)
|
||||||
{
|
{
|
||||||
if (!mConnection) {
|
if (!IsReady()) {
|
||||||
NS_WARNING("Bluetooth service not started yet, no need to stop discovery.");
|
BluetoothValue v;
|
||||||
|
nsString errorStr;
|
||||||
|
errorStr.AssignLiteral("Bluetooth service is not ready yet!");
|
||||||
|
DispatchBluetoothReply(aRunnable, v, errorStr);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
return SendDiscoveryMessage(aAdapterPath, "StopDiscovery", aRunnable);
|
return SendDiscoveryMessage(aAdapterPath, "StopDiscovery", aRunnable);
|
||||||
@@ -1666,9 +1682,12 @@ nsresult
|
|||||||
BluetoothDBusService::StartDiscoveryInternal(const nsAString& aAdapterPath,
|
BluetoothDBusService::StartDiscoveryInternal(const nsAString& aAdapterPath,
|
||||||
BluetoothReplyRunnable* aRunnable)
|
BluetoothReplyRunnable* aRunnable)
|
||||||
{
|
{
|
||||||
if (!mConnection) {
|
if (!IsReady()) {
|
||||||
NS_WARNING("Bluetooth service not started yet, cannot start discovery!");
|
BluetoothValue v;
|
||||||
return NS_ERROR_FAILURE;
|
nsString errorStr;
|
||||||
|
errorStr.AssignLiteral("Bluetooth service is not ready yet!");
|
||||||
|
DispatchBluetoothReply(aRunnable, v, errorStr);
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
return SendDiscoveryMessage(aAdapterPath, "StartDiscovery", aRunnable);
|
return SendDiscoveryMessage(aAdapterPath, "StartDiscovery", aRunnable);
|
||||||
}
|
}
|
||||||
@@ -1877,12 +1896,15 @@ nsresult
|
|||||||
BluetoothDBusService::GetPairedDevicePropertiesInternal(const nsTArray<nsString>& aDeviceAddresses,
|
BluetoothDBusService::GetPairedDevicePropertiesInternal(const nsTArray<nsString>& aDeviceAddresses,
|
||||||
BluetoothReplyRunnable* aRunnable)
|
BluetoothReplyRunnable* aRunnable)
|
||||||
{
|
{
|
||||||
if (!mConnection || !gThreadConnection) {
|
if (!IsReady()) {
|
||||||
NS_ERROR("Bluetooth service not started yet!");
|
BluetoothValue v;
|
||||||
return NS_ERROR_FAILURE;
|
nsString errorStr;
|
||||||
|
errorStr.AssignLiteral("Bluetooth service is not ready yet!");
|
||||||
|
DispatchBluetoothReply(aRunnable, v, errorStr);
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
|
|
||||||
|
|
||||||
|
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
|
||||||
nsRefPtr<nsRunnable> func(new BluetoothPairedDevicePropertiesRunnable(runnable, aDeviceAddresses));
|
nsRefPtr<nsRunnable> func(new BluetoothPairedDevicePropertiesRunnable(runnable, aDeviceAddresses));
|
||||||
if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) {
|
if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) {
|
||||||
NS_WARNING("Cannot dispatch task!");
|
NS_WARNING("Cannot dispatch task!");
|
||||||
@@ -2501,9 +2523,12 @@ BluetoothDBusService::GetSocketViaService(const nsAString& aObjectPath,
|
|||||||
BluetoothReplyRunnable* aRunnable)
|
BluetoothReplyRunnable* aRunnable)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
|
NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
|
||||||
if (!mConnection || !gThreadConnection) {
|
if (!IsReady()) {
|
||||||
NS_ERROR("Bluetooth service not started yet!");
|
BluetoothValue v;
|
||||||
return NS_ERROR_FAILURE;
|
nsString errorStr;
|
||||||
|
errorStr.AssignLiteral("Bluetooth service is not ready yet!");
|
||||||
|
DispatchBluetoothReply(aRunnable, v, errorStr);
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
|
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
|
||||||
@@ -2530,6 +2555,7 @@ BluetoothDBusService::GetScoSocket(const nsAString& aAddress,
|
|||||||
mozilla::ipc::UnixSocketConsumer* aConsumer)
|
mozilla::ipc::UnixSocketConsumer* aConsumer)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
|
NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
|
||||||
|
|
||||||
if (!mConnection || !gThreadConnection) {
|
if (!mConnection || !gThreadConnection) {
|
||||||
NS_ERROR("Bluetooth service not started yet!");
|
NS_ERROR("Bluetooth service not started yet!");
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ class BluetoothDBusService : public BluetoothService
|
|||||||
, private mozilla::ipc::RawDBusConnection
|
, private mozilla::ipc::RawDBusConnection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
bool IsReady();
|
||||||
|
|
||||||
virtual nsresult StartInternal();
|
virtual nsresult StartInternal();
|
||||||
|
|
||||||
virtual nsresult StopInternal();
|
virtual nsresult StopInternal();
|
||||||
|
|||||||
Reference in New Issue
Block a user