1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/sessions/session_service_commands.h"
9 #include "base/pickle.h"
10 #include "components/sessions/base_session_service_commands.h"
11 #include "components/sessions/base_session_service_delegate.h"
12 #include "components/sessions/session_command.h"
13 #include "components/sessions/session_types.h"
17 // Identifier for commands written to file.
18 static const SessionCommand::id_type kCommandSetTabWindow
= 0;
19 // OBSOLETE Superseded by kCommandSetWindowBounds3.
20 // static const SessionCommand::id_type kCommandSetWindowBounds = 1;
21 static const SessionCommand::id_type kCommandSetTabIndexInWindow
= 2;
22 static const SessionCommand::id_type
23 kCommandTabNavigationPathPrunedFromBack
= 5;
24 static const SessionCommand::id_type kCommandUpdateTabNavigation
= 6;
25 static const SessionCommand::id_type kCommandSetSelectedNavigationIndex
= 7;
26 static const SessionCommand::id_type kCommandSetSelectedTabInIndex
= 8;
27 static const SessionCommand::id_type kCommandSetWindowType
= 9;
28 // OBSOLETE Superseded by kCommandSetWindowBounds3. Except for data migration.
29 // static const SessionCommand::id_type kCommandSetWindowBounds2 = 10;
30 static const SessionCommand::id_type
31 kCommandTabNavigationPathPrunedFromFront
= 11;
32 static const SessionCommand::id_type kCommandSetPinnedState
= 12;
33 static const SessionCommand::id_type kCommandSetExtensionAppID
= 13;
34 static const SessionCommand::id_type kCommandSetWindowBounds3
= 14;
35 static const SessionCommand::id_type kCommandSetWindowAppName
= 15;
36 static const SessionCommand::id_type kCommandTabClosed
= 16;
37 static const SessionCommand::id_type kCommandWindowClosed
= 17;
38 static const SessionCommand::id_type kCommandSetTabUserAgentOverride
= 18;
39 static const SessionCommand::id_type kCommandSessionStorageAssociated
= 19;
40 static const SessionCommand::id_type kCommandSetActiveWindow
= 20;
41 static const SessionCommand::id_type kCommandLastActiveTime
= 21;
45 // Various payload structures.
46 struct ClosedPayload
{
47 SessionID::id_type id
;
51 struct WindowBoundsPayload2
{
52 SessionID::id_type window_id
;
60 struct WindowBoundsPayload3
{
61 SessionID::id_type window_id
;
69 typedef SessionID::id_type ActiveWindowPayload
;
71 struct IDAndIndexPayload
{
72 SessionID::id_type id
;
76 typedef IDAndIndexPayload TabIndexInWindowPayload
;
78 typedef IDAndIndexPayload TabNavigationPathPrunedFromBackPayload
;
80 typedef IDAndIndexPayload SelectedNavigationIndexPayload
;
82 typedef IDAndIndexPayload SelectedTabInIndexPayload
;
84 typedef IDAndIndexPayload WindowTypePayload
;
86 typedef IDAndIndexPayload TabNavigationPathPrunedFromFrontPayload
;
88 struct PinnedStatePayload
{
89 SessionID::id_type tab_id
;
93 struct LastActiveTimePayload
{
94 SessionID::id_type tab_id
;
95 int64 last_active_time
;
98 // Persisted versions of ui::WindowShowState that are written to disk and can
100 enum PersistedWindowShowState
{
101 // SHOW_STATE_DEFAULT (0) never persisted.
102 PERSISTED_SHOW_STATE_NORMAL
= 1,
103 PERSISTED_SHOW_STATE_MINIMIZED
= 2,
104 PERSISTED_SHOW_STATE_MAXIMIZED
= 3,
105 // SHOW_STATE_INACTIVE (4) never persisted.
106 PERSISTED_SHOW_STATE_FULLSCREEN
= 5,
107 PERSISTED_SHOW_STATE_DETACHED_DEPRECATED
= 6,
108 PERSISTED_SHOW_STATE_DOCKED
= 7,
109 PERSISTED_SHOW_STATE_END
= 7
112 typedef std::map
<SessionID::id_type
, SessionTab
*> IdToSessionTab
;
113 typedef std::map
<SessionID::id_type
, SessionWindow
*> IdToSessionWindow
;
115 // Assert to ensure PersistedWindowShowState is updated if ui::WindowShowState
117 static_assert(ui::SHOW_STATE_END
==
118 static_cast<ui::WindowShowState
>(PERSISTED_SHOW_STATE_END
),
119 "SHOW_STATE_END must equal PERSISTED_SHOW_STATE_END");
121 // Returns the show state to store to disk based |state|.
122 PersistedWindowShowState
ShowStateToPersistedShowState(
123 ui::WindowShowState state
) {
125 case ui::SHOW_STATE_NORMAL
:
126 return PERSISTED_SHOW_STATE_NORMAL
;
127 case ui::SHOW_STATE_MINIMIZED
:
128 return PERSISTED_SHOW_STATE_MINIMIZED
;
129 case ui::SHOW_STATE_MAXIMIZED
:
130 return PERSISTED_SHOW_STATE_MAXIMIZED
;
131 case ui::SHOW_STATE_FULLSCREEN
:
132 return PERSISTED_SHOW_STATE_FULLSCREEN
;
133 case ui::SHOW_STATE_DOCKED
:
134 return PERSISTED_SHOW_STATE_DOCKED
;
136 case ui::SHOW_STATE_DEFAULT
:
137 case ui::SHOW_STATE_INACTIVE
:
138 return PERSISTED_SHOW_STATE_NORMAL
;
140 case ui::SHOW_STATE_END
:
144 return PERSISTED_SHOW_STATE_NORMAL
;
147 // Lints show state values when read back from persited disk.
148 ui::WindowShowState
PersistedShowStateToShowState(int state
) {
150 case PERSISTED_SHOW_STATE_NORMAL
:
151 return ui::SHOW_STATE_NORMAL
;
152 case PERSISTED_SHOW_STATE_MINIMIZED
:
153 return ui::SHOW_STATE_MINIMIZED
;
154 case PERSISTED_SHOW_STATE_MAXIMIZED
:
155 return ui::SHOW_STATE_MAXIMIZED
;
156 case PERSISTED_SHOW_STATE_FULLSCREEN
:
157 return ui::SHOW_STATE_FULLSCREEN
;
158 case PERSISTED_SHOW_STATE_DOCKED
:
159 return ui::SHOW_STATE_DOCKED
;
160 case PERSISTED_SHOW_STATE_DETACHED_DEPRECATED
:
161 return ui::SHOW_STATE_NORMAL
;
164 return ui::SHOW_STATE_NORMAL
;
167 // Iterates through the vector updating the selected_tab_index of each
168 // SessionWindow based on the actual tabs that were restored.
169 void UpdateSelectedTabIndex(std::vector
<SessionWindow
*>* windows
) {
170 for (std::vector
<SessionWindow
*>::const_iterator i
= windows
->begin();
171 i
!= windows
->end(); ++i
) {
172 // See note in SessionWindow as to why we do this.
174 for (std::vector
<SessionTab
*>::const_iterator j
= (*i
)->tabs
.begin();
175 j
!= (*i
)->tabs
.end(); ++j
) {
176 if ((*j
)->tab_visual_index
== (*i
)->selected_tab_index
) {
177 new_index
= static_cast<int>(j
- (*i
)->tabs
.begin());
181 (*i
)->selected_tab_index
= new_index
;
185 // Returns the window in windows with the specified id. If a window does
186 // not exist, one is created.
187 SessionWindow
* GetWindow(SessionID::id_type window_id
,
188 IdToSessionWindow
* windows
) {
189 std::map
<int, SessionWindow
*>::iterator i
= windows
->find(window_id
);
190 if (i
== windows
->end()) {
191 SessionWindow
* window
= new SessionWindow();
192 window
->window_id
.set_id(window_id
);
193 (*windows
)[window_id
] = window
;
199 // Returns the tab with the specified id in tabs. If a tab does not exist,
201 SessionTab
* GetTab(SessionID::id_type tab_id
, IdToSessionTab
* tabs
) {
203 std::map
<int, SessionTab
*>::iterator i
= tabs
->find(tab_id
);
204 if (i
== tabs
->end()) {
205 SessionTab
* tab
= new SessionTab();
206 tab
->tab_id
.set_id(tab_id
);
207 (*tabs
)[tab_id
] = tab
;
213 // Returns an iterator into navigations pointing to the navigation whose
214 // index matches |index|. If no navigation index matches |index|, the first
215 // navigation with an index > |index| is returned.
217 // This assumes the navigations are ordered by index in ascending order.
218 std::vector
<sessions::SerializedNavigationEntry
>::iterator
219 FindClosestNavigationWithIndex(
220 std::vector
<sessions::SerializedNavigationEntry
>* navigations
,
223 for (std::vector
<sessions::SerializedNavigationEntry
>::iterator
224 i
= navigations
->begin(); i
!= navigations
->end(); ++i
) {
225 if (i
->index() >= index
)
228 return navigations
->end();
231 // Function used in sorting windows. Sorting is done based on window id. As
232 // window ids increment for each new window, this effectively sorts by creation
234 static bool WindowOrderSortFunction(const SessionWindow
* w1
,
235 const SessionWindow
* w2
) {
236 return w1
->window_id
.id() < w2
->window_id
.id();
239 // Compares the two tabs based on visual index.
240 static bool TabVisualIndexSortFunction(const SessionTab
* t1
,
241 const SessionTab
* t2
) {
242 const int delta
= t1
->tab_visual_index
- t2
->tab_visual_index
;
243 return delta
== 0 ? (t1
->tab_id
.id() < t2
->tab_id
.id()) : (delta
< 0);
246 // Does the following:
247 // . Deletes and removes any windows with no tabs. NOTE: constrained windows
248 // that have been dragged out are of type browser. As such, this preserves any
249 // dragged out constrained windows (aka popups that have been dragged out).
250 // . Sorts the tabs in windows with valid tabs based on the tabs
251 // visual order, and adds the valid windows to windows.
252 void SortTabsBasedOnVisualOrderAndPrune(
253 std::map
<int, SessionWindow
*>* windows
,
254 std::vector
<SessionWindow
*>* valid_windows
) {
255 std::map
<int, SessionWindow
*>::iterator i
= windows
->begin();
256 while (i
!= windows
->end()) {
257 SessionWindow
* window
= i
->second
;
258 if (window
->tabs
.empty() || window
->is_constrained
) {
262 // Valid window; sort the tabs and add it to the list of valid windows.
263 std::sort(window
->tabs
.begin(), window
->tabs
.end(),
264 &TabVisualIndexSortFunction
);
265 // Otherwise, add the window such that older windows appear first.
266 if (valid_windows
->empty()) {
267 valid_windows
->push_back(window
);
269 valid_windows
->insert(
270 std::upper_bound(valid_windows
->begin(), valid_windows
->end(),
271 window
, &WindowOrderSortFunction
),
279 // Adds tabs to their parent window based on the tab's window_id. This
280 // ignores tabs with no navigations.
281 void AddTabsToWindows(std::map
<int, SessionTab
*>* tabs
,
282 std::map
<int, SessionWindow
*>* windows
) {
283 DVLOG(1) << "AddTabsToWindws";
284 DVLOG(1) << "Tabs " << tabs
->size() << ", windows " << windows
->size();
285 std::map
<int, SessionTab
*>::iterator i
= tabs
->begin();
286 while (i
!= tabs
->end()) {
287 SessionTab
* tab
= i
->second
;
288 if (tab
->window_id
.id() && !tab
->navigations
.empty()) {
289 SessionWindow
* window
= GetWindow(tab
->window_id
.id(), windows
);
290 window
->tabs
.push_back(tab
);
293 // See note in SessionTab as to why we do this.
294 std::vector
<sessions::SerializedNavigationEntry
>::iterator j
=
295 FindClosestNavigationWithIndex(&(tab
->navigations
),
296 tab
->current_navigation_index
);
297 if (j
== tab
->navigations
.end()) {
298 tab
->current_navigation_index
=
299 static_cast<int>(tab
->navigations
.size() - 1);
301 tab
->current_navigation_index
=
302 static_cast<int>(j
- tab
->navigations
.begin());
305 // Never got a set tab index in window, or tabs are empty, nothing
312 // Creates tabs and windows from the commands specified in |data|. The created
313 // tabs and windows are added to |tabs| and |windows| respectively, with the
314 // id of the active window set in |active_window_id|. It is up to the caller
315 // to delete the tabs and windows added to |tabs| and |windows|.
317 // This does NOT add any created SessionTabs to SessionWindow.tabs, that is
318 // done by AddTabsToWindows.
319 bool CreateTabsAndWindows(const ScopedVector
<SessionCommand
>& data
,
320 std::map
<int, SessionTab
*>* tabs
,
321 std::map
<int, SessionWindow
*>* windows
,
322 SessionID::id_type
* active_window_id
) {
323 // If the file is corrupt (command with wrong size, or unknown command), we
324 // still return true and attempt to restore what we we can.
325 DVLOG(1) << "CreateTabsAndWindows";
327 for (std::vector
<SessionCommand
*>::const_iterator i
= data
.begin();
328 i
!= data
.end(); ++i
) {
329 const SessionCommand::id_type kCommandSetWindowBounds2
= 10;
330 const SessionCommand
* command
= *i
;
332 DVLOG(1) << "Read command " << (int) command
->id();
333 switch (command
->id()) {
334 case kCommandSetTabWindow
: {
335 SessionID::id_type payload
[2];
336 if (!command
->GetPayload(payload
, sizeof(payload
))) {
337 DVLOG(1) << "Failed reading command " << command
->id();
340 GetTab(payload
[1], tabs
)->window_id
.set_id(payload
[0]);
344 // This is here for forward migration only. New data is saved with
345 // |kCommandSetWindowBounds3|.
346 case kCommandSetWindowBounds2
: {
347 WindowBoundsPayload2 payload
;
348 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
349 DVLOG(1) << "Failed reading command " << command
->id();
352 GetWindow(payload
.window_id
, windows
)->bounds
.SetRect(payload
.x
,
356 GetWindow(payload
.window_id
, windows
)->show_state
=
357 payload
.is_maximized
?
358 ui::SHOW_STATE_MAXIMIZED
: ui::SHOW_STATE_NORMAL
;
362 case kCommandSetWindowBounds3
: {
363 WindowBoundsPayload3 payload
;
364 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
365 DVLOG(1) << "Failed reading command " << command
->id();
368 GetWindow(payload
.window_id
, windows
)->bounds
.SetRect(payload
.x
,
372 GetWindow(payload
.window_id
, windows
)->show_state
=
373 PersistedShowStateToShowState(payload
.show_state
);
377 case kCommandSetTabIndexInWindow
: {
378 TabIndexInWindowPayload payload
;
379 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
380 DVLOG(1) << "Failed reading command " << command
->id();
383 GetTab(payload
.id
, tabs
)->tab_visual_index
= payload
.index
;
387 case kCommandTabClosed
:
388 case kCommandWindowClosed
: {
389 ClosedPayload payload
;
390 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
391 DVLOG(1) << "Failed reading command " << command
->id();
394 if (command
->id() == kCommandTabClosed
) {
395 delete GetTab(payload
.id
, tabs
);
396 tabs
->erase(payload
.id
);
398 delete GetWindow(payload
.id
, windows
);
399 windows
->erase(payload
.id
);
404 case kCommandTabNavigationPathPrunedFromBack
: {
405 TabNavigationPathPrunedFromBackPayload payload
;
406 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
407 DVLOG(1) << "Failed reading command " << command
->id();
410 SessionTab
* tab
= GetTab(payload
.id
, tabs
);
411 tab
->navigations
.erase(
412 FindClosestNavigationWithIndex(&(tab
->navigations
), payload
.index
),
413 tab
->navigations
.end());
417 case kCommandTabNavigationPathPrunedFromFront
: {
418 TabNavigationPathPrunedFromFrontPayload payload
;
419 if (!command
->GetPayload(&payload
, sizeof(payload
)) ||
420 payload
.index
<= 0) {
421 DVLOG(1) << "Failed reading command " << command
->id();
424 SessionTab
* tab
= GetTab(payload
.id
, tabs
);
426 // Update the selected navigation index.
427 tab
->current_navigation_index
=
428 std::max(-1, tab
->current_navigation_index
- payload
.index
);
430 // And update the index of existing navigations.
431 for (std::vector
<sessions::SerializedNavigationEntry
>::iterator
432 i
= tab
->navigations
.begin();
433 i
!= tab
->navigations
.end();) {
434 i
->set_index(i
->index() - payload
.index
);
436 i
= tab
->navigations
.erase(i
);
443 case kCommandUpdateTabNavigation
: {
444 sessions::SerializedNavigationEntry navigation
;
445 SessionID::id_type tab_id
;
446 if (!RestoreUpdateTabNavigationCommand(*command
,
449 DVLOG(1) << "Failed reading command " << command
->id();
452 SessionTab
* tab
= GetTab(tab_id
, tabs
);
453 std::vector
<sessions::SerializedNavigationEntry
>::iterator i
=
454 FindClosestNavigationWithIndex(&(tab
->navigations
),
456 if (i
!= tab
->navigations
.end() && i
->index() == navigation
.index())
459 tab
->navigations
.insert(i
, navigation
);
463 case kCommandSetSelectedNavigationIndex
: {
464 SelectedNavigationIndexPayload payload
;
465 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
466 DVLOG(1) << "Failed reading command " << command
->id();
469 GetTab(payload
.id
, tabs
)->current_navigation_index
= payload
.index
;
473 case kCommandSetSelectedTabInIndex
: {
474 SelectedTabInIndexPayload payload
;
475 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
476 DVLOG(1) << "Failed reading command " << command
->id();
479 GetWindow(payload
.id
, windows
)->selected_tab_index
= payload
.index
;
483 case kCommandSetWindowType
: {
484 WindowTypePayload payload
;
485 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
486 DVLOG(1) << "Failed reading command " << command
->id();
489 GetWindow(payload
.id
, windows
)->is_constrained
= false;
490 GetWindow(payload
.id
, windows
)->type
=
491 static_cast<SessionWindow::WindowType
>(payload
.index
);
495 case kCommandSetPinnedState
: {
496 PinnedStatePayload payload
;
497 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
498 DVLOG(1) << "Failed reading command " << command
->id();
501 GetTab(payload
.tab_id
, tabs
)->pinned
= payload
.pinned_state
;
505 case kCommandSetWindowAppName
: {
506 SessionID::id_type window_id
;
507 std::string app_name
;
508 if (!RestoreSetWindowAppNameCommand(*command
, &window_id
, &app_name
))
511 GetWindow(window_id
, windows
)->app_name
.swap(app_name
);
515 case kCommandSetExtensionAppID
: {
516 SessionID::id_type tab_id
;
517 std::string extension_app_id
;
518 if (!RestoreSetTabExtensionAppIDCommand(*command
,
520 &extension_app_id
)) {
521 DVLOG(1) << "Failed reading command " << command
->id();
525 GetTab(tab_id
, tabs
)->extension_app_id
.swap(extension_app_id
);
529 case kCommandSetTabUserAgentOverride
: {
530 SessionID::id_type tab_id
;
531 std::string user_agent_override
;
532 if (!RestoreSetTabUserAgentOverrideCommand(
535 &user_agent_override
)) {
539 GetTab(tab_id
, tabs
)->user_agent_override
.swap(user_agent_override
);
543 case kCommandSessionStorageAssociated
: {
544 scoped_ptr
<base::Pickle
> command_pickle(command
->PayloadAsPickle());
545 SessionID::id_type command_tab_id
;
546 std::string session_storage_persistent_id
;
547 base::PickleIterator
iter(*command_pickle
.get());
548 if (!iter
.ReadInt(&command_tab_id
) ||
549 !iter
.ReadString(&session_storage_persistent_id
))
551 // Associate the session storage back.
552 GetTab(command_tab_id
, tabs
)->session_storage_persistent_id
=
553 session_storage_persistent_id
;
557 case kCommandSetActiveWindow
: {
558 ActiveWindowPayload payload
;
559 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
560 DVLOG(1) << "Failed reading command " << command
->id();
563 *active_window_id
= payload
;
567 case kCommandLastActiveTime
: {
568 LastActiveTimePayload payload
;
569 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
570 DVLOG(1) << "Failed reading command " << command
->id();
573 SessionTab
* tab
= GetTab(payload
.tab_id
, tabs
);
574 tab
->last_active_time
=
575 base::TimeTicks::FromInternalValue(payload
.last_active_time
);
580 // TODO(skuhne): This might call back into a callback handler to extend
581 // the command set for specific implementations.
582 DVLOG(1) << "Failed reading an unknown command " << command
->id();
591 scoped_ptr
<SessionCommand
> CreateSetSelectedTabInWindowCommand(
592 const SessionID
& window_id
,
594 SelectedTabInIndexPayload payload
= { 0 };
595 payload
.id
= window_id
.id();
596 payload
.index
= index
;
597 scoped_ptr
<SessionCommand
> command(
598 new SessionCommand(kCommandSetSelectedTabInIndex
, sizeof(payload
)));
599 memcpy(command
->contents(), &payload
, sizeof(payload
));
603 scoped_ptr
<SessionCommand
> CreateSetTabWindowCommand(const SessionID
& window_id
,
604 const SessionID
& tab_id
) {
605 SessionID::id_type payload
[] = { window_id
.id(), tab_id
.id() };
606 scoped_ptr
<SessionCommand
> command(
607 new SessionCommand(kCommandSetTabWindow
, sizeof(payload
)));
608 memcpy(command
->contents(), payload
, sizeof(payload
));
612 scoped_ptr
<SessionCommand
> CreateSetWindowBoundsCommand(
613 const SessionID
& window_id
,
614 const gfx::Rect
& bounds
,
615 ui::WindowShowState show_state
) {
616 WindowBoundsPayload3 payload
= { 0 };
617 payload
.window_id
= window_id
.id();
618 payload
.x
= bounds
.x();
619 payload
.y
= bounds
.y();
620 payload
.w
= bounds
.width();
621 payload
.h
= bounds
.height();
622 payload
.show_state
= ShowStateToPersistedShowState(show_state
);
623 scoped_ptr
<SessionCommand
> command(
624 new SessionCommand(kCommandSetWindowBounds3
, sizeof(payload
)));
625 memcpy(command
->contents(), &payload
, sizeof(payload
));
629 scoped_ptr
<SessionCommand
> CreateSetTabIndexInWindowCommand(
630 const SessionID
& tab_id
,
632 TabIndexInWindowPayload payload
= { 0 };
633 payload
.id
= tab_id
.id();
634 payload
.index
= new_index
;
635 scoped_ptr
<SessionCommand
> command(
636 new SessionCommand(kCommandSetTabIndexInWindow
, sizeof(payload
)));
637 memcpy(command
->contents(), &payload
, sizeof(payload
));
641 scoped_ptr
<SessionCommand
> CreateTabClosedCommand(
642 const SessionID::id_type tab_id
) {
643 ClosedPayload payload
;
644 // Because of what appears to be a compiler bug setting payload to {0} doesn't
645 // set the padding to 0, resulting in Purify reporting an UMR when we write
646 // the structure to disk. To avoid this we explicitly memset the struct.
647 memset(&payload
, 0, sizeof(payload
));
649 payload
.close_time
= base::Time::Now().ToInternalValue();
650 scoped_ptr
<SessionCommand
> command(
651 new SessionCommand(kCommandTabClosed
, sizeof(payload
)));
652 memcpy(command
->contents(), &payload
, sizeof(payload
));
656 scoped_ptr
<SessionCommand
> CreateWindowClosedCommand(
657 const SessionID::id_type window_id
) {
658 ClosedPayload payload
;
659 // See comment in CreateTabClosedCommand as to why we do this.
660 memset(&payload
, 0, sizeof(payload
));
661 payload
.id
= window_id
;
662 payload
.close_time
= base::Time::Now().ToInternalValue();
663 scoped_ptr
<SessionCommand
> command(
664 new SessionCommand(kCommandWindowClosed
, sizeof(payload
)));
665 memcpy(command
->contents(), &payload
, sizeof(payload
));
669 scoped_ptr
<SessionCommand
> CreateSetSelectedNavigationIndexCommand(
670 const SessionID
& tab_id
,
672 SelectedNavigationIndexPayload payload
= { 0 };
673 payload
.id
= tab_id
.id();
674 payload
.index
= index
;
675 scoped_ptr
<SessionCommand
> command(
676 new SessionCommand(kCommandSetSelectedNavigationIndex
, sizeof(payload
)));
677 memcpy(command
->contents(), &payload
, sizeof(payload
));
681 scoped_ptr
<SessionCommand
> CreateSetWindowTypeCommand(
682 const SessionID
& window_id
,
683 SessionWindow::WindowType type
) {
684 WindowTypePayload payload
= { 0 };
685 payload
.id
= window_id
.id();
686 payload
.index
= static_cast<int32
>(type
);
687 scoped_ptr
<SessionCommand
> command(
688 new SessionCommand( kCommandSetWindowType
, sizeof(payload
)));
689 memcpy(command
->contents(), &payload
, sizeof(payload
));
693 scoped_ptr
<SessionCommand
> CreatePinnedStateCommand(
694 const SessionID
& tab_id
,
696 PinnedStatePayload payload
= { 0 };
697 payload
.tab_id
= tab_id
.id();
698 payload
.pinned_state
= is_pinned
;
699 scoped_ptr
<SessionCommand
> command(
700 new SessionCommand(kCommandSetPinnedState
, sizeof(payload
)));
701 memcpy(command
->contents(), &payload
, sizeof(payload
));
705 scoped_ptr
<SessionCommand
> CreateSessionStorageAssociatedCommand(
706 const SessionID
& tab_id
,
707 const std::string
& session_storage_persistent_id
) {
709 pickle
.WriteInt(tab_id
.id());
710 pickle
.WriteString(session_storage_persistent_id
);
711 return scoped_ptr
<SessionCommand
>(
712 new SessionCommand(kCommandSessionStorageAssociated
, pickle
));
715 scoped_ptr
<SessionCommand
> CreateSetActiveWindowCommand(
716 const SessionID
& window_id
) {
717 ActiveWindowPayload payload
= 0;
718 payload
= window_id
.id();
719 scoped_ptr
<SessionCommand
> command(
720 new SessionCommand(kCommandSetActiveWindow
, sizeof(payload
)));
721 memcpy(command
->contents(), &payload
, sizeof(payload
));
725 scoped_ptr
<SessionCommand
> CreateLastActiveTimeCommand(
726 const SessionID
& tab_id
,
727 base::TimeTicks last_active_time
) {
728 LastActiveTimePayload payload
= {0};
729 payload
.tab_id
= tab_id
.id();
730 payload
.last_active_time
= last_active_time
.ToInternalValue();
731 scoped_ptr
<SessionCommand
> command(
732 new SessionCommand(kCommandLastActiveTime
, sizeof(payload
)));
733 memcpy(command
->contents(), &payload
, sizeof(payload
));
737 scoped_ptr
<SessionCommand
> CreateTabNavigationPathPrunedFromBackCommand(
738 const SessionID
& tab_id
,
740 TabNavigationPathPrunedFromBackPayload payload
= { 0 };
741 payload
.id
= tab_id
.id();
742 payload
.index
= count
;
743 scoped_ptr
<SessionCommand
> command(
744 new SessionCommand(kCommandTabNavigationPathPrunedFromBack
,
746 memcpy(command
->contents(), &payload
, sizeof(payload
));
750 scoped_ptr
<SessionCommand
> CreateTabNavigationPathPrunedFromFrontCommand(
751 const SessionID
& tab_id
,
753 TabNavigationPathPrunedFromFrontPayload payload
= { 0 };
754 payload
.id
= tab_id
.id();
755 payload
.index
= count
;
756 scoped_ptr
<SessionCommand
> command(
757 new SessionCommand(kCommandTabNavigationPathPrunedFromFront
,
759 memcpy(command
->contents(), &payload
, sizeof(payload
));
763 scoped_ptr
<SessionCommand
> CreateUpdateTabNavigationCommand(
764 const SessionID
& tab_id
,
765 const sessions::SerializedNavigationEntry
& navigation
) {
766 return CreateUpdateTabNavigationCommand(kCommandUpdateTabNavigation
,
771 scoped_ptr
<SessionCommand
> CreateSetTabExtensionAppIDCommand(
772 const SessionID
& tab_id
,
773 const std::string
& extension_id
) {
774 return CreateSetTabExtensionAppIDCommand(kCommandSetExtensionAppID
,
779 scoped_ptr
<SessionCommand
> CreateSetTabUserAgentOverrideCommand(
780 const SessionID
& tab_id
,
781 const std::string
& user_agent_override
) {
782 return CreateSetTabUserAgentOverrideCommand(kCommandSetTabUserAgentOverride
,
784 user_agent_override
);
787 scoped_ptr
<SessionCommand
> CreateSetWindowAppNameCommand(
788 const SessionID
& window_id
,
789 const std::string
& app_name
) {
790 return CreateSetWindowAppNameCommand(kCommandSetWindowAppName
,
795 bool ReplacePendingCommand(BaseSessionService
* base_session_service
,
796 scoped_ptr
<SessionCommand
>* command
) {
797 // We optimize page navigations, which can happen quite frequently and
798 // is expensive. And activation is like Highlander, there can only be one!
799 if ((*command
)->id() != kCommandUpdateTabNavigation
&&
800 (*command
)->id() != kCommandSetActiveWindow
) {
803 for (ScopedVector
<SessionCommand
>::const_reverse_iterator i
=
804 base_session_service
->pending_commands().rbegin();
805 i
!= base_session_service
->pending_commands().rend(); ++i
) {
806 SessionCommand
* existing_command
= *i
;
807 if ((*command
)->id() == kCommandUpdateTabNavigation
&&
808 existing_command
->id() == kCommandUpdateTabNavigation
) {
809 scoped_ptr
<base::Pickle
> command_pickle((*command
)->PayloadAsPickle());
810 base::PickleIterator
iterator(*command_pickle
);
811 SessionID::id_type command_tab_id
;
812 int command_nav_index
;
813 if (!iterator
.ReadInt(&command_tab_id
) ||
814 !iterator
.ReadInt(&command_nav_index
)) {
817 SessionID::id_type existing_tab_id
;
818 int existing_nav_index
;
820 // Creating a pickle like this means the Pickle references the data from
821 // the command. Make sure we delete the pickle before the command, else
822 // the pickle references deleted memory.
823 scoped_ptr
<base::Pickle
> existing_pickle(
824 existing_command
->PayloadAsPickle());
825 iterator
= base::PickleIterator(*existing_pickle
);
826 if (!iterator
.ReadInt(&existing_tab_id
) ||
827 !iterator
.ReadInt(&existing_nav_index
)) {
831 if (existing_tab_id
== command_tab_id
&&
832 existing_nav_index
== command_nav_index
) {
833 // existing_command is an update for the same tab/index pair. Replace
834 // it with the new one. We need to add to the end of the list just in
835 // case there is a prune command after the update command.
836 base_session_service
->EraseCommand(*(i
.base() - 1));
837 base_session_service
->AppendRebuildCommand((*command
).Pass());
842 if ((*command
)->id() == kCommandSetActiveWindow
&&
843 existing_command
->id() == kCommandSetActiveWindow
) {
844 base_session_service
->SwapCommand(existing_command
, (*command
).Pass());
851 bool IsClosingCommand(SessionCommand
* command
) {
852 return command
->id() == kCommandTabClosed
||
853 command
->id() == kCommandWindowClosed
;
856 void RestoreSessionFromCommands(const ScopedVector
<SessionCommand
>& commands
,
857 std::vector
<SessionWindow
*>* valid_windows
,
858 SessionID::id_type
* active_window_id
) {
859 std::map
<int, SessionTab
*> tabs
;
860 std::map
<int, SessionWindow
*> windows
;
862 DVLOG(1) << "RestoreSessionFromCommands " << commands
.size();
863 if (CreateTabsAndWindows(commands
, &tabs
, &windows
, active_window_id
)) {
864 AddTabsToWindows(&tabs
, &windows
);
865 SortTabsBasedOnVisualOrderAndPrune(&windows
, valid_windows
);
866 UpdateSelectedTabIndex(valid_windows
);
868 STLDeleteValues(&tabs
);
869 // Don't delete contents of windows, that is done by the caller as all
870 // valid windows are added to valid_windows.
873 } // namespace sessions