blob: df66d2a5107b17148bc18ecfb690a19897e2b117 [file] [log] [blame]
// Copyright 2019 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 "chrome/chrome_cleaner/engines/target/sandboxed_test_helpers.h"
#include <utility>
#include "base/bind_helpers.h"
#include "base/task/single_thread_task_executor.h"
#include "chrome/chrome_cleaner/engines/common/engine_result_codes.h"
#include "chrome/chrome_cleaner/os/early_exit.h"
#include "chrome/chrome_cleaner/os/initializer.h"
namespace chrome_cleaner {
const int SandboxChildProcess::kConnectionErrorExitCode = 0xDEAD;
// FakeEngineDelegate takes a base::Event that it signals once either
// Initialize, StartScan, or StartCleanup has been called to indicate when this
// class is fully functional (for either scanning or cleaning test). It does not
// invoke any actual engine commands.
class SandboxChildProcess::FakeEngineDelegate : public EngineDelegate {
public:
explicit FakeEngineDelegate(base::WaitableEvent* event) : event_(event) {}
Engine::Name engine() const override { return Engine::TEST_ONLY; }
void Initialize(const base::FilePath& log_directory_path,
scoped_refptr<EngineFileRequestsProxy> privileged_file_calls,
mojom::EngineCommands::InitializeCallback callback) override {
privileged_file_calls_ = privileged_file_calls;
event_->Signal();
std::move(callback).Run(EngineResultCode::kSuccess);
}
uint32_t StartScan(
const std::vector<UwSId>& enabled_uws,
const std::vector<UwS::TraceLocation>& enabled_locations,
bool include_details,
scoped_refptr<EngineFileRequestsProxy> privileged_file_calls,
scoped_refptr<EngineRequestsProxy> privileged_scan_calls,
scoped_refptr<EngineScanResultsProxy> /*report_result_calls*/) override {
privileged_file_calls_ = privileged_file_calls;
privileged_scan_calls_ = privileged_scan_calls;
event_->Signal();
return EngineResultCode::kSuccess;
}
uint32_t StartCleanup(
const std::vector<UwSId>& enabled_uws,
scoped_refptr<EngineFileRequestsProxy> privileged_file_calls,
scoped_refptr<EngineRequestsProxy> privileged_scan_calls,
scoped_refptr<CleanerEngineRequestsProxy> privileged_removal_calls,
scoped_refptr<EngineCleanupResultsProxy> /*report_result_calls*/)
override {
privileged_file_calls_ = privileged_file_calls;
privileged_scan_calls_ = privileged_scan_calls;
privileged_removal_calls_ = privileged_removal_calls;
event_->Signal();
return EngineResultCode::kSuccess;
}
uint32_t Finalize() override { return EngineResultCode::kSuccess; }
scoped_refptr<EngineFileRequestsProxy> GetFileRequestsProxy() {
return privileged_file_calls_;
}
scoped_refptr<EngineRequestsProxy> GetEngineRequestsProxy() {
return privileged_scan_calls_;
}
scoped_refptr<CleanerEngineRequestsProxy> GetCleanerEngineRequestsProxy() {
return privileged_removal_calls_;
}
void UnbindRequestsPtrs() {
if (privileged_scan_calls_) {
privileged_scan_calls_->UnbindRequestsPtr();
}
if (privileged_file_calls_) {
privileged_file_calls_->UnbindRequestsPtr();
}
}
private:
~FakeEngineDelegate() override = default;
base::WaitableEvent* event_;
scoped_refptr<EngineFileRequestsProxy> privileged_file_calls_;
scoped_refptr<EngineRequestsProxy> privileged_scan_calls_;
scoped_refptr<CleanerEngineRequestsProxy> privileged_removal_calls_;
};
SandboxChildProcess::SandboxChildProcess(
scoped_refptr<MojoTaskRunner> mojo_task_runner)
: ChildProcess(std::move(mojo_task_runner)) {
// This must be called before accessing Mojo, because the parent process is
// waiting on this and won't respond to Mojo calls.
NotifyInitializationDone();
mojo::ScopedMessagePipeHandle message_pipe_handle =
CreateMessagePipeFromCommandLine();
mojom::EngineCommandsRequest engine_commands_request(
std::move(message_pipe_handle));
base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
mojo_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&SandboxChildProcess::BindEngineCommandsRequest,
base::Unretained(this),
base::Passed(&engine_commands_request), &event));
event.Wait();
}
void SandboxChildProcess::SandboxChildProcess::BindEngineCommandsRequest(
mojom::EngineCommandsRequest request,
base::WaitableEvent* event) {
fake_engine_delegate_ = base::MakeRefCounted<FakeEngineDelegate>(event);
engine_commands_impl_ = std::make_unique<EngineCommandsImpl>(
fake_engine_delegate_, std::move(request), mojo_task_runner_,
/*error_handler=*/base::BindOnce(&EarlyExit, kConnectionErrorExitCode));
}
scoped_refptr<EngineFileRequestsProxy>
SandboxChildProcess::GetFileRequestsProxy() {
return fake_engine_delegate_->GetFileRequestsProxy();
}
scoped_refptr<EngineRequestsProxy>
SandboxChildProcess::GetEngineRequestsProxy() {
return fake_engine_delegate_->GetEngineRequestsProxy();
}
scoped_refptr<CleanerEngineRequestsProxy>
SandboxChildProcess::GetCleanerEngineRequestsProxy() {
return fake_engine_delegate_->GetCleanerEngineRequestsProxy();
}
void SandboxChildProcess::UnbindRequestsPtrs() {
base::SingleThreadTaskExecutor main_task_executor;
base::RunLoop run_loop;
if (GetCleanerEngineRequestsProxy() != nullptr) {
mojo_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&CleanerEngineRequestsProxy::UnbindRequestsPtr,
GetCleanerEngineRequestsProxy()));
}
mojo_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&FakeEngineDelegate::UnbindRequestsPtrs,
fake_engine_delegate_));
mojo_task_runner_->PostTaskAndReply(FROM_HERE, base::DoNothing(),
run_loop.QuitClosure());
run_loop.Run();
}
SandboxChildProcess::~SandboxChildProcess() {
// |engine_commands_impl_| must be destroyed on the Mojo thread or it will
// crash.
mojo_task_runner_->PostTask(
FROM_HERE, base::BindOnce(
[](std::unique_ptr<EngineCommandsImpl> commands) {
commands.reset();
},
base::Passed(&engine_commands_impl_)));
}
} // namespace chrome_cleaner