// Copyright (c) 2012 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 "chromeos/dbus/dbus_thread_manager.h"
#include "base/command_line.h"
#include "base/sys_info.h"
#include "base/threading/thread.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/bluetooth_adapter_client.h"
#include "chromeos/dbus/bluetooth_agent_manager_client.h"
#include "chromeos/dbus/bluetooth_device_client.h"
#include "chromeos/dbus/bluetooth_gatt_characteristic_client.h"
#include "chromeos/dbus/bluetooth_gatt_descriptor_client.h"
#include "chromeos/dbus/bluetooth_gatt_manager_client.h"
#include "chromeos/dbus/bluetooth_gatt_service_client.h"
#include "chromeos/dbus/bluetooth_input_client.h"
#include "chromeos/dbus/bluetooth_profile_manager_client.h"
#include "chromeos/dbus/cras_audio_client.h"
#include "chromeos/dbus/cros_disks_client.h"
#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/dbus_client.h"
#include "chromeos/dbus/dbus_client_bundle.h"
#include "chromeos/dbus/debug_daemon_client.h"
#include "chromeos/dbus/easy_unlock_client.h"
#include "chromeos/dbus/gsm_sms_client.h"
#include "chromeos/dbus/image_burner_client.h"
#include "chromeos/dbus/introspectable_client.h"
#include "chromeos/dbus/lorgnette_manager_client.h"
#include "chromeos/dbus/modem_messaging_client.h"
#include "chromeos/dbus/nfc_adapter_client.h"
#include "chromeos/dbus/nfc_device_client.h"
#include "chromeos/dbus/nfc_manager_client.h"
#include "chromeos/dbus/nfc_record_client.h"
#include "chromeos/dbus/nfc_tag_client.h"
#include "chromeos/dbus/permission_broker_client.h"
#include "chromeos/dbus/power_manager_client.h"
#include "chromeos/dbus/power_policy_controller.h"
#include "chromeos/dbus/session_manager_client.h"
#include "chromeos/dbus/shill_device_client.h"
#include "chromeos/dbus/shill_ipconfig_client.h"
#include "chromeos/dbus/shill_manager_client.h"
#include "chromeos/dbus/shill_profile_client.h"
#include "chromeos/dbus/shill_service_client.h"
#include "chromeos/dbus/sms_client.h"
#include "chromeos/dbus/system_clock_client.h"
#include "chromeos/dbus/update_engine_client.h"
#include "dbus/bus.h"
#include "dbus/dbus_statistics.h"
namespace chromeos {
static DBusThreadManager* g_dbus_thread_manager = NULL;
static bool g_using_dbus_thread_manager_for_testing = false;
DBusThreadManager::DBusThreadManager(scoped_ptr<DBusClientBundle> client_bundle)
: client_bundle_(client_bundle.Pass()) {
dbus::statistics::Initialize();
if (client_bundle_->IsUsingAnyRealClient()) {
// At least one real DBusClient is used.
// Create the D-Bus thread.
base::Thread::Options thread_options;
thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
dbus_thread_.reset(new base::Thread("D-Bus thread"));
dbus_thread_->StartWithOptions(thread_options);
// Create the connection to the system bus.
dbus::Bus::Options system_bus_options;
system_bus_options.bus_type = dbus::Bus::SYSTEM;
system_bus_options.connection_type = dbus::Bus::PRIVATE;
system_bus_options.dbus_task_runner = dbus_thread_->message_loop_proxy();
system_bus_ = new dbus::Bus(system_bus_options);
}
// TODO(crbug.com/345586): Move PowerPolicyController out of
// DBusThreadManager.
power_policy_controller_.reset(new PowerPolicyController);
}
DBusThreadManager::~DBusThreadManager() {
// PowerPolicyController's destructor depends on PowerManagerClient.
power_policy_controller_.reset();
// Delete all D-Bus clients before shutting down the system bus.
client_bundle_.reset();
// Shut down the bus. During the browser shutdown, it's ok to shut down
// the bus synchronously.
if (system_bus_.get())
system_bus_->ShutdownOnDBusThreadAndBlock();
// Stop the D-Bus thread.
if (dbus_thread_)
dbus_thread_->Stop();
dbus::statistics::Shutdown();
if (!g_dbus_thread_manager)
return; // Called form Shutdown() or local test instance.
// There should never be both a global instance and a local instance.
CHECK(this == g_dbus_thread_manager);
if (g_using_dbus_thread_manager_for_testing) {
g_dbus_thread_manager = NULL;
g_using_dbus_thread_manager_for_testing = false;
VLOG(1) << "DBusThreadManager destroyed";
} else {
LOG(FATAL) << "~DBusThreadManager() called outside of Shutdown()";
}
}
dbus::Bus* DBusThreadManager::GetSystemBus() {
return system_bus_.get();
}
BluetoothAdapterClient* DBusThreadManager::GetBluetoothAdapterClient() {
return client_bundle_->bluetooth_adapter_client();
}
BluetoothAgentManagerClient*
DBusThreadManager::GetBluetoothAgentManagerClient() {
return client_bundle_->bluetooth_agent_manager_client();
}
BluetoothDeviceClient* DBusThreadManager::GetBluetoothDeviceClient() {
return client_bundle_->bluetooth_device_client();
}
BluetoothGattCharacteristicClient*
DBusThreadManager::GetBluetoothGattCharacteristicClient() {
return client_bundle_->bluetooth_gatt_characteristic_client();
}
BluetoothGattDescriptorClient*
DBusThreadManager::GetBluetoothGattDescriptorClient() {
return client_bundle_->bluetooth_gatt_descriptor_client();
}
BluetoothGattManagerClient*
DBusThreadManager::GetBluetoothGattManagerClient() {
return client_bundle_->bluetooth_gatt_manager_client();
}
BluetoothGattServiceClient*
DBusThreadManager::GetBluetoothGattServiceClient() {
return client_bundle_->bluetooth_gatt_service_client();
}
BluetoothInputClient* DBusThreadManager::GetBluetoothInputClient() {
return client_bundle_->bluetooth_input_client();
}
BluetoothProfileManagerClient*
DBusThreadManager::GetBluetoothProfileManagerClient() {
return client_bundle_->bluetooth_profile_manager_client();
}
CrasAudioClient* DBusThreadManager::GetCrasAudioClient() {
return client_bundle_->cras_audio_client();
}
CrosDisksClient* DBusThreadManager::GetCrosDisksClient() {
return client_bundle_->cros_disks_client();
}
CryptohomeClient* DBusThreadManager::GetCryptohomeClient() {
return client_bundle_->cryptohome_client();
}
DebugDaemonClient* DBusThreadManager::GetDebugDaemonClient() {
return client_bundle_->debug_daemon_client();
}
EasyUnlockClient* DBusThreadManager::GetEasyUnlockClient() {
return client_bundle_->easy_unlock_client();
}
LorgnetteManagerClient*
DBusThreadManager::GetLorgnetteManagerClient() {
return client_bundle_->lorgnette_manager_client();
}
ShillDeviceClient*
DBusThreadManager::GetShillDeviceClient() {
return client_bundle_->shill_device_client();
}
ShillIPConfigClient*
DBusThreadManager::GetShillIPConfigClient() {
return client_bundle_->shill_ipconfig_client();
}
ShillManagerClient*
DBusThreadManager::GetShillManagerClient() {
return client_bundle_->shill_manager_client();
}
ShillServiceClient*
DBusThreadManager::GetShillServiceClient() {
return client_bundle_->shill_service_client();
}
ShillProfileClient*
DBusThreadManager::GetShillProfileClient() {
return client_bundle_->shill_profile_client();
}
GsmSMSClient* DBusThreadManager::GetGsmSMSClient() {
return client_bundle_->gsm_sms_client();
}
ImageBurnerClient* DBusThreadManager::GetImageBurnerClient() {
return client_bundle_->image_burner_client();
}
IntrospectableClient* DBusThreadManager::GetIntrospectableClient() {
return client_bundle_->introspectable_client();
}
ModemMessagingClient* DBusThreadManager::GetModemMessagingClient() {
return client_bundle_->modem_messaging_client();
}
NfcAdapterClient* DBusThreadManager::GetNfcAdapterClient() {
return client_bundle_->nfc_adapter_client();
}
NfcDeviceClient* DBusThreadManager::GetNfcDeviceClient() {
return client_bundle_->nfc_device_client();
}
NfcManagerClient* DBusThreadManager::GetNfcManagerClient() {
return client_bundle_->nfc_manager_client();
}
NfcRecordClient* DBusThreadManager::GetNfcRecordClient() {
return client_bundle_->nfc_record_client();
}
NfcTagClient* DBusThreadManager::GetNfcTagClient() {
return client_bundle_->nfc_tag_client();
}
PermissionBrokerClient* DBusThreadManager::GetPermissionBrokerClient() {
return client_bundle_->permission_broker_client();
}
PowerManagerClient* DBusThreadManager::GetPowerManagerClient() {
return client_bundle_->power_manager_client();
}
SessionManagerClient* DBusThreadManager::GetSessionManagerClient() {
return client_bundle_->session_manager_client();
}
SMSClient* DBusThreadManager::GetSMSClient() {
return client_bundle_->sms_client();
}
SystemClockClient* DBusThreadManager::GetSystemClockClient() {
return client_bundle_->system_clock_client();
}
UpdateEngineClient* DBusThreadManager::GetUpdateEngineClient() {
return client_bundle_->update_engine_client();
}
PowerPolicyController* DBusThreadManager::GetPowerPolicyController() {
return power_policy_controller_.get();
}
void DBusThreadManager::InitializeClients() {
GetBluetoothAdapterClient()->Init(GetSystemBus());
GetBluetoothAgentManagerClient()->Init(GetSystemBus());
GetBluetoothDeviceClient()->Init(GetSystemBus());
GetBluetoothGattCharacteristicClient()->Init(GetSystemBus());
GetBluetoothGattDescriptorClient()->Init(GetSystemBus());
GetBluetoothGattManagerClient()->Init(GetSystemBus());
GetBluetoothGattServiceClient()->Init(GetSystemBus());
GetBluetoothInputClient()->Init(GetSystemBus());
GetBluetoothProfileManagerClient()->Init(GetSystemBus());
GetCrasAudioClient()->Init(GetSystemBus());
GetCrosDisksClient()->Init(GetSystemBus());
GetCryptohomeClient()->Init(GetSystemBus());
GetDebugDaemonClient()->Init(GetSystemBus());
GetEasyUnlockClient()->Init(GetSystemBus());
GetGsmSMSClient()->Init(GetSystemBus());
GetImageBurnerClient()->Init(GetSystemBus());
GetIntrospectableClient()->Init(GetSystemBus());
GetLorgnetteManagerClient()->Init(GetSystemBus());
GetModemMessagingClient()->Init(GetSystemBus());
GetPermissionBrokerClient()->Init(GetSystemBus());
GetPowerManagerClient()->Init(GetSystemBus());
GetSessionManagerClient()->Init(GetSystemBus());
GetShillDeviceClient()->Init(GetSystemBus());
GetShillIPConfigClient()->Init(GetSystemBus());
GetShillManagerClient()->Init(GetSystemBus());
GetShillServiceClient()->Init(GetSystemBus());
GetShillProfileClient()->Init(GetSystemBus());
GetSMSClient()->Init(GetSystemBus());
GetSystemClockClient()->Init(GetSystemBus());
GetUpdateEngineClient()->Init(GetSystemBus());
// Initialize the NFC clients in the correct order. The order of
// initialization matters due to dependencies that exist between the
// client objects.
GetNfcManagerClient()->Init(GetSystemBus());
GetNfcAdapterClient()->Init(GetSystemBus());
GetNfcDeviceClient()->Init(GetSystemBus());
GetNfcTagClient()->Init(GetSystemBus());
GetNfcRecordClient()->Init(GetSystemBus());
// PowerPolicyController is dependent on PowerManagerClient, so
// initialize it after the main list of clients.
if (GetPowerPolicyController())
GetPowerPolicyController()->Init(this);
// This must be called after the list of clients so they've each had a
// chance to register with their object g_dbus_thread_managers.
if (GetSystemBus())
GetSystemBus()->GetManagedObjects();
client_bundle_->SetupDefaultEnvironment();
}
bool DBusThreadManager::IsUsingStub(DBusClientBundle::DBusClientType client) {
return client_bundle_->IsUsingStub(client);
}
// static
void DBusThreadManager::Initialize() {
// If we initialize DBusThreadManager twice we may also be shutting it down
// early; do not allow that.
if (g_using_dbus_thread_manager_for_testing)
return;
CHECK(!g_dbus_thread_manager);
bool use_dbus_stub = !base::SysInfo::IsRunningOnChromeOS() ||
CommandLine::ForCurrentProcess()->HasSwitch(
chromeos::switches::kDbusStub);
bool force_unstub_clients = CommandLine::ForCurrentProcess()->HasSwitch(
chromeos::switches::kDbusUnstubClients);
// Determine whether we use stub or real client implementations.
if (force_unstub_clients) {
InitializeWithPartialStub(
CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
chromeos::switches::kDbusUnstubClients));
} else if (use_dbus_stub) {
InitializeWithStubs();
} else {
InitializeWithRealClients();
}
}
// static
scoped_ptr<DBusThreadManagerSetter> DBusThreadManager::GetSetterForTesting() {
if (!g_using_dbus_thread_manager_for_testing) {
g_using_dbus_thread_manager_for_testing = true;
InitializeWithStubs();
}
return make_scoped_ptr(new DBusThreadManagerSetter());
}
// static
void DBusThreadManager::CreateGlobalInstance(
DBusClientBundle::DBusClientTypeMask unstub_client_mask) {
CHECK(!g_dbus_thread_manager);
g_dbus_thread_manager = new DBusThreadManager(
make_scoped_ptr(new DBusClientBundle(unstub_client_mask)));
g_dbus_thread_manager->InitializeClients();
}
// static
void DBusThreadManager::InitializeWithRealClients() {
CreateGlobalInstance(~static_cast<DBusClientBundle::DBusClientTypeMask>(0));
VLOG(1) << "DBusThreadManager initialized for Chrome OS";
}
// static
void DBusThreadManager::InitializeWithStubs() {
CreateGlobalInstance(0 /* unstub_client_mask */);
VLOG(1) << "DBusThreadManager created for testing";
}
// static
void DBusThreadManager::InitializeWithPartialStub(
const std::string& unstub_clients) {
DBusClientBundle::DBusClientTypeMask unstub_client_mask =
DBusClientBundle::ParseUnstubList(unstub_clients);
// We should have something parsed correctly here.
LOG_IF(FATAL, unstub_client_mask == 0)
<< "Switch values for --" << chromeos::switches::kDbusUnstubClients
<< " cannot be parsed: " << unstub_clients;
VLOG(1) << "DBusThreadManager initialized for mixed runtime environment";
CreateGlobalInstance(unstub_client_mask);
}
// static
bool DBusThreadManager::IsInitialized() {
return g_dbus_thread_manager != NULL;
}
// static
void DBusThreadManager::Shutdown() {
// Ensure that we only shutdown DBusThreadManager once.
CHECK(g_dbus_thread_manager);
DBusThreadManager* dbus_thread_manager = g_dbus_thread_manager;
g_dbus_thread_manager = NULL;
g_using_dbus_thread_manager_for_testing = false;
delete dbus_thread_manager;
VLOG(1) << "DBusThreadManager Shutdown completed";
}
// static
DBusThreadManager* DBusThreadManager::Get() {
CHECK(g_dbus_thread_manager)
<< "DBusThreadManager::Get() called before Initialize()";
return g_dbus_thread_manager;
}
DBusThreadManagerSetter::DBusThreadManagerSetter() {
}
DBusThreadManagerSetter::~DBusThreadManagerSetter() {
}
void DBusThreadManagerSetter::SetBluetoothAdapterClient(
scoped_ptr<BluetoothAdapterClient> client) {
DBusThreadManager::Get()->client_bundle_->bluetooth_adapter_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetBluetoothAgentManagerClient(
scoped_ptr<BluetoothAgentManagerClient> client) {
DBusThreadManager::Get()->client_bundle_->bluetooth_agent_manager_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetBluetoothDeviceClient(
scoped_ptr<BluetoothDeviceClient> client) {
DBusThreadManager::Get()->client_bundle_->bluetooth_device_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetBluetoothGattCharacteristicClient(
scoped_ptr<BluetoothGattCharacteristicClient> client) {
DBusThreadManager::Get()->client_bundle_->
bluetooth_gatt_characteristic_client_ = client.Pass();
}
void DBusThreadManagerSetter::SetBluetoothGattDescriptorClient(
scoped_ptr<BluetoothGattDescriptorClient> client) {
DBusThreadManager::Get()->client_bundle_->bluetooth_gatt_descriptor_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetBluetoothGattManagerClient(
scoped_ptr<BluetoothGattManagerClient> client) {
DBusThreadManager::Get()->client_bundle_->bluetooth_gatt_manager_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetBluetoothGattServiceClient(
scoped_ptr<BluetoothGattServiceClient> client) {
DBusThreadManager::Get()->client_bundle_->bluetooth_gatt_service_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetBluetoothInputClient(
scoped_ptr<BluetoothInputClient> client) {
DBusThreadManager::Get()->client_bundle_->bluetooth_input_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetBluetoothProfileManagerClient(
scoped_ptr<BluetoothProfileManagerClient> client) {
DBusThreadManager::Get()->client_bundle_->bluetooth_profile_manager_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetCrasAudioClient(
scoped_ptr<CrasAudioClient> client) {
DBusThreadManager::Get()->client_bundle_->cras_audio_client_ = client.Pass();
}
void DBusThreadManagerSetter::SetCrosDisksClient(
scoped_ptr<CrosDisksClient> client) {
DBusThreadManager::Get()->client_bundle_->cros_disks_client_ = client.Pass();
}
void DBusThreadManagerSetter::SetCryptohomeClient(
scoped_ptr<CryptohomeClient> client) {
DBusThreadManager::Get()->client_bundle_->cryptohome_client_ = client.Pass();
}
void DBusThreadManagerSetter::SetDebugDaemonClient(
scoped_ptr<DebugDaemonClient> client) {
DBusThreadManager::Get()->client_bundle_->debug_daemon_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetEasyUnlockClient(
scoped_ptr<EasyUnlockClient> client) {
DBusThreadManager::Get()->client_bundle_->easy_unlock_client_ = client.Pass();
}
void DBusThreadManagerSetter::SetLorgnetteManagerClient(
scoped_ptr<LorgnetteManagerClient> client) {
DBusThreadManager::Get()->client_bundle_->lorgnette_manager_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetShillDeviceClient(
scoped_ptr<ShillDeviceClient> client) {
DBusThreadManager::Get()->client_bundle_->shill_device_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetShillIPConfigClient(
scoped_ptr<ShillIPConfigClient> client) {
DBusThreadManager::Get()->client_bundle_->shill_ipconfig_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetShillManagerClient(
scoped_ptr<ShillManagerClient> client) {
DBusThreadManager::Get()->client_bundle_->shill_manager_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetShillServiceClient(
scoped_ptr<ShillServiceClient> client) {
DBusThreadManager::Get()->client_bundle_->shill_service_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetShillProfileClient(
scoped_ptr<ShillProfileClient> client) {
DBusThreadManager::Get()->client_bundle_->shill_profile_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetGsmSMSClient(
scoped_ptr<GsmSMSClient> client) {
DBusThreadManager::Get()->client_bundle_->gsm_sms_client_ = client.Pass();
}
void DBusThreadManagerSetter::SetImageBurnerClient(
scoped_ptr<ImageBurnerClient> client) {
DBusThreadManager::Get()->client_bundle_->image_burner_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetIntrospectableClient(
scoped_ptr<IntrospectableClient> client) {
DBusThreadManager::Get()->client_bundle_->introspectable_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetModemMessagingClient(
scoped_ptr<ModemMessagingClient> client) {
DBusThreadManager::Get()->client_bundle_->modem_messaging_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetNfcAdapterClient(
scoped_ptr<NfcAdapterClient> client) {
DBusThreadManager::Get()->client_bundle_->nfc_adapter_client_ = client.Pass();
}
void DBusThreadManagerSetter::SetNfcDeviceClient(
scoped_ptr<NfcDeviceClient> client) {
DBusThreadManager::Get()->client_bundle_->nfc_device_client_ = client.Pass();
}
void DBusThreadManagerSetter::SetNfcManagerClient(
scoped_ptr<NfcManagerClient> client) {
DBusThreadManager::Get()->client_bundle_->nfc_manager_client_ = client.Pass();
}
void DBusThreadManagerSetter::SetNfcRecordClient(
scoped_ptr<NfcRecordClient> client) {
DBusThreadManager::Get()->client_bundle_->nfc_record_client_ = client.Pass();
}
void DBusThreadManagerSetter::SetNfcTagClient(
scoped_ptr<NfcTagClient> client) {
DBusThreadManager::Get()->client_bundle_->nfc_tag_client_ = client.Pass();
}
void DBusThreadManagerSetter::SetPermissionBrokerClient(
scoped_ptr<PermissionBrokerClient> client) {
DBusThreadManager::Get()->client_bundle_->permission_broker_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetPowerManagerClient(
scoped_ptr<PowerManagerClient> client) {
DBusThreadManager::Get()->power_policy_controller_.reset();
DBusThreadManager::Get()->client_bundle_->power_manager_client_ =
client.Pass();
DBusThreadManager::Get()->power_policy_controller_.reset(
new PowerPolicyController);
DBusThreadManager::Get()->power_policy_controller_->Init(
DBusThreadManager::Get());
}
void DBusThreadManagerSetter::SetSessionManagerClient(
scoped_ptr<SessionManagerClient> client) {
DBusThreadManager::Get()->client_bundle_->session_manager_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetSMSClient(scoped_ptr<SMSClient> client) {
DBusThreadManager::Get()->client_bundle_->sms_client_ = client.Pass();
}
void DBusThreadManagerSetter::SetSystemClockClient(
scoped_ptr<SystemClockClient> client) {
DBusThreadManager::Get()->client_bundle_->system_clock_client_ =
client.Pass();
}
void DBusThreadManagerSetter::SetUpdateEngineClient(
scoped_ptr<UpdateEngineClient> client) {
DBusThreadManager::Get()->client_bundle_->update_engine_client_ =
client.Pass();
}
} // namespace chromeos