blob: 5308882f053daa790015599989ca2f0f435f7a6b [file] [log] [blame]
// Copyright 2012 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/sessions/core/base_session_service.h"
#include <utility>
#include "base/bind.h"
#include "base/location.h"
#include "base/sequenced_task_runner.h"
#include "base/task_scheduler/post_task.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/sessions/core/base_session_service_delegate.h"
#include "components/sessions/core/session_backend.h"
// BaseSessionService ---------------------------------------------------------
namespace sessions {
namespace {
// Helper used by ScheduleGetLastSessionCommands. It runs callback on TaskRunner
// thread if it's not canceled.
void RunIfNotCanceled(
const base::CancelableTaskTracker::IsCanceledCallback& is_canceled,
const BaseSessionService::GetCommandsCallback& callback,
std::vector<std::unique_ptr<SessionCommand>> commands) {
if (is_canceled.Run())
return;
callback.Run(std::move(commands));
}
void PostOrRunInternalGetCommandsCallback(
base::TaskRunner* task_runner,
const BaseSessionService::GetCommandsCallback& callback,
std::vector<std::unique_ptr<SessionCommand>> commands) {
if (task_runner->RunsTasksInCurrentSequence()) {
callback.Run(std::move(commands));
} else {
task_runner->PostTask(FROM_HERE,
base::Bind(callback, base::Passed(&commands)));
}
}
} // namespace
// Delay between when a command is received, and when we save it to the
// backend.
static const int kSaveDelayMS = 2500;
BaseSessionService::BaseSessionService(SessionType type,
const base::FilePath& path,
BaseSessionServiceDelegate* delegate)
: pending_reset_(false),
commands_since_reset_(0),
delegate_(delegate),
backend_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
{base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN})),
weak_factory_(this) {
backend_ = new SessionBackend(type, path);
DCHECK(backend_.get());
}
BaseSessionService::~BaseSessionService() {}
void BaseSessionService::MoveCurrentSessionToLastSession() {
Save();
RunTaskOnBackendThread(
FROM_HERE,
base::BindOnce(&SessionBackend::MoveCurrentSessionToLastSession,
backend_));
}
void BaseSessionService::DeleteLastSession() {
RunTaskOnBackendThread(
FROM_HERE, base::BindOnce(&SessionBackend::DeleteLastSession, backend_));
}
void BaseSessionService::ScheduleCommand(
std::unique_ptr<SessionCommand> command) {
DCHECK(command);
commands_since_reset_++;
pending_commands_.push_back(std::move(command));
StartSaveTimer();
}
void BaseSessionService::AppendRebuildCommand(
std::unique_ptr<SessionCommand> command) {
DCHECK(command);
pending_commands_.push_back(std::move(command));
}
void BaseSessionService::EraseCommand(SessionCommand* old_command) {
auto it = std::find_if(
pending_commands_.begin(), pending_commands_.end(),
[old_command](const std::unique_ptr<SessionCommand>& command_ptr) {
return command_ptr.get() == old_command;
});
CHECK(it != pending_commands_.end());
pending_commands_.erase(it);
}
void BaseSessionService::SwapCommand(
SessionCommand* old_command,
std::unique_ptr<SessionCommand> new_command) {
auto it = std::find_if(
pending_commands_.begin(), pending_commands_.end(),
[old_command](const std::unique_ptr<SessionCommand>& command_ptr) {
return command_ptr.get() == old_command;
});
CHECK(it != pending_commands_.end());
*it = std::move(new_command);
}
void BaseSessionService::ClearPendingCommands() {
pending_commands_.clear();
}
void BaseSessionService::StartSaveTimer() {
// Don't start a timer when testing.
if (delegate_->ShouldUseDelayedSave() &&
base::ThreadTaskRunnerHandle::IsSet() && !weak_factory_.HasWeakPtrs()) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&BaseSessionService::Save, weak_factory_.GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kSaveDelayMS));
}
}
void BaseSessionService::Save() {
// Inform the delegate that we will save the commands now, giving it the
// opportunity to append more commands.
delegate_->OnWillSaveCommands();
if (pending_commands_.empty())
return;
// We create a new vector which will receive all elements from the
// current commands. This will also clear the current list.
RunTaskOnBackendThread(
FROM_HERE,
base::BindOnce(&SessionBackend::AppendCommands, backend_,
base::Passed(&pending_commands_), pending_reset_));
if (pending_reset_) {
commands_since_reset_ = 0;
pending_reset_ = false;
}
delegate_->OnSavedCommands();
}
base::CancelableTaskTracker::TaskId
BaseSessionService::ScheduleGetLastSessionCommands(
const GetCommandsCallback& callback,
base::CancelableTaskTracker* tracker) {
base::CancelableTaskTracker::IsCanceledCallback is_canceled;
base::CancelableTaskTracker::TaskId id =
tracker->NewTrackedTaskId(&is_canceled);
GetCommandsCallback run_if_not_canceled =
base::Bind(&RunIfNotCanceled, is_canceled, callback);
GetCommandsCallback callback_runner =
base::Bind(&PostOrRunInternalGetCommandsCallback,
base::RetainedRef(base::ThreadTaskRunnerHandle::Get()),
run_if_not_canceled);
RunTaskOnBackendThread(
FROM_HERE, base::BindOnce(&SessionBackend::ReadLastSessionCommands,
backend_, is_canceled, callback_runner));
return id;
}
void BaseSessionService::RunTaskOnBackendThread(
const tracked_objects::Location& from_here,
base::OnceClosure task) {
backend_task_runner_->PostNonNestableTask(from_here, std::move(task));
}
} // namespace sessions