// 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 #include "base/command_line.h" #include "base/observer_list.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_thread_manager_observer.h" #include "chromeos/dbus/debug_daemon_client.h" #include "chromeos/dbus/fake_dbus_thread_manager.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 DBusThreadManager* g_dbus_thread_manager_for_testing = NULL; // The bundle of all D-Bus clients used in DBusThreadManagerImpl. The bundle // is used to delete them at once in the right order before shutting down the // system bus. See also the comment in the destructor of DBusThreadManagerImpl. class DBusClientBundle { public: DBusClientBundle() { const DBusClientImplementationType type = REAL_DBUS_CLIENT_IMPLEMENTATION; bluetooth_adapter_client_.reset(BluetoothAdapterClient::Create()); bluetooth_agent_manager_client_.reset( BluetoothAgentManagerClient::Create()); bluetooth_device_client_.reset(BluetoothDeviceClient::Create()); bluetooth_gatt_characteristic_client_.reset( BluetoothGattCharacteristicClient::Create()); bluetooth_gatt_descriptor_client_.reset( BluetoothGattDescriptorClient::Create()); bluetooth_gatt_manager_client_.reset(BluetoothGattManagerClient::Create()); bluetooth_gatt_service_client_.reset(BluetoothGattServiceClient::Create()); bluetooth_input_client_.reset(BluetoothInputClient::Create()); bluetooth_profile_manager_client_.reset( BluetoothProfileManagerClient::Create()); cras_audio_client_.reset(CrasAudioClient::Create()); cros_disks_client_.reset(CrosDisksClient::Create(type)); cryptohome_client_.reset(CryptohomeClient::Create()); debug_daemon_client_.reset(DebugDaemonClient::Create()); lorgnette_manager_client_.reset(LorgnetteManagerClient::Create()); shill_manager_client_.reset(ShillManagerClient::Create()); shill_device_client_.reset(ShillDeviceClient::Create()); shill_ipconfig_client_.reset(ShillIPConfigClient::Create()); shill_service_client_.reset(ShillServiceClient::Create()); shill_profile_client_.reset(ShillProfileClient::Create()); gsm_sms_client_.reset(GsmSMSClient::Create()); image_burner_client_.reset(ImageBurnerClient::Create()); introspectable_client_.reset(IntrospectableClient::Create()); modem_messaging_client_.reset(ModemMessagingClient::Create()); // Create the NFC clients in the correct order based on their dependencies. nfc_manager_client_.reset(NfcManagerClient::Create()); nfc_adapter_client_.reset( NfcAdapterClient::Create(nfc_manager_client_.get())); nfc_device_client_.reset( NfcDeviceClient::Create(nfc_adapter_client_.get())); nfc_tag_client_.reset(NfcTagClient::Create(nfc_adapter_client_.get())); nfc_record_client_.reset(NfcRecordClient::Create(nfc_device_client_.get(), nfc_tag_client_.get())); permission_broker_client_.reset(PermissionBrokerClient::Create()); power_manager_client_.reset(PowerManagerClient::Create(type)); session_manager_client_.reset(SessionManagerClient::Create(type)); sms_client_.reset(SMSClient::Create()); system_clock_client_.reset(SystemClockClient::Create()); update_engine_client_.reset(UpdateEngineClient::Create(type)); } BluetoothAdapterClient* bluetooth_adapter_client() { return bluetooth_adapter_client_.get(); } BluetoothAgentManagerClient* bluetooth_agent_manager_client() { return bluetooth_agent_manager_client_.get(); } BluetoothDeviceClient* bluetooth_device_client() { return bluetooth_device_client_.get(); } BluetoothGattCharacteristicClient* bluetooth_gatt_characteristic_client() { return bluetooth_gatt_characteristic_client_.get(); } BluetoothGattDescriptorClient* bluetooth_gatt_descriptor_client() { return bluetooth_gatt_descriptor_client_.get(); } BluetoothGattManagerClient* bluetooth_gatt_manager_client() { return bluetooth_gatt_manager_client_.get(); } BluetoothGattServiceClient* bluetooth_gatt_service_client() { return bluetooth_gatt_service_client_.get(); } BluetoothInputClient* bluetooth_input_client() { return bluetooth_input_client_.get(); } BluetoothProfileManagerClient* bluetooth_profile_manager_client() { return bluetooth_profile_manager_client_.get(); } CrasAudioClient* cras_audio_client() { return cras_audio_client_.get(); } CrosDisksClient* cros_disks_client() { return cros_disks_client_.get(); } CryptohomeClient* cryptohome_client() { return cryptohome_client_.get(); } DebugDaemonClient* debug_daemon_client() { return debug_daemon_client_.get(); } LorgnetteManagerClient* lorgnette_manager_client() { return lorgnette_manager_client_.get(); } ShillDeviceClient* shill_device_client() { return shill_device_client_.get(); } ShillIPConfigClient* shill_ipconfig_client() { return shill_ipconfig_client_.get(); } ShillManagerClient* shill_manager_client() { return shill_manager_client_.get(); } ShillServiceClient* shill_service_client() { return shill_service_client_.get(); } ShillProfileClient* shill_profile_client() { return shill_profile_client_.get(); } GsmSMSClient* gsm_sms_client() { return gsm_sms_client_.get(); } ImageBurnerClient* image_burner_client() { return image_burner_client_.get(); } IntrospectableClient* introspectable_client() { return introspectable_client_.get(); } ModemMessagingClient* modem_messaging_client() { return modem_messaging_client_.get(); } NfcManagerClient* nfc_manager_client() { return nfc_manager_client_.get(); } NfcAdapterClient* nfc_adapter_client() { return nfc_adapter_client_.get(); } NfcDeviceClient* nfc_device_client() { return nfc_device_client_.get(); } NfcTagClient* nfc_tag_client() { return nfc_tag_client_.get(); } NfcRecordClient* nfc_record_client() { return nfc_record_client_.get(); } PermissionBrokerClient* permission_broker_client() { return permission_broker_client_.get(); } SystemClockClient* system_clock_client() { return system_clock_client_.get(); } PowerManagerClient* power_manager_client() { return power_manager_client_.get(); } SessionManagerClient* session_manager_client() { return session_manager_client_.get(); } SMSClient* sms_client() { return sms_client_.get(); } UpdateEngineClient* update_engine_client() { return update_engine_client_.get(); } private: scoped_ptr bluetooth_adapter_client_; scoped_ptr bluetooth_agent_manager_client_; scoped_ptr bluetooth_device_client_; scoped_ptr bluetooth_gatt_characteristic_client_; scoped_ptr bluetooth_gatt_descriptor_client_; scoped_ptr bluetooth_gatt_manager_client_; scoped_ptr bluetooth_gatt_service_client_; scoped_ptr bluetooth_input_client_; scoped_ptr bluetooth_profile_manager_client_; scoped_ptr cras_audio_client_; scoped_ptr cros_disks_client_; scoped_ptr cryptohome_client_; scoped_ptr debug_daemon_client_; scoped_ptr lorgnette_manager_client_; scoped_ptr shill_device_client_; scoped_ptr shill_ipconfig_client_; scoped_ptr shill_manager_client_; scoped_ptr shill_service_client_; scoped_ptr shill_profile_client_; scoped_ptr gsm_sms_client_; scoped_ptr image_burner_client_; scoped_ptr introspectable_client_; scoped_ptr modem_messaging_client_; // The declaration order for NFC client objects is important. See // DBusThreadManager::CreateDefaultClients for the dependencies. scoped_ptr nfc_manager_client_; scoped_ptr nfc_adapter_client_; scoped_ptr nfc_device_client_; scoped_ptr nfc_tag_client_; scoped_ptr nfc_record_client_; scoped_ptr permission_broker_client_; scoped_ptr system_clock_client_; scoped_ptr power_manager_client_; scoped_ptr session_manager_client_; scoped_ptr sms_client_; scoped_ptr update_engine_client_; DISALLOW_COPY_AND_ASSIGN(DBusClientBundle); }; // The DBusThreadManager implementation used in production. class DBusThreadManagerImpl : public DBusThreadManager { public: explicit DBusThreadManagerImpl() { // 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); CreateDefaultClients(); } virtual ~DBusThreadManagerImpl() { FOR_EACH_OBSERVER(DBusThreadManagerObserver, observers_, OnDBusThreadManagerDestroying(this)); // 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. system_bus_->ShutdownOnDBusThreadAndBlock(); // Stop the D-Bus thread. dbus_thread_->Stop(); } // DBusThreadManager overrides: virtual void AddObserver(DBusThreadManagerObserver* observer) OVERRIDE { DCHECK(observer); observers_.AddObserver(observer); } virtual void RemoveObserver(DBusThreadManagerObserver* observer) OVERRIDE { DCHECK(observer); observers_.RemoveObserver(observer); } virtual dbus::Bus* GetSystemBus() OVERRIDE { return system_bus_.get(); } virtual BluetoothAdapterClient* GetBluetoothAdapterClient() OVERRIDE { return client_bundle_->bluetooth_adapter_client(); } virtual BluetoothAgentManagerClient* GetBluetoothAgentManagerClient() OVERRIDE { return client_bundle_->bluetooth_agent_manager_client(); } virtual BluetoothDeviceClient* GetBluetoothDeviceClient() OVERRIDE { return client_bundle_->bluetooth_device_client(); } virtual BluetoothGattCharacteristicClient* GetBluetoothGattCharacteristicClient() OVERRIDE { return client_bundle_->bluetooth_gatt_characteristic_client(); } virtual BluetoothGattDescriptorClient* GetBluetoothGattDescriptorClient() OVERRIDE { return client_bundle_->bluetooth_gatt_descriptor_client(); } virtual BluetoothGattManagerClient* GetBluetoothGattManagerClient() OVERRIDE { return client_bundle_->bluetooth_gatt_manager_client(); } virtual BluetoothGattServiceClient* GetBluetoothGattServiceClient() OVERRIDE { return client_bundle_->bluetooth_gatt_service_client(); } virtual BluetoothInputClient* GetBluetoothInputClient() OVERRIDE { return client_bundle_->bluetooth_input_client(); } virtual BluetoothProfileManagerClient* GetBluetoothProfileManagerClient() OVERRIDE { return client_bundle_->bluetooth_profile_manager_client(); } virtual CrasAudioClient* GetCrasAudioClient() OVERRIDE { return client_bundle_->cras_audio_client(); } virtual CrosDisksClient* GetCrosDisksClient() OVERRIDE { return client_bundle_->cros_disks_client(); } virtual CryptohomeClient* GetCryptohomeClient() OVERRIDE { return client_bundle_->cryptohome_client(); } virtual DebugDaemonClient* GetDebugDaemonClient() OVERRIDE { return client_bundle_->debug_daemon_client(); } virtual LorgnetteManagerClient* GetLorgnetteManagerClient() OVERRIDE { return client_bundle_->lorgnette_manager_client(); } virtual ShillDeviceClient* GetShillDeviceClient() OVERRIDE { return client_bundle_->shill_device_client(); } virtual ShillIPConfigClient* GetShillIPConfigClient() OVERRIDE { return client_bundle_->shill_ipconfig_client(); } virtual ShillManagerClient* GetShillManagerClient() OVERRIDE { return client_bundle_->shill_manager_client(); } virtual ShillServiceClient* GetShillServiceClient() OVERRIDE { return client_bundle_->shill_service_client(); } virtual ShillProfileClient* GetShillProfileClient() OVERRIDE { return client_bundle_->shill_profile_client(); } virtual GsmSMSClient* GetGsmSMSClient() OVERRIDE { return client_bundle_->gsm_sms_client(); } virtual ImageBurnerClient* GetImageBurnerClient() OVERRIDE { return client_bundle_->image_burner_client(); } virtual IntrospectableClient* GetIntrospectableClient() OVERRIDE { return client_bundle_->introspectable_client(); } virtual ModemMessagingClient* GetModemMessagingClient() OVERRIDE { return client_bundle_->modem_messaging_client(); } virtual NfcAdapterClient* GetNfcAdapterClient() OVERRIDE { return client_bundle_->nfc_adapter_client(); } virtual NfcDeviceClient* GetNfcDeviceClient() OVERRIDE { return client_bundle_->nfc_device_client(); } virtual NfcManagerClient* GetNfcManagerClient() OVERRIDE { return client_bundle_->nfc_manager_client(); } virtual NfcRecordClient* GetNfcRecordClient() OVERRIDE { return client_bundle_->nfc_record_client(); } virtual NfcTagClient* GetNfcTagClient() OVERRIDE { return client_bundle_->nfc_tag_client(); } virtual PermissionBrokerClient* GetPermissionBrokerClient() OVERRIDE { return client_bundle_->permission_broker_client(); } virtual PowerManagerClient* GetPowerManagerClient() OVERRIDE { return client_bundle_->power_manager_client(); } virtual SessionManagerClient* GetSessionManagerClient() OVERRIDE { return client_bundle_->session_manager_client(); } virtual SMSClient* GetSMSClient() OVERRIDE { return client_bundle_->sms_client(); } virtual SystemClockClient* GetSystemClockClient() OVERRIDE { return client_bundle_->system_clock_client(); } virtual UpdateEngineClient* GetUpdateEngineClient() OVERRIDE { return client_bundle_->update_engine_client(); } virtual PowerPolicyController* GetPowerPolicyController() OVERRIDE { return power_policy_controller_.get(); } private: // Constructs all clients and stores them in the respective *_client_ member // variable. void CreateDefaultClients() { client_bundle_.reset(new DBusClientBundle); power_policy_controller_.reset(new PowerPolicyController); } // Note: Keep this before other members so they can call AddObserver() in // their c'tors. ObserverList observers_; scoped_ptr dbus_thread_; scoped_refptr system_bus_; scoped_ptr client_bundle_; scoped_ptr power_policy_controller_; }; // static void DBusThreadManager::Initialize() { // If we initialize DBusThreadManager twice we may also be shutting it down // early; do not allow that. CHECK(g_dbus_thread_manager == NULL); if (g_dbus_thread_manager_for_testing) { g_dbus_thread_manager = g_dbus_thread_manager_for_testing; InitializeClients(); VLOG(1) << "DBusThreadManager initialized with test implementation"; return; } // Determine whether we use stub or real client implementations. if (!base::SysInfo::IsRunningOnChromeOS() || CommandLine::ForCurrentProcess()->HasSwitch( chromeos::switches::kDbusStub)) { InitializeWithStub(); } else { g_dbus_thread_manager = new DBusThreadManagerImpl; InitializeClients(); VLOG(1) << "DBusThreadManager initialized for Chrome OS"; } } // static void DBusThreadManager::SetInstanceForTesting( DBusThreadManager* dbus_thread_manager) { CHECK(!g_dbus_thread_manager); CHECK(!g_dbus_thread_manager_for_testing); g_dbus_thread_manager_for_testing = dbus_thread_manager; } // static void DBusThreadManager::InitializeForTesting( DBusThreadManager* dbus_thread_manager) { SetInstanceForTesting(dbus_thread_manager); Initialize(); } // static void DBusThreadManager::InitializeWithStub() { // If we initialize DBusThreadManager twice we may also be shutting it down // early; do not allow that. CHECK(g_dbus_thread_manager == NULL); FakeDBusThreadManager* fake_dbus_thread_manager = new FakeDBusThreadManager; fake_dbus_thread_manager->SetFakeClients(); g_dbus_thread_manager = fake_dbus_thread_manager; InitializeClients(); fake_dbus_thread_manager->SetupDefaultEnvironment(); VLOG(1) << "DBusThreadManager initialized with stub implementation"; } // static bool DBusThreadManager::IsInitialized() { return g_dbus_thread_manager != NULL; } // static void DBusThreadManager::Shutdown() { // If we called InitializeForTesting, this may get called more than once. // Ensure that we only shutdown DBusThreadManager once. CHECK(g_dbus_thread_manager || g_dbus_thread_manager_for_testing); DBusThreadManager* dbus_thread_manager = g_dbus_thread_manager; g_dbus_thread_manager = NULL; g_dbus_thread_manager_for_testing = NULL; delete dbus_thread_manager; VLOG(1) << "DBusThreadManager Shutdown completed"; } DBusThreadManager::DBusThreadManager() { dbus::statistics::Initialize(); } DBusThreadManager::~DBusThreadManager() { dbus::statistics::Shutdown(); if (g_dbus_thread_manager == NULL) 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_dbus_thread_manager_for_testing) { g_dbus_thread_manager = NULL; g_dbus_thread_manager_for_testing = NULL; VLOG(1) << "DBusThreadManager destroyed"; } else { LOG(FATAL) << "~DBusThreadManager() called outside of Shutdown()"; } } // static DBusThreadManager* DBusThreadManager::Get() { CHECK(g_dbus_thread_manager) << "DBusThreadManager::Get() called before Initialize()"; return g_dbus_thread_manager; } // static void DBusThreadManager::InitializeClients() { InitClient(g_dbus_thread_manager->GetBluetoothAdapterClient()); InitClient(g_dbus_thread_manager->GetBluetoothAgentManagerClient()); InitClient(g_dbus_thread_manager->GetBluetoothDeviceClient()); InitClient(g_dbus_thread_manager->GetBluetoothGattCharacteristicClient()); InitClient(g_dbus_thread_manager->GetBluetoothGattDescriptorClient()); InitClient(g_dbus_thread_manager->GetBluetoothGattManagerClient()); InitClient(g_dbus_thread_manager->GetBluetoothGattServiceClient()); InitClient(g_dbus_thread_manager->GetBluetoothInputClient()); InitClient(g_dbus_thread_manager->GetBluetoothProfileManagerClient()); InitClient(g_dbus_thread_manager->GetCrasAudioClient()); InitClient(g_dbus_thread_manager->GetCrosDisksClient()); InitClient(g_dbus_thread_manager->GetCryptohomeClient()); InitClient(g_dbus_thread_manager->GetDebugDaemonClient()); InitClient(g_dbus_thread_manager->GetGsmSMSClient()); InitClient(g_dbus_thread_manager->GetImageBurnerClient()); InitClient(g_dbus_thread_manager->GetIntrospectableClient()); InitClient(g_dbus_thread_manager->GetLorgnetteManagerClient()); InitClient(g_dbus_thread_manager->GetModemMessagingClient()); InitClient(g_dbus_thread_manager->GetPermissionBrokerClient()); InitClient(g_dbus_thread_manager->GetPowerManagerClient()); InitClient(g_dbus_thread_manager->GetSessionManagerClient()); InitClient(g_dbus_thread_manager->GetShillDeviceClient()); InitClient(g_dbus_thread_manager->GetShillIPConfigClient()); InitClient(g_dbus_thread_manager->GetShillManagerClient()); InitClient(g_dbus_thread_manager->GetShillServiceClient()); InitClient(g_dbus_thread_manager->GetShillProfileClient()); InitClient(g_dbus_thread_manager->GetSMSClient()); InitClient(g_dbus_thread_manager->GetSystemClockClient()); InitClient(g_dbus_thread_manager->GetUpdateEngineClient()); // Initialize the NFC clients in the correct order. The order of // initialization matters due to dependencies that exist between the // client objects. InitClient(g_dbus_thread_manager->GetNfcManagerClient()); InitClient(g_dbus_thread_manager->GetNfcAdapterClient()); InitClient(g_dbus_thread_manager->GetNfcDeviceClient()); InitClient(g_dbus_thread_manager->GetNfcTagClient()); InitClient(g_dbus_thread_manager->GetNfcRecordClient()); // PowerPolicyController is dependent on PowerManagerClient, so // initialize it after the main list of clients. if (g_dbus_thread_manager->GetPowerPolicyController()) { g_dbus_thread_manager->GetPowerPolicyController()->Init( g_dbus_thread_manager); } // 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 (g_dbus_thread_manager->GetSystemBus()) g_dbus_thread_manager->GetSystemBus()->GetManagedObjects(); } // static void DBusThreadManager::InitClient(DBusClient* client) { if (client) client->Init(g_dbus_thread_manager->GetSystemBus()); } } // namespace chromeos