Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: store portal restore token under the right source ID #40098

Merged
merged 1 commit into from Oct 12, 2023

Conversation

aiddya
Copy link
Contributor

@aiddya aiddya commented Oct 5, 2023

Description of Change

XDG Desktop Portal provides restore tokens to restore a previously selected PipeWire stream instead of prompting the user again. This restore token is single use only and it has to be replaced when the stream is completed/stopped.

BaseCapturerPipewire maintains two source IDs: one is initialized by the constructor for new sources (source_id_) and another is for capturing previously selected sources (selected_source_id_). The restore token was always being stored under source_id_, even if the capture was ongoing for selected_source_id_. This prevents a stream from being restored more than once. Fix that by storing the restore token under the selected source ID if it exists.

Fixes #40097

cc @VerteDinde (this might fix some of the duplicate permission dialog issues)

Checklist

Release Notes

Notes: Fixed some redundant permission dialogs while screen sharing on Wayland.

@grulja
Copy link

grulja commented Oct 5, 2023

Hi, can you please target this to WebRTC upstream? I see you also have another related fixes, it's unfortunate these will land only for Electron and not for all the others.

I will test this myself, it will take a while for me to build Chromium as I haven't updated my checkout for a while, but I'm not sure it will fix the issue I'm seeing with Google Meet. I'm also not sure it's correct, usually the selected_source_id_ is expected to be the same as source_id_ as the client should only select a source we previously sent him through GetSourceList(). I will look and let you know.

@grulja
Copy link

grulja commented Oct 5, 2023

It doesn't fix my issue with Google Meet, but I think I understand the issue you are trying to fix. I believe the main problem in your case is that once the stream is stopped, it will bump the source_id so it will no longer match the selected_source_id_. This is not a problem in Chrome since usually when the stream is stopped, the DesktopCapturer instance is destroyed.

For Google Meet I can see it properly stores the token with source_id_ and tries to access it with selected_source_id_ while both are equal, yet it will open another portal dialog. I will keep digging.

@aiddya
Copy link
Contributor Author

aiddya commented Oct 5, 2023

@grulja I would prefer to target upstream, but WebRTC's CLA requirement is a significant hurdle for me. My employer does not permit CLAs and I'll have to check if there's an exception process.

Did you check the D-Bus calls that were being made? It was helpful for me to debug this issue. I observed that Electron was not passing the restore token in SelectSources call, which led me to look into how source IDs and restore tokens were managed. I think the bug that you're seeing is in Electron as well as I've observed that Slack is unable to restore the stream even once.

@aiddya
Copy link
Contributor Author

aiddya commented Oct 6, 2023

@grulja I looked further into the Google Meet issue. It appears that after the source is chosen, two desktop capturer instances are created in quick succession. The first instance takes the restore token, but is destroyed before it can replace it. When the second one tries to look for the token, it gets nothing. Here are some logs that I added to describe the issue:

[538330:538330:1005/203914.785878:ERROR:desktop_capture.cc(112)] Creating window capturer from DesktopCapture
[538330:538330:1005/203914.787846:ERROR:base_capturer_pipewire.cc(60)] Instantiated with source ID: 1
[538330:538330:1005/203914.788420:ERROR:desktop_capture.cc(97)] Creating screen capturer from DesktopCapture
[538330:538330:1005/203914.788495:ERROR:base_capturer_pipewire.cc(60)] Instantiated with source ID: 2
[538330:538921:1005/203928.183964:ERROR:base_capturer_pipewire.cc(211)] Instance 2: Selecting source ID 2
[538330:538921:1005/203929.201088:ERROR:base_capturer_pipewire.cc(211)] Instance 2: Selecting source ID 2
[538330:538330:1005/203929.511695:ERROR:base_capturer_pipewire.cc(89)] Instance 2: Storing token 07ec33a7-ba27-4683-bfb1-6a12be991f49 under source ID 2
[538330:538921:1005/203930.201934:ERROR:base_capturer_pipewire.cc(211)] Instance 2: Selecting source ID 2
[538330:538921:1005/203931.224216:ERROR:base_capturer_pipewire.cc(211)] Instance 2: Selecting source ID 2
[538330:538921:1005/203931.370653:ERROR:base_capturer_pipewire.cc(66)] Destroying instance 2
[538330:538920:1005/203931.377076:ERROR:base_capturer_pipewire.cc(66)] Destroying instance 1
[538330:538384:1005/203931.463943:ERROR:desktop_capture_device.cc(798)] Creating screen capturer from DesktopCaptureDevice for source ID 2
[538330:538384:1005/203931.464109:ERROR:base_capturer_pipewire.cc(60)] Instantiated with source ID: 3
[538330:538384:1005/203931.464192:ERROR:base_capturer_pipewire.cc(211)] Instance 3: Selecting source ID 2
[538330:539620:1005/203931.465545:ERROR:base_capturer_pipewire.cc(156)] Instance 3: Attempting to restore source ID 2 using restore token 07ec33a7-ba27-4683-bfb1-6a12be991f49
[538330:539620:1005/203931.505070:ERROR:base_capturer_pipewire.cc(66)] Destroying instance 3
[538330:538384:1005/203931.510572:ERROR:desktop_capture_device.cc(798)] Creating screen capturer from DesktopCaptureDevice for source ID 2
[538330:538384:1005/203931.510656:ERROR:base_capturer_pipewire.cc(60)] Instantiated with source ID: 4
[538330:538384:1005/203931.510705:ERROR:base_capturer_pipewire.cc(211)] Instance 4: Selecting source ID 2
[538330:539624:1005/203931.512228:ERROR:base_capturer_pipewire.cc(156)] Instance 4: Attempting to restore source ID 2 using restore token 
[538330:538330:1005/203934.032677:ERROR:base_capturer_pipewire.cc(89)] Instance 4: Storing token 327a403f-8616-42fb-a6f4-5e9b7a0c73b7 under source ID 2
[538330:539624:1005/203938.478562:ERROR:base_capturer_pipewire.cc(66)] Destroying instance 4

The first two BaseCapturerPipeWire instances are from the Chromium picker. The restore token is stored correctly, but is taken by a transient third instance of BaseCapturerPipeWire, which lasts just a few milliseconds. The fix has to somehow avoid creating this transient instance. Delaying the destruction of BaseCapturerPipeWire is not a fix, as it'll just create a race between the portal sending a restore token and the BaseCapturerPipeWire trying to read it.

This PR does fix a valid issue in Electron, but there's probably another issue that has to be fixed to avoid the duplicate permission dialogs.

@grulja
Copy link

grulja commented Oct 6, 2023

Interesting. I can certainly see in that scenario why it breaks. I wonder whether we can do a simple fix to both of our issues by just making RestoreManager::TakeToken(SourceId id) not to remove the token from the list. It fixes the issue for me and I believe it should fix yours issue. Still probably the right fix would be not to create the redundant DesktopCapture instance, but could that be a GMeet issue? I don't see this behavior with the WebRTC testing page for example.

@grulja
Copy link

grulja commented Oct 6, 2023

I opened a bug and added you to CC: https://bugs.chromium.org/p/webrtc/issues/detail?id=15544
And also opened a merge request: https://webrtc-review.googlesource.com/c/src/+/322621

It should fix both issues.

@aiddya
Copy link
Contributor Author

aiddya commented Oct 6, 2023

I think simply changing RestoreManager to not delete tokens on fetching them is not the right fix by itself, because XDG Desktop Portal returning the same token is an implementation detail. The portal documentation on restore_token says:

If the stored session cannot be restored, this value is ignored and the user will be prompted normally. This may happen when, for example, the session contains a monitor or a window that is not available anymore, or when the stored permissions are withdrawn.

The restore token is invalidated after using it once. To restore the same session again, use the new restore token sent in response to starting this session.

This design choice is inherently racy, as the process to use and replenish a token is not an atomic operation. This is especially true for web browsers, where a stream could be restored multiple times in different threads due to website code. XDG Desktop Portal should document that the restore token will be retained if the stream is restored.

It might be okay to rely on the implementation detail for now and not delete tokens, but only for race conditions. The returned restore token should be stored under the right source ID to handle other cases mentioned in the documentation.

XDG Desktop Portal provides restore tokens to restore a previously
selected PipeWire stream instead of prompting the user again. This
restore token is single use only and it has to be replaced when the
stream is completed/stopped.

BaseCapturerPipewire maintains two source IDs: one is initialized by
the constructor for new sources (source_id_) and another is for
capturing previously selected sources (selected_source_id_). The
restore token was always being stored under `source_id_`, even if the
capture was ongoing for `selected_source_id_`. This prevents a stream
from being restored more than once. Fix that by storing the restore
token under the selected source ID if it exists.
@aiddya
Copy link
Contributor Author

aiddya commented Oct 10, 2023

Replaced with the upstream patch, which subsumes my previous patch and includes an additional fix for race conditions.

@aiddya
Copy link
Contributor Author

aiddya commented Oct 12, 2023

Can we land this before #40114? The patch is included in #40114, so if that PR lands first, I'll have to manually backport this to all the stable branches.

@electron-cation electron-cation bot removed the new-pr 🌱 PR opened in the last 24 hours label Oct 12, 2023
@codebytere codebytere added semver/patch backwards-compatible bug fixes target/26-x-y PR should also be added to the "26-x-y" branch. target/27-x-y PR should also be added to the "27-x-y" branch. target/28-x-y PR should also be added to the "28-x-y" branch. labels Oct 12, 2023
@codebytere codebytere merged commit 3c31246 into electron:main Oct 12, 2023
21 checks passed
@release-clerk
Copy link

release-clerk bot commented Oct 12, 2023

Release Notes Persisted

Fixed some redundant permission dialogs while screen sharing on Wayland.

@trop
Copy link
Contributor

trop bot commented Oct 12, 2023

I have automatically backported this PR to "26-x-y", please check out #40191

@trop trop bot removed the target/26-x-y PR should also be added to the "26-x-y" branch. label Oct 12, 2023
@trop
Copy link
Contributor

trop bot commented Oct 12, 2023

I have automatically backported this PR to "28-x-y", please check out #40192

@trop
Copy link
Contributor

trop bot commented Oct 12, 2023

I have automatically backported this PR to "27-x-y", please check out #40193

@trop trop bot added in-flight/27-x-y merged/27-x-y PR was merged to the "27-x-y" branch. merged/28-x-y PR was merged to the "28-x-y" branch. merged/26-x-y PR was merged to the "26-x-y" branch. and removed target/28-x-y PR should also be added to the "28-x-y" branch. target/27-x-y PR should also be added to the "27-x-y" branch. in-flight/27-x-y in-flight/28-x-y in-flight/26-x-y labels Oct 12, 2023
MrHuangJser pushed a commit to MrHuangJser/electron that referenced this pull request Dec 11, 2023
…0098)

XDG Desktop Portal provides restore tokens to restore a previously
selected PipeWire stream instead of prompting the user again. This
restore token is single use only and it has to be replaced when the
stream is completed/stopped.

BaseCapturerPipewire maintains two source IDs: one is initialized by
the constructor for new sources (source_id_) and another is for
capturing previously selected sources (selected_source_id_). The
restore token was always being stored under `source_id_`, even if the
capture was ongoing for `selected_source_id_`. This prevents a stream
from being restored more than once. Fix that by storing the restore
token under the selected source ID if it exists.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged/26-x-y PR was merged to the "26-x-y" branch. merged/27-x-y PR was merged to the "27-x-y" branch. merged/28-x-y PR was merged to the "28-x-y" branch. semver/patch backwards-compatible bug fixes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug]: desktopCapturer source IDs are valid for a single use on Wayland
3 participants