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: 32 explicit CrosDBusServiceImpl(dbus::Bus* bus) 33 : service_started_(false), 34 origin_thread_id_(base::PlatformThread::CurrentId()), 35 bus_(bus) { 36 } 37 38 virtual ~CrosDBusServiceImpl() { 39 STLDeleteElements(&service_providers_); 40 } 41 42 // Starts the D-Bus service. 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. 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. 84 bool OnOriginThread() { 85 return base::PlatformThread::CurrentId() == origin_thread_id_; 86 } 87 88 // Called when an ownership request is completed. 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: 107 CrosDBusServiceStubImpl() { 108 } 109 110 virtual ~CrosDBusServiceStubImpl() { 111 } 112 }; 113 114 // static 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 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 151 void CrosDBusService::Shutdown() { 152 delete g_cros_dbus_service; 153 g_cros_dbus_service = NULL; 154 VLOG(1) << "CrosDBusService Shutdown completed"; 155 } 156 157 CrosDBusService::~CrosDBusService() { 158 } 159 160 CrosDBusService::ServiceProviderInterface::~ServiceProviderInterface() { 161 } 162 163 } // namespace chromeos 164