blob: d26da927268dc6dea299c371a80484bbbc5a4ac3 [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 "services/service_manager/tests/util.h"
#include "base/base_paths.h"
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/path_service.h"
#include "base/process/process.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/system/invitation.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/service_executable/switches.h"
#include "services/service_manager/public/mojom/connector.mojom.h"
#include "services/service_manager/public/mojom/service.mojom.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace service_manager {
namespace test {
namespace {
void GrabConnectResult(base::RunLoop* loop,
mojom::ConnectResult* out_result,
mojom::ConnectResult result) {
loop->Quit();
*out_result = result;
}
} // namespace
mojom::ConnectResult LaunchAndConnectToProcess(
const std::string& target_exe_name,
const Identity& target,
service_manager::Connector* connector,
base::Process* process) {
base::FilePath target_path;
CHECK(base::PathService::Get(base::DIR_ASSETS, &target_path));
target_path = target_path.AppendASCII(target_exe_name);
base::CommandLine child_command_line(target_path);
// Forward the wait-for-debugger flag but nothing else - we don't want to
// stamp on the platform-channel flag.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
::switches::kWaitForDebugger)) {
child_command_line.AppendSwitch(::switches::kWaitForDebugger);
}
// Create the channel to be shared with the target process. Pass one end
// on the command line.
mojo::PlatformChannel channel;
mojo::PlatformChannel::HandlePassingInfo handle_passing_info;
channel.PrepareToPassRemoteEndpoint(&handle_passing_info,
&child_command_line);
mojo::OutgoingInvitation invitation;
auto pipe_name = base::NumberToString(base::RandUint64());
mojo::ScopedMessagePipeHandle pipe = invitation.AttachMessagePipe(pipe_name);
child_command_line.AppendSwitchASCII(switches::kServiceRequestAttachmentName,
pipe_name);
mojo::Remote<service_manager::mojom::ProcessMetadata> metadata;
mojom::ConnectResult result;
base::RunLoop loop(base::RunLoop::Type::kNestableTasksAllowed);
connector->RegisterServiceInstance(
target,
mojo::PendingRemote<service_manager::mojom::Service>(std::move(pipe), 0),
metadata.BindNewPipeAndPassReceiver(),
base::BindOnce(&GrabConnectResult, &loop, &result));
loop.Run();
base::LaunchOptions options;
#if defined(OS_WIN)
options.handles_to_inherit = handle_passing_info;
#elif defined(OS_FUCHSIA)
options.handles_to_transfer = handle_passing_info;
#elif defined(OS_MAC)
options.mach_ports_for_rendezvous = handle_passing_info;
#elif defined(OS_POSIX)
options.fds_to_remap = handle_passing_info;
#endif
*process = base::LaunchProcess(child_command_line, options);
DCHECK(process->IsValid());
channel.RemoteProcessLaunchAttempted();
metadata->SetPID(process->Pid());
mojo::OutgoingInvitation::Send(std::move(invitation), process->Handle(),
channel.TakeLocalEndpoint());
return result;
}
} // namespace test
} // namespace service_manager