blob: 7296d60405ec9201690c88548713a9dfb71fe199 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sessions/app_session_service.h"
#include <algorithm>
#include <set>
#include <utility>
#include "build/build_config.h"
#include "chrome/browser/apps/app_service/launch_utils.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_common_utils.h"
#include "chrome/browser/sessions/session_data_deleter.h"
#include "chrome/browser/sessions/session_service_utils.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "components/sessions/content/content_serialized_navigation_builder.h"
#include "components/sessions/content/session_tab_helper.h"
#include "components/sessions/core/command_storage_manager.h"
#include "components/sessions/core/session_command.h"
#include "components/sessions/core/session_constants.h"
#include "components/sessions/core/session_types.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/session_storage_namespace.h"
#include "content/public/browser/web_contents.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/ash/crostini/crostini_util.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "chrome/browser/app_controller_mac.h"
#endif
using content::NavigationEntry;
using content::WebContents;
using sessions::ContentSerializedNavigationBuilder;
using sessions::SerializedNavigationEntry;
AppSessionService::AppSessionService(Profile* profile)
: SessionServiceBase(profile,
SessionServiceBase::SessionServiceType::kAppRestore) {}
AppSessionService::~AppSessionService() {
// The BrowserList should outlive the SessionService since it's static and
// the SessionService is a KeyedService.
// BrowserList is subscribed to by SessionServiceBase's constructor.
BrowserList::RemoveObserver(this);
command_storage_manager()->Save();
DestroyCommandStorageManager();
}
void AppSessionService::TabClosed(SessionID window_id, SessionID tab_id) {
if (!tab_id.id())
return; // Happens when the tab is replaced.
if (!ShouldTrackChangesToWindow(window_id))
return;
auto i = tab_to_available_range()->find(tab_id);
if (i != tab_to_available_range()->end())
tab_to_available_range()->erase(i);
// If an individual tab is being closed or a secondary window is being
// closed, just mark the tab as closed now.
ScheduleCommand(sessions::CreateTabClosedCommand(tab_id));
}
void AppSessionService::WindowOpened(Browser* browser) {
if (!ShouldTrackBrowser(browser))
return;
SetWindowType(browser->session_id(), browser->type());
SetWindowAppName(browser->session_id(), browser->app_name());
// Save a browser workspace after window is created in `Browser()`.
// Bento desks restore feature in ash requires this line to restore correctly
// after creating a new browser window in a particular desk.
SetWindowWorkspace(browser->session_id(), browser->window()->GetWorkspace());
}
void AppSessionService::WindowClosing(SessionID window_id) {
if (!ShouldTrackChangesToWindow(window_id))
return;
// If Chrome is closed immediately after a history deletion, we have to
// rebuild commands before this window is closed, otherwise these tabs would
// be lost.
RebuildCommandsIfRequired();
}
void AppSessionService::WindowClosed(SessionID window_id) {
if (!ShouldTrackChangesToWindow(window_id)) {
return;
}
windows_tracking()->erase(window_id);
tab_to_available_range()->erase(window_id);
ScheduleCommand(sessions::CreateWindowClosedCommand(window_id));
}
void AppSessionService::SetWindowType(SessionID window_id, Browser::Type type) {
sessions::SessionWindow::WindowType window_type =
WindowTypeForBrowserType(type);
if (!ShouldRestoreWindowOfType(window_type))
return;
windows_tracking()->insert(window_id);
ScheduleCommand(CreateSetWindowTypeCommand(window_id, window_type));
}
Browser::Type AppSessionService::GetDesiredBrowserTypeForWebContents() {
return Browser::Type::TYPE_APP;
}
bool AppSessionService::ShouldRestoreWindowOfType(
sessions::SessionWindow::WindowType window_type) const {
if (window_type == sessions::SessionWindow::TYPE_APP ||
window_type == sessions::SessionWindow::TYPE_APP_POPUP) {
return true;
}
return false;
}
void AppSessionService::ScheduleResetCommands() {
command_storage_manager()->set_pending_reset(true);
command_storage_manager()->ClearPendingCommands();
tab_to_available_range()->clear();
windows_tracking()->clear();
set_rebuild_on_next_save(false);
BuildCommandsFromBrowsers(tab_to_available_range(), windows_tracking());
command_storage_manager()->StartSaveTimer();
}
void AppSessionService::RebuildCommandsIfRequired() {
if (rebuild_on_next_save())
ScheduleResetCommands();
}