Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(105)

Side by Side Diff: components/sessions/core/persistent_tab_restore_service.cc

Issue 2868983003: Ensure History > Recent Tabs restore preserves window disposition. (Closed)
Patch Set: Minor cleanup. Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/sessions/core/persistent_tab_restore_service.h" 5 #include "components/sessions/core/persistent_tab_restore_service.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 #include <string.h> 9 #include <string.h>
10 #include <utility> 10 #include <utility>
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 44
45 // Payload used for the start of a window close. This is the old struct that is 45 // Payload used for the start of a window close. This is the old struct that is
46 // used for backwards compat when it comes to reading the session files. This 46 // used for backwards compat when it comes to reading the session files. This
47 // struct must be POD, because we memset the contents. 47 // struct must be POD, because we memset the contents.
48 struct WindowPayload { 48 struct WindowPayload {
49 SessionID::id_type window_id; 49 SessionID::id_type window_id;
50 int32_t selected_tab_index; 50 int32_t selected_tab_index;
51 int32_t num_tabs; 51 int32_t num_tabs;
52 }; 52 };
53 53
54 // Payload used for the start of a window close. This struct must be POD, 54 // Payload used for the start of a window close. This struct must be POD,
55 // because we memset the contents. 55 // because we memset the contents. This is an older version of the struct that
56 // is used for backwards compat when it comes to reading the session files.
56 struct WindowPayload2 : WindowPayload { 57 struct WindowPayload2 : WindowPayload {
sky 2017/06/28 22:38:01 How about adding Obsolete as a suffix to this and
chrisha 2017/06/30 15:42:12 Done.
57 int64_t timestamp; 58 int64_t timestamp;
58 }; 59 };
59 60
60 // Payload used for the start of a tab close. 61 // Payload used for the start of a tab close.
61 struct SelectedNavigationInTabPayload2 : SelectedNavigationInTabPayload { 62 struct SelectedNavigationInTabPayload2 : SelectedNavigationInTabPayload {
62 int64_t timestamp; 63 int64_t timestamp;
63 }; 64 };
64 65
65 // Used to indicate what has loaded. 66 // Used to indicate what has loaded.
66 enum LoadState { 67 enum LoadState {
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 // Erase it if it's our target. 129 // Erase it if it's our target.
129 if (tab.id == id) { 130 if (tab.id == id) {
130 window.tabs.erase(it); 131 window.tabs.erase(it);
131 return; 132 return;
132 } 133 }
133 } 134 }
134 } 135 }
135 } 136 }
136 } 137 }
137 138
139 // Superset of WindowPayload/WindowPayload2 and the other fields that can appear
140 // in the Pickle version of a Window command.
141 struct WindowCommandFields {
142 // Fields in WindowPayload/WindowPayload2/Pickle:
143 SessionID::id_type window_id = 0;
144 int32_t selected_tab_index = 0;
145 int32_t num_tabs = 0;
146
147 // Fields in WindowPayload2/Pickle:
148 int64_t timestamp = 0;
149
150 // Fields in Pickle:
151 // Completely zeroed position/dimensions indicates that defaults should be
152 // used.
153 int32_t window_x = 0;
154 int32_t window_y = 0;
155 int32_t window_width = 0;
156 int32_t window_height = 0;
157 // Use the default show state if none is specified.
158 int32_t window_show_state = static_cast<int32_t>(ui::SHOW_STATE_DEFAULT);
159 std::string workspace;
160 };
161
162 std::unique_ptr<sessions::TabRestoreService::Window>
163 CreateWindowEntryFromCommand(const SessionCommand* command,
164 SessionID::id_type* window_id,
165 int32_t* num_tabs) {
166 bool parsed = false;
167
168 WindowCommandFields fields;
169
170 // First try to parse the command as a pickle (the most modern version).
171 std::unique_ptr<base::Pickle> pickle(command->PayloadAsPickle());
172 if (pickle.get()) {
173 base::PickleIterator it(*pickle);
174 WindowCommandFields f;
sky 2017/06/28 22:38:00 Please use a more readable name then 'f'.
chrisha 2017/06/30 15:42:12 Done.
175
176 // The first version of the pickle contains all of the following fields, so
177 // they should all successfully parse if the command is in fact a pickle.
178 if (it.ReadInt(&f.window_id) && it.ReadInt(&f.selected_tab_index) &&
179 it.ReadInt(&f.num_tabs) && it.ReadInt64(&f.timestamp) &&
180 it.ReadInt(&f.window_x) && it.ReadInt(&f.window_y) &&
181 it.ReadInt(&f.window_width) && it.ReadInt(&f.window_height) &&
182 it.ReadInt(&f.window_show_state) && it.ReadString(&f.workspace)) {
183 // New fields added to the pickle in later versions would be parsed here.
184
185 // Copy the parsed data.
186 fields = f;
187 parsed = true;
188 }
189 }
190
191 // Next try to parse the command as a WindowPayload2.
192 if (!parsed) {
193 WindowPayload2 payload2;
194 if (command->GetPayload(&payload2, sizeof(payload2))) {
195 fields.window_id = payload2.window_id;
196 fields.selected_tab_index = payload2.selected_tab_index;
197 fields.num_tabs = payload2.num_tabs;
198 fields.timestamp = payload2.timestamp;
199 parsed = true;
200 }
201 }
202
203 // Finally, try the oldest WindowPayload type.
204 if (!parsed) {
205 WindowPayload payload;
206 if (command->GetPayload(&payload, sizeof(payload))) {
207 fields.window_id = payload.window_id;
208 fields.selected_tab_index = payload.selected_tab_index;
209 fields.num_tabs = payload.num_tabs;
210 parsed = true;
211 }
212 }
213
214 if (!parsed)
215 return nullptr;
216
217 // Create the Window entry.
218 std::unique_ptr<sessions::TabRestoreService::Window> window =
219 base::MakeUnique<sessions::TabRestoreService::Window>();
220 window->selected_tab_index = fields.selected_tab_index;
221 window->timestamp = base::Time::FromInternalValue(fields.timestamp);
222 window->selected_tab_index = fields.selected_tab_index;
223 window->timestamp = base::Time::FromInternalValue(fields.timestamp);
224 *window_id = fields.window_id;
225 *num_tabs = fields.num_tabs;
226
227 // Set the bounds, show state and workspace if valid ones have been provided.
228 if (!(fields.window_x == 0 && fields.window_y == 0 &&
229 fields.window_width == 0 && fields.window_height == 0)) {
230 window->bounds.SetRect(fields.window_x, fields.window_y,
231 fields.window_width, fields.window_height);
232 window->show_state =
233 static_cast<ui::WindowShowState>(fields.window_show_state);
sky 2017/06/28 22:38:00 You need to validate the enum.
chrisha 2017/06/30 15:42:13 Done.
234 window->workspace = std::move(fields.workspace);
235 }
236
237 return window;
238 }
239
138 } // namespace 240 } // namespace
139 241
140 // PersistentTabRestoreService::Delegate --------------------------------------- 242 // PersistentTabRestoreService::Delegate ---------------------------------------
141 243
142 // This restore service will create and own a BaseSessionService and implement 244 // This restore service will create and own a BaseSessionService and implement
143 // the required BaseSessionServiceDelegate. 245 // the required BaseSessionServiceDelegate.
144 class PersistentTabRestoreService::Delegate 246 class PersistentTabRestoreService::Delegate
145 : public BaseSessionServiceDelegate, 247 : public BaseSessionServiceDelegate,
146 public TabRestoreServiceHelper::Observer { 248 public TabRestoreServiceHelper::Observer {
147 public: 249 public:
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 282
181 // Schedules the commands for a window close. 283 // Schedules the commands for a window close.
182 void ScheduleCommandsForWindow(const Window& window); 284 void ScheduleCommandsForWindow(const Window& window);
183 285
184 // Schedules the commands for a tab close. |selected_index| gives the index of 286 // Schedules the commands for a tab close. |selected_index| gives the index of
185 // the selected navigation. 287 // the selected navigation.
186 void ScheduleCommandsForTab(const Tab& tab, int selected_index); 288 void ScheduleCommandsForTab(const Tab& tab, int selected_index);
187 289
188 // Creates a window close command. 290 // Creates a window close command.
189 static std::unique_ptr<SessionCommand> CreateWindowCommand( 291 static std::unique_ptr<SessionCommand> CreateWindowCommand(
190 SessionID::id_type id, 292 SessionID::id_type window_id,
191 int selected_tab_index, 293 int selected_tab_index,
192 int num_tabs, 294 int num_tabs,
295 const gfx::Rect& bounds,
296 ui::WindowShowState show_state,
297 const std::string& workspace,
193 base::Time timestamp); 298 base::Time timestamp);
194 299
195 // Creates a tab close command. 300 // Creates a tab close command.
196 static std::unique_ptr<SessionCommand> CreateSelectedNavigationInTabCommand( 301 static std::unique_ptr<SessionCommand> CreateSelectedNavigationInTabCommand(
197 SessionID::id_type tab_id, 302 SessionID::id_type tab_id,
198 int32_t index, 303 int32_t index,
199 base::Time timestamp); 304 base::Time timestamp);
200 305
201 // Creates a restore command. 306 // Creates a restore command.
202 static std::unique_ptr<SessionCommand> CreateRestoredEntryCommand( 307 static std::unique_ptr<SessionCommand> CreateRestoredEntryCommand(
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after
428 valid_tab_count++; 533 valid_tab_count++;
429 } else if (static_cast<int>(i) < selected_tab) { 534 } else if (static_cast<int>(i) < selected_tab) {
430 real_selected_tab--; 535 real_selected_tab--;
431 } 536 }
432 } 537 }
433 if (valid_tab_count == 0) 538 if (valid_tab_count == 0)
434 return; // No tabs to persist. 539 return; // No tabs to persist.
435 540
436 base_session_service_->ScheduleCommand(CreateWindowCommand( 541 base_session_service_->ScheduleCommand(CreateWindowCommand(
437 window.id, std::min(real_selected_tab, valid_tab_count - 1), 542 window.id, std::min(real_selected_tab, valid_tab_count - 1),
438 valid_tab_count, window.timestamp)); 543 valid_tab_count, window.bounds, window.show_state, window.workspace,
544 window.timestamp));
439 545
440 if (!window.app_name.empty()) { 546 if (!window.app_name.empty()) {
441 base_session_service_->ScheduleCommand(CreateSetWindowAppNameCommand( 547 base_session_service_->ScheduleCommand(CreateSetWindowAppNameCommand(
442 kCommandSetWindowAppName, window.id, window.app_name)); 548 kCommandSetWindowAppName, window.id, window.app_name));
443 } 549 }
444 550
445 for (size_t i = 0; i < window.tabs.size(); ++i) { 551 for (size_t i = 0; i < window.tabs.size(); ++i) {
446 int selected_index = GetSelectedNavigationIndexToPersist(*window.tabs[i]); 552 int selected_index = GetSelectedNavigationIndexToPersist(*window.tabs[i]);
447 if (selected_index != -1) 553 if (selected_index != -1)
448 ScheduleCommandsForTab(*window.tabs[i], selected_index); 554 ScheduleCommandsForTab(*window.tabs[i], selected_index);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 CreateUpdateTabNavigationCommand(kCommandUpdateTabNavigation, 603 CreateUpdateTabNavigationCommand(kCommandUpdateTabNavigation,
498 tab.id, 604 tab.id,
499 navigations[i])); 605 navigations[i]));
500 } 606 }
501 } 607 }
502 } 608 }
503 609
504 // static 610 // static
505 std::unique_ptr<SessionCommand> 611 std::unique_ptr<SessionCommand>
506 PersistentTabRestoreService::Delegate::CreateWindowCommand( 612 PersistentTabRestoreService::Delegate::CreateWindowCommand(
507 SessionID::id_type id, 613 SessionID::id_type window_id,
508 int selected_tab_index, 614 int selected_tab_index,
509 int num_tabs, 615 int num_tabs,
616 const gfx::Rect& bounds,
617 ui::WindowShowState show_state,
618 const std::string& workspace,
510 base::Time timestamp) { 619 base::Time timestamp) {
511 WindowPayload2 payload; 620 // Use a pickle to handle marshaling as this command contains variable-length
512 // |timestamp| is aligned on a 16 byte boundary, leaving 4 bytes of 621 // content.
513 // uninitialized memory in the struct. 622 base::Pickle pickle;
514 memset(&payload, 0, sizeof(payload)); 623 pickle.WriteInt(window_id);
sky 2017/06/28 22:38:00 You need to make sure the writing, reading and rep
chrisha 2017/06/30 15:42:12 Done.
515 payload.window_id = id; 624 pickle.WriteInt(selected_tab_index);
516 payload.selected_tab_index = selected_tab_index; 625 pickle.WriteInt(num_tabs);
517 payload.num_tabs = num_tabs; 626 pickle.WriteInt64(timestamp.ToInternalValue());
518 payload.timestamp = timestamp.ToInternalValue(); 627 pickle.WriteInt(bounds.x());
628 pickle.WriteInt(bounds.y());
629 pickle.WriteInt(bounds.width());
630 pickle.WriteInt(bounds.height());
631 pickle.WriteInt(static_cast<int32_t>(show_state));
sky 2017/06/28 22:38:00 I would prefer you mirror WindowShowState locally.
chrisha 2017/06/30 15:42:12 Done.
632
633 // Enforce a maximum length on workspace names. A common size is 32 bytes for
634 // GUIDs.
635 if (workspace.size() <= 128) {
sky 2017/06/28 22:38:00 no {}
chrisha 2017/06/30 15:42:13 Done.
636 pickle.WriteString(workspace);
637 } else {
638 pickle.WriteString(std::string());
639 }
519 640
520 std::unique_ptr<SessionCommand> command( 641 std::unique_ptr<SessionCommand> command(
521 new SessionCommand(kCommandWindow, sizeof(payload))); 642 new SessionCommand(kCommandWindow, pickle));
522 memcpy(command->contents(), &payload, sizeof(payload));
523 return command; 643 return command;
524 } 644 }
525 645
526 // static 646 // static
527 std::unique_ptr<SessionCommand> 647 std::unique_ptr<SessionCommand>
528 PersistentTabRestoreService::Delegate::CreateSelectedNavigationInTabCommand( 648 PersistentTabRestoreService::Delegate::CreateSelectedNavigationInTabCommand(
529 SessionID::id_type tab_id, 649 SessionID::id_type tab_id,
530 int32_t index, 650 int32_t index,
531 base::Time timestamp) { 651 base::Time timestamp) {
532 SelectedNavigationInTabPayload2 payload; 652 SelectedNavigationInTabPayload2 payload;
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
618 current_window = nullptr; 738 current_window = nullptr;
619 739
620 RestoredEntryPayload payload; 740 RestoredEntryPayload payload;
621 if (!command.GetPayload(&payload, sizeof(payload))) 741 if (!command.GetPayload(&payload, sizeof(payload)))
622 return; 742 return;
623 RemoveEntryByID(payload, &entries); 743 RemoveEntryByID(payload, &entries);
624 break; 744 break;
625 } 745 }
626 746
627 case kCommandWindow: { 747 case kCommandWindow: {
628 WindowPayload2 payload; 748 // Should never receive a window command while waiting for all the
629 if (pending_window_tabs > 0) { 749 // tabs in a window.
630 // Should never receive a window command while waiting for all the 750 if (pending_window_tabs > 0)
631 // tabs in a window.
632 return; 751 return;
633 }
634 752
635 // Try the new payload first 753 // Try to parse the command, and silently skip if it fails.
636 if (!command.GetPayload(&payload, sizeof(payload))) { 754 int32_t num_tabs = 0;
637 // then the old payload 755 SessionID::id_type window_id = 0;
638 WindowPayload old_payload; 756 std::unique_ptr<Window> window =
639 if (!command.GetPayload(&old_payload, sizeof(old_payload))) 757 CreateWindowEntryFromCommand(&command, &window_id, &num_tabs);
640 return; 758 if (!window)
759 return;
641 760
642 // Copy the old payload data to the new payload. 761 // Should always have at least 1 tab. Likely indicates corruption.
643 payload.window_id = old_payload.window_id; 762 pending_window_tabs = num_tabs;
644 payload.selected_tab_index = old_payload.selected_tab_index; 763 if (pending_window_tabs <= 0)
645 payload.num_tabs = old_payload.num_tabs; 764 return;
646 // Since we don't have a time use time 0 which is used to mark as an
647 // unknown timestamp.
648 payload.timestamp = 0;
649 }
650 765
651 pending_window_tabs = payload.num_tabs; 766 RemoveEntryByID(window_id, &entries);
652 if (pending_window_tabs <= 0) { 767 current_window = window.get();
653 // Should always have at least 1 tab. Likely indicates corruption. 768 entries.push_back(std::move(window));
654 return;
655 }
656
657 RemoveEntryByID(payload.window_id, &entries);
658
659 entries.push_back(base::MakeUnique<Window>());
660 current_window = static_cast<Window*>(entries.back().get());
661 current_window->selected_tab_index = payload.selected_tab_index;
662 current_window->timestamp =
663 base::Time::FromInternalValue(payload.timestamp);
664 break; 769 break;
665 } 770 }
666 771
667 case kCommandSelectedNavigationInTab: { 772 case kCommandSelectedNavigationInTab: {
668 SelectedNavigationInTabPayload2 payload; 773 SelectedNavigationInTabPayload2 payload;
669 if (!command.GetPayload(&payload, sizeof(payload))) { 774 if (!command.GetPayload(&payload, sizeof(payload))) {
670 SelectedNavigationInTabPayload old_payload; 775 SelectedNavigationInTabPayload old_payload;
671 if (!command.GetPayload(&old_payload, sizeof(old_payload))) 776 if (!command.GetPayload(&old_payload, sizeof(old_payload)))
672 return; 777 return;
673 payload.id = old_payload.id; 778 payload.id = old_payload.id;
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
766 if (!RestoreSetTabUserAgentOverrideCommand(command, 871 if (!RestoreSetTabUserAgentOverrideCommand(command,
767 &tab_id, 872 &tab_id,
768 &user_agent_override)) { 873 &user_agent_override)) {
769 return; 874 return;
770 } 875 }
771 current_tab->user_agent_override.swap(user_agent_override); 876 current_tab->user_agent_override.swap(user_agent_override);
772 break; 877 break;
773 } 878 }
774 879
775 default: 880 default:
776 // Unknown type, usually indicates corruption of file. Ignore it.
sky 2017/06/28 22:38:00 Why are you removing this comment?
chrisha 2017/06/30 15:42:12 Oops, stray line removal. Restored.
777 return; 881 return;
778 } 882 }
779 } 883 }
780 884
781 // If there was corruption some of the entries won't be valid. 885 // If there was corruption some of the entries won't be valid.
782 ValidateAndDeleteEmptyEntries(&entries); 886 ValidateAndDeleteEmptyEntries(&entries);
783
784 loaded_entries->swap(entries); 887 loaded_entries->swap(entries);
785 } 888 }
786 889
787 // static 890 // static
788 void PersistentTabRestoreService::Delegate::ValidateAndDeleteEmptyEntries( 891 void PersistentTabRestoreService::Delegate::ValidateAndDeleteEmptyEntries(
789 std::vector<std::unique_ptr<Entry>>* entries) { 892 std::vector<std::unique_ptr<Entry>>* entries) {
790 std::vector<std::unique_ptr<Entry>> valid_entries; 893 std::vector<std::unique_ptr<Entry>> valid_entries;
791 894
792 // Iterate from the back so that we keep the most recently closed entries. 895 // Iterate from the back so that we keep the most recently closed entries.
793 for (auto i = entries->rbegin(); i != entries->rend(); ++i) { 896 for (auto i = entries->rbegin(); i != entries->rend(); ++i) {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
826 tab.timestamp = base::Time(); 929 tab.timestamp = base::Time();
827 } 930 }
828 } 931 }
829 if (window->tabs.empty()) 932 if (window->tabs.empty())
830 return false; 933 return false;
831 934
832 window->selected_tab_index = 935 window->selected_tab_index =
833 std::min(session_window->selected_tab_index, 936 std::min(session_window->selected_tab_index,
834 static_cast<int>(window->tabs.size() - 1)); 937 static_cast<int>(window->tabs.size() - 1));
835 window->timestamp = base::Time(); 938 window->timestamp = base::Time();
939 window->bounds = session_window->bounds;
940 window->show_state = session_window->show_state;
941 window->workspace = session_window->workspace;
836 return true; 942 return true;
837 } 943 }
838 944
839 void PersistentTabRestoreService::Delegate::LoadStateChanged() { 945 void PersistentTabRestoreService::Delegate::LoadStateChanged() {
840 if ((load_state_ & (LOADED_LAST_TABS | LOADED_LAST_SESSION)) != 946 if ((load_state_ & (LOADED_LAST_TABS | LOADED_LAST_SESSION)) !=
841 (LOADED_LAST_TABS | LOADED_LAST_SESSION)) { 947 (LOADED_LAST_TABS | LOADED_LAST_SESSION)) {
842 // Still waiting on previous session or previous tabs. 948 // Still waiting on previous session or previous tabs.
843 return; 949 return;
844 } 950 }
845 951
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
964 1070
965 TabRestoreService::Entries* PersistentTabRestoreService::mutable_entries() { 1071 TabRestoreService::Entries* PersistentTabRestoreService::mutable_entries() {
966 return &helper_.entries_; 1072 return &helper_.entries_;
967 } 1073 }
968 1074
969 void PersistentTabRestoreService::PruneEntries() { 1075 void PersistentTabRestoreService::PruneEntries() {
970 helper_.PruneEntries(); 1076 helper_.PruneEntries();
971 } 1077 }
972 1078
973 } // namespace sessions 1079 } // namespace sessions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698