fix(servo): retire sessions on internal navigation

This commit is contained in:
2026-07-09 22:37:17 -04:00
parent b422ac1631
commit 31fc1acf17
9 changed files with 571 additions and 93 deletions
+14 -36
View File
@@ -8,7 +8,7 @@ use ely_domain::{BrowserTab, TabId};
use crate::services::{
ProfileDataMode,
servo_live::{ServoLiveEnsureRequest, ServoLiveSitePermission},
servo_live::{ServoLiveEnsureRequest, ServoLivePermissionGrant, ServoLiveSitePermission},
servo_profile_data::cleanup_stale_transient_profile_data_dirs,
};
@@ -39,6 +39,7 @@ pub(super) struct WebSurfaceRuntime {
sessions: BTreeMap<TabId, WebSurfaceSession>,
retry_state: BTreeMap<WebSurfaceRuntimeScope, ScopeRetryState>,
retired_workers: Vec<JoinHandle<Result<(), String>>>,
retired_permission_consumptions: Vec<ServoLivePermissionGrant>,
transient_cleanup_error: Option<String>,
client_factory: LiveRuntimeClientFactory,
last_generation: u64,
@@ -55,6 +56,7 @@ impl WebSurfaceRuntime {
sessions: BTreeMap::new(),
retry_state: BTreeMap::new(),
retired_workers: Vec::new(),
retired_permission_consumptions: Vec::new(),
transient_cleanup_error,
client_factory: new_servo_live_client,
last_generation: 0,
@@ -68,6 +70,7 @@ impl WebSurfaceRuntime {
sessions: BTreeMap::new(),
retry_state: BTreeMap::new(),
retired_workers: Vec::new(),
retired_permission_consumptions: Vec::new(),
transient_cleanup_error: None,
client_factory,
last_generation: 0,
@@ -136,9 +139,10 @@ impl WebSurfaceRuntime {
allow_once_grants: allow_once_grants(tab.profile_id(), permissions),
};
let Some(scoped) = self.workers.get(&scope) else {
let Some(scoped) = self.workers.get_mut(&scope) else {
return Err("Servo sidecar worker was created but is no longer registered".to_string());
};
scoped.track_allow_once_grants(&request.allow_once_grants);
scoped.worker.submit_ensure(generation, request);
if let Some(session) = self.sessions.get_mut(tab.id()) {
session.cadence.note_poll_submitted(submitted_at);
@@ -150,7 +154,7 @@ impl WebSurfaceRuntime {
pub(super) fn tick(&mut self, visible_tab_ids: &[TabId]) -> Vec<WebSurfaceRuntimeFrame> {
self.reap_retired_workers(false);
let mut frames = Vec::new();
let mut frames = self.take_retired_permission_frames();
let now = Instant::now();
let scopes = self.workers.keys().cloned().collect::<Vec<_>>();
let mut unavailable_scopes = Vec::new();
@@ -168,6 +172,7 @@ impl WebSurfaceRuntime {
for scope in unavailable_scopes {
self.invalidate_scope(&scope, now);
}
frames.extend(self.take_retired_permission_frames());
let poll_now = Instant::now();
for tab_id in visible_tab_ids {
@@ -209,19 +214,6 @@ impl WebSurfaceRuntime {
.min()
}
pub(super) fn close_tab(&mut self, tab_id: &TabId) {
let Some(session) = self.sessions.remove(tab_id) else {
return;
};
let has_remaining_session =
self.sessions.values().any(|candidate| candidate.scope == session.scope);
if session.scope.is_transient() && !has_remaining_session {
self.remove_worker(&session.scope);
} else if let Some(scoped) = self.workers.get(&session.scope) {
scoped.worker.submit_close(tab_id.as_str().to_string());
}
}
pub(super) fn has_session(
&self,
tab_id: &TabId,
@@ -277,28 +269,10 @@ impl WebSurfaceRuntime {
return Err(error);
}
};
self.workers.insert(scope, ScopedWorker { worker, transient_profile_data_dir });
self.workers.insert(scope, ScopedWorker::new(worker, transient_profile_data_dir));
Ok(())
}
fn detach_tab_from_previous_scope(&mut self, tab_id: &TabId, scope: &WebSurfaceRuntimeScope) {
let Some(previous_scope) = self.sessions.get(tab_id).map(|session| session.scope.clone())
else {
return;
};
if &previous_scope == scope {
return;
}
self.sessions.remove(tab_id);
let has_remaining_session =
self.sessions.values().any(|candidate| candidate.scope == previous_scope);
if previous_scope.is_transient() && !has_remaining_session {
self.remove_worker(&previous_scope);
} else if let Some(scoped) = self.workers.get(&previous_scope) {
scoped.worker.submit_close(tab_id.as_str().to_string());
}
}
fn collect_responses(
&mut self,
scope: &WebSurfaceRuntimeScope,
@@ -362,6 +336,9 @@ impl WebSurfaceRuntime {
frames.push(WebSurfaceRuntimeFrame::PermissionSnapshotAccepted(grant));
}
WorkerResponse::PermissionConsumed(consumed) => {
if let Some(scoped) = self.workers.get_mut(scope) {
scoped.mark_permission_consumed(&consumed);
}
frames.push(WebSurfaceRuntimeFrame::PermissionConsumed(consumed));
}
}
@@ -398,9 +375,10 @@ impl WebSurfaceRuntime {
}
fn remove_worker(&mut self, scope: &WebSurfaceRuntimeScope) {
let Some(scoped) = self.workers.remove(scope) else {
let Some(mut scoped) = self.workers.remove(scope) else {
return;
};
self.retire_scoped_worker_permissions(&mut scoped);
if scoped.transient_profile_data_dir.is_some() {
match std::thread::Builder::new()
.name("ely-servo-profile-cleanup".to_string())