blob: fac2b599495a3e60026f18248f510ff28f8ffe99 [file] [log] [blame]
// Copyright 2016 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 "components/nacl/common/nacl_service.h"
#include <memory>
#include <string>
#include "base/command_line.h"
#include "content/public/common/service_names.mojom.h"
#include "ipc/ipc.mojom.h"
#include "mojo/core/embedder/scoped_ipc_support.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/platform/platform_channel_endpoint.h"
#include "mojo/public/cpp/platform/platform_handle.h"
#include "mojo/public/cpp/system/invitation.h"
#include "services/service_manager/embedder/switches.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_context.h"
#if defined(OS_POSIX)
#include "base/files/scoped_file.h"
#include "base/posix/global_descriptors.h"
#include "services/service_manager/embedder/descriptors.h"
#endif
namespace {
mojo::IncomingInvitation EstablishMojoConnection() {
mojo::PlatformChannelEndpoint endpoint;
#if defined(OS_WIN)
endpoint = mojo::PlatformChannel::RecoverPassedEndpointFromCommandLine(
*base::CommandLine::ForCurrentProcess());
#else
endpoint = mojo::PlatformChannelEndpoint(mojo::PlatformHandle(
base::ScopedFD(base::GlobalDescriptors::GetInstance()->Get(
service_manager::kMojoIPCChannel))));
#endif
DCHECK(endpoint.is_valid());
return mojo::IncomingInvitation::Accept(std::move(endpoint));
}
service_manager::mojom::ServiceRequest ConnectToServiceManager(
mojo::IncomingInvitation* invitation) {
const std::string service_request_channel_token =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
service_manager::switches::kServiceRequestChannelToken);
DCHECK(!service_request_channel_token.empty());
mojo::ScopedMessagePipeHandle parent_handle =
invitation->ExtractMessagePipe(service_request_channel_token);
DCHECK(parent_handle.is_valid());
return service_manager::mojom::ServiceRequest(std::move(parent_handle));
}
class NaClService : public service_manager::Service {
public:
NaClService(IPC::mojom::ChannelBootstrapPtrInfo bootstrap,
std::unique_ptr<mojo::core::ScopedIPCSupport> ipc_support);
~NaClService() override;
// Service overrides.
void OnBindInterface(const service_manager::BindSourceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) override;
private:
IPC::mojom::ChannelBootstrapPtrInfo ipc_channel_bootstrap_;
std::unique_ptr<mojo::core::ScopedIPCSupport> ipc_support_;
bool connected_ = false;
};
NaClService::NaClService(
IPC::mojom::ChannelBootstrapPtrInfo bootstrap,
std::unique_ptr<mojo::core::ScopedIPCSupport> ipc_support)
: ipc_channel_bootstrap_(std::move(bootstrap)),
ipc_support_(std::move(ipc_support)) {}
NaClService::~NaClService() = default;
void NaClService::OnBindInterface(
const service_manager::BindSourceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
if (source_info.identity.name() == content::mojom::kBrowserServiceName &&
interface_name == IPC::mojom::ChannelBootstrap::Name_ && !connected_) {
connected_ = true;
mojo::FuseInterface(
IPC::mojom::ChannelBootstrapRequest(std::move(interface_pipe)),
std::move(ipc_channel_bootstrap_));
} else {
DVLOG(1) << "Ignoring request for unknown interface " << interface_name;
}
}
} // namespace
std::unique_ptr<service_manager::ServiceContext> CreateNaClServiceContext(
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
mojo::ScopedMessagePipeHandle* ipc_channel) {
auto ipc_support = std::make_unique<mojo::core::ScopedIPCSupport>(
std::move(io_task_runner),
mojo::core::ScopedIPCSupport::ShutdownPolicy::FAST);
auto invitation = EstablishMojoConnection();
IPC::mojom::ChannelBootstrapPtr bootstrap;
*ipc_channel = mojo::MakeRequest(&bootstrap).PassMessagePipe();
auto context = std::make_unique<service_manager::ServiceContext>(
std::make_unique<NaClService>(bootstrap.PassInterface(),
std::move(ipc_support)),
ConnectToServiceManager(&invitation));
return context;
}