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 "chrome/browser/chromeos/dbus/cros_dbus_service.h"
6
7 #include "base/bind.h"
8 #include "base/stl_util.h"
9 #include "base/sys_info.h"
10 #include "base/threading/platform_thread.h"
11 #include "chrome/browser/chromeos/dbus/display_power_service_provider.h"
12 #include "chrome/browser/chromeos/dbus/liveness_service_provider.h"
13 #include "chrome/browser/chromeos/dbus/printer_service_provider.h"
14 #include "chrome/browser/chromeos/dbus/proxy_resolution_service_provider.h"
15 #include "chromeos/dbus/dbus_thread_manager.h"
16 #include "dbus/bus.h"
17 #include "dbus/exported_object.h"
18 #include "dbus/object_path.h"
19 #include "third_party/cros_system_api/dbus/service_constants.h"
20
21 namespace chromeos {
22
23 namespace {
24
25 CrosDBusService* g_cros_dbus_service = NULL;
26
27 } // namespace
28
29 // The CrosDBusService implementation used in production, and unit tests.
30 class CrosDBusServiceImpl : public CrosDBusService {
31 public:
CrosDBusServiceImpl(dbus::Bus * bus)32 explicit CrosDBusServiceImpl(dbus::Bus* bus)
33 : service_started_(false),
34 origin_thread_id_(base::PlatformThread::CurrentId()),
35 bus_(bus) {
36 }
37
~CrosDBusServiceImpl()38 virtual ~CrosDBusServiceImpl() {
39 STLDeleteElements(&service_providers_);
40 }
41
42 // Starts the D-Bus service.
Start()43 void Start() {
44 // Make sure we're running on the origin thread (i.e. the UI thread in
45 // production).
46 DCHECK(OnOriginThread());
47
48 // Return if the service has been already started.
49 if (service_started_)
50 return;
51
52 // There are some situations, described in http://crbug.com/234382#c27,
53 // where processes on Linux can wind up stuck in an uninterruptible state
54 // for tens of seconds. If this happens when Chrome is trying to exit,
55 // this unkillable process can wind up clinging to ownership of
56 // kLibCrosServiceName while the system is trying to restart the browser.
57 // This leads to a fatal situation if we don't allow the new browser
58 // instance to replace the old as the owner of kLibCrosServiceName as seen
59 // in http://crbug.com/234382. Hence, REQUIRE_PRIMARY_ALLOW_REPLACEMENT.
60 bus_->RequestOwnership(kLibCrosServiceName,
61 dbus::Bus::REQUIRE_PRIMARY_ALLOW_REPLACEMENT,
62 base::Bind(&CrosDBusServiceImpl::OnOwnership,
63 base::Unretained(this)));
64
65 exported_object_ = bus_->GetExportedObject(
66 dbus::ObjectPath(kLibCrosServicePath));
67
68 for (size_t i = 0; i < service_providers_.size(); ++i)
69 service_providers_[i]->Start(exported_object_);
70
71 service_started_ = true;
72
73 VLOG(1) << "CrosDBusServiceImpl started.";
74 }
75
76 // Registers a service provider. This must be done before Start().
77 // |provider| will be owned by CrosDBusService.
RegisterServiceProvider(ServiceProviderInterface * provider)78 void RegisterServiceProvider(ServiceProviderInterface* provider) {
79 service_providers_.push_back(provider);
80 }
81
82 private:
83 // Returns true if the current thread is on the origin thread.
OnOriginThread()84 bool OnOriginThread() {
85 return base::PlatformThread::CurrentId() == origin_thread_id_;
86 }
87
88 // Called when an ownership request is completed.
OnOwnership(const std::string & service_name,bool success)89 void OnOwnership(const std::string& service_name,
90 bool success) {
91 LOG_IF(FATAL, !success) << "Failed to own: " << service_name;
92 }
93
94 bool service_started_;
95 base::PlatformThreadId origin_thread_id_;
96 dbus::Bus* bus_;
97 scoped_refptr<dbus::ExportedObject> exported_object_;
98
99 // Service providers that form CrosDBusService.
100 std::vector<ServiceProviderInterface*> service_providers_;
101 };
102
103 // The stub CrosDBusService implementation used on Linux desktop,
104 // which does nothing as of now.
105 class CrosDBusServiceStubImpl : public CrosDBusService {
106 public:
CrosDBusServiceStubImpl()107 CrosDBusServiceStubImpl() {
108 }
109
~CrosDBusServiceStubImpl()110 virtual ~CrosDBusServiceStubImpl() {
111 }
112 };
113
114 // static
Initialize()115 void CrosDBusService::Initialize() {
116 if (g_cros_dbus_service) {
117 LOG(WARNING) << "CrosDBusService was already initialized";
118 return;
119 }
120 dbus::Bus* bus = DBusThreadManager::Get()->GetSystemBus();
121 if (base::SysInfo::IsRunningOnChromeOS() && bus) {
122 CrosDBusServiceImpl* service = new CrosDBusServiceImpl(bus);
123 service->RegisterServiceProvider(ProxyResolutionServiceProvider::Create());
124 service->RegisterServiceProvider(new DisplayPowerServiceProvider);
125 service->RegisterServiceProvider(new LivenessServiceProvider);
126 service->RegisterServiceProvider(new PrinterServiceProvider);
127 g_cros_dbus_service = service;
128 service->Start();
129 } else {
130 g_cros_dbus_service = new CrosDBusServiceStubImpl;
131 }
132 VLOG(1) << "CrosDBusService initialized";
133 }
134
135 // static
InitializeForTesting(dbus::Bus * bus,ServiceProviderInterface * proxy_resolution_service)136 void CrosDBusService::InitializeForTesting(
137 dbus::Bus* bus,
138 ServiceProviderInterface* proxy_resolution_service) {
139 if (g_cros_dbus_service) {
140 LOG(WARNING) << "CrosDBusService was already initialized";
141 return;
142 }
143 CrosDBusServiceImpl* service = new CrosDBusServiceImpl(bus);
144 service->RegisterServiceProvider(proxy_resolution_service);
145 service->Start();
146 g_cros_dbus_service = service;
147 VLOG(1) << "CrosDBusService initialized";
148 }
149
150 // static
Shutdown()151 void CrosDBusService::Shutdown() {
152 delete g_cros_dbus_service;
153 g_cros_dbus_service = NULL;
154 VLOG(1) << "CrosDBusService Shutdown completed";
155 }
156
~CrosDBusService()157 CrosDBusService::~CrosDBusService() {
158 }
159
~ServiceProviderInterface()160 CrosDBusService::ServiceProviderInterface::~ServiceProviderInterface() {
161 }
162
163 } // namespace chromeos
164