chromium/chromeos/ash/services/bluetooth_config/in_process_instance.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/ash/services/bluetooth_config/in_process_instance.h"

#include <optional>

#include "ash/constants/ash_features.h"
#include "base/check.h"
#include "base/functional/bind.h"
#include "chromeos/ash/services/bluetooth_config/cros_bluetooth_config.h"
#include "chromeos/ash/services/bluetooth_config/fast_pair_delegate.h"
#include "chromeos/ash/services/bluetooth_config/initializer_impl.h"
#include "components/device_event_log/device_event_log.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"

namespace ash::bluetooth_config {

namespace {

CrosBluetoothConfig* g_instance = nullptr;

// Flag indicating that Shutdown() has been called and g_instance should not be
// initialized.
bool g_is_shut_down = false;

// PrefServices that should be used by CrosBluetoothConfig once it has finished
// initializing.
PrefService* g_pending_logged_in_profile_prefs = nullptr;
PrefService* g_pending_device_prefs = nullptr;

FastPairDelegate* g_fast_pair_delegate = nullptr;

void OnBluetoothAdapter(
    std::optional<mojo::PendingReceiver<mojom::CrosBluetoothConfig>>
        pending_receiver,
    scoped_refptr<device::BluetoothAdapter> bluetooth_adapter) {
  if (g_is_shut_down)
    return;

  if (!g_instance) {
    BLUETOOTH_LOG(EVENT) << "Initializing CrosBluetoothConfig";
    InitializerImpl initializer;
    g_instance = new CrosBluetoothConfig(
        initializer, std::move(bluetooth_adapter), g_fast_pair_delegate);
    g_instance->SetPrefs(g_pending_logged_in_profile_prefs,
                         g_pending_device_prefs);
    g_pending_logged_in_profile_prefs = nullptr;
    g_pending_device_prefs = nullptr;
  }
  if (pending_receiver)
    g_instance->BindPendingReceiver(std::move(*pending_receiver));
}

}  // namespace

void Initialize(FastPairDelegate* delegate) {
  BLUETOOTH_LOG(EVENT) << "Beginning CrosBluetoothConfig initialization";
  CHECK(!g_instance);
  DCHECK_EQ(features::IsFastPairEnabled(), static_cast<bool>(delegate));

  g_fast_pair_delegate = delegate;

  device::BluetoothAdapterFactory::Get()->GetAdapter(
      base::BindOnce(&OnBluetoothAdapter, /*pending_receiver=*/std::nullopt));
}

void Shutdown() {
  BLUETOOTH_LOG(EVENT) << "Shutting down CrosBluetoothConfig";
  if (g_instance) {
    delete g_instance;
    g_instance = nullptr;
  } else {
    g_is_shut_down = true;
  }
  g_pending_logged_in_profile_prefs = nullptr;
  g_pending_device_prefs = nullptr;
}

void SetPrefs(PrefService* logged_in_profile_prefs, PrefService* device_prefs) {
  if (!g_instance) {
    // |g_instance| may not be initialized yet if we're still getting the
    // Bluetooth adapter. Save the prefs to be used once the instance has
    // initialized.
    g_pending_logged_in_profile_prefs = logged_in_profile_prefs;
    g_pending_device_prefs = device_prefs;
    return;
  }
  g_instance->SetPrefs(logged_in_profile_prefs, device_prefs);
}

void BindToInProcessInstance(
    mojo::PendingReceiver<mojom::CrosBluetoothConfig> pending_receiver) {
  BLUETOOTH_LOG(DEBUG) << "Binding to CrosBluetoothConfig";
  device::BluetoothAdapterFactory::Get()->GetAdapter(
      base::BindOnce(&OnBluetoothAdapter, std::move(pending_receiver)));
}

void OverrideInProcessInstanceForTesting(Initializer* initializer,
                                         FastPairDelegate* fast_pair_delegate) {
  if (g_instance) {
    delete g_instance;
    g_instance = nullptr;
  }

  if (!initializer)
    return;

  // Null BluetoothAdapter is used since |initializer| is expected to fake
  // Bluetooth functionality in tests.
  g_instance = new CrosBluetoothConfig(*initializer,
                                       /*bluetooth_adapter=*/nullptr,
                                       fast_pair_delegate);
}

}  // namespace ash::bluetooth_config