15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/persistent_tab_restore_service.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cstring>  // memcpy
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_vector.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/task/cancelable_task_tracker.h"
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/base_session_service.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/session_command.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/session_service.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/session_service_factory.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/tab_restore_service_factory.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/session_storage_namespace.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Only written if the tab is pinned.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef bool PinnedStatePayload;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef int32 RestoredEntryPayload;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef std::map<SessionID::id_type, TabRestoreService::Entry*> IDToEntry;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Payload used for the start of a tab close. This is the old struct that is
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// used for backwards compat when it comes to reading the session files.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct SelectedNavigationInTabPayload {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SessionID::id_type id;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 index;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Payload used for the start of a window close. This is the old struct that is
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// used for backwards compat when it comes to reading the session files. This
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// struct must be POD, because we memset the contents.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct WindowPayload {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SessionID::id_type window_id;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 selected_tab_index;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32 num_tabs;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Payload used for the start of a window close.  This struct must be POD,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// because we memset the contents.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct WindowPayload2 : WindowPayload {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 timestamp;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Payload used for the start of a tab close.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct SelectedNavigationInTabPayload2 : SelectedNavigationInTabPayload {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 timestamp;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Used to indicate what has loaded.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum LoadState {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicates we haven't loaded anything.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOT_LOADED           = 1 << 0,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicates we've asked for the last sessions and tabs but haven't gotten the
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // result back yet.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOADING              = 1 << 2,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicates we finished loading the last tabs (but not necessarily the last
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // session).
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOADED_LAST_TABS     = 1 << 3,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicates we finished loading the last session (but not necessarily the
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // last tabs).
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOADED_LAST_SESSION  = 1 << 4
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Identifier for commands written to file. The ordering in the file is as
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// follows:
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// . When the user closes a tab a command of type
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   kCommandSelectedNavigationInTab is written identifying the tab and
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   the selected index, then a kCommandPinnedState command if the tab was
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   pinned and kCommandSetExtensionAppID if the tab has an app id and
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   the user agent override if it was using one.  This is
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   followed by any number of kCommandUpdateTabNavigation commands (1 per
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   navigation entry).
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// . When the user closes a window a kCommandSelectedNavigationInTab command
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   is written out and followed by n tab closed sequences (as previoulsy
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   described).
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// . When the user restores an entry a command of type kCommandRestoredEntry
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   is written.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SessionCommand::id_type kCommandUpdateTabNavigation = 1;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SessionCommand::id_type kCommandRestoredEntry = 2;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SessionCommand::id_type kCommandWindow = 3;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SessionCommand::id_type kCommandSelectedNavigationInTab = 4;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SessionCommand::id_type kCommandPinnedState = 5;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SessionCommand::id_type kCommandSetExtensionAppID = 6;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SessionCommand::id_type kCommandSetWindowAppName = 7;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SessionCommand::id_type kCommandSetTabUserAgentOverride = 8;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Number of entries (not commands) before we clobber the file and write
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// everything.
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kEntriesPerReset = 40;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kMaxEntries = TabRestoreServiceHelper::kMaxEntries;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PersistentTabRestoreService::Delegate ---------------------------------------
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implements the link between the tab restore service and the session backend.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PersistentTabRestoreService::Delegate
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public BaseSessionService,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public TabRestoreServiceHelper::Observer {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit Delegate(Profile* profile);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~Delegate();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // BaseSessionService:
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Save() OVERRIDE;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TabRestoreServiceHelper::Observer:
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnClearEntries() OVERRIDE;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnRestoreEntryById(
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SessionID::id_type id,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Entries::const_iterator entry_iterator) OVERRIDE;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnAddEntry() OVERRIDE;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void set_tab_restore_service_helper(
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TabRestoreServiceHelper* tab_restore_service_helper) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tab_restore_service_helper_ = tab_restore_service_helper;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void LoadTabsFromLastSession();
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool IsLoaded() const;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates and add entries to |entries| for each of the windows in |windows|.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void CreateEntriesFromWindows(std::vector<SessionWindow*>* windows,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       std::vector<Entry*>* entries);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Shutdown();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedules the commands for a window close.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ScheduleCommandsForWindow(const Window& window);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedules the commands for a tab close. |selected_index| gives the index of
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the selected navigation.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ScheduleCommandsForTab(const Tab& tab, int selected_index);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates a window close command.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static SessionCommand* CreateWindowCommand(SessionID::id_type id,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             int selected_tab_index,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             int num_tabs,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             base::Time timestamp);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates a tab close command.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static SessionCommand* CreateSelectedNavigationInTabCommand(
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SessionID::id_type tab_id,
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int32 index,
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Time timestamp);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates a restore command.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static SessionCommand* CreateRestoredEntryCommand(
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SessionID::id_type entry_id);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the index to persist as the selected index. This is the same as
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |tab.current_navigation_index| unless the entry at
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |tab.current_navigation_index| shouldn't be persisted. Returns -1 if no
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // valid navigation to persist.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int GetSelectedNavigationIndexToPersist(const Tab& tab);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Invoked when we've loaded the session commands that identify the previously
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // closed tabs. This creates entries, adds them to staging_entries_, and
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // invokes LoadState.
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void OnGotLastSessionCommands(ScopedVector<SessionCommand> commands);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Populates |loaded_entries| with Entries from |commands|.
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void CreateEntriesFromCommands(const std::vector<SessionCommand*>& commands,
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 std::vector<Entry*>* loaded_entries);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Validates all entries in |entries|, deleting any with no navigations. This
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // also deletes any entries beyond the max number of entries we can hold.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void ValidateAndDeleteEmptyEntries(std::vector<Entry*>* entries);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Callback from SessionService when we've received the windows from the
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // previous session. This creates and add entries to |staging_entries_| and
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // invokes LoadStateChanged. |ignored_active_window| is ignored because we
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // don't need to restore activation.
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void OnGotPreviousSession(ScopedVector<SessionWindow> windows,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            SessionID::id_type ignored_active_window);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Converts a SessionWindow into a Window, returning true on success. We use 0
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // as the timestamp here since we do not know when the window/tab was closed.
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool ConvertSessionWindowToWindow(SessionWindow* session_window,
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           Window* window);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Invoked when previous tabs or session is loaded. If both have finished
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // loading the entries in |staging_entries_| are added to entries and
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // observers are notified.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void LoadStateChanged();
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |id_to_entry| contains an entry for |id| the corresponding entry is
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // deleted and removed from both |id_to_entry| and |entries|. This is used
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when creating entries from the backend file.
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RemoveEntryByID(SessionID::id_type id,
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       IDToEntry* id_to_entry,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       std::vector<TabRestoreService::Entry*>* entries);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TabRestoreServiceHelper* tab_restore_service_helper_;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The number of entries to write.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int entries_to_write_;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Number of entries we've written.
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int entries_written_;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Whether we've loaded the last session.
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int load_state_;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Results from previously closed tabs/sessions is first added here. When the
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // results from both us and the session restore service have finished loading
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LoadStateChanged is invoked, which adds these entries to entries_.
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedVector<Entry> staging_entries_;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Used when loading previous tabs/session and open tabs/session.
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::CancelableTaskTracker cancelable_task_tracker_;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Delegate);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PersistentTabRestoreService::Delegate::Delegate(Profile* profile)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : BaseSessionService(BaseSessionService::TAB_RESTORE, profile,
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         base::FilePath()),
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_restore_service_helper_(NULL),
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries_to_write_(0),
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries_written_(0),
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      load_state_(NOT_LOADED) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)PersistentTabRestoreService::Delegate::~Delegate() {}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::Save() {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Entries& entries = tab_restore_service_helper_->entries();
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int to_write_count = std::min(entries_to_write_,
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                static_cast<int>(entries.size()));
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_to_write_ = 0;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entries_written_ + to_write_count > kEntriesPerReset) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    to_write_count = entries.size();
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    set_pending_reset(true);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (to_write_count) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Write the to_write_count most recently added entries out. The most
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // recently added entry is at the front, so we use a reverse iterator to
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // write in the order the entries were added.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Entries::const_reverse_iterator i = entries.rbegin();
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(static_cast<size_t>(to_write_count) <= entries.size());
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::advance(i, entries.size() - static_cast<int>(to_write_count));
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (; i != entries.rend(); ++i) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Entry* entry = *i;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (entry->type == TAB) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Tab* tab = static_cast<Tab*>(entry);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int selected_index = GetSelectedNavigationIndexToPersist(*tab);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (selected_index != -1)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ScheduleCommandsForTab(*tab, selected_index);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ScheduleCommandsForWindow(*static_cast<Window*>(entry));
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries_written_++;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pending_reset())
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries_written_ = 0;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BaseSessionService::Save();
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::OnClearEntries() {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mark all the tabs as closed so that we don't attempt to restore them.
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Entries& entries = tab_restore_service_helper_->entries();
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (Entries::const_iterator i = entries.begin(); i != entries.end(); ++i)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommand(CreateRestoredEntryCommand((*i)->id));
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_to_write_ = 0;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedule a pending reset so that we nuke the file on next write.
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_pending_reset(true);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedule a command, otherwise if there are no pending commands Save does
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // nothing.
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommand(CreateRestoredEntryCommand(1));
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::OnRestoreEntryById(
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SessionID::id_type id,
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Entries::const_iterator entry_iterator) {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t index = 0;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Entries& entries = tab_restore_service_helper_->entries();
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (Entries::const_iterator j = entries.begin();
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       j != entry_iterator && j != entries.end();
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++j, ++index) {}
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (static_cast<int>(index) < entries_to_write_)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries_to_write_--;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommand(CreateRestoredEntryCommand(id));
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::OnAddEntry() {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start the save timer, when it fires we'll generate the commands.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartSaveTimer();
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_to_write_++;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::LoadTabsFromLastSession() {
320a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (load_state_ != NOT_LOADED)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
323a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (tab_restore_service_helper_->entries().size() == kMaxEntries) {
324a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // We already have the max number of entries we can take. There is no point
325a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // in attempting to load since we'll just drop the results. Skip to loaded.
326a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    load_state_ = (LOADING | LOADED_LAST_SESSION | LOADED_LAST_TABS);
327a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    LoadStateChanged();
328a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return;
329a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
330a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(ENABLE_SESSION_SERVICE)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If sessions are not stored in the SessionService, default to
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |LOADED_LAST_SESSION| state.
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  load_state_ = LOADING | LOADED_LAST_SESSION;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  load_state_ = LOADING;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SessionService* session_service =
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SessionServiceFactory::GetForProfile(profile());
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile::ExitType exit_type = profile()->GetLastSessionExitType();
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!profile()->restored_last_session() && session_service &&
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (exit_type == Profile::EXIT_CRASHED ||
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       exit_type == Profile::EXIT_SESSION_ENDED)) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The previous session crashed and wasn't restored, or was a forced
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // shutdown. Both of which won't have notified us of the browser close so
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that we need to load the windows from session service (which will have
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // saved them).
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    session_service->GetLastSession(
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&Delegate::OnGotPreviousSession, base::Unretained(this)),
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        &cancelable_task_tracker_);
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    load_state_ |= LOADED_LAST_SESSION;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Request the tabs closed in the last session. If the last session crashed,
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this won't contain the tabs/window that were open at the point of the
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // crash (the call to GetLastSession above requests those).
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleGetLastSessionCommands(
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&Delegate::OnGotLastSessionCommands, base::Unretained(this)),
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &cancelable_task_tracker_);
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PersistentTabRestoreService::Delegate::IsLoaded() const {
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !(load_state_ & (NOT_LOADED | LOADING));
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::CreateEntriesFromWindows(
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<SessionWindow*>* windows,
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<Entry*>* entries) {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < windows->size(); ++i) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<Window> window(new Window());
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ConvertSessionWindowToWindow((*windows)[i], window.get()))
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries->push_back(window.release());
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::Shutdown() {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (backend())
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Save();
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::ScheduleCommandsForWindow(
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Window& window) {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!window.tabs.empty());
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int selected_tab = window.selected_tab_index;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int valid_tab_count = 0;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int real_selected_tab = selected_tab;
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < window.tabs.size(); ++i) {
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (GetSelectedNavigationIndexToPersist(window.tabs[i]) != -1) {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      valid_tab_count++;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (static_cast<int>(i) < selected_tab) {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      real_selected_tab--;
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (valid_tab_count == 0)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // No tabs to persist.
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommand(
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CreateWindowCommand(window.id,
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          std::min(real_selected_tab, valid_tab_count - 1),
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          valid_tab_count,
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          window.timestamp));
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!window.app_name.empty()) {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommand(
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CreateSetWindowAppNameCommand(kCommandSetWindowAppName,
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      window.id,
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      window.app_name));
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < window.tabs.size(); ++i) {
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int selected_index = GetSelectedNavigationIndexToPersist(window.tabs[i]);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (selected_index != -1)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ScheduleCommandsForTab(window.tabs[i], selected_index);
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::ScheduleCommandsForTab(
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Tab& tab,
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int selected_index) {
423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const std::vector<sessions::SerializedNavigationEntry>& navigations =
424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      tab.navigations;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_index = static_cast<int>(navigations.size());
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Determine the first navigation we'll persist.
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int valid_count_before_selected = 0;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int first_index_to_persist = selected_index;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = selected_index - 1; i >= 0 &&
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       valid_count_before_selected < max_persist_navigation_count; --i) {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ShouldTrackEntry(navigations[i].virtual_url())) {
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_index_to_persist = i;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      valid_count_before_selected++;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Write the command that identifies the selected tab.
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleCommand(
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CreateSelectedNavigationInTabCommand(tab.id,
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           valid_count_before_selected,
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           tab.timestamp));
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tab.pinned) {
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PinnedStatePayload payload = true;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SessionCommand* command =
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new SessionCommand(kCommandPinnedState, sizeof(payload));
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(command->contents(), &payload, sizeof(payload));
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommand(command);
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!tab.extension_app_id.empty()) {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommand(
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CreateSetTabExtensionAppIDCommand(kCommandSetExtensionAppID, tab.id,
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          tab.extension_app_id));
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!tab.user_agent_override.empty()) {
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleCommand(
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CreateSetTabUserAgentOverrideCommand(kCommandSetTabUserAgentOverride,
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             tab.id, tab.user_agent_override));
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Then write the navigations.
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = first_index_to_persist, wrote_count = 0;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i < max_index && wrote_count < 2 * max_persist_navigation_count; ++i) {
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ShouldTrackEntry(navigations[i].virtual_url())) {
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ScheduleCommand(
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          CreateUpdateTabNavigationCommand(kCommandUpdateTabNavigation, tab.id,
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           navigations[i]));
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SessionCommand* PersistentTabRestoreService::Delegate::CreateWindowCommand(
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SessionID::id_type id,
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int selected_tab_index,
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int num_tabs,
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time timestamp) {
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WindowPayload2 payload;
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |timestamp| is aligned on a 16 byte boundary, leaving 4 bytes of
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // uninitialized memory in the struct.
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&payload, 0, sizeof(payload));
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  payload.window_id = id;
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  payload.selected_tab_index = selected_tab_index;
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  payload.num_tabs = num_tabs;
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  payload.timestamp = timestamp.ToInternalValue();
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SessionCommand* command =
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new SessionCommand(kCommandWindow, sizeof(payload));
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(command->contents(), &payload, sizeof(payload));
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return command;
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SessionCommand*
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PersistentTabRestoreService::Delegate::CreateSelectedNavigationInTabCommand(
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SessionID::id_type tab_id,
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int32 index,
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time timestamp) {
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SelectedNavigationInTabPayload2 payload;
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  payload.id = tab_id;
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  payload.index = index;
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  payload.timestamp = timestamp.ToInternalValue();
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SessionCommand* command =
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new SessionCommand(kCommandSelectedNavigationInTab, sizeof(payload));
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(command->contents(), &payload, sizeof(payload));
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return command;
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SessionCommand*
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PersistentTabRestoreService::Delegate::CreateRestoredEntryCommand(
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SessionID::id_type entry_id) {
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RestoredEntryPayload payload = entry_id;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SessionCommand* command =
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new SessionCommand(kCommandRestoredEntry, sizeof(payload));
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(command->contents(), &payload, sizeof(payload));
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return command;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int PersistentTabRestoreService::Delegate::GetSelectedNavigationIndexToPersist(
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Tab& tab) {
525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const std::vector<sessions::SerializedNavigationEntry>& navigations =
526c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      tab.navigations;
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int selected_index = tab.current_navigation_index;
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_index = static_cast<int>(navigations.size());
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the first navigation to persist. We won't persist the selected
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // navigation if ShouldTrackEntry returns false.
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (selected_index >= 0 &&
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         !ShouldTrackEntry(navigations[selected_index].virtual_url())) {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    selected_index--;
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (selected_index != -1)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return selected_index;
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Couldn't find a navigation to persist going back, go forward.
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  selected_index = tab.current_navigation_index + 1;
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (selected_index < max_index &&
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         !ShouldTrackEntry(navigations[selected_index].virtual_url())) {
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    selected_index++;
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (selected_index == max_index) ? -1 : selected_index;
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::OnGotLastSessionCommands(
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ScopedVector<SessionCommand> commands) {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<Entry*> entries;
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CreateEntriesFromCommands(commands.get(), &entries);
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Closed tabs always go to the end.
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  staging_entries_.insert(staging_entries_.end(), entries.begin(),
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          entries.end());
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  load_state_ |= LOADED_LAST_TABS;
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadStateChanged();
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands(
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<SessionCommand*>& commands,
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<Entry*>* loaded_entries) {
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (tab_restore_service_helper_->entries().size() == kMaxEntries)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iterate through the commands populating entries and id_to_entry.
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<Entry> entries;
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IDToEntry id_to_entry;
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If non-null we're processing the navigations of this tab.
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tab* current_tab = NULL;
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If non-null we're processing the tabs of this window.
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Window* current_window = NULL;
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If > 0, we've gotten a window command but not all the tabs yet.
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pending_window_tabs = 0;
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<SessionCommand*>::const_iterator i = commands.begin();
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != commands.end(); ++i) {
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SessionCommand& command = *(*i);
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (command.id()) {
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kCommandRestoredEntry: {
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (pending_window_tabs > 0) {
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Should never receive a restored command while waiting for all the
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // tabs in a window.
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_tab = NULL;
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_window = NULL;
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        RestoredEntryPayload payload;
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!command.GetPayload(&payload, sizeof(payload)))
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        RemoveEntryByID(payload, &id_to_entry, &(entries.get()));
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kCommandWindow: {
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        WindowPayload2 payload;
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (pending_window_tabs > 0) {
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Should never receive a window command while waiting for all the
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // tabs in a window.
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Try the new payload first
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!command.GetPayload(&payload, sizeof(payload))) {
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // then the old payload
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          WindowPayload old_payload;
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!command.GetPayload(&old_payload, sizeof(old_payload)))
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return;
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Copy the old payload data to the new payload.
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          payload.window_id = old_payload.window_id;
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          payload.selected_tab_index = old_payload.selected_tab_index;
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          payload.num_tabs = old_payload.num_tabs;
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Since we don't have a time use time 0 which is used to mark as an
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // unknown timestamp.
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          payload.timestamp = 0;
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pending_window_tabs = payload.num_tabs;
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (pending_window_tabs <= 0) {
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Should always have at least 1 tab. Likely indicates corruption.
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        RemoveEntryByID(payload.window_id, &id_to_entry, &(entries.get()));
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_window = new Window();
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_window->selected_tab_index = payload.selected_tab_index;
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_window->timestamp =
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            base::Time::FromInternalValue(payload.timestamp);
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        entries.push_back(current_window);
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        id_to_entry[payload.window_id] = current_window;
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kCommandSelectedNavigationInTab: {
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SelectedNavigationInTabPayload2 payload;
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!command.GetPayload(&payload, sizeof(payload))) {
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          SelectedNavigationInTabPayload old_payload;
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!command.GetPayload(&old_payload, sizeof(old_payload)))
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return;
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          payload.id = old_payload.id;
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          payload.index = old_payload.index;
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Since we don't have a time use time 0 which is used to mark as an
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // unknown timestamp.
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          payload.timestamp = 0;
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (pending_window_tabs > 0) {
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!current_window) {
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // We should have created a window already.
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            NOTREACHED();
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return;
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          current_window->tabs.resize(current_window->tabs.size() + 1);
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          current_tab = &(current_window->tabs.back());
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (--pending_window_tabs == 0)
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            current_window = NULL;
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          RemoveEntryByID(payload.id, &id_to_entry, &(entries.get()));
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          current_tab = new Tab();
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          id_to_entry[payload.id] = current_tab;
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          current_tab->timestamp =
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              base::Time::FromInternalValue(payload.timestamp);
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          entries.push_back(current_tab);
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_tab->current_navigation_index = payload.index;
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kCommandUpdateTabNavigation: {
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!current_tab) {
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Should be in a tab when we get this.
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_tab->navigations.resize(current_tab->navigations.size() + 1);
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SessionID::id_type tab_id;
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!RestoreUpdateTabNavigationCommand(
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            command, &current_tab->navigations.back(), &tab_id)) {
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kCommandPinnedState: {
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!current_tab) {
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Should be in a tab when we get this.
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // NOTE: payload doesn't matter. kCommandPinnedState is only written if
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // tab is pinned.
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_tab->pinned = true;
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kCommandSetWindowAppName: {
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!current_window) {
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // We should have created a window already.
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          NOTREACHED();
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SessionID::id_type window_id;
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::string app_name;
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!RestoreSetWindowAppNameCommand(command, &window_id, &app_name))
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_window->app_name.swap(app_name);
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kCommandSetExtensionAppID: {
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!current_tab) {
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Should be in a tab when we get this.
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SessionID::id_type tab_id;
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::string extension_app_id;
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!RestoreSetTabExtensionAppIDCommand(command, &tab_id,
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &extension_app_id)) {
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_tab->extension_app_id.swap(extension_app_id);
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kCommandSetTabUserAgentOverride: {
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!current_tab) {
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Should be in a tab when we get this.
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SessionID::id_type tab_id;
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::string user_agent_override;
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!RestoreSetTabUserAgentOverrideCommand(command, &tab_id,
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   &user_agent_override)) {
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_tab->user_agent_override.swap(user_agent_override);
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Unknown type, usually indicates corruption of file. Ignore it.
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there was corruption some of the entries won't be valid.
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ValidateAndDeleteEmptyEntries(&(entries.get()));
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  loaded_entries->swap(entries.get());
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::ValidateAndDeleteEmptyEntries(
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<Entry*>* entries) {
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<Entry*> valid_entries;
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<Entry*> invalid_entries;
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iterate from the back so that we keep the most recently closed entries.
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<Entry*>::reverse_iterator i = entries->rbegin();
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != entries->rend(); ++i) {
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (TabRestoreServiceHelper::ValidateEntry(*i))
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      valid_entries.push_back(*i);
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      invalid_entries.push_back(*i);
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: at this point the entries are ordered with newest at the front.
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries->swap(valid_entries);
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete the remaining entries.
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&invalid_entries);
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::OnGotPreviousSession(
7782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ScopedVector<SessionWindow> windows,
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SessionID::id_type ignored_active_window) {
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<Entry*> entries;
7812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CreateEntriesFromWindows(&windows.get(), &entries);
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Previous session tabs go first.
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  staging_entries_.insert(staging_entries_.begin(), entries.begin(),
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          entries.end());
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  load_state_ |= LOADED_LAST_SESSION;
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadStateChanged();
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PersistentTabRestoreService::Delegate::ConvertSessionWindowToWindow(
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SessionWindow* session_window,
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Window* window) {
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < session_window->tabs.size(); ++i) {
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!session_window->tabs[i]->navigations.empty()) {
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window->tabs.resize(window->tabs.size() + 1);
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Tab& tab = window->tabs.back();
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab.pinned = session_window->tabs[i]->pinned;
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab.navigations.swap(session_window->tabs[i]->navigations);
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab.current_navigation_index =
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          session_window->tabs[i]->current_navigation_index;
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab.extension_app_id = session_window->tabs[i]->extension_app_id;
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab.timestamp = base::Time();
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (window->tabs.empty())
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window->selected_tab_index =
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::min(session_window->selected_tab_index,
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               static_cast<int>(window->tabs.size() - 1));
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window->timestamp = base::Time();
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::LoadStateChanged() {
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((load_state_ & (LOADED_LAST_TABS | LOADED_LAST_SESSION)) !=
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (LOADED_LAST_TABS | LOADED_LAST_SESSION)) {
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Still waiting on previous session or previous tabs.
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We're done loading.
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  load_state_ ^= LOADING;
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Entries& entries = tab_restore_service_helper_->entries();
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (staging_entries_.empty() || entries.size() >= kMaxEntries) {
826c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    staging_entries_.clear();
827a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    tab_restore_service_helper_->NotifyLoaded();
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (staging_entries_.size() + entries.size() > kMaxEntries) {
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we add all the staged entries we'll end up with more than
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // kMaxEntries. Delete entries such that we only end up with at most
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // kMaxEntries.
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int surplus = kMaxEntries - entries.size();
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK_LE(0, surplus);
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK_GE(static_cast<int>(staging_entries_.size()), surplus);
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    staging_entries_.erase(
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        staging_entries_.begin() + (kMaxEntries - entries.size()),
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        staging_entries_.end());
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // And add them.
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < staging_entries_.size(); ++i) {
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    staging_entries_[i]->from_last_session = true;
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tab_restore_service_helper_->AddEntry(staging_entries_[i], false, false);
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // AddEntry takes ownership of the entry, need to clear out entries so that
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it doesn't delete them.
851c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  staging_entries_.weak_clear();
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make it so we rewrite all the tabs. We need to do this otherwise we won't
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // correctly write out the entries when Save is invoked (Save starts from
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the front, not the end and we just added the entries to the end).
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_to_write_ = staging_entries_.size();
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_restore_service_helper_->PruneEntries();
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_restore_service_helper_->NotifyTabsChanged();
860a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
861a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  tab_restore_service_helper_->NotifyLoaded();
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Delegate::RemoveEntryByID(
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SessionID::id_type id,
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IDToEntry* id_to_entry,
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<TabRestoreService::Entry*>* entries) {
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Look for the entry in the map. If it is present, erase it from both
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // collections and return.
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IDToEntry::iterator i = id_to_entry->find(id);
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (i != id_to_entry->end()) {
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->erase(std::find(entries->begin(), entries->end(), i->second));
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete i->second;
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    id_to_entry->erase(i);
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Otherwise, loop over all items in the map and see if any of the Windows
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // have Tabs with the |id|.
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (IDToEntry::iterator i = id_to_entry->begin(); i != id_to_entry->end();
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++i) {
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i->second->type == TabRestoreService::WINDOW) {
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TabRestoreService::Window* window =
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static_cast<TabRestoreService::Window*>(i->second);
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<TabRestoreService::Tab>::iterator j = window->tabs.begin();
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for ( ; j != window->tabs.end(); ++j) {
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the ID matches one of this window's tabs, remove it from the
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // list.
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ((*j).id == id) {
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window->tabs.erase(j);
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PersistentTabRestoreService -------------------------------------------------
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PersistentTabRestoreService::PersistentTabRestoreService(
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Profile* profile,
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TimeFactory* time_factory)
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(new Delegate(profile)),
904c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      helper_(this, delegate_.get(), profile, time_factory) {
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->set_tab_restore_service_helper(&helper_);
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PersistentTabRestoreService::~PersistentTabRestoreService() {}
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::AddObserver(
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreServiceObserver* observer) {
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  helper_.AddObserver(observer);
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::RemoveObserver(
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreServiceObserver* observer) {
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  helper_.RemoveObserver(observer);
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::CreateHistoricalTab(
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::WebContents* contents,
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index) {
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  helper_.CreateHistoricalTab(contents, index);
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::BrowserClosing(
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreServiceDelegate* delegate) {
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  helper_.BrowserClosing(delegate);
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::BrowserClosed(
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreServiceDelegate* delegate) {
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  helper_.BrowserClosed(delegate);
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::ClearEntries() {
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  helper_.ClearEntries();
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const TabRestoreService::Entries& PersistentTabRestoreService::entries() const {
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return helper_.entries();
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9443240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochstd::vector<content::WebContents*>
9453240926e260ce088908e02ac07a6cf7b0c0cbf44Ben MurdochPersistentTabRestoreService::RestoreMostRecentEntry(
9462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    TabRestoreServiceDelegate* delegate,
9472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    chrome::HostDesktopType host_desktop_type) {
9483240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  return helper_.RestoreMostRecentEntry(delegate, host_desktop_type);
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabRestoreService::Tab* PersistentTabRestoreService::RemoveTabEntryById(
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SessionID::id_type id) {
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return helper_.RemoveTabEntryById(id);
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9563240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochstd::vector<content::WebContents*>
9573240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    PersistentTabRestoreService::RestoreEntryById(
9583240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      TabRestoreServiceDelegate* delegate,
9593240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      SessionID::id_type id,
9603240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      chrome::HostDesktopType host_desktop_type,
9613240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      WindowOpenDisposition disposition) {
9623240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  return helper_.RestoreEntryById(delegate, id, host_desktop_type, disposition);
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PersistentTabRestoreService::IsLoaded() const {
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return delegate_->IsLoaded();
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::DeleteLastSession() {
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return delegate_->DeleteLastSession();
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::Shutdown() {
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return delegate_->Shutdown();
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::LoadTabsFromLastSession() {
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->LoadTabsFromLastSession();
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabRestoreService::Entries* PersistentTabRestoreService::mutable_entries() {
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return &helper_.entries_;
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PersistentTabRestoreService::PruneEntries() {
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  helper_.PruneEntries();
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
989a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)KeyedService* TabRestoreServiceFactory::BuildServiceInstanceFor(
990c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    content::BrowserContext* profile) const {
991c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return new PersistentTabRestoreService(static_cast<Profile*>(profile), NULL);
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
993