// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_APP_RESTORE_FULL_RESTORE_SAVE_HANDLER_H_
#define COMPONENTS_APP_RESTORE_FULL_RESTORE_SAVE_HANDLER_H_
#include <list>
#include <map>
#include <memory>
#include <set>
#include <utility>
#include "base/component_export.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_multi_source_observation.h"
#include "base/scoped_observation.h"
#include "base/timer/timer.h"
#include "base/uuid.h"
#include "components/app_restore/app_restore_arc_info.h"
#include "components/app_restore/arc_save_handler.h"
#include "components/app_restore/lacros_save_handler.h"
#include "ui/aura/env.h"
#include "ui/aura/env_observer.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
namespace apps {
class AppRegistryCache;
} // namespace apps
namespace app_restore {
struct AppLaunchInfo;
class RestoreData;
struct WindowInfo;
} // namespace app_restore
namespace ash::full_restore {
class FullRestoreServiceTestHavingFullRestoreFile;
class FullRestoreAppLaunchHandlerArcAppBrowserTest;
} // namespace ash::full_restore
namespace base {
class FilePath;
class SequencedTaskRunner;
} // namespace base
namespace full_restore {
class FullRestoreFileHandler;
// FullRestoreSaveHandler is responsible for writing both the app launch
// information and the app window information to disk. FullRestoreSaveHandler
// runs on the main thread and creates FullRestoreFileHandler (which runs on a
// background task runner) for the actual writing. To minimize IO,
// FullRestoreSaveHandler starts a timer that invokes restore data saving at a
// later time.
class COMPONENT_EXPORT(APP_RESTORE) FullRestoreSaveHandler
: public aura::EnvObserver,
public aura::WindowObserver,
public app_restore::AppRestoreArcInfo::Observer {
public:
using AppLaunchInfoPtr = std::unique_ptr<app_restore::AppLaunchInfo>;
static FullRestoreSaveHandler* GetInstance();
FullRestoreSaveHandler();
FullRestoreSaveHandler(const FullRestoreSaveHandler&) = delete;
FullRestoreSaveHandler& operator=(const FullRestoreSaveHandler&) = delete;
~FullRestoreSaveHandler() override;
void InsertIgnoreApplicationId(const std::string& app_id);
void SetPrimaryProfilePath(const base::FilePath& profile_path);
void SetActiveProfilePath(const base::FilePath& profile_path);
void SetAppRegistryCache(const base::FilePath& profile_path,
apps::AppRegistryCache* app_registry_cache);
// When called, allows the Save() method to write to disk. Schedules the save
// timer to start for each monitored profile.
void AllowSave();
void SetShutDown();
// aura::EnvObserver:
void OnWindowInitialized(aura::Window* window) override;
// aura::WindowObserver:
void OnWindowDestroyed(aura::Window* window) override;
// app_restore::AppRestoreArcInfo::Observer:
void OnTaskCreated(const std::string& app_id,
int32_t task_id,
int32_t session_id) override;
void OnTaskDestroyed(int32_t task_id) override;
void OnArcConnectionChanged(bool is_connection_ready) override;
void OnArcPlayStoreEnabledChanged(bool enabled) override;
void OnTaskThemeColorUpdated(int32_t task_id,
uint32_t primary_color,
uint32_t status_bar_color) override;
// Saves |app_launch_info| to the full restore file in |profile_path|.
void SaveAppLaunchInfo(
const base::FilePath& profile_path,
std::unique_ptr<app_restore::AppLaunchInfo> app_launch_info);
// Saves |window_info| to |profile_path_to_restore_data_|.
void SaveWindowInfo(const app_restore::WindowInfo& window_info);
// Saves `removing_desk_guid` to the restore data for the currently active
// profile path.
void SaveRemovingDeskGuid(const base::Uuid& removing_desk_guid);
// Invoked when an Chrome app Lacros window is created. `app_id` is the
// AppService id, and `window_id` is the wayland app_id property for the
// window.
void OnLacrosChromeAppWindowAdded(const std::string& app_id,
const std::string& window_id);
// Invoked when an Chrome app Lacros window is removed. `app_id` is the
// AppService id, and `window_id` is the wayland app_id property for the
// window.
void OnLacrosChromeAppWindowRemoved(const std::string& app_id,
const std::string& window_id);
// Flushes the full restore file in |profile_path| with the current restore
// data.
void Flush(const base::FilePath& profile_path);
// Returns true if there is a AppRestoreData for the given `profile_path`,
// `app_id` and `window_id`. Otherwise, returns false.
bool HasAppRestoreData(const base::FilePath& profile_path,
const std::string& app_id,
int32_t window_id);
// Saves |app_launch_info| to |profile_path_to_file_handler_| for
// |profile_path| which will be written to the full restore file, if
// |app_launch_info| has a window_id.
void AddAppLaunchInfo(const base::FilePath& profile_path,
AppLaunchInfoPtr app_launch_info);
// Modify the window id for `app_id` from `old_window_id` to `new_window_id`.
void ModifyWindowId(const base::FilePath& profile_path,
const std::string& app_id,
int32_t old_window_id,
int32_t new_window_id);
// Saves |window_info| to |profile_path| for |app_id| and |window_id|.
void ModifyWindowInfo(const base::FilePath& profile_path,
const std::string& app_id,
int32_t window_id,
const app_restore::WindowInfo& window_info);
// Saves |primary_color| and |status_bar_color| to |profile_path| for |app_id|
// and |window_id|.
void ModifyThemeColor(const base::FilePath& profile_path,
const std::string& app_id,
int32_t window_id,
uint32_t primary_color,
uint32_t status_bar_color);
// Removes app launching and app windows for an app with the given |app_id|
// from |file_path_to_restore_data_| for |profile_path| .
void RemoveApp(const base::FilePath& profile_path, const std::string& app_id);
// Removes AppRestoreData from |profile_path| for |app_id| and |window_id|.
void RemoveAppRestoreData(const base::FilePath& profile_path,
const std::string& app_id,
int window_id);
// Sends the window for `profile_path` `app_id and `window_id` to background.
void SendWindowToBackground(const base::FilePath& profile_path,
const std::string& app_id,
int window_id);
// Starts the timer, and when timeout, clears restore data for |profile_path|.
void ClearRestoreData(const base::FilePath& profile_path);
// Generates the ARC session id (0 - 1,000,000,000) for ARC apps.
int32_t GetArcSessionId();
// Returns the RestoreData that associates with |profile_path|. Returns
// nullptr if there is no such RestoreData.
const app_restore::RestoreData* GetRestoreData(
const base::FilePath& profile_path);
// Returns the full restore app id for |window| that can be used to look up
// the window's associated AppRestoreData.
std::string GetAppId(aura::Window* window);
// Returns the window id of a chrome app hosted in lacros. Returns -1 if
// `window` is not in the lacros save handler.
int GetLacrosChromeAppWindowId(aura::Window* window) const;
// Fetches the app launch information from `app_id_to_app_launch_infos_` for
// the given `profile_path` and `app_id`. `app_id` should be a Chrome app id.
AppLaunchInfoPtr FetchAppLaunchInfo(const base::FilePath& profile_path,
const std::string& app_id);
// Returns the window information from the restore data of `profile_path` for
// `app_id` and `window_id`.
std::unique_ptr<app_restore::WindowInfo> GetWindowInfo(
const base::FilePath& profile_path,
const std::string& app_id,
int window_id);
base::OneShotTimer* GetTimerForTesting() { return &save_timer_; }
// Since this is a singleton, tests may need to clear it between tests.
void ClearForTesting();
private:
friend class FullRestoreSaveHandlerTestApi;
friend class ash::full_restore::FullRestoreServiceTestHavingFullRestoreFile;
friend class ash::full_restore::FullRestoreAppLaunchHandlerArcAppBrowserTest;
// Map from a profile path to AppLaunchInfos.
using AppLaunchInfos =
base::flat_map<base::FilePath, std::list<AppLaunchInfoPtr>>;
// Starts the timer that invokes Save (if timer isn't already running).
void MaybeStartSaveTimer(const base::FilePath& profile_path);
// Passes |profile_path_to_restore_data_| to the backend for saving.
void Save();
// Invoked when write to file operation for |profile_path| is finished.
void OnSaveFinished(const base::FilePath& profile_path);
FullRestoreFileHandler* GetFileHandler(const base::FilePath& profile_path);
base::SequencedTaskRunner* BackendTaskRunner(
const base::FilePath& profile_path);
// Saves |window_info| to |profile_path_to_file_handler_|.
void ModifyWindowInfo(int window_id,
const app_restore::WindowInfo& window_info);
// Removes AppRestoreData for |window_id|.
void RemoveAppRestoreData(int window_id);
// Applications with their app ids in this set will not have their app launch
// infos saved.
base::flat_set<std::string> ignore_applications_ids_;
// FullRestoreSaveHandler might be called to save the help app before
// FullRestoreAppLaunchHandler reads the full restore data from the full
// restore file during the system startup phase, e.g. when a new user login.
// So call FullRestoreReadHandler to read the file before saving the new data.
// `been_read_profile_paths_` is used to save the profile paths, whose full
// restore file has been read by FullRestoreReadHandler.
std::set<base::FilePath> been_read_profile_paths_;
// Records whether there are new updates for saving between each saving delay.
// |pending_save_profile_paths_| is cleared when Save is invoked.
std::set<base::FilePath> pending_save_profile_paths_;
// The restore data for each user's profile. The key is the profile path.
std::map<base::FilePath, app_restore::RestoreData>
profile_path_to_restore_data_;
// The file handler for each user's profile to write the restore data to the
// full restore file for each user. The key is the profile path.
base::flat_map<base::FilePath, scoped_refptr<FullRestoreFileHandler>>
profile_path_to_file_handler_;
// The AppRegistryCache for each user's profile. The key is the profile path.
base::flat_map<base::FilePath, apps::AppRegistryCache*>
profile_path_to_app_registry_cache_;
// The map from the window id to the full restore file path and the app id.
// The window id is saved in the window property. This map is used to find the
// file path and the app id for browser windows and Chrome app windows only
// when save the window info. This map can't be used for ARC app windows.
std::map<int32_t, std::pair<base::FilePath, std::string>>
window_id_to_app_restore_info_;
// The map from the app id to the app launch info for each full restore file
// path.
std::map<std::string, AppLaunchInfos> app_id_to_app_launch_infos_;
// The current active user profile path.
base::FilePath active_profile_path_;
// Timer used to delay the restore data writing to the full restore file.
base::OneShotTimer save_timer_;
// During the startup phase, start `wait_timer_` to wait for the system
// finishes the startup and the restore process, to prevent the original
// restore data is overwritten if the system restarts due to fast crash or
// upgrading.
base::OneShotTimer wait_timer_;
// Records whether the saving process is running for a full restore file.
std::set<base::FilePath> save_running_;
std::unique_ptr<ArcSaveHandler> arc_save_handler_;
std::unique_ptr<LacrosSaveHandler> lacros_save_handler_;
bool is_shut_down_ = false;
// Due to the system crash or upgrading, the system might restart or reboot
// very fast after startup. If the new window is written for the first time
// startup, after the second time reboot, the original restore data can't be
// restored. For the user, it looks like not restore. So block the save timer
// when startup until one of the below condition is matched:
// 1. restore finish if the restore setting is always, and no crash.
// 2. restore finish if there is a restore notification, and the user selects
// restore.
// 3. an app is launched by the user if there is a restore notification.
// 4. the restore notification is cancel or closed by the user if there is a
// restore notification.
// 5. the restore setting is off.
// 6. 'wait_timer_' is expired.
//
// When one of the above condition is matched, allow_save_ is set as true to
// permit `save_timer_` to start periodically triggering saving to disk.
bool allow_save_ = false;
base::ScopedObservation<aura::Env, aura::EnvObserver> env_observer_{this};
base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver>
observed_windows_{this};
base::ScopedObservation<app_restore::AppRestoreArcInfo,
app_restore::AppRestoreArcInfo::Observer>
arc_info_observer_{this};
base::WeakPtrFactory<FullRestoreSaveHandler> weak_factory_{this};
};
} // namespace full_restore
#endif // COMPONENTS_APP_RESTORE_FULL_RESTORE_SAVE_HANDLER_H_