chromium/chromecast/browser/service_connector.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromecast/browser/service_connector.h"

#include "base/functional/bind.h"
#include "base/logging.h"
#include "chromecast/browser/system_connector.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"

namespace chromecast {

namespace {

ServiceConnector* g_instance = nullptr;

}  // namespace

const ServiceConnectorClientId kBrowserProcessClientId =
    ServiceConnectorClientId::FromUnsafeValue(1);

const ServiceConnectorClientId kMediaServiceClientId =
    ServiceConnectorClientId::FromUnsafeValue(2);

ServiceConnector::ServiceConnector() {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  DCHECK(!g_instance);
  g_instance = this;
}

ServiceConnector::~ServiceConnector() {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  DCHECK_EQ(this, g_instance);
  g_instance = nullptr;
}

// static
mojo::PendingRemote<mojom::ServiceConnector> ServiceConnector::MakeRemote(
    ServiceConnectorClientId client_id) {
  DCHECK(g_instance);
  mojo::PendingRemote<mojom::ServiceConnector> remote;
  BindReceiver(client_id, remote.InitWithNewPipeAndPassReceiver());
  return remote;
}

// static
void ServiceConnector::BindReceiver(
    ServiceConnectorClientId client_id,
    mojo::PendingReceiver<mojom::ServiceConnector> receiver) {
  if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
    content::GetUIThreadTaskRunner({})->PostTask(
        FROM_HERE, base::BindOnce(&ServiceConnector::BindReceiver, client_id,
                                  std::move(receiver)));
    return;
  }

  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  DCHECK(g_instance);
  g_instance->receivers_.Add(g_instance, std::move(receiver), client_id);
}

void ServiceConnector::Connect(const std::string& service_name,
                               mojo::GenericPendingReceiver receiver) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

  const ServiceConnectorClientId client_id = receivers_.current_context();

  // If the client is browser code, forward indscriminately through the Service
  // Manager. The browser generally has access unfettered to everything.
  if (client_id == kBrowserProcessClientId) {
    auto interface_name = *receiver.interface_name();
    GetSystemConnector()->BindInterface(
        service_manager::ServiceFilter::ByName(service_name), interface_name,
        receiver.PassPipe());
    return;
  }

  LOG(ERROR) << "Client " << client_id.GetUnsafeValue() << " attempted to bind "
             << *receiver.interface_name() << " in inaccessible service "
             << service_name;
}

}  // namespace chromecast