blob: d0cd06368c62af090349f0f4e7c6a74a4472c12f [file] [log] [blame]
// Copyright 2018 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/ipc/chrome_prompt_ipc.h"
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/system/invitation.h"
#include "mojo/public/cpp/system/message_pipe.h"
namespace chrome_cleaner {
ChromePromptIPC::ChromePromptIPC(const std::string& chrome_mojo_pipe_token,
scoped_refptr<MojoTaskRunner> task_runner)
: task_runner_(std::move(task_runner)),
chrome_mojo_pipe_token_(chrome_mojo_pipe_token) {
// Accesses to |state_| must happen on |task_runner_|'s sequence, which is
// not the construction sequence.
DETACH_FROM_SEQUENCE(sequence_checker_);
}
void ChromePromptIPC::Initialize(ErrorHandler* error_handler) {
DCHECK(!chrome_mojo_pipe_token_.empty());
DCHECK(task_runner_);
error_handler_ = error_handler;
// No need to retain this object, since it will live until the process
// finishes.
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&ChromePromptIPC::InitializeChromePromptPtr,
base::Unretained(this)));
}
ChromePromptIPC::~ChromePromptIPC() {
// This object is only destroyed when the cleaner process ends. At this point
// we don't need to close the IPC, since the broken connection message will
// be received by Chrome anyway, and we can simply leak the pointer.
chrome_prompt_service_.release(); // Leaked.
}
void ChromePromptIPC::PostPromptUserTask(
const std::vector<base::FilePath>& files_to_delete,
const std::vector<base::string16>& registry_keys,
mojom::ChromePrompt::PromptUserCallback callback) {
DCHECK(task_runner_);
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&ChromePromptIPC::RunPromptUserTask, base::Unretained(this),
files_to_delete, registry_keys,
base::BindOnce(&ChromePromptIPC::OnChromeResponseReceived,
base::Unretained(this), std::move(callback))));
}
void ChromePromptIPC::OnChromeResponseReceived(
mojom::ChromePrompt::PromptUserCallback callback,
mojom::PromptAcceptance prompt_acceptance) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(State::kWaitingForResponseFromChrome, state_);
state_ = State::kDone;
std::move(callback).Run(prompt_acceptance);
}
void ChromePromptIPC::OnConnectionError() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(State::kUninitialized, state_);
if (!error_handler_)
return;
if (state_ == State::kDone) {
error_handler_->OnConnectionClosedAfterDone();
} else {
state_ = State::kDone;
error_handler_->OnConnectionClosed();
}
}
void ChromePromptIPC::InitializeChromePromptPtr() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(State::kUninitialized, state_);
auto channel_endpoint =
mojo::PlatformChannel::RecoverPassedEndpointFromCommandLine(
*base::CommandLine::ForCurrentProcess());
auto incoming_invitation =
mojo::IncomingInvitation::Accept(std::move(channel_endpoint));
mojo::ScopedMessagePipeHandle message_pipe_handle =
incoming_invitation.ExtractMessagePipe(chrome_mojo_pipe_token_);
chrome_prompt_service_.reset(new chrome_cleaner::mojom::ChromePromptPtr);
chrome_prompt_service_->Bind(chrome_cleaner::mojom::ChromePromptPtrInfo(
std::move(message_pipe_handle), 0));
// No need to retain this object, since it will live until the process
// finishes.
chrome_prompt_service_->set_connection_error_handler(base::BindOnce(
&ChromePromptIPC::OnConnectionError, base::Unretained(this)));
state_ = State::kWaitingForScanResults;
}
void ChromePromptIPC::RunPromptUserTask(
const std::vector<base::FilePath>& files_to_delete,
const std::vector<base::string16>& registry_keys,
mojom::ChromePrompt::PromptUserCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(chrome_prompt_service_);
DCHECK(state_ != State::kUninitialized);
DCHECK(state_ != State::kWaitingForResponseFromChrome);
// This is a corner case, in which we receive the disconnect message on the
// IPC thread right before this task is posted. In that case, this function
// will be a no-op.
if (state_ == State::kDone)
return;
state_ = State::kWaitingForResponseFromChrome;
(*chrome_prompt_service_)
->PromptUser(std::move(files_to_delete), std::move(registry_keys),
base::nullopt, std::move(callback));
}
} // namespace chrome_cleaner