dbus_thread_manager.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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/bluetooth_adapter_client.h"
15#include "chromeos/dbus/bluetooth_agent_manager_client.h"
16#include "chromeos/dbus/bluetooth_device_client.h"
17#include "chromeos/dbus/bluetooth_input_client.h"
18#include "chromeos/dbus/bluetooth_profile_manager_client.h"
19#include "chromeos/dbus/cras_audio_client.h"
20#include "chromeos/dbus/cros_disks_client.h"
21#include "chromeos/dbus/cryptohome_client.h"
22#include "chromeos/dbus/dbus_client_implementation_type.h"
23#include "chromeos/dbus/dbus_thread_manager_observer.h"
24#include "chromeos/dbus/debug_daemon_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 = base::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    bluetooth_adapter_client_.reset(
87        BluetoothAdapterClient::Create(client_type_, system_bus_.get()));
88    bluetooth_agent_manager_client_.reset(
89        BluetoothAgentManagerClient::Create(client_type_, system_bus_.get()));
90    bluetooth_device_client_.reset(
91        BluetoothDeviceClient::Create(client_type_, system_bus_.get()));
92    bluetooth_input_client_.reset(
93        BluetoothInputClient::Create(client_type_, system_bus_.get()));
94    bluetooth_profile_manager_client_.reset(
95        BluetoothProfileManagerClient::Create(client_type_, system_bus_.get()));
96    cras_audio_client_.reset(CrasAudioClient::Create(
97        client_type_, system_bus_.get()));
98    cros_disks_client_.reset(
99        CrosDisksClient::Create(client_type_, system_bus_.get()));
100    cryptohome_client_.reset(
101        CryptohomeClient::Create(client_type_, system_bus_.get()));
102    debug_daemon_client_.reset(
103        DebugDaemonClient::Create(client_type_, system_bus_.get()));
104
105    shill_manager_client_.reset(
106        ShillManagerClient::Create(client_type_override_, system_bus_.get()));
107    shill_device_client_.reset(
108        ShillDeviceClient::Create(client_type_override_, system_bus_.get()));
109    shill_ipconfig_client_.reset(
110        ShillIPConfigClient::Create(client_type_override_, system_bus_.get()));
111    shill_profile_client_.reset(
112        ShillProfileClient::Create(client_type_override_, system_bus_.get()));
113    shill_service_client_.reset(
114        ShillServiceClient::Create(client_type_override_, system_bus_.get()));
115    gsm_sms_client_.reset(
116        GsmSMSClient::Create(client_type_override_, system_bus_.get()));
117
118    image_burner_client_.reset(ImageBurnerClient::Create(client_type_,
119                                                         system_bus_.get()));
120    introspectable_client_.reset(
121        IntrospectableClient::Create(client_type_, system_bus_.get()));
122    modem_messaging_client_.reset(
123        ModemMessagingClient::Create(client_type_, system_bus_.get()));
124    permission_broker_client_.reset(
125        PermissionBrokerClient::Create(client_type_, system_bus_.get()));
126    power_manager_client_.reset(
127        PowerManagerClient::Create(client_type_override_, system_bus_.get()));
128    session_manager_client_.reset(
129        SessionManagerClient::Create(client_type_, system_bus_.get()));
130    sms_client_.reset(
131        SMSClient::Create(client_type_, system_bus_.get()));
132    system_clock_client_.reset(
133        SystemClockClient::Create(client_type_, system_bus_.get()));
134    update_engine_client_.reset(
135        UpdateEngineClient::Create(client_type_, system_bus_.get()));
136
137    // PowerPolicyController is dependent on PowerManagerClient, so
138    // initialize it after the main list of clients.
139    power_policy_controller_.reset(
140        new PowerPolicyController(this, power_manager_client_.get()));
141
142    // This must be called after the list of clients so they've each had a
143    // chance to register with their object managers.
144    system_bus_->GetManagedObjects();
145  }
146
147  virtual ~DBusThreadManagerImpl() {
148    FOR_EACH_OBSERVER(DBusThreadManagerObserver, observers_,
149                      OnDBusThreadManagerDestroying(this));
150
151    // Shut down the bus. During the browser shutdown, it's ok to shut down
152    // the bus synchronously.
153    system_bus_->ShutdownOnDBusThreadAndBlock();
154    if (ibus_bus_.get())
155      ibus_bus_->ShutdownOnDBusThreadAndBlock();
156
157    // Release IBusEngineService instances.
158    for (std::map<dbus::ObjectPath, IBusEngineService*>::iterator it
159            = ibus_engine_services_.begin();
160         it != ibus_engine_services_.end(); it++) {
161      delete it->second;
162    }
163
164    // Stop the D-Bus thread.
165    dbus_thread_->Stop();
166  }
167
168  // DBusThreadManager override.
169  virtual void AddObserver(DBusThreadManagerObserver* observer) OVERRIDE {
170    DCHECK(observer);
171    observers_.AddObserver(observer);
172  }
173
174  // DBusThreadManager override.
175  virtual void RemoveObserver(DBusThreadManagerObserver* observer) OVERRIDE {
176    DCHECK(observer);
177    observers_.RemoveObserver(observer);
178  }
179
180  // DBusThreadManager override.
181  virtual void InitIBusBus(
182      const std::string &ibus_address,
183      const base::Closure& on_disconnected_callback) OVERRIDE {
184    DCHECK(!ibus_bus_.get());
185    dbus::Bus::Options ibus_bus_options;
186    ibus_bus_options.bus_type = dbus::Bus::CUSTOM_ADDRESS;
187    ibus_bus_options.address = ibus_address;
188    ibus_bus_options.connection_type = dbus::Bus::PRIVATE;
189    ibus_bus_options.dbus_task_runner = dbus_thread_->message_loop_proxy();
190    ibus_bus_options.disconnected_callback = on_disconnected_callback;
191    ibus_bus_ = new dbus::Bus(ibus_bus_options);
192    ibus_address_ = ibus_address;
193    VLOG(1) << "Connected to ibus-daemon: " << ibus_address;
194
195    DBusClientImplementationType client_type =
196        base::chromeos::IsRunningOnChromeOS() ? REAL_DBUS_CLIENT_IMPLEMENTATION
197                                              : STUB_DBUS_CLIENT_IMPLEMENTATION;
198
199    ibus_client_.reset(
200        IBusClient::Create(client_type, ibus_bus_.get()));
201    ibus_config_client_.reset(
202        IBusConfigClient::Create(client_type, ibus_bus_.get()));
203    ibus_input_context_client_.reset(
204        IBusInputContextClient::Create(client_type));
205    ibus_engine_factory_service_.reset(
206        IBusEngineFactoryService::Create(ibus_bus_.get(), client_type));
207    ibus_panel_service_.reset(
208        IBusPanelService::Create(client_type,
209                                 ibus_bus_.get(),
210                                 ibus_input_context_client_.get()));
211
212    ibus_engine_services_.clear();
213  }
214
215  // DBusThreadManager overrides:
216  virtual dbus::Bus* GetSystemBus() OVERRIDE {
217    return system_bus_.get();
218  }
219
220  virtual dbus::Bus* GetIBusBus() OVERRIDE {
221    return ibus_bus_.get();
222  }
223
224  virtual BluetoothAdapterClient* GetBluetoothAdapterClient() OVERRIDE {
225    return bluetooth_adapter_client_.get();
226  }
227
228  virtual BluetoothAgentManagerClient* GetBluetoothAgentManagerClient()
229      OVERRIDE {
230    return bluetooth_agent_manager_client_.get();
231  }
232
233  virtual BluetoothDeviceClient* GetBluetoothDeviceClient() OVERRIDE {
234    return bluetooth_device_client_.get();
235  }
236
237  virtual BluetoothInputClient* GetBluetoothInputClient() OVERRIDE {
238    return bluetooth_input_client_.get();
239  }
240
241  virtual BluetoothProfileManagerClient* GetBluetoothProfileManagerClient()
242      OVERRIDE {
243    return bluetooth_profile_manager_client_.get();
244  }
245
246  virtual CrasAudioClient* GetCrasAudioClient() OVERRIDE {
247    return cras_audio_client_.get();
248  }
249
250  virtual CrosDisksClient* GetCrosDisksClient() OVERRIDE {
251    return cros_disks_client_.get();
252  }
253
254  virtual CryptohomeClient* GetCryptohomeClient() OVERRIDE {
255    return cryptohome_client_.get();
256  }
257
258  virtual DebugDaemonClient* GetDebugDaemonClient() OVERRIDE {
259    return debug_daemon_client_.get();
260  }
261
262  virtual ShillDeviceClient* GetShillDeviceClient() OVERRIDE {
263    return shill_device_client_.get();
264  }
265
266  virtual ShillIPConfigClient* GetShillIPConfigClient() OVERRIDE {
267    return shill_ipconfig_client_.get();
268  }
269
270  virtual ShillManagerClient* GetShillManagerClient() OVERRIDE {
271    return shill_manager_client_.get();
272  }
273
274  virtual ShillProfileClient* GetShillProfileClient() OVERRIDE {
275    return shill_profile_client_.get();
276  }
277
278  virtual ShillServiceClient* GetShillServiceClient() OVERRIDE {
279    return shill_service_client_.get();
280  }
281
282  virtual GsmSMSClient* GetGsmSMSClient() OVERRIDE {
283    return gsm_sms_client_.get();
284  }
285
286  virtual ImageBurnerClient* GetImageBurnerClient() OVERRIDE {
287    return image_burner_client_.get();
288  }
289
290  virtual IntrospectableClient* GetIntrospectableClient() OVERRIDE {
291    return introspectable_client_.get();
292  }
293
294  virtual ModemMessagingClient* GetModemMessagingClient() OVERRIDE {
295    return modem_messaging_client_.get();
296  }
297
298  virtual PermissionBrokerClient* GetPermissionBrokerClient() OVERRIDE {
299    return permission_broker_client_.get();
300  }
301
302  virtual PowerManagerClient* GetPowerManagerClient() OVERRIDE {
303    return power_manager_client_.get();
304  }
305
306  virtual PowerPolicyController* GetPowerPolicyController() OVERRIDE {
307    return power_policy_controller_.get();
308  }
309
310  virtual SessionManagerClient* GetSessionManagerClient() OVERRIDE {
311    return session_manager_client_.get();
312  }
313
314  virtual SMSClient* GetSMSClient() OVERRIDE {
315    return sms_client_.get();
316  }
317
318  virtual SystemClockClient* GetSystemClockClient() OVERRIDE {
319    return system_clock_client_.get();
320  }
321
322  virtual UpdateEngineClient* GetUpdateEngineClient() OVERRIDE {
323    return update_engine_client_.get();
324  }
325
326  virtual IBusClient* GetIBusClient() OVERRIDE {
327    return ibus_client_.get();
328  }
329
330  virtual IBusConfigClient* GetIBusConfigClient() OVERRIDE {
331    return ibus_config_client_.get();
332  }
333
334  virtual IBusInputContextClient* GetIBusInputContextClient() OVERRIDE {
335    return ibus_input_context_client_.get();
336  }
337
338  virtual IBusEngineFactoryService* GetIBusEngineFactoryService() OVERRIDE {
339    return ibus_engine_factory_service_.get();
340  }
341
342  virtual IBusEngineService* GetIBusEngineService(
343      const dbus::ObjectPath& object_path) OVERRIDE {
344    const DBusClientImplementationType client_type =
345        base::chromeos::IsRunningOnChromeOS() ? REAL_DBUS_CLIENT_IMPLEMENTATION
346                                              : STUB_DBUS_CLIENT_IMPLEMENTATION;
347
348    if (ibus_engine_services_.find(object_path)
349            == ibus_engine_services_.end()) {
350      ibus_engine_services_[object_path] =
351          IBusEngineService::Create(client_type, ibus_bus_.get(), object_path);
352    }
353    return ibus_engine_services_[object_path];
354  }
355
356  virtual void RemoveIBusEngineService(
357      const dbus::ObjectPath& object_path) OVERRIDE {
358    if (ibus_engine_services_.find(object_path) !=
359        ibus_engine_services_.end()) {
360      LOG(WARNING) << "Object path not found: " << object_path.value();
361      return;
362    }
363    delete ibus_engine_services_[object_path];
364    ibus_engine_services_.erase(object_path);
365  }
366
367  virtual IBusPanelService* GetIBusPanelService() OVERRIDE {
368    return ibus_panel_service_.get();
369  }
370
371  DBusClientImplementationType client_type_;
372  DBusClientImplementationType client_type_override_;
373
374  // Note: Keep this before other members so they can call AddObserver() in
375  // their c'tors.
376  ObserverList<DBusThreadManagerObserver> observers_;
377
378  scoped_ptr<base::Thread> dbus_thread_;
379  scoped_refptr<dbus::Bus> system_bus_;
380  scoped_refptr<dbus::Bus> ibus_bus_;
381  scoped_ptr<BluetoothAdapterClient> bluetooth_adapter_client_;
382  scoped_ptr<BluetoothAgentManagerClient> bluetooth_agent_manager_client_;
383  scoped_ptr<BluetoothDeviceClient> bluetooth_device_client_;
384  scoped_ptr<BluetoothInputClient> bluetooth_input_client_;
385  scoped_ptr<BluetoothProfileManagerClient> bluetooth_profile_manager_client_;
386  scoped_ptr<CrasAudioClient> cras_audio_client_;
387  scoped_ptr<CrosDisksClient> cros_disks_client_;
388  scoped_ptr<CryptohomeClient> cryptohome_client_;
389  scoped_ptr<DebugDaemonClient> debug_daemon_client_;
390  scoped_ptr<ShillDeviceClient> shill_device_client_;
391  scoped_ptr<ShillIPConfigClient> shill_ipconfig_client_;
392  scoped_ptr<ShillManagerClient> shill_manager_client_;
393  scoped_ptr<ShillProfileClient> shill_profile_client_;
394  scoped_ptr<ShillServiceClient> shill_service_client_;
395  scoped_ptr<GsmSMSClient> gsm_sms_client_;
396  scoped_ptr<ImageBurnerClient> image_burner_client_;
397  scoped_ptr<IntrospectableClient> introspectable_client_;
398  scoped_ptr<ModemMessagingClient> modem_messaging_client_;
399  scoped_ptr<PermissionBrokerClient> permission_broker_client_;
400  scoped_ptr<SystemClockClient> system_clock_client_;
401  scoped_ptr<PowerManagerClient> power_manager_client_;
402  scoped_ptr<SessionManagerClient> session_manager_client_;
403  scoped_ptr<SMSClient> sms_client_;
404  scoped_ptr<UpdateEngineClient> update_engine_client_;
405  scoped_ptr<IBusClient> ibus_client_;
406  scoped_ptr<IBusConfigClient> ibus_config_client_;
407  scoped_ptr<IBusInputContextClient> ibus_input_context_client_;
408  scoped_ptr<IBusEngineFactoryService> ibus_engine_factory_service_;
409  std::map<dbus::ObjectPath, IBusEngineService*> ibus_engine_services_;
410  scoped_ptr<IBusPanelService> ibus_panel_service_;
411  scoped_ptr<PowerPolicyController> power_policy_controller_;
412
413  std::string ibus_address_;
414};
415
416// static
417void DBusThreadManager::Initialize() {
418  // Ignore Initialize() if we set a test DBusThreadManager.
419  if (g_dbus_thread_manager_set_for_testing)
420    return;
421  // If we initialize DBusThreadManager twice we may also be shutting it down
422  // early; do not allow that.
423  CHECK(g_dbus_thread_manager == NULL);
424  // Determine whether we use stub or real client implementations.
425  DBusThreadManagerImpl* dbus_thread_manager_impl;
426  if (base::chromeos::IsRunningOnChromeOS()) {
427    dbus_thread_manager_impl =
428        new DBusThreadManagerImpl(REAL_DBUS_CLIENT_IMPLEMENTATION);
429    VLOG(1) << "DBusThreadManager initialized for ChromeOS";
430  } else {
431    dbus_thread_manager_impl =
432        new DBusThreadManagerImpl(STUB_DBUS_CLIENT_IMPLEMENTATION);
433    VLOG(1) << "DBusThreadManager initialized with Stub";
434  }
435  g_dbus_thread_manager = dbus_thread_manager_impl;
436  dbus_thread_manager_impl->InitializeClients();
437}
438
439// static
440void DBusThreadManager::InitializeForTesting(
441    DBusThreadManager* dbus_thread_manager) {
442  // If we initialize DBusThreadManager twice we may also be shutting it down
443  // early; do not allow that.
444  CHECK(g_dbus_thread_manager == NULL);
445  CHECK(dbus_thread_manager);
446  g_dbus_thread_manager = dbus_thread_manager;
447  g_dbus_thread_manager_set_for_testing = true;
448  VLOG(1) << "DBusThreadManager initialized with test implementation";
449}
450
451// static
452void DBusThreadManager::InitializeWithStub() {
453  // If we initialize DBusThreadManager twice we may also be shutting it down
454  // early; do not allow that.
455  CHECK(g_dbus_thread_manager == NULL);
456  DBusThreadManagerImpl* dbus_thread_manager_impl =
457      new DBusThreadManagerImpl(STUB_DBUS_CLIENT_IMPLEMENTATION);
458  g_dbus_thread_manager = dbus_thread_manager_impl;
459  dbus_thread_manager_impl->InitializeClients();
460  VLOG(1) << "DBusThreadManager initialized with stub implementation";
461}
462
463// static
464bool DBusThreadManager::IsInitialized() {
465  return g_dbus_thread_manager != NULL;
466}
467
468// static
469void DBusThreadManager::Shutdown() {
470  // If we called InitializeForTesting, this may get called more than once.
471  // Ensure that we only shutdown DBusThreadManager once.
472  CHECK(g_dbus_thread_manager || g_dbus_thread_manager_set_for_testing);
473  DBusThreadManager* dbus_thread_manager = g_dbus_thread_manager;
474  g_dbus_thread_manager = NULL;
475  delete dbus_thread_manager;
476  VLOG(1) << "DBusThreadManager Shutdown completed";
477}
478
479DBusThreadManager::DBusThreadManager() {
480  dbus::statistics::Initialize();
481}
482
483DBusThreadManager::~DBusThreadManager() {
484  dbus::statistics::Shutdown();
485  if (g_dbus_thread_manager == NULL)
486    return;  // Called form Shutdown() or local test instance.
487  // There should never be both a global instance and a local instance.
488  CHECK(this == g_dbus_thread_manager);
489  if (g_dbus_thread_manager_set_for_testing) {
490    g_dbus_thread_manager = NULL;
491    g_dbus_thread_manager_set_for_testing = false;
492    VLOG(1) << "DBusThreadManager destroyed";
493  } else {
494    LOG(FATAL) << "~DBusThreadManager() called outside of Shutdown()";
495  }
496}
497
498// static
499DBusThreadManager* DBusThreadManager::Get() {
500  CHECK(g_dbus_thread_manager)
501      << "DBusThreadManager::Get() called before Initialize()";
502  return g_dbus_thread_manager;
503}
504
505}  // namespace chromeos
506