dbus_thread_manager.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chromeos/dbus/dbus_thread_manager.h"
6
7#include <map>
8
9#include "base/chromeos/chromeos_version.h"
10#include "base/command_line.h"
11#include "base/observer_list.h"
12#include "base/threading/thread.h"
13#include "chromeos/chromeos_switches.h"
14#include "chromeos/dbus/cras_audio_client.h"
15#include "chromeos/dbus/cros_disks_client.h"
16#include "chromeos/dbus/cryptohome_client.h"
17#include "chromeos/dbus/dbus_client_implementation_type.h"
18#include "chromeos/dbus/dbus_thread_manager_observer.h"
19#include "chromeos/dbus/debug_daemon_client.h"
20#include "chromeos/dbus/experimental_bluetooth_adapter_client.h"
21#include "chromeos/dbus/experimental_bluetooth_agent_manager_client.h"
22#include "chromeos/dbus/experimental_bluetooth_device_client.h"
23#include "chromeos/dbus/experimental_bluetooth_input_client.h"
24#include "chromeos/dbus/experimental_bluetooth_profile_manager_client.h"
25#include "chromeos/dbus/gsm_sms_client.h"
26#include "chromeos/dbus/shill_device_client.h"
27#include "chromeos/dbus/shill_ipconfig_client.h"
28#include "chromeos/dbus/shill_manager_client.h"
29#include "chromeos/dbus/shill_profile_client.h"
30#include "chromeos/dbus/shill_service_client.h"
31#include "chromeos/dbus/system_clock_client.h"
32#include "chromeos/dbus/ibus/ibus_client.h"
33#include "chromeos/dbus/ibus/ibus_config_client.h"
34#include "chromeos/dbus/ibus/ibus_engine_factory_service.h"
35#include "chromeos/dbus/ibus/ibus_engine_service.h"
36#include "chromeos/dbus/ibus/ibus_input_context_client.h"
37#include "chromeos/dbus/ibus/ibus_panel_service.h"
38#include "chromeos/dbus/image_burner_client.h"
39#include "chromeos/dbus/introspectable_client.h"
40#include "chromeos/dbus/modem_messaging_client.h"
41#include "chromeos/dbus/permission_broker_client.h"
42#include "chromeos/dbus/power_manager_client.h"
43#include "chromeos/dbus/power_policy_controller.h"
44#include "chromeos/dbus/session_manager_client.h"
45#include "chromeos/dbus/sms_client.h"
46#include "chromeos/dbus/update_engine_client.h"
47#include "dbus/bus.h"
48#include "dbus/dbus_statistics.h"
49
50namespace chromeos {
51
52static DBusThreadManager* g_dbus_thread_manager = NULL;
53static bool g_dbus_thread_manager_set_for_testing = false;
54
55// The DBusThreadManager implementation used in production.
56class DBusThreadManagerImpl : public DBusThreadManager {
57 public:
58  explicit DBusThreadManagerImpl(DBusClientImplementationType client_type)
59      : client_type_(client_type),
60        client_type_override_(client_type) {
61    // If --dbus-stub was requested, pass STUB to specific components;
62    // Many components like login are not useful with a stub implementation.
63    if (CommandLine::ForCurrentProcess()->HasSwitch(
64            chromeos::switches::kDbusStub)) {
65      client_type_override_ = STUB_DBUS_CLIENT_IMPLEMENTATION;
66    }
67
68    // Create the D-Bus thread.
69    base::Thread::Options thread_options;
70    thread_options.message_loop_type = MessageLoop::TYPE_IO;
71    dbus_thread_.reset(new base::Thread("D-Bus thread"));
72    dbus_thread_->StartWithOptions(thread_options);
73
74    // Create the connection to the system bus.
75    dbus::Bus::Options system_bus_options;
76    system_bus_options.bus_type = dbus::Bus::SYSTEM;
77    system_bus_options.connection_type = dbus::Bus::PRIVATE;
78    system_bus_options.dbus_task_runner = dbus_thread_->message_loop_proxy();
79    system_bus_ = new dbus::Bus(system_bus_options);
80  }
81
82  // InitializeClients gets called after g_dbus_thread_manager is set.
83  // NOTE: Clients that access other clients in their constructor must be
84  // construced in the correct order.
85  void InitializeClients() {
86    cras_audio_client_.reset(CrasAudioClient::Create(
87        client_type_, system_bus_.get()));
88    cros_disks_client_.reset(
89        CrosDisksClient::Create(client_type_, system_bus_.get()));
90    cryptohome_client_.reset(
91        CryptohomeClient::Create(client_type_, system_bus_.get()));
92    debug_daemon_client_.reset(
93        DebugDaemonClient::Create(client_type_, system_bus_.get()));
94
95    experimental_bluetooth_adapter_client_.reset(
96        ExperimentalBluetoothAdapterClient::Create(
97            client_type_, system_bus_.get()));
98    experimental_bluetooth_agent_manager_client_.reset(
99        ExperimentalBluetoothAgentManagerClient::Create(
100            client_type_, system_bus_.get()));
101    experimental_bluetooth_device_client_.reset(
102        ExperimentalBluetoothDeviceClient::Create(
103            client_type_, system_bus_.get()));
104    experimental_bluetooth_input_client_.reset(
105        ExperimentalBluetoothInputClient::Create(
106            client_type_, system_bus_.get()));
107    experimental_bluetooth_profile_manager_client_.reset(
108        ExperimentalBluetoothProfileManagerClient::Create(
109            client_type_, system_bus_.get()));
110
111    shill_manager_client_.reset(
112        ShillManagerClient::Create(client_type_override_, system_bus_.get()));
113    shill_device_client_.reset(
114        ShillDeviceClient::Create(client_type_override_, system_bus_.get()));
115    shill_ipconfig_client_.reset(
116        ShillIPConfigClient::Create(client_type_override_, system_bus_.get()));
117    shill_profile_client_.reset(
118        ShillProfileClient::Create(client_type_override_, system_bus_.get()));
119    shill_service_client_.reset(
120        ShillServiceClient::Create(client_type_override_, system_bus_.get()));
121    gsm_sms_client_.reset(
122        GsmSMSClient::Create(client_type_override_, system_bus_.get()));
123
124    image_burner_client_.reset(ImageBurnerClient::Create(client_type_,
125                                                         system_bus_.get()));
126    introspectable_client_.reset(
127        IntrospectableClient::Create(client_type_, system_bus_.get()));
128    modem_messaging_client_.reset(
129        ModemMessagingClient::Create(client_type_, system_bus_.get()));
130    permission_broker_client_.reset(
131        PermissionBrokerClient::Create(client_type_, system_bus_.get()));
132    power_manager_client_.reset(
133        PowerManagerClient::Create(client_type_override_, system_bus_.get()));
134    session_manager_client_.reset(
135        SessionManagerClient::Create(client_type_, system_bus_.get()));
136    sms_client_.reset(
137        SMSClient::Create(client_type_, system_bus_.get()));
138    system_clock_client_.reset(
139        SystemClockClient::Create(client_type_, system_bus_.get()));
140    update_engine_client_.reset(
141        UpdateEngineClient::Create(client_type_, system_bus_.get()));
142
143    // PowerPolicyController is dependent on PowerManagerClient, so
144    // initialize it after the main list of clients.
145    power_policy_controller_.reset(
146        new PowerPolicyController(this, power_manager_client_.get()));
147
148    // This must be called after the list of clients so they've each had a
149    // chance to register with their object managers.
150    system_bus_->GetManagedObjects();
151  }
152
153  virtual ~DBusThreadManagerImpl() {
154    FOR_EACH_OBSERVER(DBusThreadManagerObserver, observers_,
155                      OnDBusThreadManagerDestroying(this));
156
157    // Shut down the bus. During the browser shutdown, it's ok to shut down
158    // the bus synchronously.
159    system_bus_->ShutdownOnDBusThreadAndBlock();
160    if (ibus_bus_.get())
161      ibus_bus_->ShutdownOnDBusThreadAndBlock();
162
163    // Release IBusEngineService instances.
164    for (std::map<dbus::ObjectPath, IBusEngineService*>::iterator it
165            = ibus_engine_services_.begin();
166         it != ibus_engine_services_.end(); it++) {
167      delete it->second;
168    }
169
170    // Stop the D-Bus thread.
171    dbus_thread_->Stop();
172  }
173
174  // DBusThreadManager override.
175  virtual void AddObserver(DBusThreadManagerObserver* observer) OVERRIDE {
176    DCHECK(observer);
177    observers_.AddObserver(observer);
178  }
179
180  // DBusThreadManager override.
181  virtual void RemoveObserver(DBusThreadManagerObserver* observer) OVERRIDE {
182    DCHECK(observer);
183    observers_.RemoveObserver(observer);
184  }
185
186  // DBusThreadManager override.
187  virtual void InitIBusBus(
188      const std::string &ibus_address,
189      const base::Closure& on_disconnected_callback) OVERRIDE {
190    DCHECK(!ibus_bus_);
191    dbus::Bus::Options ibus_bus_options;
192    ibus_bus_options.bus_type = dbus::Bus::CUSTOM_ADDRESS;
193    ibus_bus_options.address = ibus_address;
194    ibus_bus_options.connection_type = dbus::Bus::PRIVATE;
195    ibus_bus_options.dbus_task_runner = dbus_thread_->message_loop_proxy();
196    ibus_bus_options.disconnected_callback = on_disconnected_callback;
197    ibus_bus_ = new dbus::Bus(ibus_bus_options);
198    ibus_address_ = ibus_address;
199    VLOG(1) << "Connected to ibus-daemon: " << ibus_address;
200
201    DBusClientImplementationType client_type =
202        base::chromeos::IsRunningOnChromeOS() ? REAL_DBUS_CLIENT_IMPLEMENTATION
203                                              : STUB_DBUS_CLIENT_IMPLEMENTATION;
204
205    ibus_client_.reset(
206        IBusClient::Create(client_type, ibus_bus_.get()));
207    ibus_config_client_.reset(
208        IBusConfigClient::Create(client_type, ibus_bus_.get()));
209    ibus_input_context_client_.reset(
210        IBusInputContextClient::Create(client_type));
211    ibus_engine_factory_service_.reset(
212        IBusEngineFactoryService::Create(ibus_bus_.get(), client_type));
213    ibus_panel_service_.reset(
214        IBusPanelService::Create(client_type,
215                                 ibus_bus_.get(),
216                                 ibus_input_context_client_.get()));
217
218    ibus_engine_services_.clear();
219  }
220
221  // DBusThreadManager overrides:
222  virtual dbus::Bus* GetSystemBus() OVERRIDE {
223    return system_bus_.get();
224  }
225
226  virtual dbus::Bus* GetIBusBus() OVERRIDE {
227    return ibus_bus_.get();
228  }
229
230  virtual CrasAudioClient* GetCrasAudioClient() OVERRIDE {
231    return cras_audio_client_.get();
232  }
233
234  virtual CrosDisksClient* GetCrosDisksClient() OVERRIDE {
235    return cros_disks_client_.get();
236  }
237
238  virtual CryptohomeClient* GetCryptohomeClient() OVERRIDE {
239    return cryptohome_client_.get();
240  }
241
242  virtual DebugDaemonClient* GetDebugDaemonClient() OVERRIDE {
243    return debug_daemon_client_.get();
244  }
245
246  virtual ExperimentalBluetoothAdapterClient*
247        GetExperimentalBluetoothAdapterClient() OVERRIDE {
248    return experimental_bluetooth_adapter_client_.get();
249  }
250
251  virtual ExperimentalBluetoothAgentManagerClient*
252        GetExperimentalBluetoothAgentManagerClient() OVERRIDE {
253    return experimental_bluetooth_agent_manager_client_.get();
254  }
255
256  virtual ExperimentalBluetoothDeviceClient*
257        GetExperimentalBluetoothDeviceClient() OVERRIDE {
258    return experimental_bluetooth_device_client_.get();
259  }
260
261  virtual ExperimentalBluetoothInputClient*
262        GetExperimentalBluetoothInputClient() OVERRIDE {
263    return experimental_bluetooth_input_client_.get();
264  }
265
266  virtual ExperimentalBluetoothProfileManagerClient*
267        GetExperimentalBluetoothProfileManagerClient() OVERRIDE {
268    return experimental_bluetooth_profile_manager_client_.get();
269  }
270
271  virtual ShillDeviceClient* GetShillDeviceClient() OVERRIDE {
272    return shill_device_client_.get();
273  }
274
275  virtual ShillIPConfigClient* GetShillIPConfigClient() OVERRIDE {
276    return shill_ipconfig_client_.get();
277  }
278
279  virtual ShillManagerClient* GetShillManagerClient() OVERRIDE {
280    return shill_manager_client_.get();
281  }
282
283  virtual ShillProfileClient* GetShillProfileClient() OVERRIDE {
284    return shill_profile_client_.get();
285  }
286
287  virtual ShillServiceClient* GetShillServiceClient() OVERRIDE {
288    return shill_service_client_.get();
289  }
290
291  virtual GsmSMSClient* GetGsmSMSClient() OVERRIDE {
292    return gsm_sms_client_.get();
293  }
294
295  virtual ImageBurnerClient* GetImageBurnerClient() OVERRIDE {
296    return image_burner_client_.get();
297  }
298
299  virtual IntrospectableClient* GetIntrospectableClient() OVERRIDE {
300    return introspectable_client_.get();
301  }
302
303  virtual ModemMessagingClient* GetModemMessagingClient() OVERRIDE {
304    return modem_messaging_client_.get();
305  }
306
307  virtual PermissionBrokerClient* GetPermissionBrokerClient() OVERRIDE {
308    return permission_broker_client_.get();
309  }
310
311  virtual PowerManagerClient* GetPowerManagerClient() OVERRIDE {
312    return power_manager_client_.get();
313  }
314
315  virtual PowerPolicyController* GetPowerPolicyController() OVERRIDE {
316    return power_policy_controller_.get();
317  }
318
319  virtual SessionManagerClient* GetSessionManagerClient() OVERRIDE {
320    return session_manager_client_.get();
321  }
322
323  virtual SMSClient* GetSMSClient() OVERRIDE {
324    return sms_client_.get();
325  }
326
327  virtual SystemClockClient* GetSystemClockClient() OVERRIDE {
328    return system_clock_client_.get();
329  }
330
331  virtual UpdateEngineClient* GetUpdateEngineClient() OVERRIDE {
332    return update_engine_client_.get();
333  }
334
335  virtual IBusClient* GetIBusClient() OVERRIDE {
336    return ibus_client_.get();
337  }
338
339  virtual IBusConfigClient* GetIBusConfigClient() OVERRIDE {
340    return ibus_config_client_.get();
341  }
342
343  virtual IBusInputContextClient* GetIBusInputContextClient() OVERRIDE {
344    return ibus_input_context_client_.get();
345  }
346
347  virtual IBusEngineFactoryService* GetIBusEngineFactoryService() OVERRIDE {
348    return ibus_engine_factory_service_.get();
349  }
350
351  virtual IBusEngineService* GetIBusEngineService(
352      const dbus::ObjectPath& object_path) OVERRIDE {
353    const DBusClientImplementationType client_type =
354        base::chromeos::IsRunningOnChromeOS() ? REAL_DBUS_CLIENT_IMPLEMENTATION
355                                              : STUB_DBUS_CLIENT_IMPLEMENTATION;
356
357    if (ibus_engine_services_.find(object_path)
358            == ibus_engine_services_.end()) {
359      ibus_engine_services_[object_path] =
360          IBusEngineService::Create(client_type, ibus_bus_.get(), object_path);
361    }
362    return ibus_engine_services_[object_path];
363  }
364
365  virtual void RemoveIBusEngineService(
366      const dbus::ObjectPath& object_path) OVERRIDE {
367    if (ibus_engine_services_.find(object_path) !=
368        ibus_engine_services_.end()) {
369      LOG(WARNING) << "Object path not found: " << object_path.value();
370      return;
371    }
372    delete ibus_engine_services_[object_path];
373    ibus_engine_services_.erase(object_path);
374  }
375
376  virtual IBusPanelService* GetIBusPanelService() OVERRIDE {
377    return ibus_panel_service_.get();
378  }
379
380  DBusClientImplementationType client_type_;
381  DBusClientImplementationType client_type_override_;
382
383  // Note: Keep this before other members so they can call AddObserver() in
384  // their c'tors.
385  ObserverList<DBusThreadManagerObserver> observers_;
386
387  scoped_ptr<base::Thread> dbus_thread_;
388  scoped_refptr<dbus::Bus> system_bus_;
389  scoped_refptr<dbus::Bus> ibus_bus_;
390  scoped_ptr<CrasAudioClient> cras_audio_client_;
391  scoped_ptr<CrosDisksClient> cros_disks_client_;
392  scoped_ptr<CryptohomeClient> cryptohome_client_;
393  scoped_ptr<DebugDaemonClient> debug_daemon_client_;
394  scoped_ptr<ExperimentalBluetoothAdapterClient>
395      experimental_bluetooth_adapter_client_;
396  scoped_ptr<ExperimentalBluetoothAgentManagerClient>
397      experimental_bluetooth_agent_manager_client_;
398  scoped_ptr<ExperimentalBluetoothDeviceClient>
399      experimental_bluetooth_device_client_;
400  scoped_ptr<ExperimentalBluetoothInputClient>
401      experimental_bluetooth_input_client_;
402  scoped_ptr<ExperimentalBluetoothProfileManagerClient>
403      experimental_bluetooth_profile_manager_client_;
404  scoped_ptr<ShillDeviceClient> shill_device_client_;
405  scoped_ptr<ShillIPConfigClient> shill_ipconfig_client_;
406  scoped_ptr<ShillManagerClient> shill_manager_client_;
407  scoped_ptr<ShillProfileClient> shill_profile_client_;
408  scoped_ptr<ShillServiceClient> shill_service_client_;
409  scoped_ptr<GsmSMSClient> gsm_sms_client_;
410  scoped_ptr<ImageBurnerClient> image_burner_client_;
411  scoped_ptr<IntrospectableClient> introspectable_client_;
412  scoped_ptr<ModemMessagingClient> modem_messaging_client_;
413  scoped_ptr<PermissionBrokerClient> permission_broker_client_;
414  scoped_ptr<SystemClockClient> system_clock_client_;
415  scoped_ptr<PowerManagerClient> power_manager_client_;
416  scoped_ptr<SessionManagerClient> session_manager_client_;
417  scoped_ptr<SMSClient> sms_client_;
418  scoped_ptr<UpdateEngineClient> update_engine_client_;
419  scoped_ptr<IBusClient> ibus_client_;
420  scoped_ptr<IBusConfigClient> ibus_config_client_;
421  scoped_ptr<IBusInputContextClient> ibus_input_context_client_;
422  scoped_ptr<IBusEngineFactoryService> ibus_engine_factory_service_;
423  std::map<dbus::ObjectPath, IBusEngineService*> ibus_engine_services_;
424  scoped_ptr<IBusPanelService> ibus_panel_service_;
425  scoped_ptr<PowerPolicyController> power_policy_controller_;
426
427  std::string ibus_address_;
428};
429
430// static
431void DBusThreadManager::Initialize() {
432  // Ignore Initialize() if we set a test DBusThreadManager.
433  if (g_dbus_thread_manager_set_for_testing)
434    return;
435  // If we initialize DBusThreadManager twice we may also be shutting it down
436  // early; do not allow that.
437  CHECK(g_dbus_thread_manager == NULL);
438  // Determine whether we use stub or real client implementations.
439  DBusThreadManagerImpl* dbus_thread_manager_impl;
440  if (base::chromeos::IsRunningOnChromeOS()) {
441    dbus_thread_manager_impl =
442        new DBusThreadManagerImpl(REAL_DBUS_CLIENT_IMPLEMENTATION);
443    VLOG(1) << "DBusThreadManager initialized for ChromeOS";
444  } else {
445    dbus_thread_manager_impl =
446        new DBusThreadManagerImpl(STUB_DBUS_CLIENT_IMPLEMENTATION);
447    VLOG(1) << "DBusThreadManager initialized with Stub";
448  }
449  g_dbus_thread_manager = dbus_thread_manager_impl;
450  dbus_thread_manager_impl->InitializeClients();
451}
452
453// static
454void DBusThreadManager::InitializeForTesting(
455    DBusThreadManager* dbus_thread_manager) {
456  // If we initialize DBusThreadManager twice we may also be shutting it down
457  // early; do not allow that.
458  CHECK(g_dbus_thread_manager == NULL);
459  CHECK(dbus_thread_manager);
460  g_dbus_thread_manager = dbus_thread_manager;
461  g_dbus_thread_manager_set_for_testing = true;
462  VLOG(1) << "DBusThreadManager initialized with test implementation";
463}
464
465// static
466void DBusThreadManager::InitializeWithStub() {
467  // If we initialize DBusThreadManager twice we may also be shutting it down
468  // early; do not allow that.
469  CHECK(g_dbus_thread_manager == NULL);
470  DBusThreadManagerImpl* dbus_thread_manager_impl =
471      new DBusThreadManagerImpl(STUB_DBUS_CLIENT_IMPLEMENTATION);
472  g_dbus_thread_manager = dbus_thread_manager_impl;
473  dbus_thread_manager_impl->InitializeClients();
474  VLOG(1) << "DBusThreadManager initialized with stub implementation";
475}
476
477// static
478bool DBusThreadManager::IsInitialized() {
479  return g_dbus_thread_manager != NULL;
480}
481
482// static
483void DBusThreadManager::Shutdown() {
484  // If we called InitializeForTesting, this may get called more than once.
485  // Ensure that we only shutdown DBusThreadManager once.
486  CHECK(g_dbus_thread_manager || g_dbus_thread_manager_set_for_testing);
487  DBusThreadManager* dbus_thread_manager = g_dbus_thread_manager;
488  g_dbus_thread_manager = NULL;
489  delete dbus_thread_manager;
490  VLOG(1) << "DBusThreadManager Shutdown completed";
491}
492
493DBusThreadManager::DBusThreadManager() {
494  dbus::statistics::Initialize();
495}
496
497DBusThreadManager::~DBusThreadManager() {
498  dbus::statistics::Shutdown();
499  if (g_dbus_thread_manager == NULL)
500    return;  // Called form Shutdown() or local test instance.
501  // There should never be both a global instance and a local instance.
502  CHECK(this == g_dbus_thread_manager);
503  if (g_dbus_thread_manager_set_for_testing) {
504    g_dbus_thread_manager = NULL;
505    g_dbus_thread_manager_set_for_testing = false;
506    VLOG(1) << "DBusThreadManager destroyed";
507  } else {
508    LOG(FATAL) << "~DBusThreadManager() called outside of Shutdown()";
509  }
510}
511
512// static
513DBusThreadManager* DBusThreadManager::Get() {
514  CHECK(g_dbus_thread_manager)
515      << "DBusThreadManager::Get() called before Initialize()";
516  return g_dbus_thread_manager;
517}
518
519}  // namespace chromeos
520