summaryrefslogtreecommitdiff
path: root/chromium/components/sync_sessions/synced_session_tracker.h
blob: 24dac10ad45c33f93e2267d11fe3aa34b694a269 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
// 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/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;

// 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.
  // TODO(zea): Replace SessionTab with a Sync specific wrapper.
  // https://crbug.com/662597
  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 CleanupForeignSession, but also marks any unmapped tabs as free
  // in the tab node pool and fills |deleted_node_ids| with the set of locally
  // free tab nodes to be deleted.
  void CleanupLocalTabs(std::set<int>* deleted_node_ids);

  // 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. This is useful
  // on restart when sync needs to reassociate tabs from a previous session with
  // newly restored tabs (and can be used in conjunction with PutTabInWindow).
  // 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 CleanupForeignSession/CleanupLocalTabs.
  void CleanupSessionImpl(const std::string& session_tag);

  // 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_