#include "components/app_restore/full_restore_save_handler.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/no_destructor.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "components/app_constants/constants.h"
#include "components/app_restore/app_launch_info.h"
#include "components/app_restore/app_restore_info.h"
#include "components/app_restore/app_restore_utils.h"
#include "components/app_restore/full_restore_file_handler.h"
#include "components/app_restore/full_restore_read_handler.h"
#include "components/app_restore/full_restore_utils.h"
#include "components/app_restore/restore_data.h"
#include "components/app_restore/window_info.h"
#include "components/app_restore/window_properties.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/services/app_service/public/cpp/app_types.h"
#include "components/sessions/core/session_id.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/env.h"
namespace full_restore {
namespace {
constexpr base::TimeDelta kSaveDelay = base::Milliseconds(2500);
constexpr base::TimeDelta kWaitDelay = base::Seconds(120);
}
FullRestoreSaveHandler* FullRestoreSaveHandler::GetInstance() {
static base::NoDestructor<FullRestoreSaveHandler> full_restore_save_handler;
return full_restore_save_handler.get();
}
FullRestoreSaveHandler::FullRestoreSaveHandler() {
if (aura::Env::HasInstance())
env_observer_.Observe(aura::Env::GetInstance());
arc_info_observer_.Observe(app_restore::AppRestoreArcInfo::GetInstance());
}
FullRestoreSaveHandler::~FullRestoreSaveHandler() = default;
void FullRestoreSaveHandler::InsertIgnoreApplicationId(
const std::string& app_id) {
ignore_applications_ids_.insert(app_id);
}
void FullRestoreSaveHandler::SetPrimaryProfilePath(
const base::FilePath& profile_path) {
arc_save_handler_ = std::make_unique<ArcSaveHandler>(profile_path);
}
void FullRestoreSaveHandler::SetActiveProfilePath(
const base::FilePath& profile_path) {
active_profile_path_ = profile_path;
}
void FullRestoreSaveHandler::SetAppRegistryCache(
const base::FilePath& profile_path,
apps::AppRegistryCache* app_registry_cache) {
if (app_registry_cache)
profile_path_to_app_registry_cache_[profile_path] = app_registry_cache;
else
profile_path_to_app_registry_cache_.erase(profile_path);
}
void FullRestoreSaveHandler::AllowSave() {
if (allow_save_)
return;
allow_save_ = true;
if (wait_timer_.IsRunning())
wait_timer_.Stop();
if (!is_shut_down_ &&
base::Contains(pending_save_profile_paths_, active_profile_path_)) {
MaybeStartSaveTimer(active_profile_path_);
}
}
void FullRestoreSaveHandler::SetShutDown() {
is_shut_down_ = true;
}
void FullRestoreSaveHandler::OnWindowInitialized(aura::Window* window) {
if (app_restore::IsArcWindow(window)) {
observed_windows_.AddObservation(window);
if (arc_save_handler_)
arc_save_handler_->OnWindowInitialized(window);
return;
}
const int32_t window_id = window->GetProperty(app_restore::kWindowIdKey);
if (!SessionID::IsValidValue(window_id)) {
return;
}
observed_windows_.AddObservation(window);
std::string* app_id_str = window->GetProperty(app_restore::kAppIdKey);
AppLaunchInfoPtr app_launch_info;
if (app_id_str) {
app_launch_info = FetchAppLaunchInfo(active_profile_path_, *app_id_str);
if (!app_launch_info)
return;
app_launch_info->window_id = window_id;
} else {
app_launch_info = std::make_unique<app_restore::AppLaunchInfo>(
app_constants::kChromeAppId, window_id);
if (window->GetProperty(app_restore::kAppTypeBrowser)) {
app_launch_info->browser_extra_info.app_type_browser = true;
std::string* browser_app_name =
window->GetProperty(app_restore::kBrowserAppNameKey);
if (browser_app_name) {
std::string app_id =
app_restore::GetAppIdFromAppName(*browser_app_name);
auto it =
profile_path_to_app_registry_cache_.find(active_profile_path_);
if (it != profile_path_to_app_registry_cache_.end() && it->second) {
if (it->second->GetAppType(app_id) == apps::AppType::kUnknown) {
return;
}
if (it->second->GetAppType(app_id) == apps::AppType::kWeb ||
it->second->GetAppType(app_id) == apps::AppType::kSystemWeb) {
it->second->ForOneApp(app_id, [&app_launch_info, app_id](
const apps::AppUpdate& update) {
if (update.InstallReason() == apps::InstallReason::kSystem) {
app_launch_info->app_id = app_id;
}
});
}
}
}
if (base::Contains(ignore_applications_ids_, app_launch_info->app_id)) {
return;
}
}
}
AddAppLaunchInfo(active_profile_path_, std::move(app_launch_info));
app_restore::AppRestoreInfo::GetInstance()->OnAppLaunched(window);
}
void FullRestoreSaveHandler::OnWindowDestroyed(aura::Window* window) {
DCHECK(observed_windows_.IsObservingSource(window));
observed_windows_.RemoveObservation(window);
if (app_restore::IsArcWindow(window)) {
if (arc_save_handler_)
arc_save_handler_->OnWindowDestroyed(window);
return;
}
int32_t window_id = window->GetProperty(app_restore::kWindowIdKey);
DCHECK(SessionID::IsValidValue(window_id));
RemoveAppRestoreData(window_id);
}
void FullRestoreSaveHandler::OnTaskCreated(const std::string& app_id,
int32_t task_id,
int32_t session_id) {
if (arc_save_handler_)
arc_save_handler_->OnTaskCreated(app_id, task_id, session_id);
}
void FullRestoreSaveHandler::OnTaskDestroyed(int32_t task_id) {
if (arc_save_handler_)
arc_save_handler_->OnTaskDestroyed(task_id);
}
void FullRestoreSaveHandler::OnArcConnectionChanged(bool is_connection_ready) {
if (arc_save_handler_)
arc_save_handler_->set_is_connection_ready(is_connection_ready);
}
void FullRestoreSaveHandler::OnArcPlayStoreEnabledChanged(bool enabled) {
if (enabled)
return;
if (arc_save_handler_)
arc_save_handler_->OnArcPlayStoreEnabledChanged(enabled);
auto restore_data_it =
profile_path_to_restore_data_.find(active_profile_path_);
if (restore_data_it == profile_path_to_restore_data_.end())
return;
auto app_registry_cache_it =
profile_path_to_app_registry_cache_.find(active_profile_path_);
if (app_registry_cache_it == profile_path_to_app_registry_cache_.end())
return;
const auto& launch_list = restore_data_it->second.app_id_to_launch_list();
std::vector<std::string> arc_app_ids;
for (const auto& it : launch_list) {
if (app_registry_cache_it->second->GetAppType(it.first) ==
apps::AppType::kArc) {
arc_app_ids.push_back(it.first);
}
}
if (arc_app_ids.empty())
return;
for (const auto& app_id : arc_app_ids)
restore_data_it->second.RemoveApp(app_id);
pending_save_profile_paths_.insert(active_profile_path_);
MaybeStartSaveTimer(active_profile_path_);
}
void FullRestoreSaveHandler::OnTaskThemeColorUpdated(
int32_t task_id,
uint32_t primary_color,
uint32_t status_bar_color) {
if (arc_save_handler_) {
arc_save_handler_->OnTaskThemeColorUpdated(task_id, primary_color,
status_bar_color);
}
}
void FullRestoreSaveHandler::SaveAppLaunchInfo(
const base::FilePath& profile_path,
AppLaunchInfoPtr app_launch_info) {
if (profile_path.empty() || !app_launch_info)
return;
const std::string app_id = app_launch_info->app_id;
if (app_launch_info->arc_session_id.has_value()) {
if (arc_save_handler_)
arc_save_handler_->SaveAppLaunchInfo(std::move(app_launch_info));
return;
}
if (!app_launch_info->window_id.has_value()) {
app_id_to_app_launch_infos_[app_id][profile_path].push_back(
std::move(app_launch_info));
return;
}
const int window_id = app_launch_info->window_id.value();
std::unique_ptr<app_restore::WindowInfo> window_info;
if (app_id != app_constants::kChromeAppId) {
auto it = window_id_to_app_restore_info_.find(window_id);
if (it != window_id_to_app_restore_info_.end()) {
window_info = GetWindowInfo(profile_path, app_id, window_id);
RemoveAppRestoreData(window_id);
}
}
AddAppLaunchInfo(profile_path, std::move(app_launch_info));
if (window_info) {
profile_path_to_restore_data_[profile_path].ModifyWindowInfo(
app_id, window_id, *window_info);
}
}
void FullRestoreSaveHandler::SaveWindowInfo(
const app_restore::WindowInfo& window_info) {
if (!window_info.window)
return;
if (app_restore::IsArcWindow(window_info.window)) {
if (arc_save_handler_)
arc_save_handler_->ModifyWindowInfo(window_info);
return;
}
int32_t window_id =
window_info.window->GetProperty(app_restore::kWindowIdKey);
if (!SessionID::IsValidValue(window_id))
return;
ModifyWindowInfo(window_id, window_info);
}
void FullRestoreSaveHandler::SaveRemovingDeskGuid(
const base::Uuid& removing_desk_guid) {
profile_path_to_restore_data_[active_profile_path_].set_removing_desk_guid(
removing_desk_guid);
pending_save_profile_paths_.insert(active_profile_path_);
MaybeStartSaveTimer(active_profile_path_);
}
void FullRestoreSaveHandler::Flush(const base::FilePath& profile_path) {
if (save_running_.find(profile_path) != save_running_.end())
return;
save_running_.insert(profile_path);
BackendTaskRunner(profile_path)
->PostTaskAndReply(
FROM_HERE,
base::BindOnce(&FullRestoreFileHandler::WriteToFile,
GetFileHandler(profile_path),
profile_path_to_restore_data_[profile_path].Clone()),
base::BindOnce(&FullRestoreSaveHandler::OnSaveFinished,
weak_factory_.GetWeakPtr(), profile_path));
}
bool FullRestoreSaveHandler::HasAppRestoreData(
const base::FilePath& profile_path,
const std::string& app_id,
int32_t window_id) {
auto it = profile_path_to_restore_data_.find(profile_path);
if (it == profile_path_to_restore_data_.end())
return false;
return it->second.HasAppRestoreData(app_id, window_id);
}
void FullRestoreSaveHandler::AddAppLaunchInfo(
const base::FilePath& profile_path,
AppLaunchInfoPtr app_launch_info) {
if (profile_path.empty() || !app_launch_info ||
!app_launch_info->window_id.has_value()) {
return;
}
if (!app_launch_info->arc_session_id.has_value()) {
window_id_to_app_restore_info_[app_launch_info->window_id.value()] =
std::make_pair(profile_path, app_launch_info->app_id);
}
profile_path_to_restore_data_[profile_path].AddAppLaunchInfo(
std::move(app_launch_info));
pending_save_profile_paths_.insert(profile_path);
MaybeStartSaveTimer(profile_path);
}
void FullRestoreSaveHandler::ModifyWindowId(const base::FilePath& profile_path,
const std::string& app_id,
int32_t old_window_id,
int32_t new_window_id) {
auto it = profile_path_to_restore_data_.find(profile_path);
if (it == profile_path_to_restore_data_.end())
return;
profile_path_to_restore_data_[profile_path].ModifyWindowId(
app_id, old_window_id, new_window_id);
pending_save_profile_paths_.insert(profile_path);
MaybeStartSaveTimer(profile_path);
}
void FullRestoreSaveHandler::ModifyWindowInfo(
const base::FilePath& profile_path,
const std::string& app_id,
int32_t window_id,
const app_restore::WindowInfo& window_info) {
auto it = profile_path_to_restore_data_.find(profile_path);
if (it == profile_path_to_restore_data_.end())
return;
profile_path_to_restore_data_[profile_path].ModifyWindowInfo(
app_id, window_id, window_info);
pending_save_profile_paths_.insert(profile_path);
MaybeStartSaveTimer(profile_path);
}
void FullRestoreSaveHandler::ModifyThemeColor(
const base::FilePath& profile_path,
const std::string& app_id,
int32_t window_id,
uint32_t primary_color,
uint32_t status_bar_color) {
auto it = profile_path_to_restore_data_.find(profile_path);
if (it == profile_path_to_restore_data_.end())
return;
profile_path_to_restore_data_[profile_path].ModifyThemeColor(
app_id, window_id, primary_color, status_bar_color);
pending_save_profile_paths_.insert(profile_path);
MaybeStartSaveTimer(profile_path);
}
void FullRestoreSaveHandler::RemoveApp(const base::FilePath& profile_path,
const std::string& app_id) {
auto it = profile_path_to_restore_data_.find(profile_path);
if (it == profile_path_to_restore_data_.end())
return;
it->second.RemoveApp(app_id);
pending_save_profile_paths_.insert(profile_path);
MaybeStartSaveTimer(profile_path);
}
void FullRestoreSaveHandler::RemoveAppRestoreData(
const base::FilePath& profile_path,
const std::string& app_id,
int window_id) {
auto it = profile_path_to_restore_data_.find(profile_path);
if (it == profile_path_to_restore_data_.end())
return;
it->second.RemoveAppRestoreData(app_id, window_id);
pending_save_profile_paths_.insert(profile_path);
MaybeStartSaveTimer(profile_path);
}
void FullRestoreSaveHandler::SendWindowToBackground(
const base::FilePath& profile_path,
const std::string& app_id,
int window_id) {
auto it = profile_path_to_restore_data_.find(profile_path);
if (it == profile_path_to_restore_data_.end())
return;
it->second.SendWindowToBackground(app_id, window_id);
pending_save_profile_paths_.insert(profile_path);
MaybeStartSaveTimer(profile_path);
}
void FullRestoreSaveHandler::ClearRestoreData(
const base::FilePath& profile_path) {
pending_save_profile_paths_.insert(profile_path);
MaybeStartSaveTimer(profile_path);
}
int32_t FullRestoreSaveHandler::GetArcSessionId() {
if (!arc_save_handler_)
return -1;
return arc_save_handler_->GetArcSessionId();
}
const app_restore::RestoreData* FullRestoreSaveHandler::GetRestoreData(
const base::FilePath& profile_path) {
auto it = profile_path_to_restore_data_.find(profile_path);
if (it == profile_path_to_restore_data_.end())
return nullptr;
return &(profile_path_to_restore_data_[profile_path]);
}
std::string FullRestoreSaveHandler::GetAppId(aura::Window* window) {
DCHECK(window);
if (app_restore::IsArcWindow(window)) {
return arc_save_handler_ ? arc_save_handler_->GetAppId(window)
: std::string();
} else {
const int32_t window_id = window->GetProperty(app_restore::kWindowIdKey);
auto iter = window_id_to_app_restore_info_.find(window_id);
return iter != window_id_to_app_restore_info_.end() ? iter->second.second
: std::string();
}
}
std::unique_ptr<app_restore::AppLaunchInfo>
FullRestoreSaveHandler::FetchAppLaunchInfo(const base::FilePath& profile_path,
const std::string& app_id) {
auto it = app_id_to_app_launch_infos_.find(app_id);
if (it == app_id_to_app_launch_infos_.end())
return nullptr;
auto launch_it = it->second.find(profile_path);
if (launch_it == it->second.end())
return nullptr;
DCHECK(!launch_it->second.empty());
auto app_launch_info = std::move(*launch_it->second.begin());
it->second.erase(profile_path);
if (it->second.empty())
app_id_to_app_launch_infos_.erase(it);
return app_launch_info;
}
std::unique_ptr<app_restore::WindowInfo> FullRestoreSaveHandler::GetWindowInfo(
const base::FilePath& profile_path,
const std::string& app_id,
int window_id) {
auto it = profile_path_to_restore_data_.find(profile_path);
return it != profile_path_to_restore_data_.end()
? it->second.GetWindowInfo(app_id, window_id)
: nullptr;
}
void FullRestoreSaveHandler::ClearForTesting() {
profile_path_to_file_handler_.clear();
profile_path_to_restore_data_.clear();
app_id_to_app_launch_infos_.clear();
save_running_.clear();
pending_save_profile_paths_.clear();
window_id_to_app_restore_info_.clear();
app_id_to_app_launch_infos_.clear();
is_shut_down_ = false;
allow_save_ = false;
save_timer_.Stop();
wait_timer_.Stop();
}
void FullRestoreSaveHandler::MaybeStartSaveTimer(
const base::FilePath& profile_path) {
if (!base::Contains(been_read_profile_paths_, profile_path)) {
FullRestoreReadHandler::GetInstance()->ReadFromFile(profile_path,
base::DoNothing());
been_read_profile_paths_.insert(profile_path);
}
if (!allow_save_) {
if (!wait_timer_.IsRunning()) {
wait_timer_.Start(FROM_HERE, kWaitDelay,
base::BindOnce(&FullRestoreSaveHandler::AllowSave,
weak_factory_.GetWeakPtr()));
}
return;
}
if (!save_timer_.IsRunning() && save_running_.empty()) {
save_timer_.Start(FROM_HERE, kSaveDelay,
base::BindOnce(&FullRestoreSaveHandler::Save,
weak_factory_.GetWeakPtr()));
}
}
void FullRestoreSaveHandler::Save() {
if (is_shut_down_ ||
!base::Contains(pending_save_profile_paths_, active_profile_path_)) {
return;
}
Flush(active_profile_path_);
pending_save_profile_paths_.erase(active_profile_path_);
}
void FullRestoreSaveHandler::OnSaveFinished(
const base::FilePath& profile_path) {
save_running_.erase(profile_path);
}
FullRestoreFileHandler* FullRestoreSaveHandler::GetFileHandler(
const base::FilePath& profile_path) {
if (profile_path_to_file_handler_.find(profile_path) ==
profile_path_to_file_handler_.end()) {
profile_path_to_file_handler_[profile_path] =
base::MakeRefCounted<FullRestoreFileHandler>(profile_path);
}
return profile_path_to_file_handler_[profile_path].get();
}
base::SequencedTaskRunner* FullRestoreSaveHandler::BackendTaskRunner(
const base::FilePath& profile_path) {
return GetFileHandler(profile_path)->owning_task_runner();
}
void FullRestoreSaveHandler::ModifyWindowInfo(
int window_id,
const app_restore::WindowInfo& window_info) {
auto it = window_id_to_app_restore_info_.find(window_id);
if (it == window_id_to_app_restore_info_.end())
return;
const base::FilePath& profile_path = it->second.first;
const std::string& app_id = it->second.second;
ModifyWindowInfo(profile_path, app_id, window_id, window_info);
}
void FullRestoreSaveHandler::RemoveAppRestoreData(int window_id) {
auto it = window_id_to_app_restore_info_.find(window_id);
if (it == window_id_to_app_restore_info_.end())
return;
const base::FilePath& profile_path = it->second.first;
const std::string& app_id = it->second.second;
RemoveAppRestoreData(profile_path, app_id, window_id);
window_id_to_app_restore_info_.erase(it);
}
}