devtools: Fix id collisions by using incrementing counters (#35971)

Devtools clients need a `browserId`, `browsingContextID`, and
`outerWindowID`, which correspond to WebViewId, BrowsingContextId, and
PipelineId in Servo. These u32 values were previously derived from our
sharded (u32,u32) id values by taking only the `index` (second u32) and
ignoring the `namespace_id` (first u32), leading to collisions.

This patch fixes that by mapping those Servo ids to sequential u32
values.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by
`[X]` when the step is complete, and replace `___` with appropriate
data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #35954

<!-- Either: -->
- [x] There are tests for these changes OR
- [ ] These changes do not require tests because ___

<!-- Also, please make sure that "Allow edits from maintainers" checkbox
is checked, so that we can help you if you get stuck somewhere along the
way.-->

<!-- Pull requests that do not address these steps are welcome, but they
will require additional verification as part of the review process. -->

---------

Signed-off-by: Delan Azabani <dazabani@igalia.com>
This commit is contained in:
Delan Azabani 2025-04-01 17:00:40 +08:00 committed by GitHub
parent fcef1dff9d
commit 30b712aaf9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 219 additions and 33 deletions

View file

@ -10,7 +10,7 @@ use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::net::TcpStream;
use base::id::{BrowsingContextId, PipelineId, WebViewId};
use base::id::PipelineId;
use devtools_traits::DevtoolScriptControlMsg::{self, GetCssDatabase, WantsLiveNotifications};
use devtools_traits::{DevtoolsPageInfo, NavigationState};
use ipc_channel::ipc::{self, IpcSender};
@ -26,6 +26,7 @@ use crate::actors::stylesheets::StyleSheetsActor;
use crate::actors::tab::TabDescriptorActor;
use crate::actors::thread::ThreadActor;
use crate::actors::watcher::{SessionContext, SessionContextType, WatcherActor};
use crate::id::{DevtoolsBrowserId, DevtoolsBrowsingContextId, DevtoolsOuterWindowId, IdMap};
use crate::protocol::JsonPacketStream;
use crate::{EmptyReplyMsg, StreamId};
@ -124,10 +125,11 @@ pub(crate) struct BrowsingContextActor {
pub name: String,
pub title: RefCell<String>,
pub url: RefCell<String>,
/// This correspond to webview_id
pub browser_id: WebViewId,
pub active_pipeline: Cell<PipelineId>,
pub browsing_context_id: BrowsingContextId,
/// This corresponds to webview_id
pub browser_id: DevtoolsBrowserId,
pub active_pipeline_id: Cell<PipelineId>,
pub active_outer_window_id: Cell<DevtoolsOuterWindowId>,
pub browsing_context_id: DevtoolsBrowsingContextId,
pub accessibility: String,
pub console: String,
pub css_properties: String,
@ -169,19 +171,21 @@ impl Actor for BrowsingContextActor {
self.streams.borrow_mut().remove(&id);
if self.streams.borrow().is_empty() {
self.script_chan
.send(WantsLiveNotifications(self.active_pipeline.get(), false))
.send(WantsLiveNotifications(self.active_pipeline_id.get(), false))
.unwrap();
}
}
}
impl BrowsingContextActor {
#[allow(clippy::too_many_arguments)]
pub(crate) fn new(
console: String,
browser_id: WebViewId,
browsing_context_id: BrowsingContextId,
browser_id: DevtoolsBrowserId,
browsing_context_id: DevtoolsBrowsingContextId,
page_info: DevtoolsPageInfo,
pipeline_id: PipelineId,
outer_window_id: DevtoolsOuterWindowId,
script_sender: IpcSender<DevtoolScriptControlMsg>,
actors: &mut ActorRegistry,
) -> BrowsingContextActor {
@ -230,7 +234,8 @@ impl BrowsingContextActor {
script_chan: script_sender,
title: RefCell::new(title),
url: RefCell::new(url.into_string()),
active_pipeline: Cell::new(pipeline_id),
active_pipeline_id: Cell::new(pipeline_id),
active_outer_window_id: Cell::new(outer_window_id),
browser_id,
browsing_context_id,
accessibility: accessibility.name(),
@ -270,11 +275,9 @@ impl BrowsingContextActor {
},
title: self.title.borrow().clone(),
url: self.url.borrow().clone(),
browser_id: self.browser_id.0.index.0.get(),
//FIXME: shouldn't ignore pipeline namespace field
browsing_context_id: self.browsing_context_id.index.0.get(),
//FIXME: shouldn't ignore pipeline namespace field
outer_window_id: self.active_pipeline.get().index.0.get(),
browser_id: self.browser_id.value(),
browsing_context_id: self.browsing_context_id.value(),
outer_window_id: self.active_outer_window_id.get().value(),
is_top_level_target: true,
accessibility_actor: self.accessibility.clone(),
console_actor: self.console.clone(),
@ -286,15 +289,17 @@ impl BrowsingContextActor {
}
}
pub(crate) fn navigate(&self, state: NavigationState) {
let (pipeline, title, url, state) = match state {
pub(crate) fn navigate(&self, state: NavigationState, id_map: &mut IdMap) {
let (pipeline_id, title, url, state) = match state {
NavigationState::Start(url) => (None, None, url, "start"),
NavigationState::Stop(pipeline, info) => {
(Some(pipeline), Some(info.title), info.url, "stop")
},
};
if let Some(p) = pipeline {
self.active_pipeline.set(p);
if let Some(pipeline_id) = pipeline_id {
let outer_window_id = id_map.outer_window_id(pipeline_id);
self.active_outer_window_id.set(outer_window_id);
self.active_pipeline_id.set(pipeline_id);
}
url.as_str().clone_into(&mut self.url.borrow_mut());
if let Some(ref t) = title {
@ -317,7 +322,7 @@ impl BrowsingContextActor {
}
pub(crate) fn title_changed(&self, pipeline_id: PipelineId, title: String) {
if pipeline_id != self.active_pipeline.get() {
if pipeline_id != self.active_pipeline_id.get() {
return;
}
*self.title.borrow_mut() = title;
@ -328,7 +333,7 @@ impl BrowsingContextActor {
from: self.name(),
type_: "frameUpdate".into(),
frames: vec![FrameUpdateMsg {
id: self.browsing_context_id.index.0.get(),
id: self.browsing_context_id.value(),
is_top_level: true,
title: self.title.borrow().clone(),
url: self.url.borrow().clone(),

View file

@ -152,7 +152,7 @@ impl ConsoleActor {
Root::BrowsingContext(bc) => UniqueId::Pipeline(
registry
.find::<BrowsingContextActor>(bc)
.active_pipeline
.active_pipeline_id
.get(),
),
Root::DedicatedWorker(w) => UniqueId::Worker(registry.find::<WorkerActor>(w).worker_id),

View file

@ -80,7 +80,7 @@ impl Actor for InspectorActor {
_id: StreamId,
) -> Result<ActorMessageStatus, ()> {
let browsing_context = registry.find::<BrowsingContextActor>(&self.browsing_context);
let pipeline = browsing_context.active_pipeline.get();
let pipeline = browsing_context.active_pipeline_id.get();
Ok(match msg_type {
"getWalker" => {
let (tx, rx) = ipc::channel().unwrap();

View file

@ -146,18 +146,15 @@ impl TabDescriptorActor {
pub fn encodable(&self, registry: &ActorRegistry, selected: bool) -> TabDescriptorActorMsg {
let ctx_actor = registry.find::<BrowsingContextActor>(&self.browsing_context_actor);
let browser_id = ctx_actor.browser_id.0.index.0.get();
let browsing_context_id = ctx_actor.browsing_context_id.index.0.get();
let outer_window_id = ctx_actor.active_pipeline.get().index.0.get();
let title = ctx_actor.title.borrow().clone();
let url = ctx_actor.url.borrow().clone();
TabDescriptorActorMsg {
actor: self.name(),
browser_id,
browsing_context_id,
browser_id: ctx_actor.browser_id.value(),
browsing_context_id: ctx_actor.browsing_context_id.value(),
is_zombie_tab: false,
outer_window_id,
outer_window_id: ctx_actor.active_outer_window_id.get().value(),
selected,
title,
traits: DescriptorTraits {

View file

@ -259,10 +259,9 @@ impl Actor for WatcherActor {
ActorMessageStatus::Processed
},
"getParentBrowsingContextID" => {
let browsing_context_id = target.browsing_context_id.index.0.get();
let msg = GetParentBrowsingContextIDReply {
from: self.name(),
browsing_context_id,
browsing_context_id: target.browsing_context_id.value(),
};
let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed