Commit bb12724f authored by Miao-chen Chou's avatar Miao-chen Chou Committed by Commit Bot

arc/bluetooth: Fix the powered state synchronization between Chrome and Android

Since the observation of the local powered state change and the receiver of
enable/disable requests from Android is in arc_bluetooth_service are in
arc_setting_service and arc_bluetooth_bridge separately, the power state can
get out of sync or restore to the wrong state due to the lack of coordination
between these two pieces of information.

Issues:
- The powered state can get out-of-sync between Android and Chrome if the power
  state of adapter is repeatedly toggled from Chrome setting.
- If the powered state is ON before deep suspend/resume, the state will
  turn to OFF after resume and turn immediately back to ON on Chrome. However
  without waiting for the previous disable intent to finish, arc_setting_service
  sends the enable intent right after while Android Bluetooth statck is still
  processing the disable intent. Also there is a 3~4 seconds delay for bringing
  down to complete on Android Bluetooth stack. Besides, the enable intent
  is treated as a no op if the ongoing intent is disable. So after 3~4 seconds
  Android sends a disable request to Chrome while the powered state is ON on
  Chrome, so the powered state fall to the wrong one, disable, instead.

The changes includes:
 - moving the observation of Bluetooth adapter from arc_settings_service
   to arc_bluetooth_bridge,
 - changing the cycle of observing Bluetooth adapter from living along with ARC
   Bluetooth instance to living along with ARC Bluetooth bridge,
 - adding IntentHelperObserver to listen to the OnInstanceReady event and fire
   the initial powered state of Bluetooth to Android via intent,
 - adding two queues and a timer to track the powered state changes initiated by
   either Chrome or Android and to track the completion of the power
   changes initiated by Chrome,
 - and adding helper functions to enqueue/dequeue the power change intents and
   to compress the toggling of state to reduce the intents sent to Android.

BUG=b:62578573
TEST=(1) On Android start-up, verify that the powered state is synchronized
     between Android and Chrome.
     (2) After Repeatedly toggling Bluetooth powered state, the state
     remains synchronized between Android and Chrome.
     (3) Put device into deep suspend and resume, the state restores to
     the previous state.

Change-Id: I753839e2bb9228703492ebd23703cf8b67494998
Reviewed-on: https://chromium-review.googlesource.com/580314
Commit-Queue: Miao-chen Chou <mcchou@chromium.org>
Reviewed-by: default avatarLuis Hector Chavez <lhchavez@chromium.org>
Reviewed-by: default avatarRahul Chaturvedi <rkc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#491556}
parent 77be83bc
...@@ -34,8 +34,6 @@ ...@@ -34,8 +34,6 @@
#include "components/proxy_config/pref_proxy_config_tracker_impl.h" #include "components/proxy_config/pref_proxy_config_tracker_impl.h"
#include "components/proxy_config/proxy_config_dictionary.h" #include "components/proxy_config/proxy_config_dictionary.h"
#include "components/proxy_config/proxy_config_pref_names.h" #include "components/proxy_config/proxy_config_pref_names.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "net/proxy/proxy_config.h" #include "net/proxy/proxy_config.h"
using ::chromeos::CrosSettings; using ::chromeos::CrosSettings;
...@@ -99,7 +97,6 @@ class ArcSettingsServiceFactory ...@@ -99,7 +97,6 @@ class ArcSettingsServiceFactory
// about and sends the new values to Android to keep the state in sync. // about and sends the new values to Android to keep the state in sync.
class ArcSettingsServiceImpl class ArcSettingsServiceImpl
: public chromeos::system::TimezoneSettings::Observer, : public chromeos::system::TimezoneSettings::Observer,
public device::BluetoothAdapter::Observer,
public ArcSessionManager::Observer, public ArcSessionManager::Observer,
public chromeos::NetworkStateHandlerObserver { public chromeos::NetworkStateHandlerObserver {
public: public:
...@@ -114,10 +111,6 @@ class ArcSettingsServiceImpl ...@@ -114,10 +111,6 @@ class ArcSettingsServiceImpl
// TimezoneSettings::Observer: // TimezoneSettings::Observer:
void TimezoneChanged(const icu::TimeZone& timezone) override; void TimezoneChanged(const icu::TimeZone& timezone) override;
// BluetoothAdapter::Observer:
void AdapterPoweredChanged(device::BluetoothAdapter* adapter,
bool powered) override;
// ArcSessionManager::Observer: // ArcSessionManager::Observer:
void OnArcInitialStart() override; void OnArcInitialStart() override;
...@@ -164,9 +157,6 @@ class ArcSettingsServiceImpl ...@@ -164,9 +157,6 @@ class ArcSettingsServiceImpl
void SyncTimeZoneByGeolocation() const; void SyncTimeZoneByGeolocation() const;
void SyncUse24HourClock() const; void SyncUse24HourClock() const;
void OnBluetoothAdapterInitialized(
scoped_refptr<device::BluetoothAdapter> adapter);
// Registers to listen to a particular perf. // Registers to listen to a particular perf.
void AddPrefToObserve(const std::string& pref_name); void AddPrefToObserve(const std::string& pref_name);
...@@ -198,9 +188,6 @@ class ArcSettingsServiceImpl ...@@ -198,9 +188,6 @@ class ArcSettingsServiceImpl
std::unique_ptr<chromeos::CrosSettings::ObserverSubscription> std::unique_ptr<chromeos::CrosSettings::ObserverSubscription>
reporting_consent_subscription_; reporting_consent_subscription_;
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
// WeakPtrFactory to use for callback for getting the bluetooth adapter.
base::WeakPtrFactory<ArcSettingsServiceImpl> weak_factory_; base::WeakPtrFactory<ArcSettingsServiceImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ArcSettingsServiceImpl); DISALLOW_COPY_AND_ASSIGN(ArcSettingsServiceImpl);
...@@ -224,9 +211,6 @@ ArcSettingsServiceImpl::~ArcSettingsServiceImpl() { ...@@ -224,9 +211,6 @@ ArcSettingsServiceImpl::~ArcSettingsServiceImpl() {
ArcSessionManager* arc_session_manager = ArcSessionManager::Get(); ArcSessionManager* arc_session_manager = ArcSessionManager::Get();
if (arc_session_manager) if (arc_session_manager)
arc_session_manager->RemoveObserver(this); arc_session_manager->RemoveObserver(this);
if (bluetooth_adapter_)
bluetooth_adapter_->RemoveObserver(this);
} }
void ArcSettingsServiceImpl::OnPrefChanged(const std::string& pref_name) const { void ArcSettingsServiceImpl::OnPrefChanged(const std::string& pref_name) const {
...@@ -274,15 +258,6 @@ void ArcSettingsServiceImpl::TimezoneChanged(const icu::TimeZone& timezone) { ...@@ -274,15 +258,6 @@ void ArcSettingsServiceImpl::TimezoneChanged(const icu::TimeZone& timezone) {
SyncTimeZone(); SyncTimeZone();
} }
void ArcSettingsServiceImpl::AdapterPoweredChanged(
device::BluetoothAdapter* adapter,
bool powered) {
base::DictionaryValue extras;
extras.SetBoolean("enable", powered);
SendSettingsBroadcast("org.chromium.arc.intent_helper.SET_BLUETOOTH_STATE",
extras);
}
void ArcSettingsServiceImpl::OnArcInitialStart() { void ArcSettingsServiceImpl::OnArcInitialStart() {
SyncInitialSettings(); SyncInitialSettings();
} }
...@@ -328,12 +303,6 @@ void ArcSettingsServiceImpl::StartObservingSettingsChanges() { ...@@ -328,12 +303,6 @@ void ArcSettingsServiceImpl::StartObservingSettingsChanges() {
TimezoneSettings::GetInstance()->AddObserver(this); TimezoneSettings::GetInstance()->AddObserver(this);
if (device::BluetoothAdapterFactory::IsBluetoothSupported()) {
device::BluetoothAdapterFactory::GetAdapter(
base::Bind(&ArcSettingsServiceImpl::OnBluetoothAdapterInitialized,
weak_factory_.GetWeakPtr()));
}
chromeos::NetworkHandler::Get()->network_state_handler()->AddObserver( chromeos::NetworkHandler::Get()->network_state_handler()->AddObserver(
this, FROM_HERE); this, FROM_HERE);
} }
...@@ -569,15 +538,6 @@ void ArcSettingsServiceImpl::SyncUse24HourClock() const { ...@@ -569,15 +538,6 @@ void ArcSettingsServiceImpl::SyncUse24HourClock() const {
extras); extras);
} }
void ArcSettingsServiceImpl::OnBluetoothAdapterInitialized(
scoped_refptr<device::BluetoothAdapter> adapter) {
DCHECK(adapter);
bluetooth_adapter_ = adapter;
bluetooth_adapter_->AddObserver(this);
AdapterPoweredChanged(adapter.get(), adapter->IsPowered());
}
void ArcSettingsServiceImpl::AddPrefToObserve(const std::string& pref_name) { void ArcSettingsServiceImpl::AddPrefToObserve(const std::string& pref_name) {
registrar_.Add(pref_name, base::Bind(&ArcSettingsServiceImpl::OnPrefChanged, registrar_.Add(pref_name, base::Bind(&ArcSettingsServiceImpl::OnPrefChanged,
base::Unretained(this))); base::Unretained(this)));
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <utility> #include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/json/json_writer.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
...@@ -87,6 +88,22 @@ constexpr base::TimeDelta kDiscoveryTimeout = base::TimeDelta::FromSeconds(120); ...@@ -87,6 +88,22 @@ constexpr base::TimeDelta kDiscoveryTimeout = base::TimeDelta::FromSeconds(120);
// From https://www.bluetooth.com/specifications/assigned-numbers/baseband // From https://www.bluetooth.com/specifications/assigned-numbers/baseband
// The Class of Device for generic computer. // The Class of Device for generic computer.
constexpr uint32_t kBluetoothComputerClass = 0x100; constexpr uint32_t kBluetoothComputerClass = 0x100;
// Timeout for Android to complete a disabling op to adapter.
// In the case where an enabling op happens immediately after a disabling op,
// Android takes the following enabling op as a no-op and waits 3~4 seconds for
// the previous disabling op to finish, so the enabling op will never be
// fulfilled by Android, and the disabling op will later routed back to Chrome
// while Chrome's adapter is enabled. This results in the wrong power state
// which should be enabled. Since the signaling from Android to Chrome for
// Bluetooth is via Bluetooth HAL layer which run on the same process as
// Bluetooth Service in Java space, so the signaling to Chrome about the
// to-be-happen sleep cannot be done. This timeout tries to ensure the validity
// and the order of toggles on power state sent to Android.
// If Android takes more than 5 seconds to complete the intent initiated by
// Chrome, Chrome will take EnableAdapter/DisableAdapter calls as a request from
// Android to toggle the power state. The power state will be synced on both
// Chrome and Android, but as a result, Bluetooth will be off.
constexpr base::TimeDelta kPowerIntentTimeout = base::TimeDelta::FromSeconds(5);
using GattStatusCallback = using GattStatusCallback =
base::Callback<void(arc::mojom::BluetoothGattStatus)>; base::Callback<void(arc::mojom::BluetoothGattStatus)>;
...@@ -281,8 +298,12 @@ ArcBluetoothBridge* ArcBluetoothBridge::GetForBrowserContext( ...@@ -281,8 +298,12 @@ ArcBluetoothBridge* ArcBluetoothBridge::GetForBrowserContext(
ArcBluetoothBridge::ArcBluetoothBridge(content::BrowserContext* context, ArcBluetoothBridge::ArcBluetoothBridge(content::BrowserContext* context,
ArcBridgeService* bridge_service) ArcBridgeService* bridge_service)
: arc_bridge_service_(bridge_service), binding_(this), weak_factory_(this) { : arc_bridge_service_(bridge_service),
binding_(this),
intent_helper_observer_(this),
weak_factory_(this) {
arc_bridge_service_->bluetooth()->AddObserver(this); arc_bridge_service_->bluetooth()->AddObserver(this);
arc_bridge_service_->intent_helper()->AddObserver(&intent_helper_observer_);
if (BluetoothAdapterFactory::IsBluetoothSupported()) { if (BluetoothAdapterFactory::IsBluetoothSupported()) {
VLOG(1) << "Registering bluetooth adapter."; VLOG(1) << "Registering bluetooth adapter.";
...@@ -299,11 +320,14 @@ ArcBluetoothBridge::~ArcBluetoothBridge() { ...@@ -299,11 +320,14 @@ ArcBluetoothBridge::~ArcBluetoothBridge() {
if (bluetooth_adapter_) if (bluetooth_adapter_)
bluetooth_adapter_->RemoveObserver(this); bluetooth_adapter_->RemoveObserver(this);
arc_bridge_service_->intent_helper()->RemoveObserver(
&intent_helper_observer_);
arc_bridge_service_->bluetooth()->RemoveObserver(this); arc_bridge_service_->bluetooth()->RemoveObserver(this);
} }
void ArcBluetoothBridge::OnAdapterInitialized( void ArcBluetoothBridge::OnAdapterInitialized(
scoped_refptr<BluetoothAdapter> adapter) { scoped_refptr<BluetoothAdapter> adapter) {
DCHECK(adapter);
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// We can downcast here because we are always running on Chrome OS, and // We can downcast here because we are always running on Chrome OS, and
...@@ -311,13 +335,8 @@ void ArcBluetoothBridge::OnAdapterInitialized( ...@@ -311,13 +335,8 @@ void ArcBluetoothBridge::OnAdapterInitialized(
bluetooth_adapter_ = bluetooth_adapter_ =
static_cast<bluez::BluetoothAdapterBlueZ*>(adapter.get()); static_cast<bluez::BluetoothAdapterBlueZ*>(adapter.get());
// The ARC instance was ready before the Bluetooth adapter, hence we didn't if (!bluetooth_adapter_->HasObserver(this))
// register ourselves as an observer with it then. Since our adapter is
// ready, we should register it now.
if (!bluetooth_adapter_->HasObserver(this) &&
arc_bridge_service_->bluetooth()->has_instance()) {
bluetooth_adapter_->AddObserver(this); bluetooth_adapter_->AddObserver(this);
}
} }
void ArcBluetoothBridge::OnInstanceReady() { void ArcBluetoothBridge::OnInstanceReady() {
...@@ -329,16 +348,11 @@ void ArcBluetoothBridge::OnInstanceReady() { ...@@ -329,16 +348,11 @@ void ArcBluetoothBridge::OnInstanceReady() {
binding_.Bind(mojo::MakeRequest(&host_proxy)); binding_.Bind(mojo::MakeRequest(&host_proxy));
bluetooth_instance->Init(std::move(host_proxy)); bluetooth_instance->Init(std::move(host_proxy));
// The Bluetooth adapter was ready before the ARC instance, hence we didn't is_bluetooth_instance_up_ = true;
// register ourselves as an observer with it then. Since our instance is
// ready, we should register it now.
if (bluetooth_adapter_ && !bluetooth_adapter_->HasObserver(this))
bluetooth_adapter_->AddObserver(this);
} }
void ArcBluetoothBridge::OnInstanceClosed() { void ArcBluetoothBridge::OnInstanceClosed() {
if (bluetooth_adapter_) is_bluetooth_instance_up_ = false;
bluetooth_adapter_->RemoveObserver(this);
} }
void ArcBluetoothBridge::SendDevice(const BluetoothDevice* device) const { void ArcBluetoothBridge::SendDevice(const BluetoothDevice* device) const {
...@@ -382,13 +396,29 @@ void ArcBluetoothBridge::SendDevice(const BluetoothDevice* device) const { ...@@ -382,13 +396,29 @@ void ArcBluetoothBridge::SendDevice(const BluetoothDevice* device) const {
OnGattConnectStateChanged(std::move(addr), true); OnGattConnectStateChanged(std::move(addr), true);
} }
void ArcBluetoothBridge::AdapterPoweredChanged(BluetoothAdapter* adapter,
bool powered) {
AdapterPowerState power_change =
powered ? AdapterPowerState::TURN_ON : AdapterPowerState::TURN_OFF;
if (IsPowerChangeInitiatedByRemote(power_change))
DequeueRemotePowerChange(power_change);
else
EnqueueLocalPowerChange(power_change);
}
void ArcBluetoothBridge::DeviceAdded(BluetoothAdapter* adapter, void ArcBluetoothBridge::DeviceAdded(BluetoothAdapter* adapter,
BluetoothDevice* device) { BluetoothDevice* device) {
if (!IsInstanceUp())
return;
SendDevice(device); SendDevice(device);
} }
void ArcBluetoothBridge::DeviceChanged(BluetoothAdapter* adapter, void ArcBluetoothBridge::DeviceChanged(BluetoothAdapter* adapter,
BluetoothDevice* device) { BluetoothDevice* device) {
if (!IsInstanceUp())
return;
SendDevice(device); SendDevice(device);
if (!(device->GetType() & device::BLUETOOTH_TRANSPORT_LE)) if (!(device->GetType() & device::BLUETOOTH_TRANSPORT_LE))
...@@ -414,6 +444,9 @@ void ArcBluetoothBridge::DeviceChanged(BluetoothAdapter* adapter, ...@@ -414,6 +444,9 @@ void ArcBluetoothBridge::DeviceChanged(BluetoothAdapter* adapter,
void ArcBluetoothBridge::DeviceAddressChanged(BluetoothAdapter* adapter, void ArcBluetoothBridge::DeviceAddressChanged(BluetoothAdapter* adapter,
BluetoothDevice* device, BluetoothDevice* device,
const std::string& old_address) { const std::string& old_address) {
if (!IsInstanceUp())
return;
if (old_address == device->GetAddress()) if (old_address == device->GetAddress())
return; return;
...@@ -443,6 +476,9 @@ void ArcBluetoothBridge::DeviceAddressChanged(BluetoothAdapter* adapter, ...@@ -443,6 +476,9 @@ void ArcBluetoothBridge::DeviceAddressChanged(BluetoothAdapter* adapter,
void ArcBluetoothBridge::DevicePairedChanged(BluetoothAdapter* adapter, void ArcBluetoothBridge::DevicePairedChanged(BluetoothAdapter* adapter,
BluetoothDevice* device, BluetoothDevice* device,
bool new_paired_status) { bool new_paired_status) {
if (!IsInstanceUp())
return;
DCHECK(adapter); DCHECK(adapter);
DCHECK(device); DCHECK(device);
...@@ -463,6 +499,9 @@ void ArcBluetoothBridge::DevicePairedChanged(BluetoothAdapter* adapter, ...@@ -463,6 +499,9 @@ void ArcBluetoothBridge::DevicePairedChanged(BluetoothAdapter* adapter,
void ArcBluetoothBridge::DeviceRemoved(BluetoothAdapter* adapter, void ArcBluetoothBridge::DeviceRemoved(BluetoothAdapter* adapter,
BluetoothDevice* device) { BluetoothDevice* device) {
if (!IsInstanceUp())
return;
DCHECK(adapter); DCHECK(adapter);
DCHECK(device); DCHECK(device);
...@@ -482,6 +521,8 @@ void ArcBluetoothBridge::DeviceRemoved(BluetoothAdapter* adapter, ...@@ -482,6 +521,8 @@ void ArcBluetoothBridge::DeviceRemoved(BluetoothAdapter* adapter,
void ArcBluetoothBridge::GattServiceAdded(BluetoothAdapter* adapter, void ArcBluetoothBridge::GattServiceAdded(BluetoothAdapter* adapter,
BluetoothDevice* device, BluetoothDevice* device,
BluetoothRemoteGattService* service) { BluetoothRemoteGattService* service) {
if (!IsInstanceUp())
return;
// Placeholder for GATT client functionality // Placeholder for GATT client functionality
} }
...@@ -489,11 +530,16 @@ void ArcBluetoothBridge::GattServiceRemoved( ...@@ -489,11 +530,16 @@ void ArcBluetoothBridge::GattServiceRemoved(
BluetoothAdapter* adapter, BluetoothAdapter* adapter,
BluetoothDevice* device, BluetoothDevice* device,
BluetoothRemoteGattService* service) { BluetoothRemoteGattService* service) {
if (!IsInstanceUp())
return;
// Placeholder for GATT client functionality // Placeholder for GATT client functionality
} }
void ArcBluetoothBridge::GattServicesDiscovered(BluetoothAdapter* adapter, void ArcBluetoothBridge::GattServicesDiscovered(BluetoothAdapter* adapter,
BluetoothDevice* device) { BluetoothDevice* device) {
if (!IsInstanceUp())
return;
auto* btle_instance = ARC_GET_INSTANCE_FOR_METHOD( auto* btle_instance = ARC_GET_INSTANCE_FOR_METHOD(
arc_bridge_service_->bluetooth(), OnSearchComplete); arc_bridge_service_->bluetooth(), OnSearchComplete);
if (!btle_instance) if (!btle_instance)
...@@ -509,36 +555,48 @@ void ArcBluetoothBridge::GattServicesDiscovered(BluetoothAdapter* adapter, ...@@ -509,36 +555,48 @@ void ArcBluetoothBridge::GattServicesDiscovered(BluetoothAdapter* adapter,
void ArcBluetoothBridge::GattDiscoveryCompleteForService( void ArcBluetoothBridge::GattDiscoveryCompleteForService(
BluetoothAdapter* adapter, BluetoothAdapter* adapter,
BluetoothRemoteGattService* service) { BluetoothRemoteGattService* service) {
if (!IsInstanceUp())
return;
// Placeholder for GATT client functionality // Placeholder for GATT client functionality
} }
void ArcBluetoothBridge::GattServiceChanged( void ArcBluetoothBridge::GattServiceChanged(
BluetoothAdapter* adapter, BluetoothAdapter* adapter,
BluetoothRemoteGattService* service) { BluetoothRemoteGattService* service) {
if (!IsInstanceUp())
return;
// Placeholder for GATT client functionality // Placeholder for GATT client functionality
} }
void ArcBluetoothBridge::GattCharacteristicAdded( void ArcBluetoothBridge::GattCharacteristicAdded(
BluetoothAdapter* adapter, BluetoothAdapter* adapter,
BluetoothRemoteGattCharacteristic* characteristic) { BluetoothRemoteGattCharacteristic* characteristic) {
if (!IsInstanceUp())
return;
// Placeholder for GATT client functionality // Placeholder for GATT client functionality
} }
void ArcBluetoothBridge::GattCharacteristicRemoved( void ArcBluetoothBridge::GattCharacteristicRemoved(
BluetoothAdapter* adapter, BluetoothAdapter* adapter,
BluetoothRemoteGattCharacteristic* characteristic) { BluetoothRemoteGattCharacteristic* characteristic) {
if (!IsInstanceUp())
return;
// Placeholder for GATT client functionality // Placeholder for GATT client functionality
} }
void ArcBluetoothBridge::GattDescriptorAdded( void ArcBluetoothBridge::GattDescriptorAdded(
BluetoothAdapter* adapter, BluetoothAdapter* adapter,
BluetoothRemoteGattDescriptor* descriptor) { BluetoothRemoteGattDescriptor* descriptor) {
if (!IsInstanceUp())
return;
// Placeholder for GATT client functionality // Placeholder for GATT client functionality
} }
void ArcBluetoothBridge::GattDescriptorRemoved( void ArcBluetoothBridge::GattDescriptorRemoved(
BluetoothAdapter* adapter, BluetoothAdapter* adapter,
BluetoothRemoteGattDescriptor* descriptor) { BluetoothRemoteGattDescriptor* descriptor) {
if (!IsInstanceUp())
return;
// Placeholder for GATT client functionality // Placeholder for GATT client functionality
} }
...@@ -546,6 +604,9 @@ void ArcBluetoothBridge::GattCharacteristicValueChanged( ...@@ -546,6 +604,9 @@ void ArcBluetoothBridge::GattCharacteristicValueChanged(
BluetoothAdapter* adapter, BluetoothAdapter* adapter,
BluetoothRemoteGattCharacteristic* characteristic, BluetoothRemoteGattCharacteristic* characteristic,
const std::vector<uint8_t>& value) { const std::vector<uint8_t>& value) {
if (!IsInstanceUp())
return;
auto* btle_instance = ARC_GET_INSTANCE_FOR_METHOD( auto* btle_instance = ARC_GET_INSTANCE_FOR_METHOD(
arc_bridge_service_->bluetooth(), OnGattNotify); arc_bridge_service_->bluetooth(), OnGattNotify);
if (!btle_instance) if (!btle_instance)
...@@ -574,6 +635,8 @@ void ArcBluetoothBridge::GattDescriptorValueChanged( ...@@ -574,6 +635,8 @@ void ArcBluetoothBridge::GattDescriptorValueChanged(
BluetoothAdapter* adapter, BluetoothAdapter* adapter,
BluetoothRemoteGattDescriptor* descriptor, BluetoothRemoteGattDescriptor* descriptor,
const std::vector<uint8_t>& value) { const std::vector<uint8_t>& value) {
if (!IsInstanceUp())
return;
// Placeholder for GATT client functionality // Placeholder for GATT client functionality
} }
...@@ -676,13 +739,13 @@ void ArcBluetoothBridge::OnNotificationsStop( ...@@ -676,13 +739,13 @@ void ArcBluetoothBridge::OnNotificationsStop(
void ArcBluetoothBridge::EnableAdapter(const EnableAdapterCallback& callback) { void ArcBluetoothBridge::EnableAdapter(const EnableAdapterCallback& callback) {
DCHECK(bluetooth_adapter_); DCHECK(bluetooth_adapter_);
if (!bluetooth_adapter_->IsPowered()) { if (IsPowerChangeInitiatedByLocal(AdapterPowerState::TURN_ON)) {
bluetooth_adapter_->SetPowered( DequeueLocalPowerChange(AdapterPowerState::TURN_ON);
true, base::Bind(&ArcBluetoothBridge::OnPoweredOn, } else {
weak_factory_.GetWeakPtr(), callback), if (!bluetooth_adapter_->IsPowered()) {
base::Bind(&ArcBluetoothBridge::OnPoweredError, EnqueueRemotePowerChange(AdapterPowerState::TURN_ON, callback);
weak_factory_.GetWeakPtr(), callback)); return;
return; }
} }
OnPoweredOn(callback); OnPoweredOn(callback);
...@@ -691,11 +754,16 @@ void ArcBluetoothBridge::EnableAdapter(const EnableAdapterCallback& callback) { ...@@ -691,11 +754,16 @@ void ArcBluetoothBridge::EnableAdapter(const EnableAdapterCallback& callback) {
void ArcBluetoothBridge::DisableAdapter( void ArcBluetoothBridge::DisableAdapter(
const DisableAdapterCallback& callback) { const DisableAdapterCallback& callback) {
DCHECK(bluetooth_adapter_); DCHECK(bluetooth_adapter_);
bluetooth_adapter_->SetPowered( if (IsPowerChangeInitiatedByLocal(AdapterPowerState::TURN_OFF)) {
false, base::Bind(&ArcBluetoothBridge::OnPoweredOff, DequeueLocalPowerChange(AdapterPowerState::TURN_OFF);
weak_factory_.GetWeakPtr(), callback), } else {
base::Bind(&ArcBluetoothBridge::OnPoweredError, if (bluetooth_adapter_->IsPowered()) {
weak_factory_.GetWeakPtr(), callback)); EnqueueRemotePowerChange(AdapterPowerState::TURN_OFF, callback);
return;
}
}
OnPoweredOff(callback);
} }
void ArcBluetoothBridge::GetAdapterProperty(mojom::BluetoothPropertyType type) { void ArcBluetoothBridge::GetAdapterProperty(mojom::BluetoothPropertyType type) {
...@@ -1320,6 +1388,25 @@ BluetoothRemoteGattDescriptor* ArcBluetoothBridge::FindGattDescriptor( ...@@ -1320,6 +1388,25 @@ BluetoothRemoteGattDescriptor* ArcBluetoothBridge::FindGattDescriptor(
desc_id->uuid); desc_id->uuid);
} }
void ArcBluetoothBridge::SendBluetoothPoweredStateBroadcast(
AdapterPowerState powered) const {
auto* intent_instance = ARC_GET_INSTANCE_FOR_METHOD(
arc_bridge_service_->intent_helper(), SendBroadcast);
if (!intent_instance)
return;
base::DictionaryValue extras;
extras.SetBoolean("enable", powered == AdapterPowerState::TURN_ON);
std::string extras_json;
bool write_success = base::JSONWriter::Write(extras, &extras_json);
DCHECK(write_success);
intent_instance->SendBroadcast(
"org.chromium.arc.intent_helper.SET_BLUETOOTH_STATE",
"org.chromium.arc.intent_helper",
"org.chromium.arc.intent_helper.SettingsReceiver", extras_json);
}
void ArcBluetoothBridge::ReadGattCharacteristic( void ArcBluetoothBridge::ReadGattCharacteristic(
mojom::BluetoothAddressPtr remote_addr, mojom::BluetoothAddressPtr remote_addr,
mojom::BluetoothGattServiceIDPtr service_id, mojom::BluetoothGattServiceIDPtr service_id,
...@@ -1878,6 +1965,97 @@ void ArcBluetoothBridge::OnForgetError(mojom::BluetoothAddressPtr addr) const { ...@@ -1878,6 +1965,97 @@ void ArcBluetoothBridge::OnForgetError(mojom::BluetoothAddressPtr addr) const {
std::move(addr), bond_state); std::move(addr), bond_state);
} }
ArcBluetoothBridge::IntentHelperObserver::IntentHelperObserver(
ArcBluetoothBridge* bluetooth_bridge)
: bluetooth_bridge_(bluetooth_bridge) {}
ArcBluetoothBridge::IntentHelperObserver::~IntentHelperObserver() = default;
void ArcBluetoothBridge::IntentHelperObserver::OnInstanceReady() {
bluetooth_bridge_->SendInitialPowerChange();
}
bool ArcBluetoothBridge::IsPowerChangeInitiatedByRemote(
ArcBluetoothBridge::AdapterPowerState powered) const {
return !remote_power_changes_.empty() &&
remote_power_changes_.front() == powered;
}
bool ArcBluetoothBridge::IsPowerChangeInitiatedByLocal(
ArcBluetoothBridge::AdapterPowerState powered) const {
return !local_power_changes_.empty() &&
local_power_changes_.front() == powered;
}
void ArcBluetoothBridge::SendInitialPowerChange() {
if (!bluetooth_adapter_ || !bluetooth_adapter_->IsPowered()) {
// The default power state of Bluetooth on Android is off, so there is no
// need to send an intent to turn off Bluetooth if the initial power state
// is off.
return;
}
EnqueueLocalPowerChange(AdapterPowerState::TURN_ON);
}
void ArcBluetoothBridge::EnqueueLocalPowerChange(
ArcBluetoothBridge::AdapterPowerState powered) {
local_power_changes_.push(powered);
if (power_intent_timer_.IsRunning())
return;
SendBluetoothPoweredStateBroadcast(local_power_changes_.front());
power_intent_timer_.Start(
FROM_HERE, kPowerIntentTimeout,
base::Bind(&ArcBluetoothBridge::DequeueLocalPowerChange,
weak_factory_.GetWeakPtr(), powered));
}
void ArcBluetoothBridge::DequeueLocalPowerChange(
ArcBluetoothBridge::AdapterPowerState powered) {
power_intent_timer_.Stop();
if (!IsPowerChangeInitiatedByLocal(powered))
return;
AdapterPowerState current_change = local_power_changes_.front();
AdapterPowerState last_change = local_power_changes_.back();
// Compress the queue for power intent to reduce the amount of intents being
// sent to Android so that the powered state will be synced between Android
// and Chrome even if the state is toggled repeatedly on Chrome.
std::queue<AdapterPowerState> empty_queue;
std::swap(local_power_changes_, empty_queue);
if (last_change == current_change)
return;
local_power_changes_.push(last_change);
SendBluetoothPoweredStateBroadcast(last_change);
power_intent_timer_.Start(
FROM_HERE, kPowerIntentTimeout,
base::Bind(&ArcBluetoothBridge::DequeueLocalPowerChange,
weak_factory_.GetWeakPtr(), last_change));
}
void ArcBluetoothBridge::EnqueueRemotePowerChange(
ArcBluetoothBridge::AdapterPowerState powered,
const EnableAdapterCallback& callback) {
remote_power_changes_.push(powered);
bluetooth_adapter_->SetPowered(
powered == AdapterPowerState::TURN_ON,
base::Bind(&ArcBluetoothBridge::OnPoweredOff, weak_factory_.GetWeakPtr(),
callback),
base::Bind(&ArcBluetoothBridge::OnPoweredError,
weak_factory_.GetWeakPtr(), callback));
}
void ArcBluetoothBridge::DequeueRemotePowerChange(
ArcBluetoothBridge::AdapterPowerState powered) {
remote_power_changes_.pop();
}
std::vector<mojom::BluetoothPropertyPtr> std::vector<mojom::BluetoothPropertyPtr>
ArcBluetoothBridge::GetDeviceProperties(mojom::BluetoothPropertyType type, ArcBluetoothBridge::GetDeviceProperties(mojom::BluetoothPropertyType type,
const BluetoothDevice* device) const { const BluetoothDevice* device) const {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <queue>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
...@@ -17,6 +18,7 @@ ...@@ -17,6 +18,7 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "components/arc/common/bluetooth.mojom.h" #include "components/arc/common/bluetooth.mojom.h"
#include "components/arc/common/intent_helper.mojom.h"
#include "components/arc/instance_holder.h" #include "components/arc/instance_holder.h"
#include "components/keyed_service/core/keyed_service.h" #include "components/keyed_service/core/keyed_service.h"
#include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_adapter.h"
...@@ -62,7 +64,10 @@ class ArcBluetoothBridge ...@@ -62,7 +64,10 @@ class ArcBluetoothBridge
void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter); void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter);
// Overridden from device::BluetoothAdadpter::Observer // Overridden from device::BluetoothAdapter::Observer
void AdapterPoweredChanged(device::BluetoothAdapter* adapter,
bool powered) override;
void DeviceAdded(device::BluetoothAdapter* adapter, void DeviceAdded(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) override; device::BluetoothDevice* device) override;
...@@ -341,6 +346,49 @@ class ArcBluetoothBridge ...@@ -341,6 +346,49 @@ class ArcBluetoothBridge
std::unique_ptr<device::BluetoothGattNotifySession> notify_session); std::unique_ptr<device::BluetoothGattNotifySession> notify_session);
private: private:
// IntentHelperObserver listens to the OnInstanceReady call on the intent
// helper which indicated the IntentHelperService has been brought up and the
// initial powered state of Bluetooth adapter can be sent to Android.
class IntentHelperObserver
: public InstanceHolder<mojom::IntentHelperInstance>::Observer {
public:
explicit IntentHelperObserver(ArcBluetoothBridge* bluetooth_bridge);
~IntentHelperObserver() override;
private:
// InstanceHolder<mojom::IntentHelperInstance>::Observer overrides
void OnInstanceReady() override;
// ArcBluetoothBridge owns IntentHelperObserver, and ArcBluetoothBridge will
// always outlive it.
ArcBluetoothBridge* const bluetooth_bridge_;
DISALLOW_COPY_AND_ASSIGN(IntentHelperObserver);
};
// Power state change on Bluetooth adapter.
enum class AdapterPowerState { TURN_OFF, TURN_ON };
bool IsInstanceUp() const { return is_bluetooth_instance_up_; }
// Indicates if a power change is initiated by Chrome / Android.
bool IsPowerChangeInitiatedByRemote(
ArcBluetoothBridge::AdapterPowerState powered) const;
bool IsPowerChangeInitiatedByLocal(
ArcBluetoothBridge::AdapterPowerState powered) const;
// Called by IntentHelperObserver to send the initial power state.
void SendInitialPowerChange();
// Manages the powered change intents sent to Android.
void EnqueueLocalPowerChange(AdapterPowerState powered);
void DequeueLocalPowerChange(AdapterPowerState powered);
// Manages the powered change requests received from Android.
void EnqueueRemotePowerChange(AdapterPowerState powered,
const EnableAdapterCallback& callback);
void DequeueRemotePowerChange(AdapterPowerState powered);
std::vector<mojom::BluetoothPropertyPtr> GetDeviceProperties( std::vector<mojom::BluetoothPropertyPtr> GetDeviceProperties(
mojom::BluetoothPropertyType type, mojom::BluetoothPropertyType type,
const device::BluetoothDevice* device) const; const device::BluetoothDevice* device) const;
...@@ -362,6 +410,9 @@ class ArcBluetoothBridge ...@@ -362,6 +410,9 @@ class ArcBluetoothBridge
mojom::BluetoothGattIDPtr char_id, mojom::BluetoothGattIDPtr char_id,
mojom::BluetoothGattIDPtr desc_id) const; mojom::BluetoothGattIDPtr desc_id) const;
// Send the power status change to Android via an intent.
void SendBluetoothPoweredStateBroadcast(AdapterPowerState powered) const;
// Propagates the list of paired device to Android. // Propagates the list of paired device to Android.
void SendCachedPairedDevices() const; void SendCachedPairedDevices() const;
...@@ -471,6 +522,19 @@ class ArcBluetoothBridge ...@@ -471,6 +522,19 @@ class ArcBluetoothBridge
// Timer to turn adapter discoverable off. // Timer to turn adapter discoverable off.
base::OneShotTimer discoverable_off_timer_; base::OneShotTimer discoverable_off_timer_;
// This indicates whether the remote Bluetooth ARC instance is ready to
// receive events.
bool is_bluetooth_instance_up_;
// Observer to listen the start-up of Intent Helper.
IntentHelperObserver intent_helper_observer_;
// Queue to track the powered state changes initiated by Android.
std::queue<AdapterPowerState> remote_power_changes_;
// Queue to track the powered state changes initiated by Chrome.
std::queue<AdapterPowerState> local_power_changes_;
// Timer to track the completion of power-changed intent sent to Android.
base::OneShotTimer power_intent_timer_;
// Holds advertising data registered by the instance. // Holds advertising data registered by the instance.
// //
// When a handle is reserved, an entry is placed into the advertisements_ // When a handle is reserved, an entry is placed into the advertisements_
......
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