0

wayland: xdg-session-management: Add command for platform_session_id

Some platforms support window-related session management at display
server side. Such as, Linux/Wayland with xdg-session-management protocol
extension. In that case, 1 new piece of data must be requested and
persisted by the client application in order to be able to ask the
windowing system to restore window states when needed:

- platform_session_id: a string that identifies a platform session,
  generated by the display server (eg: the Wayland compositor
  implementing the xdg-session-management protocol), stored by chromium
  in the session commands backing storage, and sent back to the display
  server when restoring a browser session.

Further design notes available at
https://notes.nickdiego.dev/chromium/wayland-session-management

The upcoming CLs will add the remaining bits, including:

- UI/Views framework API required additions.
- Ozone/Wayland implementation based on xdg-toplevel-drag-v1 protocol.
- Chrome required plumbing and required changes.

Bug: 352081012
Change-Id: I5d2d7c5755c1cf5848bffd6231cc75f3fda2def3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6329136
Reviewed-by: Darryl James <dljames@chromium.org>
Commit-Queue: Nick Yamane <nickdiego@igalia.com>
Cr-Commit-Position: refs/heads/main@{#1437661}
This commit is contained in:
Nick Diego Yamane
2025-03-25 12:14:54 -07:00
committed by Chromium LUCI CQ
parent 46b457cf14
commit d0faf7d8b4
10 changed files with 140 additions and 44 deletions

@ -527,8 +527,10 @@ void SessionServiceBase::OnGotSessionCommands(
std::vector<std::unique_ptr<sessions::SessionWindow>> valid_windows;
SessionID active_window_id = SessionID::InvalidValue();
// TODO(crbug.com/352081012): Add platform session plumbing code.
std::string platform_session_id;
sessions::RestoreSessionFromCommands(commands, &valid_windows,
&active_window_id);
&active_window_id, &platform_session_id);
RemoveUnusedRestoreWindows(&valid_windows);
std::move(callback).Run(std::move(valid_windows), active_window_id,
@ -810,3 +812,14 @@ void SessionServiceBase::SetSavingEnabled(bool enabled) {
ScheduleResetCommands();
}
}
std::optional<std::string> SessionServiceBase::GetPlatformSessionId() {
// TODO(crbug.com/352081012): Request from the platform API, if needed.
return platform_session_id_;
}
void SessionServiceBase::SetPlatformSessionIdForTesting(const std::string& id) {
platform_session_id_ = id;
ScheduleCommand(sessions::CreateSetPlatformSessionIdCommand(
platform_session_id_.value()));
}

@ -182,6 +182,14 @@ class SessionServiceBase : public sessions::CommandStorageManagerDelegate,
virtual base::Value ToDebugValue() const;
#endif // DCHECK_IS_ON()
// Some platforms support windowing system level session management, in such
// cases, GetPlatformSessionId() returns a non-empty string identifier
// provided by the platform at session initialization and persisted in the
// session command backing storage for future session restoration.
// See ui/ozone/public/platfrom_session_manager.h for more details.
std::optional<std::string> GetPlatformSessionId();
void SetPlatformSessionIdForTesting(const std::string& id);
protected:
// Creates a SessionService for the specified profile.
SessionServiceBase(Profile* profile, SessionServiceType type);
@ -319,6 +327,10 @@ class SessionServiceBase : public sessions::CommandStorageManagerDelegate,
bool did_save_commands_at_least_once_ = false;
// The platform session identifier, if supported and successfully initialized.
// See GetPlatformSessionId() for more details.
std::optional<std::string> platform_session_id_;
base::WeakPtrFactory<SessionServiceBase> weak_factory_{this};
};

@ -60,7 +60,9 @@ void SessionServiceBaseTestHelper::ReadWindows(
service_->GetCommandStorageManagerForTest());
std::vector<std::unique_ptr<sessions::SessionCommand>> read_commands =
test_helper.ReadLastSessionCommands();
RestoreSessionFromCommands(read_commands, windows, active_window_id);
std::string platform_session_id;
RestoreSessionFromCommands(read_commands, windows, active_window_id,
&platform_session_id);
service_->RemoveUnusedRestoreWindows(windows);
}

@ -67,12 +67,14 @@ void SessionServiceTestHelper::SetForceBrowserNotAliveWithNoWindows(
// Be sure and null out service to force closing the file.
void SessionServiceTestHelper::ReadWindows(
std::vector<std::unique_ptr<sessions::SessionWindow>>* windows,
SessionID* active_window_id) {
SessionID* active_window_id,
std::string* platform_session_id) {
sessions::CommandStorageManagerTestHelper test_helper(
service_->GetCommandStorageManagerForTest());
std::vector<std::unique_ptr<sessions::SessionCommand>> read_commands =
test_helper.ReadLastSessionCommands();
RestoreSessionFromCommands(read_commands, windows, active_window_id);
RestoreSessionFromCommands(read_commands, windows, active_window_id,
platform_session_id);
service_->RemoveUnusedRestoreWindows(windows);
}

@ -66,7 +66,8 @@ class SessionServiceTestHelper {
// Reads the contents of the last session.
void ReadWindows(
std::vector<std::unique_ptr<sessions::SessionWindow>>* windows,
SessionID* active_window_id);
SessionID* active_window_id,
std::string* platform_session_id);
void AssertTabEquals(SessionID window_id,
SessionID tab_id,

@ -129,17 +129,22 @@ class SessionServiceTest : public BrowserWithTestWindowTest {
void ReadWindows(
std::vector<std::unique_ptr<sessions::SessionWindow>>* windows,
SessionID* active_window_id) {
SessionID* active_window_id,
std::string* platform_session_id) {
DestroySessionService();
session_service_ = std::make_unique<SessionService>(browser()->profile());
helper_.SetService(session_service_.get());
SessionID* non_null_active_window_id = active_window_id;
SessionID dummy_active_window_id = SessionID::InvalidValue();
if (!non_null_active_window_id)
non_null_active_window_id = &dummy_active_window_id;
helper_.ReadWindows(windows, non_null_active_window_id);
SessionID* non_null_active_window_id =
active_window_id ? active_window_id : &dummy_active_window_id;
std::string dummy_platform_session_id{};
std::string* non_null_platform_session_id =
platform_session_id ? platform_session_id : &dummy_platform_session_id;
helper_.ReadWindows(windows, non_null_active_window_id,
non_null_platform_session_id);
}
// Configures the session service with one window with one tab and a single
@ -158,7 +163,7 @@ class SessionServiceTest : public BrowserWithTestWindowTest {
helper_.service()->SetPinnedState(window_id, tab_id, pinned_state);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
EXPECT_EQ(1U, windows.size());
if (HasFatalFailure())
@ -216,8 +221,11 @@ TEST_F(SessionServiceTest, Basic) {
helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
UpdateNavigation(window_id, tab_id, nav1, true);
service()->SetPlatformSessionIdForTesting("some-platform-session-id");
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
std::string platform_session_id;
ReadWindows(&windows, nullptr, &platform_session_id);
ASSERT_EQ(1U, windows.size());
ASSERT_TRUE(window_bounds == windows[0]->bounds);
@ -226,6 +234,7 @@ TEST_F(SessionServiceTest, Basic) {
ASSERT_EQ(window_id, windows[0]->window_id);
ASSERT_EQ(1U, windows[0]->tabs.size());
ASSERT_EQ(sessions::SessionWindow::TYPE_NORMAL, windows[0]->type);
ASSERT_EQ("some-platform-session-id", platform_session_id);
sessions::SessionTab* tab = windows[0]->tabs[0].get();
helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
@ -246,7 +255,7 @@ TEST_F(SessionServiceTest, PersistPostData) {
UpdateNavigation(window_id, tab_id, nav1, true);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
helper_.AssertSingleWindowWithSingleTab(windows, 1);
}
@ -271,7 +280,7 @@ TEST_F(SessionServiceTest, ClosingTabStaysClosed) {
EXPECT_TRUE(helper_.GetHasOpenTrackableBrowsers());
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(1U, windows.size());
EXPECT_EQ(0, windows[0]->selected_tab_index);
@ -301,7 +310,7 @@ TEST_F(SessionServiceTest, CloseSingleTabClosesWindowAndTab) {
EXPECT_FALSE(helper_.GetHasOpenTrackableBrowsers());
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
EXPECT_TRUE(windows.empty());
}
@ -333,7 +342,7 @@ TEST_F(SessionServiceTest, Pruning) {
EXPECT_EQ(2, available_range.second);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(1U, windows.size());
ASSERT_EQ(0, windows[0]->selected_tab_index);
@ -361,7 +370,7 @@ TEST_F(SessionServiceTest, TwoWindows) {
window2_id, tab1_id, tab2_id, &nav1, &nav2);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(2U, windows.size());
ASSERT_EQ(0, windows[0]->selected_tab_index);
@ -412,7 +421,7 @@ TEST_F(SessionServiceTest, WindowWithNoTabsGetsPruned) {
helper_.PrepareTabInWindow(window2_id, tab2_id, 0, true);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(1U, windows.size());
ASSERT_EQ(0, windows[0]->selected_tab_index);
@ -446,7 +455,7 @@ TEST_F(SessionServiceTest, ClosingLastWindowDoesntCloseTabs) {
service()->WindowClosed(window_id);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(1U, windows.size());
EXPECT_EQ(0, windows[0]->selected_tab_index);
@ -480,7 +489,7 @@ TEST_F(SessionServiceTest, ClosingSecondWindowClosesTabs) {
service()->WindowClosed(window2_id);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(1U, windows.size());
EXPECT_EQ(0, windows[0]->selected_tab_index);
@ -514,7 +523,7 @@ TEST_F(SessionServiceTest, LockingWindowRemembersAll) {
service()->WindowClosed(window2_id);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(2U, windows.size());
ASSERT_EQ(1U, windows[0]->tabs.size());
@ -547,7 +556,7 @@ TEST_F(SessionServiceTest, WindowCloseCommittedAfterNavigate) {
service()->WindowClosed(window2_id);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(1U, windows.size());
ASSERT_EQ(0, windows[0]->selected_tab_index);
@ -600,7 +609,7 @@ TEST_F(SessionServiceTest, PruneFromFront) {
// Read back in.
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(1U, windows.size());
ASSERT_EQ(0, windows[0]->selected_tab_index);
@ -651,7 +660,7 @@ TEST_F(SessionServiceTest, PruneFromMiddle) {
// Read back in.
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(1U, windows.size());
ASSERT_EQ(0, windows[0]->selected_tab_index);
@ -772,7 +781,7 @@ TEST_F(SessionServiceTest, PruneToEmpty) {
// Read back in.
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(0U, windows.size());
}
@ -806,7 +815,7 @@ TEST_F(SessionServiceTest, PersistApplicationExtensionID) {
helper_.SetTabExtensionAppID(window_id, tab_id, app_id);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
helper_.AssertSingleWindowWithSingleTab(windows, 1);
EXPECT_TRUE(app_id == windows[0]->tabs[0]->extension_app_id);
@ -840,7 +849,7 @@ TEST_F(SessionServiceTest, PersistUserAgentOverrides) {
helper_.SetTabUserAgentOverride(window_id, tab_id, serialized_override);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
helper_.AssertSingleWindowWithSingleTab(windows, 1);
sessions::SessionTab* tab = windows[0]->tabs[0].get();
@ -867,7 +876,7 @@ TEST_F(SessionServiceTest, PersistExtraData) {
kSampleValue);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
EXPECT_EQ(1U, windows.size());
EXPECT_EQ(1U, windows[0]->tabs.size());
EXPECT_EQ(1U, windows[0]->extra_data.size());
@ -892,7 +901,7 @@ TEST_F(SessionServiceTest, DontPersistDefault) {
ui::mojom::WindowShowState::kDefault);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(1U, windows.size());
EXPECT_EQ(ui::mojom::WindowShowState::kNormal, windows[0]->show_state);
}
@ -931,7 +940,7 @@ TEST_F(SessionServiceTest, KeepPostDataWithoutPasswords) {
UpdateNavigation(window_id, tab_id, nav2, true);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
helper_.AssertSingleWindowWithSingleTab(windows, 2);
@ -966,7 +975,7 @@ TEST_F(SessionServiceTest, RemovePostDataWithPasswords) {
UpdateNavigation(window_id, tab_id, nav1, true);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
helper_.AssertSingleWindowWithSingleTab(windows, 1);
@ -992,7 +1001,7 @@ TEST_F(SessionServiceTest, ReplacePendingNavigation) {
// Read back in.
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
// The ones with index 0, and 2 should have been replaced by 1 and 3.
ASSERT_EQ(1U, windows.size());
@ -1039,7 +1048,7 @@ TEST_F(SessionServiceTest, ReplacePendingNavigationAndPrune) {
// Read back in.
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
// We should still have that last navigation at the end,
// even though it replaced one that was set before the prune.
@ -1066,7 +1075,7 @@ TEST_F(SessionServiceTest, RestoreActivation1) {
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
SessionID active_window_id = SessionID::InvalidValue();
ReadWindows(&windows, &active_window_id);
ReadWindows(&windows, &active_window_id, nullptr);
EXPECT_EQ(window_id, active_window_id);
}
@ -1090,8 +1099,10 @@ TEST_F(SessionServiceTest, RestoreActivation2) {
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
SessionID active_window_id = SessionID::InvalidValue();
ReadWindows(&windows, &active_window_id);
std::string platform_session_id;
ReadWindows(&windows, &active_window_id, &platform_session_id);
EXPECT_EQ(window2_id, active_window_id);
EXPECT_TRUE(platform_session_id.empty());
}
// Makes sure sessions doesn't track certain urls.
@ -1111,7 +1122,7 @@ TEST_F(SessionServiceTest, IgnoreBlockedUrls) {
UpdateNavigation(window_id, tab_id, nav3, true);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(1U, windows.size());
ASSERT_EQ(0, windows[0]->selected_tab_index);
@ -1127,7 +1138,7 @@ TEST_F(SessionServiceTest, TabGroupDefaultsToNone) {
CreateTabWithTestNavigationData(window_id, 0);
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(1U, windows.size());
ASSERT_EQ(1U, windows[0]->tabs.size());
@ -1153,7 +1164,7 @@ TEST_F(SessionServiceTest, TabGroupsSaved) {
}
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(1U, windows.size());
ASSERT_EQ(kNumTabs, static_cast<int>(windows[0]->tabs.size()));
@ -1194,7 +1205,7 @@ TEST_F(SessionServiceTest, TabGroupMetadataSaved) {
}
std::vector<std::unique_ptr<sessions::SessionWindow>> windows;
ReadWindows(&windows, nullptr);
ReadWindows(&windows, nullptr, nullptr);
ASSERT_EQ(1U, windows.size());
ASSERT_EQ(2U, windows[0]->tabs.size());

@ -165,6 +165,19 @@ std::unique_ptr<SessionCommand> CreateAddExtraDataCommand(
return std::make_unique<SessionCommand>(command, pickle);
}
std::unique_ptr<SessionCommand> CreateSetPlatformSessionIdCommand(
SessionCommand::id_type command_id,
const std::string& platform_session_id) {
base::Pickle pickle;
static const SessionCommand::size_type max_id_size =
std::numeric_limits<SessionCommand::size_type>::max() - 1024;
int bytes_written = 0;
WriteStringToPickle(pickle, &bytes_written, max_id_size, platform_session_id);
return std::make_unique<SessionCommand>(command_id, pickle);
}
bool RestoreUpdateTabNavigationCommand(
const SessionCommand& command,
sessions::SerializedNavigationEntry* navigation,
@ -260,4 +273,12 @@ bool RestoreAddExtraDataCommand(const SessionCommand& command,
it.ReadString(data);
}
bool RestoreSetPlatformSessionIdCommand(const SessionCommand& command,
std::string* platform_session_id) {
base::Pickle pickle = command.PayloadAsPickle();
base::PickleIterator iterator(pickle);
return iterator.ReadString(platform_session_id);
}
} // namespace sessions

@ -59,6 +59,11 @@ std::unique_ptr<SessionCommand> CreateAddExtraDataCommand(
const std::string& key,
const std::string& data);
// Creates a SessionCommand storing the platform session id.
std::unique_ptr<SessionCommand> CreateSetPlatformSessionIdCommand(
SessionCommand::id_type command_id,
const std::string& platform_session_id);
// Converts a SessionCommand previously created by
// CreateUpdateTabNavigationCommand into a
// SerializedNavigationEntry. Returns true on success. If
@ -109,6 +114,11 @@ bool RestoreAddExtraDataCommand(const SessionCommand& command,
std::string* key,
std::string* data);
// Extracts a SessionCommand as previously created by
// CreateSetPlatformSessionIdCommand into platform_session_id.
bool RestoreSetPlatformSessionIdCommand(const SessionCommand& command,
std::string* platform_session_id);
} // namespace sessions
#endif // COMPONENTS_SESSIONS_CORE_BASE_SESSION_SERVICE_COMMANDS_H_

@ -80,6 +80,7 @@ static const SessionCommand::id_type kCommandSetWindowVisibleOnAllWorkspaces =
32;
static const SessionCommand::id_type kCommandAddTabExtraData = 33;
static const SessionCommand::id_type kCommandAddWindowExtraData = 34;
static const SessionCommand::id_type kCommandSetPlatformSessionId = 35;
// ID 255 is used by CommandStorageBackend.
namespace {
@ -452,7 +453,8 @@ void CreateTabsAndWindows(
IdToSessionTab* tabs,
GroupIdToSessionTabGroup* tab_groups,
IdToSessionWindow* windows,
SessionID* active_window_id) {
SessionID* active_window_id,
std::string* platform_session_id) {
// If the file is corrupt (command with wrong size, or unknown command), we
// still return true and attempt to restore what we we can.
DVLOG(1) << "CreateTabsAndWindows";
@ -905,6 +907,17 @@ void CreateTabsAndWindows(
break;
}
case kCommandSetPlatformSessionId: {
std::string id;
if (!RestoreSetPlatformSessionIdCommand(*command, &id)) {
DVLOG(1) << "Failed reading command " << command->id();
return;
}
DVLOG(1) << " restored platform_session_id=" << id;
*platform_session_id = id;
break;
}
default:
DVLOG(1) << "Failed reading an unknown command " << command->id();
return;
@ -1174,6 +1187,12 @@ std::unique_ptr<SessionCommand> CreateAddWindowExtraDataCommand(
data);
}
std::unique_ptr<SessionCommand> CreateSetPlatformSessionIdCommand(
const std::string& platform_session_id) {
return CreateSetPlatformSessionIdCommand(kCommandSetPlatformSessionId,
platform_session_id);
}
bool ReplacePendingCommand(CommandStorageManager* command_storage_manager,
std::unique_ptr<SessionCommand>* command) {
// We optimize page navigations, which can happen quite frequently and
@ -1237,14 +1256,15 @@ bool IsClosingCommand(SessionCommand* command) {
void RestoreSessionFromCommands(
const std::vector<std::unique_ptr<SessionCommand>>& commands,
std::vector<std::unique_ptr<SessionWindow>>* valid_windows,
SessionID* active_window_id) {
SessionID* active_window_id,
std::string* platform_session_id) {
IdToSessionTab tabs;
GroupIdToSessionTabGroup tab_groups;
IdToSessionWindow windows;
DVLOG(1) << "RestoreSessionFromCommands " << commands.size();
CreateTabsAndWindows(commands, &tabs, &tab_groups, &windows,
active_window_id);
CreateTabsAndWindows(commands, &tabs, &tab_groups, &windows, active_window_id,
platform_session_id);
AddTabsToWindows(&tabs, &tab_groups, &windows);
SortTabsBasedOnVisualOrderAndClear(&windows, valid_windows);
UpdateSelectedTabIndex(valid_windows);

@ -111,6 +111,9 @@ SESSIONS_EXPORT std::unique_ptr<SessionCommand> CreateAddWindowExtraDataCommand(
const std::string& key,
const std::string& data);
SESSIONS_EXPORT std::unique_ptr<SessionCommand>
CreateSetPlatformSessionIdCommand(const std::string& platform_session_id);
// Searches for a pending command using |command_storage_manager| that can be
// replaced with |command|. If one is found, pending command is removed, the
// command is added to the pending commands (taken ownership) and true is
@ -129,7 +132,8 @@ SESSIONS_EXPORT bool IsClosingCommand(SessionCommand* command);
SESSIONS_EXPORT void RestoreSessionFromCommands(
const std::vector<std::unique_ptr<SessionCommand>>& commands,
std::vector<std::unique_ptr<SessionWindow>>* valid_windows,
SessionID* active_window_id);
SessionID* active_window_id,
std::string* platform_session_id);
} // namespace sessions