Home | History | Annotate | Download | only in dbus
      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/chromeos/chromeos_version.h"
      9 #include "base/stl_util.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::chromeos::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