15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/dbus/cros_dbus_service.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/sys_info.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/dbus/display_power_service_provider.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/dbus/liveness_service_provider.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/dbus/printer_service_provider.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/dbus/proxy_resolution_service_provider.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/dbus/dbus_thread_manager.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/bus.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/exported_object.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/object_path.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/cros_system_api/dbus/service_constants.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CrosDBusService* g_cros_dbus_service = NULL;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The CrosDBusService implementation used in production, and unit tests.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CrosDBusServiceImpl : public CrosDBusService {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit CrosDBusServiceImpl(dbus::Bus* bus)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : service_started_(false),
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        origin_thread_id_(base::PlatformThread::CurrentId()),
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bus_(bus) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~CrosDBusServiceImpl() {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STLDeleteElements(&service_providers_);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Starts the D-Bus service.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Start() {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make sure we're running on the origin thread (i.e. the UI thread in
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // production).
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(OnOriginThread());
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Return if the service has been already started.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (service_started_)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // There are some situations, described in http://crbug.com/234382#c27,
53a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // where processes on Linux can wind up stuck in an uninterruptible state
54a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // for tens of seconds. If this happens when Chrome is trying to exit,
55a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // this unkillable process can wind up clinging to ownership of
56a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // kLibCrosServiceName while the system is trying to restart the browser.
57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // This leads to a fatal situation if we don't allow the new browser
58a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // instance to replace the old as the owner of kLibCrosServiceName as seen
59a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // in http://crbug.com/234382. Hence, REQUIRE_PRIMARY_ALLOW_REPLACEMENT.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bus_->RequestOwnership(kLibCrosServiceName,
61a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                           dbus::Bus::REQUIRE_PRIMARY_ALLOW_REPLACEMENT,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           base::Bind(&CrosDBusServiceImpl::OnOwnership,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      base::Unretained(this)));
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    exported_object_ = bus_->GetExportedObject(
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dbus::ObjectPath(kLibCrosServicePath));
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < service_providers_.size(); ++i)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      service_providers_[i]->Start(exported_object_);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    service_started_ = true;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "CrosDBusServiceImpl started.";
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Registers a service provider. This must be done before Start().
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |provider| will be owned by CrosDBusService.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RegisterServiceProvider(ServiceProviderInterface* provider) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    service_providers_.push_back(provider);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if the current thread is on the origin thread.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool OnOriginThread() {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return base::PlatformThread::CurrentId() == origin_thread_id_;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called when an ownership request is completed.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnOwnership(const std::string& service_name,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   bool success) {
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG_IF(FATAL, !success) << "Failed to own: " << service_name;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool service_started_;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PlatformThreadId origin_thread_id_;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dbus::Bus* bus_;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<dbus::ExportedObject> exported_object_;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Service providers that form CrosDBusService.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<ServiceProviderInterface*> service_providers_;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The stub CrosDBusService implementation used on Linux desktop,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// which does nothing as of now.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CrosDBusServiceStubImpl : public CrosDBusService {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CrosDBusServiceStubImpl() {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~CrosDBusServiceStubImpl() {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CrosDBusService::Initialize() {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_cros_dbus_service) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "CrosDBusService was already initialized";
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dbus::Bus* bus = DBusThreadManager::Get()->GetSystemBus();
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (base::SysInfo::IsRunningOnChromeOS() && bus) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CrosDBusServiceImpl* service = new CrosDBusServiceImpl(bus);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    service->RegisterServiceProvider(ProxyResolutionServiceProvider::Create());
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    service->RegisterServiceProvider(new DisplayPowerServiceProvider);
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    service->RegisterServiceProvider(new LivenessServiceProvider);
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    service->RegisterServiceProvider(new PrinterServiceProvider);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_cros_dbus_service = service;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    service->Start();
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_cros_dbus_service = new CrosDBusServiceStubImpl;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CrosDBusService initialized";
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CrosDBusService::InitializeForTesting(
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dbus::Bus* bus,
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ServiceProviderInterface* proxy_resolution_service) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_cros_dbus_service) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "CrosDBusService was already initialized";
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CrosDBusServiceImpl* service =  new CrosDBusServiceImpl(bus);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service->RegisterServiceProvider(proxy_resolution_service);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service->Start();
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_cros_dbus_service = service;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CrosDBusService initialized";
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CrosDBusService::Shutdown() {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete g_cros_dbus_service;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_cros_dbus_service = NULL;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CrosDBusService Shutdown completed";
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CrosDBusService::~CrosDBusService() {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CrosDBusService::ServiceProviderInterface::~ServiceProviderInterface() {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chromeos
164