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