browser_persister.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "weblayer/browser/persistence/browser_persister.h"
  5. #include <stddef.h>
  6. #include <algorithm>
  7. #include <utility>
  8. #include <vector>
  9. #include "base/bind.h"
  10. #include "components/sessions/content/content_serialized_navigation_builder.h"
  11. #include "components/sessions/content/session_tab_helper.h"
  12. #include "components/sessions/core/command_storage_manager.h"
  13. #include "components/sessions/core/session_command.h"
  14. #include "components/sessions/core/session_constants.h"
  15. #include "components/sessions/core/session_id.h"
  16. #include "components/sessions/core/session_types.h"
  17. #include "content/public/browser/navigation_details.h"
  18. #include "content/public/browser/navigation_entry.h"
  19. #include "content/public/browser/restore_type.h"
  20. #include "content/public/browser/session_storage_namespace.h"
  21. #include "content/public/browser/storage_partition.h"
  22. #include "content/public/browser/web_contents.h"
  23. #include "weblayer/browser/browser_context_impl.h"
  24. #include "weblayer/browser/browser_impl.h"
  25. #include "weblayer/browser/persistence/browser_persistence_common.h"
  26. #include "weblayer/browser/profile_impl.h"
  27. #include "weblayer/browser/tab_impl.h"
  28. using sessions::ContentSerializedNavigationBuilder;
  29. using sessions::SerializedNavigationEntry;
  30. namespace weblayer {
  31. namespace {
  32. int GetIndexOfTab(BrowserImpl* browser, Tab* tab) {
  33. const std::vector<Tab*>& tabs = browser->GetTabs();
  34. auto iter = std::find(tabs.begin(), tabs.end(), tab);
  35. DCHECK(iter != tabs.end());
  36. return static_cast<int>(iter - tabs.begin());
  37. }
  38. } // namespace
  39. // Every kWritesPerReset commands triggers recreating the file.
  40. constexpr int kWritesPerReset = 250;
  41. // BrowserPersister
  42. // -------------------------------------------------------------
  43. BrowserPersister::BrowserPersister(const base::FilePath& path,
  44. BrowserImpl* browser,
  45. const std::vector<uint8_t>& decryption_key)
  46. : browser_(browser),
  47. browser_session_id_(SessionID::NewUnique()),
  48. command_storage_manager_(
  49. std::make_unique<sessions::CommandStorageManager>(
  50. sessions::CommandStorageManager::kOther,
  51. path,
  52. this,
  53. browser->profile()->GetBrowserContext()->IsOffTheRecord(),
  54. decryption_key)),
  55. rebuild_on_next_save_(false),
  56. crypto_key_(decryption_key) {
  57. browser_->AddObserver(this);
  58. command_storage_manager_->GetLastSessionCommands(base::BindOnce(
  59. &BrowserPersister::OnGotLastSessionCommands, weak_factory_.GetWeakPtr()));
  60. }
  61. BrowserPersister::~BrowserPersister() {
  62. SaveIfNecessary();
  63. browser_->RemoveObserver(this);
  64. }
  65. void BrowserPersister::SaveIfNecessary() {
  66. if (command_storage_manager_->HasPendingSave())
  67. command_storage_manager_->Save();
  68. }
  69. const std::vector<uint8_t>& BrowserPersister::GetCryptoKey() const {
  70. return crypto_key_;
  71. }
  72. bool BrowserPersister::ShouldUseDelayedSave() {
  73. return true;
  74. }
  75. void BrowserPersister::OnWillSaveCommands() {
  76. if (!rebuild_on_next_save_)
  77. return;
  78. rebuild_on_next_save_ = false;
  79. command_storage_manager_->set_pending_reset(true);
  80. command_storage_manager_->ClearPendingCommands();
  81. tab_to_available_range_.clear();
  82. BuildCommandsForBrowser();
  83. }
  84. void BrowserPersister::OnGeneratedNewCryptoKey(
  85. const std::vector<uint8_t>& key) {
  86. crypto_key_ = key;
  87. }
  88. void BrowserPersister::OnErrorWritingSessionCommands() {
  89. rebuild_on_next_save_ = true;
  90. command_storage_manager_->StartSaveTimer();
  91. }
  92. void BrowserPersister::OnTabAdded(Tab* tab) {
  93. auto* tab_impl = static_cast<TabImpl*>(tab);
  94. data_observations_.AddObservation(tab_impl);
  95. content::WebContents* web_contents = tab_impl->web_contents();
  96. auto* tab_helper = sessions::SessionTabHelper::FromWebContents(web_contents);
  97. DCHECK(tab_helper);
  98. tab_helper->SetWindowID(browser_session_id_);
  99. // Record the association between the SessionStorageNamespace and the
  100. // tab.
  101. content::SessionStorageNamespace* session_storage_namespace =
  102. web_contents->GetController().GetDefaultSessionStorageNamespace();
  103. session_storage_namespace->SetShouldPersist(true);
  104. if (rebuild_on_next_save_)
  105. return;
  106. int index = GetIndexOfTab(browser_, tab);
  107. BuildCommandsForTab(static_cast<TabImpl*>(tab), index);
  108. const std::vector<Tab*>& tabs = browser_->GetTabs();
  109. for (int i = index + 1; i < static_cast<int>(tabs.size()); ++i) {
  110. ScheduleCommand(sessions::CreateSetTabIndexInWindowCommand(
  111. GetSessionIDForTab(tabs[i]), i));
  112. }
  113. }
  114. void BrowserPersister::OnTabRemoved(Tab* tab, bool active_tab_changed) {
  115. auto* tab_impl = static_cast<TabImpl*>(tab);
  116. data_observations_.RemoveObservation(tab_impl);
  117. // Allow the associated sessionStorage to get deleted; it won't be needed
  118. // in the session restore.
  119. content::WebContents* web_contents = tab_impl->web_contents();
  120. content::SessionStorageNamespace* session_storage_namespace =
  121. web_contents->GetController().GetDefaultSessionStorageNamespace();
  122. session_storage_namespace->SetShouldPersist(false);
  123. if (rebuild_on_next_save_)
  124. return;
  125. ScheduleCommand(sessions::CreateTabClosedCommand(GetSessionIDForTab(tab)));
  126. const std::vector<Tab*>& tabs = browser_->GetTabs();
  127. for (size_t i = 0; i < tabs.size(); ++i) {
  128. ScheduleCommand(sessions::CreateSetTabIndexInWindowCommand(
  129. GetSessionIDForTab(tabs[i]), i));
  130. }
  131. auto i = tab_to_available_range_.find(GetSessionIDForTab(tab));
  132. if (i != tab_to_available_range_.end())
  133. tab_to_available_range_.erase(i);
  134. }
  135. void BrowserPersister::OnActiveTabChanged(Tab* tab) {
  136. if (rebuild_on_next_save_)
  137. return;
  138. const int index = tab == nullptr ? -1 : GetIndexOfTab(browser_, tab);
  139. ScheduleCommand(sessions::CreateSetSelectedTabInWindowCommand(
  140. browser_session_id_, index));
  141. }
  142. void BrowserPersister::OnDataChanged(
  143. TabImpl* tab,
  144. const std::map<std::string, std::string>& data) {
  145. if (rebuild_on_next_save_)
  146. return;
  147. ScheduleCommand(
  148. sessions::CreateSetTabDataCommand(GetSessionIDForTab(tab), data));
  149. }
  150. void BrowserPersister::SetTabUserAgentOverride(
  151. const SessionID& window_id,
  152. const SessionID& tab_id,
  153. const sessions::SerializedUserAgentOverride& user_agent_override) {
  154. if (rebuild_on_next_save_)
  155. return;
  156. ScheduleCommand(sessions::CreateSetTabUserAgentOverrideCommand(
  157. tab_id, user_agent_override));
  158. }
  159. void BrowserPersister::SetSelectedNavigationIndex(const SessionID& window_id,
  160. const SessionID& tab_id,
  161. int index) {
  162. if (rebuild_on_next_save_)
  163. return;
  164. if (tab_to_available_range_.find(tab_id) != tab_to_available_range_.end()) {
  165. if (index < tab_to_available_range_[tab_id].first ||
  166. index > tab_to_available_range_[tab_id].second) {
  167. // The new index is outside the range of what we've archived, schedule
  168. // a reset.
  169. ScheduleRebuildOnNextSave();
  170. return;
  171. }
  172. }
  173. ScheduleCommand(
  174. sessions::CreateSetSelectedNavigationIndexCommand(tab_id, index));
  175. }
  176. void BrowserPersister::UpdateTabNavigation(
  177. const SessionID& window_id,
  178. const SessionID& tab_id,
  179. const SerializedNavigationEntry& navigation) {
  180. if (rebuild_on_next_save_)
  181. return;
  182. if (tab_to_available_range_.find(tab_id) != tab_to_available_range_.end()) {
  183. std::pair<int, int>& range = tab_to_available_range_[tab_id];
  184. range.first = std::min(navigation.index(), range.first);
  185. range.second = std::max(navigation.index(), range.second);
  186. }
  187. ScheduleCommand(CreateUpdateTabNavigationCommand(tab_id, navigation));
  188. }
  189. void BrowserPersister::TabNavigationPathPruned(const SessionID& window_id,
  190. const SessionID& tab_id,
  191. int index,
  192. int count) {
  193. if (rebuild_on_next_save_)
  194. return;
  195. DCHECK_GE(index, 0);
  196. DCHECK_GT(count, 0);
  197. // Update the range of available indices.
  198. if (tab_to_available_range_.find(tab_id) != tab_to_available_range_.end()) {
  199. std::pair<int, int>& range = tab_to_available_range_[tab_id];
  200. // if both range.first and range.second are also deleted.
  201. if (range.second >= index && range.second < index + count &&
  202. range.first >= index && range.first < index + count) {
  203. range.first = range.second = 0;
  204. } else {
  205. // Update range.first
  206. if (range.first >= index + count)
  207. range.first = range.first - count;
  208. else if (range.first >= index && range.first < index + count)
  209. range.first = index;
  210. // Update range.second
  211. if (range.second >= index + count)
  212. range.second = std::max(range.first, range.second - count);
  213. else if (range.second >= index && range.second < index + count)
  214. range.second = std::max(range.first, index - 1);
  215. }
  216. }
  217. return ScheduleCommand(
  218. sessions::CreateTabNavigationPathPrunedCommand(tab_id, index, count));
  219. }
  220. void BrowserPersister::TabNavigationPathEntriesDeleted(
  221. const SessionID& window_id,
  222. const SessionID& tab_id) {
  223. if (rebuild_on_next_save_)
  224. return;
  225. // Multiple tabs might be affected by this deletion, so the rebuild is
  226. // delayed until next save.
  227. rebuild_on_next_save_ = true;
  228. command_storage_manager_->StartSaveTimer();
  229. }
  230. void BrowserPersister::ScheduleRebuildOnNextSave() {
  231. rebuild_on_next_save_ = true;
  232. command_storage_manager_->StartSaveTimer();
  233. }
  234. void BrowserPersister::OnGotLastSessionCommands(
  235. std::vector<std::unique_ptr<sessions::SessionCommand>> commands,
  236. bool read_error) {
  237. ScheduleRebuildOnNextSave();
  238. RestoreBrowserState(browser_, std::move(commands));
  239. is_restore_in_progress_ = false;
  240. browser_->OnRestoreCompleted();
  241. }
  242. void BrowserPersister::BuildCommandsForTab(TabImpl* tab, int index_in_browser) {
  243. command_storage_manager_->AppendRebuildCommands(
  244. BuildCommandsForTabConfiguration(browser_session_id_, tab,
  245. index_in_browser));
  246. const SessionID& session_id = GetSessionIDForTab(tab);
  247. content::NavigationController& controller =
  248. tab->web_contents()->GetController();
  249. // Ensure that we don't try to persist initial NavigationEntry, as it is
  250. // not actually associated with any navigation and will just result in
  251. // about:blank on session restore.
  252. bool is_on_initial_entry =
  253. (tab->web_contents()->GetController().GetLastCommittedEntry() &&
  254. tab->web_contents()
  255. ->GetController()
  256. .GetLastCommittedEntry()
  257. ->IsInitialEntry());
  258. const int current_index =
  259. is_on_initial_entry ? -1 : controller.GetCurrentEntryIndex();
  260. const int min_index =
  261. std::max(current_index - sessions::gMaxPersistNavigationCount, 0);
  262. const int max_index =
  263. std::min(current_index + sessions::gMaxPersistNavigationCount,
  264. controller.GetEntryCount());
  265. const int pending_index = controller.GetPendingEntryIndex();
  266. tab_to_available_range_[session_id] =
  267. std::pair<int, int>(min_index, max_index);
  268. for (int i = min_index; i < max_index; ++i) {
  269. content::NavigationEntry* entry = (i == pending_index)
  270. ? controller.GetPendingEntry()
  271. : controller.GetEntryAtIndex(i);
  272. DCHECK(entry);
  273. if (entry->IsInitialEntry())
  274. continue;
  275. const SerializedNavigationEntry navigation =
  276. ContentSerializedNavigationBuilder::FromNavigationEntry(i, entry);
  277. command_storage_manager_->AppendRebuildCommand(
  278. CreateUpdateTabNavigationCommand(session_id, navigation));
  279. }
  280. command_storage_manager_->AppendRebuildCommand(
  281. sessions::CreateSetSelectedNavigationIndexCommand(session_id,
  282. current_index));
  283. // Record the association between the sessionStorage namespace and the tab.
  284. content::SessionStorageNamespace* session_storage_namespace =
  285. controller.GetDefaultSessionStorageNamespace();
  286. ScheduleCommand(sessions::CreateSessionStorageAssociatedCommand(
  287. session_id, session_storage_namespace->id()));
  288. }
  289. void BrowserPersister::BuildCommandsForBrowser() {
  290. // This is necessary for BrowserPersister to restore the browser. The type is
  291. // effectively ignored.
  292. command_storage_manager_->AppendRebuildCommand(
  293. sessions::CreateSetWindowTypeCommand(
  294. browser_session_id_,
  295. sessions::SessionWindow::WindowType::TYPE_NORMAL));
  296. int active_index = -1;
  297. int tab_index = 0;
  298. for (Tab* tab : browser_->GetTabs()) {
  299. BuildCommandsForTab(static_cast<TabImpl*>(tab), tab_index);
  300. if (tab == browser_->GetActiveTab())
  301. active_index = tab_index;
  302. ++tab_index;
  303. }
  304. command_storage_manager_->AppendRebuildCommand(
  305. sessions::CreateSetSelectedTabInWindowCommand(browser_session_id_,
  306. active_index));
  307. }
  308. void BrowserPersister::ScheduleCommand(
  309. std::unique_ptr<sessions::SessionCommand> command) {
  310. DCHECK(command);
  311. if (ReplacePendingCommand(command_storage_manager_.get(), &command))
  312. return;
  313. command_storage_manager_->ScheduleCommand(std::move(command));
  314. if (command_storage_manager_->commands_since_reset() >= kWritesPerReset)
  315. ScheduleRebuildOnNextSave();
  316. }
  317. } // namespace weblayer