blob: e0585400b9969619c66db67e2326d10fef13080b [file] [log] [blame]
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_SYNC_SESSIONS_SYNCED_SESSION_TRACKER_H_
#define COMPONENTS_SYNC_SESSIONS_SYNCED_SESSION_TRACKER_H_
#include <stddef.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/feature_list.h"
#include "base/macros.h"
#include "components/sessions/core/session_id.h"
#include "components/sessions/core/session_types.h"
#include "components/sync_sessions/synced_session.h"
#include "components/sync_sessions/tab_node_pool.h"
namespace sync_pb {
class SessionSpecifics;
}
namespace sync_sessions {
class SyncSessionsClient;
// TODO(crbug.com/882489): Remove feature toggle during code cleanup when a
// satisfying solution is found for closed tabs.
extern const base::Feature kDeferRecyclingOfSyncTabNodesIfUnsynced;
// Class to manage synced sessions. The tracker will own all SyncedSession
// and SyncedSessionTab objects it creates, and deletes them appropriately on
// destruction.
//
// Note: SyncedSession objects are created for all synced sessions, including
// the local session (whose tag we maintain separately).
class SyncedSessionTracker {
public:
// Different ways to lookup/filter tabs.
enum SessionLookup {
RAW, // Return all foreign sessions.
PRESENTABLE // Have one window with at least one tab with syncable content.
};
explicit SyncedSessionTracker(SyncSessionsClient* sessions_client);
~SyncedSessionTracker();
// **** Synced session/tab query methods. ****
// Returns vector with all sessions we're tracking. SyncedSession ownership
// remains within the SyncedSessionTracker. Lookup parameter is used to decide
// which tabs should be included.
std::vector<const SyncedSession*> LookupAllSessions(
SessionLookup lookup) const;
// Returns all foreign sessions we're tracking (skips the local session
// object). SyncedSession ownership remains within the SyncedSessionTracker.
// Lookup parameter is used to decide which foreign tabs should be include.
std::vector<const SyncedSession*> LookupAllForeignSessions(
SessionLookup lookup) const;
// Returns the tab node ids (see GetTab) for all the tabs* associated with the
// session having tag |session_tag|.
std::set<int> LookupTabNodeIds(const std::string& session_tag) const;
// Returns tabs that are unmapped for session with tag |session_tag|.
std::vector<const sessions::SessionTab*> LookupUnmappedTabs(
const std::string& session_tag) const;
// Attempts to look up the session windows associatd with the session given
// by |session_tag|. Ownership of SessionWindows stays within the
// SyncedSessionTracker.
// If lookup succeeds:
// - Fills windows with the SessionWindow pointers, returns true.
// Else
// - Returns false.
bool LookupSessionWindows(
const std::string& session_tag,
std::vector<const sessions::SessionWindow*>* windows) const;
// Attempts to look up the tab associated with the given tag and tab id.
// Ownership of the SessionTab remains within the SyncedSessionTracker.
// Returns null if lookup fails.
const sessions::SessionTab* LookupSessionTab(const std::string& session_tag,
SessionID tab_id) const;
// Allows retrieval of existing data for the local session. Unlike GetSession
// this won't create-if-not-present and will return null instead.
const SyncedSession* LookupLocalSession() const;
// **** Methods for manipulating synced sessions and tabs. ****
// Returns a pointer to the SyncedSession object associated with
// |session_tag|. If none exists, returns nullptr. Ownership of the
// SyncedSession remains within the SyncedSessionTracker.
const SyncedSession* LookupSession(const std::string& session_tag) const;
// Returns a pointer to the SyncedSession object associated with
// |session_tag|. If none exists, creates one. Ownership of the
// SyncedSession remains within the SyncedSessionTracker.
SyncedSession* GetSession(const std::string& session_tag);
// Resets the tracking information for the session specified by |session_tag|.
// This involves clearing all the windows and tabs from the session, while
// keeping pointers saved in the synced_window_map_ and synced_tab_map_. Once
// reset, all calls to PutWindowInSession and PutTabInWindow will denote that
// the requested windows and tabs are owned and add them back to their
// session. The next call to CleanupSession(...) will delete those windows and
// tabs not owned.
void ResetSessionTracking(const std::string& session_tag);
// Deletes those windows and tabs associated with |session_tag| that are no
// longer owned. See ResetSessionTracking(...)..
void CleanupSession(const std::string& session_tag);
// Adds the window with id |window_id| to the session specified by
// |session_tag|. If none existed for that session, creates one. Similarly, if
// the session did not exist yet, creates it. Ownership of the SessionWindow
// remains within the SyncedSessionTracker.
// Attempting to add a window to a session multiple times will have no effect.
void PutWindowInSession(const std::string& session_tag, SessionID window_id);
// Adds the tab with id |tab_id| to the window |window_id|. If none existed
// for that session, creates one. Ownership of the SessionTab remains within
// the SyncedSessionTracker.
//
// Note: GetSession(..) must have already been called with |session_tag| to
// ensure we having mapping information for this session.
void PutTabInWindow(const std::string& session_tag,
SessionID window_id,
SessionID tab_id);
// Adds |tab_node_id| to the session specified by |session_tag|, creating that
// session if necessary. This is necessary to ensure that each session has an
// up to date list of tab nodes linked to it for session deletion purposes.
// Note that this won't update the local tab pool, even if the local session
// tag is passed. The tab pool is only updated with new tab nodes when they're
// associated with a tab id (see ReassociateLocalTabNode or
// GetTabNodeFromLocalTabId).
void OnTabNodeSeen(const std::string& session_tag,
int tab_node_id,
SessionID tab_id);
// Returns a pointer to the SessionTab object associated with
// |tab_id| for the session specified with |session_tag|.
// Note: Ownership of the SessionTab remains within the SyncedSessionTracker.
sessions::SessionTab* GetTab(const std::string& session_tag,
SessionID tab_id);
// **** Methods specific to foreign sessions. ****
// Tracks the deletion of a foreign tab by removing the given |tab_node_id|
// from the parent session. Doesn't actually remove any tab objects because
// the header may have or may not have already been updated to no longer
// parent this tab. Regardless, when the header is updated then cleanup will
// remove the actual tab data. However, this method always needs to be called
// upon foreign tab deletion, otherwise LookupTabNodeIds(...) may return
// already deleted tab node ids.
void DeleteForeignTab(const std::string& session_tag, int tab_node_id);
// Deletes the session associated with |session_tag| if it exists.
// Returns true if the session existed and was deleted, false otherwise.
bool DeleteForeignSession(const std::string& session_tag);
// **** Methods specific to the local session. ****
// Set the local session information. Must be called before any other local
// session methods are invoked.
void InitLocalSession(const std::string& local_session_tag,
const std::string& local_session_name,
sync_pb::SyncEnums::DeviceType local_device_type);
// Gets the session tag previously set with InitLocalSession().
const std::string& GetLocalSessionTag() const;
// Similar to CleanupSession() but also marks unmapped tabs (i.e. closed ones)
// as free tab nodes (which can be reused by future tabs) and triggers garbage
// collection (i.e. deletion) of free tab nodes. It returns the set of locally
// free tab nodes to be deleted. |is_tab_node_unsynced_cb| allows callers to
// prevent tab nodes from being "free" (and hence reusable), which in practice
// is useful to avoid overriding data that hasn't been synced yet.
std::set<int> CleanupLocalTabs(
const base::RepeatingCallback<bool(int /*tab_node_id*/)>&
is_tab_node_unsynced_cb);
// Returns the tab node ID for |tab_id| if an existing tab node was found, or
// kInvalidTabNodeID otherwise.
int LookupTabNodeFromTabId(const std::string& session_tag,
SessionID tab_id) const;
// Returns the tab ID associated to |tab_node_id| or SessionID::InvalidValue()
// if not associated.
SessionID LookupTabIdFromTabNodeId(const std::string& session_tag,
int tab_node_id) const;
// Returns a valid tab node for |tab_id|. Will reuse an existing tab node if
// possible, and otherwise create a new one.
int AssociateLocalTabWithFreeTabNode(SessionID tab_id);
// Reassociates the tab denoted by |tab_node_id| with a new tab id, preserving
// any previous SessionTab object the node was associated with. If
// |new_tab_id| is already associated with a tab object, that tab will be
// overwritten. Reassociating a tab with a node it is already mapped to will
// have no effect.
void ReassociateLocalTab(int tab_node_id, SessionID new_tab_id);
// **** Methods for querying/manipulating overall state ****.
// Free the memory for all dynamically allocated objects and clear the
// tracking structures.
void Clear();
bool Empty() const { return session_map_.empty(); }
// Includes both foreign sessions and the local session.
size_t num_synced_sessions() const { return session_map_.size(); }
// Returns the number of tabs associated with the specified session tag.
size_t num_synced_tabs(const std::string& session_tag) const {
auto iter = session_map_.find(session_tag);
if (iter != session_map_.end()) {
return iter->second.synced_tab_map.size();
} else {
return 0;
}
}
// Returns whether a tab is unmapped or not.
bool IsTabUnmappedForTesting(SessionID tab_id);
private:
friend class SyncedSessionTrackerTest;
struct TrackedSession {
TrackedSession();
~TrackedSession();
// Owns the SyncedSessions, and transitively, all of the windows and tabs
// they contain.
SyncedSession synced_session;
// The mapping of tab/window to their SessionTab/SessionWindow objects.
// The SessionTab/SessionWindow objects referred to may be owned either by
// the session in the |synced_session| or be temporarily unmapped and live
// in the |unmapped_tabs|/|unmapped_windows| collections.
std::map<SessionID, sessions::SessionTab*> synced_tab_map;
std::map<SessionID, SyncedSessionWindow*> synced_window_map;
// The collection of tabs/windows not owned by SyncedSession. This is the
// case either because 1. (in the case of tabs) they were newly created by
// GetTab() and not yet added to a session, or 2. they were removed from
// their owning session by a call to ResetSessionTracking() and not yet
// added back.
std::map<SessionID, std::unique_ptr<sessions::SessionTab>> unmapped_tabs;
std::map<SessionID, std::unique_ptr<SyncedSessionWindow>> unmapped_windows;
// Mappings between tab node IDs and tab IDs. For the local session, it also
// knows about available sync nodes associated with this session.
TabNodePool tab_node_pool;
};
// LookupTrackedSession() returns null if the session tag is unknown.
const TrackedSession* LookupTrackedSession(
const std::string& session_tag) const;
TrackedSession* LookupTrackedSession(const std::string& session_tag);
// Creates tracked session if it wasn't known previously. Never returns null.
TrackedSession* GetTrackedSession(const std::string& session_tag);
std::vector<const SyncedSession*> LookupSessions(
SessionLookup lookup,
bool exclude_local_session) const;
// Implementation of CleanupSession()/CleanupLocalTabs().
void CleanupSessionImpl(
const std::string& session_tag,
const base::RepeatingCallback<bool(int /*tab_node_id*/)>&
is_tab_node_unsynced_cb);
// The client of the sync sessions datatype.
SyncSessionsClient* const sessions_client_;
// Map: session tag -> TrackedSession.
std::map<std::string, TrackedSession> session_map_;
// The tag for this machine's local session, so we can distinguish the foreign
// sessions.
std::string local_session_tag_;
DISALLOW_COPY_AND_ASSIGN(SyncedSessionTracker);
};
// Helper function to load and add window or tab data from synced specifics to
// our internal tracking in SyncedSessionTracker.
void UpdateTrackerWithSpecifics(const sync_pb::SessionSpecifics& specifics,
base::Time modification_time,
SyncedSessionTracker* tracker);
// Generates all sync entities represented by the tracker. Instead of returning
// protos by value, |output_cb| is run for each serialized entity.
void SerializeTrackerToSpecifics(
const SyncedSessionTracker& tracker,
const base::RepeatingCallback<void(const std::string& session_name,
sync_pb::SessionSpecifics* specifics)>&
output_cb);
// Same as above but generates a subset of sync entities represented by the
// tracker, as selected by |session_tag_to_node_ids|. Unknown session tags or
// node IDs will be ignored. kInvalidTabNodeID can be used to request header
// entities.
void SerializePartialTrackerToSpecifics(
const SyncedSessionTracker& tracker,
const std::map<std::string, std::set<int>>& session_tag_to_node_ids,
const base::RepeatingCallback<void(const std::string& session_name,
sync_pb::SessionSpecifics* specifics)>&
output_cb);
} // namespace sync_sessions
#endif // COMPONENTS_SYNC_SESSIONS_SYNCED_SESSION_TRACKER_H_