// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/dbus/services/cros_dbus_service.h"

#include <stddef.h>

#include <memory>
#include <utility>

#include "base/bind.h"
#include "base/stl_util.h"
#include "base/system/sys_info.h"
#include "dbus/bus.h"
#include "dbus/exported_object.h"
#include "dbus/object_path.h"

namespace chromeos {

// The CrosDBusService implementation used in production, and unit tests.
class CrosDBusServiceImpl : public CrosDBusService {
 public:
  CrosDBusServiceImpl(dbus::Bus* bus,
                      const std::string& service_name,
                      const dbus::ObjectPath& object_path,
                      ServiceProviderList service_providers)
      : service_started_(false),
        origin_thread_id_(base::PlatformThread::CurrentId()),
        bus_(bus),
        service_name_(service_name),
        object_path_(object_path),
        service_providers_(std::move(service_providers)) {
    DCHECK(bus);
    DCHECK(!service_name_.empty());
    DCHECK(object_path_.IsValid());
  }

  ~CrosDBusServiceImpl() override = default;

  // Starts the D-Bus service.
  void Start() {
    // Make sure we're running on the origin thread (i.e. the UI thread in
    // production).
    DCHECK(OnOriginThread());
    DCHECK(!service_started_);

    // Methods must be exported before RequestOwnership is called:
    // https://crbug.com/874978
    exported_object_ = bus_->GetExportedObject(object_path_);
    for (const auto& provider : service_providers_)
      provider->Start(exported_object_);

    // There are some situations, described in http://crbug.com/234382#c27,
    // where processes on Linux can wind up stuck in an uninterruptible state
    // for tens of seconds. If this happens when Chrome is trying to exit, this
    // unkillable process can wind up clinging to ownership of |service_name_|
    // while the system is trying to restart the browser. This leads to a fatal
    // situation if we don't allow the new browser instance to replace the old
    // as the owner of |service_name_| as seen in http://crbug.com/234382.
    // Hence, REQUIRE_PRIMARY_ALLOW_REPLACEMENT.
    bus_->RequestOwnership(
        service_name_, dbus::Bus::REQUIRE_PRIMARY_ALLOW_REPLACEMENT,
        base::Bind(&CrosDBusServiceImpl::OnOwnership, base::Unretained(this)));

    service_started_ = true;
  }

 private:
  // Returns true if the current thread is on the origin thread.
  bool OnOriginThread() {
    return base::PlatformThread::CurrentId() == origin_thread_id_;
  }

  // Called when an ownership request is completed.
  void OnOwnership(const std::string& service_name,
                   bool success) {
    LOG_IF(FATAL, !success) << "Failed to own: " << service_name;
  }

  bool service_started_;
  base::PlatformThreadId origin_thread_id_;
  dbus::Bus* bus_;
  std::string service_name_;
  dbus::ObjectPath object_path_;
  scoped_refptr<dbus::ExportedObject> exported_object_;

  // Service providers that form CrosDBusService.
  ServiceProviderList service_providers_;

  DISALLOW_COPY_AND_ASSIGN(CrosDBusServiceImpl);
};

// The stub CrosDBusService implementation used on Linux desktop,
// which does nothing as of now.
class CrosDBusServiceStubImpl : public CrosDBusService {
 public:
  CrosDBusServiceStubImpl() = default;
  ~CrosDBusServiceStubImpl() override = default;

 private:
  DISALLOW_COPY_AND_ASSIGN(CrosDBusServiceStubImpl);
};

// static
std::unique_ptr<CrosDBusService> CrosDBusService::Create(
    dbus::Bus* system_bus,
    const std::string& service_name,
    const dbus::ObjectPath& object_path,
    ServiceProviderList service_providers) {
  if (!system_bus)
    return std::make_unique<CrosDBusServiceStubImpl>();

  return CreateRealImpl(system_bus, service_name, object_path,
                        std::move(service_providers));
}

// static
CrosDBusService::ServiceProviderList CrosDBusService::CreateServiceProviderList(
    std::unique_ptr<ServiceProviderInterface> provider) {
  ServiceProviderList list;
  list.push_back(std::move(provider));
  return list;
}

// static
std::unique_ptr<CrosDBusService> CrosDBusService::CreateRealImpl(
    dbus::Bus* bus,
    const std::string& service_name,
    const dbus::ObjectPath& object_path,
    ServiceProviderList service_providers) {
  auto service = std::make_unique<CrosDBusServiceImpl>(
      bus, service_name, object_path, std::move(service_providers));
  service->Start();
  return std::move(service);
}

CrosDBusService::~CrosDBusService() = default;

CrosDBusService::CrosDBusService() = default;

CrosDBusService::ServiceProviderInterface::~ServiceProviderInterface() =
    default;

}  // namespace chromeos
