普通文本  |  575行  |  20.85 KB

// 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 <map>

#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_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/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/shill_stub_helper.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() {
    DBusClientImplementationType client_type = REAL_DBUS_CLIENT_IMPLEMENTATION;
    DBusClientImplementationType client_type_override = client_type;
    // If --dbus-stub was requested, pass STUB to specific components;
    // Many components like login are not useful with a stub implementation.
    if (CommandLine::ForCurrentProcess()->HasSwitch(
            chromeos::switches::kDbusStub)) {
      client_type_override = STUB_DBUS_CLIENT_IMPLEMENTATION;
    }

    bluetooth_adapter_client_.reset(BluetoothAdapterClient::Create());
    bluetooth_agent_manager_client_.reset(
        BluetoothAgentManagerClient::Create());
    bluetooth_device_client_.reset(BluetoothDeviceClient::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(client_type));
    cryptohome_client_.reset(CryptohomeClient::Create());
    debug_daemon_client_.reset(DebugDaemonClient::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(client_type_override));
    session_manager_client_.reset(SessionManagerClient::Create(client_type));
    sms_client_.reset(SMSClient::Create());
    system_clock_client_.reset(SystemClockClient::Create());
    update_engine_client_.reset(UpdateEngineClient::Create(client_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();
  }
  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();
  }
  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<BluetoothAdapterClient> bluetooth_adapter_client_;
  scoped_ptr<BluetoothAgentManagerClient> bluetooth_agent_manager_client_;
  scoped_ptr<BluetoothDeviceClient> bluetooth_device_client_;
  scoped_ptr<BluetoothInputClient> bluetooth_input_client_;
  scoped_ptr<BluetoothProfileManagerClient> bluetooth_profile_manager_client_;
  scoped_ptr<CrasAudioClient> cras_audio_client_;
  scoped_ptr<CrosDisksClient> cros_disks_client_;
  scoped_ptr<CryptohomeClient> cryptohome_client_;
  scoped_ptr<DebugDaemonClient> debug_daemon_client_;
  scoped_ptr<ShillDeviceClient> shill_device_client_;
  scoped_ptr<ShillIPConfigClient> shill_ipconfig_client_;
  scoped_ptr<ShillManagerClient> shill_manager_client_;
  scoped_ptr<ShillServiceClient> shill_service_client_;
  scoped_ptr<ShillProfileClient> shill_profile_client_;
  scoped_ptr<GsmSMSClient> gsm_sms_client_;
  scoped_ptr<ImageBurnerClient> image_burner_client_;
  scoped_ptr<IntrospectableClient> introspectable_client_;
  scoped_ptr<ModemMessagingClient> modem_messaging_client_;
  // The declaration order for NFC client objects is important. See
  // DBusThreadManager::CreateDefaultClients for the dependencies.
  scoped_ptr<NfcManagerClient> nfc_manager_client_;
  scoped_ptr<NfcAdapterClient> nfc_adapter_client_;
  scoped_ptr<NfcDeviceClient> nfc_device_client_;
  scoped_ptr<NfcTagClient> nfc_tag_client_;
  scoped_ptr<NfcRecordClient> nfc_record_client_;
  scoped_ptr<PermissionBrokerClient> permission_broker_client_;
  scoped_ptr<SystemClockClient> system_clock_client_;
  scoped_ptr<PowerManagerClient> power_manager_client_;
  scoped_ptr<SessionManagerClient> session_manager_client_;
  scoped_ptr<SMSClient> sms_client_;
  scoped_ptr<UpdateEngineClient> 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 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 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<DBusThreadManagerObserver> observers_;

  scoped_ptr<base::Thread> dbus_thread_;
  scoped_refptr<dbus::Bus> system_bus_;
  scoped_ptr<DBusClientBundle> client_bundle_;
  scoped_ptr<PowerPolicyController> 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()) {
    g_dbus_thread_manager = new DBusThreadManagerImpl;
    InitializeClients();
    VLOG(1) << "DBusThreadManager initialized for ChromeOS";
  } else {
    InitializeWithStub();
  }
}

// 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();
  shill_stub_helper::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->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->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