Compare commits

..

212 Commits

Author SHA1 Message Date
Sudowoodo Release Bot
79b45ac5f6 Bump v15.5.1 2022-03-30 08:32:53 -07:00
trop[bot]
e5e8dd5156 fix: libuv patches to address child_process.spawn slowness (#33406)
* fix: libuv patches to address child_process.spawn slowness

* chore: backport additional patches

* Update .patches

* chore: update patches

* chore: update patches

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
2022-03-29 19:45:46 -04:00
trop[bot]
4e75499270 fix: crash when WindowButtonsProxy references cleared NSWindow (#33487)
* resets WindowButtonsProxy on window delete on macOS

* fixes reset

* chore: empty commit

Co-authored-by: Gellert Hegyi <gellert.hegyi@around.co>
Co-authored-by: Samuel Attard <sattard@salesforce.com>
2022-03-29 19:43:28 -04:00
Sudowoodo Release Bot
1bc5b6177f Bump v15.5.0 2022-03-28 13:24:07 -07:00
Pedro Pontes
5647382a55 chore: cherry-pick 26b7ad6967b1 from v8 (#33473)
* chore: cherry-pick 26b7ad6967b1 from v8

* chore: update patches

* kick lint

* kick lint

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
Co-authored-by: Electron Bot <electron@github.com>
2022-03-28 13:12:10 -07:00
Pedro Pontes
fd272d89bc chore: cherry-pick c46fb3a15ec2 from v8 (#33393)
* chore: cherry-pick c46fb3a15ec2 from v8

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-03-28 12:45:57 -04:00
Calvin
d745647c54 fix: non-client windows messages on legacy widget host (again) (#33449) 2022-03-28 16:34:53 +09:00
trop[bot]
9038bdd7bc fix: use stricter options in SecStaticCodeCheckValidity (#33376)
* fix: use stricter options in SecStaticCodeCheckValidity

* Update patches/squirrel.mac/fix_use_kseccschecknestedcode_kseccsstrictvalidate_in_the_sec.patch

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

* Trigger Build

Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
Co-authored-by: Samuel Attard <sam@electronjs.org>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-03-25 10:53:56 +01:00
trop[bot]
bbc862c878 test: disable webview.capturePage test (#33433)
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2022-03-24 12:19:24 -04:00
trop[bot]
ff57df1ecb ci: abort CI if goma authentication is invalid (#33417)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-03-24 09:01:35 -04:00
Milan Burda
37dfd8be4a feat: add nativeTheme.inForcedColorsMode (#32956) (#33360) 2022-03-23 16:55:09 -07:00
Sudowoodo Release Bot
f043e665dd Bump v15.4.2 2022-03-23 08:32:18 -07:00
Pedro Pontes
798f151e05 chore: cherry-pick 2b75a29bf2 from angle (#33390)
* chore: cherry-pick 2b75a29bf2 from angle

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-03-23 09:48:49 -04:00
Robin Ebert
a9a3910aa0 chore: backport dd4c3ddadbb9 from chromium (#33038)
* chore: backport dd4c3ddadbb9 from chromium

* Fix mapping of keymap fd

* Implement a proper wayland keymap fix that doesn't depend on fd permissions

* Close keymap fd at the end of Keymap-event handler
2022-03-23 18:42:26 +09:00
Pedro Pontes
2f28e10543 chore: cherry-pick ca32852e4f from angle (#33222)
Co-authored-by: Electron Bot <electron@github.com>
2022-03-22 20:11:21 -04:00
trop[bot]
f1021b93d0 fix: non-client mouse events on WCO-enabled windows (#33199)
* fix: non-client mouse events on WCO-enabled windows

* chore: cleanup .patches after merge

Co-authored-by: clavin <clavin@electronjs.org>
Co-authored-by: Calvin <clavin@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-03-22 11:29:04 -04:00
Pedro Pontes
6788561bb3 chore: cherry-pick 161f0866e8 from angle (#33342)
* chore: cherry-pick 161f0866e8 from angle

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-03-22 15:08:45 +09:00
Pedro Pontes
35d3f35a44 chore: cherry-pick 905302eb3a2b from chromium (#33237)
* chore: cherry-pick 905302eb3a2b from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-03-22 08:27:15 +09:00
trop[bot]
f949a1aafd chore: cherry-pick 2ed58f4 from chromium (#33109) (#33248)
Refs: https://chromium-review.googlesource.com/c/chromium/src/+/3492658
Fixes: https://github.com/electron/electron/issues/33049
Signed-off-by: Darshan Sen <raisinten@gmail.com>

Co-authored-by: Charles Kerr <charles@charleskerr.com>

Co-authored-by: Darshan Sen <raisinten@gmail.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2022-03-21 11:09:31 +09:00
Pedro Pontes
b8e22532b0 chore: cherry-pick 246c10dede97 from chromium (#33245)
* chore: cherry-pick 246c10dede97 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-03-21 10:26:20 +09:00
trop[bot]
c2758554ed fix: crash when destroying node env with pending promises (#33300)
* fix: crash when destroying node env with pending promises

* chore: add spec

Co-authored-by: deepak1556 <hop2deep@gmail.com>
2022-03-21 10:20:30 +09:00
trop[bot]
05cb4240bd build: drop pywin32 usage (#33296)
* build: drop pywin32 usage

* chore: ignore extra output on AppVeyor

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2022-03-21 10:16:28 +09:00
trop[bot]
c84b152164 docs: remove "marked" from process.getBlinkMemoryInfo() (#33289)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2022-03-17 14:08:45 +01:00
David Sanders
20f8c10977 fix: ensure external memory adjustments are balanced (#33311) 2022-03-16 22:17:18 -07:00
Pedro Pontes
38be2dfb25 chore: cherry-pick eb967bf211 from chromium (#33242) 2022-03-16 12:34:55 +01:00
Jeremy Rose
0c371e53a4 chore: cherry-pick 62142d222a80 from chromium (#33185)
* chore: cherry-pick 62142d222a80 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-03-09 16:27:32 -05:00
Sudowoodo Release Bot
8e517202ea Bump v15.4.1 2022-03-09 07:31:54 -08:00
Jeremy Rose
3410147699 chore: cherry-pick 1887414c016d from chromium (#33178)
* chore: cherry-pick 1887414c016d from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-03-08 14:36:13 -05:00
Jeremy Rose
ce5157236c chore: cherry-pick 49e8ff16f1fe from angle (#33181)
* chore: cherry-pick 49e8ff16f1fe from angle

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-03-08 10:54:31 -05:00
Jeremy Rose
8ec2469379 chore: cherry-pick 6b2643846ae3 from chromium (#33168)
* chore: cherry-pick 6b2643846ae3 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-03-07 16:52:22 -08:00
trop[bot]
ddf348d609 fix: really strip crashpad handler binary (#33173)
Co-authored-by: Micha Hanselmann <micha.hanselmann@gmail.com>
2022-03-07 17:05:50 -05:00
trop[bot]
f757a17821 fix: macOS tray icon alternate images (#33104)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-03-02 12:01:13 -08:00
Sudowoodo Release Bot
8519ba881e Bump v15.4.0 2022-02-28 16:11:36 -08:00
Michaela Laurencin
bd31023314 feat: add WCO height option (#33064)
* feat: add WCO height option (#31222)

* feat: add WCO height option

* add docs and mac functionality

* add macOS functionality and height lowerbound

* Update docs/api/browser-window.md

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

* update macOS functionality

* add chromium related notes

* add test and fix pixel under button bug and fix typo

* revert changes to docs/api/frameless-window.md

* modify `useCustomHeight` calls

* update `useCustomHeight` and `getCurrentMargin`

* modify margin calculation

* fix minimum custom height on macOS

* Update window_buttons_proxy.mm

* fix specified traffic light positions

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

* Update win_caption_button.h

* Update win_caption_button_container.h

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-02-28 11:35:04 -08:00
trop[bot]
fb0eb6c0ca fix: tray garbage collection (#33077)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-02-24 16:34:27 -05:00
Sudowoodo Release Bot
390349e3db Revert "Bump v15.3.8"
This reverts commit f6e6873971.
2022-02-23 15:45:05 -08:00
Sudowoodo Release Bot
f6e6873971 Bump v15.3.8 2022-02-23 11:30:58 -08:00
Robo
ecd6918166 chore: cherry-pick a1c1ec1ea from chromium (#32800)
Backports https://chromium-review.googlesource.com/c/chromium/src/+/3244046

Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2022-02-22 16:33:44 +09:00
Shelley Vohr
d54f1d58f7 fix: savePage throw on relative paths (#33018) 2022-02-22 16:30:46 +09:00
trop[bot]
5d5b2bf8e5 fix: command string for windows protocol handler (#33011)
Co-authored-by: deepak1556 <hop2deep@gmail.com>
2022-02-22 16:26:43 +09:00
Pedro Pontes
fa37e1533f chore: cherry-pick 11505c3867 from chromium (#32912) 2022-02-21 14:07:46 -08:00
Pedro Pontes
f9cf232597 chore: cherry-pick 05e714a87c from chromium (#32908)
Co-authored-by: Electron Bot <electron@github.com>
2022-02-21 10:41:47 -08:00
trop[bot]
615c15c914 chore: add @electron/wg-security to patches/ CODEOWNERS (#33004)
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2022-02-21 11:47:52 +01:00
Pedro Pontes
4550baa7a5 chore: cherry-pick be50c60b4225 from chromium (#32917)
* chore: cherry-pick be50c60b4225 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2022-02-21 16:46:12 +09:00
Robo
7469c72d80 chore: cherry-pick e8379497e from chromium (#32799)
* chore: cherry-pick e8379497e from chromium

Backports https://chromium-review.googlesource.com/c/chromium/src/+/3335320

* chore: update patches

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2022-02-21 16:43:59 +09:00
Robo
bedb5e1055 chore: cherry-pick ebddaedee from v8 (#32797)
* chore: cherry-pick ebddaedee from v8

Backports https://chromium-review.googlesource.com/c/v8/v8/+/3218193

* chore: update patches

Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-02-21 16:36:00 +09:00
trop[bot]
6815c823b3 fix: stale renderer process on quit (#32967)
Co-authored-by: Micha Hanselmann <micha.hanselmann@gmail.com>
2022-02-21 10:26:22 +09:00
Cheng Zhao
78c5a2cf4b chore: cherry-pick fix for 1277917 from chromium (#32786)
Co-authored-by: Electron Bot <electron@github.com>
2022-02-18 11:11:54 +09:00
Pedro Pontes
3c3d279182 chore: cherry-pick ebc188ad769e from chromium (#32914)
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-02-17 13:19:27 -08:00
Pedro Pontes
1c7a612931 chore: cherry-pick e3805f29fed7 from chromium (#32901)
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-02-17 10:03:12 -08:00
Cheng Zhao
4615dcbbfd chore: cherry-pick fix for 1281979 from chromium (#32785)
Co-authored-by: Electron Bot <electron@github.com>
2022-02-17 21:07:15 +09:00
Pedro Pontes
3bbe839403 chore: cherry-pick b790affce3 and 9c1efd3def from angle (#32904) 2022-02-17 21:06:21 +09:00
Pedro Pontes
0f5967fce2 chore: cherry-pick 0081bb347e67 from chromium (#32919)
* chore: cherry-pick 0081bb347e67 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-02-17 15:00:09 +09:00
Robo
da171befe7 chore: cherry-pick 1c93e2afc8 from v8 (#32796)
Backports https://chromium-review.googlesource.com/c/v8/v8/+/3338698

Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2022-02-17 14:53:48 +09:00
Cheng Zhao
c850e2452c chore: cherry-pick fix for 1282354 from chromium (#32783)
Co-authored-by: Electron Bot <electron@github.com>
2022-02-17 14:53:12 +09:00
Cheng Zhao
f3ca6ff998 chore: cherry-pick fix for 1283198 from chromium (#32781)
* chore: cherry-pick fix for 1283198 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-02-16 17:05:14 +09:00
Sudowoodo Release Bot
58e9dedd76 Bump v15.3.7 2022-02-14 11:23:11 -08:00
Cheng Zhao
51a673e7e0 chore: cherry-pick fix for 1283375 from chromium (#32777)
Co-authored-by: Electron Bot <electron@github.com>
2022-02-14 20:04:39 +09:00
Milan Burda
fed01fb57d fix: will-attach-webview handler modifying params.instanceId does not break <webview> (#32386) (#32855) 2022-02-13 22:33:31 -08:00
Micha Hanselmann
65c9f47e15 chore: cherry-pick c1700c5 from v8 (#32770)
* chore: cherry-pick c1700c5 from v8

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-02-10 11:27:01 -05:00
Cheng Zhao
1b54c4bc44 chore: cherry-pick fix for 1283371 from chromium (#32779)
Co-authored-by: Electron Bot <electron@github.com>
2022-02-10 10:03:37 -06:00
Robo
f903141394 chore: cherry-pick 06504ff3b1 from chromium (#32793)
* chore: cherry-pick 06504ff3b1 from chromium

Backports https://chromium-review.googlesource.com/c/chromium/src/+/3308537

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2022-02-10 22:16:55 +09:00
Robo
6c1f9f8270 chore: cherry-pick 5c41beab6 from chromium (#32798)
* chore: cherry-pick 5c41beab6 from chromium

Backports https://chromium-review.googlesource.com/c/chromium/src/+/3337896

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2022-02-10 19:36:18 +09:00
Robo
7432ea43b7 chore: cherry-pick 91fbf1798 and cff03c22c5 from chromium (#32792)
Backports
https://chromium-review.googlesource.com/c/chromium/src/+/3347570
https://chromium-review.googlesource.com/c/chromium/src/+/3348406

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2022-02-10 17:22:19 +09:00
Robo
0d1b7be451 chore: cherry-pick efdfe711dc5 from chromium (#32791)
Backports
https://chromium-review.googlesource.com/c/chromium/src/+/3242785
https://chromium-review.googlesource.com/c/angle/angle/+/3242963

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2022-02-10 15:13:26 +09:00
Robo
e0a7f869de chore: cherry-pick 349a35b19 from chromium (#32790)
Backports https://chromium-review.googlesource.com/c/chromium/src/+/3226142

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-02-10 09:37:43 +09:00
Jeremy Rose
d9dd6138e2 chore: cherry-pick 9db9911e1242 from chromium (#32741)
* chore: cherry-pick 9db9911e1242 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-02-09 16:49:44 -05:00
trop[bot]
c1651e333b test: disable the test that makes spec runner hang on exit (#32836)
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2022-02-09 12:11:16 -05:00
trop[bot]
c0ea40e71d build: rebuild the dist_zips when the deps get modified (#32819)
* build: rebuild the dist_zips when the deps get modified

The dist.zip generated by the electron_dist_zip action was not getting
updated when changes were being made to the dependencies, like the
source files. It turns out, we were using data_deps for the dependencies
instead of deps. Here is the difference:

data_deps: things needed to ultimately run the thing built by a target
deps: things needed to build the target

So the difference in treatment of both sets of dependencies is actually
intentional.

Signed-off-by: Darshan Sen <raisinten@gmail.com>

* fixup! build: rebuild the dist_zips when the deps get modified

Signed-off-by: Darshan Sen <raisinten@gmail.com>

Co-authored-by: Darshan Sen <raisinten@gmail.com>
2022-02-09 11:13:28 -05:00
Robo
501bb98a10 chore: cherry-pick 5f8ddef5a6 from chromium (#32789)
Backports https://chromium-review.googlesource.com/c/chromium/src/+/3193885

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2022-02-09 13:04:10 +09:00
Robo
9fe9a0ccc1 chore: cherry-pick ce8b70863 from angle (#32795)
Backports https://chromium-review.googlesource.com/c/angle/angle/+/3335173
2022-02-09 09:41:57 +09:00
Robo
f6d2b9dc63 chore: cherry-pick 55f6cb37 from chromium (#32794)
* chore: cherry-pick 55f6cb37 from chromium

Backports https://chromium-review.googlesource.com/c/chromium/src/+/3279207

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-02-09 09:41:24 +09:00
Jeremy Rose
b04be1dff6 chore: cherry-pick 27bc67f761e6 from v8 (#32739)
* chore: cherry-pick 27bc67f761e6 from v8

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-02-09 09:40:26 +09:00
Cheng Zhao
656463c2f4 chore: cherry-pick fix for 1284367 from chromium (#32775) 2022-02-08 11:32:00 -05:00
trop[bot]
a0e9cc6c02 fix: WCO window hover on window controls on Windows (#32717) 2022-02-03 10:06:48 +01:00
trop[bot]
27e2c79dd0 docs: fix missing tag end in clipboard example (#32693)
Co-authored-by: Paul Hollinsky <paulhollinsky@gmail.com>
2022-02-02 10:13:58 -05:00
trop[bot]
d74441f00e docs: fix typo in BrowserWindow description (#32697)
Co-authored-by: Tobias Nießen <tniessen@tnie.de>
2022-02-02 10:09:58 -05:00
trop[bot]
97e52764a8 fix: some frameless windows showing a frame on Windows (#32708)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-02-02 15:38:37 +01:00
trop[bot]
112392c414 fix: expose all serial devices to setDevicePermissionHandler (#32686)
* fix: expose all serial devices to setDevicePermissionHandler

* Trigger Build

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-02-01 19:28:20 -05:00
trop[bot]
42c2eecdef fix: transparent window max/unmax event firing (#32688)
* fix: transparent window max/unmax event firing

* chore: fixup tests

* Update spec-main/api-browser-window-spec.ts

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2022-02-01 20:21:42 +09:00
trop[bot]
98603c645e fix: missing comma in config.py (#32676)
* Fix missing comma

Co-authored-by: Marek Šuppa <mrshu@users.noreply.github.com>
2022-02-01 17:52:59 +09:00
trop[bot]
11391e7351 docs: update context bridge docs about Promises and Errors (#32533) (#32646)
* Update context bridge docs about Promises

From my testing it doesn't remove Promises in nested objects,
also according to the test suite it does not:
80577a4f08/spec-main/api-context-bridge-spec.ts (L693)

* docs: Update docs for errors too

Co-authored-by: Mikael Finstad <finstaden@gmail.com>
2022-01-28 19:59:28 +09:00
Sudowoodo Release Bot
a636ab7c61 Bump v15.3.6 2022-01-27 09:46:32 -08:00
trop[bot]
53e39eb9c0 ci: update ts-compile-doc-change to properly use src cache (#32625)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-01-26 10:30:22 -05:00
trop[bot]
cccd74e6a6 fix: webContents.setZoomFactor crash (#32619)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-01-26 20:05:49 +09:00
trop[bot]
1efa631b56 fix: crash when saving edited PDF files (#32537)
* fix: crash when saving edited PDF files

* chore: update patches after backport

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-01-26 20:03:37 +09:00
trop[bot]
221d2220e1 fix: make window without rounded corners closable (#32610)
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2022-01-26 20:03:12 +09:00
trop[bot]
ae3ee8ad00 test: disable flaky test on WOA (#32562)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-01-25 13:31:02 -05:00
Jeremy Rose
b39a34650f chore: cherry-pick c5571653d932 from chromium (#32353)
* chore: cherry-pick c5571653d932 from chromium

* fix patch

* Update cherry-pick-c5571653d932.patch

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-01-24 13:16:38 -05:00
trop[bot]
8292b3dc0c fix: strip crashpad_handler binary (#32548)
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2022-01-24 20:06:55 +09:00
David Sanders
8653dfc8b3 docs: fix anchors for broken relative links (#32568) 2022-01-24 19:59:27 +09:00
trop[bot]
1ef9a756e5 ci: call autoninja without ninjalog_uploader_wrapper.py (#32573)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-01-24 19:55:03 +09:00
Pedro Pontes
fdfa5d41d4 chore: cherry-pick cc44ae61f37b from angle (#32546)
* chore: cherry-pick cc44ae61f37b from angle

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-01-20 11:08:23 -08:00
trop[bot]
86e10b06dd fix: check for maximized window before unmaximizings (#32494)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2022-01-19 10:39:04 -05:00
Shelley Vohr
d2497a14e0 fix: maximize/unmaximize firing on linux (#32498) 2022-01-19 10:30:47 -05:00
trop[bot]
5963024ac7 docs: fix broken images for symbol server setup (#32524)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2022-01-18 15:24:12 -05:00
trop[bot]
26690b12f2 fix: Corrupted title of alert dialog (#32468)
Co-authored-by: Takao Baba <babatakao@gmail.com>
2022-01-17 16:34:26 +09:00
trop[bot]
1a148a8232 fix: optional postMessage transfer arg (#32458)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-01-14 09:42:37 +09:00
Pedro Pontes
cff70f15aa chore: cherry-pick f0a63e1f361f from chromium (#32012)
* chore: cherry-pick f0a63e1f361f from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-13 18:39:01 +09:00
trop[bot]
a6f094c983 fix: use setAspectRatio for frameless window on mac (#32445)
* fix(window): setAspectRatio for frameless windows

* dummy

* undo dummy

Co-authored-by: Gellert Hegyi <gellert.hegyi@around.co>
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2022-01-13 17:19:12 +09:00
Pedro Pontes
04dcbe4c74 chore: cherry-pick 27eb11a28555 from chromium (#32015)
* chore: cherry-pick 27eb11a28555 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-13 09:36:39 +09:00
Pedro Pontes
28def9ed7d chore: cherry-pick 855df1837e from chromium (#32032)
Co-authored-by: Electron Bot <electron@github.com>
2022-01-12 16:45:06 +09:00
trop[bot]
2089370bbb build: pin colors to v1.4.0 in package.json (#32424)
* pin colors to v1.4.0 in packae.json

Fixes #32416

* fixup! pin colors to v1.4.0 in packae.json

update yarn.lock too

Co-authored-by: Charles Kerr <charles@charleskerr.com>
2022-01-12 16:44:27 +09:00
Pedro Pontes
837dc05204 chore: cherry-pick bdffa0ea5148 from angle (#32184)
* chore: cherry-pick bdffa0ea5148 from angle

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-12 16:42:40 +09:00
Sudowoodo Release Bot
9f08e46018 Bump v15.3.5 2022-01-11 11:18:16 -08:00
trop[bot]
6a70d8a6ca fix: incorrect skipTransformProcessType option parsing in win.setVisibleOnAllWorkspaces() (#32396)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2022-01-11 14:45:25 +09:00
Pedro Pontes
aab276c532 chore: cherry-pick da11d71a0227 from chromium (#32181)
* chore: cherry-pick da11d71a0227 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-11 14:43:57 +09:00
Pedro Pontes
053fea1b44 chore: cherry-pick 05e69c75905f from angle (#32190)
* chore: cherry-pick 05e69c75905f from angle

* chore: update patches

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-11 14:42:40 +09:00
Pedro Pontes
0b0e991a54 chore: cherry-pick 809830f1b3 from webrtc (#32226)
* chore: cherry-pick 809830f1b3 from webrtc

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-01-11 14:40:54 +09:00
Pedro Pontes
ec7408a2d4 chore: cherry-pick 891020ed64d4 from angle (#32223)
* chore: cherry-pick 891020ed64d4 from angle

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-01-10 17:01:35 -05:00
Milan Burda
250b7ed3db docs: left is a valid mode in contents.openDevTools() options (#32372) (#32404) 2022-01-10 16:54:07 -05:00
Pedro Pontes
d136430b35 chore: cherry-pick dbde8795233a from chromium (#32210)
* chore: cherry-pick dbde8795233a from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-10 11:10:32 +01:00
Pedro Pontes
79abfe7ac8 chore: cherry-pick 05ccacee14 from v8. (#32216)
Co-authored-by: Electron Bot <electron@github.com>
2022-01-10 11:07:14 +01:00
trop[bot]
a18a4609ad fix: Allow npm_config_arch override on mac (#32380)
If the npm_config_arch environment variable is set on Mac, then use the
specified architecture rather than overriding it to x64.

Co-authored-by: Tommy MacWilliam <tommy@serenade.ai>
2022-01-10 10:49:30 +01:00
Pedro Pontes
cdf661939d chore: cherry-pick 6bb320d134b1 from chromium (#32009)
* chore: cherry-pick 6bb320d134b1 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-06 09:47:14 -05:00
Pedro Pontes
98cf0e5dff chore: cherry-pick 2b98abd8cb6c from angle (#32187)
* chore: cherry-pick 2b98abd8cb6c from angle

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-01-06 13:34:35 +01:00
trop[bot]
be9dccfcc6 fix: rename patch file to .patch to conform to naming standard which utilizes .gitattributes settings (#32346)
* Rename patch file to .patch to conform to naming standard which utilizes .gitattributes settings

* chore: remove backported patches

* chore: rename patch (don't re-add)

Co-authored-by: stsean <stsean@justin.tv>
Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
2022-01-06 09:19:17 +09:00
Pedro Pontes
e4bb98195f chore: cherry-pick 109fde1088be from chromium (#32011)
* chore: cherry-pick 109fde1088be from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-05 13:50:59 -05:00
trop[bot]
099560c59c fix: crash caused by app.getLocaleCountryCode() (#32332)
CFLocaleGetValue() returned null and crashed the process when
app.getLocaleCountryCode() was run on a CircleCI metal resource class
macOS instance with Xcode 12.5.1. This change fixes that logic and adds
further checks to make the code future-proof.

Here too people are complaining that the returned country code migth be
null: https://stackoverflow.com/questions/15202454/nslocalecountrycode-returns-nil

Signed-off-by: Darshan Sen <darshan.sen@postman.com>

Co-authored-by: Darshan Sen <darshan.sen@postman.com>
2022-01-05 18:35:00 +09:00
trop[bot]
efd276d31f fix: #32141 register wrong command for setAsDefaultProtocolClient for windows (#32330)
Co-authored-by: Shubham-Kumar-2000 <shukhu10@gmail.com>
2022-01-04 16:09:13 +09:00
Pedro Pontes
e2cb43768d chore: cherry-pick 2b978fb482 from chromium (#32232)
Co-authored-by: Electron Bot <electron@github.com>
2022-01-04 10:09:05 +09:00
Cheng Zhao
e654f5ecb3 fix: window.open not overriding parent's webPreferences (#32109) 2022-01-04 09:18:38 +09:00
Pedro Pontes
f74940b536 chore: cherry-pick f781748dcb3c from chromium (#32257)
* chore: cherry-pick f781748dcb3c from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-01-03 12:01:51 -05:00
Pedro Pontes
fe8508a287 chore: cherry-pick 04a58fedd5 from v8 (#32235) 2022-01-03 09:43:48 -05:00
trop[bot]
d5dd50f87e fix: check for single bluetooth listener (#32245)
Co-authored-by: VerteDinde <khammond@slack-corp.com>
2022-01-03 10:29:19 +01:00
trop[bot]
952994c591 fix: older systems crash when playing media files (#32213)
* fix: win7 crash when playing media

* reset

* chore: update patches

Co-authored-by: Micha Hanselmann <micha.hanselmann@gmail.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-12-17 13:30:03 -08:00
Sudowoodo Release Bot
536b5c4e3b Bump v15.3.4 2021-12-16 09:06:05 -08:00
trop[bot]
210bae878f fix: ensure bluetooth devices are not returned by default (#32197)
Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
2021-12-15 19:51:28 -08:00
trop[bot]
9b78227260 docs: Fix environment variable name (#32161)
The names of environment variables are case-sensitive on Linux and Mac.

Co-authored-by: stephen9357 <stephen9357@gmail.com>
2021-12-14 19:42:16 +09:00
Keeley Hammond
0a50571460 build: add CI path-filtering for docs-only changes (#32056)
* build: add CI path-filtering for docs-only changes (#31741)

build: (wip) initial dynamic config research

* build: (wip) test path filtering option

* build: (wip) remove doc-only script, use path filtering to check changes

* build: (wip) add docker image with Electron dependencies

* build: (wip) clean up config

* build (wip): readd parameters, executors and env*s

* build: re-add steps and commands

* build: change doc-only to ts-compile-doc-only

* build: re-add workflows and jobs

* build: split configs to setup & build

* build: move lint to "always run" config

* build: clean up, remove old reference config

* build: bump to path-filtering 0.1.0

* build: remove ts-compile step from build-linux

* build: remove nightly-linux-release-test, linux-checks-nightly

* build: don't run build on publish

* build: set base-revision to main (runs branch vs commit)

* build: update config from chromium roll

* build: don't use python3 on sync-step

reverts ea6087e343. This commit was added in
the Nov. 23, 2021 Chromium roll in main, and doesn't apply to 15-x-y

* build: account for path-filtering workflow in release-build script (#32063)

* build: account for path-filtering workflow in release-build script

* build: update syntax for workflow id

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2021-12-06 11:36:18 +09:00
trop[bot]
248a6012d5 fix: gtk_native_dialog_run() calls show() internally (#32081)
In the synchronous code path, gtk_native_dialog_run() will call
gtk_native_dialog_show(). Previously this was causing an assertion to be
hit at run time.

Co-authored-by: Tristan Partin <tristan@partin.io>
2021-12-06 11:29:54 +09:00
Sudowoodo Release Bot
ed52801e09 Bump v15.3.3 2021-11-30 12:57:10 -08:00
trop[bot]
6226507536 fix: aspect ratio when max width/height is set (#31956)
* fix: fix aspect ratio when max width/height is set

Add the native frame border size to the minimum and maximum size if
the view reports its size as the client size. It allows to enlarge
window to proper values when aspect ratio and max width/height are
set. It also fixes DCHECK which was triggered when user tried to
enlarge window above dimensions set during creation of the
BrowserWindow.

* chore: update patches

Co-authored-by: Cezary Kulakowski <cezary@openfin.co>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-11-24 15:42:20 -05:00
Pedro Pontes
098a118dce chore: cherry-pick 56de3b2004, bbca3704f9 and f2b0985ac3 from chromium (#31919)
Co-authored-by: Electron Bot <electron@github.com>
2021-11-24 10:49:13 -05:00
Pedro Pontes
56e08fe5f1 chore: cherry-pick 1fcfb942bd from chromium (#31927) 2021-11-22 16:22:03 -05:00
trop[bot]
8dba1cf5fa fix: ninja build failed on some system (#31942)
Co-authored-by: Black-Hole1 <158blackhole@gmail.com>
2021-11-22 16:16:21 -05:00
Pedro Pontes
1fc7634f69 chore: cherry-pick 1a8af2da50e4 from chromium (#31902)
* chore: cherry-pick 1a8af2da50e4 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2021-11-22 08:29:39 -08:00
Pedro Pontes
52e443ec52 chore: cherry-pick 5d2b5e7c006c from v8 (#31910)
* chore: cherry-pick 5d2b5e7c006c from v8

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-11-22 01:44:38 -08:00
Pedro Pontes
16be926e0a chore: cherry-pick a5f54612590d from chromium (#31899) 2021-11-22 01:36:15 -08:00
trop[bot]
5c2d65c749 fix: BrowserView setBackgroundColor needs two calls (#31946)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-11-22 16:41:33 +09:00
trop[bot]
7bf1d3c110 fix: lint Objective-C header files (#31938)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2021-11-22 16:35:19 +09:00
trop[bot]
92969d6032 docs: fix typo in distribution docs (#31879)
Co-authored-by: Sergey Zolotarev <sryze@protonmail.com>
2021-11-18 20:32:17 +09:00
trop[bot]
b48d0f2cbe fix: setContentProtection affects BrowserWindow frame (#31830)
Co-authored-by: Micha Hanselmann <micha.hanselmann@gmail.com>
2021-11-17 19:36:25 +09:00
Shelley Vohr
ff8594b11b chore: fix malformed mojom::CreateNewWindowParams patch (#31843)
* chore: fix malformed mojom::CreateNewWindowParams patch

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-11-16 20:39:31 +01:00
trop[bot]
a41f04028e chore: use std::forward() in ConvertToV8() (#31856)
The variable `input` is accepted by a universal reference, so it doesn't
make sense to cast a potential lvalue reference into an rvalue
reference. In case `input` is an lvalue reference, we should rather
forward the value as is to `ToV8()`.

Signed-off-by: Darshan Sen <darshan.sen@postman.com>

Co-authored-by: Darshan Sen <darshan.sen@postman.com>
2021-11-16 10:03:36 -05:00
Sudowoodo Release Bot
1f320e0688 Bump v15.3.2 2021-11-15 15:45:07 -08:00
Shelley Vohr
1f23e83ef9 fix: BrowserView setBackgroundColor() (#31844) 2021-11-15 10:32:56 -08:00
trop[bot]
11ea44925b fix: make BrowserView aware of owning window (#31841)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-11-15 10:32:30 -08:00
trop[bot]
21a6c6dc76 fix: in GTK open dialog, do not preview huge files (#31820)
* fix: in GTK open dialog, do not preview huge files

Previewing images whose files are larger than a GB can crash Electron.

* refactor: tweak CanPreview()

Co-authored-by: Charles Kerr <charles@charleskerr.com>
2021-11-15 10:48:27 -06:00
trop[bot]
057c24feec fix: media shouldn't open permissions dialog (#31836)
* fix: media shouldn't open permissions dialog

Playing media shouldn't open Accessibility permissions dialog on macOS.
However, we still need to watch for media events, just not globally and
`media_keys_listener_` is an API over global capture of the media keys.

The fix is to let chromium call `UpdateWhichKeysAreListenedFor` which
will call `UpdateSystemMediaControlsEnabledControls` and watch for
events on `system_media_controls_` without triggering permissions popup.

* chore: update patches

* chore: update patches

Co-authored-by: Fedor Indutny <fedor@indutny.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-11-15 08:20:38 -08:00
trop[bot]
69014e7aad fix: correct default text for button labels in gtk dialogs (#31823) 2021-11-15 16:19:21 +01:00
trop[bot]
ec293f4de0 fix: crash on browserView.webContents.destroy() (#31826)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-11-15 16:18:54 +01:00
trop[bot]
15038974ad chore: cleanup obsolete lib/common/remote/ipc-messages.ts (#31766)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2021-11-09 11:37:06 -05:00
trop[bot]
d2287a1935 test: fix crash in electron::NativeWindowMac::Close() (#31760)
* test: fix crash in electron::NativeWindowMac::Close()

* remove extra close

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2021-11-09 11:25:15 -05:00
Sudowoodo Release Bot
e298bf46e4 Bump v15.3.1 2021-11-08 09:26:37 -08:00
trop[bot]
5426d2c920 fix: clipboard.writeBuffer raw format access (#31720)
* fix: clipboard.writeBuffer raw format access (#31116)

* fix: clipboard.writeBuffer raw format access

* test: clipboard.writeBuffer raw format access

* test: clipboard win32 test skip

* fixup spec

* cleanup patch

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

* fixup .patches file

Co-authored-by: henrit <henrit@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2021-11-08 11:36:14 -05:00
Milan Burda
3e0a2edec4 fix: <webview> background transparency (#31701)
Co-authored-by: Milan Burda <miburda@microsoft.com>
2021-11-05 14:43:08 -07:00
trop[bot]
f74d89ba80 fix: crash dump location on Linux (#31712)
* fix: crash dump location on Linux

* fix: ignore client_id for Zygote process

* chore: update comment

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
2021-11-04 17:18:50 -04:00
trop[bot]
4e14dca687 test: deflake <webview> tag loads devtools extensions on WOA (#31716)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2021-11-04 16:36:11 -04:00
Pedro Pontes
1aaf1e7241 chore: cherry-pick 91dd4f79ab5b from chromium (#31680)
* chore: cherry-pick 91dd4f79ab5b from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-11-04 14:28:26 -04:00
Keeley Hammond
1e7c8a3c63 docs: update test automation doc (#31506) (#31699)
* Update WebdriverIO documentation

* Update docs/tutorial/using-selenium-and-webdriver.md

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>

* Update docs/tutorial/using-selenium-and-webdriver.md

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>

* docs: update automated testing docs

* lint

* update

* Update docs/tutorial/automated-testing.md

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* fixes

Co-authored-by: Christian Bromann <github@christian-bromann.com>
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>

Co-authored-by: Christian Bromann <github@christian-bromann.com>
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2021-11-04 09:52:23 -07:00
trop[bot]
8496a12321 fix: incorrect Content-Disposition serialization (#31693)
* fix: incorrect Content-Disposition serialization

* test: fixup test

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-11-04 10:00:12 +09:00
trop[bot]
98bab0ca28 fix: do not run dialog callback inside transaction commit (#31658)
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2021-11-02 13:22:23 +01:00
trop[bot]
a630db8c86 test: fix test-datetime-change-notify after daylight change (#31655)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2021-11-01 20:57:41 -04:00
trop[bot]
7e19dbad6f fix: use disable-hid-blocklist to allow FIDO devices (#31649)
* fix: use disable-hid-blocklist to allow FIDO

* Trigger Build

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2021-11-01 17:09:53 -04:00
Milan Burda
2b8fc8a139 chore: update chore_add_context_to_context_aware_module_prevention.patch (#31579) (#31628)
Co-authored-by: Milan Burda <miburda@microsoft.com>
2021-11-01 15:39:42 -04:00
trop[bot]
30b9d15af0 fix: crash on close window when webContents destroyed (#31644)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-11-01 15:30:46 -04:00
trop[bot]
bcf04f5878 fix: clipboard.read() to recognize custom types (#31651)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2021-11-01 13:45:48 -04:00
Shelley Vohr
9fba8b35cb fix: silent print settings (#31616) 2021-11-01 10:03:27 -04:00
trop[bot]
ad3563687f docs: link to Apple developer docs for app.ready event (#31599)
Changes some links around. There was no link for `NSUserNotification`, and
`UNNotificationResponse` incorrectly linked to our own `NotificationResponse`
API structure doc.

Co-authored-by: Erick Zhao <erick@hotmail.ca>
2021-10-28 11:17:10 +09:00
trop[bot]
4e2c19944f fix: clipboard.read() crash (#31591)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-10-26 11:29:58 -04:00
trop[bot]
95814288cf build: retry hasher function if it fails first time (#31582)
* build: retry hasher function if it fails first time

* Update script/release/get-url-hash.js

Co-authored-by: Cheng Zhao <zcbenz@gmail.com>

Co-authored-by: Samuel Attard <sattard@slack-corp.com>
Co-authored-by: Samuel Attard <sam@electronjs.org>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2021-10-26 17:40:41 +09:00
trop[bot]
b711b8f98d docs: win.getParentWindow() returns BrowserWindow | null (#31576)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2021-10-26 17:38:12 +09:00
Pedro Pontes
a1744e5de0 chore: cherry-pick 36028012d897 from chromium (#31539)
Co-authored-by: Electron Bot <electron@github.com>
2021-10-25 13:27:14 -04:00
trop[bot]
e9446f0dc4 fix: MediaMetadata not working properly (#31534)
* fix: MediaMetadata not working properly

* chore: update patches

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-10-25 16:55:16 +02:00
Pedro Pontes
1cda1d0e86 chore: cherry-pick 0894af410c4e from chromium (#31543)
* chore: cherry-pick 0894af410c4e from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-10-25 13:03:10 +02:00
Pedro Pontes
c2023dd9f5 chore: cherry-pick 8af66de55aad from chromium (#31523)
* chore: cherry-pick 8af66de55aad from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2021-10-25 09:47:11 +09:00
Pedro Pontes
c98059abd9 chore: cherry-pick c69dddfe1cde from chromium (#31519)
* chore: cherry-pick c69dddfe1cde from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2021-10-22 21:19:03 +09:00
Pedro Pontes
df726b619d chore: cherry-pick 6de4e210688e from v8 (#31501)
* chore: cherry-pick 6de4e210688e from v8

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2021-10-22 21:14:15 +09:00
trop[bot]
c2b1db192d fix: event with invalid timestamp in trace log (#31422)
* fix: event with invalid timestamp in trace log

When node is started within Electron's environment it doesn't
initialize v8 and time of v8's start is never set. As a result
we log v8's start time as 0 and it breaks timestamps in the
trace log. With this change we log v8's start time only when
it was initialized by node.

* fixup patches for 15-x-y

Co-authored-by: Cezary Kulakowski <cezary@openfin.co>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2021-10-22 21:13:02 +09:00
Pedro Pontes
235c32ee55 chore: cherry-pick 29be6884cb8a from v8 (#31516) 2021-10-21 16:08:48 -04:00
Pedro Pontes
7e66d6a952 chore: cherry-pick 2e7c9b33453b from chromium (#31497)
* chore: cherry-pick 2e7c9b33453b from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-10-21 15:15:43 -04:00
Erick Zhao
0db4d5add5 docs: add window customization guide (#31054) (#31507)
* docs: add window customization guide

* fixes

* Update docs/api/browser-window.md

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

* Update docs/api/browser-window.md

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

* Update docs/fiddles/windows/manage-windows/frameless-window/index.html

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

* fix code fence

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

Co-authored-by: Mark Lee <malept@users.noreply.github.com>
2021-10-21 14:07:57 -04:00
trop[bot]
9380803004 feat: warn when ipcRenderer.sendSync() called with no listeners for channel (#31434)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2021-10-21 09:09:01 +09:00
trop[bot]
2a12d5fa7f fix: ensure TracingAgent in place for SWs (#31476)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-10-21 09:07:41 +09:00
trop[bot]
93e8de87a5 fix: remove 'NOTREACHED()' from 'GetWindowResizeEdge' (#31480)
Co-authored-by: mlaurencin <mlaurencin@electronjs.org>
2021-10-21 09:05:45 +09:00
Sudowoodo Release Bot
b6c9110923 Bump v15.3.0 2021-10-20 07:51:47 -07:00
Keeley Hammond
5e815df20f fix: don't use private enterprise APIs in MAS build (#31483) 2021-10-19 23:14:22 -07:00
trop[bot]
e676b3862c fix: link to image windows progress bar image was linked with square brackets [] insted of parenthesis () and to github asset storage instead of local image directory. (#31472)
Co-authored-by: Daniel Ramp <12480131+DanielRamp@users.noreply.github.com>
2021-10-19 20:40:12 +09:00
trop[bot]
cd8f678a8d Avoid Undefined Variable In printToPdf Example (#31465)
Co-authored-by: universalstrapping <90921972+universalstrapping@users.noreply.github.com>
2021-10-19 17:41:24 +09:00
trop[bot]
79554ba989 fix: add isDestroyed check (#31468)
* Added isDestroyed check

fix: https://github.com/electron/electron/issues/31196

* fix: unregister frame name

Unregister the frame name so that we do not accidentally unregister the wrong window later on in case there is a timing issue with the events

* fix; check if webContents is destroyed

* fix: check if window/webContents is destroyed

Co-authored-by: Cheng Zhao <github@zcbenz.com>

Co-authored-by: t57ser <seve@live.at>
Co-authored-by: Cheng Zhao <github@zcbenz.com>
2021-10-19 17:39:49 +09:00
Cheng Zhao
ad67a27dcf fix: generate valid config.gypi (#31442) 2021-10-19 09:39:47 +09:00
trop[bot]
c9476eb821 fix: also pass securityOrigin to media permissions request handler (#31417)
Co-authored-by: Maxime Serrano <mserrano@alumni.cmu.edu>
2021-10-15 13:31:48 +09:00
John Kleinschmidt
2c6321c9af chore: refactor persisting permission granted to serial ports (#31418)
(cherry picked from commit 515785aabe)
2021-10-15 09:07:24 +09:00
trop[bot]
715de396d4 fix: mac window crash native theme update (#31429)
Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>
2021-10-15 09:06:05 +09:00
Sudowoodo Release Bot
98d6b9bf15 Bump v15.2.0 2021-10-14 12:54:57 -07:00
trop[bot]
a05ed73f43 fix: reset render_frame_disposed_ after render frame host change (#31426)
* fix: reset render_frame_disposed_ after hang

* fix: handle exception in webContents.send

Co-authored-by: VerteDinde <keeleymhammond@gmail.com>
Co-authored-by: VerteDinde <khammond@slack-corp.com>
2021-10-14 12:52:46 -07:00
trop[bot]
f7fdd34c45 docs: update Versioning doc (#31388)
* fix information

* move historical section to bottom

* Update docs/tutorial/electron-versioning.md

Co-authored-by: Charles Kerr <charles@charleskerr.com>

* chore: fix small typo

Co-authored-by: Erick Zhao <erick@hotmail.ca>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
2021-10-13 11:24:56 +09:00
trop[bot]
55e6ce81e0 fix: black window on screen capture when content protection is enabled (#31385)
Co-authored-by: Micha Hanselmann <mhanselmann@microsoft.com>
2021-10-12 09:09:10 +09:00
trop[bot]
b5c81db591 feat: add commandLine.removeSwitch (#31326)
* feat: add commandLine.removeSwitch

In some cases apps may want to remove Chromium command line switches to avoid certain Chromium behaviors being used, E.g. remote-debugging-port or gpu-launcher

* fix: add missing removeSwitch to app.ts

Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2021-10-12 09:05:52 +09:00
electron-roller[bot]
cffbeeaefa chore: bump chromium to 94.0.4606.81 (15-x-y) (#31351) 2021-10-11 13:28:17 +02:00
trop[bot]
c81380848f fix: correctly notify WebViewGuestDelegate when webview is detached (#31376)
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2021-10-11 14:35:33 +09:00
Milan Burda
45a1d81315 docs: nativeWindowOpen default was changed in Electron 15 (#31345) (#31367)
Co-authored-by: Milan Burda <miburda@microsoft.com>
2021-10-10 15:50:48 -07:00
Sudowoodo Release Bot
ded013e4a7 Bump v15.1.2 2021-10-08 09:10:28 -07:00
Samuel Attard
2cabee9128 chore: cherry-pick 39090918efac from chromium (#31297)
* chore: cherry-pick 39090918efac from chromium

* chore: cherry-pick ec42dfd3545f from chromium

* chore: reconcile FPS patch differences

Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
Co-authored-by: VerteDinde <keeleymhammond@gmail.com>
2021-10-08 09:07:58 -07:00
trop[bot]
0c9571c89f docs: add missing 'context-menu' event to webview-tag.md (#31309)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2021-10-08 08:57:45 -07:00
electron-roller[bot]
c93204ec0d chore: bump chromium to 94.0.4606.71 (15-x-y) (#31234)
* chore: bump chromium in DEPS to 94.0.4606.71

* chore: update patches

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-10-07 22:02:54 -04:00
trop[bot]
3c47d9e0d7 fix: crash on missing render frame (#31334)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-10-07 20:15:48 +02:00
Robo
9c54bf7973 refactor: only access memory coordinator interface from browser process (#31295) (#31303)
Refs https://chromium-review.googlesource.com/c/chromium/src/+/3174305
2021-10-06 15:44:14 -07:00
trop[bot]
d6f44a75d2 test: add missing context-menu event spec for <webview> (#31306)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2021-10-06 15:16:28 -05:00
trop[bot]
259f27070c chore: add logging for print_backend failures (#31286)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-10-06 16:55:17 +02:00
trop[bot]
6d1fa337c2 fix: return HTNOWHERE in resize hit test to allow draggable regions to kick in when required (#31299)
Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
2021-10-06 09:22:21 +09:00
273 changed files with 22829 additions and 3821 deletions

2420
.circleci/build_config.yml Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2
.github/CODEOWNERS vendored
View File

@@ -4,7 +4,7 @@
# https://git-scm.com/docs/gitignore
# Upgrades WG
/patches/ @electron/wg-upgrades
/patches/ @electron/wg-upgrades @electron/wg-security
DEPS @electron/wg-upgrades
# Releases WG

View File

@@ -187,6 +187,12 @@ action("electron_js2c") {
rebase_path(sources, root_build_dir)
}
action("generate_config_gypi") {
outputs = [ "$root_gen_dir/config.gypi" ]
script = "script/generate-config-gypi.py"
args = rebase_path(outputs) + [ target_cpu ]
}
target_gen_default_app_js = "$target_gen_dir/js/default_app"
typescript_build("default_app_js") {
@@ -1361,11 +1367,13 @@ dist_zip("electron_dist_zip") {
if (is_linux) {
data_deps += [ "//sandbox/linux:chrome_sandbox" ]
}
deps = data_deps
outputs = [ "$root_build_dir/dist.zip" ]
}
dist_zip("electron_ffmpeg_zip") {
data_deps = [ "//third_party/ffmpeg" ]
deps = data_deps
outputs = [ "$root_build_dir/ffmpeg.zip" ]
}
@@ -1383,6 +1391,7 @@ group("electron_chromedriver") {
dist_zip("electron_chromedriver_zip") {
testonly = true
data_deps = electron_chromedriver_deps
deps = data_deps
outputs = [ "$root_build_dir/chromedriver.zip" ]
}
@@ -1401,6 +1410,7 @@ group("electron_mksnapshot") {
dist_zip("electron_mksnapshot_zip") {
data_deps = mksnapshot_deps
deps = data_deps
outputs = [ "$root_build_dir/mksnapshot.zip" ]
}
@@ -1411,6 +1421,7 @@ copy("hunspell_dictionaries") {
dist_zip("hunspell_dictionaries_zip") {
data_deps = [ ":hunspell_dictionaries" ]
deps = data_deps
flatten = true
outputs = [ "$root_build_dir/hunspell_dictionaries.zip" ]
@@ -1424,6 +1435,7 @@ copy("libcxx_headers") {
dist_zip("libcxx_headers_zip") {
data_deps = [ ":libcxx_headers" ]
deps = data_deps
flatten = true
flatten_relative_to = rebase_path(
"$target_gen_dir/electron_libcxx_include/buildtools/third_party/libc++/trunk",
@@ -1439,6 +1451,7 @@ copy("libcxxabi_headers") {
dist_zip("libcxxabi_headers_zip") {
data_deps = [ ":libcxxabi_headers" ]
deps = data_deps
flatten = true
flatten_relative_to = rebase_path(
"$target_gen_dir/electron_libcxxabi_include/buildtools/third_party/libc++abi/trunk",

2
DEPS
View File

@@ -15,7 +15,7 @@ gclient_gn_args = [
vars = {
'chromium_version':
'94.0.4606.61',
'94.0.4606.81',
'node_version':
'v16.5.0',
'nan_version':

View File

@@ -1 +1 @@
15.1.1
15.5.1

View File

@@ -66,6 +66,31 @@ build_script:
- mkdir src
- update_depot_tools.bat
- ps: Move-Item $env:APPVEYOR_BUILD_FOLDER -Destination src\electron
- ps: >-
if (Test-Path 'env:RAW_GOMA_AUTH') {
$env:GOMA_OAUTH2_CONFIG_FILE = "$pwd\.goma_oauth2_config"
$env:RAW_GOMA_AUTH | Set-Content $env:GOMA_OAUTH2_CONFIG_FILE
}
- git clone https://github.com/electron/build-tools.git
- cd build-tools
- npm install
- mkdir third_party
- ps: >-
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
- ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)"
- ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)"
- cd ..
- ps: .\src\electron\script\start-goma.ps1 -gomaDir $env:LOCAL_GOMA_DIR
- ps: >-
if (Test-Path 'env:RAW_GOMA_AUTH') {
$goma_login = python $env:LOCAL_GOMA_DIR\goma_auth.py info
if ($goma_login -eq 'Login as Fermi Planck') {
Write-warning "Goma authentication is correct";
} else {
Write-warning "WARNING!!!!!! Goma authentication is incorrect; please update Goma auth token.";
$host.SetShouldExit(1)
}
}
- ps: $env:CHROMIUM_BUILDTOOLS_PATH="$pwd\src\buildtools"
- ps: >-
if ($env:GN_CONFIG -ne 'release') {
@@ -129,21 +154,6 @@ build_script:
Write-warning "Failed to add third_party\angle\.git; continuing anyway"
}
}
- ps: >-
if (Test-Path 'env:RAW_GOMA_AUTH') {
$env:GOMA_OAUTH2_CONFIG_FILE = "$pwd\.goma_oauth2_config"
$env:RAW_GOMA_AUTH | Set-Content $env:GOMA_OAUTH2_CONFIG_FILE
}
- git clone https://github.com/electron/build-tools.git
- cd build-tools
- npm install
- mkdir third_party
- ps: >-
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
- ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)"
- ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)"
- cd ..
- ps: .\src\electron\script\start-goma.ps1 -gomaDir $env:LOCAL_GOMA_DIR
- cd src
- set BUILD_CONFIG_PATH=//electron/build/args/%GN_CONFIG%.gn
- gn gen out/Default "--args=import(\"%BUILD_CONFIG_PATH%\") import(\"%GN_GOMA_FILE%\") %GN_EXTRA_ARGS% "

View File

@@ -1,9 +1,12 @@
from __future__ import with_statement
from __future__ import unicode_literals
import contextlib
import sys
import os
import optparse
import json
import re
import subprocess
sys.path.append("%s/../../build" % os.path.dirname(os.path.realpath(__file__)))
@@ -33,36 +36,56 @@ def calculate_hash(root):
return CalculateHash('.', None)
def windows_installed_software():
import win32com.client
strComputer = "."
objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator")
objSWbemServices = objWMIService.ConnectServer(strComputer, "root\cimv2")
colItems = objSWbemServices.ExecQuery("Select * from Win32_Product")
items = []
powershell_command = [
"Get-CimInstance",
"-Namespace",
"root\cimv2",
"-Class",
"Win32_product",
"|",
"Select",
"vendor,",
"description,",
"@{l='install_location';e='InstallLocation'},",
"@{l='install_date';e='InstallDate'},",
"@{l='install_date_2';e='InstallDate2'},",
"caption,",
"version,",
"name,",
"@{l='sku_number';e='SKUNumber'}",
"|",
"ConvertTo-Json",
]
for objItem in colItems:
item = {}
if objItem.Caption:
item['caption'] = objItem.Caption
if objItem.Caption:
item['description'] = objItem.Description
if objItem.InstallDate:
item['install_date'] = objItem.InstallDate
if objItem.InstallDate2:
item['install_date_2'] = objItem.InstallDate2
if objItem.InstallLocation:
item['install_location'] = objItem.InstallLocation
if objItem.Name:
item['name'] = objItem.Name
if objItem.SKUNumber:
item['sku_number'] = objItem.SKUNumber
if objItem.Vendor:
item['vendor'] = objItem.Vendor
if objItem.Version:
item['version'] = objItem.Version
items.append(item)
proc = subprocess.Popen(
["powershell.exe", "-Command", "-"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
)
return items
stdout, _ = proc.communicate(" ".join(powershell_command).encode("utf-8"))
if proc.returncode != 0:
raise RuntimeError("Failed to get list of installed software")
# On AppVeyor there's other output related to PSReadline,
# so grab only the JSON output and ignore everything else
json_match = re.match(
r".*(\[.*{.*}.*\]).*", stdout.decode("utf-8"), re.DOTALL
)
if not json_match:
raise RuntimeError(
"Couldn't find JSON output for list of installed software"
)
# Filter out missing keys
return list(
map(
lambda info: {k: info[k] for k in info if info[k]},
json.loads(json_match.group(1)),
)
)
def windows_profile():
@@ -89,7 +112,7 @@ def windows_profile():
def main(options):
if sys.platform == 'win32':
with open(options.output_json, 'wb') as f:
with open(options.output_json, 'w') as f:
json.dump(windows_profile(), f)
else:
raise OSError("Unsupported OS")

View File

@@ -59,10 +59,9 @@ an issue:
* [Testing and Debugging](tutorial/application-debugging.md)
* [Debugging the Main Process](tutorial/debugging-main-process.md)
* [Debugging with Visual Studio Code](tutorial/debugging-vscode.md)
* [Using Selenium and WebDriver](tutorial/using-selenium-and-webdriver.md)
* [Testing on Headless CI Systems (Travis, Jenkins)](tutorial/testing-on-headless-ci.md)
* [DevTools Extension](tutorial/devtools-extension.md)
* [Automated Testing with a Custom Driver](tutorial/automated-testing-with-a-custom-driver.md)
* [Automated Testing](tutorial/automated-testing.md)
* [REPL](tutorial/repl.md)
* [Distribution](tutorial/application-distribution.md)
* [Supported Platforms](tutorial/support.md#supported-platforms)

View File

@@ -36,10 +36,10 @@ Returns:
* `launchInfo` Record<string, any> | [NotificationResponse](structures/notification-response.md) _macOS_
Emitted once, when Electron has finished initializing. On macOS, `launchInfo`
holds the `userInfo` of the `NSUserNotification` or information from
[`UNNotificationResponse`](structures/notification-response.md) that was used to open the
application, if it was launched from Notification Center. You can also call
`app.isReady()` to check if this event has already fired and `app.whenReady()`
holds the `userInfo` of the [`NSUserNotification`](https://developer.apple.com/documentation/foundation/nsusernotification)
or information from [`UNNotificationResponse`](https://developer.apple.com/documentation/usernotifications/unnotificationresponse)
that was used to open the application, if it was launched from Notification Center.
You can also call `app.isReady()` to check if this event has already fired and `app.whenReady()`
to get a Promise that is fulfilled when Electron is initialized.
### Event: 'window-all-closed'

View File

@@ -17,10 +17,11 @@ win.loadURL('https://github.com')
win.loadFile('index.html')
```
## Frameless window
## Window customization
To create a window without chrome, or a transparent window in arbitrary shape,
you can use the [Frameless Window](frameless-window.md) API.
The `BrowserWindow` class exposes various ways to modify the look and behavior of
your app's windows. For more details, see the [Window Customization](../tutorial/window-customization.md)
tutorial.
## Showing the window gracefully
@@ -184,7 +185,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
`true`.
* `paintWhenInitiallyHidden` Boolean (optional) - Whether the renderer should be active when `show` is `false` and it has just been created. In order for `document.visibilityState` to work correctly on first load with `show: false` you should set this to `false`. Setting this to `false` will cause the `ready-to-show` event to not fire. Default is `true`.
* `frame` Boolean (optional) - Specify `false` to create a
[Frameless Window](frameless-window.md). Default is `true`.
[frameless window](../tutorial/window-customization.md#create-frameless-windows). Default is `true`.
* `parent` BrowserWindow (optional) - Specify parent window. Default is `null`.
* `modal` Boolean (optional) - Whether this is a modal window. This only works when the
window is a child window. Default is `false`.
@@ -206,7 +207,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
transparent) and 1.0 (fully opaque). This is only implemented on Windows and macOS.
* `darkTheme` Boolean (optional) - Forces using dark theme for the window, only works on
some GTK+3 desktop environments. Default is `false`.
* `transparent` Boolean (optional) - Makes the window [transparent](frameless-window.md#transparent-window).
* `transparent` Boolean (optional) - Makes the window [transparent](../tutorial/window-customization.md#create-transparent-windows).
Default is `false`. On Windows, does not work unless the window is frameless.
* `type` String (optional) - The type of window, default is normal window. See more about
this below.
@@ -393,6 +394,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
* `titleBarOverlay` Object | Boolean (optional) - When using a frameless window in conjuction with `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so that the standard window controls ("traffic lights" on macOS) are visible, this property enables the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. Specifying `true` will result in an overlay with default system colors. Default is `false`.
* `color` String (optional) _Windows_ - The CSS color of the Window Controls Overlay when enabled. Default is the system color.
* `symbolColor` String (optional) _Windows_ - The CSS color of the symbols on the Window Controls Overlay when enabled. Default is the system color.
* `height` Integer (optional) _macOS_ _Windows_ - The height of the title bar and Window Controls Overlay in pixels. Default is system height.
When setting minimum or maximum window size with `minWidth`/`maxWidth`/
`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from
@@ -998,7 +1000,7 @@ APIs like `win.setSize`.
is `true`). Default is `#FFF` (white).
Sets the background color of the window. See [Setting
`backgroundColor`](#setting-backgroundcolor).
`backgroundColor`](#setting-the-backgroundcolor-property).
#### `win.previewFile(path[, displayName])` _macOS_
@@ -1043,7 +1045,7 @@ Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window as `
#### `win.getBackgroundColor()`
Returns `String` - Gets the background color of the window. See [Setting
`backgroundColor`](#setting-backgroundcolor).
`backgroundColor`](#setting-the-backgroundcolor-property).
#### `win.setContentBounds(bounds[, animate])`
@@ -1696,7 +1698,7 @@ current window into a top-level window.
#### `win.getParentWindow()`
Returns `BrowserWindow` - The parent window.
Returns `BrowserWindow | null` - The parent window or `null` if there is no parent.
#### `win.getChildWindows()`

View File

@@ -76,7 +76,7 @@ Writes `markup` to the clipboard.
```js
const { clipboard } = require('electron')
clipboard.writeHTML('<b>Hi</b')
clipboard.writeHTML('<b>Hi</b>')
```
### `clipboard.readImage([type])`
@@ -197,7 +197,7 @@ Returns `Boolean` - Whether the clipboard supports the specified `format`.
```js
const { clipboard } = require('electron')
const hasFormat = clipboard.has('<p>selection</p>')
const hasFormat = clipboard.has('public/utf8-plain-text')
console.log(hasFormat)
// 'true' or 'false'
```

View File

@@ -53,3 +53,12 @@ Returns `Boolean` - Whether the command-line switch is present.
Returns `String` - The command-line switch value.
**Note:** When the switch is not present or has no value, it returns empty string.
#### `commandLine.removeSwitch(switch)`
* `switch` String - A command-line switch
Removes the specified switch from Chromium's command line.
**Note:** This will not affect `process.argv`. The intended usage of this function is to
control Chromium's behavior.

View File

@@ -102,8 +102,8 @@ has been included below for completeness:
| `Boolean` | Simple | ✅ | ✅ | N/A |
| `Object` | Complex | ✅ | ✅ | Keys must be supported using only "Simple" types in this table. Values must be supported in this table. Prototype modifications are dropped. Sending custom classes will copy values but not the prototype. |
| `Array` | Complex | ✅ | ✅ | Same limitations as the `Object` type |
| `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context |
| `Promise` | Complex | ✅ | ✅ | Promises are only proxied if they are the return value or exact parameter. Promises nested in arrays or objects will be dropped. |
| `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context, and any custom properties on the Error object [will be lost](https://github.com/electron/electron/issues/25596) |
| `Promise` | Complex | ✅ | ✅ | N/A
| `Function` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending classes or constructors will not work. |
| [Cloneable Types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) | Simple | ✅ | ✅ | See the linked document on cloneable types |
| `Element` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending custom elements will not work. |

View File

@@ -122,7 +122,7 @@ Prints Chromium's internal logging to the console.
Setting this variable is the same as passing `--enable-logging`
on the command line. For more info, see `--enable-logging` in [command-line
switches](./command-line-switches.md#enable-loggingfile).
switches](./command-line-switches.md#--enable-loggingfile).
### `ELECTRON_LOG_FILE`
@@ -130,7 +130,7 @@ Sets the file destination for Chromium's internal logging.
Setting this variable is the same as passing `--log-file`
on the command line. For more info, see `--log-file` in [command-line
switches](./command-line-switches.md#log-filepath).
switches](./command-line-switches.md#--log-filepath).
### `ELECTRON_DEBUG_DRAG_REGIONS`

View File

@@ -1,221 +0,0 @@
# Frameless Window
> Open a window without toolbars, borders, or other graphical "chrome".
A frameless window is a window that has no
[chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome), the parts of
the window, like toolbars, that are not a part of the web page. These are
options on the [`BrowserWindow`](browser-window.md) class.
## Create a frameless window
To create a frameless window, you need to set `frame` to `false` in
[BrowserWindow](browser-window.md)'s `options`:
```javascript
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 600, frame: false })
win.show()
```
### Alternatives
There's an alternative way to specify a chromeless window on macOS and Windows.
Instead of setting `frame` to `false` which disables both the titlebar and window controls,
you may want to have the title bar hidden and your content extend to the full window size,
yet still preserve the window controls ("traffic lights" on macOS) for standard window actions.
You can do so by specifying the `titleBarStyle` option:
#### `hidden`
Results in a hidden title bar and a full size content window. On macOS, the title bar still has the standard window controls (“traffic lights”) in the top left.
```javascript
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ titleBarStyle: 'hidden' })
win.show()
```
### Alternatives on macOS
#### `hiddenInset`
Results in a hidden title bar with an alternative look where the traffic light buttons are slightly more inset from the window edge.
```javascript
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ titleBarStyle: 'hiddenInset' })
win.show()
```
#### `customButtonsOnHover`
Uses custom drawn close, and miniaturize buttons that display
when hovering in the top left of the window. The fullscreen button
is not available due to restrictions of frameless windows as they
interface with Apple's macOS window masks. These custom buttons prevent
issues with mouse events that occur with the standard window toolbar buttons.
This option is only applicable for frameless windows.
```javascript
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover', frame: false })
win.show()
```
## Windows Control Overlay
When using a frameless window in conjuction with `win.setWindowButtonVisibility(true)` on macOS, using one of the `titleBarStyle`s as described above so
that the traffic lights are visible, or using `titleBarStyle: hidden` on Windows, you can access the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and
[CSS Environment Variables][overlay-css-env-vars] by setting the `titleBarOverlay` option to true. Specifying `true` will result in an overlay with default system colors.
On Windows, you can also specify the color of the overlay and its symbols by setting `titleBarOverlay` to an object with the options `color` and `symbolColor`. If an option is not specified, the color will default to its system color for the window control buttons:
```javascript
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
titleBarStyle: 'hidden',
titleBarOverlay: true
})
win.show()
```
```javascript
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
titleBarStyle: 'hidden',
titleBarOverlay: {
color: '#2f3241',
symbolColor: '#74b1be'
}
})
win.show()
```
## Transparent window
By setting the `transparent` option to `true`, you can also make the frameless
window transparent:
```javascript
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ transparent: true, frame: false })
win.show()
```
### Limitations
* You can not click through the transparent area. We are going to introduce an
API to set window shape to solve this, see
[our issue](https://github.com/electron/electron/issues/1335) for details.
* Transparent windows are not resizable. Setting `resizable` to `true` may make
a transparent window stop working on some platforms.
* The `blur` filter only applies to the web page, so there is no way to apply
blur effect to the content below the window (i.e. other applications open on
the user's system).
* The window will not be transparent when DevTools is opened.
* On Windows operating systems,
* transparent windows will not work when DWM is
disabled.
* transparent windows can not be maximized using the Windows system menu or by double clicking the title bar. The reasoning behind this can be seen on [this pull request](https://github.com/electron/electron/pull/28207).
* On Linux, users have to put `--enable-transparent-visuals --disable-gpu` in
the command line to disable GPU and allow ARGB to make transparent window,
this is caused by an upstream bug that [alpha channel doesn't work on some
NVidia drivers](https://bugs.chromium.org/p/chromium/issues/detail?id=369209) on
Linux.
* On Mac, the native window shadow will not be shown on a transparent window.
## Click-through window
To create a click-through window, i.e. making the window ignore all mouse
events, you can call the [win.setIgnoreMouseEvents(ignore)][ignore-mouse-events]
API:
```javascript
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.setIgnoreMouseEvents(true)
```
### Forwarding
Ignoring mouse messages makes the web page oblivious to mouse movement, meaning
that mouse movement events will not be emitted. On Windows operating systems an
optional parameter can be used to forward mouse move messages to the web page,
allowing events such as `mouseleave` to be emitted:
```javascript
const { ipcRenderer } = require('electron')
const el = document.getElementById('clickThroughElement')
el.addEventListener('mouseenter', () => {
ipcRenderer.send('set-ignore-mouse-events', true, { forward: true })
})
el.addEventListener('mouseleave', () => {
ipcRenderer.send('set-ignore-mouse-events', false)
})
// Main process
const { ipcMain } = require('electron')
ipcMain.on('set-ignore-mouse-events', (event, ...args) => {
BrowserWindow.fromWebContents(event.sender).setIgnoreMouseEvents(...args)
})
```
This makes the web page click-through when over `el`, and returns to normal
outside it.
## Draggable region
By default, the frameless window is non-draggable. Apps need to specify
`-webkit-app-region: drag` in CSS to tell Electron which regions are draggable
(like the OS's standard titlebar), and apps can also use
`-webkit-app-region: no-drag` to exclude the non-draggable area from the
draggable region. Note that only rectangular shapes are currently supported.
Note: `-webkit-app-region: drag` is known to have problems while the developer tools are open. See this [GitHub issue](https://github.com/electron/electron/issues/3647) for more information including a workaround.
To make the whole window draggable, you can add `-webkit-app-region: drag` as
`body`'s style:
```html
<body style="-webkit-app-region: drag">
</body>
```
And note that if you have made the whole window draggable, you must also mark
buttons as non-draggable, otherwise it would be impossible for users to click on
them:
```css
button {
-webkit-app-region: no-drag;
}
```
If you're only setting a custom titlebar as draggable, you also need to make all
buttons in titlebar non-draggable.
## Text selection
In a frameless window the dragging behavior may conflict with selecting text.
For example, when you drag the titlebar you may accidentally select the text on
the titlebar. To prevent this, you need to disable text selection within a
draggable area like this:
```css
.titlebar {
-webkit-user-select: none;
-webkit-app-region: drag;
}
```
## Context menu
On some platforms, the draggable area will be treated as a non-client frame, so
when you right click on it a system menu will pop up. To make the context menu
behave correctly on all platforms you should never use a custom context menu on
draggable areas.
[ignore-mouse-events]: browser-window.md#winsetignoremouseeventsignore-options
[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis
[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables

View File

@@ -67,3 +67,8 @@ or is being instructed to show a high-contrast UI.
A `Boolean` for if the OS / Chromium currently has an inverted color scheme
or is being instructed to use an inverted color scheme.
### `nativeTheme.inForcedColorsMode` _Windows_ _Readonly_
A `boolean` indicating whether Chromium is in forced colors mode, controlled by system accessibility settings.
Currently, Windows high contrast is the only system setting that triggers forced colors mode.

View File

@@ -178,7 +178,6 @@ Returns an object with V8 heap statistics. Note that all statistics are reported
Returns `Object`:
* `allocated` Integer - Size of all allocated objects in Kilobytes.
* `marked` Integer - Size of all marked objects in Kilobytes.
* `total` Integer - Total allocated space in Kilobytes.
Returns an object with Blink memory information.

View File

@@ -297,6 +297,35 @@ app.whenReady().then(() => {
width: 800,
height: 600
})
win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
if (permission === 'serial') {
// Add logic here to determine if permission should be given to allow serial selection
return true
}
return false
})
// Optionally, retrieve previously persisted devices from a persistent store
const grantedDevices = fetchGrantedDevices()
win.webContents.session.setDevicePermissionHandler((details) => {
if (new URL(details.origin).hostname === 'some-host' && details.deviceType === 'serial') {
if (details.device.vendorId === 123 && details.device.productId === 345) {
// Always allow this type of device (this allows skipping the call to `navigator.serial.requestPort` first)
return true
}
// Search through the list of devices that have previously been granted permission
return grantedDevices.some((grantedDevice) => {
return grantedDevice.vendorId === details.device.vendorId &&
grantedDevice.productId === details.device.productId &&
grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber
})
}
return false
})
win.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => {
event.preventDefault()
const selectedPort = portList.find((device) => {
@@ -588,6 +617,7 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
* `permissionGranted` Boolean - Allow or deny the permission.
* `details` Object - Some properties are only available on certain permission types.
* `externalURL` String (optional) - The url of the `openExternal` request.
* `securityOrigin` String (optional) - The security origin of the `media` request.
* `mediaTypes` String[] (optional) - The types of media access being requested, elements can be `video`
or `audio`
* `requestingUrl` String - The last URL the requesting frame loaded
@@ -646,9 +676,9 @@ session.fromPartition('some-partition').setPermissionCheckHandler((webContents,
* `handler` Function\<Boolean> | null
* `details` Object
* `deviceType` String - The type of device that permission is being requested on, can be `hid`.
* `deviceType` String - The type of device that permission is being requested on, can be `hid` or `serial`.
* `origin` String - The origin URL of the device permission check.
* `device` [HIDDevice](structures/hid-device.md) - the device that permission is being requested for.
* `device` [HIDDevice](structures/hid-device.md) | [SerialPort](structures/serial-port.md)- the device that permission is being requested for.
* `frame` [WebFrameMain](web-frame-main.md) - WebFrameMain checking the device permission.
Sets the handler which can be used to respond to device permission checks for the `session`.
@@ -673,6 +703,8 @@ app.whenReady().then(() => {
if (permission === 'hid') {
// Add logic here to determine if permission should be given to allow HID selection
return true
} else if (permission === 'serial') {
// Add logic here to determine if permission should be given to allow serial port selection
}
return false
})
@@ -693,6 +725,11 @@ app.whenReady().then(() => {
grantedDevice.productId === details.device.productId &&
grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber
})
} else if (details.deviceType === 'serial') {
if (details.device.vendorId === 123 && details.device.productId === 345) {
// Always allow this type of device (this allows skipping the call to `navigator.hid.requestDevice` first)
return true
}
}
return false
})

View File

@@ -736,6 +736,8 @@ first available device will be selected. `callback` should be called with
`deviceId` to be selected, passing empty string to `callback` will
cancel the request.
If no event listener is added for this event, all bluetooth requests will be cancelled.
```javascript
const { app, BrowserWindow } = require('electron')
@@ -1494,8 +1496,8 @@ win.loadURL('http://github.com')
win.webContents.on('did-finish-load', () => {
// Use default printing options
const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf')
win.webContents.printToPDF({}).then(data => {
const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf')
fs.writeFile(pdfPath, data, (error) => {
if (error) throw error
console.log(`Wrote PDF successfully to ${pdfPath}`)
@@ -1610,7 +1612,7 @@ app.whenReady().then(() => {
* `options` Object (optional)
* `mode` String - Opens the devtools with specified dock state, can be
`right`, `bottom`, `undocked`, `detach`. Defaults to last used dock state.
`left`, `right`, `bottom`, `undocked`, `detach`. Defaults to last used dock state.
In `undocked` mode it's possible to dock back. In `detach` mode it's not.
* `activate` Boolean (optional) - Whether to bring the opened devtools window
to the foreground. The default is `true`.
@@ -1838,7 +1840,7 @@ the cursor when dragging.
#### `contents.savePage(fullPath, saveType)`
* `fullPath` String - The full file path.
* `fullPath` String - The absolute file path.
* `saveType` String - Specify the save type.
* `HTMLOnly` - Save only the HTML of the page.
* `HTMLComplete` - Save complete-html page.

View File

@@ -1025,3 +1025,78 @@ Emitted when DevTools is focused / opened.
[runtime-enabled-features]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/runtime_enabled_features.json5?l=70
[chrome-webview]: https://developer.chrome.com/docs/extensions/reference/webviewTag/
### Event: 'context-menu'
Returns:
* `params` Object
* `x` Integer - x coordinate.
* `y` Integer - y coordinate.
* `linkURL` String - URL of the link that encloses the node the context menu
was invoked on.
* `linkText` String - Text associated with the link. May be an empty
string if the contents of the link are an image.
* `pageURL` String - URL of the top level page that the context menu was
invoked on.
* `frameURL` String - URL of the subframe that the context menu was invoked
on.
* `srcURL` String - Source URL for the element that the context menu
was invoked on. Elements with source URLs are images, audio and video.
* `mediaType` String - Type of the node the context menu was invoked on. Can
be `none`, `image`, `audio`, `video`, `canvas`, `file` or `plugin`.
* `hasImageContents` Boolean - Whether the context menu was invoked on an image
which has non-empty contents.
* `isEditable` Boolean - Whether the context is editable.
* `selectionText` String - Text of the selection that the context menu was
invoked on.
* `titleText` String - Title text of the selection that the context menu was
invoked on.
* `altText` String - Alt text of the selection that the context menu was
invoked on.
* `suggestedFilename` String - Suggested filename to be used when saving file through 'Save
Link As' option of context menu.
* `selectionRect` [Rectangle](structures/rectangle.md) - Rect representing the coordinates in the document space of the selection.
* `selectionStartOffset` Number - Start position of the selection text.
* `referrerPolicy` [Referrer](structures/referrer.md) - The referrer policy of the frame on which the menu is invoked.
* `misspelledWord` String - The misspelled word under the cursor, if any.
* `dictionarySuggestions` String[] - An array of suggested words to show the
user to replace the `misspelledWord`. Only available if there is a misspelled
word and spellchecker is enabled.
* `frameCharset` String - The character encoding of the frame on which the
menu was invoked.
* `inputFieldType` String - If the context menu was invoked on an input
field, the type of that field. Possible values are `none`, `plainText`,
`password`, `other`.
* `spellcheckEnabled` Boolean - If the context is editable, whether or not spellchecking is enabled.
* `menuSourceType` String - Input source that invoked the context menu.
Can be `none`, `mouse`, `keyboard`, `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, `adjustSelection`, or `adjustSelectionReset`.
* `mediaFlags` Object - The flags for the media element the context menu was
invoked on.
* `inError` Boolean - Whether the media element has crashed.
* `isPaused` Boolean - Whether the media element is paused.
* `isMuted` Boolean - Whether the media element is muted.
* `hasAudio` Boolean - Whether the media element has audio.
* `isLooping` Boolean - Whether the media element is looping.
* `isControlsVisible` Boolean - Whether the media element's controls are
visible.
* `canToggleControls` Boolean - Whether the media element's controls are
toggleable.
* `canPrint` Boolean - Whether the media element can be printed.
* `canSave` Boolean - Whether or not the media element can be downloaded.
* `canShowPictureInPicture` Boolean - Whether the media element can show picture-in-picture.
* `isShowingPictureInPicture` Boolean - Whether the media element is currently showing picture-in-picture.
* `canRotate` Boolean - Whether the media element can be rotated.
* `canLoop` Boolean - Whether the media element can be looped.
* `editFlags` Object - These flags indicate whether the renderer believes it
is able to perform the corresponding action.
* `canUndo` Boolean - Whether the renderer believes it can undo.
* `canRedo` Boolean - Whether the renderer believes it can redo.
* `canCut` Boolean - Whether the renderer believes it can cut.
* `canCopy` Boolean - Whether the renderer believes it can copy.
* `canPaste` Boolean - Whether the renderer believes it can paste.
* `canDelete` Boolean - Whether the renderer believes it can delete.
* `canSelectAll` Boolean - Whether the renderer believes it can select all.
* `canEditRichly` Boolean - Whether the renderer believes it can edit text richly.
Emitted when there is a new context menu that needs to be handled.

View File

@@ -64,6 +64,9 @@ window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIn
`features` will be passed to any registered `webContents`'s
`did-create-window` event handler in the `options` argument.
* `frameName` follows the specification of `windowName` located in the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters).
* When opening `about:blank`, the child window's `WebPreferences` will be copied
from the parent window, and there is no way to override it because Chromium
skips browser side navigation in this case.
To customize or cancel the creation of the window, you can optionally set an
override handler with `webContents.setWindowOpenHandler()` from the main

View File

@@ -12,6 +12,18 @@ This document uses the following convention to categorize breaking changes:
* **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release.
* **Removed:** An API or feature was removed, and is no longer supported by Electron.
## Planned Breaking API Changes (15.0)
### Default Changed: `nativeWindowOpen` defaults to `true`
Prior to Electron 15, `window.open` was by default shimmed to use
`BrowserWindowProxy`. This meant that `window.open('about:blank')` did not work
to open synchronously scriptable child windows, among other incompatibilities.
`nativeWindowOpen` is no longer experimental, and is now the default.
See the documentation for [window.open in Electron](api/window-open.md)
for more details.
## Planned Breaking API Changes (14.0)
### Removed: `remote` module
@@ -62,16 +74,6 @@ ensure your code works with this property enabled. It has been enabled by defau
You will be affected by this change if you use either `webFrame.executeJavaScript` or `webFrame.executeJavaScriptInIsolatedWorld`. You will need to ensure that values returned by either of those methods are supported by the [Context Bridge API](api/context-bridge.md#parameter--error--return-type-support) as these methods use the same value passing semantics.
### Default Changed: `nativeWindowOpen` defaults to `true`
Prior to Electron 14, `window.open` was by default shimmed to use
`BrowserWindowProxy`. This meant that `window.open('about:blank')` did not work
to open synchronously scriptable child windows, among other incompatibilities.
`nativeWindowOpen` is no longer experimental, and is now the default.
See the documentation for [window.open in Electron](api/window-open.md)
for more details.
### Removed: BrowserWindowConstructorOptions inheriting from parent windows
Prior to Electron 14, windows opened with `window.open` would inherit

View File

@@ -43,8 +43,9 @@ SRV*c:\code\symbols\*https://msdl.microsoft.com/download/symbols;SRV*c:\code\sym
## Using the symbol server in Visual Studio
![Tools -> Options](https://mdn.mozillademos.org/files/733/symbol-server-vc8express-menu.jpg)
![Symbols Settings](https://mdn.mozillademos.org/files/2497/2005_options.gif)
![Tools -> Options](../images/vs-tools-options.png)
![Symbols Settings](../images/vs-options-debugging-symbols.png)
## Troubleshooting: Symbols will not load

View File

@@ -59,8 +59,9 @@
<p>
For more details, see the
<a href="https://electronjs.org/docs/api/frameless-window/">
Frameless Window
<a href="https://electronjs.org/docs/tutorial/window-customization/">
Window Customization
</a>
documentation.
</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -1,48 +1,7 @@
# Accessibility
Making accessible applications is important and we're happy to provide
functionality to [Devtron][devtron] and [Spectron][spectron] that gives
developers the opportunity to make their apps better for everyone.
---
Accessibility concerns in Electron applications are similar to those of
websites because they're both ultimately HTML. With Electron apps, however,
you can't use the online resources for accessibility audits because your app
doesn't have a URL to point the auditor to.
These features bring those auditing tools to your Electron app. You can
choose to add audits to your tests with Spectron or use them within DevTools
with Devtron. Read on for a summary of the tools.
## Spectron
In the testing framework Spectron, you can now audit each window and `<webview>`
tag in your application. For example:
```javascript
app.client.auditAccessibility().then(function (audit) {
if (audit.failed) {
console.error(audit.message)
}
})
```
You can read more about this feature in [Spectron's documentation][spectron-a11y].
## Devtron
In Devtron, there is an accessibility tab which will allow you to audit a
page in your app, sort and filter the results.
![devtron screenshot][devtron-screenshot]
Both of these tools are using the [Accessibility Developer Tools][a11y-devtools]
library built by Google for Chrome. You can learn more about the accessibility
audit rules this library uses on that [repository's wiki][a11y-devtools-wiki].
If you know of other great accessibility tools for Electron, add them to the
accessibility documentation with a pull request.
websites because they're both ultimately HTML.
## Manually enabling accessibility features
@@ -84,10 +43,6 @@ CFStringRef kAXManualAccessibility = CFSTR("AXManualAccessibility");
}
```
[devtron]: https://electronjs.org/devtron
[devtron-screenshot]: https://cloud.githubusercontent.com/assets/1305617/17156618/9f9bcd72-533f-11e6-880d-389115f40a2a.png
[spectron]: https://electronjs.org/spectron
[spectron-a11y]: https://github.com/electron/spectron#accessibility-testing
[a11y-docs]: https://www.chromium.org/developers/design-documents/accessibility#TOC-How-Chrome-detects-the-presence-of-Assistive-Technology
[a11y-devtools]: https://github.com/GoogleChrome/accessibility-developer-tools
[a11y-devtools-wiki]: https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules

View File

@@ -56,7 +56,7 @@ will then be your distribution to deliver to users.
### With an app source code archive
Instead of from shipping your app by copying all of its source files, you can
Instead of shipping your app by copying all of its source files, you can
package your app into an [asar] archive to improve the performance of reading
files on platforms like Windows, if you are not already using a bundler such
as Parcel or Webpack.

View File

@@ -1,135 +0,0 @@
# Automated Testing with a Custom Driver
To write automated tests for your Electron app, you will need a way to "drive" your application. [Spectron](https://electronjs.org/spectron) is a commonly-used solution which lets you emulate user actions via [WebDriver](https://webdriver.io/). However, it's also possible to write your own custom driver using node's builtin IPC-over-STDIO. The benefit of a custom driver is that it tends to require less overhead than Spectron, and lets you expose custom methods to your test suite.
To create a custom driver, we'll use Node.js' [child_process](https://nodejs.org/api/child_process.html) API. The test suite will spawn the Electron process, then establish a simple messaging protocol:
```js
const childProcess = require('child_process')
const electronPath = require('electron')
// spawn the process
const env = { /* ... */ }
const stdio = ['inherit', 'inherit', 'inherit', 'ipc']
const appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env })
// listen for IPC messages from the app
appProcess.on('message', (msg) => {
// ...
})
// send an IPC message to the app
appProcess.send({ my: 'message' })
```
From within the Electron app, you can listen for messages and send replies using the Node.js [process](https://nodejs.org/api/process.html) API:
```js
// listen for IPC messages from the test suite
process.on('message', (msg) => {
// ...
})
// send an IPC message to the test suite
process.send({ my: 'message' })
```
We can now communicate from the test suite to the Electron app using the `appProcess` object.
For convenience, you may want to wrap `appProcess` in a driver object that provides more high-level functions. Here is an example of how you can do this:
```js
class TestDriver {
constructor ({ path, args, env }) {
this.rpcCalls = []
// start child process
env.APP_TEST_DRIVER = 1 // let the app know it should listen for messages
this.process = childProcess.spawn(path, args, { stdio: ['inherit', 'inherit', 'inherit', 'ipc'], env })
// handle rpc responses
this.process.on('message', (message) => {
// pop the handler
const rpcCall = this.rpcCalls[message.msgId]
if (!rpcCall) return
this.rpcCalls[message.msgId] = null
// reject/resolve
if (message.reject) rpcCall.reject(message.reject)
else rpcCall.resolve(message.resolve)
})
// wait for ready
this.isReady = this.rpc('isReady').catch((err) => {
console.error('Application failed to start', err)
this.stop()
process.exit(1)
})
}
// simple RPC call
// to use: driver.rpc('method', 1, 2, 3).then(...)
async rpc (cmd, ...args) {
// send rpc request
const msgId = this.rpcCalls.length
this.process.send({ msgId, cmd, args })
return new Promise((resolve, reject) => this.rpcCalls.push({ resolve, reject }))
}
stop () {
this.process.kill()
}
}
```
In the app, you'd need to write a simple handler for the RPC calls:
```js
if (process.env.APP_TEST_DRIVER) {
process.on('message', onMessage)
}
async function onMessage ({ msgId, cmd, args }) {
let method = METHODS[cmd]
if (!method) method = () => new Error('Invalid method: ' + cmd)
try {
const resolve = await method(...args)
process.send({ msgId, resolve })
} catch (err) {
const reject = {
message: err.message,
stack: err.stack,
name: err.name
}
process.send({ msgId, reject })
}
}
const METHODS = {
isReady () {
// do any setup needed
return true
}
// define your RPC-able methods here
}
```
Then, in your test suite, you can use your test-driver as follows:
```js
const test = require('ava')
const electronPath = require('electron')
const app = new TestDriver({
path: electronPath,
args: ['./app'],
env: {
NODE_ENV: 'test'
}
})
test.before(async t => {
await app.isReady
})
test.after.always('cleanup', async t => {
await app.stop()
})
```

View File

@@ -0,0 +1,265 @@
# Automated Testing
Test automation is an efficient way of validating that your application code works as intended.
While Electron doesn't actively maintain its own testing solution, this guide will go over a couple
ways you can run end-to-end automated tests on your Electron app.
## Using the WebDriver interface
From [ChromeDriver - WebDriver for Chrome][chrome-driver]:
> WebDriver is an open source tool for automated testing of web apps across many
> browsers. It provides capabilities for navigating to web pages, user input,
> JavaScript execution, and more. ChromeDriver is a standalone server which
> implements WebDriver's wire protocol for Chromium. It is being developed by
> members of the Chromium and WebDriver teams.
There are a few ways that you can set up testing using WebDriver.
### With WebdriverIO
[WebdriverIO](https://webdriver.io/) (WDIO) is a test automation framework that provides a
Node.js package for testing with WebDriver. Its ecosystem also includes various plugins
(e.g. reporter and services) that can help you put together your test setup.
#### Install the testrunner
First you need to run the WebdriverIO starter toolkit in your project root directory:
```sh npm2yarn
npx wdio . --yes
```
This installs all necessary packages for you and generates a `wdio.conf.js` configuration file.
#### Connect WDIO to your Electron app
Update the capabilities in your configuration file to point to your Electron app binary:
```javascript title='wdio.conf.js'
export.config = {
// ...
capabilities: [{
browserName: 'chrome',
'goog:chromeOptions': {
binary: '/path/to/your/electron/binary', // Path to your Electron binary.
args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/
}
}]
// ...
}
```
#### Run your tests
To run your tests:
```sh
$ npx wdio run wdio.conf.js
```
[chrome-driver]: https://sites.google.com/chromium.org/driver/
### With Selenium
[Selenium](https://www.selenium.dev/) is a web automation framework that
exposes bindings to WebDriver APIs in many languages. Their Node.js bindings
are available under the `selenium-webdriver` package on NPM.
#### Run a ChromeDriver server
In order to use Selenium with Electron, you need to download the `electron-chromedriver`
binary, and run it:
```sh npm2yarn
npm install --save-dev electron-chromedriver
./node_modules/.bin/chromedriver
Starting ChromeDriver (v2.10.291558) on port 9515
Only local connections are allowed.
```
Remember the port number `9515`, which will be used later.
#### Connect Selenium to ChromeDriver
Next, install Selenium into your project:
```sh npm2yarn
npm install --save-dev selenium-webdriver
```
Usage of `selenium-webdriver` with Electron is the same as with
normal websites, except that you have to manually specify how to connect
ChromeDriver and where to find the binary of your Electron app:
```js title='test.js'
const webdriver = require('selenium-webdriver')
const driver = new webdriver.Builder()
// The "9515" is the port opened by ChromeDriver.
.usingServer('http://localhost:9515')
.withCapabilities({
'goog:chromeOptions': {
// Here is the path to your Electron binary.
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
}
})
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
.build()
driver.get('http://www.google.com')
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver')
driver.findElement(webdriver.By.name('btnG')).click()
driver.wait(() => {
return driver.getTitle().then((title) => {
return title === 'webdriver - Google Search'
})
}, 1000)
driver.quit()
```
## Using a custom test driver
It's also possible to write your own custom driver using Node.js' built-in IPC-over-STDIO.
Custom test drivers require you to write additional app code, but have lower overhead and let you
expose custom methods to your test suite.
To create a custom driver, we'll use Node.js' [`child_process`](https://nodejs.org/api/child_process.html) API.
The test suite will spawn the Electron process, then establish a simple messaging protocol:
```js title='testDriver.js'
const childProcess = require('child_process')
const electronPath = require('electron')
// spawn the process
const env = { /* ... */ }
const stdio = ['inherit', 'inherit', 'inherit', 'ipc']
const appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env })
// listen for IPC messages from the app
appProcess.on('message', (msg) => {
// ...
})
// send an IPC message to the app
appProcess.send({ my: 'message' })
```
From within the Electron app, you can listen for messages and send replies using the Node.js
[`process`](https://nodejs.org/api/process.html) API:
```js title='main.js'
// listen for messages from the test suite
process.on('message', (msg) => {
// ...
})
// send a message to the test suite
process.send({ my: 'message' })
```
We can now communicate from the test suite to the Electron app using the `appProcess` object.
For convenience, you may want to wrap `appProcess` in a driver object that provides more
high-level functions. Here is an example of how you can do this. Let's start by creating
a `TestDriver` class:
```js title='testDriver.js'
class TestDriver {
constructor ({ path, args, env }) {
this.rpcCalls = []
// start child process
env.APP_TEST_DRIVER = 1 // let the app know it should listen for messages
this.process = childProcess.spawn(path, args, { stdio: ['inherit', 'inherit', 'inherit', 'ipc'], env })
// handle rpc responses
this.process.on('message', (message) => {
// pop the handler
const rpcCall = this.rpcCalls[message.msgId]
if (!rpcCall) return
this.rpcCalls[message.msgId] = null
// reject/resolve
if (message.reject) rpcCall.reject(message.reject)
else rpcCall.resolve(message.resolve)
})
// wait for ready
this.isReady = this.rpc('isReady').catch((err) => {
console.error('Application failed to start', err)
this.stop()
process.exit(1)
})
}
// simple RPC call
// to use: driver.rpc('method', 1, 2, 3).then(...)
async rpc (cmd, ...args) {
// send rpc request
const msgId = this.rpcCalls.length
this.process.send({ msgId, cmd, args })
return new Promise((resolve, reject) => this.rpcCalls.push({ resolve, reject }))
}
stop () {
this.process.kill()
}
}
module.exports = { TestDriver };
```
In your app code, can then write a simple handler to receive RPC calls:
```js title='main.js'
const METHODS = {
isReady () {
// do any setup needed
return true
}
// define your RPC-able methods here
}
const onMessage = async ({ msgId, cmd, args }) => {
let method = METHODS[cmd]
if (!method) method = () => new Error('Invalid method: ' + cmd)
try {
const resolve = await method(...args)
process.send({ msgId, resolve })
} catch (err) {
const reject = {
message: err.message,
stack: err.stack,
name: err.name
}
process.send({ msgId, reject })
}
}
if (process.env.APP_TEST_DRIVER) {
process.on('message', onMessage)
}
```
Then, in your test suite, you can use your `TestDriver` class with the test automation
framework of your choosing. The following example uses
[`ava`](https://www.npmjs.com/package/ava), but other popular choices like Jest
or Mocha would work as well:
```js title='test.js'
const test = require('ava')
const electronPath = require('electron')
const { TestDriver } = require('./testDriver')
const app = new TestDriver({
path: electronPath,
args: ['./app'],
env: {
NODE_ENV: 'test'
}
})
test.before(async t => {
await app.isReady
})
test.after.always('cleanup', async t => {
await app.stop()
})
```

View File

@@ -84,13 +84,22 @@ There are several additional APIs for working with the Web Serial API:
and [`serial-port-removed`](../api/session.md#event-serial-port-removed) events
on the Session can be used to handle devices being plugged in or unplugged during the
`navigator.serial.requestPort` process.
* [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
can be used to provide default permissioning to devices without first calling
for permission to devices via `navigator.serial.requestPort`. Additionally,
the default behavior of Electron is to store granted device permision through
the lifetime of the corresponding WebContents. If longer term storage is
needed, a developer can store granted device permissions (eg when handling
the `select-serial-port` event) and then read from that storage with
`setDevicePermissionHandler`.
* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler)
can be used to disable serial access for specific origins.
### Example
This example demonstrates an Electron application that automatically selects
the first available Arduino Uno serial device (if connected) through
serial devices through [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
as well as demonstrating selecting the first available Arduino Uno serial device (if connected) through
[`select-serial-port` event on the Session](../api/session.md#event-select-serial-port)
when the `Test Web Serial` button is clicked.

View File

@@ -2,43 +2,31 @@
> A detailed look at our versioning policy and implementation.
As of version 2.0.0, Electron follows [SemVer](#semver). The following command will install the most recent stable build of Electron:
As of version 2.0.0, Electron follows the [SemVer](#semver) spec. The following command will install the most recent stable build of Electron:
```sh
```sh npm2yarn
npm install --save-dev electron
```
To update an existing project to use the latest stable version:
```sh
```sh npm2yarn
npm install --save-dev electron@latest
```
## Version 1.x
Electron versions *< 2.0* did not conform to the [SemVer](https://semver.org) spec: major versions corresponded to end-user API changes, minor versions corresponded to Chromium major releases, and patch versions corresponded to new features and bug fixes. While convenient for developers merging features, it creates problems for developers of client-facing applications. The QA testing cycles of major apps like Slack, Stride, Teams, Skype, VS Code, Atom, and Desktop can be lengthy and stability is a highly desired outcome. There is a high risk in adopting new features while trying to absorb bug fixes.
Here is an example of the 1.x strategy:
![1.x Versioning](../images/versioning-sketch-0.png)
An app developed with `1.8.1` cannot take the `1.8.3` bug fix without either absorbing the `1.8.2` feature, or by backporting the fix and maintaining a new release line.
## Version 2.0 and Beyond
## Versioning scheme
There are several major changes from our 1.x strategy outlined below. Each change is intended to satisfy the needs and priorities of developers/maintainers and app developers.
1. Strict use of SemVer
1. Strict use of the [SemVer](#semver) spec
2. Introduction of semver-compliant `-beta` tags
3. Introduction of [conventional commit messages](https://conventionalcommits.org/)
4. Well-defined stabilization branches
5. The `master` branch is versionless; only stabilization branches contain version information
5. The `main` branch is versionless; only stabilization branches contain version information
We will cover in detail how git branching works, how npm tagging works, what developers should expect to see, and how one can backport changes.
# SemVer
From 2.0 onward, Electron will follow SemVer.
## SemVer
Below is a table explicitly mapping types of changes to their corresponding category of SemVer (e.g. Major, Minor, Patch).
@@ -48,22 +36,25 @@ Below is a table explicitly mapping types of changes to their corresponding cate
| Node.js major version updates | Node.js minor version updates | Node.js patch version updates |
| Chromium version updates | | fix-related chromium patches |
For more information, see the [Semantic Versioning 2.0.0](https://semver.org/) spec.
Note that most Chromium updates will be considered breaking. Fixes that can be backported will likely be cherry-picked as patches.
# Stabilization Branches
## Stabilization branches
Stabilization branches are branches that run parallel to master, taking in only cherry-picked commits that are related to security or stability. These branches are never merged back to master.
Stabilization branches are branches that run parallel to `main`, taking in only cherry-picked commits that are related to security or stability. These branches are never merged back to `main`.
![Stabilization Branches](../images/versioning-sketch-1.png)
Since Electron 8, stabilization branches are always **major** version lines, and named against the following template `$MAJOR-x-y` e.g. `8-x-y`. Prior to that we used **minor** version lines and named them as `$MAJOR-$MINOR-x` e.g. `2-0-x`
Since Electron 8, stabilization branches are always **major** version lines, and named against the following template `$MAJOR-x-y` e.g. `8-x-y`. Prior to that we used **minor** version lines and named them as `$MAJOR-$MINOR-x` e.g. `2-0-x`.
We allow for multiple stabilization branches to exist simultaneously, one for each supported version. For more details on which versions are supported, see our [Electron Release Timelines](./electron-timelines.md) doc.
We allow for multiple stabilization branches to exist simultaneously, and intend to support at least two in parallel at all times, backporting security fixes as necessary.
![Multiple Stability Branches](../images/versioning-sketch-2.png)
Older lines will not be supported by GitHub, but other groups can take ownership and backport stability and security fixes on their own. We discourage this, but recognize that it makes life easier for many app developers.
Older lines will not be supported by the Electron project, but other groups can take ownership and backport stability and security fixes on their own. We discourage this, but recognize that it makes life easier for many app developers.
# Beta Releases and Bug Fixes
## Beta releases and bug fixes
Developers want to know which releases are _safe_ to use. Even seemingly innocent features can introduce regressions in complex applications. At the same time, locking to a fixed version is dangerous because youre ignoring security patches and bug fixes that may have come out since your version. Our goal is to allow the following standard semver ranges in `package.json` :
@@ -116,15 +107,7 @@ A few examples of how various SemVer ranges will pick up new releases:
![Semvers and Releases](../images/versioning-sketch-7.png)
# Missing Features: Alphas
Our strategy has a few tradeoffs, which for now we feel are appropriate. Most importantly that new features in master may take a while before reaching a stable release line. If you want to try a new feature immediately, you will have to build Electron yourself.
As a future consideration, we may introduce one or both of the following:
* alpha releases that have looser stability constraints to betas; for example it would be allowable to admit new features while a stability channel is in _alpha_
# Feature Flags
## Feature flags
Feature flags are a common practice in Chromium, and are well-established in the web-development ecosystem. In the context of Electron, a feature flag or **soft branch** must have the following properties:
@@ -132,20 +115,29 @@ Feature flags are a common practice in Chromium, and are well-established in the
* it completely segments new and old code paths; refactoring old code to support a new feature _violates_ the feature-flag contract
* feature flags are eventually removed after the feature is released
# Semantic Commits
## Semantic commits
We seek to increase clarity at all levels of the update and releases process. Starting with `2.0.0` we will require pull requests adhere to the [Conventional Commits](https://conventionalcommits.org/) spec, which can be summarized as follows:
All pull requests must adhere to the [Conventional Commits](https://conventionalcommits.org/) spec, which can be summarized as follows:
* Commits that would result in a SemVer **major** bump must start their body with `BREAKING CHANGE:`.
* Commits that would result in a SemVer **minor** bump must start with `feat:`.
* Commits that would result in a SemVer **patch** bump must start with `fix:`.
* We allow squashing of commits, provided that the squashed message adheres to the above message format.
* It is acceptable for some commits in a pull request to not include a semantic prefix, as long as the pull request title contains a meaningful encompassing semantic message.
The `electron/electron` repository also enforces squash merging, so you only need to make sure that your pull request has the correct title prefix.
# Versioned `master`
## Versioned `main` branch
* The `master` branch will always contain the next major version `X.0.0-nightly.DATE` in its `package.json`
* Release branches are never merged back to master
* Release branches _do_ contain the correct version in their `package.json`
* As soon as a release branch is cut for a major, master must be bumped to the next major. I.e. `master` is always versioned as the next theoretical release branch
* The `main` branch will always contain the next major version `X.0.0-nightly.DATE` in its `package.json`.
* Release branches are never merged back to `main`.
* Release branches _do_ contain the correct version in their `package.json`.
* As soon as a release branch is cut for a major, `main` must be bumped to the next major (i.e. `main` is always versioned as the next theoretical release branch).
## Historical versioning (Electron 1.X)
Electron versions *< 2.0* did not conform to the [SemVer](https://semver.org) spec: major versions corresponded to end-user API changes, minor versions corresponded to Chromium major releases, and patch versions corresponded to new features and bug fixes. While convenient for developers merging features, it creates problems for developers of client-facing applications. The QA testing cycles of major apps like Slack, Teams, Skype, VS Code, and GitHub Desktop can be lengthy and stability is a highly desired outcome. There is a high risk in adopting new features while trying to absorb bug fixes.
Here is an example of the 1.x strategy:
![1.x Versioning](../images/versioning-sketch-0.png)
An app developed with `1.8.1` cannot take the `1.8.3` bug fix without either absorbing the `1.8.2` feature, or by backporting the fix and maintaining a new release line.

View File

@@ -91,7 +91,7 @@ The above configuration will download from URLs such as
`https://npm.taobao.org/mirrors/electron/8.0.0/electron-v8.0.0-linux-x64.zip`.
If your mirror serves artifacts with different checksums to the official
Electron release you may have to set `ELECTRON_USE_REMOTE_CHECKSUMS=1` to
Electron release you may have to set `electron_use_remote_checksums=1` to
force Electron to use the remote `SHASUMS256.txt` file to verify the checksum
instead of the embedded checksums.

View File

@@ -17,7 +17,7 @@ the dirty area is passed to the `paint` event to be more efficient.
losses with no benefits.
* When nothing is happening on a webpage, no frames are generated.
* An offscreen window is always created as a
[Frameless Window](../api/frameless-window.md).
[Frameless Window](../tutorial/window-customization.md)..
### Rendering Modes

View File

@@ -7,7 +7,7 @@ without the need of switching to the window itself.
On Windows, you can use a taskbar button to display a progress bar.
![Windows Progress Bar][https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png]
![Windows Progress Bar](../images/windows-progress-bar.png)
On macOS, the progress bar will be displayed as a part of the dock icon.

View File

@@ -1,173 +0,0 @@
# Selenium and WebDriver
From [ChromeDriver - WebDriver for Chrome][chrome-driver]:
> WebDriver is an open source tool for automated testing of web apps across many
> browsers. It provides capabilities for navigating to web pages, user input,
> JavaScript execution, and more. ChromeDriver is a standalone server which
> implements WebDriver's wire protocol for Chromium. It is being developed by
> members of the Chromium and WebDriver teams.
## Setting up Spectron
[Spectron][spectron] is the officially supported ChromeDriver testing framework
for Electron. It is built on top of [WebdriverIO](https://webdriver.io/) and
has helpers to access Electron APIs in your tests and bundles ChromeDriver.
```sh
$ npm install --save-dev spectron
```
```javascript
// A simple test to verify a visible window is opened with a title
const Application = require('spectron').Application
const assert = require('assert')
const myApp = new Application({
path: '/Applications/MyApp.app/Contents/MacOS/MyApp'
})
const verifyWindowIsVisibleWithTitle = async (app) => {
await app.start()
try {
// Check if the window is visible
const isVisible = await app.browserWindow.isVisible()
// Verify the window is visible
assert.strictEqual(isVisible, true)
// Get the window's title
const title = await app.client.getTitle()
// Verify the window's title
assert.strictEqual(title, 'My App')
} catch (error) {
// Log any failures
console.error('Test failed', error.message)
}
// Stop the application
await app.stop()
}
verifyWindowIsVisibleWithTitle(myApp)
```
## Setting up with WebDriverJs
[WebDriverJs](https://www.selenium.dev/selenium/docs/api/javascript/index.html) provides
a Node package for testing with web driver, we will use it as an example.
### 1. Start ChromeDriver
First you need to download the `chromedriver` binary, and run it:
```sh
$ npm install electron-chromedriver
$ ./node_modules/.bin/chromedriver
Starting ChromeDriver (v2.10.291558) on port 9515
Only local connections are allowed.
```
Remember the port number `9515`, which will be used later
### 2. Install WebDriverJS
```sh
$ npm install selenium-webdriver
```
### 3. Connect to ChromeDriver
The usage of `selenium-webdriver` with Electron is the same with
upstream, except that you have to manually specify how to connect
chrome driver and where to find Electron's binary:
```javascript
const webdriver = require('selenium-webdriver')
const driver = new webdriver.Builder()
// The "9515" is the port opened by chrome driver.
.usingServer('http://localhost:9515')
.withCapabilities({
'goog:chromeOptions': {
// Here is the path to your Electron binary.
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
}
})
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
.build()
driver.get('http://www.google.com')
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver')
driver.findElement(webdriver.By.name('btnG')).click()
driver.wait(() => {
return driver.getTitle().then((title) => {
return title === 'webdriver - Google Search'
})
}, 1000)
driver.quit()
```
## Setting up with WebdriverIO
[WebdriverIO](https://webdriver.io/) provides a Node package for testing with web
driver.
### 1. Start ChromeDriver
First you need to download the `chromedriver` binary, and run it:
```sh
$ npm install electron-chromedriver
$ ./node_modules/.bin/chromedriver --url-base=wd/hub --port=9515
Starting ChromeDriver (v2.10.291558) on port 9515
Only local connections are allowed.
```
Remember the port number `9515`, which will be used later
### 2. Install WebdriverIO
```sh
$ npm install webdriverio
```
### 3. Connect to chrome driver
```javascript
const webdriverio = require('webdriverio')
const options = {
host: 'localhost', // Use localhost as chrome driver server
port: 9515, // "9515" is the port opened by chrome driver.
desiredCapabilities: {
browserName: 'chrome',
'goog:chromeOptions': {
binary: '/Path-to-Your-App/electron', // Path to your Electron binary.
args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/
}
}
}
const client = webdriverio.remote(options)
client
.init()
.url('http://google.com')
.setValue('#q', 'webdriverio')
.click('#btnG')
.getTitle().then((title) => {
console.log('Title was: ' + title)
})
.end()
```
## Workflow
To test your application without rebuilding Electron,
[place](application-distribution.md)
your app source into Electron's resource directory.
Alternatively, pass an argument to run with your Electron binary that points to
your app's folder. This eliminates the need to copy-paste your app into
Electron's resource directory.
[chrome-driver]: https://sites.google.com/a/chromium.org/chromedriver/
[spectron]: https://electronjs.org/spectron

View File

@@ -0,0 +1,271 @@
# Window Customization
The `BrowserWindow` module is the foundation of your Electron application, and it exposes
many APIs that can change the look and behavior of your browser windows. In this
tutorial, we will be going over the various use-cases for window customization on
macOS, Windows, and Linux.
## Create frameless windows
A frameless window is a window that has no [chrome]. Not to be confused with the Google
Chrome browser, window _chrome_ refers to the parts of the window (e.g. toolbars, controls)
that are not a part of the web page.
To create a frameless window, you need to set `frame` to `false` in the `BrowserWindow`
constructor.
```javascript title='main.js'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ frame: false })
```
## Apply custom title bar styles _macOS_ _Windows_
Title bar styles allow you to hide most of a BrowserWindow's chrome while keeping the
system's native window controls intact and can be configured with the `titleBarStyle`
option in the `BrowserWindow` constructor.
Applying the `hidden` title bar style results in a hidden title bar and a full-size
content window.
```javascript title='main.js'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ titleBarStyle: 'hidden' })
```
### Control the traffic lights _macOS_
On macOS, applying the `hidden` title bar style will still expose the standard window
controls (“traffic lights”) in the top left.
#### Customize the look of your traffic lights _macOS_
The `customButtonsOnHover` title bar style will hide the traffic lights until you hover
over them. This is useful if you want to create custom traffic lights in your HTML but still
use the native UI to control the window.
```javascript
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover' })
```
#### Customize the traffic light position _macOS_
To modify the position of the traffic light window controls, there are two configuration
options available.
Applying `hiddenInset` title bar style will shift the vertical inset of the traffic lights
by a fixed amount.
```javascript title='main.js'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ titleBarStyle: 'hiddenInset' })
```
If you need more granular control over the positioning of the traffic lights, you can pass
a set of coordinates to the `trafficLightPosition` option in the `BrowserWindow`
constructor.
```javascript title='main.js'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
titleBarStyle: 'hidden',
trafficLightPosition: { x: 10, y: 10 }
})
```
#### Show and hide the traffic lights programmatically _macOS_
You can also show and hide the traffic lights programmatically from the main process.
The `win.setWindowButtonVisibility` forces traffic lights to be show or hidden depending
on the value of its boolean parameter.
```javascript title='main.js'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
// hides the traffic lights
win.setWindowButtonVisibility(false)
```
> Note: Given the number of APIs available, there are many ways of achieving this. For instance,
> combining `frame: false` with `win.setWindowButtonVisibility(true)` will yield the same
> layout outcome as setting `titleBarStyle: 'hidden'`.
## Window Controls Overlay _macOS_ _Windows_
The [Window Controls Overlay API] is a web standard that gives web apps the ability to
customize their title bar region when installed on desktop. Electron exposes this API
through the `BrowserWindow` constructor option `titleBarOverlay`.
This option only works whenever a custom `titlebarStyle` is applied on macOS or Windows.
When `titleBarOverlay` is enabled, the window controls become exposed in their default
position, and DOM elements cannot use the area underneath this region.
The `titleBarOverlay` option accepts two different value formats.
Specifying `true` on either platform will result in an overlay region with default
system colors:
```javascript title='main.js'
// on macOS or Windows
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
titleBarStyle: 'hidden',
titleBarOverlay: true
})
```
On Windows, you can also specify the color of the overlay and its symbols by setting
`titleBarOverlay` to an object with the `color` and `symbolColor` properties. If an option
is not specified, the color will default to its system color for the window control buttons:
```javascript title='main.js'
// on Windows
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
titleBarStyle: 'hidden',
titleBarOverlay: {
color: '#2f3241',
symbolColor: '#74b1be'
}
})
```
> Note: Once your title bar overlay is enabled from the main process, you can access the overlay's
> color and dimension values from a renderer using a set of readonly
> [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars].
## Create transparent windows
By setting the `transparent` option to `true`, you can make a fully transparent window.
```javascript title='main.js'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ transparent: true })
```
### Limitations
* You cannot click through the transparent area. See
[#1335](https://github.com/electron/electron/issues/1335) for details.
* Transparent windows are not resizable. Setting `resizable` to `true` may make
a transparent window stop working on some platforms.
* The CSS [`blur()`] filter only applies to the window's web contents, so there is no way to apply
blur effect to the content below the window (i.e. other applications open on
the user's system).
* The window will not be transparent when DevTools is opened.
* On _Windows_:
* Transparent windows will not work when DWM is disabled.
* Transparent windows can not be maximized using the Windows system menu or by double
clicking the title bar. The reasoning behind this can be seen on
PR [#28207](https://github.com/electron/electron/pull/28207).
* On _macOS_:
* The native window shadow will not be shown on a transparent window.
## Create click-through windows
To create a click-through window, i.e. making the window ignore all mouse
events, you can call the [win.setIgnoreMouseEvents(ignore)][ignore-mouse-events]
API:
```javascript title='main.js'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.setIgnoreMouseEvents(true)
```
### Forward mouse events _macOS_ _Windows_
Ignoring mouse messages makes the web contents oblivious to mouse movement,
meaning that mouse movement events will not be emitted. On Windows and macOS, an
optional parameter can be used to forward mouse move messages to the web page,
allowing events such as `mouseleave` to be emitted:
```javascript title='main.js'
const { BrowserWindow, ipcMain } = require('electron')
const path = require('path')
const win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
ipcMain.on('set-ignore-mouse-events', (event, ...args) => {
const win = BrowserWindow.fromWebContents(event.sender)
win.setIgnoreMouseEvents(...args)
})
```
```javascript title='preload.js'
window.addEventListener('DOMContentLoaded', () => {
const el = document.getElementById('clickThroughElement')
el.addEventListener('mouseenter', () => {
ipcRenderer.send('set-ignore-mouse-events', true, { forward: true })
})
el.addEventListener('mouseleave', () => {
ipcRenderer.send('set-ignore-mouse-events', false)
})
})
```
This makes the web page click-through when over the `#clickThroughElement` element,
and returns to normal outside it.
## Set custom draggable region
By default, the frameless window is non-draggable. Apps need to specify
`-webkit-app-region: drag` in CSS to tell Electron which regions are draggable
(like the OS's standard titlebar), and apps can also use
`-webkit-app-region: no-drag` to exclude the non-draggable area from the
draggable region. Note that only rectangular shapes are currently supported.
To make the whole window draggable, you can add `-webkit-app-region: drag` as
`body`'s style:
```css title='styles.css'
body {
-webkit-app-region: drag;
}
```
And note that if you have made the whole window draggable, you must also mark
buttons as non-draggable, otherwise it would be impossible for users to click on
them:
```css title='styles.css'
button {
-webkit-app-region: no-drag;
}
```
If you're only setting a custom titlebar as draggable, you also need to make all
buttons in titlebar non-draggable.
### Tip: disable text selection
When creating a draggable region, the dragging behavior may conflict with text selection.
For example, when you drag the titlebar, you may accidentally select its text contents.
To prevent this, you need to disable text selection within a draggable area like this:
```css
.titlebar {
-webkit-user-select: none;
-webkit-app-region: drag;
}
```
### Tip: disable context menus
On some platforms, the draggable area will be treated as a non-client frame, so
when you right click on it, a system menu will pop up. To make the context menu
behave correctly on all platforms, you should never use a custom context menu on
draggable areas.
[`blur()`]: https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/blur()
[`BrowserWindow`]: ../api/browser-window.md
[chrome]: https://developer.mozilla.org/en-US/docs/Glossary/Chrome
[ignore-mouse-events]: ../api/browser-window.md#winsetignoremouseeventsignore-options
[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables
[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis
[Window Controls Overlay API]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md

View File

@@ -23,7 +23,6 @@ auto_filenames = {
"docs/api/environment-variables.md",
"docs/api/extensions.md",
"docs/api/file-object.md",
"docs/api/frameless-window.md",
"docs/api/global-shortcut.md",
"docs/api/in-app-purchase.md",
"docs/api/incoming-message.md",

View File

@@ -39,7 +39,8 @@ Object.assign(app, {
hasSwitch: (theSwitch: string) => commandLine.hasSwitch(String(theSwitch)),
getSwitchValue: (theSwitch: string) => commandLine.getSwitchValue(String(theSwitch)),
appendSwitch: (theSwitch: string, value?: string) => commandLine.appendSwitch(String(theSwitch), typeof value === 'undefined' ? value : String(value)),
appendArgument: (arg: string) => commandLine.appendArgument(String(arg))
appendArgument: (arg: string) => commandLine.appendArgument(String(arg)),
removeSwitch: (theSwitch: string) => commandLine.removeSwitch(String(theSwitch))
} as Electron.CommandLine
});

View File

@@ -593,6 +593,9 @@ WebContents.prototype._init = function () {
ipcMainInternal.emit(channel, event, ...args);
} else {
addReplyToEvent(event);
if (this.listenerCount('ipc-message-sync') === 0 && ipcMain.listenerCount(channel) === 0) {
console.warn(`WebContents #${this.id} called ipcRenderer.sendSync() with '${channel}' channel without listeners.`);
}
this.emit('ipc-message-sync', event, channel, ...args);
ipcMain.emit(channel, event, ...args);
}
@@ -666,16 +669,6 @@ WebContents.prototype._init = function () {
postBody
};
windowOpenOverriddenOptions = this._callWindowOpenHandler(event, details);
// if attempting to use this API with the deprecated new-window event,
// windowOpenOverriddenOptions will always return null. This ensures
// short-term backwards compatibility until new-window is removed.
const parsedFeatures = parseFeatures(rawFeatures);
const overriddenFeatures: BrowserWindowConstructorOptions = {
...parsedFeatures.options,
webPreferences: parsedFeatures.webPreferences
};
windowOpenOverriddenOptions = windowOpenOverriddenOptions || overriddenFeatures;
if (!event.defaultPrevented) {
const secureOverrideWebPreferences = windowOpenOverriddenOptions ? {
// Allow setting of backgroundColor as a webPreference even though
@@ -685,9 +678,19 @@ WebContents.prototype._init = function () {
transparent: windowOpenOverriddenOptions.transparent,
...windowOpenOverriddenOptions.webPreferences
} : undefined;
this._setNextChildWebPreferences(
makeWebPreferences({ embedder: event.sender, secureOverrideWebPreferences })
);
// TODO(zcbenz): The features string is parsed twice: here where it is
// passed to C++, and in |makeBrowserWindowOptions| later where it is
// not actually used since the WebContents is created here.
// We should be able to remove the latter once the |nativeWindowOpen|
// option is removed.
const { webPreferences: parsedWebPreferences } = parseFeatures(rawFeatures);
// Parameters should keep same with |makeBrowserWindowOptions|.
const webPreferences = makeWebPreferences({
embedder: event.sender,
insecureParsedWebPreferences: parsedWebPreferences,
secureOverrideWebPreferences
});
this._setNextChildWebPreferences(webPreferences);
}
});
@@ -735,6 +738,14 @@ WebContents.prototype._init = function () {
}
});
this.on('select-bluetooth-device', (event, devices, callback) => {
if (this.listenerCount('select-bluetooth-device') === 1) {
// Cancel it if there are no handlers
event.preventDefault();
callback('');
}
});
const event = process._linkedBinding('electron_browser_event').createEmpty();
app.emit('web-contents-created', event, this);

View File

@@ -7,7 +7,11 @@ WebFrameMain.prototype.send = function (channel, ...args) {
throw new Error('Missing required channel argument');
}
return this._send(false /* internal */, channel, args);
try {
return this._send(false /* internal */, channel, args);
} catch (e) {
console.error('Error sending from webFrameMain: ', e);
}
};
WebFrameMain.prototype._sendInternal = function (channel, ...args) {
@@ -15,7 +19,11 @@ WebFrameMain.prototype._sendInternal = function (channel, ...args) {
throw new Error('Missing required channel argument');
}
return this._send(true /* internal */, channel, args);
try {
return this._send(true /* internal */, channel, args);
} catch (e) {
console.error('Error sending from webFrameMain: ', e);
}
};
WebFrameMain.prototype.postMessage = function (...args) {

View File

@@ -28,6 +28,17 @@ function sanitizeOptionsForGuest (options: Record<string, any>) {
return ret;
}
function makeLoadURLOptions (params: Record<string, any>) {
const opts: Electron.LoadURLOptions = {};
if (params.httpreferrer) {
opts.httpReferrer = params.httpreferrer;
}
if (params.useragent) {
opts.userAgent = params.useragent;
}
return opts;
}
// Create a new guest instance.
const createGuest = function (embedder: Electron.WebContents, params: Record<string, any>) {
// eslint-disable-next-line no-undef
@@ -51,7 +62,7 @@ const createGuest = function (embedder: Electron.WebContents, params: Record<str
// Init guest web view after attached.
guest.once('did-attach' as any, function (this: Electron.WebContents, event: Electron.Event) {
params = this.attachParams!;
const params = this.attachParams!;
delete this.attachParams;
const previouslyAttached = this.viewInstanceId != null;
@@ -63,14 +74,7 @@ const createGuest = function (embedder: Electron.WebContents, params: Record<str
}
if (params.src) {
const opts: Electron.LoadURLOptions = {};
if (params.httpreferrer) {
opts.httpReferrer = params.httpreferrer;
}
if (params.useragent) {
opts.userAgent = params.useragent;
}
this.loadURL(params.src, opts);
this.loadURL(params.src, params.opts);
}
embedder.emit('did-attach-webview', event, guest);
});
@@ -149,13 +153,15 @@ const attachGuest = function (event: Electron.IpcMainInvokeEvent,
throw new Error(`Access denied to guestInstanceId: ${guestInstanceId}`);
}
const { instanceId } = params;
// If this guest is already attached to an element then remove it
if (guestInstance.elementInstanceId) {
const oldKey = `${guestInstance.embedder.id}-${guestInstance.elementInstanceId}`;
embedderElementsMap.delete(oldKey);
// Remove guest from embedder if moving across web views
if (guest.viewInstanceId !== params.instanceId) {
if (guest.viewInstanceId !== instanceId) {
webViewManager.removeGuest(guestInstance.embedder, guestInstanceId);
guestInstance.embedder._sendInternal(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${guest.viewInstanceId}`);
}
@@ -206,12 +212,12 @@ const attachGuest = function (event: Electron.IpcMainInvokeEvent,
embedder.emit('will-attach-webview', event, webPreferences, params);
if (event.defaultPrevented) {
if (guest.viewInstanceId == null) guest.viewInstanceId = params.instanceId;
if (guest.viewInstanceId == null) guest.viewInstanceId = instanceId;
guest.destroy();
return;
}
guest.attachParams = params;
guest.attachParams = { instanceId, src: params.src, opts: makeLoadURLOptions(params) };
embedderElementsMap.set(key, guestInstanceId);
guest.setEmbedder(embedder);

View File

@@ -65,8 +65,13 @@ export function openGuestWindow ({ event, embedder, guest, referrer, disposition
// https://html.spec.whatwg.org/multipage/window-object.html#apis-for-creating-and-navigating-browsing-contexts-by-name
const existingWindow = getGuestWindowByFrameName(frameName);
if (existingWindow) {
existingWindow.loadURL(url);
return existingWindow;
if (existingWindow.isDestroyed() || existingWindow.webContents.isDestroyed()) {
// FIXME(t57ser): The webContents is destroyed for some reason, unregister the frame name
unregisterFrameName(frameName);
} else {
existingWindow.loadURL(url);
return existingWindow;
}
}
const window = new BrowserWindow({
@@ -212,6 +217,10 @@ function makeBrowserWindowOptions ({ embedder, features, overrideOptions }: {
height: 600,
...parsedOptions,
...overrideOptions,
// Note that for |nativeWindowOpen: true| the WebContents is created in
// |api::WebContents::WebContentsCreatedWithFullParams|, with prefs
// parsed in the |-will-add-new-contents| event.
// The |webPreferences| here is only used by |nativeWindowOpen: false|.
webPreferences: makeWebPreferences({
embedder,
insecureParsedWebPreferences: parsedWebPreferences,

View File

@@ -39,6 +39,10 @@ ipcMainInternal.handle(IPC_MESSAGES.BROWSER_GET_LAST_WEB_PREFERENCES, function (
return event.sender.getLastWebPreferences();
});
ipcMainInternal.handle(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO, function (event) {
return event.sender._getProcessMemoryInfo();
});
// Methods not listed in this set are called directly in the renderer process.
const allowedClipboardMethods = (() => {
switch (process.platform) {

View File

@@ -4,6 +4,7 @@ export const enum IPC_MESSAGES {
BROWSER_PRELOAD_ERROR = 'BROWSER_PRELOAD_ERROR',
BROWSER_SANDBOX_LOAD = 'BROWSER_SANDBOX_LOAD',
BROWSER_WINDOW_CLOSE = 'BROWSER_WINDOW_CLOSE',
BROWSER_GET_PROCESS_MEMORY_INFO = 'BROWSER_GET_PROCESS_MEMORY_INFO',
GUEST_INSTANCE_VISIBILITY_CHANGE = 'GUEST_INSTANCE_VISIBILITY_CHANGE',

View File

@@ -1,19 +0,0 @@
export const enum IPC_MESSAGES {
BROWSER_REQUIRE = 'REMOTE_BROWSER_REQUIRE',
BROWSER_GET_BUILTIN = 'REMOTE_BROWSER_GET_BUILTIN',
BROWSER_GET_GLOBAL = 'REMOTE_BROWSER_GET_GLOBAL',
BROWSER_GET_CURRENT_WINDOW = 'REMOTE_BROWSER_GET_CURRENT_WINDOW',
BROWSER_GET_CURRENT_WEB_CONTENTS = 'REMOTE_BROWSER_GET_CURRENT_WEB_CONTENTS',
BROWSER_CONSTRUCTOR = 'REMOTE_BROWSER_CONSTRUCTOR',
BROWSER_FUNCTION_CALL = 'REMOTE_BROWSER_FUNCTION_CALL',
BROWSER_MEMBER_CONSTRUCTOR = 'REMOTE_BROWSER_MEMBER_CONSTRUCTOR',
BROWSER_MEMBER_CALL = 'REMOTE_BROWSER_MEMBER_CALL',
BROWSER_MEMBER_GET = 'REMOTE_BROWSER_MEMBER_GET',
BROWSER_MEMBER_SET = 'REMOTE_BROWSER_MEMBER_SET',
BROWSER_DEREFERENCE = 'REMOTE_BROWSER_DEREFERENCE',
BROWSER_CONTEXT_RELEASE = 'REMOTE_BROWSER_CONTEXT_RELEASE',
BROWSER_WRONG_CONTEXT_ERROR = 'REMOTE_BROWSER_WRONG_CONTEXT_ERROR',
RENDERER_CALLBACK = 'REMOTE_RENDERER_CALLBACK',
RENDERER_RELEASE_CALLBACK = 'REMOTE_RENDERER_RELEASE_CALLBACK',
}

View File

@@ -59,6 +59,10 @@ v8Util.setHiddenValue(global, 'ipcNative', {
}
});
process.getProcessMemoryInfo = () => {
return ipcRendererInternal.invoke<Electron.ProcessMemoryInfo>(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO);
};
// Use electron module after everything is ready.
const { webFrameInit } = require('@electron/internal/renderer/web-frame-init') as typeof webFrameInitModule;
webFrameInit();

View File

@@ -27,7 +27,6 @@ export class WebViewImpl {
public hasFocus = false
public internalInstanceId?: number;
public resizeObserver?: ResizeObserver;
public userAgentOverride?: string;
public viewInstanceId: number
// on* Event handlers.
@@ -180,8 +179,7 @@ export class WebViewImpl {
buildParams () {
const params: Record<string, any> = {
instanceId: this.viewInstanceId,
userAgentOverride: this.userAgentOverride
instanceId: this.viewInstanceId
};
for (const [attributeName, attribute] of this.attributes) {

View File

@@ -86,6 +86,10 @@ Object.assign(preloadProcess, processProps);
Object.assign(process, binding.process);
Object.assign(process, processProps);
process.getProcessMemoryInfo = preloadProcess.getProcessMemoryInfo = () => {
return ipcRendererInternal.invoke<Electron.ProcessMemoryInfo>(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO);
};
Object.defineProperty(preloadProcess, 'noDeprecation', {
get () {
return process.noDeprecation;

View File

@@ -22,7 +22,8 @@ if (isInstalled()) {
const platform = process.env.npm_config_platform || process.platform;
let arch = process.env.npm_config_arch || process.arch;
if (platform === 'darwin' && process.platform === 'darwin' && arch === 'x64') {
if (platform === 'darwin' && process.platform === 'darwin' && arch === 'x64' &&
process.env.npm_config_arch === undefined) {
// When downloading for macOS ON macOS and we think we need x64 we should
// check if we're running under rosetta and download the arm64 version if appropriate
try {

View File

@@ -1,6 +1,6 @@
{
"name": "electron",
"version": "15.1.1",
"version": "15.5.1",
"repository": "https://github.com/electron/electron",
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
"devDependencies": {
@@ -33,7 +33,7 @@
"asar": "^3.1.0",
"aws-sdk": "^2.727.1",
"check-for-leaks": "^1.2.1",
"colors": "^1.4.0",
"colors": "1.4.0",
"dotenv-safe": "^4.0.4",
"dugite": "^1.103.0",
"eslint": "^7.4.0",

14
patches/angle/.patches Normal file
View File

@@ -0,0 +1,14 @@
cherry-pick-bdffa0ea5148.patch
cherry-pick-05e69c75905f.patch
cherry-pick-891020ed64d4.patch
cherry-pick-2b98abd8cb6c.patch
cherry-pick-cc44ae61f37b.patch
vangle_change_the_default_vulkan_device_choose_logic.patch
m96_validate_samplerformat.patch
m98_vulkan_fix_vkcmdresolveimage_extents.patch
m98_vulkan_fix_vkcmdresolveimage_offsets.patch
cherry-pick-49e8ff16f1fe.patch
m99_vulkan_prevent_out_of_bounds_read_in_divisor_emulation_path.patch
m99_vulkan_streamvertexdatawithdivisor_write_beyond_buffer_boundary.patch
m98_protect_against_deleting_a_current_xfb_buffer.patch
m96-lts_vulkan_fix_issue_with_redefining_a_layered_attachment.patch

View File

@@ -0,0 +1,118 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lingfeng Yang <lfy@google.com>
Date: Wed, 1 Dec 2021 18:16:14 -0800
Subject: M96: Vulkan: remove staged updates on storage set
Previously we would allow staged updates to bigger versions of a texture
to go through even if the texture was redefined via glTexStorage*.
Bug: chromium:1262080
Change-Id: I9d861fed68d4a1fdcd0777b97caf729cc74c595e
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3312718
Reviewed-by: Charlie Lao <cclao@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Lingfeng Yang <lfy@google.com>
(cherry picked from commit 929c8ed4e8c3912cf027d843e7a2af47b21e5612)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3328001
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index e0be9676912e49d70473ffdcd4d7b1549210be25..b43f41dbae29356f1ffe4f961ed83e0f0e9cdcd2 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -1236,6 +1236,10 @@ angle::Result TextureVk::setStorageMultisample(const gl::Context *context,
{
releaseAndDeleteImageAndViews(contextVk);
}
+ else if (mImage)
+ {
+ mImage->releaseStagingBuffer(contextVk->getRenderer());
+ }
const vk::Format &format = renderer->getFormat(internalformat);
ANGLE_TRY(ensureImageAllocated(contextVk, format));
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index e79bc700d4991752289ff3d7c76f2ccbb3ba932a..a3dec629c9ea96b276ff8bf344d4a4628ff20b3b 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -9703,6 +9703,73 @@ void main()
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
}
+class TextureChangeStorageUploadTest : public ANGLETest
+{
+ protected:
+ TextureChangeStorageUploadTest()
+ {
+ setWindowWidth(256);
+ setWindowHeight(256);
+ setConfigRedBits(8);
+ setConfigGreenBits(8);
+ setConfigBlueBits(8);
+ setConfigAlphaBits(8);
+ }
+
+ void testSetUp() override
+ {
+ mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
+ if (mProgram == 0)
+ {
+ FAIL() << "shader compilation failed.";
+ }
+
+ mColorLocation = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform());
+
+ glUseProgram(mProgram);
+
+ glClearColor(0, 0, 0, 0);
+ glClearDepthf(0.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glEnable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+
+ glGenTextures(1, &mTexture);
+ ASSERT_GL_NO_ERROR();
+ }
+
+ void testTearDown() override
+ {
+ glDeleteTextures(1, &mTexture);
+ glDeleteProgram(mProgram);
+ }
+
+ GLuint mProgram;
+ GLint mColorLocation;
+ GLuint mTexture;
+};
+
+// Verify that respecifying storage and re-uploading doesn't crash.
+TEST_P(TextureChangeStorageUploadTest, Basic)
+{
+ constexpr int kImageSize = 8; // 4 doesn't trip ASAN
+ constexpr int kSmallerImageSize = kImageSize / 2;
+ EXPECT_GT(kImageSize, kSmallerImageSize);
+ EXPECT_GT(kSmallerImageSize / 2, 0);
+
+ std::array<GLColor, kImageSize * kImageSize> kColor;
+
+ glBindTexture(GL_TEXTURE_2D, mTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kImageSize, kImageSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kColor.data());
+ glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSmallerImageSize, kSmallerImageSize);
+ // need partial update to sidestep optimizations that remove the full upload
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSmallerImageSize / 2, kSmallerImageSize / 2, GL_RGBA,
+ GL_UNSIGNED_BYTE, kColor.data());
+ EXPECT_GL_NO_ERROR();
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
#define ES2_EMULATE_COPY_TEX_IMAGE() \
@@ -9816,4 +9883,6 @@ ANGLE_INSTANTIATE_TEST_ES31_AND(TextureBufferTestES31, WithDirectSPIRVGeneration
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CopyImageTestES31);
ANGLE_INSTANTIATE_TEST_ES31_AND(CopyImageTestES31, WithDirectSPIRVGeneration(ES31_VULKAN()));
+ANGLE_INSTANTIATE_TEST_ES3(TextureChangeStorageUploadTest);
+
} // anonymous namespace

View File

@@ -0,0 +1,96 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Tue, 30 Nov 2021 23:48:30 -0500
Subject: M96: Vulkan: Fix image respecify's usage tracking
When respecifying an image due to mip level count changes, the previous
image is staged as an update to the new image. The resource usage info
was not being transferred to the image being staged as an update,
causing it to be prematurely deleted.
Test based on one authored by sugoi@google.com.
Bug: chromium:1270658
Bug: angleproject:4835
Change-Id: I9810f8940e0107bc8a04fa3fb9c26a045c0d689c
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3318257
Reviewed-by: Lingfeng Yang <lfy@google.com>
diff --git a/src/libANGLE/renderer/vulkan/ResourceVk.cpp b/src/libANGLE/renderer/vulkan/ResourceVk.cpp
index efb04acf0fe5dc7c2d860ac8cc33dbe30691c4a3..e2cd1e3a96b1fa4e034efe6ed78ea1a787af6af6 100644
--- a/src/libANGLE/renderer/vulkan/ResourceVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ResourceVk.cpp
@@ -26,6 +26,12 @@ Resource::Resource(Resource &&other) : Resource()
mUse = std::move(other.mUse);
}
+Resource &Resource::operator=(Resource &&rhs)
+{
+ std::swap(mUse, rhs.mUse);
+ return *this;
+}
+
Resource::~Resource()
{
mUse.release();
diff --git a/src/libANGLE/renderer/vulkan/ResourceVk.h b/src/libANGLE/renderer/vulkan/ResourceVk.h
index 67440122bf7fa0f72b5412816853b2eddd770fd4..abab9900b7361c8564cb1ad30e0841eaf873ee2e 100644
--- a/src/libANGLE/renderer/vulkan/ResourceVk.h
+++ b/src/libANGLE/renderer/vulkan/ResourceVk.h
@@ -192,6 +192,7 @@ class Resource : angle::NonCopyable
protected:
Resource();
Resource(Resource &&other);
+ Resource &operator=(Resource &&rhs);
// Current resource lifetime.
SharedResourceUse mUse;
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
index a06b60d9c2c91280b925b12825e104bdbb757c05..893144ff07760dc1608a4b2d3af565e23ef27ba4 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
@@ -6140,6 +6140,9 @@ void ImageHelper::stageSelfAsSubresourceUpdates(ContextVk *contextVk,
// Move the necessary information for staged update to work, and keep the rest as part of this
// object.
+ // Usage info
+ prevImage->get().Resource::operator=(std::move(*this));
+
// Vulkan objects
prevImage->get().mImage = std::move(mImage);
prevImage->get().mDeviceMemory = std::move(mDeviceMemory);
diff --git a/src/tests/gl_tests/MipmapTest.cpp b/src/tests/gl_tests/MipmapTest.cpp
index 4db00e78a7d2f7375fdcb9228fbdc83395973125..8a6d01ca36a84a9e294de3f6f0114ee7a54e1d9a 100644
--- a/src/tests/gl_tests/MipmapTest.cpp
+++ b/src/tests/gl_tests/MipmapTest.cpp
@@ -2106,6 +2106,30 @@ TEST_P(MipmapTestES3, GenerateMipmapZeroSize)
glGenerateMipmap(GL_TEXTURE_3D);
}
+// Test that reducing the size of the mipchain by resizing the base image then deleting it doesn't
+// cause a crash. Issue found by fuzzer.
+TEST_P(MipmapTestES3, ResizeBaseMipTo1x1ThenDelete)
+{
+ GLTexture tex;
+ glBindTexture(GL_TEXTURE_2D, tex);
+
+ std::vector<GLColor> data(2, GLColor::blue);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
+
+ clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
+
+ data[0] = GLColor::green;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
+
+ clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
+
+ tex.reset();
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(MipmapTest);

View File

@@ -0,0 +1,381 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Tue, 25 Jan 2022 12:15:16 -0500
Subject: M99: Vulkan: Fix texture array level redefinition
When a level of a texture is redefined, all staged updates to that level
should be removed, not the ones specific to the new layers. The bug
fixed was that if the texture was redefined to have its number of layers
changed, the staged higher-layer-count update to the image was not
removed.
Bug: chromium:1289383
Change-Id: Iab79c38d846d1abbdd92e11b1b60a3adf0fbde4c
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3441309
Reviewed-by: Lingfeng Yang <lfy@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index b43f41dbae29356f1ffe4f961ed83e0f0e9cdcd2..610f720b68d37aaddf142b0dca538749386cef7e 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -1553,12 +1553,25 @@ angle::Result TextureVk::redefineLevel(const gl::Context *context,
if (mImage != nullptr)
{
- // If there is any staged changes for this index, we can remove them since we're going to
+ // If there are any staged changes for this index, we can remove them since we're going to
// override them with this call.
gl::LevelIndex levelIndexGL(index.getLevelIndex());
uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
- mImage->removeSingleSubresourceStagedUpdates(contextVk, levelIndexGL, layerIndex,
- index.getLayerCount());
+ if (gl::IsArrayTextureType(index.getType()))
+ {
+ // A multi-layer texture is being redefined, remove all updates to this level; the
+ // number of layers may have changed.
+ mImage->removeStagedUpdates(contextVk, levelIndexGL, levelIndexGL);
+ }
+ else
+ {
+ // Otherwise remove only updates to this layer. For example, cube map updates can be
+ // done through glTexImage2D, one per cube face (i.e. layer) and so should not remove
+ // updates to the other layers.
+ ASSERT(index.getLayerCount() == 1);
+ mImage->removeSingleSubresourceStagedUpdates(contextVk, levelIndexGL, layerIndex,
+ index.getLayerCount());
+ }
if (mImage->valid())
{
diff --git a/src/tests/gl_tests/MipmapTest.cpp b/src/tests/gl_tests/MipmapTest.cpp
index 8a6d01ca36a84a9e294de3f6f0114ee7a54e1d9a..957a52304edc9aa245f9f21e5557cc105cbad789 100644
--- a/src/tests/gl_tests/MipmapTest.cpp
+++ b/src/tests/gl_tests/MipmapTest.cpp
@@ -1686,6 +1686,106 @@ TEST_P(MipmapTestES3, MipmapsForTexture3D)
EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
}
+// Create a 2D array, then immediately redefine it to have fewer layers. Regression test for a bug
+// in the Vulkan backend where the old higher-layer-count data upload was not removed.
+TEST_P(MipmapTestES3, TextureArrayRedefineThenGenerateMipmap)
+{
+ int px = getWindowWidth() / 2;
+ int py = getWindowHeight() / 2;
+
+ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
+
+ // Fill the whole texture with red, then redefine it and fill with green
+ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
+ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsRed.data());
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsGreen.data());
+
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ EXPECT_GL_NO_ERROR();
+
+ // Generate mipmaps
+ glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
+ EXPECT_GL_NO_ERROR();
+
+ glUseProgram(mArrayProgram);
+ EXPECT_GL_NO_ERROR();
+
+ // Draw the first slice
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
+ drawQuad(mArrayProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+
+ // Draw the second slice
+ glUniform1i(mTextureArraySliceUniformLocation, 1);
+ drawQuad(mArrayProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+}
+
+// Create a 2D array, use it, then redefine it to have fewer layers. Regression test for a bug in
+// the Vulkan backend where the old higher-layer-count data upload was not removed.
+TEST_P(MipmapTestES3, TextureArrayUseThenRedefineThenGenerateMipmap)
+{
+ int px = getWindowWidth() / 2;
+ int py = getWindowHeight() / 2;
+
+ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
+
+ // Fill the whole texture with red.
+ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsRed.data());
+
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ EXPECT_GL_NO_ERROR();
+
+ // Generate mipmap
+ glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
+ EXPECT_GL_NO_ERROR();
+
+ glUseProgram(mArrayProgram);
+ EXPECT_GL_NO_ERROR();
+
+ // Draw the first slice
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
+ drawQuad(mArrayProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
+
+ // Draw the fourth slice
+ glUniform1i(mTextureArraySliceUniformLocation, 3);
+ drawQuad(mArrayProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
+
+ // Redefine the image and fill with green
+ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsGreen.data());
+
+ // Generate mipmap
+ glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
+ EXPECT_GL_NO_ERROR();
+
+ // Draw the first slice
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
+ drawQuad(mArrayProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+
+ // Draw the second slice
+ glUniform1i(mTextureArraySliceUniformLocation, 1);
+ drawQuad(mArrayProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+}
+
// Create a 2D texture with levels 0-2, call GenerateMipmap with base level 1 so that level 0 stays
// the same, and then sample levels 0 and 2.
// GLES 3.0.4 section 3.8.10:
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index 56bef0186234f59d370669c21f588ea9c5c356fc..772fe27daac3ac0b5f54b8319cef6aa9c980208a 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -1028,31 +1028,37 @@ class SamplerArrayAsFunctionParameterTest : public SamplerArrayTest
class Texture2DArrayTestES3 : public TexCoordDrawTest
{
protected:
- Texture2DArrayTestES3() : TexCoordDrawTest(), m2DArrayTexture(0), mTextureArrayLocation(-1) {}
+ Texture2DArrayTestES3()
+ : TexCoordDrawTest(),
+ m2DArrayTexture(0),
+ mTextureArrayLocation(-1),
+ mTextureArraySliceUniformLocation(-1)
+ {}
const char *getVertexShaderSource() override
{
- return "#version 300 es\n"
- "out vec2 texcoord;\n"
- "in vec4 position;\n"
- "void main()\n"
- "{\n"
- " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
- " texcoord = (position.xy * 0.5) + 0.5;\n"
- "}\n";
+ return R"(#version 300 es
+out vec2 texcoord;
+in vec4 position;
+void main()
+{
+ gl_Position = vec4(position.xy, 0.0, 1.0);
+ texcoord = (position.xy * 0.5) + 0.5;
+})";
}
const char *getFragmentShaderSource() override
{
- return "#version 300 es\n"
- "precision highp float;\n"
- "uniform highp sampler2DArray tex2DArray;\n"
- "in vec2 texcoord;\n"
- "out vec4 fragColor;\n"
- "void main()\n"
- "{\n"
- " fragColor = texture(tex2DArray, vec3(texcoord.x, texcoord.y, 0.0));\n"
- "}\n";
+ return R"(#version 300 es
+precision highp float;
+uniform highp sampler2DArray tex2DArray;
+uniform int slice;
+in vec2 texcoord;
+out vec4 fragColor;
+void main()
+{
+ fragColor = texture(tex2DArray, vec3(texcoord, float(slice)));
+})";
}
void testSetUp() override
@@ -1064,6 +1070,9 @@ class Texture2DArrayTestES3 : public TexCoordDrawTest
mTextureArrayLocation = glGetUniformLocation(mProgram, "tex2DArray");
ASSERT_NE(-1, mTextureArrayLocation);
+ mTextureArraySliceUniformLocation = glGetUniformLocation(mProgram, "slice");
+ ASSERT_NE(-1, mTextureArraySliceUniformLocation);
+
glGenTextures(1, &m2DArrayTexture);
ASSERT_GL_NO_ERROR();
}
@@ -1076,6 +1085,7 @@ class Texture2DArrayTestES3 : public TexCoordDrawTest
GLuint m2DArrayTexture;
GLint mTextureArrayLocation;
+ GLint mTextureArraySliceUniformLocation;
};
class TextureSizeTextureArrayTest : public TexCoordDrawTest
@@ -1718,28 +1728,28 @@ class Texture2DArrayIntegerTestES3 : public Texture2DArrayTestES3
const char *getVertexShaderSource() override
{
- return "#version 300 es\n"
- "out vec2 texcoord;\n"
- "in vec4 position;\n"
- "void main()\n"
- "{\n"
- " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
- " texcoord = (position.xy * 0.5) + 0.5;\n"
- "}\n";
+ return R"(#version 300 es
+out vec2 texcoord;
+in vec4 position;
+void main()
+{
+ gl_Position = vec4(position.xy, 0.0, 1.0);
+ texcoord = (position.xy * 0.5) + 0.5;
+})";
}
const char *getFragmentShaderSource() override
{
- return "#version 300 es\n"
- "precision highp float;\n"
- "uniform highp usampler2DArray tex2DArray;\n"
- "in vec2 texcoord;\n"
- "out vec4 fragColor;\n"
- "void main()\n"
- "{\n"
- " fragColor = vec4(texture(tex2DArray, vec3(texcoord.x, texcoord.y, "
- "0.0)))/255.0;\n"
- "}\n";
+ return R"(#version 300 es
+precision highp float;
+uniform highp usampler2DArray tex2DArray;
+uniform int slice;
+in vec2 texcoord;
+out vec4 fragColor;
+void main()
+{
+ fragColor = vec4(texture(tex2DArray, vec3(texcoord, slice)))/255.0;
+})";
}
};
@@ -5112,6 +5122,94 @@ TEST_P(Texture2DArrayTestES3, DrawWithLevelsOutsideRangeWithInconsistentDimensio
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
}
+// Create a 2D array, then immediately redefine it to have fewer layers. Regression test for a bug
+// in the Vulkan backend where the old higher-layer-count data upload was not removed.
+TEST_P(Texture2DArrayTestES3, TextureArrayRedefineThenUse)
+{
+ int px = getWindowWidth() / 2;
+ int py = getWindowHeight() / 2;
+
+ glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
+
+ // Fill the whole texture with red, then redefine it and fill with green
+ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
+ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsRed.data());
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsGreen.data());
+
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ EXPECT_GL_NO_ERROR();
+
+ glUseProgram(mProgram);
+ EXPECT_GL_NO_ERROR();
+
+ // Draw the first slice
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+
+ // Draw the second slice
+ glUniform1i(mTextureArraySliceUniformLocation, 1);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+}
+
+// Create a 2D array, use it, then redefine it to have fewer layers. Regression test for a bug in
+// the Vulkan backend where the old higher-layer-count data upload was not removed.
+TEST_P(Texture2DArrayTestES3, TextureArrayUseThenRedefineThenUse)
+{
+ int px = getWindowWidth() / 2;
+ int py = getWindowHeight() / 2;
+
+ glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
+
+ // Fill the whole texture with red.
+ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsRed.data());
+
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ EXPECT_GL_NO_ERROR();
+
+ glUseProgram(mProgram);
+ EXPECT_GL_NO_ERROR();
+
+ // Draw the first slice
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
+
+ // Draw the fourth slice
+ glUniform1i(mTextureArraySliceUniformLocation, 3);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
+
+ // Redefine the image and fill with green
+ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsGreen.data());
+
+ // Draw the first slice
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+
+ // Draw the second slice
+ glUniform1i(mTextureArraySliceUniformLocation, 1);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+}
+
// Test that texture completeness is updated if texture max level changes.
// GLES 3.0.4 section 3.8.13 Texture completeness
TEST_P(Texture2DTestES3, TextureCompletenessChangesWithMaxLevel)

View File

@@ -0,0 +1,163 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonah Ryan-Davis <jonahr@google.com>
Date: Mon, 22 Nov 2021 14:30:52 -0500
Subject: Ignore the pixel unpack state for compressed textures.
From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding
a compressed texture image
This was causing a bad access when calling compressedTexImage3D
with GL_UNPACK_IMAGE_HEIGHT greater than the image height.
Bug: chromium:1267496
Change-Id: I9b1f4c645548af64f2695fd23262225a1ad07cd7
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3296622
Commit-Queue: Jonah Ryan-Davis <jonahr@google.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
(cherry picked from commit 870f458f507ff7ba0f67b28a30a27955ce79dd3e)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3309097
Reviewed-by: Jonah Ryan-Davis <jonahr@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index c4ce77d612d88a898f8a8164466d25b210e2144b..eb60719ac38543b608c122daebd71b1084ac35f2 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -4961,7 +4961,9 @@ void Context::compressedTexImage2D(TextureTarget target,
Extents size(width, height, 1);
Texture *texture = getTextureByTarget(target);
- ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, mState.getUnpackState(), target, level,
+ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture
+ // image. So we use an empty PixelUnpackState.
+ ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, PixelUnpackState(), target, level,
internalformat, size, imageSize,
static_cast<const uint8_t *>(data)));
}
@@ -4993,7 +4995,9 @@ void Context::compressedTexImage3D(TextureTarget target,
Extents size(width, height, depth);
Texture *texture = getTextureByTarget(target);
- ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, mState.getUnpackState(), target, level,
+ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture
+ // image. So we use an empty PixelUnpackState.
+ ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, PixelUnpackState(), target, level,
internalformat, size, imageSize,
static_cast<const uint8_t *>(data)));
}
@@ -5027,8 +5031,10 @@ void Context::compressedTexSubImage2D(TextureTarget target,
Box area(xoffset, yoffset, 0, width, height, 1);
Texture *texture = getTextureByTarget(target);
- ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, mState.getUnpackState(), target, level,
- area, format, imageSize,
+ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture
+ // image. So we use an empty PixelUnpackState.
+ ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, PixelUnpackState(), target, level, area,
+ format, imageSize,
static_cast<const uint8_t *>(data)));
}
@@ -5069,8 +5075,10 @@ void Context::compressedTexSubImage3D(TextureTarget target,
Box area(xoffset, yoffset, zoffset, width, height, depth);
Texture *texture = getTextureByTarget(target);
- ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, mState.getUnpackState(), target, level,
- area, format, imageSize,
+ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture
+ // image. So we use an empty PixelUnpackState.
+ ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, PixelUnpackState(), target, level, area,
+ format, imageSize,
static_cast<const uint8_t *>(data)));
}
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index a3dec629c9ea96b276ff8bf344d4a4628ff20b3b..ba512a11cb023d9caae666ab2634d1e66057d12c 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -5151,6 +5151,43 @@ TEST_P(Texture2DTestES3, TextureCompletenessChangesWithMaxLevel)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
}
+// Test that compressed textures ignore the pixel unpack state.
+// (https://crbug.org/1267496)
+TEST_P(Texture3DTestES3, PixelUnpackStateTexImage)
+{
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") &&
+ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3"));
+
+ glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 5);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture3D);
+
+ uint8_t data[64] = {0};
+ glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 4, 0, 64,
+ data);
+ EXPECT_GL_NO_ERROR();
+}
+
+// Test that compressed textures ignore the pixel unpack state.
+// (https://crbug.org/1267496)
+TEST_P(Texture3DTestES3, PixelUnpackStateTexSubImage)
+{
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") &&
+ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3"));
+
+ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture3D);
+
+ uint8_t data[64] = {0};
+ glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 4, 0, 64,
+ data);
+ EXPECT_GL_NO_ERROR();
+
+ glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 5);
+
+ glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 4, 4, 4,
+ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 64, data);
+ EXPECT_GL_NO_ERROR();
+}
+
// Test that 3D texture completeness is updated if texture max level changes.
// GLES 3.0.4 section 3.8.13 Texture completeness
TEST_P(Texture3DTestES3, Texture3DCompletenessChangesWithMaxLevel)
@@ -5830,6 +5867,41 @@ TEST_P(Texture2DTestES3, TextureCOMPRESSEDSRGB8ETC2ImplicitAlpha1)
EXPECT_PIXEL_ALPHA_EQ(0, 0, 255);
}
+// Test that compressed textures ignore the pixel unpack state.
+// (https://crbug.org/1267496)
+TEST_P(Texture2DTestES3, PixelUnpackStateTexImage)
+{
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") &&
+ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3"));
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 5);
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+
+ uint8_t data[16] = {0};
+ glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 0, 16, data);
+ EXPECT_GL_NO_ERROR();
+}
+
+// Test that compressed textures ignore the pixel unpack state.
+// (https://crbug.org/1267496)
+TEST_P(Texture2DTestES3, PixelUnpackStateTexSubImage)
+{
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") &&
+ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3"));
+
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+
+ uint8_t data[16] = {0};
+ glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 0, 16, data);
+ EXPECT_GL_NO_ERROR();
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 5);
+
+ glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 16,
+ data);
+ EXPECT_GL_NO_ERROR();
+}
+
// Copied from Texture2DTest::TexStorage
// Test that glTexSubImage2D works properly when glTexStorage2DEXT has initialized the image with a
// default color.

View File

@@ -0,0 +1,169 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Thu, 2 Dec 2021 14:30:42 -0500
Subject: M96: Fix changing attached renderbuffer from MSRTT to non-MSRTT
FramebufferAttachment::mRenderToTextureSamples was never updated if the
renderbuffer storage was changed after attaching to framebuffer.
Bug: chromium:1272068
Change-Id: Icddbb5650354ea16d06c49532d6a8d0ae962ab5f
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3320923
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/FramebufferAttachment.cpp b/src/libANGLE/FramebufferAttachment.cpp
index 00714d0a0303050893abcd9564e760b22d9b2de5..720d3000d42e6c8c23214e66eee4aa6982216a60 100644
--- a/src/libANGLE/FramebufferAttachment.cpp
+++ b/src/libANGLE/FramebufferAttachment.cpp
@@ -129,7 +129,7 @@ void FramebufferAttachment::attach(const Context *context,
mNumViews = numViews;
mBaseViewIndex = baseViewIndex;
mIsMultiview = isMultiview;
- mRenderToTextureSamples = samples;
+ mRenderToTextureSamples = type == GL_RENDERBUFFER ? kDefaultRenderToTextureSamples : samples;
resource->onAttach(context, framebufferSerial);
if (mResource != nullptr)
@@ -222,6 +222,29 @@ GLint FramebufferAttachment::getBaseViewIndex() const
return mBaseViewIndex;
}
+bool FramebufferAttachment::isRenderToTexture() const
+{
+ ASSERT(mRenderToTextureSamples == kDefaultRenderToTextureSamples || mType == GL_TEXTURE);
+
+ if (mType == GL_RENDERBUFFER)
+ {
+ return getRenderbuffer()->getMultisamplingMode() ==
+ MultisamplingMode::MultisampledRenderToTexture;
+ }
+ return mRenderToTextureSamples != kDefaultRenderToTextureSamples;
+}
+
+GLsizei FramebufferAttachment::getRenderToTextureSamples() const
+{
+ ASSERT(mRenderToTextureSamples == kDefaultRenderToTextureSamples || mType == GL_TEXTURE);
+
+ if (mType == GL_RENDERBUFFER)
+ {
+ return getRenderbuffer()->getState().getSamples();
+ }
+ return mRenderToTextureSamples;
+}
+
Texture *FramebufferAttachment::getTexture() const
{
return rx::GetAs<Texture>(mResource);
diff --git a/src/libANGLE/FramebufferAttachment.h b/src/libANGLE/FramebufferAttachment.h
index 7ebf5f5e620cfac47be176fa0bc668353e923104..a5d5bf0eb0c50e37656b241d105be3f35a657585 100644
--- a/src/libANGLE/FramebufferAttachment.h
+++ b/src/libANGLE/FramebufferAttachment.h
@@ -117,11 +117,8 @@ class FramebufferAttachment final
bool isMultiview() const;
GLint getBaseViewIndex() const;
- bool isRenderToTexture() const
- {
- return mRenderToTextureSamples != kDefaultRenderToTextureSamples;
- }
- GLsizei getRenderToTextureSamples() const { return mRenderToTextureSamples; }
+ bool isRenderToTexture() const;
+ GLsizei getRenderToTextureSamples() const;
// The size of the underlying resource the attachment points to. The 'depth' value will
// correspond to a 3D texture depth or the layer count of a 2D array texture. For Surfaces and
@@ -195,6 +192,14 @@ class FramebufferAttachment final
GLsizei mNumViews;
bool mIsMultiview;
GLint mBaseViewIndex;
+ // A single-sampled texture can be attached to a framebuffer either as single-sampled or as
+ // multisampled-render-to-texture. In the latter case, |mRenderToTextureSamples| will contain
+ // the number of samples. For renderbuffers, the number of samples is inherited from the
+ // renderbuffer itself.
+ //
+ // Note that textures cannot change storage between single and multisample once attached to a
+ // framebuffer. Renderbuffers instead can, and caching the number of renderbuffer samples here
+ // can lead to stale data.
GLsizei mRenderToTextureSamples;
};
@@ -254,8 +259,7 @@ inline Format FramebufferAttachment::getFormat() const
inline GLsizei FramebufferAttachment::getSamples() const
{
- return (mRenderToTextureSamples != kDefaultRenderToTextureSamples) ? getRenderToTextureSamples()
- : getResourceSamples();
+ return isRenderToTexture() ? getRenderToTextureSamples() : getResourceSamples();
}
inline GLsizei FramebufferAttachment::getResourceSamples() const
diff --git a/src/tests/gl_tests/FramebufferTest.cpp b/src/tests/gl_tests/FramebufferTest.cpp
index ff01848daff091d92e4fdce08bc6842a3bdd3ee9..cd733be3ae5c179860d882e305ec84d093a283ed 100644
--- a/src/tests/gl_tests/FramebufferTest.cpp
+++ b/src/tests/gl_tests/FramebufferTest.cpp
@@ -3366,6 +3366,65 @@ void main() {
// This shouldn't crash.
glDrawArrays(GL_POINTS, 0, 1);
+ ASSERT_GL_NO_ERROR();
+}
+
+// Modify renderbuffer attachment samples after bind
+TEST_P(FramebufferTest_ES3, BindRenderbufferThenModifySamples)
+{
+ ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
+ glUseProgram(program);
+ GLint colorUniformLocation =
+ glGetUniformLocation(program, angle::essl1_shaders::ColorUniform());
+ ASSERT_NE(colorUniformLocation, -1);
+
+ GLFramebuffer fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ GLsizei size = 16;
+ glViewport(0, 0, size, size);
+
+ GLRenderbuffer color;
+ glBindRenderbuffer(GL_RENDERBUFFER, color);
+
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, size, size);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, size, size);
+
+ glUniform4f(colorUniformLocation, 1, 0, 0, 1);
+ drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
+ ASSERT_GL_NO_ERROR();
+}
+
+// Modify renderbuffer attachment size after bind
+TEST_P(FramebufferTest_ES3, BindRenderbufferThenModifySize)
+{
+ ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
+ glUseProgram(program);
+ GLint colorUniformLocation =
+ glGetUniformLocation(program, angle::essl1_shaders::ColorUniform());
+ ASSERT_NE(colorUniformLocation, -1);
+
+ GLFramebuffer fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ GLsizei size = 16;
+ glViewport(0, 0, size, size);
+
+ GLRenderbuffer color;
+ glBindRenderbuffer(GL_RENDERBUFFER, color);
+
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, size, size);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, size / 2, size * 2);
+
+ glUniform4f(colorUniformLocation, 1, 0, 0, 1);
+ drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
+ ASSERT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST_ES2(AddMockTextureNoRenderTargetTest);

View File

@@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jamie Madill <jmadill@chromium.org>
Date: Tue, 4 Jan 2022 12:28:55 -0500
Subject: M96: D3D11: Fix OOB access in vertex conversion code.
This could happen when using certain combinations of stride and
offset. Fix the issue by using checked math.
Bug: chromium:1274499
Change-Id: I3e286a30fe128ab4684ee5e172dc9e3345e3b2f4
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3365657
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/VertexDataManager.cpp b/src/libANGLE/renderer/d3d/VertexDataManager.cpp
index 43fcdc8de5a0d15aacf4b06e0e32df008d78f886..031a12e2b8b0e0dee91087c02cbd2f8b17435a2b 100644
--- a/src/libANGLE/renderer/d3d/VertexDataManager.cpp
+++ b/src/libANGLE/renderer/d3d/VertexDataManager.cpp
@@ -58,17 +58,15 @@ int ElementsInBuffer(const gl::VertexAttribute &attrib,
const gl::VertexBinding &binding,
unsigned int size)
{
- // Size cannot be larger than a GLsizei
- if (size > static_cast<unsigned int>(std::numeric_limits<int>::max()))
- {
- size = static_cast<unsigned int>(std::numeric_limits<int>::max());
- }
+ angle::CheckedNumeric<size_t> bufferSize(size);
+ angle::CheckedNumeric<size_t> stride = ComputeVertexAttributeStride(attrib, binding);
+ angle::CheckedNumeric<size_t> offset = ComputeVertexAttributeOffset(attrib, binding);
+ angle::CheckedNumeric<size_t> elementSize = ComputeVertexAttributeTypeSize(attrib);
+
+ auto elementsInBuffer = (bufferSize - (offset % stride) + (stride - elementSize)) / stride;
+ auto elementsInBufferInt = angle::CheckedNumeric<int>::cast(elementsInBuffer);
- GLsizei stride = static_cast<GLsizei>(ComputeVertexAttributeStride(attrib, binding));
- GLsizei offset = static_cast<GLsizei>(ComputeVertexAttributeOffset(attrib, binding));
- return (size - offset % stride +
- (stride - static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib)))) /
- stride;
+ return elementsInBufferInt.ValueOrDefault(0);
}
// Warning: you should ensure binding really matches attrib.bindingIndex before using this function.

View File

@@ -0,0 +1,94 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jamie Madill <jmadill@chromium.org>
Date: Tue, 1 Mar 2022 15:40:38 -0500
Subject: Vulkan: Fix issue with redefining a layered attachment.
The fix ensures we complete level redefinition before we get the
layer render target in TextureVk::getAttachmentRenderTarget.
Bug: chromium:1296866
Change-Id: Id7fa8e9fed5e766c30580b09336713c675c4e4f0
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3498283
Commit-Queue: Jamie Madill <jmadill@chromium.org>
(cherry picked from commit 348ece42552a99cff88f79c80652b9dd3155ab22)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3513754
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index 610f720b68d37aaddf142b0dca538749386cef7e..569118e7137e8ea6dc02cc6247980c2198bf92db 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -2174,6 +2174,15 @@ angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context,
ContextVk *contextVk = vk::GetImpl(context);
+ if (mRedefinedLevels.any())
+ {
+ // If we have redefined levels, we must flush those out to fix the render targets.
+ ANGLE_TRY(respecifyImageStorage(contextVk));
+ }
+
+ // Otherwise, don't flush staged updates here. We'll handle that in FramebufferVk so we can
+ // defer clears.
+
if (!mImage->valid())
{
// Immutable texture must already have a valid image
@@ -2217,8 +2226,6 @@ angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context,
mState.getType(), samples, *mImage, useRobustInit));
}
- // Don't flush staged updates here. We'll handle that in FramebufferVk so it can defer clears.
-
GLuint layerIndex = 0, layerCount = 0, imageLayerCount = 0;
GetRenderTargetLayerCountAndIndex(mImage, imageIndex, &layerIndex, &layerCount,
&imageLayerCount);
@@ -2229,10 +2236,14 @@ angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context,
gl::LevelIndex(imageIndex.getLevelIndex()),
renderToTextureIndex);
- ASSERT(imageIndex.getLevelIndex() <
- static_cast<int32_t>(mSingleLayerRenderTargets[renderToTextureIndex].size()));
- *rtOut = &mSingleLayerRenderTargets[renderToTextureIndex][imageIndex.getLevelIndex()]
- [layerIndex];
+ std::vector<RenderTargetVector> &levelRenderTargets =
+ mSingleLayerRenderTargets[renderToTextureIndex];
+ ASSERT(imageIndex.getLevelIndex() < static_cast<int32_t>(levelRenderTargets.size()));
+
+ RenderTargetVector &layerRenderTargets = levelRenderTargets[imageIndex.getLevelIndex()];
+ ASSERT(imageIndex.getLayerIndex() < static_cast<int32_t>(layerRenderTargets.size()));
+
+ *rtOut = &layerRenderTargets[layerIndex];
}
else
{
diff --git a/src/tests/gl_tests/FramebufferTest.cpp b/src/tests/gl_tests/FramebufferTest.cpp
index cd733be3ae5c179860d882e305ec84d093a283ed..c0b745978ae5d28d97bb833f7fe6278872d8d620 100644
--- a/src/tests/gl_tests/FramebufferTest.cpp
+++ b/src/tests/gl_tests/FramebufferTest.cpp
@@ -3427,6 +3427,25 @@ TEST_P(FramebufferTest_ES3, BindRenderbufferThenModifySize)
ASSERT_GL_NO_ERROR();
}
+// Tests redefining a layered framebuffer attachment.
+TEST_P(FramebufferTest_ES3, RedefineLayerAttachment)
+{
+ GLTexture texture;
+ glBindTexture(GL_TEXTURE_3D, texture);
+ std::vector<uint8_t> imgData(20480, 0);
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_R8, 8, 8, 8, 0, GL_RED, GL_UNSIGNED_BYTE, imgData.data());
+
+ GLFramebuffer fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 8);
+ glGenerateMipmap(GL_TEXTURE_3D);
+
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_R8UI, 16, 16, 16, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE,
+ imgData.data());
+ glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 2, 2, 15, 16, 16);
+ ASSERT_GL_NO_ERROR();
+}
+
ANGLE_INSTANTIATE_TEST_ES2(AddMockTextureNoRenderTargetTest);
ANGLE_INSTANTIATE_TEST_ES2(FramebufferTest);
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(FramebufferFormatsTest);

View File

@@ -0,0 +1,115 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lingfeng Yang <lfy@google.com>
Date: Wed, 1 Dec 2021 17:08:01 -0800
Subject: M96: Validate SamplerFormat
We weren't validating sampler formats in ProgramExecutable validation.
Bug: chromium:1273661
Change-Id: Ida0c67c0c7169ea3f47ceb2d433bee17012a7e5e
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3312717
Reviewed-by: Charlie Lao <cclao@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Lingfeng Yang <lfy@google.com>
(cherry picked from commit 6d3435fddd7abd67699c3f020d6b4fa21445d9b3)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3335173
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/src/libANGLE/ProgramExecutable.cpp b/src/libANGLE/ProgramExecutable.cpp
index baf63ecec6f82fda9dd79a1c398b8e95ec70e321..14e5abdfab36a95f39839fc171e6e0bc3a5dc6e9 100644
--- a/src/libANGLE/ProgramExecutable.cpp
+++ b/src/libANGLE/ProgramExecutable.cpp
@@ -1132,6 +1132,19 @@ bool ProgramExecutable::validateSamplersImpl(InfoLog *infoLog, const Caps &caps)
mCachedValidateSamplersResult = false;
return false;
}
+
+ if (mActiveSamplerFormats[textureUnit] == SamplerFormat::InvalidEnum)
+ {
+ if (infoLog)
+ {
+ (*infoLog) << "Samplers of conflicting formats refer to the same texture "
+ "image unit ("
+ << textureUnit << ").";
+ }
+
+ mCachedValidateSamplersResult = false;
+ return false;
+ }
}
mCachedValidateSamplersResult = true;
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index ba512a11cb023d9caae666ab2634d1e66057d12c..56bef0186234f59d370669c21f588ea9c5c356fc 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -9796,8 +9796,6 @@ class TextureChangeStorageUploadTest : public ANGLETest
FAIL() << "shader compilation failed.";
}
- mColorLocation = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform());
-
glUseProgram(mProgram);
glClearColor(0, 0, 0, 0);
@@ -9842,6 +9840,53 @@ TEST_P(TextureChangeStorageUploadTest, Basic)
EXPECT_GL_NO_ERROR();
}
+class ExtraSamplerCubeShadowUseTest : public ANGLETest
+{
+ protected:
+ ExtraSamplerCubeShadowUseTest() : ANGLETest() {}
+
+ const char *getVertexShaderSource() { return "#version 300 es\nvoid main() {}"; }
+
+ const char *getFragmentShaderSource()
+ {
+ return R"(#version 300 es
+precision mediump float;
+
+uniform mediump samplerCube var_0002; // this has to be there
+uniform highp samplerCubeShadow var_0004; // this has to be a cube shadow sampler
+out vec4 color;
+void main() {
+
+ vec4 var_0031 = texture(var_0002, vec3(1,1,1));
+ ivec2 size = textureSize(var_0004, 0) ;
+ var_0031.x += float(size.y);
+
+ color = var_0031;
+})";
+ }
+
+ void testSetUp() override
+ {
+ mProgram = CompileProgram(getVertexShaderSource(), getFragmentShaderSource());
+ if (mProgram == 0)
+ {
+ FAIL() << "shader compilation failed.";
+ }
+ glUseProgram(mProgram);
+ ASSERT_GL_NO_ERROR();
+ }
+
+ void testTearDown() override { glDeleteProgram(mProgram); }
+
+ GLuint mProgram;
+};
+
+TEST_P(ExtraSamplerCubeShadowUseTest, Basic)
+{
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 3);
+ EXPECT_GL_ERROR(GL_INVALID_OPERATION);
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
#define ES2_EMULATE_COPY_TEX_IMAGE() \
@@ -9957,4 +10002,6 @@ ANGLE_INSTANTIATE_TEST_ES31_AND(CopyImageTestES31, WithDirectSPIRVGeneration(ES3
ANGLE_INSTANTIATE_TEST_ES3(TextureChangeStorageUploadTest);
+ANGLE_INSTANTIATE_TEST_ES3(ExtraSamplerCubeShadowUseTest);
+
} // anonymous namespace

View File

@@ -0,0 +1,109 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jamie Madill <jmadill@chromium.org>
Date: Tue, 1 Mar 2022 16:14:47 -0500
Subject: Protect against deleting a current XFB buffer.
Bug: chromium:1295411
Change-Id: I097f272c38e444e0af71aa55c0dc508a07aa0bd3
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3498262
Reviewed-by: Amirali Abdolrashidi <abdolrashidi@google.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
(cherry picked from commit d9002eef2a5f27fc5d6b65d01d02afcfb9a35db1)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3514175
Reviewed-by: Ian Elliott <ianelliott@google.com>
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
index 8ec1eca3f4bc70da39c838a0f81664043276bc80..182709c348f7490e1ee990a05570c13d7e9d0dd7 100644
--- a/src/libANGLE/State.cpp
+++ b/src/libANGLE/State.cpp
@@ -2115,6 +2115,10 @@ angle::Result State::detachBuffer(Context *context, const Buffer *buffer)
if (curTransformFeedback)
{
ANGLE_TRY(curTransformFeedback->detachBuffer(context, bufferID));
+ if (isTransformFeedbackActiveUnpaused())
+ {
+ context->getStateCache().onActiveTransformFeedbackChange(context);
+ }
}
if (getVertexArray()->detachBuffer(context, bufferID))
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 4c1ec1fc73746e2aba97ea83da5e8bcbd0b41ba5..d5732741dff989b8b8f6f669511bf7bc001c4eaa 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -3948,6 +3948,14 @@ const char *ValidateDrawStates(const Context *context)
return kTessellationShaderRequiresBothControlAndEvaluation;
}
}
+
+ if (state.isTransformFeedbackActiveUnpaused())
+ {
+ if (!ValidateProgramExecutableXFBBuffersPresent(context, executable))
+ {
+ return kTransformFeedbackBufferMissing;
+ }
+ }
}
if (programIsYUVOutput != framebufferIsYUV)
@@ -8055,4 +8063,21 @@ bool ValidateInvalidateTextureANGLE(const Context *context, TextureType target)
return true;
}
+bool ValidateProgramExecutableXFBBuffersPresent(const Context *context,
+ const ProgramExecutable *programExecutable)
+{
+ size_t programXfbCount = programExecutable->getTransformFeedbackBufferCount();
+ const TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
+ for (size_t programXfbIndex = 0; programXfbIndex < programXfbCount; ++programXfbIndex)
+ {
+ const OffsetBindingPointer<Buffer> &buffer =
+ transformFeedback->getIndexedBuffer(programXfbIndex);
+ if (!buffer.get())
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
} // namespace gl
diff --git a/src/libANGLE/validationES.h b/src/libANGLE/validationES.h
index f7daadb3de4d0a28f1896bad54bdc59f31a45cd3..934a35f6557462fd8da52fd7de7aba0ee5186dff 100644
--- a/src/libANGLE/validationES.h
+++ b/src/libANGLE/validationES.h
@@ -755,6 +755,9 @@ bool ValidateGetMultisamplefvBase(const Context *context,
const GLfloat *val);
bool ValidateSampleMaskiBase(const Context *context, GLuint maskNumber, GLbitfield mask);
+bool ValidateProgramExecutableXFBBuffersPresent(const Context *context,
+ const ProgramExecutable *programExecutable);
+
// We should check with Khronos if returning INVALID_FRAMEBUFFER_OPERATION is OK when querying
// implementation format info for incomplete framebuffers. It seems like these queries are
// incongruent with the other errors.
diff --git a/src/libANGLE/validationES3.cpp b/src/libANGLE/validationES3.cpp
index f385ef623cc56658dc5f840ddd3f3c3bf9bf3e05..1523cd5f0093b7b4b03bf0cd5432ee0a15f17dab 100644
--- a/src/libANGLE/validationES3.cpp
+++ b/src/libANGLE/validationES3.cpp
@@ -2786,16 +2786,10 @@ bool ValidateBeginTransformFeedback(const Context *context, PrimitiveMode primit
return false;
}
- size_t programXfbCount = programExecutable->getTransformFeedbackBufferCount();
- for (size_t programXfbIndex = 0; programXfbIndex < programXfbCount; ++programXfbIndex)
+ if (!ValidateProgramExecutableXFBBuffersPresent(context, programExecutable))
{
- const OffsetBindingPointer<Buffer> &buffer =
- transformFeedback->getIndexedBuffer(programXfbIndex);
- if (!buffer.get())
- {
- context->validationError(GL_INVALID_OPERATION, kTransformFeedbackBufferMissing);
- return false;
- }
+ context->validationError(GL_INVALID_OPERATION, kTransformFeedbackBufferMissing);
+ return false;
}
return true;

View File

@@ -0,0 +1,112 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Mon, 31 Jan 2022 12:07:43 -0500
Subject: M98: Vulkan: Fix vkCmdResolveImage extents
The source framebuffer's extents were accidentally used instead of the
blit area extents.
Bug: chromium:1288020
Change-Id: I5c6128a191deeea2f972dc7f010be9d40c674ce6
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3457022
Reviewed-by: Tim Van Patten <timvp@google.com>
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
index 4f7428217a130482dbbee760d32f183cee2255f6..ac4c4086c28be29a65386ef06cc103d14dfb0d48 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
@@ -1459,8 +1459,8 @@ angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
resolveRegion.dstOffset.x = params.destOffset[0];
resolveRegion.dstOffset.y = params.destOffset[1];
resolveRegion.dstOffset.z = 0;
- resolveRegion.extent.width = params.srcExtents[0];
- resolveRegion.extent.height = params.srcExtents[1];
+ resolveRegion.extent.width = params.blitArea.width;
+ resolveRegion.extent.height = params.blitArea.height;
resolveRegion.extent.depth = 1;
vk::PerfCounters &perfCounters = contextVk->getPerfCounters();
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
index 5712456966c3a77ba73295c083888ad0ab821a78..b9a0423345ba3a19e425a0b7ba7985ca191fdae7 100644
--- a/src/tests/angle_end2end_tests_expectations.txt
+++ b/src/tests/angle_end2end_tests_expectations.txt
@@ -70,6 +70,7 @@
// the test says. The test also fails on Intel/Vulkan/Windows.
6068 INTEL VULKAN : MultiviewRenderPrimitiveTest.LineLoop/* = SKIP
6068 INTEL VULKAN : MultiviewRenderPrimitiveTest.LineStrip/* = SKIP
+6962 WIN INTEL VULKAN : BlitFramebufferTestES31.PartialResolve/* = SKIP
// Mac
6025 MAC AMD OPENGL : IndexBufferOffsetTestES3.UseAsUBOThenUpdateThenUInt8Index/* = SKIP
diff --git a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
index affed96be99a8e0b819919ce971968168c546ca1..22356a7c65339fe8b1e601f54a3491ea77237432 100644
--- a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
+++ b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
@@ -2637,6 +2637,67 @@ TEST_P(BlitFramebufferTest, BlitDepthStencilPixelByPixel)
EXPECT_PIXEL_RECT_EQ(64, 0, 128, 1, GLColor::blue);
}
+// Regression test for a bug in the Vulkan backend where vkCmdResolveImage was using the src extents
+// as the resolve area instead of the area passed to glBlitFramebuffer.
+TEST_P(BlitFramebufferTestES31, PartialResolve)
+{
+ constexpr GLint kWidth = 16;
+ constexpr GLint kHeight = 32;
+
+ // Read framebuffer is multisampled.
+ GLTexture readTexture;
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, readTexture);
+ glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kWidth, kHeight, GL_TRUE);
+
+ GLFramebuffer readFbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, readFbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
+ readTexture, 0);
+ ASSERT_GL_NO_ERROR();
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ glClearColor(1, 0, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Draw framebuffer is single sampled. It's bound to a texture with base level the same size as
+ // the read framebuffer, but it's bound to mip 1.
+ GLTexture drawTexture;
+ glBindTexture(GL_TEXTURE_2D, drawTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ nullptr);
+ glGenerateMipmap(GL_TEXTURE_2D);
+
+ GLFramebuffer drawFbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, drawFbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, drawTexture, 1);
+ ASSERT_GL_NO_ERROR();
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ glClearColor(0, 1, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth / 2, kHeight / 2, GLColor::green);
+
+ constexpr GLint kResolveX0 = 1;
+ constexpr GLint kResolveY0 = 2;
+ constexpr GLint kResolveX1 = 4;
+ constexpr GLint kResolveY1 = 6;
+
+ // Resolve only a portion of the read framebuffer.
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo);
+ glBlitFramebuffer(kResolveX0, kResolveY0, kResolveX1, kResolveY1, kResolveX0, kResolveY0,
+ kResolveX1, kResolveY1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ ASSERT_GL_NO_ERROR();
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, drawFbo);
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth / 2, kResolveY0, GLColor::green);
+ EXPECT_PIXEL_RECT_EQ(0, 0, kResolveX0, kHeight / 2, GLColor::green);
+ EXPECT_PIXEL_RECT_EQ(kResolveX1, 0, kWidth / 2 - kResolveX1, kHeight / 2, GLColor::green);
+ EXPECT_PIXEL_RECT_EQ(0, kResolveY1, kWidth / 2, kHeight / 2 - kResolveY1, GLColor::green);
+
+ EXPECT_PIXEL_RECT_EQ(kResolveX0, kResolveY0, kResolveX1 - kResolveX0, kResolveY1 - kResolveY0,
+ GLColor::red);
+}
+
// Test that a draw call to a small FBO followed by a resolve of a large FBO works.
TEST_P(BlitFramebufferTestES31, DrawToSmallFBOThenResolveLargeFBO)
{

View File

@@ -0,0 +1,109 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Mon, 7 Feb 2022 13:46:46 -0500
Subject: M98: Vulkan: Fix vkCmdResolveImage offsets
glBlitFramebuffer takes identical regions for src and dst when
resolving. vkCmdResolveImage should use the clipped area instead of
using the actual offsets passed to this function.
Bug: chromium:1292537
Change-Id: If283a8acbca3249b771facbc30bd9f8080a03656
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3457023
Reviewed-by: Tim Van Patten <timvp@google.com>
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
index ac4c4086c28be29a65386ef06cc103d14dfb0d48..45308e0261b48eed17d144169b698165b04422f9 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
@@ -1451,13 +1451,13 @@ angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
resolveRegion.srcSubresource.mipLevel = 0;
resolveRegion.srcSubresource.baseArrayLayer = params.srcLayer;
resolveRegion.srcSubresource.layerCount = 1;
- resolveRegion.srcOffset.x = params.srcOffset[0];
- resolveRegion.srcOffset.y = params.srcOffset[1];
+ resolveRegion.srcOffset.x = params.blitArea.x;
+ resolveRegion.srcOffset.y = params.blitArea.y;
resolveRegion.srcOffset.z = 0;
resolveRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
resolveRegion.dstSubresource.layerCount = 1;
- resolveRegion.dstOffset.x = params.destOffset[0];
- resolveRegion.dstOffset.y = params.destOffset[1];
+ resolveRegion.dstOffset.x = params.blitArea.x;
+ resolveRegion.dstOffset.y = params.blitArea.y;
resolveRegion.dstOffset.z = 0;
resolveRegion.extent.width = params.blitArea.width;
resolveRegion.extent.height = params.blitArea.height;
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
index b9a0423345ba3a19e425a0b7ba7985ca191fdae7..0646a12afacc16fd7df938e615976a28b6da6ab0 100644
--- a/src/tests/angle_end2end_tests_expectations.txt
+++ b/src/tests/angle_end2end_tests_expectations.txt
@@ -15,6 +15,8 @@
6142 VULKAN : BlitFramebufferTest.BlitDepthStencilPixelByPixel/* = SKIP
6153 VULKAN WIN INTEL : GLSLTest_ES31.StructAndArrayEqualOperator/ES3_1_Vulkan_DirectSPIRVGen = SKIP
6153 VULKAN PIXEL4ORXL : GLSLTest_ES31.StructAndArrayEqualOperator/ES3_1_Vulkan_DirectSPIRVGen = SKIP
+6989 OPENGL : BlitFramebufferTestES31.OOBResolve/* = SKIP
+6989 GLES : BlitFramebufferTestES31.OOBResolve/* = SKIP
// Direct SPIR-V generation. The following tests pass on some platforms but not others. Need to investigate.
4889 VULKAN : GeometryShaderTest.LayeredFramebufferPreRenderClear2DArrayColor/ES3_1_Vulkan_DirectSPIRVGen = SKIP
diff --git a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
index 22356a7c65339fe8b1e601f54a3491ea77237432..697cfcc8e10db571a407c0e44da36583614f2cb8 100644
--- a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
+++ b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
@@ -2637,6 +2637,55 @@ TEST_P(BlitFramebufferTest, BlitDepthStencilPixelByPixel)
EXPECT_PIXEL_RECT_EQ(64, 0, 128, 1, GLColor::blue);
}
+// Regression test for a bug in the Vulkan backend where vkCmdResolveImage was used with
+// out-of-bounds regions.
+TEST_P(BlitFramebufferTestES31, OOBResolve)
+{
+ constexpr GLint kWidth = 16;
+ constexpr GLint kHeight = 32;
+
+ // Read framebuffer is multisampled.
+ GLTexture readTexture;
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, readTexture);
+ glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kWidth, kHeight, GL_TRUE);
+
+ GLFramebuffer readFbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, readFbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
+ readTexture, 0);
+ ASSERT_GL_NO_ERROR();
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ glClearColor(1, 0, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Draw framebuffer is single sampled.
+ GLTexture drawTexture;
+ glBindTexture(GL_TEXTURE_2D, drawTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ nullptr);
+ glGenerateMipmap(GL_TEXTURE_2D);
+
+ GLFramebuffer drawFbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, drawFbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, drawTexture, 0);
+ ASSERT_GL_NO_ERROR();
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ glClearColor(0, 1, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::green);
+
+ // Resolve the read framebuffer, using bounds that are outside the size of the image.
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo);
+ glBlitFramebuffer(-kWidth * 2, -kHeight * 3, kWidth * 11, kHeight * 8, -kWidth * 2,
+ -kHeight * 3, kWidth * 11, kHeight * 8, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ ASSERT_GL_NO_ERROR();
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, drawFbo);
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::red);
+}
+
// Regression test for a bug in the Vulkan backend where vkCmdResolveImage was using the src extents
// as the resolve area instead of the area passed to glBlitFramebuffer.
TEST_P(BlitFramebufferTestES31, PartialResolve)

View File

@@ -0,0 +1,303 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Roman Lavrov <romanl@google.com>
Date: Tue, 18 Jan 2022 20:05:55 +0000
Subject: M99: Vulkan: Prevent out of bounds read in divisor emulation path.
Split the replicated part of StreamVertexData out to
StreamVertexDataWithDivisor, there is only a partial argument
overlap between the two.
Bug: chromium:1285885
Change-Id: Ibf6ab3efc6b12b430b1d391c6ae61bd9668b4407
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3398816
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Roman Lavrov <romanl@google.com>
(cherry picked from commit 5f0badf4541ba52659c937cfe9190d3735a76c10)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3461414
diff --git a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
index ed416508cab06797a8c4d52e7ab982d538f57e3c..1ca486af3ff004e11aea82c391b4c504b569096c 100644
--- a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
+++ b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
@@ -81,34 +81,62 @@ angle::Result StreamVertexData(ContextVk *contextVk,
size_t destOffset,
size_t vertexCount,
size_t sourceStride,
- size_t destStride,
VertexCopyFunction vertexLoadFunction,
vk::BufferHelper **bufferOut,
- VkDeviceSize *bufferOffsetOut,
- uint32_t replicateCount)
+ VkDeviceSize *bufferOffsetOut)
{
uint8_t *dst = nullptr;
ANGLE_TRY(dynamicBuffer->allocate(contextVk, bytesToAllocate, &dst, nullptr, bufferOffsetOut,
nullptr));
*bufferOut = dynamicBuffer->getCurrentBuffer();
dst += destOffset;
- if (replicateCount == 1)
+ vertexLoadFunction(sourceData, sourceStride, vertexCount, dst);
+
+ ANGLE_TRY(dynamicBuffer->flush(contextVk));
+ return angle::Result::Continue;
+}
+
+angle::Result StreamVertexDataWithDivisor(ContextVk *contextVk,
+ vk::DynamicBuffer *dynamicBuffer,
+ const uint8_t *sourceData,
+ size_t bytesToAllocate,
+ size_t sourceStride,
+ size_t destStride,
+ VertexCopyFunction vertexLoadFunction,
+ vk::BufferHelper **bufferOut,
+ VkDeviceSize *bufferOffsetOut,
+ uint32_t divisor,
+ size_t numSrcVertices)
+{
+ uint8_t *dst = nullptr;
+ ANGLE_TRY(dynamicBuffer->allocate(contextVk, bytesToAllocate, &dst, nullptr, bufferOffsetOut,
+ nullptr));
+ *bufferOut = dynamicBuffer->getCurrentBuffer();
+
+ // Each source vertex is used `divisor` times before advancing. Clamp to avoid OOB reads.
+ size_t clampedSize = std::min(numSrcVertices * destStride * divisor, bytesToAllocate);
+
+ ASSERT(clampedSize % destStride == 0);
+ ASSERT(divisor > 0);
+
+ uint32_t sourceVertexUseCount = 0;
+ for (size_t dataCopied = 0; dataCopied < clampedSize; dataCopied += destStride, dst += destStride)
{
- vertexLoadFunction(sourceData, sourceStride, vertexCount, dst);
+ vertexLoadFunction(sourceData, sourceStride, 1, dst);
+ sourceVertexUseCount++;
+ if (sourceVertexUseCount == divisor)
+ {
+ sourceData += sourceStride;
+ sourceVertexUseCount = 0;
+ }
}
- else
+
+ // Satisfy robustness constraints (only if extension enabled)
+ if (contextVk->getExtensions().robustness)
{
- ASSERT(replicateCount > 1);
- uint32_t sourceRemainingCount = replicateCount - 1;
- for (size_t dataCopied = 0; dataCopied < bytesToAllocate;
- dataCopied += destStride, dst += destStride, sourceRemainingCount--)
+ if (clampedSize < bytesToAllocate)
{
- vertexLoadFunction(sourceData, sourceStride, 1, dst);
- if (sourceRemainingCount == 0)
- {
- sourceData += sourceStride;
- sourceRemainingCount = replicateCount;
- }
+ memset(dst + clampedSize, 0, bytesToAllocate - clampedSize);
}
}
@@ -124,6 +152,7 @@ size_t GetVertexCount(BufferVk *srcBuffer, const gl::VertexBinding &binding, uin
return 0;
// Count the last vertex. It may occupy less than a full stride.
+ // This is also correct if stride happens to be less than srcFormatSize.
size_t numVertices = 1;
bytes -= srcFormatSize;
@@ -452,8 +481,8 @@ angle::Result VertexArrayVk::convertVertexBufferCPU(ContextVk *contextVk,
ASSERT(GetVertexInputAlignment(vertexFormat, compressed) <= vk::kVertexBufferAlignment);
ANGLE_TRY(StreamVertexData(
contextVk, &conversion->data, srcBytes, numVertices * dstFormatSize, 0, numVertices,
- binding.getStride(), srcFormatSize, vertexFormat.getVertexLoadFunction(compressed),
- &mCurrentArrayBuffers[attribIndex], &conversion->lastAllocationOffset, 1));
+ binding.getStride(), vertexFormat.getVertexLoadFunction(compressed),
+ &mCurrentArrayBuffers[attribIndex], &conversion->lastAllocationOffset));
ANGLE_TRY(srcBuffer->unmapImpl(contextVk));
ASSERT(conversion->dirty);
@@ -808,28 +837,41 @@ angle::Result VertexArrayVk::updateStreamedAttribs(const gl::Context *context,
// Instanced attrib
if (divisor > renderer->getMaxVertexAttribDivisor())
{
- // Emulated attrib
- BufferVk *bufferVk = nullptr;
+ // Divisor will be set to 1 & so update buffer to have 1 attrib per instance
+ size_t bytesToAllocate = instanceCount * stride;
+
if (binding.getBuffer().get() != nullptr)
{
// Map buffer to expand attribs for divisor emulation
- bufferVk = vk::GetImpl(binding.getBuffer().get());
- void *buffSrc = nullptr;
+ BufferVk *bufferVk = vk::GetImpl(binding.getBuffer().get());
+ void *buffSrc = nullptr;
ANGLE_TRY(bufferVk->mapImpl(contextVk, &buffSrc));
src = reinterpret_cast<const uint8_t *>(buffSrc) + binding.getOffset();
- }
- // Divisor will be set to 1 & so update buffer to have 1 attrib per instance
- size_t bytesToAllocate = instanceCount * stride;
- ANGLE_TRY(StreamVertexData(contextVk, &mDynamicVertexData, src, bytesToAllocate, 0,
- instanceCount, binding.getStride(), stride,
- vertexFormat.vertexLoadFunction,
- &mCurrentArrayBuffers[attribIndex],
- &mCurrentArrayBufferOffsets[attribIndex], divisor));
- if (bufferVk)
- {
+ uint32_t srcAttributeSize =
+ static_cast<uint32_t>(ComputeVertexAttributeTypeSize(attrib));
+
+ size_t numVertices = GetVertexCount(bufferVk, binding, srcAttributeSize);
+
+ ANGLE_TRY(StreamVertexDataWithDivisor(
+ contextVk, &mDynamicVertexData, src, bytesToAllocate, binding.getStride(),
+ stride, vertexFormat.vertexLoadFunction,
+ &mCurrentArrayBuffers[attribIndex],
+ &mCurrentArrayBufferOffsets[attribIndex], divisor,
+ numVertices));
+
ANGLE_TRY(bufferVk->unmapImpl(contextVk));
}
+ else
+ {
+ size_t numVertices = instanceCount;
+ ANGLE_TRY(StreamVertexDataWithDivisor(
+ contextVk, &mDynamicVertexData, src, bytesToAllocate, binding.getStride(),
+ stride, vertexFormat.vertexLoadFunction,
+ &mCurrentArrayBuffers[attribIndex],
+ &mCurrentArrayBufferOffsets[attribIndex], divisor,
+ numVertices));
+ }
}
else
{
@@ -838,10 +880,10 @@ angle::Result VertexArrayVk::updateStreamedAttribs(const gl::Context *context,
size_t bytesToAllocate = count * stride;
ANGLE_TRY(StreamVertexData(contextVk, &mDynamicVertexData, src, bytesToAllocate, 0,
- count, binding.getStride(), stride,
+ count, binding.getStride(),
vertexFormat.vertexLoadFunction,
&mCurrentArrayBuffers[attribIndex],
- &mCurrentArrayBufferOffsets[attribIndex], 1));
+ &mCurrentArrayBufferOffsets[attribIndex]));
}
}
else
@@ -856,8 +898,8 @@ angle::Result VertexArrayVk::updateStreamedAttribs(const gl::Context *context,
ANGLE_TRY(StreamVertexData(
contextVk, &mDynamicVertexData, src, bytesToAllocate, destOffset, vertexCount,
- binding.getStride(), stride, vertexFormat.vertexLoadFunction,
- &mCurrentArrayBuffers[attribIndex], &mCurrentArrayBufferOffsets[attribIndex], 1));
+ binding.getStride(), vertexFormat.vertexLoadFunction,
+ &mCurrentArrayBuffers[attribIndex], &mCurrentArrayBufferOffsets[attribIndex]));
}
mCurrentArrayBufferHandles[attribIndex] =
diff --git a/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp b/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp
index 08917a2de3385eb853bced1dd576aff46f34f709..db708b0a2a3ce90a370b43786af6884b2f992bef 100644
--- a/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp
+++ b/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp
@@ -564,6 +564,98 @@ TEST_P(RobustBufferAccessBehaviorTest, DynamicBuffer)
}
}
+// Tests out of bounds read by divisor emulation due to a user-provided offset.
+// Adapted from https://crbug.com/1285885.
+TEST_P(RobustBufferAccessBehaviorTest, IndexOutOfBounds)
+{
+ ANGLE_SKIP_TEST_IF(!initExtension());
+
+ constexpr char kVS[] = R"(precision highp float;
+attribute vec4 a_position;
+void main(void) {
+ gl_Position = a_position;
+})";
+
+ constexpr char kFS[] = R"(precision highp float;
+uniform sampler2D oTexture;
+uniform float oColor[3];
+void main(void) {
+ gl_FragData[0] = texture2DProj(oTexture, vec3(0.1,0.1,0.1));
+})";
+
+ GLfloat singleFloat = 1.0f;
+
+ GLBuffer buf;
+ glBindBuffer(GL_ARRAY_BUFFER, buf);
+ glBufferData(GL_ARRAY_BUFFER, 4, &singleFloat, GL_STATIC_DRAW);
+
+ ANGLE_GL_PROGRAM(program, kVS, kFS);
+ glBindAttribLocation(program, 0, "a_position");
+ glLinkProgram(program);
+ ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
+
+ glEnableVertexAttribArray(0);
+
+ // Trying to exceed renderer->getMaxVertexAttribDivisor()
+ GLuint constexpr kDivisor = 4096;
+ glVertexAttribDivisor(0, kDivisor);
+
+ size_t outOfBoundsOffset = 0x50000000;
+ glVertexAttribPointer(0, 1, GL_FLOAT, false, 8, reinterpret_cast<void *>(outOfBoundsOffset));
+
+ glUseProgram(program);
+
+ glDrawArrays(GL_TRIANGLES, 0, 32);
+
+ // No assertions, just checking for crashes.
+}
+
+// Similar to the test above but index is first within bounds then goes out of bounds.
+TEST_P(RobustBufferAccessBehaviorTest, IndexGoingOutOfBounds)
+{
+ ANGLE_SKIP_TEST_IF(!initExtension());
+
+ constexpr char kVS[] = R"(precision highp float;
+attribute vec4 a_position;
+void main(void) {
+ gl_Position = a_position;
+})";
+
+ constexpr char kFS[] = R"(precision highp float;
+uniform sampler2D oTexture;
+uniform float oColor[3];
+void main(void) {
+ gl_FragData[0] = texture2DProj(oTexture, vec3(0.1,0.1,0.1));
+})";
+
+ GLBuffer buf;
+ glBindBuffer(GL_ARRAY_BUFFER, buf);
+ std::array<GLfloat, 2> buffer = {{0.2f, 0.2f}};
+ glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * buffer.size(), buffer.data(), GL_STATIC_DRAW);
+
+ ANGLE_GL_PROGRAM(program, kVS, kFS);
+ glBindAttribLocation(program, 0, "a_position");
+ glLinkProgram(program);
+ ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
+
+ glEnableVertexAttribArray(0);
+
+ // Trying to exceed renderer->getMaxVertexAttribDivisor()
+ GLuint constexpr kDivisor = 4096;
+ glVertexAttribDivisor(0, kDivisor);
+
+ // 6 bytes remaining in the buffer from offset so only a single vertex can be read
+ glVertexAttribPointer(0, 1, GL_FLOAT, false, 8, reinterpret_cast<void *>(2));
+
+ glUseProgram(program);
+
+ // Each vertex is read `kDivisor` times so the last read goes out of bounds
+ GLsizei instanceCount = kDivisor + 1;
+ glDrawArraysInstanced(GL_TRIANGLES, 0, 32, instanceCount);
+
+ // No assertions, just checking for crashes.
+}
+
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND_ES31(RobustBufferAccessBehaviorTest);
} // namespace

View File

@@ -0,0 +1,51 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Charlie Lao <cclao@google.com>
Date: Mon, 7 Feb 2022 15:08:15 -0800
Subject: M99: Vulkan: StreamVertexDataWithDivisor write beyond buffer boundary
StreamVertexDataWithDivisor() function is advancing dst with dstStride,
but then later on it is treating dst as if it never advanced, thus
result in write out of buffer boundary. This was hidden by VMA's memory
suballocation, which means it may result in some rendering artifacts.
Bug: angleproject:6990
Change-Id: Ic91e917cedd247dfe85b12a69ae26b21b7a4e67a
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3445528
Reviewed-by: Roman Lavrov <romanl@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Charlie Lao <cclao@google.com>
(cherry picked from commit 5204587698099207ce8ae70779ef44ffae877996)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3461417
Reviewed-by: Charlie Lao <cclao@google.com>
Commit-Queue: Roman Lavrov <romanl@google.com>
diff --git a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
index 1ca486af3ff004e11aea82c391b4c504b569096c..93378c4b24495872405fc06ea01e15254229ab63 100644
--- a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
+++ b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
@@ -120,7 +120,7 @@ angle::Result StreamVertexDataWithDivisor(ContextVk *contextVk,
ASSERT(divisor > 0);
uint32_t sourceVertexUseCount = 0;
- for (size_t dataCopied = 0; dataCopied < clampedSize; dataCopied += destStride, dst += destStride)
+ for (size_t dataCopied = 0; dataCopied < clampedSize; dataCopied += destStride)
{
vertexLoadFunction(sourceData, sourceStride, 1, dst);
sourceVertexUseCount++;
@@ -129,6 +129,7 @@ angle::Result StreamVertexDataWithDivisor(ContextVk *contextVk,
sourceData += sourceStride;
sourceVertexUseCount = 0;
}
+ dst += destStride;
}
// Satisfy robustness constraints (only if extension enabled)
@@ -136,7 +137,7 @@ angle::Result StreamVertexDataWithDivisor(ContextVk *contextVk,
{
if (clampedSize < bytesToAllocate)
{
- memset(dst + clampedSize, 0, bytesToAllocate - clampedSize);
+ memset(dst, 0, bytesToAllocate - clampedSize);
}
}

View File

@@ -0,0 +1,81 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peng Huang <penghuang@chromium.org>
Date: Mon, 25 Oct 2021 15:45:36 -0400
Subject: VANGLE: change the default vulkan device choose logic
To match the vulkan device choose logic in chrome, ANGLE will choose
the default device based on the order of (discret GPU > integrated GPU
> other GPU)
TODO: for long term, ANGLE should provide a way to let chrome specify
the physical device.
Bug: chromium:1260869
Change-Id: Id023138485eb65fcc1d2758103d59a4e6cb2a51d
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3242963
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Peng Huang <penghuang@chromium.org>
diff --git a/src/common/vulkan/vulkan_icd.cpp b/src/common/vulkan/vulkan_icd.cpp
index 0ed7ae2aa058792b700503dfdb6fd91b05bf68fb..df14f5f674b37c49332e43ccba8f1782cb13f495 100644
--- a/src/common/vulkan/vulkan_icd.cpp
+++ b/src/common/vulkan/vulkan_icd.cpp
@@ -11,6 +11,7 @@
#include <functional>
#include <vector>
+#include "common/Optional.h"
#include "common/bitset_utils.h"
#include "common/debug.h"
#include "common/system_utils.h"
@@ -94,8 +95,7 @@ ICDFilterFunc GetFilterForICD(vk::ICD preferredICD)
const std::string anglePreferredDevice =
angle::GetEnvironmentVar(kANGLEPreferredDeviceEnv);
return [anglePreferredDevice](const VkPhysicalDeviceProperties &deviceProperties) {
- return (anglePreferredDevice.empty() ||
- anglePreferredDevice == deviceProperties.deviceName);
+ return (anglePreferredDevice == deviceProperties.deviceName);
};
}
}
@@ -262,9 +262,37 @@ void ChoosePhysicalDevice(const std::vector<VkPhysicalDevice> &physicalDevices,
return;
}
}
- WARN() << "Preferred device ICD not found. Using default physicalDevice instead.";
- // Fall back to first device.
+ Optional<VkPhysicalDevice> integratedDevice;
+ VkPhysicalDeviceProperties integratedDeviceProperties;
+ for (const VkPhysicalDevice &physicalDevice : physicalDevices)
+ {
+ vkGetPhysicalDeviceProperties(physicalDevice, physicalDevicePropertiesOut);
+ // If discrete GPU exists, uses it by default.
+ if (physicalDevicePropertiesOut->deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
+ {
+ *physicalDeviceOut = physicalDevice;
+ return;
+ }
+ if (physicalDevicePropertiesOut->deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU &&
+ !integratedDevice.valid())
+ {
+ integratedDevice = physicalDevice;
+ integratedDeviceProperties = *physicalDevicePropertiesOut;
+ continue;
+ }
+ }
+
+ // If only integrated GPU exists, use it by default.
+ if (integratedDevice.valid())
+ {
+ *physicalDeviceOut = integratedDevice.value();
+ *physicalDevicePropertiesOut = integratedDeviceProperties;
+ return;
+ }
+
+ WARN() << "Preferred device ICD not found. Using default physicalDevice instead.";
+ // Fallback to the first device.
*physicalDeviceOut = physicalDevices[0];
vkGetPhysicalDeviceProperties(*physicalDeviceOut, physicalDevicePropertiesOut);
}

View File

@@ -104,3 +104,65 @@ don_t_run_pcscan_notifythreadcreated_if_pcscan_is_disabled.patch
logging_win32_only_create_a_console_if_logging_to_stderr.patch
feat_expose_raw_response_headers_from_urlloader.patch
fix_media_key_usage_with_globalshortcuts.patch
cherry-pick-ec42dfd3545f.patch
cherry-pick-39090918efac.patch
add_ui_scopedcliboardwriter_writeunsaferawdata.patch
mas_gate_private_enterprise_APIs.patch
cherry-pick-8af66de55aad.patch
cherry-pick-c69dddfe1cde.patch
cherry-pick-2e7c9b33453b.patch
move_networkstateobserver_from_document_to_window.patch
cherry-pick-0894af410c4e.patch
cherry-pick-91dd4f79ab5b.patch
introduce_crossthreadcopier_skbitmap.patch
allow_null_skbitmap_to_be_transferred_across_threads.patch
use_weakptrs_for_the_threadediconloader_s_background_tasks.patch
cherry-pick-1a8af2da50e4.patch
cherry-pick-a5f54612590d.patch
cachestorage_store_partial_opaque_responses.patch
fix_aspect_ratio_with_max_size.patch
cherry-pick-f0a63e1f361f.patch
cherry-pick-27eb11a28555.patch
sandbox_fix_sandbox_inheritance_m96_merge.patch
cherry-pick-da11d71a0227.patch
cherry-pick-dbde8795233a.patch
cherry-pick-6bb320d134b1.patch
cherry-pick-109fde1088be.patch
m96_fileapi_move_origin_checks_in_bloburlstore_sooner.patch
cherry-pick-f781748dcb3c.patch
cherry-pick-c5571653d932.patch
fix_crash_when_saving_edited_pdf_files.patch
use_axnodeid_rather_than_axnode_in_axeventgenerator_tree_events.patch
mojo_reject_addbrokerclient_on_non-broker_nodes.patch
cherry-pick-1277917.patch
cherry-pick-1281979.patch
cherry-pick-1282354.patch
cherry-pick-1283198.patch
cherry-pick-1283375.patch
cherry-pick-1283371.patch
cherry-pick-9db9911e1242.patch
cherry-pick-1284367.patch
m97_webcodecs_various_decodertemplate_shutdown_cleanups.patch
96_take_local_copy_of_ump_local_sources_to_iterate.patch
pin_scrolltop_to_0_during_autofill_preview.patch
fix_preview_state_detection.patch
do_not_select_vulkan_device_based_on_the_passed_in_gpu_info_on_linux.patch
handle_potentiallydanglingmarkup_for_cssimagevalue.patch
fire_iframe_onload_for_cross-origin-initiated_same-document.patch
merge_m-97_serial_check_for_detached_buffers_when_writing.patch
cleanup_pausablecriptexecutor_usage.patch
m98_fs_fix_fileutil_lifetime_issue.patch
cherry-pick-be50c60b4225.patch
cherry-pick-ebc188ad769e.patch
cherry-pick-e3805f29fed7.patch
cherry-pick-0081bb347e67.patch
cherry-pick-62142d222a80.patch
cherry-pick-1887414c016d.patch
cherry-pick-6b2643846ae3.patch
cherry-pick-905302eb3a2b.patch
cherry-pick-246c10dede97.patch
fix_imagebitmaprenderingcontext_interaction_with_software_compositor.patch
remove_incorrect_width_height_adjustments.patch
fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch
fixed_terminate_caused_by_binding_to_wrong_version.patch
follow_wayland_specification_regarding_xkb_keymap.patch

View File

@@ -0,0 +1,53 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tony Herre <toprice@chromium.org>
Date: Tue, 14 Dec 2021 16:35:05 +0000
Subject: Take local copy of UMP::local_sources to iterate
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Take a local copy of UserMediaProcessor::local_sources_ when iterating
over it in UserMediaProcessor::DetermineExistingAudioSessionId, as the
list can be effectively concurrently modified during destruction of
MediaStreamTracks triggered by GC during this loop. Without the copy
this leads to a container overflow.
(cherry picked from commit fb6232ffb1fec14d64ec8815f7dfc2cea0887588)
Bug: 1238209
Change-Id: I048387a51a58eacff87d220e6b67d2d09f610c1d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3320283
Reviewed-by: Henrik Boström <hbos@chromium.org>
Commit-Queue: Tony Herre <toprice@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#950499}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3337896
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
Cr-Commit-Position: refs/branch-heads/4664@{#1303}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
index d42b3d7309ce40e74ebf386f4d38eb8cce008ec0..b0b8b15657210174b000a02f711a76fa16e5948d 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
@@ -725,6 +725,7 @@ void UserMediaProcessor::SelectAudioSettings(
absl::optional<base::UnguessableToken>
UserMediaProcessor::DetermineExistingAudioSessionId() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(current_request_info_->request()->Audio());
auto settings = current_request_info_->audio_capture_settings();
@@ -733,7 +734,12 @@ UserMediaProcessor::DetermineExistingAudioSessionId() {
// Create a copy of the MediaStreamSource objects that are
// associated to the same audio device capture based on its device ID.
HeapVector<Member<MediaStreamSource>> matching_sources;
- for (const auto& source : local_sources_) {
+
+ // Take a defensive copy, as local_sources_ can be modified during
+ // destructions in GC runs triggered by the push_back allocation in this loop.
+ // crbug.com/1238209
+ HeapVector<Member<MediaStreamSource>> local_sources_copy = local_sources_;
+ for (const auto& source : local_sources_copy) {
MediaStreamSource* source_copy = source;
if (source_copy->GetType() == MediaStreamSource::kTypeAudio &&
source_copy->Id().Utf8() == device_id) {

View File

@@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Henri Torgemane <henrit@gmail.com>
Date: Thu, 23 Sep 2021 21:30:33 -0500
Subject: add ui::ScopedCliboardWriter::WriteUnsafeRawData
This restores some ability to write to the clipboard using raw formats, which
was removed as part of the Raw Clipboard API scrubbing.
https://bugs.chromium.org/p/chromium/issues/detail?id=1217643
diff --git a/ui/base/clipboard/scoped_clipboard_writer.cc b/ui/base/clipboard/scoped_clipboard_writer.cc
index 153f169d2cdef6f8a726c188283a5bc1b7395fa3..3a5d9ab8dafacafb1025e1cb8c157e8a82078424 100644
--- a/ui/base/clipboard/scoped_clipboard_writer.cc
+++ b/ui/base/clipboard/scoped_clipboard_writer.cc
@@ -212,6 +212,16 @@ void ScopedClipboardWriter::WriteData(const std::u16string& format,
}
}
+void ScopedClipboardWriter::WriteUnsafeRawData(const std::u16string& format,
+ mojo_base::BigBuffer data) {
+ static constexpr int kMaxRegisteredFormats = 100;
+ if (counter_ >= kMaxRegisteredFormats)
+ return;
+ counter_++;
+ platform_representations_.push_back(
+ {base::UTF16ToUTF8(format), std::move(data)});
+}
+
void ScopedClipboardWriter::Reset() {
objects_.clear();
platform_representations_.clear();
diff --git a/ui/base/clipboard/scoped_clipboard_writer.h b/ui/base/clipboard/scoped_clipboard_writer.h
index 879acd4f6f0101a6da3af58d78eeda877ea41a4a..4d4149b6aa34c7073804994cb1c03368830c736d 100644
--- a/ui/base/clipboard/scoped_clipboard_writer.h
+++ b/ui/base/clipboard/scoped_clipboard_writer.h
@@ -80,6 +80,10 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ScopedClipboardWriter {
// This is only used to write custom format data.
void WriteData(const std::u16string& format, mojo_base::BigBuffer data);
+ // write raw (non-pickled) data to the clipboard
+ void WriteUnsafeRawData(const std::u16string& format,
+ mojo_base::BigBuffer data);
+
void WriteImage(const SkBitmap& bitmap);
// Mark the data to be written as confidential.

View File

@@ -0,0 +1,40 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Yutaka Hirano <yhirano@chromium.org>
Date: Tue, 9 Nov 2021 09:03:17 +0000
Subject: Allow null SkBitmap to be transferred across threads
(cherry picked from commit dad0c0e5162bcc49b8f60354d3bca92224d8381b)
Bug: 1241091
Change-Id: Ie96932c14c8884d6d3eafa76dab5043e7aa31888
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3251815
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Yutaka Hirano <yhirano@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#936861}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3268018
Auto-Submit: Yutaka Hirano <yhirano@chromium.org>
Reviewed-by: Kentaro Hara <haraken@chromium.org>
Commit-Queue: Kentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/branch-heads/4664@{#893}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/third_party/blink/renderer/platform/graphics/skia/skia_utils.h b/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
index e4bde78252c90ecd19655e8c552a2a39299dff75..33d6a1f115c606c3f203b37642ad2875bcca1dd7 100644
--- a/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
+++ b/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
@@ -212,11 +212,13 @@ struct CrossThreadCopier<SkBitmap> {
using Type = SkBitmap;
static SkBitmap Copy(const SkBitmap& bitmap) {
- CHECK(bitmap.isImmutable()) << "Only immutable bitmaps can be transferred.";
+ CHECK(bitmap.isImmutable() || bitmap.isNull())
+ << "Only immutable bitmaps can be transferred.";
return bitmap;
}
static SkBitmap Copy(SkBitmap&& bitmap) {
- CHECK(bitmap.isImmutable()) << "Only immutable bitmaps can be transferred.";
+ CHECK(bitmap.isImmutable() || bitmap.isNull())
+ << "Only immutable bitmaps can be transferred.";
return std::move(bitmap);
}
};

View File

@@ -46,10 +46,10 @@ index 135ad9b24745f6d016806f3c95993efe65b370f3..c5e694cd56b9db940e8564c82e2773aa
}
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 0fcf061bf93b4b11603ef944cf8dd4d456cf5f45..c2a035289bcd7424f1a2645da86133de5288ebaa 100644
index 1004666505dc8c127bb2405571eba9ab60277e3f..700cc0d1f88d7873c1b29bc96e871983cc982403 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -5325,7 +5325,6 @@ test("unit_tests") {
@@ -5329,7 +5329,6 @@ test("unit_tests") {
assert(toolkit_views)
sources += [ "../browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc" ]
deps += [
@@ -57,7 +57,7 @@ index 0fcf061bf93b4b11603ef944cf8dd4d456cf5f45..c2a035289bcd7424f1a2645da86133de
"//chrome/browser:chrome_process_finder",
"//chrome/browser/safe_browsing/chrome_cleaner",
"//chrome/browser/safe_browsing/chrome_cleaner:public",
@@ -5338,6 +5337,12 @@ test("unit_tests") {
@@ -5342,6 +5341,12 @@ test("unit_tests") {
"//components/chrome_cleaner/public/proto",
"//ui/events/devices:test_support",
]
@@ -70,7 +70,7 @@ index 0fcf061bf93b4b11603ef944cf8dd4d456cf5f45..c2a035289bcd7424f1a2645da86133de
}
# TODO(crbug.com/931218): Ninja cannot handle certain characters appearing
@@ -5930,7 +5935,6 @@ test("unit_tests") {
@@ -5934,7 +5939,6 @@ test("unit_tests") {
}
deps += [
@@ -78,7 +78,7 @@ index 0fcf061bf93b4b11603ef944cf8dd4d456cf5f45..c2a035289bcd7424f1a2645da86133de
"//chrome/browser:cart_db_content_proto",
"//chrome/browser/media/router:test_support",
"//chrome/browser/promo_browser_command:mojo_bindings",
@@ -5966,6 +5970,9 @@ test("unit_tests") {
@@ -5970,6 +5974,9 @@ test("unit_tests") {
"//ui/color:test_support",
"//ui/native_theme:test_support",
]

View File

@@ -0,0 +1,94 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ben Kelly <wanderview@chromium.org>
Date: Fri, 5 Nov 2021 19:47:08 +0000
Subject: CacheStorage: Store partial opaque responses.
(cherry picked from commit 802faa035409ac7cbb58ad1a385bb8507fe99077)
Fixed: 1260649
Change-Id: If83156096e6aecec55490330d03c56c0c26120bc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3251749
Reviewed-by: Marijn Kruisselbrink <mek@chromium.org>
Commit-Queue: Ben Kelly <wanderview@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#937400}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3264366
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/4664@{#774}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
index 08ed40551e5d66498931271845f345e45ed7272d..f26fcfc4c676d115f2128e843f27154d8a9e03b6 100644
--- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
+++ b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
@@ -446,10 +446,10 @@ blink::mojom::FetchAPIResponsePtr CreateResponse(
? metadata.response().request_include_credentials()
: true;
- // Note that |has_range_requested| can be safely set to false since it only
- // affects HTTP 206 (Partial) responses, which are blocked from cache storage.
- // See https://fetch.spec.whatwg.org/#main-fetch for usage of
- // |has_range_requested|.
+ // While we block most partial responses from being stored, we can have
+ // partial responses for bgfetch or opaque responses.
+ bool has_range_requested = headers.contains(net::HttpRequestHeaders::kRange);
+
return blink::mojom::FetchAPIResponse::New(
url_list, metadata.response().status_code(),
metadata.response().status_text(),
@@ -467,7 +467,7 @@ blink::mojom::FetchAPIResponsePtr CreateResponse(
static_cast<net::HttpResponseInfo::ConnectionInfo>(
metadata.response().connection_info()),
alpn_negotiated_protocol, metadata.response().was_fetched_via_spdy(),
- /*has_range_requested=*/false, /*auth_challenge_info=*/absl::nullopt,
+ has_range_requested, /*auth_challenge_info=*/absl::nullopt,
request_include_credentials);
}
@@ -1888,7 +1888,13 @@ void LegacyCacheStorageCache::PutDidCreateEntry(
}
proto::CacheResponse* response_metadata = metadata.mutable_response();
- DCHECK_NE(put_context->response->status_code, net::HTTP_PARTIAL_CONTENT);
+ if (owner_ != storage::mojom::CacheStorageOwner::kBackgroundFetch &&
+ put_context->response->response_type !=
+ network::mojom::FetchResponseType::kOpaque &&
+ put_context->response->response_type !=
+ network::mojom::FetchResponseType::kOpaqueRedirect) {
+ DCHECK_NE(put_context->response->status_code, net::HTTP_PARTIAL_CONTENT);
+ }
response_metadata->set_status_code(put_context->response->status_code);
response_metadata->set_status_text(put_context->response->status_text);
response_metadata->set_response_type(FetchResponseTypeToProtoResponseType(
diff --git a/third_party/blink/renderer/modules/cache_storage/cache.cc b/third_party/blink/renderer/modules/cache_storage/cache.cc
index c76c7677a17fd58be83d5e9f2bc263b710e528ae..8c267d2f54ae6e83b86d53dd473e2ed1354aa3c4 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache.cc
+++ b/third_party/blink/renderer/modules/cache_storage/cache.cc
@@ -102,7 +102,7 @@ void ValidateResponseForPut(const Response* response,
exception_state.ThrowTypeError("Vary header contains *");
return;
}
- if (response->GetResponse()->InternalStatus() == 206) {
+ if (response->GetResponse()->Status() == 206) {
exception_state.ThrowTypeError(
"Partial response (status code 206) is unsupported");
return;
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-put.js b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-put.js
index b45910a3b8ba089e1724efa8b9e8a8d679c59320..f60c4b905ebcb61854b83177d59861ef92095624 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-put.js
+++ b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-put.js
@@ -144,7 +144,14 @@ cache_test(function(cache, test) {
'Test framework error: The status code should be 0 for an ' +
' opaque-filtered response. This is actually HTTP 206.');
response = fetch_result.clone();
- return promise_rejects_js(test, TypeError, cache.put(request, fetch_result));
+ return cache.put(request, fetch_result);
+ })
+ .then(function() {
+ return cache.match(test_url);
+ })
+ .then(function(result) {
+ assert_not_equals(result, undefined,
+ 'Cache.put should store an entry for the opaque response');
});
}, 'Cache.put with opaque-filtered HTTP 206 response');

View File

@@ -0,0 +1,26 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Matt Reynolds <mattreynolds@google.com>
Date: Wed, 19 Jan 2022 21:03:08 +0000
Subject: gamepad: Return an invalid handle after ReportBadMessage
Bug: 1285449
Change-Id: I746c539577f7bdf69cbe4212ac380e0c92a5c771
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3373944
Auto-Submit: Matt Reynolds <mattreynolds@chromium.org>
Reviewed-by: Reilly Grant <reillyg@chromium.org>
Commit-Queue: Reilly Grant <reillyg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#961125}
diff --git a/device/gamepad/gamepad_monitor.cc b/device/gamepad/gamepad_monitor.cc
index ce8ba1ef7551e52f8ae4d9a112a08308ab2ce51c..28082924e632a895fc5bc4725bc6de3d6ca120ac 100644
--- a/device/gamepad/gamepad_monitor.cc
+++ b/device/gamepad/gamepad_monitor.cc
@@ -53,6 +53,8 @@ void GamepadMonitor::GamepadStartPolling(GamepadStartPollingCallback callback) {
GamepadService* service = GamepadService::GetInstance();
if (!service->ConsumerBecameActive(this)) {
mojo::ReportBadMessage("GamepadMonitor::GamepadStartPolling failed");
+ std::move(callback).Run(base::ReadOnlySharedMemoryRegion());
+ return;
}
std::move(callback).Run(service->DuplicateSharedMemoryRegion());
}

View File

@@ -0,0 +1,385 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Min Qin <qinmin@chromium.org>
Date: Tue, 31 Aug 2021 23:03:03 +0000
Subject: Quarantine save package items that's downloaded from network
Currently quarantine is not performed for save page downloads. This CL
fixes the issue.
BUG=1243020, 811161
Change-Id: I85d03cc324b0b90a45bd8b3429e4e9eec1aaf857
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3126709
Reviewed-by: Xing Liu <xingliu@chromium.org>
Commit-Queue: Min Qin <qinmin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#917013}
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
index df2e3571636144acfefd1b79f157fd176db46ea0..f0a2d2bd58314420cc356400acc46ab412d49aca 100644
--- a/chrome/browser/download/save_page_browsertest.cc
+++ b/chrome/browser/download/save_page_browsertest.cc
@@ -49,6 +49,7 @@
#include "components/prefs/pref_member.h"
#include "components/prefs/pref_service.h"
#include "components/security_state/core/security_state.h"
+#include "components/services/quarantine/test_support.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
@@ -431,6 +432,10 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveFileURL) {
EXPECT_TRUE(base::PathExists(full_file_name));
EXPECT_FALSE(base::PathExists(dir));
EXPECT_TRUE(base::ContentsEqual(GetTestDirFile("text.txt"), full_file_name));
+#if defined(OS_WIN)
+ // Local file URL will not be quarantined.
+ EXPECT_FALSE(quarantine::IsFileQuarantined(full_file_name, GURL(), GURL()));
+#endif
}
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,
@@ -964,6 +969,25 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveUnauthorizedResource) {
EXPECT_FALSE(base::PathExists(dir.AppendASCII("should-not-save.jpg")));
}
+#if defined(OS_WIN)
+// Save a file and confirm that the file is correctly quarantined.
+IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveURLQuarantine) {
+ GURL url = embedded_test_server()->GetURL("/save_page/text.txt");
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ base::FilePath full_file_name, dir;
+ SaveCurrentTab(url, content::SAVE_PAGE_TYPE_AS_ONLY_HTML, "test", 1, &dir,
+ &full_file_name);
+ ASSERT_FALSE(HasFailure());
+
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ EXPECT_TRUE(base::PathExists(full_file_name));
+ EXPECT_FALSE(base::PathExists(dir));
+ EXPECT_TRUE(base::ContentsEqual(GetTestDirFile("text.txt"), full_file_name));
+ EXPECT_TRUE(quarantine::IsFileQuarantined(full_file_name, url, GURL()));
+}
+#endif
+
// Test suite that allows testing --site-per-process against cross-site frames.
// See http://dev.chromium.org/developers/design-documents/site-isolation.
class SavePageSitePerProcessBrowserTest : public SavePageBrowserTest {
diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h
index b8f71b60bee4b0bb7f46d2a843bb30c5d9ca494f..e3e643028cc23c5a0cfee726fe65d53333a7122f 100644
--- a/content/browser/download/download_manager_impl.h
+++ b/content/browser/download/download_manager_impl.h
@@ -170,6 +170,11 @@ class CONTENT_EXPORT DownloadManagerImpl
int frame_tree_node_id,
bool from_download_cross_origin_redirect);
+ // DownloadItemImplDelegate overrides.
+ download::QuarantineConnectionCallback GetQuarantineConnectionCallback()
+ override;
+ std::string GetApplicationClientIdForFileScanning() const override;
+
private:
using DownloadSet = std::set<download::DownloadItem*>;
using DownloadGuidMap =
@@ -237,7 +242,6 @@ class CONTENT_EXPORT DownloadManagerImpl
bool ShouldOpenDownload(download::DownloadItemImpl* item,
ShouldOpenDownloadCallback callback) override;
void CheckForFileRemoval(download::DownloadItemImpl* download_item) override;
- std::string GetApplicationClientIdForFileScanning() const override;
void ResumeInterruptedDownload(
std::unique_ptr<download::DownloadUrlParameters> params,
const GURL& site_url) override;
@@ -249,8 +253,6 @@ class CONTENT_EXPORT DownloadManagerImpl
void ReportBytesWasted(download::DownloadItemImpl* download) override;
void BindWakeLockProvider(
mojo::PendingReceiver<device::mojom::WakeLockProvider> receiver) override;
- download::QuarantineConnectionCallback GetQuarantineConnectionCallback()
- override;
std::unique_ptr<download::DownloadItemRenameHandler>
GetRenameHandlerForDownload(
download::DownloadItemImpl* download_item) override;
diff --git a/content/browser/download/save_file.cc b/content/browser/download/save_file.cc
index 6e0cf6ed1df5db407e31be0e3a6db2e919d8e1bf..296c0cf79c9f5ee5e4ab9835394fb34ae7d92acc 100644
--- a/content/browser/download/save_file.cc
+++ b/content/browser/download/save_file.cc
@@ -63,10 +63,15 @@ void SaveFile::Finish() {
file_.Finish();
}
-void SaveFile::AnnotateWithSourceInformation() {
- // TODO(gbillock): If this method is called, it should set the
- // file_.SetClientGuid() method first.
- NOTREACHED();
+void SaveFile::AnnotateWithSourceInformation(
+ const std::string& client_guid,
+ const GURL& source_url,
+ const GURL& referrer_url,
+ mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
+ download::BaseFile::OnAnnotationDoneCallback on_annotation_done_callback) {
+ file_.AnnotateWithSourceInformation(client_guid, source_url, referrer_url,
+ std::move(remote_quarantine),
+ std::move(on_annotation_done_callback));
}
base::FilePath SaveFile::FullPath() const {
diff --git a/content/browser/download/save_file.h b/content/browser/download/save_file.h
index 688574b07f9374e75a25caaaa13bdb405aea7b0d..1893a0031f4c6642c6c806577da2246e55e49091 100644
--- a/content/browser/download/save_file.h
+++ b/content/browser/download/save_file.h
@@ -34,7 +34,12 @@ class SaveFile {
void Detach();
void Cancel();
void Finish();
- void AnnotateWithSourceInformation();
+ void AnnotateWithSourceInformation(
+ const std::string& client_guid,
+ const GURL& source_url,
+ const GURL& referrer_url,
+ mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
+ download::BaseFile::OnAnnotationDoneCallback on_annotation_done_callback);
base::FilePath FullPath() const;
bool InProgress() const;
int64_t BytesSoFar() const;
diff --git a/content/browser/download/save_file_manager.cc b/content/browser/download/save_file_manager.cc
index bb322825a449920001b3c09fce33d3ed7e4d82da..98ce67d548d0880ed187779a0e41e7995c83543b 100644
--- a/content/browser/download/save_file_manager.cc
+++ b/content/browser/download/save_file_manager.cc
@@ -51,6 +51,7 @@ static SaveFileManager* g_save_file_manager = nullptr;
class SaveFileManager::SimpleURLLoaderHelper
: public network::SimpleURLLoaderStreamConsumer {
public:
+ using URLLoaderCompleteCallback = base::OnceCallback<void(bool success)>;
static std::unique_ptr<SimpleURLLoaderHelper> CreateAndStartDownload(
std::unique_ptr<network::ResourceRequest> resource_request,
SaveItemId save_item_id,
@@ -59,11 +60,12 @@ class SaveFileManager::SimpleURLLoaderHelper
int render_frame_routing_id,
const net::NetworkTrafficAnnotationTag& annotation_tag,
network::mojom::URLLoaderFactory* url_loader_factory,
- SaveFileManager* save_file_manager) {
+ SaveFileManager* save_file_manager,
+ URLLoaderCompleteCallback on_complete_cb) {
return std::unique_ptr<SimpleURLLoaderHelper>(new SimpleURLLoaderHelper(
std::move(resource_request), save_item_id, save_package_id,
render_process_id, render_frame_routing_id, annotation_tag,
- url_loader_factory, save_file_manager));
+ url_loader_factory, save_file_manager, std::move(on_complete_cb)));
}
~SimpleURLLoaderHelper() override = default;
@@ -77,10 +79,12 @@ class SaveFileManager::SimpleURLLoaderHelper
int render_frame_routing_id,
const net::NetworkTrafficAnnotationTag& annotation_tag,
network::mojom::URLLoaderFactory* url_loader_factory,
- SaveFileManager* save_file_manager)
+ SaveFileManager* save_file_manager,
+ URLLoaderCompleteCallback on_complete_cb)
: save_file_manager_(save_file_manager),
save_item_id_(save_item_id),
- save_package_id_(save_package_id) {
+ save_package_id_(save_package_id),
+ on_complete_cb_(std::move(on_complete_cb)) {
GURL url = resource_request->url;
url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
annotation_tag);
@@ -125,9 +129,7 @@ class SaveFileManager::SimpleURLLoaderHelper
void OnComplete(bool success) override {
download::GetDownloadTaskRunner()->PostTask(
- FROM_HERE,
- base::BindOnce(&SaveFileManager::SaveFinished, save_file_manager_,
- save_item_id_, save_package_id_, success));
+ FROM_HERE, base::BindOnce(std::move(on_complete_cb_), success));
}
void OnRetry(base::OnceClosure start_retry) override {
@@ -139,6 +141,7 @@ class SaveFileManager::SimpleURLLoaderHelper
SaveItemId save_item_id_;
SavePackageId save_package_id_;
std::unique_ptr<network::SimpleURLLoader> url_loader_;
+ URLLoaderCompleteCallback on_complete_cb_;
DISALLOW_COPY_AND_ASSIGN(SimpleURLLoaderHelper);
};
@@ -189,17 +192,20 @@ SavePackage* SaveFileManager::LookupPackage(SaveItemId save_item_id) {
}
// Call from SavePackage for starting a saving job
-void SaveFileManager::SaveURL(SaveItemId save_item_id,
- const GURL& url,
- const Referrer& referrer,
- int render_process_host_id,
- int render_view_routing_id,
- int render_frame_routing_id,
- SaveFileCreateInfo::SaveFileSource save_source,
- const base::FilePath& file_full_path,
- BrowserContext* context,
- StoragePartition* storage_partition,
- SavePackage* save_package) {
+void SaveFileManager::SaveURL(
+ SaveItemId save_item_id,
+ const GURL& url,
+ const Referrer& referrer,
+ int render_process_host_id,
+ int render_view_routing_id,
+ int render_frame_routing_id,
+ SaveFileCreateInfo::SaveFileSource save_source,
+ const base::FilePath& file_full_path,
+ BrowserContext* context,
+ StoragePartition* storage_partition,
+ SavePackage* save_package,
+ const std::string& client_guid,
+ mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Insert started saving job to tracking list.
@@ -285,11 +291,18 @@ void SaveFileManager::SaveURL(SaveItemId save_item_id,
factory = storage_partition->GetURLLoaderFactoryForBrowserProcess().get();
}
+ base::OnceCallback<void(bool /*success*/)> save_finished_cb =
+ base::BindOnce(&SaveFileManager::OnURLLoaderComplete, this,
+ save_item_id, save_package->id(),
+ context->IsOffTheRecord() ? GURL() : url,
+ context->IsOffTheRecord() ? GURL() : referrer.url,
+ client_guid, std::move(remote_quarantine));
+
url_loader_helpers_[save_item_id] =
SimpleURLLoaderHelper::CreateAndStartDownload(
std::move(request), save_item_id, save_package->id(),
render_process_host_id, render_frame_routing_id, traffic_annotation,
- factory, this);
+ factory, this, std::move(save_finished_cb));
} else {
// We manually start the save job.
auto info = std::make_unique<SaveFileCreateInfo>(
@@ -344,6 +357,36 @@ void SaveFileManager::SendCancelRequest(SaveItemId save_item_id) {
base::BindOnce(&SaveFileManager::CancelSave, this, save_item_id));
}
+void SaveFileManager::OnURLLoaderComplete(
+ SaveItemId save_item_id,
+ SavePackageId save_package_id,
+ const GURL& url,
+ const GURL& referrer_url,
+ const std::string& client_guid,
+ mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
+ bool is_success) {
+ DCHECK(download::GetDownloadTaskRunner()->RunsTasksInCurrentSequence());
+ SaveFile* save_file = LookupSaveFile(save_item_id);
+ if (!is_success || !save_file) {
+ SaveFinished(save_item_id, save_package_id, is_success);
+ return;
+ }
+
+ save_file->AnnotateWithSourceInformation(
+ client_guid, url, referrer_url, std::move(remote_quarantine),
+ base::BindOnce(&SaveFileManager::OnQuarantineComplete, this, save_item_id,
+ save_package_id));
+}
+
+void SaveFileManager::OnQuarantineComplete(
+ SaveItemId save_item_id,
+ SavePackageId save_package_id,
+ download::DownloadInterruptReason result) {
+ DCHECK(download::GetDownloadTaskRunner()->RunsTasksInCurrentSequence());
+ SaveFinished(save_item_id, save_package_id,
+ result == download::DOWNLOAD_INTERRUPT_REASON_NONE);
+}
+
// Notifications sent from the IO thread and run on the file thread:
// The IO thread created |info|, but the file thread (this method) uses it
diff --git a/content/browser/download/save_file_manager.h b/content/browser/download/save_file_manager.h
index 51eb63a9b189be388e4dff48e04644956e968345..0d4290b273ba4f150bc9a49418e54b709a601581 100644
--- a/content/browser/download/save_file_manager.h
+++ b/content/browser/download/save_file_manager.h
@@ -61,6 +61,8 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "components/download/public/common/download_interrupt_reasons.h"
+#include "components/services/quarantine/quarantine.h"
#include "content/browser/download/save_types.h"
#include "content/common/content_export.h"
@@ -90,17 +92,20 @@ class CONTENT_EXPORT SaveFileManager
// Saves the specified URL |url|. |save_package| must not be deleted before
// the call to RemoveSaveFile. Should be called on the UI thread,
- void SaveURL(SaveItemId save_item_id,
- const GURL& url,
- const Referrer& referrer,
- int render_process_host_id,
- int render_view_routing_id,
- int render_frame_routing_id,
- SaveFileCreateInfo::SaveFileSource save_source,
- const base::FilePath& file_full_path,
- BrowserContext* context,
- StoragePartition* storage_partition,
- SavePackage* save_package);
+ void SaveURL(
+ SaveItemId save_item_id,
+ const GURL& url,
+ const Referrer& referrer,
+ int render_process_host_id,
+ int render_view_routing_id,
+ int render_frame_routing_id,
+ SaveFileCreateInfo::SaveFileSource save_source,
+ const base::FilePath& file_full_path,
+ BrowserContext* context,
+ StoragePartition* storage_partition,
+ SavePackage* save_package,
+ const std::string& client_guid,
+ mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine);
// Notifications sent from the IO thread and run on the file thread:
void StartSave(std::unique_ptr<SaveFileCreateInfo> info);
@@ -159,6 +164,21 @@ class CONTENT_EXPORT SaveFileManager
// Help function for sending notification of canceling specific request.
void SendCancelRequest(SaveItemId save_item_id);
+ // Called on the file thread when the URLLoader completes saving a SaveItem.
+ void OnURLLoaderComplete(
+ SaveItemId save_item_id,
+ SavePackageId save_package_id,
+ const GURL& url,
+ const GURL& referrer_url,
+ const std::string& client_guid,
+ mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
+ bool is_success);
+
+ // Called on the file thread when file quarantine finishes on a SaveItem.
+ void OnQuarantineComplete(SaveItemId save_item_id,
+ SavePackageId save_package_id,
+ download::DownloadInterruptReason result);
+
// Notifications sent from the file thread and run on the UI thread.
// Lookup the SaveManager for this WebContents' saving browser context and
diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc
index 369aae121d5074f2bcabf337a87e929dc2a65b6f..b23a0201b033a0952607e00fe2d0d5e9b3337d51 100644
--- a/content/browser/download/save_package.cc
+++ b/content/browser/download/save_package.cc
@@ -856,6 +856,12 @@ void SavePackage::SaveNextFile(bool process_all_remaining_items) {
RenderFrameHostImpl* requester_frame =
requester_frame_tree_node->current_frame_host();
+ mojo::PendingRemote<quarantine::mojom::Quarantine> quarantine;
+ auto quarantine_callback =
+ download_manager_->GetQuarantineConnectionCallback();
+ if (quarantine_callback)
+ quarantine_callback.Run(quarantine.InitWithNewPipeAndPassReceiver());
+
file_manager_->SaveURL(
save_item_ptr->id(), save_item_ptr->url(), save_item_ptr->referrer(),
requester_frame->GetProcess()->GetID(),
@@ -867,8 +873,8 @@ void SavePackage::SaveNextFile(bool process_all_remaining_items) {
.GetRenderViewHost()
->GetProcess()
->GetStoragePartition(),
- this);
-
+ this, download_manager_->GetApplicationClientIdForFileScanning(),
+ std::move(quarantine));
} while (process_all_remaining_items && !waiting_item_queue_.empty());
}

View File

@@ -0,0 +1,51 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Michael Lippautz <mlippautz@chromium.org>
Date: Tue, 2 Nov 2021 21:21:27 +0000
Subject: MediaStreamSource: Retain observers till callbacks have been executed
(cherry picked from commit d1055cb23b15e42381bc815eeabb207ce18394d9)
Bug: chromium:1263620
Change-Id: I0655474bd3c5f4f927db1834e95b2724a20ba4e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3247159
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
Reviewed-by: Elad Alon <eladalon@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#935842}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3257492
Auto-Submit: Elad Alon <eladalon@chromium.org>
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
Cr-Commit-Position: refs/branch-heads/4638@{#1004}
Cr-Branched-From: 159257cab5585bc8421abf347984bb32fdfe9eb9-refs/heads/main@{#920003}
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_source.cc b/third_party/blink/renderer/platform/mediastream/media_stream_source.cc
index b37a4b9297b87092233c600953eb01af820b6df1..15ac4cce06d419646979a52a00628b152ec516de 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_source.cc
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_source.cc
@@ -32,6 +32,7 @@
#include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h"
#include "third_party/blink/renderer/platform/audio/audio_bus.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h"
#include "third_party/blink/renderer/platform/mediastream/webaudio_destination_consumer.h"
@@ -171,11 +172,13 @@ void MediaStreamSource::SetReadyState(ReadyState ready_state) {
ready_state_ = ready_state;
// Observers may dispatch events which create and add new Observers;
- // take a snapshot so as to safely iterate.
+ // take a snapshot so as to safely iterate. Wrap the observers in
+ // weak persistents to allow cancelling callbacks in case they are reclaimed
+ // until the callback is executed.
Vector<base::OnceClosure> observer_callbacks;
- for (auto it = observers_.begin(); it != observers_.end(); ++it) {
- observer_callbacks.push_back(
- base::BindOnce(&Observer::SourceChangedState, *it));
+ for (const auto& it : observers_) {
+ observer_callbacks.push_back(WTF::Bind(&Observer::SourceChangedState,
+ WrapWeakPersistent(it.Get())));
}
for (auto& observer_callback : observer_callbacks) {
std::move(observer_callback).Run();

View File

@@ -0,0 +1,176 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Simon Pelchat <spelchat@chromium.org>
Date: Fri, 7 Jan 2022 20:00:37 +0000
Subject: Avoid UAF on StreamingSearchPrefetchURLLoader.
StreamingSearchPrefetchURLLoader::OnDataAvailable used to "delete this",
which results in deleting the DataPipeDrainer, which will then be used
once OnDataAvailable returns. Instead, we post a task to delete the
URL loader later on.
Bug: 1277917
Change-Id: I8d78c73a01fff0315b96ccb0e7fe605884b99823
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3365387
Reviewed-by: Max Curran <curranmax@chromium.org>
Reviewed-by: Robert Ogden <robertogden@chromium.org>
Commit-Queue: Simon Pelchat <spelchat@chromium.org>
Cr-Commit-Position: refs/heads/main@{#956628}
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc
index 1d3d1ea93c026d371a6ad5678e8ff37dc58f8423..e3eaad96fbada18211f295988c07d218ab67921f 100644
--- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc
+++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h"
#include "chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h"
+#include "streaming_search_prefetch_request.h"
StreamingSearchPrefetchRequest::StreamingSearchPrefetchRequest(
const GURL& prefetch_url,
@@ -19,7 +20,9 @@ void StreamingSearchPrefetchRequest::StartPrefetchRequestInternal(
std::unique_ptr<network::ResourceRequest> resource_request,
const net::NetworkTrafficAnnotationTag& network_traffic_annotation) {
streaming_url_loader_ = std::make_unique<StreamingSearchPrefetchURLLoader>(
- this, profile, std::move(resource_request), network_traffic_annotation);
+ this, profile, std::move(resource_request), network_traffic_annotation,
+ base::BindOnce(&StreamingSearchPrefetchRequest::StopPrefetch,
+ weak_factory_.GetWeakPtr()));
}
std::unique_ptr<SearchPrefetchURLLoader>
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h
index ff051c61e9cbed67d5cffbcac007d6c12a26cc76..ad75d404abe9e743d079725ffd8b01d3a49ae017 100644
--- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h
+++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h
@@ -47,6 +47,8 @@ class StreamingSearchPrefetchRequest : public BaseSearchPrefetchRequest {
private:
// The ongoing prefetch request. Null before and after the fetch.
std::unique_ptr<StreamingSearchPrefetchURLLoader> streaming_url_loader_;
+
+ base::WeakPtrFactory<StreamingSearchPrefetchRequest> weak_factory_{this};
};
#endif // CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_STREAMING_SEARCH_PREFETCH_REQUEST_H_
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
index 07f4e5cd7f0adde63861962a78cdac0de43591b0..8d9009c42cdde766e105b02827a539a4477ea58e 100644
--- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
+++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
@@ -26,15 +26,18 @@
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/mojom/early_hints.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "streaming_search_prefetch_url_loader.h"
#include "url/gurl.h"
StreamingSearchPrefetchURLLoader::StreamingSearchPrefetchURLLoader(
StreamingSearchPrefetchRequest* streaming_prefetch_request,
Profile* profile,
std::unique_ptr<network::ResourceRequest> resource_request,
- const net::NetworkTrafficAnnotationTag& network_traffic_annotation)
+ const net::NetworkTrafficAnnotationTag& network_traffic_annotation,
+ base::OnceClosure stop_prefetch_closure)
: resource_request_(std::move(resource_request)),
- streaming_prefetch_request_(streaming_prefetch_request) {
+ streaming_prefetch_request_(streaming_prefetch_request),
+ stop_prefetch_closure_(std::move(stop_prefetch_closure)) {
DCHECK(streaming_prefetch_request_);
auto url_loader_factory = profile->GetDefaultStoragePartition()
->GetURLLoaderFactoryForBrowserProcess();
@@ -126,7 +129,7 @@ void StreamingSearchPrefetchURLLoader::OnReceiveRedirect(
if (streaming_prefetch_request_) {
streaming_prefetch_request_->ErrorEncountered();
} else {
- delete this;
+ PostTaskToStopPrefetchAndDeleteSelf();
}
}
@@ -209,7 +212,7 @@ void StreamingSearchPrefetchURLLoader::OnStartLoadingResponseBodyFromData() {
mojo::CreateDataPipe(&options, producer_handle_, consumer_handle);
if (rv != MOJO_RESULT_OK) {
- delete this;
+ PostTaskToStopPrefetchAndDeleteSelf();
return;
}
@@ -231,7 +234,7 @@ void StreamingSearchPrefetchURLLoader::OnHandleReady(
MojoResult result,
const mojo::HandleSignalsState& state) {
if (result != MOJO_RESULT_OK) {
- delete this;
+ PostTaskToStopPrefetchAndDeleteSelf();
return;
}
PushData();
@@ -257,7 +260,7 @@ void StreamingSearchPrefetchURLLoader::PushData() {
}
if (result != MOJO_RESULT_OK) {
- delete this;
+ PostTaskToStopPrefetchAndDeleteSelf();
return;
}
@@ -344,16 +347,24 @@ void StreamingSearchPrefetchURLLoader::OnURLLoaderMojoDisconnect() {
DCHECK(streaming_prefetch_request_);
streaming_prefetch_request_->ErrorEncountered();
} else {
- delete this;
+ PostTaskToStopPrefetchAndDeleteSelf();
}
}
void StreamingSearchPrefetchURLLoader::OnURLLoaderClientMojoDisconnect() {
DCHECK(forwarding_client_);
DCHECK(!streaming_prefetch_request_);
- delete this;
+ PostTaskToStopPrefetchAndDeleteSelf();
}
void StreamingSearchPrefetchURLLoader::ClearOwnerPointer() {
streaming_prefetch_request_ = nullptr;
}
+
+void StreamingSearchPrefetchURLLoader::PostTaskToStopPrefetchAndDeleteSelf() {
+ // To avoid UAF bugs, post a separate task to delete this object.
+ if (stop_prefetch_closure_) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, std::move(stop_prefetch_closure_));
+ }
+}
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h
index 2213fb079e3f29566d67030dd2fa399ce11024e2..ed225db0b4d2b0d24aae967f320a7010c1a45044 100644
--- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h
+++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h
@@ -39,7 +39,8 @@ class StreamingSearchPrefetchURLLoader : public network::mojom::URLLoader,
StreamingSearchPrefetchRequest* streaming_prefetch_request,
Profile* profile,
std::unique_ptr<network::ResourceRequest> resource_request,
- const net::NetworkTrafficAnnotationTag& network_traffic_annotation);
+ const net::NetworkTrafficAnnotationTag& network_traffic_annotation,
+ base::OnceClosure stop_prefetch_closure);
~StreamingSearchPrefetchURLLoader() override;
@@ -105,6 +106,9 @@ class StreamingSearchPrefetchURLLoader : public network::mojom::URLLoader,
// Clears |producer_handle_| and |handle_watcher_|.
void Finish();
+ // Post a task to delete this object by running stop_prefetch_closure_.
+ void PostTaskToStopPrefetchAndDeleteSelf();
+
// Sets up mojo forwarding to the navigation path. Resumes
// |network_url_loader_| calls. Serves the start of the response to the
// navigation path. After this method is called, |this| manages its own
@@ -164,6 +168,9 @@ class StreamingSearchPrefetchURLLoader : public network::mojom::URLLoader,
mojo::ScopedDataPipeProducerHandle producer_handle_;
std::unique_ptr<mojo::SimpleWatcher> handle_watcher_;
+ // Closure to cancel this prefetch. Running this callback will destroy |this|.
+ base::OnceClosure stop_prefetch_closure_;
+
base::WeakPtrFactory<StreamingSearchPrefetchURLLoader> weak_factory_{this};
};

View File

@@ -0,0 +1,157 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Etienne Bergeron <etienneb@chromium.org>
Date: Wed, 5 Jan 2022 23:37:26 +0000
Subject: Fix race condition while initializing GPU Watchdog
This CL is fixing a race condition detected by TSAN.
see: crbug/1281979
The race condition is between these two functions:
base::PowerMonitor::IsInitialized() and
base::PowerMonitor::Initialize(...)
The power monitor doesn't need to be initialized to add
observers. In fact, the power monitor initialization
is for plugging a power monitor source. Observers can be
safely added/removed.
R=fdoray@chromium.org
Bug: 1281979
Change-Id: Icaecd877d4b0cf5e79d7fe6a096f9d76d932b076
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3367395
Reviewed-by: Maggie Chen <magchen@chromium.org>
Commit-Queue: Etienne Bergeron <etienneb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#955944}
diff --git a/gpu/ipc/service/gpu_watchdog_thread.cc b/gpu/ipc/service/gpu_watchdog_thread.cc
index ecf8e17ce4183bfe2f22a9a6d666a60828f078a2..c518f978e602eda3cfa150bd8e9e07f7f7fc749b 100644
--- a/gpu/ipc/service/gpu_watchdog_thread.cc
+++ b/gpu/ipc/service/gpu_watchdog_thread.cc
@@ -36,9 +36,6 @@
#endif
namespace gpu {
-namespace {
-constexpr int64_t kDelayForAddPowerObserverInMs = 50;
-}
base::TimeDelta GetGpuWatchdogTimeout() {
std::string timeout_str =
@@ -176,14 +173,11 @@ void GpuWatchdogThread::OnInitComplete() {
base::Unretained(this)));
Disarm();
- // Use a delayed task for AddPowerObserver. The PowerMonitor is initialized in
- // ChildThreadImpl::Init right after GpuInit::InitializeAndStartSandbox which
- // calls OnInitComplete() at the end if no errors.
- task_runner()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&GpuWatchdogThread::AddPowerObserver,
- base::Unretained(this)),
- base::TimeDelta::FromMilliseconds(kDelayForAddPowerObserverInMs));
+ // The PowerMonitorObserver needs to be register on the watchdog thread so the
+ // notifications are delivered on that thread.
+ task_runner()->PostTask(FROM_HERE,
+ base::BindOnce(&GpuWatchdogThread::AddPowerObserver,
+ base::Unretained(this)));
}
// Called from the gpu thread in viz::GpuServiceImpl::~GpuServiceImpl().
@@ -296,26 +290,12 @@ void GpuWatchdogThread::OnResume() {
void GpuWatchdogThread::AddPowerObserver() {
DCHECK(watchdog_thread_task_runner_->BelongsToCurrentThread());
- // The Observer can only be added after the power monitor is initialized.
- // When this function is called, PowerMonitor is probably ready.
- if (base::PowerMonitor::IsInitialized()) {
- bool is_system_suspended =
- base::PowerMonitor::AddPowerSuspendObserverAndReturnSuspendedState(
- this);
- if (is_system_suspended) {
- StopWatchdogTimeoutTask(kPowerSuspendResume);
- }
-
- is_power_observer_added_ = true;
- } else {
- // Just in case PowerMonitor is not ready.
- // It usually takes hundreds of milliseconds to finish the whole GPU
- // initialization. Try again in 100 ms.
- task_runner()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&GpuWatchdogThread::AddPowerObserver, weak_ptr_),
- base::TimeDelta::FromMilliseconds(100));
- }
+ // Adding the Observer to the power monitor is safe even if power monitor is
+ // not yet initialized.
+ bool is_system_suspended =
+ base::PowerMonitor::AddPowerSuspendObserverAndReturnSuspendedState(this);
+ if (is_system_suspended)
+ StopWatchdogTimeoutTask(kPowerSuspendResume);
}
// Running on the watchdog thread.
@@ -638,7 +618,6 @@ void GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang() {
base::debug::Alias(&in_power_suspension_);
base::debug::Alias(&in_gpu_process_teardown_);
base::debug::Alias(&is_backgrounded_);
- base::debug::Alias(&is_power_observer_added_);
base::debug::Alias(&last_on_watchdog_timeout_timeticks_);
base::TimeDelta timeticks_elapses =
function_begin_timeticks - last_on_watchdog_timeout_timeticks_;
@@ -843,17 +822,4 @@ bool GpuWatchdogThread::IsGpuHangDetectedForTesting() {
return test_result_timeout_and_gpu_hang_.IsSet();
}
-// This should be called on the test main thread only. It will wait until the
-// power observer is added on the watchdog thread.
-void GpuWatchdogThread::WaitForPowerObserverAddedForTesting() {
- DCHECK(watched_gpu_task_runner_->BelongsToCurrentThread());
-
- base::WaitableEvent event;
- task_runner()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(&event)),
- base::TimeDelta::FromMilliseconds(kDelayForAddPowerObserverInMs));
- event.Wait();
-}
-
} // namespace gpu
diff --git a/gpu/ipc/service/gpu_watchdog_thread.h b/gpu/ipc/service/gpu_watchdog_thread.h
index d0d20dfc7c9fd7e13896e212673519ec5233c562..622647a68ee2bc2e3d18e58bbcfb3c7f90b3102c 100644
--- a/gpu/ipc/service/gpu_watchdog_thread.h
+++ b/gpu/ipc/service/gpu_watchdog_thread.h
@@ -121,8 +121,6 @@ class GPU_IPC_SERVICE_EXPORT GpuWatchdogThread
// For gpu testing only. Return status for the watchdog tests
bool IsGpuHangDetectedForTesting();
- void WaitForPowerObserverAddedForTesting();
-
// Implements base::Thread.
void Init() override;
void CleanUp() override;
@@ -291,10 +289,6 @@ class GPU_IPC_SERVICE_EXPORT GpuWatchdogThread
// The GPU watchdog is paused. The timeout task is temporarily stopped.
bool is_paused_ = false;
- // Whether the watchdog thread has added the power monitor observer.
- // Read/Write by the watchdog thread only.
- bool is_power_observer_added_ = false;
-
// whether GpuWatchdogThreadEvent::kGpuWatchdogStart has been recorded.
bool is_watchdog_start_histogram_recorded = false;
diff --git a/gpu/ipc/service/gpu_watchdog_thread_unittest.cc b/gpu/ipc/service/gpu_watchdog_thread_unittest.cc
index ca2006a45dd87bad106b0f75bfe8475fa1090038..b44cdd7e22686ab37c57461291676f01512fd623 100644
--- a/gpu/ipc/service/gpu_watchdog_thread_unittest.cc
+++ b/gpu/ipc/service/gpu_watchdog_thread_unittest.cc
@@ -81,9 +81,6 @@ void GpuWatchdogPowerTest::SetUp() {
// Report GPU init complete.
watchdog_thread_->OnInitComplete();
-
- // Wait until the power observer is added on the watchdog thread
- watchdog_thread_->WaitForPowerObserverAddedForTesting();
}
void GpuWatchdogPowerTest::TearDown() {

View File

@@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Bookholt <bookholt@chromium.org>
Date: Tue, 11 Jan 2022 00:33:53 +0000
Subject: ServiceWorkerContainerHost::EnsureFileAccess: abort request
processing if the requesting process lacks file access
Bug: 1282354
Change-Id: Ia37ef5b97eedb0d2ad25ffe2869844a40e5be862
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3379268
Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org>
Commit-Queue: Chris Bookholt <bookholt@chromium.org>
Cr-Commit-Position: refs/heads/main@{#957344}
diff --git a/content/browser/service_worker/service_worker_container_host.cc b/content/browser/service_worker/service_worker_container_host.cc
index 82498632c53883b5d84fb0a2e5246c98e71ef00d..f13416b0cd611ddcf18053f7a543a9a423635227 100644
--- a/content/browser/service_worker/service_worker_container_host.cc
+++ b/content/browser/service_worker/service_worker_container_host.cc
@@ -379,10 +379,12 @@ void ServiceWorkerContainerHost::EnsureFileAccess(
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();
for (const auto& file : file_paths) {
- if (!policy->CanReadFile(process_id_, file))
+ if (!policy->CanReadFile(process_id_, file)) {
mojo::ReportBadMessage(
"The renderer doesn't have access to the file "
"but it tried to grant access to the controller.");
+ return;
+ }
if (!policy->CanReadFile(controller_process_id, file))
policy->GrantReadFile(controller_process_id, file);

View File

@@ -0,0 +1,28 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Hosseinian <dhoss@chromium.org>
Date: Thu, 30 Dec 2021 05:08:29 +0000
Subject: CHECK page on thumbnail requests
Elevate DCHECK to CHECK.
Fixed: 1283198
Change-Id: Iacb3da961cfb44f94f7a377e225270a57809ef9c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3361538
Auto-Submit: Daniel Hosseinian <dhoss@chromium.org>
Reviewed-by: K. Moon <kmoon@chromium.org>
Commit-Queue: K. Moon <kmoon@chromium.org>
Cr-Commit-Position: refs/heads/main@{#954552}
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 341b183948b15f72edca6f8620c5039593d16a90..2b128d8fdde8048c1f8b92ec2e38f485feca2bf4 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -4273,7 +4273,7 @@ void PDFiumEngine::SetLinkUnderCursorForAnnotation(FPDF_ANNOTATION annot,
void PDFiumEngine::RequestThumbnail(int page_index,
float device_pixel_ratio,
SendThumbnailCallback send_callback) {
- DCHECK(PageIndexInBounds(page_index));
+ CHECK(PageIndexInBounds(page_index));
// Thumbnails cannot be generated in the middle of a progressive paint of a
// page. Generate the thumbnail immediately only if the page is not currently

View File

@@ -0,0 +1,138 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Clark DuVall <cduvall@chromium.org>
Date: Thu, 6 Jan 2022 01:21:21 +0000
Subject: Fix lifetime bug in PrefetchURLLoader
PrefetchURLLoader is now owned by PrefetchURLLoaderService, which is no
longer refcounted. This makes the lifetime much easier to reason about.
Bug: 1283371
Change-Id: Iaa58c1f44cc9f066459ce344012f57faca533197
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3361198
Reviewed-by: John Abd-El-Malek <jam@chromium.org>
Reviewed-by: Kunihiko Sakamoto <ksakamoto@chromium.org>
Commit-Queue: Clark DuVall <cduvall@chromium.org>
Cr-Commit-Position: refs/heads/main@{#955986}
diff --git a/content/browser/loader/prefetch_url_loader_service.cc b/content/browser/loader/prefetch_url_loader_service.cc
index 5211d5552d6b2e1c1967d7dd6c6079001fef6895..345bf021541a121ea183ba16fa7ed76373f0dfd1 100644
--- a/content/browser/loader/prefetch_url_loader_service.cc
+++ b/content/browser/loader/prefetch_url_loader_service.cc
@@ -202,29 +202,25 @@ void PrefetchURLLoaderService::CreateLoaderAndStart(
->prefetched_signed_exchange_cache;
}
- // For now we make self owned receiver for the loader to the request, while we
- // can also possibly make the new loader owned by the factory so that they can
- // live longer than the client (i.e. run in detached mode).
- // TODO(kinuko): Revisit this.
- mojo::MakeSelfOwnedReceiver(
- std::make_unique<PrefetchURLLoader>(
- request_id, options, current_context.frame_tree_node_id,
- resource_request,
- resource_request.trusted_params
- ? resource_request.trusted_params->isolation_info
- .network_isolation_key()
- : current_context.render_frame_host->GetNetworkIsolationKey(),
- std::move(client), traffic_annotation,
- std::move(network_loader_factory_to_use),
- base::BindRepeating(
- &PrefetchURLLoaderService::CreateURLLoaderThrottles, this,
- resource_request, current_context.frame_tree_node_id),
- browser_context_, signed_exchange_prefetch_metric_recorder_,
- std::move(prefetched_signed_exchange_cache), accept_langs_,
- base::BindOnce(
- &PrefetchURLLoaderService::GenerateRecursivePrefetchToken, this,
- current_context.weak_ptr_factory.GetWeakPtr())),
- std::move(receiver));
+ // base::Unretained is safe here since |this| owns the loader.
+ auto loader = std::make_unique<PrefetchURLLoader>(
+ request_id, options, current_context.frame_tree_node_id, resource_request,
+ resource_request.trusted_params
+ ? resource_request.trusted_params->isolation_info
+ .network_isolation_key()
+ : current_context.render_frame_host->GetNetworkIsolationKey(),
+ std::move(client), traffic_annotation,
+ std::move(network_loader_factory_to_use),
+ base::BindRepeating(&PrefetchURLLoaderService::CreateURLLoaderThrottles,
+ base::Unretained(this), resource_request,
+ current_context.frame_tree_node_id),
+ browser_context_, signed_exchange_prefetch_metric_recorder_,
+ std::move(prefetched_signed_exchange_cache), accept_langs_,
+ base::BindOnce(&PrefetchURLLoaderService::GenerateRecursivePrefetchToken,
+ base::Unretained(this),
+ current_context.weak_ptr_factory.GetWeakPtr()));
+ auto* raw_loader = loader.get();
+ prefetch_receivers_.Add(raw_loader, std::move(receiver), std::move(loader));
}
PrefetchURLLoaderService::~PrefetchURLLoaderService() = default;
diff --git a/content/browser/loader/prefetch_url_loader_service.h b/content/browser/loader/prefetch_url_loader_service.h
index 210794966c8d25947f3e6b490538c1f851d80d52..c5fff844f73deaf2912716de9cf97547c498e4e5 100644
--- a/content/browser/loader/prefetch_url_loader_service.h
+++ b/content/browser/loader/prefetch_url_loader_service.h
@@ -35,13 +35,11 @@ class URLLoaderFactoryGetter;
// prefetches. The renderer uses it for prefetch requests including <link
// rel="prefetch">.
class CONTENT_EXPORT PrefetchURLLoaderService final
- : public base::RefCountedThreadSafe<
- PrefetchURLLoaderService,
- content::BrowserThread::DeleteOnUIThread>,
- public blink::mojom::RendererPreferenceWatcher,
+ : public blink::mojom::RendererPreferenceWatcher,
public network::mojom::URLLoaderFactory {
public:
explicit PrefetchURLLoaderService(BrowserContext* browser_context);
+ ~PrefetchURLLoaderService() override;
void GetFactory(
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
@@ -67,12 +65,8 @@ class CONTENT_EXPORT PrefetchURLLoaderService final
}
private:
- friend class base::DeleteHelper<content::PrefetchURLLoaderService>;
- friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
struct BindContext;
- ~PrefetchURLLoaderService() override;
-
// network::mojom::URLLoaderFactory:
void CreateLoaderAndStart(
mojo::PendingReceiver<network::mojom::URLLoader> receiver,
@@ -114,6 +108,9 @@ class CONTENT_EXPORT PrefetchURLLoaderService final
mojo::ReceiverSet<network::mojom::URLLoaderFactory,
std::unique_ptr<BindContext>>
loader_factory_receivers_;
+ mojo::ReceiverSet<network::mojom::URLLoader,
+ std::unique_ptr<network::mojom::URLLoader>>
+ prefetch_receivers_;
// Used in the IO thread.
mojo::Receiver<blink::mojom::RendererPreferenceWatcher>
preference_watcher_receiver_{this};
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index ae284e031a6e051bda49258d54a2e62332773c70..e9af32dd2dc6ae75ded55b1ffd3fe7881408eefc 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -1321,7 +1321,7 @@ void StoragePartitionImpl::Initialize(
blob_context, filesystem_context_, fallback_blob_registry);
prefetch_url_loader_service_ =
- base::MakeRefCounted<PrefetchURLLoaderService>(browser_context_);
+ std::make_unique<PrefetchURLLoaderService>(browser_context_);
cookie_store_manager_ =
std::make_unique<CookieStoreManager>(service_worker_context_);
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index 6f3a482ae16e88271768a3f91c633201f435e271..02209f615202a987d83e72895b0782cac8a8fccd 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -552,7 +552,7 @@ class CONTENT_EXPORT StoragePartitionImpl
std::unique_ptr<BroadcastChannelProvider> broadcast_channel_provider_;
std::unique_ptr<BluetoothAllowedDevicesMap> bluetooth_allowed_devices_map_;
scoped_refptr<BlobRegistryWrapper> blob_registry_;
- scoped_refptr<PrefetchURLLoaderService> prefetch_url_loader_service_;
+ std::unique_ptr<PrefetchURLLoaderService> prefetch_url_loader_service_;
std::unique_ptr<CookieStoreManager> cookie_store_manager_;
scoped_refptr<BucketContext> bucket_context_;
scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context_;

View File

@@ -0,0 +1,74 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alan Screen <awscreen@chromium.org>
Date: Fri, 7 Jan 2022 09:38:01 +0000
Subject: Ensure valid print render host before proceeding to print.
Bug: 1283375
Change-Id: I5691fc2a9d09040e777aafd0061b957025643b8a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3369086
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Alan Screen <awscreen@chromium.org>
Cr-Commit-Position: refs/heads/main@{#956443}
diff --git a/chrome/browser/printing/print_view_manager.cc b/chrome/browser/printing/print_view_manager.cc
index 4662db344afb08574b7ac7d96cb72c71edc802af..c7535ddd5b54ae33fe6f6aea09b6b313ba38b840 100644
--- a/chrome/browser/printing/print_view_manager.cc
+++ b/chrome/browser/printing/print_view_manager.cc
@@ -111,6 +111,11 @@ bool PrintViewManager::PrintForSystemDialogNow(
on_print_dialog_shown_callback_ = std::move(dialog_shown_callback);
is_switching_to_system_dialog_ = true;
+ // Remember the ID for `print_preview_rfh_`, to enable checking that the
+ // `RenderFrameHost` is still valid after a possible inner message loop runs
+ // in `DisconnectFromCurrentPrintJob()`.
+ content::GlobalRenderFrameHostId rfh_id = print_preview_rfh_->GetGlobalId();
+
auto weak_this = weak_factory_.GetWeakPtr();
DisconnectFromCurrentPrintJob();
if (!weak_this)
@@ -120,6 +125,10 @@ bool PrintViewManager::PrintForSystemDialogNow(
if (IsCrashed())
return false;
+ // Don't print if `print_preview_rfh_` is no longer live.
+ if (!content::RenderFrameHost::FromID(rfh_id))
+ return false;
+
// TODO(crbug.com/809738) Register with `PrintBackendServiceManager` when
// system print is enabled out-of-process.
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
index 143ee383668965ba04da092e3445fc9f4a33a433..055d97cb63cb5a1b64ee0a113ec27b664113aba9 100644
--- a/chrome/browser/printing/print_view_manager_base.cc
+++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -39,6 +39,7 @@
#include "components/services/print_compositor/public/cpp/print_service_mojo_types.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
@@ -365,6 +366,11 @@ bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh,
bool silent,
base::Value settings,
CompletionCallback callback) {
+ // Remember the ID for `rfh`, to enable checking that the `RenderFrameHost`
+ // is still valid after a possible inner message loop runs in
+ // `DisconnectFromCurrentPrintJob()`.
+ content::GlobalRenderFrameHostId rfh_id = rfh->GetGlobalId();
+
auto weak_this = weak_ptr_factory_.GetWeakPtr();
DisconnectFromCurrentPrintJob();
if (!weak_this)
@@ -374,6 +380,10 @@ bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh,
if (IsCrashed())
return false;
+ // Don't print if `rfh` is no longer live.
+ if (!content::RenderFrameHost::FromID(rfh_id))
+ return false;
+
// TODO(crbug.com/809738) Register with `PrintBackendServiceManager` when
// system print is enabled out-of-process. A corresponding unregister should
// go in `ReleasePrintJob()`.

View File

@@ -0,0 +1,188 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Xinghui Lu <xinghuilu@chromium.org>
Date: Thu, 6 Jan 2022 08:36:45 +0000
Subject: Use RFH global id to ensure the RFH is valid.
Observing via RenderFrameDeleted and RenderFrameHostChanged is not
sufficient for validating the RFH is still valid, because the frames
can belong to inner WebContents. As suggested in
https://crrev.com/c/2449389, storing a GlobalFrameRoutingId is the
preferred method of keeping a reference to a RFH.
Bug: 1284367
Change-Id: I3afb40e394d6e2e7fd19b2704e0dd68fa23c7bb2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3367466
Reviewed-by: Daniel Rubery <drubery@chromium.org>
Commit-Queue: Xinghui Lu <xinghuilu@chromium.org>
Cr-Commit-Position: refs/heads/main@{#956061}
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc
index ab395a814221a900976fb5f1cdfd79946ea1b742..4bf428b1a7fc8c331d0644c0785f4e57a31c0884 100644
--- a/chrome/browser/safe_browsing/threat_details_unittest.cc
+++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
@@ -601,7 +601,8 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails) {
parent_node->children.push_back(GURL(kDOMChildURL));
params.push_back(std::move(parent_node));
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(), std::move(params));
+ main_rfh()->GetGlobalId(),
+ std::move(params));
std::string serialized = WaitForThreatDetailsDone(
report.get(), false /* did_proceed*/, 0 /* num_visit */);
@@ -820,10 +821,11 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_MultipleFrames) {
// Send both sets of nodes from different render frames.
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(),
+ main_rfh()->GetGlobalId(),
std::move(outer_params_copy));
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- child_rfh, std::move(inner_params_copy));
+ child_rfh->GetGlobalId(),
+ std::move(inner_params_copy));
std::string serialized = WaitForThreatDetailsDone(
report.get(), false /* did_proceed*/, 0 /* num_visit */);
@@ -869,9 +871,11 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_MultipleFrames) {
// Send both sets of nodes from different render frames.
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- child_rfh, std::move(inner_params));
+ child_rfh->GetGlobalId(),
+ std::move(inner_params));
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(), std::move(outer_params));
+ main_rfh()->GetGlobalId(),
+ std::move(outer_params));
std::string serialized = WaitForThreatDetailsDone(
report.get(), false /* did_proceed*/, 0 /* num_visit */);
@@ -995,9 +999,11 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_AmbiguousDOM) {
// Send both sets of nodes from different render frames.
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(), std::move(outer_params));
+ main_rfh()->GetGlobalId(),
+ std::move(outer_params));
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- child_rfh, std::move(inner_params));
+ child_rfh->GetGlobalId(),
+ std::move(inner_params));
std::string serialized = WaitForThreatDetailsDone(
report.get(), false /* did_proceed*/, 0 /* num_visit */);
ClientSafeBrowsingReportRequest actual;
@@ -1262,10 +1268,10 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_TrimToAdTags) {
// Send both sets of nodes from different render frames.
trimmed_report->OnReceivedThreatDOMDetails(
- mojo::Remote<mojom::ThreatReporter>(), child_rfh,
+ mojo::Remote<mojom::ThreatReporter>(), child_rfh->GetGlobalId(),
std::move(inner_params));
trimmed_report->OnReceivedThreatDOMDetails(
- mojo::Remote<mojom::ThreatReporter>(), main_rfh(),
+ mojo::Remote<mojom::ThreatReporter>(), main_rfh()->GetGlobalId(),
std::move(outer_params));
std::string serialized = WaitForThreatDetailsDone(
@@ -1338,10 +1344,10 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_EmptyReportNotSent) {
// Send both sets of nodes from different render frames.
trimmed_report->OnReceivedThreatDOMDetails(
- mojo::Remote<mojom::ThreatReporter>(), child_rfh,
+ mojo::Remote<mojom::ThreatReporter>(), child_rfh->GetGlobalId(),
std::move(inner_params));
trimmed_report->OnReceivedThreatDOMDetails(
- mojo::Remote<mojom::ThreatReporter>(), main_rfh(),
+ mojo::Remote<mojom::ThreatReporter>(), main_rfh()->GetGlobalId(),
std::move(outer_params));
std::string serialized = WaitForThreatDetailsDone(
@@ -1598,7 +1604,8 @@ TEST_F(ThreatDetailsTest, HTTPCache) {
// The cache collection starts after the IPC from the DOM is fired.
std::vector<mojom::ThreatDOMDetailsNodePtr> params;
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(), std::move(params));
+ main_rfh()->GetGlobalId(),
+ std::move(params));
// Let the cache callbacks complete.
base::RunLoop().RunUntilIdle();
@@ -1678,7 +1685,8 @@ TEST_F(ThreatDetailsTest, HttpsResourceSanitization) {
// The cache collection starts after the IPC from the DOM is fired.
std::vector<mojom::ThreatDOMDetailsNodePtr> params;
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(), std::move(params));
+ main_rfh()->GetGlobalId(),
+ std::move(params));
// Let the cache callbacks complete.
base::RunLoop().RunUntilIdle();
@@ -1761,7 +1769,8 @@ TEST_F(ThreatDetailsTest, HTTPCacheNoEntries) {
// The cache collection starts after the IPC from the DOM is fired.
std::vector<mojom::ThreatDOMDetailsNodePtr> params;
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(), std::move(params));
+ main_rfh()->GetGlobalId(),
+ std::move(params));
// Let the cache callbacks complete.
base::RunLoop().RunUntilIdle();
@@ -1820,7 +1829,8 @@ TEST_F(ThreatDetailsTest, HistoryServiceUrls) {
// The redirects collection starts after the IPC from the DOM is fired.
std::vector<mojom::ThreatDOMDetailsNodePtr> params;
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(), std::move(params));
+ main_rfh()->GetGlobalId(),
+ std::move(params));
// Let the redirects callbacks complete.
base::RunLoop().RunUntilIdle();
diff --git a/components/safe_browsing/content/browser/threat_details.cc b/components/safe_browsing/content/browser/threat_details.cc
index f3fe647b5d443c2a2f284289ae66d81782c5f6e8..361830189b0ab6324fe87719f36f2fa0bc948224 100644
--- a/components/safe_browsing/content/browser/threat_details.cc
+++ b/components/safe_browsing/content/browser/threat_details.cc
@@ -664,16 +664,20 @@ void ThreatDetails::RequestThreatDOMDetails(content::RenderFrameHost* frame) {
pending_render_frame_hosts_.push_back(frame);
raw_threat_report->GetThreatDOMDetails(
base::BindOnce(&ThreatDetails::OnReceivedThreatDOMDetails, GetWeakPtr(),
- std::move(threat_reporter), frame));
+ std::move(threat_reporter), frame->GetGlobalId()));
}
// When the renderer is done, this is called.
void ThreatDetails::OnReceivedThreatDOMDetails(
mojo::Remote<mojom::ThreatReporter> threat_reporter,
- content::RenderFrameHost* sender,
+ content::GlobalRenderFrameHostId sender_id,
std::vector<mojom::ThreatDOMDetailsNodePtr> params) {
// If the RenderFrameHost was closed between sending the IPC and this callback
// running, |sender| will be invalid.
+ auto* sender = content::RenderFrameHost::FromID(sender_id);
+ if (!sender) {
+ return;
+ }
const auto sender_it = std::find(pending_render_frame_hosts_.begin(),
pending_render_frame_hosts_.end(), sender);
if (sender_it == pending_render_frame_hosts_.end()) {
diff --git a/components/safe_browsing/content/browser/threat_details.h b/components/safe_browsing/content/browser/threat_details.h
index 8cb89700141561aab49edc474799c9e7148b8ae8..61dcb8d9c772d223661236d99aebd1d3ebe01d3a 100644
--- a/components/safe_browsing/content/browser/threat_details.h
+++ b/components/safe_browsing/content/browser/threat_details.h
@@ -24,6 +24,7 @@
#include "components/safe_browsing/core/common/proto/csd.pb.h"
#include "components/security_interstitials/core/unsafe_resource.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/web_contents_observer.h"
#include "mojo/public/cpp/bindings/remote.h"
@@ -169,7 +170,7 @@ class ThreatDetails : public content::WebContentsObserver {
void OnReceivedThreatDOMDetails(
mojo::Remote<mojom::ThreatReporter> threat_reporter,
- content::RenderFrameHost* sender,
+ content::GlobalRenderFrameHostId sender_id,
std::vector<mojom::ThreatDOMDetailsNodePtr> params);
void AddRedirectUrlList(const std::vector<GURL>& urls);

View File

@@ -0,0 +1,53 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Muyao Xu <muyaoxu@google.com>
Date: Thu, 17 Feb 2022 16:23:29 +0000
Subject: Replace WidgetObserver::OnWidgetClosing() with OnWidgetDestroying()
In some cases, OnWidgetClosing() is not called when the widget is
closed, resulting an invalid pointer |widget_| stored in
WebContentsDisplayObserverView.
This CL replaces OnWidgetClosing() with OnWidgetDestroying(), which
is recommended in crbug.com/1240365
(cherry picked from commit 4535fe2334d0713535adb52b641a8cb34e11333c)
Bug: 1291728
Change-Id: I64fef8b30930f60220008809ee00f4385d6c3520
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3425473
Auto-Submit: Muyao Xu <muyaoxu@google.com>
Commit-Queue: Takumi Fujimoto <takumif@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#965431}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3435985
Reviewed-by: Michael Ershov <miersh@google.com>
Owners-Override: Michael Ershov <miersh@google.com>
Commit-Queue: Roger Felipe Zanoni da Silva <rzanoni@google.com>
Cr-Commit-Position: refs/branch-heads/4664@{#1480}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/chrome/browser/ui/views/media_router/web_contents_display_observer_view.cc b/chrome/browser/ui/views/media_router/web_contents_display_observer_view.cc
index 80d33b238cd7455ec5b44d5fd966f42f690946bf..2061c2ecb476cd33ed999f180c0293641f7ac23a 100644
--- a/chrome/browser/ui/views/media_router/web_contents_display_observer_view.cc
+++ b/chrome/browser/ui/views/media_router/web_contents_display_observer_view.cc
@@ -65,7 +65,7 @@ void WebContentsDisplayObserverView::OnBrowserSetLastActive(Browser* browser) {
}
}
-void WebContentsDisplayObserverView::OnWidgetClosing(views::Widget* widget) {
+void WebContentsDisplayObserverView::OnWidgetDestroying(views::Widget* widget) {
if (widget_)
widget_->RemoveObserver(this);
widget_ = nullptr;
diff --git a/chrome/browser/ui/views/media_router/web_contents_display_observer_view.h b/chrome/browser/ui/views/media_router/web_contents_display_observer_view.h
index 17a8ca48b1c836a82e2be5e5c605bc1837150cba..b63cf4505318a44c65585b06ec13960bad5d9e32 100644
--- a/chrome/browser/ui/views/media_router/web_contents_display_observer_view.h
+++ b/chrome/browser/ui/views/media_router/web_contents_display_observer_view.h
@@ -28,7 +28,7 @@ class WebContentsDisplayObserverView : public WebContentsDisplayObserver,
void OnBrowserSetLastActive(Browser* browser) override;
// views::WidgetObserver overrides:
- void OnWidgetClosing(views::Widget* widget) override;
+ void OnWidgetDestroying(views::Widget* widget) override;
void OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& new_bounds) override;

View File

@@ -0,0 +1,354 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lukasz Anforowicz <lukasza@chromium.org>
Date: Mon, 8 Nov 2021 15:05:30 +0000
Subject: Deleting unused field: `FetchEventPreloadHandle::url_loader`.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The `FetchEventPreloadHandle::url_loader` field is not really used - it
is only needed to keep the URLLoader alive (and this can be accomplished
in a simpler way, by keeping the mojo::PendingRemote in the Browser
process).
This CL removes the `FetchEventPreloadHandle::url_loader` field and the
FetchEventPreloadHandle and WebFetchEventPreloadHandle types (collapsing
these handle types into their only other remaining field:
mojo::PendingReceiver<network::mojom::URLLoaderClient>).
(cherry picked from commit dbe67ccde52e30acf6a66b1b9cc83768a067fa6a)
Fixed: 1264477
Change-Id: I9c9c54900d79e92ac08eeb43536c938fa84a58f8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3252914
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Ben Kelly <wanderview@chromium.org>
Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org>
Commit-Queue: Łukasz Anforowicz <lukasza@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#937895}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3262600
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Ben Kelly <wanderview@chromium.org>
Cr-Commit-Position: refs/branch-heads/4664@{#853}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index 0d034293826354f6d1b7910a6604f241ff1c8988..b980c5a0745eaf7a904c1047cbe6c5e86cef0c67 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -449,8 +449,10 @@ class ServiceWorkerFetchDispatcher::URLLoaderAssets
// NetworkService.
URLLoaderAssets(
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ mojo::PendingRemote<network::mojom::URLLoader> url_loader,
std::unique_ptr<DelegatingURLLoaderClient> url_loader_client)
: shared_url_loader_factory_(std::move(shared_url_loader_factory)),
+ url_loader_(std::move(url_loader)),
url_loader_client_(std::move(url_loader_client)) {}
void MaybeReportToDevTools(std::pair<int, int> worker_id,
@@ -467,6 +469,7 @@ class ServiceWorkerFetchDispatcher::URLLoaderAssets
// NetworkService:
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
+ mojo::PendingRemote<network::mojom::URLLoader> url_loader_;
// Both:
std::unique_ptr<DelegatingURLLoaderClient> url_loader_client_;
@@ -633,7 +636,8 @@ void ServiceWorkerFetchDispatcher::DispatchFetchEvent() {
auto params = blink::mojom::DispatchFetchEventParams::New();
params->request = std::move(request_);
params->client_id = client_id_;
- params->preload_handle = std::move(preload_handle_);
+ params->preload_url_loader_client_receiver =
+ std::move(preload_url_loader_client_receiver_);
params->is_offline_capability_check = is_offline_capability_check_;
// TODO(https://crbug.com/900700): Make the remote connected to a receiver
@@ -721,13 +725,9 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload(
// When the fetch event is for an offline capability check, respond to the
// navigation preload with a network disconnected error, to simulate offline.
if (is_offline_capability_check_) {
- mojo::PendingRemote<network::mojom::URLLoader> url_loader_to_pass;
mojo::Remote<network::mojom::URLLoaderClient> url_loader_client;
- auto dummy_receiver = url_loader_to_pass.InitWithNewPipeAndPassReceiver();
- preload_handle_ = blink::mojom::FetchEventPreloadHandle::New();
- preload_handle_->url_loader = std::move(url_loader_to_pass);
- preload_handle_->url_loader_client_receiver =
+ preload_url_loader_client_receiver_ =
url_loader_client.BindNewPipeAndPassReceiver();
url_loader_client->OnComplete(
@@ -770,12 +770,10 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload(
factory = base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
std::move(network_factory));
- preload_handle_ = blink::mojom::FetchEventPreloadHandle::New();
-
// Create the DelegatingURLLoaderClient, which becomes the
// URLLoaderClient for the navigation preload network request.
mojo::PendingRemote<network::mojom::URLLoaderClient> inner_url_loader_client;
- preload_handle_->url_loader_client_receiver =
+ preload_url_loader_client_receiver_ =
inner_url_loader_client.InitWithNewPipeAndPassReceiver();
auto url_loader_client = std::make_unique<DelegatingURLLoaderClient>(
std::move(inner_url_loader_client), resource_request);
@@ -810,11 +808,9 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload(
net::MutableNetworkTrafficAnnotationTag(
kNavigationPreloadTrafficAnnotation));
- preload_handle_->url_loader = std::move(url_loader);
-
DCHECK(!url_loader_assets_);
url_loader_assets_ = base::MakeRefCounted<URLLoaderAssets>(
- std::move(factory), std::move(url_loader_client));
+ std::move(factory), std::move(url_loader), std::move(url_loader_client));
return true;
}
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.h b/content/browser/service_worker/service_worker_fetch_dispatcher.h
index 5b2a45bff25b7f2c35e304385f22935c33d60a05..b96b2de068bf9f6a38b4d995cf137ebfd53735ea 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.h
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.h
@@ -121,10 +121,11 @@ class CONTENT_EXPORT ServiceWorkerFetchDispatcher {
scoped_refptr<URLLoaderAssets> url_loader_assets_;
- // |preload_handle_| holds the URLLoader and URLLoaderClient for the service
- // worker to receive the navigation preload response. It's passed to the
- // service worker along with the fetch event.
- blink::mojom::FetchEventPreloadHandlePtr preload_handle_;
+ // Holds the URLLoaderClient for the service worker to receive the navigation
+ // preload response. It's passed to the service worker along with the fetch
+ // event.
+ mojo::PendingReceiver<network::mojom::URLLoaderClient>
+ preload_url_loader_client_receiver_;
// Whether to dispatch an offline-capability-check fetch event.
const bool is_offline_capability_check_ = false;
diff --git a/content/renderer/service_worker/navigation_preload_request.cc b/content/renderer/service_worker/navigation_preload_request.cc
index c9e9ffd4c68a583569fd5633ca2369e190e2aed7..92f9d4a7de115cac0502aeb9c777605a756b6175 100644
--- a/content/renderer/service_worker/navigation_preload_request.cc
+++ b/content/renderer/service_worker/navigation_preload_request.cc
@@ -19,12 +19,12 @@ NavigationPreloadRequest::NavigationPreloadRequest(
ServiceWorkerContextClient* owner,
int fetch_event_id,
const GURL& url,
- blink::mojom::FetchEventPreloadHandlePtr preload_handle)
+ mojo::PendingReceiver<network::mojom::URLLoaderClient>
+ preload_url_loader_client_receiver)
: owner_(owner),
fetch_event_id_(fetch_event_id),
url_(url),
- url_loader_(std::move(preload_handle->url_loader)),
- receiver_(this, std::move(preload_handle->url_loader_client_receiver)) {}
+ receiver_(this, std::move(preload_url_loader_client_receiver)) {}
NavigationPreloadRequest::~NavigationPreloadRequest() = default;
diff --git a/content/renderer/service_worker/navigation_preload_request.h b/content/renderer/service_worker/navigation_preload_request.h
index 08cfc4a0dad5777b88f2388da5d07c864d9953fd..f6d19a3d1383767e1c450be7ec29a47ff245ff5a 100644
--- a/content/renderer/service_worker/navigation_preload_request.h
+++ b/content/renderer/service_worker/navigation_preload_request.h
@@ -35,7 +35,8 @@ class NavigationPreloadRequest final : public network::mojom::URLLoaderClient {
ServiceWorkerContextClient* owner,
int fetch_event_id,
const GURL& url,
- blink::mojom::FetchEventPreloadHandlePtr preload_handle);
+ mojo::PendingReceiver<network::mojom::URLLoaderClient>
+ preload_url_loader_client_receiver);
~NavigationPreloadRequest() override;
// network::mojom::URLLoaderClient:
@@ -59,11 +60,10 @@ class NavigationPreloadRequest final : public network::mojom::URLLoaderClient {
void ReportErrorToOwner(const std::string& message,
blink::WebServiceWorkerError::Mode error_mode);
- ServiceWorkerContextClient* owner_;
+ ServiceWorkerContextClient* owner_ = nullptr;
- const int fetch_event_id_;
+ const int fetch_event_id_ = -1;
const GURL url_;
- mojo::Remote<network::mojom::URLLoader> url_loader_;
mojo::Receiver<network::mojom::URLLoaderClient> receiver_;
std::unique_ptr<blink::WebURLResponse> response_;
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index d569c5362c0c3866b333db714d7dd8e7f3344afc..f65f535b5c228ce881a0b0066b67d9847b6168a4 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -476,14 +476,14 @@ void ServiceWorkerContextClient::SendWorkerStarted(
void ServiceWorkerContextClient::SetupNavigationPreload(
int fetch_event_id,
const blink::WebURL& url,
- std::unique_ptr<blink::WebFetchEventPreloadHandle> preload_handle) {
+ blink::CrossVariantMojoReceiver<
+ network::mojom::URLLoaderClientInterfaceBase>
+ preload_url_loader_client_receiver) {
DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
DCHECK(context_);
auto preload_request = std::make_unique<NavigationPreloadRequest>(
this, fetch_event_id, GURL(url),
- blink::mojom::FetchEventPreloadHandle::New(
- std::move(preload_handle->url_loader),
- std::move(preload_handle->url_loader_client_receiver)));
+ std::move(preload_url_loader_client_receiver));
context_->preload_requests.AddWithID(std::move(preload_request),
fetch_event_id);
}
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index 8191aaec6ed37c6a64bcbd9beac720777de3075e..5abd533c6c3b1926efa6b8fc158562468cc96e19 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -159,8 +159,9 @@ class CONTENT_EXPORT ServiceWorkerContextClient
const blink::WebString& source_url) override;
void SetupNavigationPreload(int fetch_event_id,
const blink::WebURL& url,
- std::unique_ptr<blink::WebFetchEventPreloadHandle>
- preload_handle) override;
+ blink::CrossVariantMojoReceiver<
+ network::mojom::URLLoaderClientInterfaceBase>
+ preload_url_loader_client_receiver) override;
void RequestTermination(RequestTerminationCallback callback) override;
scoped_refptr<blink::WebServiceWorkerFetchContext>
CreateWorkerFetchContextOnInitiatorThread() override;
diff --git a/mojo/public/cpp/bindings/README.md b/mojo/public/cpp/bindings/README.md
index b950df5a7733b26ae3a9dbc1bacc208e584fa9e6..334ba1c8fd92aed36dec6993afe38ca91ffcc49a 100644
--- a/mojo/public/cpp/bindings/README.md
+++ b/mojo/public/cpp/bindings/README.md
@@ -1709,6 +1709,9 @@ C++ sources can depend on shared sources only, by referencing the
`"${target_name}_shared"` target, e.g. `"//foo/mojom:mojom_shared"` in the
example above.
+For converting between Blink and non-Blink variants, please see
+`//third_party/blink/public/platform/cross_variant_mojo_util.h`.
+
## Versioning Considerations
For general documentation of versioning in the Mojom IDL see
diff --git a/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom b/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom
index 382be0b3dd042ceadb73e4d514f93ac7c8624b43..c95a2e255166871ff45b6a4c3a8b206e1dace776 100644
--- a/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom
+++ b/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom
@@ -9,13 +9,6 @@ import "third_party/blink/public/mojom/blob/blob.mojom";
import "third_party/blink/public/mojom/fetch/fetch_api_request.mojom";
import "third_party/blink/public/mojom/timing/worker_timing_container.mojom";
-// Used for service worker navigation preload, to create
-// FetchEvent#preloadResponse.
-struct FetchEventPreloadHandle {
- pending_remote<network.mojom.URLLoader> url_loader;
- pending_receiver<network.mojom.URLLoaderClient> url_loader_client_receiver;
-};
-
// Parameters used for dispatching a FetchEvent.
struct DispatchFetchEventParams {
// FetchEvent#request.
@@ -23,8 +16,9 @@ struct DispatchFetchEventParams {
// FetchEvent#clientId.
string client_id;
+
// FetchEvent#preloadResponse.
- FetchEventPreloadHandle? preload_handle;
+ pending_receiver<network.mojom.URLLoaderClient>? preload_url_loader_client_receiver;
// This is currently null for navigation because it's still being implemented.
// TODO(https://crbug.com/900700): Make this non-nullable when implementation
diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
index 67c0c9d3cb10478755422b489c97afe8adce1a24..0a8cde9a7f6bab9de2c43f13c1bc0d35375bc2b5 100644
--- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
+++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
@@ -31,8 +31,6 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_CONTEXT_CLIENT_H_
#define THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_CONTEXT_CLIENT_H_
-#include <memory>
-
#include "base/memory/scoped_refptr.h"
#include "services/network/public/mojom/url_loader.mojom-shared.h"
#include "third_party/blink/public/mojom/devtools/console_message.mojom-shared.h"
@@ -53,14 +51,6 @@ namespace blink {
class WebServiceWorkerContextProxy;
class WebString;
-// Used to pass the mojom struct blink.mojom.FetchEventPreloadHandle across the
-// boundary between //content and Blink.
-struct WebFetchEventPreloadHandle {
- CrossVariantMojoRemote<network::mojom::URLLoaderInterfaceBase> url_loader;
- CrossVariantMojoReceiver<network::mojom::URLLoaderClientInterfaceBase>
- url_loader_client_receiver;
-};
-
// WebServiceWorkerContextClient is a "client" of a service worker execution
// context. This interface is implemented by the embedder and allows the
// embedder to communicate with the service worker execution context. It is
@@ -166,7 +156,8 @@ class WebServiceWorkerContextClient {
virtual void SetupNavigationPreload(
int fetch_event_id,
const WebURL& url,
- std::unique_ptr<WebFetchEventPreloadHandle> preload_handle) {}
+ CrossVariantMojoReceiver<network::mojom::URLLoaderClientInterfaceBase>
+ preload_url_loader_client_receiver) {}
// Called when we need to request to terminate this worker due to idle
// timeout.
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index 9c2cff1d0433d55c4b08fd4eef83544bd120425b..3e84a0200950a33c93f6e473a2cace4609389aea 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -1514,11 +1514,12 @@ void ServiceWorkerGlobalScope::StartFetchEvent(
params->request->url.ElidedString().Utf8());
// Set up for navigation preload (FetchEvent#preloadResponse) if needed.
- const bool navigation_preload_sent = !!params->preload_handle;
+ bool navigation_preload_sent = !!params->preload_url_loader_client_receiver;
if (navigation_preload_sent) {
To<ServiceWorkerGlobalScopeProxy>(ReportingProxy())
- .SetupNavigationPreload(event_id, params->request->url,
- std::move(params->preload_handle));
+ .SetupNavigationPreload(
+ event_id, params->request->url,
+ std::move(params->preload_url_loader_client_receiver));
}
ScriptState::Scope scope(ScriptController()->GetScriptState());
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
index b2efbea7c370b7f641cad9c5db75f9826ec705ed..33d11a19b350e1dd12c105403ed513e9a62a76ec 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
@@ -257,14 +257,11 @@ bool ServiceWorkerGlobalScopeProxy::IsServiceWorkerGlobalScopeProxy() const {
void ServiceWorkerGlobalScopeProxy::SetupNavigationPreload(
int fetch_event_id,
const KURL& url,
- mojom::blink::FetchEventPreloadHandlePtr preload_handle) {
+ mojo::PendingReceiver<network::mojom::blink::URLLoaderClient>
+ preload_url_loader_client_receiver) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
- auto web_preload_handle = std::make_unique<WebFetchEventPreloadHandle>();
- web_preload_handle->url_loader = std::move(preload_handle->url_loader);
- web_preload_handle->url_loader_client_receiver =
- std::move(preload_handle->url_loader_client_receiver);
- Client().SetupNavigationPreload(fetch_event_id, url,
- std::move(web_preload_handle));
+ Client().SetupNavigationPreload(
+ fetch_event_id, url, std::move(preload_url_loader_client_receiver));
}
void ServiceWorkerGlobalScopeProxy::RequestTermination(
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
index 783dbe1919d1282f40117aea22b75a8e54e82d89..d54a2449da63f67930cb3d85cfbb27c35c45a8d3 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
@@ -129,7 +129,8 @@ class ServiceWorkerGlobalScopeProxy final : public WebServiceWorkerContextProxy,
void SetupNavigationPreload(
int fetch_event_id,
const KURL& url,
- mojom::blink::FetchEventPreloadHandlePtr preload_handle);
+ mojo::PendingReceiver<network::mojom::blink::URLLoaderClient>
+ preload_url_loader_client_receiver);
void RequestTermination(WTF::CrossThreadOnceFunction<void(bool)> callback);
// Detaches this proxy object entirely from the outside world, clearing out

View File

@@ -0,0 +1,36 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tony Herre <toprice@chromium.org>
Date: Fri, 18 Feb 2022 13:52:01 +0000
Subject: Switch to new RequestPermissionsFromCurrentDocument API method for
Media Stream Devices
Switch away from the deprecated RequestPermissions() API, as a part of removing a bug where the previously provided request.security_origin param might get destroyed during the method execution.
(cherry picked from commit cb6778fb965e2b010922f157c68480de863c252e)
Bug: 1283402
Change-Id: I512ce910146ec60d4d35fa1a86a71a3b0983a5d1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3417436
Reviewed-by: Florent Castelli <orphis@chromium.org>
Commit-Queue: Tony Herre <toprice@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#964535}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3473365
Cr-Commit-Position: refs/branch-heads/4844@{#655}
Cr-Branched-From: 007241ce2e6c8e5a7b306cc36c730cd07cd38825-refs/heads/main@{#961656}
diff --git a/components/webrtc/media_stream_devices_controller.cc b/components/webrtc/media_stream_devices_controller.cc
index 8eb0e01815f6a5f2f0241554b3e5b93017564242..33468f9f2b1bcc2cda8d98748902984ae82e147d 100644
--- a/components/webrtc/media_stream_devices_controller.cc
+++ b/components/webrtc/media_stream_devices_controller.cc
@@ -139,9 +139,8 @@ void MediaStreamDevicesController::RequestPermissions(
}
}
- permission_manager->RequestPermissions(
- content_settings_types, rfh, request.security_origin,
- request.user_gesture,
+ permission_manager->RequestPermissionsFromCurrentDocument(
+ content_settings_types, rfh, request.user_gesture,
base::BindOnce(
&MediaStreamDevicesController::RequestAndroidPermissionsIfNeeded,
web_contents, std::move(controller), will_prompt_for_audio,

View File

@@ -0,0 +1,71 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Yutaka Hirano <yhirano@chromium.org>
Date: Wed, 29 Sep 2021 07:58:26 +0000
Subject: Run CORS check for manual redirects
...to prevent status code leak.
Bug: 1251179
Change-Id: I7fcab0daf49e16305ed53702f42d1d1eacc933e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3193481
Reviewed-by: Yoav Weiss <yoavweiss@chromium.org>
Commit-Queue: Yutaka Hirano <yhirano@chromium.org>
Cr-Commit-Position: refs/heads/main@{#926166}
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index 89813366845757aaa31a37ba155ad2e50a2f5010..88f9236a91c3b32cd1daabca4d42e47c4a959746 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -304,13 +304,6 @@ void CorsURLLoader::OnReceiveRedirect(const net::RedirectInfo& redirect_info,
DCHECK(forwarding_client_);
DCHECK(!deferred_redirect_url_);
- if (request_.redirect_mode == mojom::RedirectMode::kManual) {
- deferred_redirect_url_ = std::make_unique<GURL>(redirect_info.new_url);
- forwarding_client_->OnReceiveRedirect(redirect_info,
- std::move(response_head));
- return;
- }
-
// If |CORS flag| is set and a CORS check for |request| and |response| returns
// failure, then return a network error.
if (fetch_cors_flag_ && IsCorsEnabledRequestMode(request_.mode)) {
@@ -328,6 +321,13 @@ void CorsURLLoader::OnReceiveRedirect(const net::RedirectInfo& redirect_info,
}
}
+ if (request_.redirect_mode == mojom::RedirectMode::kManual) {
+ deferred_redirect_url_ = std::make_unique<GURL>(redirect_info.new_url);
+ forwarding_client_->OnReceiveRedirect(redirect_info,
+ std::move(response_head));
+ return;
+ }
+
timing_allow_failed_flag_ = !PassesTimingAllowOriginCheck(*response_head);
// Because we initiate a new request on redirect in some cases, we cannot
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js
index eed44e0414cb8947c9b7c21df6ef288f733f8994..9f1ff98c65af97bcf185867ac6c6e128dbd77715 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js
@@ -1,6 +1,7 @@
// META: script=/common/get-host-info.sub.js
var redirectLocation = "cors-top.txt";
+const { ORIGIN, REMOTE_ORIGIN } = get_host_info();
function testRedirect(origin, redirectStatus, redirectMode, corsMode) {
var url = new URL("../resources/redirect.py", self.location);
@@ -47,4 +48,12 @@ for (var origin of ["same-origin", "cross-origin"]) {
}
}
+promise_test(async (t) => {
+ const destination = `${ORIGIN}/common/blank.html`;
+ // We use /common/redirect.py intentionally, as we want a CORS error.
+ const url =
+ `${REMOTE_ORIGIN}/common/redirect.py?location=${destination}`;
+ await promise_rejects_js(t, TypeError, fetch(url, { redirect: "manual" }));
+}, "manual redirect with a CORS error should be rejected");
+
done();

View File

@@ -0,0 +1,63 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ionel Popescu <iopopesc@microsoft.com>
Date: Wed, 15 Sep 2021 18:16:16 +0000
Subject: Speculative fix for eye dropper getColor crash.
There seems to be a situation where the captured frame coordinates
are different than the ones accessible by moving the mouse.
I am not able to locally reproduce this issue, so I am adding DCHECKs
to validate that the coordinates are correct and I am also handling
the invalid coordinates to prevent invalid memory access.
(cherry picked from commit a656373ae7212e0d88474bdec4691a4152452748)
Bug: 1246631
Change-Id: I915d46a71aa73b5dcf08127d347fdd47c1ddf54c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3152423
Reviewed-by: Mason Freed <masonf@chromium.org>
Commit-Queue: Ionel Popescu <iopopesc@microsoft.com>
Cr-Original-Commit-Position: refs/heads/main@{#920811}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3163070
Auto-Submit: Ionel Popescu <iopopesc@microsoft.com>
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/4638@{#75}
Cr-Branched-From: 159257cab5585bc8421abf347984bb32fdfe9eb9-refs/heads/main@{#920003}
diff --git a/chrome/browser/ui/views/eye_dropper/eye_dropper_view.cc b/chrome/browser/ui/views/eye_dropper/eye_dropper_view.cc
index 46cfbf3f497fa824a112165450d5cc98883a58c3..112b734be608802a33acff0aa790ce7e829b7bb4 100644
--- a/chrome/browser/ui/views/eye_dropper/eye_dropper_view.cc
+++ b/chrome/browser/ui/views/eye_dropper/eye_dropper_view.cc
@@ -65,6 +65,7 @@ class EyeDropperView::ScreenCapturer
std::unique_ptr<webrtc::DesktopFrame> frame) override;
SkBitmap GetBitmap() const;
+ SkColor GetColor(int x, int y) const;
int original_offset_x() const;
int original_offset_y() const;
@@ -125,6 +126,13 @@ SkBitmap EyeDropperView::ScreenCapturer::GetBitmap() const {
return frame_;
}
+SkColor EyeDropperView::ScreenCapturer::GetColor(int x, int y) const {
+ DCHECK(x < frame_.width());
+ DCHECK(y < frame_.height());
+ return x < frame_.width() && y < frame_.height() ? frame_.getColor(x, y)
+ : SK_ColorBLACK;
+}
+
int EyeDropperView::ScreenCapturer::original_offset_x() const {
return original_offset_x_;
}
@@ -224,7 +232,8 @@ void EyeDropperView::OnPaint(gfx::Canvas* view_canvas) {
// Store the pixel color under the cursor as it is the last color seen
// by the user before selection.
- selected_color_ = frame.getColor(center_position.x(), center_position.y());
+ selected_color_ =
+ screen_capturer_->GetColor(center_position.x(), center_position.y());
// Paint grid.
cc::PaintFlags flags;

View File

@@ -0,0 +1,457 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: cfredric <cfredric@chromium.org>
Date: Mon, 27 Sep 2021 22:14:18 +0000
Subject: Consider HTTPS and WSS schemes identically for FPS.
This modifies the FPS implementation to normalize wss:// URLs into
https:// URLs when determining the same-partiness of a request.
This allows SameParty cookies to be sent on same-party WSS connection
requests. A browsertest is included to verify this.
Bug: 1251688
Change-Id: Id277288982805e0d29c6683e0c13d4b7c7cfe359
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3182786
Reviewed-by: Maksim Orlovich <morlovich@chromium.org>
Reviewed-by: Shuran Huang <shuuran@chromium.org>
Commit-Queue: Chris Fredrickson <cfredric@chromium.org>
Cr-Commit-Position: refs/heads/main@{#925457}
diff --git a/chrome/browser/net/websocket_browsertest.cc b/chrome/browser/net/websocket_browsertest.cc
index 0714f0d0231d677edd0f0cdf82f4129ddc43a5c2..6f2f101743fbd470bafe90d7e5d14351ee0ff708 100644
--- a/chrome/browser/net/websocket_browsertest.cc
+++ b/chrome/browser/net/websocket_browsertest.cc
@@ -21,6 +21,7 @@
#include "base/test/bind.h"
#include "build/build_config.h"
#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/login/login_handler.h"
#include "chrome/browser/ui/login/login_handler_test_utils.h"
@@ -45,25 +46,31 @@
#include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/network_isolation_key.h"
#include "net/cookies/site_for_cookies.h"
+#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/spawned_test_server/spawned_test_server.h"
#include "net/test/test_data_directory.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/cpp/network_switches.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/websocket.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace {
+using SSLOptions = net::SpawnedTestServer::SSLOptions;
+
class WebSocketBrowserTest : public InProcessBrowserTest {
public:
- WebSocketBrowserTest()
+ explicit WebSocketBrowserTest(
+ SSLOptions::ServerCertificate cert = SSLOptions::CERT_OK)
: ws_server_(net::SpawnedTestServer::TYPE_WS,
net::GetWebSocketTestDataDirectory()),
wss_server_(net::SpawnedTestServer::TYPE_WSS,
- SSLOptions(SSLOptions::CERT_OK),
+ SSLOptions(cert),
net::GetWebSocketTestDataDirectory()) {}
protected:
@@ -145,7 +152,6 @@ class WebSocketBrowserTest : public InProcessBrowserTest {
net::SpawnedTestServer wss_server_;
private:
- typedef net::SpawnedTestServer::SSLOptions SSLOptions;
std::unique_ptr<content::TitleWatcher> watcher_;
DISALLOW_COPY_AND_ASSIGN(WebSocketBrowserTest);
@@ -162,37 +168,72 @@ class WebSocketBrowserTestWithAllowFileAccessFromFiles
};
// Framework for tests using the connect_to.html page served by a separate HTTP
-// server.
+// or HTTPS server.
class WebSocketBrowserConnectToTest : public WebSocketBrowserTest {
protected:
- WebSocketBrowserConnectToTest() {
- http_server_.ServeFilesFromSourceDirectory(
- net::GetWebSocketTestDataDirectory());
- }
+ explicit WebSocketBrowserConnectToTest(
+ SSLOptions::ServerCertificate cert = SSLOptions::CERT_OK)
+ : WebSocketBrowserTest(cert) {}
// The title watcher and HTTP server are set up automatically by the test
// framework. Each test case still needs to configure and start the
// WebSocket server(s) it needs.
void SetUpOnMainThread() override {
+ server().ServeFilesFromSourceDirectory(
+ net::GetWebSocketTestDataDirectory());
WebSocketBrowserTest::SetUpOnMainThread();
- ASSERT_TRUE(http_server_.Start());
+ ASSERT_TRUE(server().Start());
}
- // Supply a ws: or wss: URL to connect to.
- void ConnectTo(GURL url) {
- ASSERT_TRUE(http_server_.Started());
+ // Supply a ws: or wss: URL to connect to. Serves connect_to.html from the
+ // server's default host.
+ void ConnectTo(const GURL& url) {
+ ConnectTo(server().base_url().host(), url);
+ }
+
+ // Supply a ws: or wss: URL to connect to via loading `host`/connect_to.html.
+ void ConnectTo(const std::string& host, const GURL& url) {
+ ASSERT_TRUE(server().Started());
std::string query("url=" + url.spec());
GURL::Replacements replacements;
replacements.SetQueryStr(query);
- ui_test_utils::NavigateToURL(browser(),
- http_server_.GetURL("/connect_to.html")
- .ReplaceComponents(replacements));
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), server()
+ .GetURL(host, "/connect_to.html")
+ .ReplaceComponents(replacements)));
}
- private:
+ virtual net::EmbeddedTestServer& server() = 0;
+};
+
+// Concrete impl for tests that use connect_to.html over HTTP.
+class WebSocketBrowserHTTPConnectToTest : public WebSocketBrowserConnectToTest {
+ protected:
+ net::EmbeddedTestServer& server() override { return http_server_; }
+
net::EmbeddedTestServer http_server_;
};
+// Concrete impl for tests that use connect_to.html over HTTPS.
+class WebSocketBrowserHTTPSConnectToTest
+ : public WebSocketBrowserConnectToTest {
+ protected:
+ explicit WebSocketBrowserHTTPSConnectToTest(
+ SSLOptions::ServerCertificate cert = SSLOptions::CERT_OK)
+ : WebSocketBrowserConnectToTest(cert),
+ https_server_(net::test_server::EmbeddedTestServer::TYPE_HTTPS) {}
+
+ void SetUpOnMainThread() override {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ server().SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
+ WebSocketBrowserConnectToTest::SetUpOnMainThread();
+ }
+
+ net::EmbeddedTestServer& server() override { return https_server_; }
+
+ net::EmbeddedTestServer https_server_;
+};
+
// Automatically fill in any login prompts that appear with the supplied
// credentials.
class AutoLogin : public content::NotificationObserver {
@@ -352,7 +393,7 @@ IN_PROC_BROWSER_TEST_F(WebSocketBrowserTest,
EXPECT_EQ("PASS", WaitAndGetTitle());
}
-IN_PROC_BROWSER_TEST_F(WebSocketBrowserConnectToTest,
+IN_PROC_BROWSER_TEST_F(WebSocketBrowserHTTPConnectToTest,
WebSocketBasicAuthInWSURL) {
// Launch a basic-auth-protected WebSocket server.
ws_server_.set_websocket_basic_auth(true);
@@ -364,7 +405,7 @@ IN_PROC_BROWSER_TEST_F(WebSocketBrowserConnectToTest,
EXPECT_EQ("PASS", WaitAndGetTitle());
}
-IN_PROC_BROWSER_TEST_F(WebSocketBrowserConnectToTest,
+IN_PROC_BROWSER_TEST_F(WebSocketBrowserHTTPConnectToTest,
WebSocketBasicAuthInWSURLBadCreds) {
// Launch a basic-auth-protected WebSocket server.
ws_server_.set_websocket_basic_auth(true);
@@ -376,7 +417,7 @@ IN_PROC_BROWSER_TEST_F(WebSocketBrowserConnectToTest,
EXPECT_EQ("FAIL", WaitAndGetTitle());
}
-IN_PROC_BROWSER_TEST_F(WebSocketBrowserConnectToTest,
+IN_PROC_BROWSER_TEST_F(WebSocketBrowserHTTPConnectToTest,
WebSocketBasicAuthNoCreds) {
// Launch a basic-auth-protected WebSocket server.
ws_server_.set_websocket_basic_auth(true);
@@ -420,8 +461,7 @@ IN_PROC_BROWSER_TEST_F(WebSocketBrowserTest, MAYBE_WebSocketAppliesHSTS) {
https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
net::SpawnedTestServer wss_server(
net::SpawnedTestServer::TYPE_WSS,
- net::SpawnedTestServer::SSLOptions(
- net::SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN),
+ SSLOptions(SSLOptions::CERT_COMMON_NAME_IS_DOMAIN),
net::GetWebSocketTestDataDirectory());
// This test sets HSTS on localhost. To avoid being redirected to https, start
// the http server on 127.0.0.1 instead.
@@ -711,4 +751,43 @@ IN_PROC_BROWSER_TEST_F(WebSocketBrowserTestWithAllowFileAccessFromFiles,
EXPECT_EQ("FILE", WaitAndGetTitle());
}
+// A test fixture that enables First-Party Sets.
+class FirstPartySetsWebSocketBrowserTest
+ : public WebSocketBrowserHTTPSConnectToTest {
+ public:
+ FirstPartySetsWebSocketBrowserTest()
+ : WebSocketBrowserHTTPSConnectToTest(SSLOptions::CERT_TEST_NAMES) {}
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ WebSocketBrowserTest::SetUpCommandLine(command_line);
+ command_line->AppendSwitchASCII(
+ network::switches::kUseFirstPartySet,
+ "https://a.test,https://b.test,https://c.test");
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(FirstPartySetsWebSocketBrowserTest,
+ SendsSamePartyCookies) {
+ ASSERT_TRUE(wss_server_.Start());
+
+ ASSERT_TRUE(content::SetCookie(browser()->profile(),
+ server().GetURL("a.test", "/"),
+ "same-party-cookie=1; SameParty; Secure"));
+ ASSERT_TRUE(content::SetCookie(browser()->profile(),
+ server().GetURL("a.test", "/"),
+ "same-site-cookie=1; SameSite=Lax; Secure"));
+
+ content::DOMMessageQueue message_queue;
+ ConnectTo("b.test", wss_server_.GetURL("a.test", "echo-request-headers"));
+
+ std::string message;
+ EXPECT_TRUE(message_queue.WaitForMessage(&message));
+ // Only the SameParty cookie should have been sent, since it was a cross-site
+ // but same-party connection.
+ EXPECT_THAT(message, testing::HasSubstr("same-party-cookie=1"));
+ EXPECT_THAT(message, testing::Not(testing::HasSubstr("same-site-cookie=1")));
+
+ EXPECT_EQ("PASS", WaitAndGetTitle());
+}
+
} // namespace
diff --git a/net/data/websocket/connect_to.html b/net/data/websocket/connect_to.html
index 05c653fc5d2ab9a333efea5b4c5eee83a03bbe07..8a6d78214fe5974cbb0ec62b61f4d7fdcdf42c3b 100644
--- a/net/data/websocket/connect_to.html
+++ b/net/data/websocket/connect_to.html
@@ -29,6 +29,17 @@ ws.onclose = function()
document.title = 'FAIL';
}
+ws.onmessage = function(evt)
+{
+ domAutomationController.send(evt.data);
+}
+
+ws.onerror = function(evt)
+{
+ console.error(`WebSocket error: '${evt.message}'`);
+}
+
+
</script>
</head>
</html>
diff --git a/net/test/spawned_test_server/base_test_server.cc b/net/test/spawned_test_server/base_test_server.cc
index 9caaf0ad501322f480be9867909e2e6cb8c56503..54c84e4d0bbd51640b374532fd92903b2e01de58 100644
--- a/net/test/spawned_test_server/base_test_server.cc
+++ b/net/test/spawned_test_server/base_test_server.cc
@@ -156,6 +156,8 @@ base::FilePath BaseTestServer::SSLOptions::GetCertificateFile() const {
FILE_PATH_LITERAL("key_usage_rsa_digitalsignature.pem"));
case CERT_AUTO:
return base::FilePath();
+ case CERT_TEST_NAMES:
+ return base::FilePath(FILE_PATH_LITERAL("test_names.pem"));
default:
NOTREACHED();
}
@@ -249,6 +251,14 @@ GURL BaseTestServer::GetURL(const std::string& path) const {
return GURL(GetScheme() + "://" + host_port_pair_.ToString() + "/" + path);
}
+GURL BaseTestServer::GetURL(const std::string& hostname,
+ const std::string& relative_url) const {
+ GURL local_url = GetURL(relative_url);
+ GURL::Replacements replace_host;
+ replace_host.SetHostStr(hostname);
+ return local_url.ReplaceComponents(replace_host);
+}
+
GURL BaseTestServer::GetURLWithUser(const std::string& path,
const std::string& user) const {
return GURL(GetScheme() + "://" + user + "@" + host_port_pair_.ToString() +
diff --git a/net/test/spawned_test_server/base_test_server.h b/net/test/spawned_test_server/base_test_server.h
index 6c209afcdeeed129ec58f4c55a78501d707fd8f3..848698160b6eba1a02618bfaa968114d10776395 100644
--- a/net/test/spawned_test_server/base_test_server.h
+++ b/net/test/spawned_test_server/base_test_server.h
@@ -82,6 +82,11 @@ class BaseTestServer {
// A certificate with invalid notBefore and notAfter times. Windows'
// certificate library will not parse this certificate.
CERT_BAD_VALIDITY,
+
+ // A certificate that covers a number of test names. See [test_names] in
+ // net/data/ssl/scripts/ee.cnf. More may be added by editing this list and
+ // and rerunning net/data/ssl/scripts/generate-test-certs.sh.
+ CERT_TEST_NAMES,
};
// Bitmask of key exchange algorithms that the test server supports and that
@@ -277,6 +282,8 @@ class BaseTestServer {
bool GetAddressList(AddressList* address_list) const WARN_UNUSED_RESULT;
GURL GetURL(const std::string& path) const;
+ GURL GetURL(const std::string& hostname,
+ const std::string& relative_url) const;
GURL GetURLWithUser(const std::string& path,
const std::string& user) const;
diff --git a/services/network/first_party_sets/first_party_sets.cc b/services/network/first_party_sets/first_party_sets.cc
index 1650c28d8b6c61b30531e1e2ef3e2869d8450360..826b403a2a9702c255ee9b7ea38dc74b9e18791d 100644
--- a/services/network/first_party_sets/first_party_sets.cc
+++ b/services/network/first_party_sets/first_party_sets.cc
@@ -91,16 +91,17 @@ bool FirstPartySets::IsContextSamePartyWithSite(
const net::SchemefulSite* top_frame_site,
const std::set<net::SchemefulSite>& party_context,
bool infer_singleton_sets) const {
- const net::SchemefulSite* site_owner = FindOwner(site, infer_singleton_sets);
- if (!site_owner)
+ const absl::optional<net::SchemefulSite> site_owner =
+ FindOwner(site, infer_singleton_sets);
+ if (!site_owner.has_value())
return false;
const auto is_owned_by_site_owner =
- [this, site_owner,
+ [this, &site_owner,
infer_singleton_sets](const net::SchemefulSite& context_site) -> bool {
- const net::SchemefulSite* context_owner =
+ const absl::optional<net::SchemefulSite> context_owner =
FindOwner(context_site, infer_singleton_sets);
- return context_owner && *context_owner == *site_owner;
+ return context_owner.has_value() && *context_owner == *site_owner;
};
if (top_frame_site && !is_owned_by_site_owner(*top_frame_site))
@@ -131,7 +132,8 @@ net::FirstPartySetsContextType FirstPartySets::ComputeContextType(
const absl::optional<net::SchemefulSite>& top_frame_site,
const std::set<net::SchemefulSite>& party_context) const {
constexpr bool infer_singleton_sets = true;
- const net::SchemefulSite* site_owner = FindOwner(site, infer_singleton_sets);
+ const absl::optional<net::SchemefulSite> site_owner =
+ FindOwner(site, infer_singleton_sets);
// Note: the `party_context` consists of the intermediate frames (for frame
// requests) or intermediate frames and current frame for subresource
// requests.
@@ -152,18 +154,22 @@ net::FirstPartySetsContextType FirstPartySets::ComputeContextType(
: net::FirstPartySetsContextType::kTopResourceMatchMixed;
}
-const net::SchemefulSite* FirstPartySets::FindOwner(
+const absl::optional<net::SchemefulSite> FirstPartySets::FindOwner(
const net::SchemefulSite& site,
bool infer_singleton_sets) const {
- const auto it = sets_.find(site);
- if (it == sets_.end())
- return infer_singleton_sets ? &site : nullptr;
- return &it->second;
+ net::SchemefulSite normalized_site = site;
+ normalized_site.ConvertWebSocketToHttp();
+ const auto it = sets_.find(normalized_site);
+ if (it != sets_.end())
+ return it->second;
+ if (infer_singleton_sets)
+ return normalized_site;
+ return absl::nullopt;
}
bool FirstPartySets::IsInNontrivialFirstPartySet(
const net::SchemefulSite& site) const {
- return base::Contains(sets_, site);
+ return FindOwner(site, /*infer_singleton_sets=*/false).has_value();
}
base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>
@@ -244,7 +250,8 @@ base::flat_set<net::SchemefulSite> FirstPartySets::ComputeSetsDiff(
for (const auto& old_pair : old_sets) {
const net::SchemefulSite& old_member = old_pair.first;
const net::SchemefulSite& old_owner = old_pair.second;
- const net::SchemefulSite* current_owner = FindOwner(old_member, false);
+ const absl::optional<net::SchemefulSite> current_owner =
+ FindOwner(old_member, false);
// Look for the removed sites and the ones have owner changed.
if (!current_owner || *current_owner != old_owner) {
result.emplace(old_member);
diff --git a/services/network/first_party_sets/first_party_sets.h b/services/network/first_party_sets/first_party_sets.h
index 8158b555856526170051cba72a08312a5528de51..fc87e5155667befc5a94bbe539ca71dc47d5f7d1 100644
--- a/services/network/first_party_sets/first_party_sets.h
+++ b/services/network/first_party_sets/first_party_sets.h
@@ -97,11 +97,12 @@ class FirstPartySets {
base::OnceCallback<void(const std::string&)> callback);
private:
- // Returns a pointer to `site`'s owner (optionally inferring a singleton set
- // if necessary), or `nullptr` if `site` has no owner. Must not return
- // `nullptr` if `infer_singleton_sets` is true.
- const net::SchemefulSite* FindOwner(const net::SchemefulSite& site,
- bool infer_singleton_sets) const;
+ // Returns `site`'s owner (optionally inferring a singleton set if necessary),
+ // or `nullopt` if `site` has no owner. Must not return `nullopt` if
+ // `infer_singleton_sets` is true.
+ const absl::optional<net::SchemefulSite> FindOwner(
+ const net::SchemefulSite& site,
+ bool infer_singleton_sets) const;
// We must ensure there's no intersection between the manually-specified set
// and the sets that came from Component Updater. (When reconciling the
diff --git a/services/network/first_party_sets/first_party_sets_unittest.cc b/services/network/first_party_sets/first_party_sets_unittest.cc
index 2055619f4c999cbfd5a5ee4780e2eb5c1dad5816..52eb8e8a3d87172353c64bba972311db2889c693 100644
--- a/services/network/first_party_sets/first_party_sets_unittest.cc
+++ b/services/network/first_party_sets/first_party_sets_unittest.cc
@@ -1167,6 +1167,8 @@ TEST_F(FirstPartySetsTest, ComputeContext) {
net::SchemefulSite nonmember1(GURL("https://nonmember1.test"));
net::SchemefulSite member(GURL("https://member1.test"));
net::SchemefulSite owner(GURL("https://example.test"));
+ net::SchemefulSite wss_member(GURL("wss://member1.test"));
+ net::SchemefulSite wss_nonmember(GURL("wss://nonmember.test"));
// Works as usual for sites that are in First-Party sets.
EXPECT_THAT(sets().ComputeContext(member, &member, {member}),
@@ -1180,10 +1182,17 @@ TEST_F(FirstPartySetsTest, ComputeContext) {
EXPECT_THAT(sets().ComputeContext(member, &member, {member, owner}),
net::SamePartyContext(SamePartyContextType::kSameParty));
+ // Works if the site is provided with WSS scheme instead of HTTPS.
+ EXPECT_THAT(sets().ComputeContext(wss_member, &member, {member, owner}),
+ net::SamePartyContext(SamePartyContextType::kSameParty));
+
EXPECT_THAT(sets().ComputeContext(nonmember, &member, {member}),
net::SamePartyContext(SamePartyContextType::kCrossParty));
EXPECT_THAT(sets().ComputeContext(member, &nonmember, {member}),
net::SamePartyContext(SamePartyContextType::kCrossParty));
+ EXPECT_THAT(
+ sets().ComputeContext(wss_nonmember, &wss_member, {member, owner}),
+ net::SamePartyContext(SamePartyContextType::kCrossParty));
// Top&resource differs from Ancestors.
EXPECT_THAT(sets().ComputeContext(member, &member, {nonmember}),
@@ -1225,6 +1234,12 @@ TEST_F(FirstPartySetsTest, IsInNontrivialFirstPartySet) {
EXPECT_TRUE(sets().IsInNontrivialFirstPartySet(
net::SchemefulSite(GURL("https://member1.test"))));
+ EXPECT_TRUE(sets().IsInNontrivialFirstPartySet(
+ net::SchemefulSite(GURL("wss://member1.test"))));
+
+ EXPECT_FALSE(sets().IsInNontrivialFirstPartySet(
+ net::SchemefulSite(GURL("ws://member1.test"))));
+
EXPECT_FALSE(sets().IsInNontrivialFirstPartySet(
net::SchemefulSite(GURL("https://nonmember.test"))));
}

View File

@@ -0,0 +1,151 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ken Rockot <rockot@google.com>
Date: Thu, 24 Feb 2022 15:13:13 +0000
Subject: Validate message headers sooner
M96 merge issues:
- multiplex_router.h: conflict in removed lines because of
differences in comments above header_validator_
- connector.h: conflicting includes
Message header validation has been tied to interface message dispatch,
but not all mojo::Message consumers are interface bindings.
mojo::Connector is a more general-purpose entry point through which
incoming messages are received and transformed into mojo::Message
objects. Blink's MessagePort implementation uses Connector directly to
transmit and receive raw serialized object data.
This change moves MessageHeaderValidator ownership into Connector and
always applies its validation immediately after reading a message from
the pipe, thereby ensuring that all mojo::Message objects used in
production have validated headers before use.
(cherry picked from commit 8d5bc69146505785ce299c490e35e3f3ef19f69c)
Fixed: 1281908
Change-Id: Ie0e251ab04681a4fd4b849d82c247e0ed800dc04
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3462461
Commit-Queue: Ken Rockot <rockot@google.com>
Cr-Original-Commit-Position: refs/heads/main@{#971263}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3483815
Reviewed-by: Victor-Gabriel Savu <vsavu@google.com>
Owners-Override: Victor-Gabriel Savu <vsavu@google.com>
Commit-Queue: Roger Felipe Zanoni da Silva <rzanoni@google.com>
Cr-Commit-Position: refs/branch-heads/4664@{#1505}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/mojo/public/cpp/bindings/connector.h b/mojo/public/cpp/bindings/connector.h
index 3975d01a434d6caf229c6d8eaedfe5e2acf684f8..ff17af9b378a1992dbd681e80e957826ebfd83dd 100644
--- a/mojo/public/cpp/bindings/connector.h
+++ b/mojo/public/cpp/bindings/connector.h
@@ -18,6 +18,7 @@
#include "base/sequenced_task_runner.h"
#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/bindings/message_header_validator.h"
#include "mojo/public/cpp/bindings/sync_handle_watcher.h"
#include "mojo/public/cpp/system/core.h"
#include "mojo/public/cpp/system/handle_signal_tracker.h"
@@ -345,6 +346,8 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) Connector : public MessageReceiver {
// The number of pending tasks for |CallDispatchNextMessageFromPipe|.
size_t num_pending_dispatch_tasks_ = 0;
+ MessageHeaderValidator header_validator_;
+
#if defined(ENABLE_IPC_FUZZER)
std::unique_ptr<MessageReceiver> message_dumper_;
#endif
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc
index 92a9756cbaebe12377e9c9b81467260c73528311..cb08f13b1bfa13a1a79f7f39005f826e51c12a69 100644
--- a/mojo/public/cpp/bindings/lib/connector.cc
+++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -19,6 +19,7 @@
#include "base/rand_util.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
#include "base/synchronization/lock.h"
#include "base/task/current_thread.h"
#include "base/threading/sequence_local_storage_slot.h"
@@ -152,7 +153,11 @@ Connector::Connector(ScopedMessagePipeHandle message_pipe,
force_immediate_dispatch_(!EnableTaskPerMessage()),
outgoing_serialization_mode_(g_default_outgoing_serialization_mode),
incoming_serialization_mode_(g_default_incoming_serialization_mode),
- interface_name_(interface_name) {
+ interface_name_(interface_name),
+ header_validator_(
+ base::JoinString({interface_name ? interface_name : "Generic",
+ "MessageHeaderValidator"},
+ "")) {
if (config == MULTI_THREADED_SEND)
lock_.emplace();
@@ -492,6 +497,7 @@ MojoResult Connector::ReadMessage(Message* message) {
return result;
*message = Message::CreateFromMessageHandle(&handle);
+
if (message->IsNull()) {
// Even if the read was successful, the Message may still be null if there
// was a problem extracting handles from it. We treat this essentially as
@@ -507,6 +513,10 @@ MojoResult Connector::ReadMessage(Message* message) {
return MOJO_RESULT_ABORTED;
}
+ if (!header_validator_.Accept(message)) {
+ return MOJO_RESULT_ABORTED;
+ }
+
return MOJO_RESULT_OK;
}
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.cc b/mojo/public/cpp/bindings/lib/multiplex_router.cc
index 605e51344d64eb5ede3ab475bc8833b37a458535..23e3970089e33d07b18d734d4f599c9c9f9e4bc8 100644
--- a/mojo/public/cpp/bindings/lib/multiplex_router.cc
+++ b/mojo/public/cpp/bindings/lib/multiplex_router.cc
@@ -23,7 +23,6 @@
#include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
#include "mojo/public/cpp/bindings/lib/may_auto_lock.h"
#include "mojo/public/cpp/bindings/lib/message_quota_checker.h"
-#include "mojo/public/cpp/bindings/message_header_validator.h"
#include "mojo/public/cpp/bindings/sequence_local_sync_event_watcher.h"
namespace mojo {
@@ -389,14 +388,7 @@ MultiplexRouter::MultiplexRouter(
if (quota_checker)
connector_.SetMessageQuotaChecker(std::move(quota_checker));
- std::unique_ptr<MessageHeaderValidator> header_validator =
- std::make_unique<MessageHeaderValidator>();
- header_validator_ = header_validator.get();
- dispatcher_.SetValidator(std::move(header_validator));
-
if (primary_interface_name) {
- header_validator_->SetDescription(base::JoinString(
- {primary_interface_name, "[primary] MessageHeaderValidator"}, " "));
control_message_handler_.SetDescription(base::JoinString(
{primary_interface_name, "[primary] PipeControlMessageHandler"}, " "));
}
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.h b/mojo/public/cpp/bindings/lib/multiplex_router.h
index 3d3bbb16e25b1adc678e536bd977fa22fc478920..3a9f76a57e301aa89d1bdc5aa1000f815793e238 100644
--- a/mojo/public/cpp/bindings/lib/multiplex_router.h
+++ b/mojo/public/cpp/bindings/lib/multiplex_router.h
@@ -38,7 +38,6 @@ class SequencedTaskRunner;
namespace mojo {
class AsyncFlusher;
-class MessageHeaderValidator;
class PendingFlush;
namespace internal {
@@ -301,9 +300,6 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) MultiplexRouter
scoped_refptr<base::SequencedTaskRunner> task_runner_;
- // Owned by |dispatcher_| below.
- MessageHeaderValidator* header_validator_ = nullptr;
-
MessageDispatcher dispatcher_;
Connector connector_;

View File

@@ -0,0 +1,150 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ted Meyer <tmathmeyer@chromium.org>
Date: Thu, 24 Feb 2022 17:39:53 +0000
Subject: Guard BatchingMediaLog::event_handlers_ with lock
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
It seems that despite MediaLog::OnWebMediaPlayerDestroyed and
MediaLog::AddLogRecord both grabbing a lock,
BatchingMediaLog::AddLogRecordLocked can escape the lock handle by
posting BatchingMediaLog::SendQueuedMediaEvents, causing a race.
When the addition of an event is interrupted by the deletion of a player
due to player culling in MediaInspectorContextImpl, a UAF can occur.
R=dalecurtis
(cherry picked from commit 34526c3d0a857a22618e4d77c7f63b5ca6f8d3d2)
Bug: 1295786
Change-Id: I77df94988f806e4d98924669d27860e50455299d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3451494
Commit-Queue: Ted (Chromium) Meyer <tmathmeyer@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#970815}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3483655
Reviewed-by: Victor-Gabriel Savu <vsavu@google.com>
Owners-Override: Victor-Gabriel Savu <vsavu@google.com>
Commit-Queue: Roger Felipe Zanoni da Silva <rzanoni@google.com>
Cr-Commit-Position: refs/branch-heads/4664@{#1508}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/content/renderer/media/batching_media_log.cc b/content/renderer/media/batching_media_log.cc
index 8d8c5cb28b9bb0fcebcceb9e56db98fdace13c88..2d12a5eb42b930acac74a5ea2b2961e6c7e32fcf 100644
--- a/content/renderer/media/batching_media_log.cc
+++ b/content/renderer/media/batching_media_log.cc
@@ -52,9 +52,9 @@ BatchingMediaLog::BatchingMediaLog(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
std::vector<std::unique_ptr<EventHandler>> event_handlers)
: task_runner_(std::move(task_runner)),
- event_handlers_(std::move(event_handlers)),
tick_clock_(base::DefaultTickClock::GetInstance()),
last_ipc_send_time_(tick_clock_->NowTicks()),
+ event_handlers_(std::move(event_handlers)),
ipc_send_pending_(false),
logged_rate_limit_warning_(false) {
// Pre-bind the WeakPtr on the right thread since we'll receive calls from
@@ -76,6 +76,7 @@ BatchingMediaLog::~BatchingMediaLog() {
}
void BatchingMediaLog::OnWebMediaPlayerDestroyedLocked() {
+ base::AutoLock lock(lock_);
for (const auto& handler : event_handlers_)
handler->OnWebMediaPlayerDestroyed();
}
@@ -198,32 +199,30 @@ std::string BatchingMediaLog::MediaEventToMessageString(
void BatchingMediaLog::SendQueuedMediaEvents() {
DCHECK(task_runner_->BelongsToCurrentThread());
+ base::AutoLock auto_lock(lock_);
- std::vector<media::MediaLogRecord> events_to_send;
- {
- base::AutoLock auto_lock(lock_);
- DCHECK(ipc_send_pending_);
- ipc_send_pending_ = false;
-
- if (last_duration_changed_event_) {
- queued_media_events_.push_back(*last_duration_changed_event_);
- last_duration_changed_event_.reset();
- }
+ DCHECK(ipc_send_pending_);
+ ipc_send_pending_ = false;
- if (last_buffering_state_event_) {
- queued_media_events_.push_back(*last_buffering_state_event_);
- last_buffering_state_event_.reset();
- }
+ if (last_duration_changed_event_) {
+ queued_media_events_.push_back(*last_duration_changed_event_);
+ last_duration_changed_event_.reset();
+ }
- queued_media_events_.swap(events_to_send);
- last_ipc_send_time_ = tick_clock_->NowTicks();
+ if (last_buffering_state_event_) {
+ queued_media_events_.push_back(*last_buffering_state_event_);
+ last_buffering_state_event_.reset();
}
- if (events_to_send.empty())
+ last_ipc_send_time_ = tick_clock_->NowTicks();
+
+ if (queued_media_events_.empty())
return;
for (const auto& handler : event_handlers_)
- handler->SendQueuedMediaEvents(events_to_send);
+ handler->SendQueuedMediaEvents(queued_media_events_);
+
+ queued_media_events_.clear();
}
void BatchingMediaLog::SetTickClockForTesting(
diff --git a/content/renderer/media/batching_media_log.h b/content/renderer/media/batching_media_log.h
index 5810efdf0a75b809b94fb5abcd5f3dfbde7b019d..c59dbf2a2b980a89b41c45818476c77e9096339b 100644
--- a/content/renderer/media/batching_media_log.h
+++ b/content/renderer/media/batching_media_log.h
@@ -63,9 +63,6 @@ class CONTENT_EXPORT BatchingMediaLog : public media::MediaLog {
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- // impl for sending queued events.
- std::vector<std::unique_ptr<EventHandler>> event_handlers_;
-
// |lock_| protects access to all of the following member variables. It
// allows any render process thread to AddEvent(), while preserving their
// sequence for throttled send on |task_runner_| and coherent retrieval by
@@ -73,19 +70,24 @@ class CONTENT_EXPORT BatchingMediaLog : public media::MediaLog {
// guarantees provided by MediaLog, since SendQueuedMediaEvents must also
// be synchronized with respect to AddEvent.
mutable base::Lock lock_;
- const base::TickClock* tick_clock_;
- base::TimeTicks last_ipc_send_time_;
- std::vector<media::MediaLogRecord> queued_media_events_;
+ const base::TickClock* tick_clock_ GUARDED_BY(lock_);
+ base::TimeTicks last_ipc_send_time_ GUARDED_BY(lock_);
+ std::vector<media::MediaLogRecord> queued_media_events_ GUARDED_BY(lock_);
+
+ // impl for sending queued events.
+ std::vector<std::unique_ptr<EventHandler>> event_handlers_ GUARDED_BY(lock_);
// For enforcing max 1 pending send.
- bool ipc_send_pending_;
+ bool ipc_send_pending_ GUARDED_BY(lock_);
// True if we've logged a warning message about exceeding rate limits.
- bool logged_rate_limit_warning_;
+ bool logged_rate_limit_warning_ GUARDED_BY(lock_);
// Limits the number of events we send over IPC to one.
- absl::optional<media::MediaLogRecord> last_duration_changed_event_;
- absl::optional<media::MediaLogRecord> last_buffering_state_event_;
+ absl::optional<media::MediaLogRecord> last_duration_changed_event_
+ GUARDED_BY(lock_);
+ absl::optional<media::MediaLogRecord> last_buffering_state_event_
+ GUARDED_BY(lock_);
// Holds the earliest MEDIA_ERROR_LOG_ENTRY event added to this log. This is
// most likely to contain the most specific information available describing

View File

@@ -0,0 +1,765 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Victor Costan <pwnall@chromium.org>
Date: Thu, 11 Nov 2021 00:22:30 +0000
Subject: M96: Storage Foundation: Share FileState ownership with I/O threads.
blink::NativeIOFile methods implementing the Storage Foundation
JavaScript API pass raw pointers to NativeIOFile::FileState instances to
their corresponding blink::NativeIOFile::Do*() methods, which rely on
that CrossThreadPersistent<NativeIOFile> arguments to keep the
underlying NativeIOFile::FileState instances alive.
CrossThreadPersistent can be used across threads to keep a garbage
collected object alive, together with any non-garbage-collected objects
that it owns. However, relying on CrossThreadPersistent existence to
access the owned objects on a different thread is not safe.
cppgc::subtle::CrossThreadPersistent (blink::CrossThreadPersistent is an
alias to that) has comments explaining that the garbage collected heap
can go away while the CrossThreadPersistent instance exists.
This CL fixes the problem by having the ownership of
NativeIOFile::FileState be shared between the corresponding NativeIOFile
instance and any threads doing I/O on the FileState.
(cherry picked from commit 7dc02206707362f3f92cea93f8eb2fa4af0d375f)
Bug: 1240593
Change-Id: I5c9c818bcb23316fe1fd5afa57ed9c3fdb034377
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3269947
Commit-Queue: Victor Costan <pwnall@chromium.org>
Reviewed-by: Austin Sullivan <asully@chromium.org>
Reviewed-by: Marijn Kruisselbrink <mek@chromium.org>
Reviewed-by: enne <enne@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#940130}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3272672
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/4664@{#945}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/third_party/blink/renderer/modules/native_io/native_io_file.cc b/third_party/blink/renderer/modules/native_io/native_io_file.cc
index 4d5aa4efa13930aea4886bac0fd8ba892ce8b5a5..615c1d3a20cba732a3d981bf6b2df181e56d2727 100644
--- a/third_party/blink/renderer/modules/native_io/native_io_file.cc
+++ b/third_party/blink/renderer/modules/native_io/native_io_file.cc
@@ -9,6 +9,7 @@
#include "base/check.h"
#include "base/files/file.h"
#include "base/location.h"
+#include "base/memory/scoped_refptr.h"
#include "base/numerics/checked_math.h"
#include "base/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
@@ -47,31 +48,167 @@
namespace blink {
-struct NativeIOFile::FileState {
- explicit FileState(base::File file) : file(std::move(file)) {}
+// State and logic for performing file I/O off the JavaScript thread.
+//
+// Instances are allocated on the PartitionAlloc heap. Instances cannot be
+// garbage-collected, because garbage collected heaps get deallocated when the
+// underlying threads are terminated, and we need a guarantee that each
+// instance remains alive while it is used by a thread performing file I/O.
+//
+// Instances are initially constructed on a Blink thread that executes
+// JavaScript, which can be Blink's main thread, or a worker thread. Afterwards,
+// instances are (mostly*) only accessed on dedicated threads that do blocking
+// file I/O.
+//
+// Mostly*: On macOS < 10.15, SetLength() synchronously accesses FileState on
+// the JavaScript thread. This could be fixed with extra thread hopping. We're
+// not currently planning to invest in the fix.
+class NativeIOFile::FileState
+ : public base::RefCountedThreadSafe<NativeIOFile::FileState> {
+ public:
+ explicit FileState(base::File file) : file_(std::move(file)) {
+ DCHECK(file_.IsValid());
+ }
FileState(const FileState&) = delete;
FileState& operator=(const FileState&) = delete;
~FileState() = default;
+ // Returns true until Close() is called. Returns false afterwards.
+ //
+ // On macOS < 10.15, returns false between a TakeFile() call and the
+ // corresponding SetFile() call.
+ bool IsValid() {
+ DCHECK(!IsMainThread());
+
+ WTF::MutexLocker locker(mutex_);
+ return file_.IsValid();
+ }
+
+ void Close() {
+ DCHECK(!IsMainThread());
+
+ WTF::MutexLocker locker(mutex_);
+ DCHECK(file_.IsValid()) << __func__ << " called on invalid file";
+
+ file_.Close();
+ }
+
+ // Returns {length, base::File::FILE_OK} in case of success.
+ // Returns {invalid number, error} in case of failure.
+ std::pair<int64_t, base::File::Error> GetLength() {
+ DCHECK(!IsMainThread());
+
+ WTF::MutexLocker mutex_locker(mutex_);
+ DCHECK(file_.IsValid()) << __func__ << " called on invalid file";
+
+ int64_t length = file_.GetLength();
+ base::File::Error error =
+ (length < 0) ? file_.GetLastFileError() : base::File::FILE_OK;
+
+ return {length, error};
+ }
+
+ // Returns {expected_length, base::File::FILE_OK} in case of success.
+ // Returns {actual file length, error} in case of failure.
+ std::pair<int64_t, base::File::Error> SetLength(int64_t expected_length) {
+ DCHECK(!IsMainThread());
+ DCHECK_GE(expected_length, 0);
+
+ WTF::MutexLocker mutex_locker(mutex_);
+ DCHECK(file_.IsValid()) << __func__ << " called on invalid file";
+
+ bool success = file_.SetLength(expected_length);
+ base::File::Error error =
+ success ? base::File::FILE_OK : file_.GetLastFileError();
+ int64_t actual_length = success ? expected_length : file_.GetLength();
+
+ return {actual_length, error};
+ }
+
+#if defined(OS_MAC)
+ // Used to implement browser-side SetLength() on macOS < 10.15.
+ base::File TakeFile() {
+ WTF::MutexLocker mutex_locker(mutex_);
+ DCHECK(file_.IsValid()) << __func__ << " called on invalid file";
+
+ return std::move(file_);
+ }
+
+ // Used to implement browser-side SetLength() on macOS < 10.15.
+ void SetFile(base::File file) {
+ WTF::MutexLocker locker(mutex_);
+ DCHECK(!file_.IsValid()) << __func__ << " called on valid file";
+
+ file_ = std::move(file);
+ }
+#endif // defined(OS_MAC)
+
+ // Returns {read byte count, base::File::FILE_OK} in case of success.
+ // Returns {invalid number, error} in case of failure.
+ std::pair<int, base::File::Error> Read(NativeIODataBuffer* buffer,
+ int64_t file_offset,
+ int read_size) {
+ DCHECK(!IsMainThread());
+ DCHECK(buffer);
+ DCHECK_GE(file_offset, 0);
+ DCHECK_GE(read_size, 0);
+
+ WTF::MutexLocker mutex_locker(mutex_);
+ DCHECK(file_.IsValid()) << __func__ << " called on invalid file";
+
+ int read_bytes = file_.Read(file_offset, buffer->Data(), read_size);
+ base::File::Error error =
+ (read_bytes < 0) ? file_.GetLastFileError() : base::File::FILE_OK;
+
+ return {read_bytes, error};
+ }
+
+ // Returns {0, write_size, base::File::FILE_OK} in case of success.
+ // Returns {actual file length, written bytes, base::File::OK} in case of a
+ // short write.
+ // Returns {actual file length, invalid number, error} in case of failure.
+ std::tuple<int64_t, int, base::File::Error> Write(NativeIODataBuffer* buffer,
+ int64_t file_offset,
+ int write_size) {
+ DCHECK(!IsMainThread());
+ DCHECK(buffer);
+ DCHECK_GE(file_offset, 0);
+ DCHECK_GE(write_size, 0);
+
+ WTF::MutexLocker mutex_locker(mutex_);
+ DCHECK(file_.IsValid()) << __func__ << " called on invalid file";
+
+ int written_bytes = file_.Write(file_offset, buffer->Data(), write_size);
+ base::File::Error error =
+ (written_bytes < 0) ? file_.GetLastFileError() : base::File::FILE_OK;
+ int64_t actual_file_length_on_failure = 0;
+ if (written_bytes < write_size || error != base::File::FILE_OK) {
+ actual_file_length_on_failure = file_.GetLength();
+ if (actual_file_length_on_failure < 0 && error != base::File::FILE_OK)
+ error = file_.GetLastFileError();
+ }
+
+ return {actual_file_length_on_failure, written_bytes, error};
+ }
+
+ base::File::Error Flush() {
+ DCHECK(!IsMainThread());
+
+ WTF::MutexLocker mutex_locker(mutex_);
+ DCHECK(file_.IsValid()) << __func__ << " called on invalid file";
+
+ bool success = file_.Flush();
+ return success ? base::File::FILE_OK : file_.GetLastFileError();
+ }
+
+ private:
// Lock coordinating cross-thread access to the state.
- WTF::Mutex mutex;
+ WTF::Mutex mutex_;
+
// The file on disk backing this NativeIOFile.
- //
- // The mutex is there to protect us against using the file after it was
- // closed, and against OS-specific behavior around concurrent file access. It
- // should never cause the main (JS) thread to block. This is because the mutex
- // is only taken on the main thread in CloseBackingFile(), which is called
- // when the NativeIOFile is destroyed (which implies there's no pending I/O
- // operation, because all I/O operations hold onto a Persistent<NativeIOFile>)
- // and when the mojo pipe is closed, which currently only happens when the JS
- // context is being torn down.
- //
- // TODO(rstz): Is it possible and worthwhile to remove the mutex and rely
- // exclusively on |NativeIOFile::io_pending_|, or remove
- // |NativeIOFile::io_pending_| in favor of the mutex (might be harder)?
- base::File file GUARDED_BY(mutex);
+ base::File file_ GUARDED_BY(mutex_);
};
NativeIOFile::NativeIOFile(
@@ -81,7 +218,7 @@ NativeIOFile::NativeIOFile(
NativeIOCapacityTracker* capacity_tracker,
ExecutionContext* execution_context)
: file_length_(backing_file_length),
- file_state_(std::make_unique<FileState>(std::move(backing_file))),
+ file_state_(base::MakeRefCounted<FileState>(std::move(backing_file))),
// TODO(pwnall): Get a dedicated queue when the specification matures.
resolver_task_runner_(
execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)),
@@ -94,7 +231,7 @@ NativeIOFile::NativeIOFile(
}
NativeIOFile::~NativeIOFile() {
- // Needed to avoid having the base::File destructor close the file descriptor
+ // Needed to avoid having the FileState destructor close the file descriptor
// synchronously on the main thread.
CloseBackingFile();
}
@@ -114,6 +251,9 @@ ScriptPromise NativeIOFile::close(ScriptState* script_state) {
queued_close_resolver_ = resolver;
if (!io_pending_) {
+ DCHECK(file_state_)
+ << "file_state_ nulled out without setting closed_ or io_pending_";
+
// Pretend that a close() promise was queued behind an I/O operation, and
// the operation just finished. This is less logic than handling the
// non-queued case separately.
@@ -138,18 +278,15 @@ ScriptPromise NativeIOFile::getLength(ScriptState* script_state,
"The file was already closed"));
return ScriptPromise();
}
- io_pending_ = true;
+ DCHECK(file_state_)
+ << "file_state_ nulled out without setting closed_ or io_pending_";
+ io_pending_ = true;
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- // CrossThreadUnretained() is safe here because the NativeIOFile::FileState
- // instance is owned by this NativeIOFile, which is also passed to the task
- // via WrapCrossThreadPersistent. Therefore, the FileState instance is
- // guaranteed to remain alive during the task's execution.
worker_pool::PostTask(
FROM_HERE, {base::MayBlock()},
CrossThreadBindOnce(&DoGetLength, WrapCrossThreadPersistent(this),
- WrapCrossThreadPersistent(resolver),
- CrossThreadUnretained(file_state_.get()),
+ WrapCrossThreadPersistent(resolver), file_state_,
resolver_task_runner_));
return resolver->Promise();
}
@@ -175,6 +312,9 @@ ScriptPromise NativeIOFile::setLength(ScriptState* script_state,
"The file was already closed"));
return ScriptPromise();
}
+ DCHECK(file_state_)
+ << "file_state_ nulled out without setting closed_ or io_pending_";
+
int64_t expected_length = base::as_signed(new_length);
DCHECK_GE(expected_length, 0);
@@ -201,8 +341,8 @@ ScriptPromise NativeIOFile::setLength(ScriptState* script_state,
}
file_length_ = expected_length;
}
- io_pending_ = true;
+ io_pending_ = true;
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
#if defined(OS_MAC)
@@ -217,26 +357,19 @@ ScriptPromise NativeIOFile::setLength(ScriptState* script_state,
// To preserve this invariant, we pass this file's handle to the browser
// process during the SetLength() mojo call, and the browser passes it back
// when the call completes.
- {
- WTF::MutexLocker locker(file_state_->mutex);
- backend_file_->SetLength(
- expected_length, std::move(file_state_->file),
- WTF::Bind(&NativeIOFile::DidSetLengthIpc, WrapPersistent(this),
- WrapPersistent(resolver)));
- }
+ base::File file = file_state_->TakeFile();
+ backend_file_->SetLength(
+ expected_length, std::move(file),
+ WTF::Bind(&NativeIOFile::DidSetLengthIpc, WrapPersistent(this),
+ WrapPersistent(resolver)));
return resolver->Promise();
}
#endif // defined(OS_MAC)
- // CrossThreadUnretained() is safe here because the NativeIOFile::FileState
- // instance is owned by this NativeIOFile, which is also passed to the task
- // via WrapCrossThreadPersistent. Therefore, the FileState instance is
- // guaranteed to remain alive during the task's execution.
worker_pool::PostTask(
FROM_HERE, {base::MayBlock()},
CrossThreadBindOnce(&DoSetLength, WrapCrossThreadPersistent(this),
- WrapCrossThreadPersistent(resolver),
- CrossThreadUnretained(file_state_.get()),
+ WrapCrossThreadPersistent(resolver), file_state_,
resolver_task_runner_, expected_length));
return resolver->Promise();
}
@@ -258,6 +391,8 @@ ScriptPromise NativeIOFile::read(ScriptState* script_state,
"The file was already closed"));
return ScriptPromise();
}
+ DCHECK(file_state_)
+ << "file_state_ nulled out without setting closed_ or io_pending_";
// TODO(pwnall): This assignment should move right before the
// worker_pool::PostTask() call.
@@ -281,16 +416,10 @@ ScriptPromise NativeIOFile::read(ScriptState* script_state,
DCHECK(buffer->IsDetached());
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- // The first CrossThreadUnretained() is safe here because the
- // NativeIOFile::FileState instance is owned by this NativeIOFile, which is
- // also passed to the task via WrapCrossThreadPersistent. Therefore, the
- // FileState instance is guaranteed to remain alive during the task's
- // execution.
worker_pool::PostTask(
FROM_HERE, {base::MayBlock()},
CrossThreadBindOnce(&DoRead, WrapCrossThreadPersistent(this),
- WrapCrossThreadPersistent(resolver),
- CrossThreadUnretained(file_state_.get()),
+ WrapCrossThreadPersistent(resolver), file_state_,
resolver_task_runner_, std::move(result_buffer_data),
file_offset, read_size));
return resolver->Promise();
@@ -313,6 +442,8 @@ ScriptPromise NativeIOFile::write(ScriptState* script_state,
"The file was already closed"));
return ScriptPromise();
}
+ DCHECK(file_state_)
+ << "file_state_ nulled out without setting closed_ or io_pending_";
int write_size = NativeIOOperationSize(*buffer);
int64_t write_end_offset;
@@ -346,6 +477,14 @@ ScriptPromise NativeIOFile::write(ScriptState* script_state,
file_length_ = write_end_offset;
}
+ // TODO(pwnall): This assignment should move right before the
+ // worker_pool::PostTask() call.
+ //
+ // `io_pending_` should only be set to true when we know for sure we'll post a
+ // task that eventually results in getting `io_pending_` set back to false.
+ // Having `io_pending_` set to true in an early return case (rejecting with an
+ // exception) leaves the NativeIOFile "stuck" in a state where all future I/O
+ // method calls will reject.
io_pending_ = true;
std::unique_ptr<NativeIODataBuffer> result_buffer_data =
@@ -358,16 +497,10 @@ ScriptPromise NativeIOFile::write(ScriptState* script_state,
DCHECK(buffer->IsDetached());
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- // The first CrossThreadUnretained() is safe here because the
- // NativeIOFile::FileState instance is owned by this NativeIOFile, which is
- // also passed to the task via WrapCrossThreadPersistent. Therefore, the
- // FileState instance is guaranteed to remain alive during the task's
- // execution.
worker_pool::PostTask(
FROM_HERE, {base::MayBlock()},
CrossThreadBindOnce(&DoWrite, WrapCrossThreadPersistent(this),
- WrapCrossThreadPersistent(resolver),
- CrossThreadUnretained(file_state_.get()),
+ WrapCrossThreadPersistent(resolver), file_state_,
resolver_task_runner_, std::move(result_buffer_data),
file_offset, write_size));
return resolver->Promise();
@@ -391,18 +524,15 @@ ScriptPromise NativeIOFile::flush(ScriptState* script_state,
"The file was already closed"));
return ScriptPromise();
}
- io_pending_ = true;
+ DCHECK(file_state_)
+ << "file_state_ nulled out without setting closed_ or io_pending_";
+ io_pending_ = true;
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- // CrossThreadUnretained() is safe here because the NativeIOFile::FileState
- // instance is owned by this NativeIOFile, which is also passed to the task
- // via WrapCrossThreadPersistent. Therefore, the FileState instance is
- // guaranteed to remain alive during the task's execution.
worker_pool::PostTask(
FROM_HERE, {base::MayBlock()},
CrossThreadBindOnce(&DoFlush, WrapCrossThreadPersistent(this),
- WrapCrossThreadPersistent(resolver),
- CrossThreadUnretained(file_state_.get()),
+ WrapCrossThreadPersistent(resolver), file_state_,
resolver_task_runner_));
return resolver->Promise();
}
@@ -430,28 +560,29 @@ void NativeIOFile::DispatchQueuedClose() {
ScriptPromiseResolver* resolver = queued_close_resolver_;
queued_close_resolver_ = nullptr;
+ scoped_refptr<FileState> file_state = std::move(file_state_);
+ DCHECK(!file_state_);
+
worker_pool::PostTask(
FROM_HERE, {base::MayBlock()},
CrossThreadBindOnce(&DoClose, WrapCrossThreadPersistent(this),
WrapCrossThreadPersistent(resolver),
- CrossThreadUnretained(file_state_.get()),
- resolver_task_runner_));
+ std::move(file_state), resolver_task_runner_));
}
// static
void NativeIOFile::DoClose(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
+ DCHECK(file_state);
+ DCHECK(file_state->IsValid())
+ << "File I/O operation queued after file closed";
+ DCHECK(resolver_task_runner);
- {
- WTF::MutexLocker locker(file_state->mutex);
- DCHECK(file_state->file.IsValid())
- << "file I/O operation queued after file closed";
- file_state->file.Close();
- }
+ file_state->Close();
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
@@ -482,19 +613,17 @@ void NativeIOFile::DidClose(
void NativeIOFile::DoGetLength(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
+ DCHECK(file_state);
+ DCHECK(file_state->IsValid())
+ << "File I/O operation queued after file closed";
+ DCHECK(resolver_task_runner);
+
+ int64_t length;
base::File::Error get_length_error;
- int64_t length = -1;
- {
- WTF::MutexLocker mutex_locker(file_state->mutex);
- DCHECK(file_state->file.IsValid())
- << "file I/O operation queued after file closed";
- length = file_state->file.GetLength();
- get_length_error = (length < 0) ? file_state->file.GetLastFileError()
- : base::File::FILE_OK;
- }
+ std::tie(length, get_length_error) = file_state->GetLength();
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
@@ -541,22 +670,20 @@ void NativeIOFile::DidGetLength(
void NativeIOFile::DoSetLength(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner,
int64_t expected_length) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
+ DCHECK(file_state);
+ DCHECK(file_state->IsValid())
+ << "File I/O operation queued after file closed";
+ DCHECK(resolver_task_runner);
+ DCHECK_GE(expected_length, 0);
- base::File::Error set_length_error;
int64_t actual_length;
- {
- WTF::MutexLocker mutex_locker(file_state->mutex);
- DCHECK(file_state->file.IsValid())
- << "file I/O operation queued after file closed";
- bool success = file_state->file.SetLength(expected_length);
- set_length_error =
- success ? base::File::FILE_OK : file_state->file.GetLastFileError();
- actual_length = success ? expected_length : file_state->file.GetLength();
- }
+ base::File::Error set_length_error;
+ std::tie(actual_length, set_length_error) =
+ file_state->SetLength(expected_length);
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
@@ -619,10 +746,7 @@ void NativeIOFile::DidSetLengthIpc(
int64_t actual_length,
mojom::blink::NativeIOErrorPtr set_length_error) {
DCHECK(backing_file.IsValid()) << "browser returned closed file";
- {
- WTF::MutexLocker locker(file_state_->mutex);
- file_state_->file = std::move(backing_file);
- }
+ file_state_->SetFile(std::move(backing_file));
ScriptState* script_state = resolver->GetScriptState();
DCHECK(io_pending_) << "I/O operation performed without io_pending_ set";
@@ -673,13 +797,15 @@ void NativeIOFile::DidSetLengthIpc(
void NativeIOFile::DoRead(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner,
std::unique_ptr<NativeIODataBuffer> result_buffer_data,
uint64_t file_offset,
int read_size) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
-
+ DCHECK(file_state);
+ DCHECK(file_state->IsValid())
+ << "File I/O operation queued after file closed";
DCHECK(resolver_task_runner);
DCHECK(result_buffer_data);
DCHECK(result_buffer_data->IsValid());
@@ -690,15 +816,8 @@ void NativeIOFile::DoRead(
int read_bytes;
base::File::Error read_error;
- {
- WTF::MutexLocker mutex_locker(file_state->mutex);
- DCHECK(file_state->file.IsValid())
- << "file I/O operation queued after file closed";
- read_bytes = file_state->file.Read(file_offset, result_buffer_data->Data(),
- read_size);
- read_error = (read_bytes < 0) ? file_state->file.GetLastFileError()
- : base::File::FILE_OK;
- }
+ std::tie(read_bytes, read_error) =
+ file_state->Read(result_buffer_data.get(), file_offset, read_size);
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
@@ -743,12 +862,15 @@ void NativeIOFile::DidRead(
void NativeIOFile::DoWrite(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner,
std::unique_ptr<NativeIODataBuffer> result_buffer_data,
uint64_t file_offset,
int write_size) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
+ DCHECK(file_state);
+ DCHECK(file_state->IsValid())
+ << "File I/O operation queued after file closed";
DCHECK(resolver_task_runner);
DCHECK(result_buffer_data);
DCHECK(result_buffer_data->IsValid());
@@ -760,22 +882,8 @@ void NativeIOFile::DoWrite(
int written_bytes;
int64_t actual_file_length_on_failure = 0;
base::File::Error write_error;
- {
- WTF::MutexLocker mutex_locker(file_state->mutex);
- DCHECK(file_state->file.IsValid())
- << "file I/O operation queued after file closed";
- written_bytes = file_state->file.Write(
- file_offset, result_buffer_data->Data(), write_size);
- write_error = (written_bytes < 0) ? file_state->file.GetLastFileError()
- : base::File::FILE_OK;
- if (written_bytes < write_size || write_error != base::File::FILE_OK) {
- actual_file_length_on_failure = file_state->file.GetLength();
- if (actual_file_length_on_failure < 0 &&
- write_error != base::File::FILE_OK) {
- write_error = file_state->file.GetLastFileError();
- }
- }
- }
+ std::tie(actual_file_length_on_failure, written_bytes, write_error) =
+ file_state->Write(result_buffer_data.get(), file_offset, write_size);
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
@@ -846,18 +954,14 @@ void NativeIOFile::DidWrite(
void NativeIOFile::DoFlush(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
- base::File::Error flush_error;
- {
- WTF::MutexLocker mutex_locker(file_state->mutex);
- DCHECK(file_state->file.IsValid())
- << "file I/O operation queued after file closed";
- bool success = file_state->file.Flush();
- flush_error =
- success ? base::File::FILE_OK : file_state->file.GetLastFileError();
- }
+ DCHECK(file_state);
+ DCHECK(file_state->IsValid())
+ << "File I/O operation queued after file closed";
+
+ base::File::Error flush_error = file_state->Flush();
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
@@ -887,20 +991,23 @@ void NativeIOFile::DidFlush(
void NativeIOFile::CloseBackingFile() {
closed_ = true;
- file_state_->mutex.lock();
- base::File backing_file = std::move(file_state_->file);
- file_state_->mutex.unlock();
- if (!backing_file.IsValid()) {
+ if (!file_state_) {
// Avoid posting a cross-thread task if the file is already closed. This is
// the expected path.
return;
}
- worker_pool::PostTask(
- FROM_HERE, {base::MayBlock()},
- CrossThreadBindOnce([](base::File file) { file.Close(); },
- std::move(backing_file)));
+ scoped_refptr<FileState> file_state = std::move(file_state_);
+ DCHECK(!file_state_);
+
+ worker_pool::PostTask(FROM_HERE, {base::MayBlock()},
+ CrossThreadBindOnce(
+ [](scoped_refptr<FileState> file_state) {
+ DCHECK(file_state);
+ file_state->Close();
+ },
+ std::move(file_state)));
}
} // namespace blink
diff --git a/third_party/blink/renderer/modules/native_io/native_io_file.h b/third_party/blink/renderer/modules/native_io/native_io_file.h
index 8ae49ebc2d36d547d152d4e56192e30f8cacd641..95d2da4ac3e1859a0abc21ea15d269758eed1681 100644
--- a/third_party/blink/renderer/modules/native_io/native_io_file.h
+++ b/third_party/blink/renderer/modules/native_io/native_io_file.h
@@ -67,12 +67,7 @@ class NativeIOFile final : public ScriptWrappable {
void Trace(Visitor* visitor) const override;
private:
- // Data accessed on the threads that do file I/O.
- //
- // Instances are allocated on the PartitionAlloc heap. Instances are initially
- // constructed on Blink's main thread, or on a worker thread. Afterwards,
- // instances are only accessed on dedicated threads that do blocking file I/O.
- struct FileState;
+ class FileState;
// Called when the mojo backend disconnects.
void OnBackendDisconnect();
@@ -84,7 +79,7 @@ class NativeIOFile final : public ScriptWrappable {
static void DoClose(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> file_task_runner);
// Performs the post file I/O part of close(), on the main thread.
void DidClose(CrossThreadPersistent<ScriptPromiseResolver> resolver);
@@ -93,7 +88,7 @@ class NativeIOFile final : public ScriptWrappable {
static void DoGetLength(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> file_task_runner);
// Performs the post file I/O part of getLength(), on the main thread.
void DidGetLength(CrossThreadPersistent<ScriptPromiseResolver> resolver,
@@ -104,7 +99,7 @@ class NativeIOFile final : public ScriptWrappable {
static void DoSetLength(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> file_task_runner,
int64_t expected_length);
// Performs the post file I/O part of setLength(), on the main thread.
@@ -128,7 +123,7 @@ class NativeIOFile final : public ScriptWrappable {
// Performs the file I/O part of read(), off the main thread.
static void DoRead(CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> file_task_runner,
std::unique_ptr<NativeIODataBuffer> result_buffer_data,
uint64_t file_offset,
@@ -143,7 +138,7 @@ class NativeIOFile final : public ScriptWrappable {
static void DoWrite(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner,
std::unique_ptr<NativeIODataBuffer> result_buffer_data,
uint64_t file_offset,
@@ -163,7 +158,7 @@ class NativeIOFile final : public ScriptWrappable {
static void DoFlush(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> file_task_runner);
// Performs the post file-I/O part of flush(), on the main thread.
void DidFlush(CrossThreadPersistent<ScriptPromiseResolver> resolver,
@@ -210,8 +205,13 @@ class NativeIOFile final : public ScriptWrappable {
// TODO(rstz): Consider moving this variable into `file_state_`
int64_t file_length_ = 0;
- // See NativeIOFile::FileState, declared above.
- const std::unique_ptr<FileState> file_state_;
+ // Points to a NativeIOFile::FileState while the underlying file is open.
+ //
+ // When the underlying file is closed, this pointer is nulled out, and the
+ // FileState instance is passed to a different thread, where the closing
+ // happens. This avoids having any I/O performed by the base::File::Close()
+ // jank the JavaScript thread that owns this NativeIOFile instance.
+ scoped_refptr<FileState> file_state_;
// Schedules resolving Promises with file I/O results.
const scoped_refptr<base::SequencedTaskRunner> resolver_task_runner_;

View File

@@ -0,0 +1,126 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Sartori <antoniosartori@chromium.org>
Date: Tue, 24 Aug 2021 15:01:17 +0000
Subject: Limit length of 'csp' attribute
Most servers limit the length of request headers anywhere. 4Kb seems
like a reasonable limit, which some popular http servers have by
default, and which we already enforce for Referer
(https://crrev.com/c/1595872).
I would have liked the constant 4096 to be shared between //content
and blink. This would have required putting it somewhere like in
//services/network or in //third_party/blink/common, creating a new
file for it. I thought it would be easier to avoid that for this
change.
It would be safer to not load the iframe document, or to impose some
very strict CSP like "default-src 'none'", instead than just ignoring
the 'csp' attribute if that's too long. However, ignoring is what we
already do if the attribute contains illegal characters or does not
match the CSP grammary or is not subsumed by the parent iframe's csp
attribute. For this change, I believe it's better to stay consistent
with that, and later change the CSPEE code to block loading in all
those cases.
Bug: 1233067
Change-Id: Ie9cd3db82287a76892cca76a0bf0d4a1613a3055
Fixed: 1233067
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3057048
Commit-Queue: Antonio Sartori <antoniosartori@chromium.org>
Reviewed-by: Arthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: Mike West <mkwst@chromium.org>
Cr-Commit-Position: refs/heads/main@{#914730}
diff --git a/content/browser/content_security_policy_browsertest.cc b/content/browser/content_security_policy_browsertest.cc
index 1d0631955600449d142697ce68c474f1957eae75..f95fe16e3c3f8c8b6c603f7cd19dcdb915deacfa 100644
--- a/content/browser/content_security_policy_browsertest.cc
+++ b/content/browser/content_security_policy_browsertest.cc
@@ -225,4 +225,21 @@ IN_PROC_BROWSER_TEST_F(ContentSecurityPolicyBrowserTest, FileURLs) {
}
}
+// Test that a 'csp' attribute longer than 4096 bytes is ignored.
+IN_PROC_BROWSER_TEST_F(ContentSecurityPolicyBrowserTest, CSPAttributeTooLong) {
+ std::string long_csp_attribute = "script-src 'none' ";
+ long_csp_attribute.resize(4097, 'a');
+ std::string page = "data:text/html,<body><iframe csp=\"" +
+ long_csp_attribute + "\"></iframe></body>";
+
+ GURL url(page);
+ WebContentsConsoleObserver console_observer(web_contents());
+ console_observer.SetPattern("'csp' attribute too long*");
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+ console_observer.Wait();
+
+ EXPECT_EQ(current_frame_host()->child_count(), 1u);
+ EXPECT_FALSE(current_frame_host()->child_at(0)->csp_attribute());
+}
+
} // namespace content
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index a0c056f47b9582536f9c8ee93517c872bfadf2e3..72c08a7ac135149b66f6710ff01b4922df5aba24 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -821,9 +821,11 @@ enum class VerifyDidCommitParamsDifference {
};
bool ValidateCSPAttribute(const std::string& value) {
+ static const size_t kMaxLengthCSPAttribute = 4096;
if (!base::IsStringASCII(value))
return false;
- if (value.find('\n') != std::string::npos ||
+ if (value.length() > kMaxLengthCSPAttribute ||
+ value.find('\n') != std::string::npos ||
value.find('\r') != std::string::npos) {
return false;
}
diff --git a/third_party/blink/renderer/core/html/html_iframe_element.cc b/third_party/blink/renderer/core/html/html_iframe_element.cc
index c60e3281ea96ef39e16034c88abf4c6c2a9bd2eb..f9434ae7a2c1066dd2c97f552ee572ca4d808f24 100644
--- a/third_party/blink/renderer/core/html/html_iframe_element.cc
+++ b/third_party/blink/renderer/core/html/html_iframe_element.cc
@@ -208,16 +208,27 @@ void HTMLIFrameElement::ParseAttribute(
UpdateContainerPolicy();
}
} else if (name == html_names::kCspAttr) {
+ static const size_t kMaxLengthCSPAttribute = 4096;
if (value && (value.Contains('\n') || value.Contains('\r') ||
!MatchesTheSerializedCSPGrammar(value.GetString()))) {
+ // TODO(antoniosartori): It would be safer to block loading iframes with
+ // invalid 'csp' attribute.
required_csp_ = g_null_atom;
GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
mojom::blink::ConsoleMessageSource::kOther,
mojom::blink::ConsoleMessageLevel::kError,
"'csp' attribute is invalid: " + value));
- return;
- }
- if (required_csp_ != value) {
+ } else if (value && value.length() > kMaxLengthCSPAttribute) {
+ // TODO(antoniosartori): It would be safer to block loading iframes with
+ // invalid 'csp' attribute.
+ required_csp_ = g_null_atom;
+ GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kOther,
+ mojom::blink::ConsoleMessageLevel::kError,
+ String::Format("'csp' attribute too long. The max length for the "
+ "'csp' attribute is %zu bytes.",
+ kMaxLengthCSPAttribute)));
+ } else if (required_csp_ != value) {
required_csp_ = value;
DidChangeAttributes();
UseCounter::Count(GetDocument(), WebFeature::kIFrameCSPAttribute);
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/embedded-enforcement/required_csp-header.html b/third_party/blink/web_tests/external/wpt/content-security-policy/embedded-enforcement/required_csp-header.html
index a9ad787408786e594ccb554d2bd9186a9e8e7c1e..e0a31db8e28fb1a9d2884c7677597072d4badba2 100644
--- a/third_party/blink/web_tests/external/wpt/content-security-policy/embedded-enforcement/required_csp-header.html
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/embedded-enforcement/required_csp-header.html
@@ -59,6 +59,9 @@
{ "name": "Wrong and dangerous value of `csp` should not trigger sending Sec-Required-CSP Header - report-to present",
"csp": "script-src 'unsafe-inline'; report-to resources/dummy-report.php",
"expected": null },
+ { "name": "Sec-Required-CSP is not sent if `csp` attribute is longer than 4096 bytes",
+ "csp": "style-src " + Array.from(Array(2044).keys()).map(i => 'a').join(' '),
+ "expected": null },
];
tests.forEach(test => {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ken Rockot <rockot@google.com>
Date: Mon, 25 Oct 2021 18:22:50 +0000
Subject: Validate INTRODUCE source node
INTRODUCE NodeChannel messages should only be acknowledged when coming
from the broker process.
(cherry picked from commit 6e74f7b5cb2f48b17403f0431f3e4f3a2e716265)
Fixed: 1252858
Change-Id: I2dff6d5cab102ce744ad2ad66a9f24b4202cbea8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3193798
Reviewed-by: Alex Gough <ajgo@chromium.org>
Commit-Queue: Ken Rockot <rockot@google.com>
Cr-Original-Commit-Position: refs/heads/main@{#926430}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3229034
Auto-Submit: Ken Rockot <rockot@google.com>
Reviewed-by: Oksana Zhuravlova <oksamyt@chromium.org>
Commit-Queue: Oksana Zhuravlova <oksamyt@chromium.org>
Cr-Commit-Position: refs/branch-heads/4638@{#964}
Cr-Branched-From: 159257cab5585bc8421abf347984bb32fdfe9eb9-refs/heads/main@{#920003}
diff --git a/mojo/core/node_controller.cc b/mojo/core/node_controller.cc
index 9f2e79b9e04e9df8aff6c924e6a480ac81857701..21edab39368e69ee6665e490b2c4de13f424edbd 100644
--- a/mojo/core/node_controller.cc
+++ b/mojo/core/node_controller.cc
@@ -20,6 +20,7 @@
#include "mojo/core/broker.h"
#include "mojo/core/broker_host.h"
#include "mojo/core/configuration.h"
+#include "mojo/core/ports/name.h"
#include "mojo/core/request_context.h"
#include "mojo/core/user_message_impl.h"
#include "mojo/public/cpp/platform/named_platform_channel.h"
@@ -1127,6 +1128,12 @@ void NodeController::OnIntroduce(const ports::NodeName& from_node,
const uint64_t remote_capabilities) {
DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ if (broker_name_ == ports::kInvalidNodeName || from_node != broker_name_) {
+ DVLOG(1) << "Ignoring introduction from non-broker process.";
+ DropPeer(from_node, nullptr);
+ return;
+ }
+
if (!channel_handle.is_valid()) {
node_->LostConnectionToNode(name);

View File

@@ -0,0 +1,151 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Stephen Roettger <sroettger@google.com>
Date: Fri, 7 Jan 2022 09:36:31 +0000
Subject: Keep a set of previously dropped peers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Test that a given node name hasn't been seen before.
A side effect of this fix is that re-invitation will not work anymore.
BUG=chromium:1274113
Change-Id: Ibdc50291efa1f6298614b163b544ad980615a981
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3341553
Reviewed-by: Ken Rockot <rockot@google.com>
Commit-Queue: Stephen Röttger <sroettger@google.com>
Cr-Commit-Position: refs/heads/main@{#956441}
diff --git a/mojo/core/invitation_unittest.cc b/mojo/core/invitation_unittest.cc
index 2c8eeef9feefc6be689f1ca2052af316b4b7db68..0687a58ee2b294580d1165e872ec5855e5de2b53 100644
--- a/mojo/core/invitation_unittest.cc
+++ b/mojo/core/invitation_unittest.cc
@@ -693,7 +693,8 @@ DEFINE_TEST_CLIENT(ProcessErrorsClient) {
EXPECT_EQ(kDisconnectMessage, ReadMessage(pipe));
}
-TEST_F(InvitationTest, Reinvitation) {
+// Temporary removed support for reinvitation for non-isolated connections.
+TEST_F(InvitationTest, DISABLED_Reinvitation) {
// The gist of this test is that a process should be able to accept an
// invitation, lose its connection to the process network, and then accept a
// new invitation to re-establish communication.
diff --git a/mojo/core/node_controller.cc b/mojo/core/node_controller.cc
index b34753b2dc0c58e5a80e1d0678ee178e2589e8e3..1a343929127e748b78fdb2107ec7a91f71c846a7 100644
--- a/mojo/core/node_controller.cc
+++ b/mojo/core/node_controller.cc
@@ -543,7 +543,8 @@ scoped_refptr<NodeChannel> NodeController::GetBrokerChannel() {
void NodeController::AddPeer(const ports::NodeName& name,
scoped_refptr<NodeChannel> channel,
- bool start_channel) {
+ bool start_channel,
+ bool allow_name_reuse) {
DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
DCHECK(name != ports::kInvalidNodeName);
@@ -562,6 +563,11 @@ void NodeController::AddPeer(const ports::NodeName& name,
return;
}
+ if (dropped_peers_.Contains(name) && !allow_name_reuse) {
+ LOG(ERROR) << "Trying to re-add dropped peer " << name;
+ return;
+ }
+
auto result = peers_.insert(std::make_pair(name, channel));
DCHECK(result.second);
@@ -602,6 +608,7 @@ void NodeController::DropPeer(const ports::NodeName& node_name,
if (it != peers_.end()) {
ports::NodeName peer = it->first;
peers_.erase(it);
+ dropped_peers_.Insert(peer);
DVLOG(1) << "Dropped peer " << peer;
}
@@ -1270,7 +1277,8 @@ void NodeController::OnAcceptPeer(const ports::NodeName& from_node,
// Note that we explicitly drop any prior connection to the same peer so
// that new isolated connections can replace old ones.
DropPeer(peer_name, nullptr);
- AddPeer(peer_name, channel, false /* start_channel */);
+ AddPeer(peer_name, channel, false /* start_channel */,
+ true /* allow_name_reuse */);
DVLOG(1) << "Node " << name_ << " accepted peer " << peer_name;
}
@@ -1386,5 +1394,24 @@ NodeController::IsolatedConnection&
NodeController::IsolatedConnection::operator=(IsolatedConnection&& other) =
default;
+BoundedPeerSet::BoundedPeerSet() = default;
+BoundedPeerSet::~BoundedPeerSet() = default;
+
+void BoundedPeerSet::Insert(const ports::NodeName& name) {
+ if (new_set_.size() == kHalfSize) {
+ old_set_.clear();
+ std::swap(old_set_, new_set_);
+ }
+ new_set_.insert(name);
+}
+
+bool BoundedPeerSet::Contains(const ports::NodeName& name) {
+ if (old_set_.find(name) != old_set_.end())
+ return true;
+ if (new_set_.find(name) != new_set_.end())
+ return true;
+ return false;
+}
+
} // namespace core
} // namespace mojo
diff --git a/mojo/core/node_controller.h b/mojo/core/node_controller.h
index 040eeab79f72efcdb2823cf62e7dbaefa8b9233f..571e578da4950135456bb97c8ea7a30ceabca7cc 100644
--- a/mojo/core/node_controller.h
+++ b/mojo/core/node_controller.h
@@ -38,6 +38,26 @@ namespace core {
class Broker;
class Core;
+// A set of NodeNames that is bounded by a maximum size.
+// If the max size is reached, it will delete the older half of stored names.
+class BoundedPeerSet {
+ public:
+ BoundedPeerSet();
+ BoundedPeerSet(const BoundedPeerSet&) = delete;
+ BoundedPeerSet& operator=(const BoundedPeerSet&) = delete;
+
+ ~BoundedPeerSet();
+
+ void Insert(const ports::NodeName& name);
+ bool Contains(const ports::NodeName& name);
+
+ private:
+ static constexpr int kHalfSize = 50000;
+
+ std::unordered_set<ports::NodeName> old_set_;
+ std::unordered_set<ports::NodeName> new_set_;
+};
+
// The owner of ports::Node which facilitates core EDK implementation. All
// public interface methods are safe to call from any thread.
class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
@@ -180,7 +200,8 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
void AddPeer(const ports::NodeName& name,
scoped_refptr<NodeChannel> channel,
- bool start_channel);
+ bool start_channel,
+ bool allow_name_reuse = false);
void DropPeer(const ports::NodeName& name, NodeChannel* channel);
void SendPeerEvent(const ports::NodeName& name, ports::ScopedEvent event);
void DropAllPeers();
@@ -265,6 +286,7 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
// Channels to known peers, including inviter and invitees, if any.
NodeMap peers_;
+ BoundedPeerSet dropped_peers_;
// Outgoing message queues for peers we've heard of but can't yet talk to.
std::unordered_map<ports::NodeName, OutgoingMessageQueue>

View File

@@ -0,0 +1,649 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Victor Costan <pwnall@chromium.org>
Date: Wed, 10 Nov 2021 21:14:03 +0000
Subject: M96: Storage Foundation: Avoid cross-thread access of
DOMArrayBufferView.
blink::NativeIOFile::{read, write}() (in the Storage Foundation API
implementation) pass DOMArrayBufferView instances to
blink::NativeIOFile::Do{Read,Write}() via CrossThreadPersistent.
blink::NativeIOFile::Do{Read,Write}() accesses these instances.
CrossThreadPersistent can be used across threads to keep a garbage
collected object alive. However, accessing the object on a different
thread is not safe. cppgc::subtle::CrossThreadPersistent
(blink::CrossThreadPersistent is an alias to that) has comments
explaining that the garbage collected heap can go away while the
CrossThreadPersistent instance exists.
This CL bypasses the problem by having Do{Read,Write}() receive a
ArrayBufferContents that has the DOMArrayBufferView's backing buffer.
ArrayBufferContents is not garbage-collected, so it can be safely used
across threads.
This CL introduces a NativeIODataBuffer class that contains the logic
and state for tearing a DOMArrayBufferView apart into its components
(backing buffer, view type, view offset, view length) and putting it
back together into a new DOMArrayBufferView, after it doesn't need to be
accessed cross-thread anymore.
(cherry picked from commit 5200793c2aea5979cc79f3350a4e3d6c0795d6f2)
Bug: 1268274
Change-Id: I51588f5bfe963de96ce426e0f480e8c5b4902688
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3269366
Commit-Queue: Victor Costan <pwnall@chromium.org>
Reviewed-by: enne <enne@chromium.org>
Reviewed-by: Joshua Bell <jsbell@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#940070}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3272377
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/4664@{#941}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/third_party/blink/renderer/modules/native_io/native_io_file.cc b/third_party/blink/renderer/modules/native_io/native_io_file.cc
index b25cf909f05be73f690fabee7942ee1fa83c1e04..4d5aa4efa13930aea4886bac0fd8ba892ce8b5a5 100644
--- a/third_party/blink/renderer/modules/native_io/native_io_file.cc
+++ b/third_party/blink/renderer/modules/native_io/native_io_file.cc
@@ -24,7 +24,9 @@
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h"
+#include "third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
#include "third_party/blink/renderer/modules/native_io/native_io_error.h"
#include "third_party/blink/renderer/modules/native_io/native_io_file_utils.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h"
@@ -256,39 +258,41 @@ ScriptPromise NativeIOFile::read(ScriptState* script_state,
"The file was already closed"));
return ScriptPromise();
}
+
+ // TODO(pwnall): This assignment should move right before the
+ // worker_pool::PostTask() call.
+ //
+ // `io_pending_` should only be set to true when we know for sure we'll post a
+ // task that eventually results in getting `io_pending_` set back to false.
+ // Having `io_pending_` set to true in an early return case (rejecting with an
+ // exception) leaves the NativeIOFile "stuck" in a state where all future I/O
+ // method calls will reject.
io_pending_ = true;
int read_size = NativeIOOperationSize(*buffer);
- DOMArrayBufferView* result_buffer =
- TransferToNewArrayBufferView(script_state->GetIsolate(), buffer);
- if (!result_buffer) {
+ std::unique_ptr<NativeIODataBuffer> result_buffer_data =
+ NativeIODataBuffer::Create(script_state, buffer);
+ if (!result_buffer_data) {
exception_state.ThrowTypeError("Could not transfer buffer");
return ScriptPromise();
}
+ DCHECK(result_buffer_data->IsValid());
DCHECK(buffer->IsDetached());
- char* result_buffer_data = static_cast<char*>(result_buffer->BaseAddress());
-
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
// The first CrossThreadUnretained() is safe here because the
// NativeIOFile::FileState instance is owned by this NativeIOFile, which is
// also passed to the task via WrapCrossThreadPersistent. Therefore, the
// FileState instance is guaranteed to remain alive during the task's
// execution.
- //
- // The second CrossThreadUnretained() is safe here because result_buffer_data
- // is backed by a DOMArrayBufferView that is also passed to the task via
- // WrapCrossThreadPersistent. Therefore, the buffer is guaranteed to remain
- // alive during the task's execution.
worker_pool::PostTask(
FROM_HERE, {base::MayBlock()},
- CrossThreadBindOnce(
- &DoRead, WrapCrossThreadPersistent(this),
- WrapCrossThreadPersistent(resolver),
- WrapCrossThreadPersistent(result_buffer),
- CrossThreadUnretained(file_state_.get()), resolver_task_runner_,
- CrossThreadUnretained(result_buffer_data), file_offset, read_size));
+ CrossThreadBindOnce(&DoRead, WrapCrossThreadPersistent(this),
+ WrapCrossThreadPersistent(resolver),
+ CrossThreadUnretained(file_state_.get()),
+ resolver_task_runner_, std::move(result_buffer_data),
+ file_offset, read_size));
return resolver->Promise();
}
@@ -344,35 +348,28 @@ ScriptPromise NativeIOFile::write(ScriptState* script_state,
io_pending_ = true;
- DOMArrayBufferView* result_buffer =
- TransferToNewArrayBufferView(script_state->GetIsolate(), buffer);
- if (!result_buffer) {
+ std::unique_ptr<NativeIODataBuffer> result_buffer_data =
+ NativeIODataBuffer::Create(script_state, buffer);
+ if (!result_buffer_data) {
exception_state.ThrowTypeError("Could not transfer buffer");
return ScriptPromise();
}
+ DCHECK(result_buffer_data->IsValid());
DCHECK(buffer->IsDetached());
- char* result_buffer_data = static_cast<char*>(result_buffer->BaseAddress());
-
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
// The first CrossThreadUnretained() is safe here because the
// NativeIOFile::FileState instance is owned by this NativeIOFile, which is
// also passed to the task via WrapCrossThreadPersistent. Therefore, the
// FileState instance is guaranteed to remain alive during the task's
// execution.
- //
- // The second CrossThreadUnretained() is safe here because result_buffer_data
- // is backed by a DOMArrayBufferView that is also passed to the task via
- // WrapCrossThreadPersistent. Therefore, the data is guaranteed to remain
- // alive during the task's execution.
worker_pool::PostTask(
FROM_HERE, {base::MayBlock()},
- CrossThreadBindOnce(
- &DoWrite, WrapCrossThreadPersistent(this),
- WrapCrossThreadPersistent(resolver),
- WrapCrossThreadPersistent(result_buffer),
- CrossThreadUnretained(file_state_.get()), resolver_task_runner_,
- CrossThreadUnretained(result_buffer_data), file_offset, write_size));
+ CrossThreadBindOnce(&DoWrite, WrapCrossThreadPersistent(this),
+ WrapCrossThreadPersistent(resolver),
+ CrossThreadUnretained(file_state_.get()),
+ resolver_task_runner_, std::move(result_buffer_data),
+ file_offset, write_size));
return resolver->Promise();
}
@@ -676,22 +673,29 @@ void NativeIOFile::DidSetLengthIpc(
void NativeIOFile::DoRead(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- CrossThreadPersistent<DOMArrayBufferView> result_buffer,
NativeIOFile::FileState* file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner,
- char* result_buffer_data,
+ std::unique_ptr<NativeIODataBuffer> result_buffer_data,
uint64_t file_offset,
int read_size) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
+ DCHECK(resolver_task_runner);
+ DCHECK(result_buffer_data);
+ DCHECK(result_buffer_data->IsValid());
+ DCHECK_GE(read_size, 0);
+#if DCHECK_IS_ON()
+ DCHECK_LE(static_cast<size_t>(read_size), result_buffer_data->DataLength());
+#endif // DCHECK_IS_ON()
+
int read_bytes;
base::File::Error read_error;
{
WTF::MutexLocker mutex_locker(file_state->mutex);
DCHECK(file_state->file.IsValid())
<< "file I/O operation queued after file closed";
- read_bytes =
- file_state->file.Read(file_offset, result_buffer_data, read_size);
+ read_bytes = file_state->file.Read(file_offset, result_buffer_data->Data(),
+ read_size);
read_error = (read_bytes < 0) ? file_state->file.GetLastFileError()
: base::File::FILE_OK;
}
@@ -699,15 +703,18 @@ void NativeIOFile::DoRead(
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
CrossThreadBindOnce(&NativeIOFile::DidRead, std::move(native_io_file),
- std::move(resolver), std::move(result_buffer),
+ std::move(resolver), std::move(result_buffer_data),
read_bytes, read_error));
}
void NativeIOFile::DidRead(
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- CrossThreadPersistent<DOMArrayBufferView> result_buffer,
+ std::unique_ptr<NativeIODataBuffer> result_buffer_data,
int read_bytes,
base::File::Error read_error) {
+ DCHECK(result_buffer_data);
+ DCHECK(result_buffer_data->IsValid());
+
ScriptState* script_state = resolver->GetScriptState();
if (!script_state->ContextIsValid())
return;
@@ -727,7 +734,7 @@ void NativeIOFile::DidRead(
DCHECK_EQ(read_error, base::File::FILE_OK)
<< "Error set but positive number of bytes read.";
NativeIOReadResult* read_result = MakeGarbageCollected<NativeIOReadResult>();
- read_result->setBuffer(NotShared<DOMArrayBufferView>(result_buffer));
+ read_result->setBuffer(result_buffer_data->Take());
read_result->setReadBytes(read_bytes);
resolver->Resolve(read_result);
}
@@ -736,13 +743,19 @@ void NativeIOFile::DidRead(
void NativeIOFile::DoWrite(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- CrossThreadPersistent<DOMArrayBufferView> result_buffer,
NativeIOFile::FileState* file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner,
- const char* result_buffer_data,
+ std::unique_ptr<NativeIODataBuffer> result_buffer_data,
uint64_t file_offset,
int write_size) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
+ DCHECK(resolver_task_runner);
+ DCHECK(result_buffer_data);
+ DCHECK(result_buffer_data->IsValid());
+ DCHECK_GE(write_size, 0);
+#if DCHECK_IS_ON()
+ DCHECK_LE(static_cast<size_t>(write_size), result_buffer_data->DataLength());
+#endif // DCHECK_IS_ON()
int written_bytes;
int64_t actual_file_length_on_failure = 0;
@@ -751,8 +764,8 @@ void NativeIOFile::DoWrite(
WTF::MutexLocker mutex_locker(file_state->mutex);
DCHECK(file_state->file.IsValid())
<< "file I/O operation queued after file closed";
- written_bytes =
- file_state->file.Write(file_offset, result_buffer_data, write_size);
+ written_bytes = file_state->file.Write(
+ file_offset, result_buffer_data->Data(), write_size);
write_error = (written_bytes < 0) ? file_state->file.GetLastFileError()
: base::File::FILE_OK;
if (written_bytes < write_size || write_error != base::File::FILE_OK) {
@@ -767,18 +780,21 @@ void NativeIOFile::DoWrite(
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
CrossThreadBindOnce(&NativeIOFile::DidWrite, std::move(native_io_file),
- std::move(resolver), std::move(result_buffer),
+ std::move(resolver), std::move(result_buffer_data),
written_bytes, write_error, write_size,
actual_file_length_on_failure));
}
void NativeIOFile::DidWrite(
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- CrossThreadPersistent<DOMArrayBufferView> result_buffer,
+ std::unique_ptr<NativeIODataBuffer> result_buffer_data,
int written_bytes,
base::File::Error write_error,
int write_size,
int64_t actual_file_length_on_failure) {
+ DCHECK(result_buffer_data);
+ DCHECK(result_buffer_data->IsValid());
+
ScriptState* script_state = resolver->GetScriptState();
if (!script_state->ContextIsValid())
return;
@@ -821,7 +837,7 @@ void NativeIOFile::DidWrite(
DCHECK_EQ(write_error, base::File::FILE_OK);
NativeIOWriteResult* write_result =
MakeGarbageCollected<NativeIOWriteResult>();
- write_result->setBuffer(NotShared<DOMArrayBufferView>(result_buffer));
+ write_result->setBuffer(result_buffer_data->Take());
write_result->setWrittenBytes(written_bytes);
resolver->Resolve(write_result);
}
diff --git a/third_party/blink/renderer/modules/native_io/native_io_file.h b/third_party/blink/renderer/modules/native_io/native_io_file.h
index 2e41efeefbcf9805ec2b2ed70d018c717c5c75d1..8ae49ebc2d36d547d152d4e56192e30f8cacd641 100644
--- a/third_party/blink/renderer/modules/native_io/native_io_file.h
+++ b/third_party/blink/renderer/modules/native_io/native_io_file.h
@@ -16,6 +16,7 @@
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
#include "third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.h"
+#include "third_party/blink/renderer/modules/native_io/native_io_file_utils.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
@@ -127,15 +128,14 @@ class NativeIOFile final : public ScriptWrappable {
// Performs the file I/O part of read(), off the main thread.
static void DoRead(CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- CrossThreadPersistent<DOMArrayBufferView> result_buffer,
NativeIOFile::FileState* file_state,
scoped_refptr<base::SequencedTaskRunner> file_task_runner,
- char* result_buffer_data,
+ std::unique_ptr<NativeIODataBuffer> result_buffer_data,
uint64_t file_offset,
int read_size);
// Performs the post file I/O part of read(), on the main thread.
void DidRead(CrossThreadPersistent<ScriptPromiseResolver> resolver,
- CrossThreadPersistent<DOMArrayBufferView> result_buffer,
+ std::unique_ptr<NativeIODataBuffer> result_buffer_data,
int read_bytes,
base::File::Error read_error);
@@ -143,10 +143,9 @@ class NativeIOFile final : public ScriptWrappable {
static void DoWrite(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- CrossThreadPersistent<DOMArrayBufferView> result_buffer,
NativeIOFile::FileState* file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner,
- const char* result_buffer_data,
+ std::unique_ptr<NativeIODataBuffer> result_buffer_data,
uint64_t file_offset,
int write_size);
// Performs the post file I/O part of write(), on the main thread.
@@ -154,7 +153,7 @@ class NativeIOFile final : public ScriptWrappable {
// `actual_file_length_on_failure` is negative if the I/O operation was
// unsuccessful and the correct length of the file could not be determined.
void DidWrite(CrossThreadPersistent<ScriptPromiseResolver> resolver,
- CrossThreadPersistent<DOMArrayBufferView> result_buffer,
+ std::unique_ptr<NativeIODataBuffer> result_buffer_data,
int written_bytes,
base::File::Error write_error,
int write_size,
diff --git a/third_party/blink/renderer/modules/native_io/native_io_file_utils.cc b/third_party/blink/renderer/modules/native_io/native_io_file_utils.cc
index c50a0a94d111d9ea4eb1eac8a7da920936e0d1a3..3e98a12059374d41b22c8d5c706c31e81581aeae 100644
--- a/third_party/blink/renderer/modules/native_io/native_io_file_utils.cc
+++ b/third_party/blink/renderer/modules/native_io/native_io_file_utils.cc
@@ -3,9 +3,16 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/native_io/native_io_file_utils.h"
+
#include "base/numerics/safe_conversions.h"
+#include "base/sequence_checker.h"
+#include "base/types/pass_key.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_data_view.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "v8/include/v8.h"
namespace blink {
@@ -72,4 +79,140 @@ DOMArrayBufferView* TransferToNewArrayBufferView(
return target;
}
+// static
+std::unique_ptr<NativeIODataBuffer> NativeIODataBuffer::Create(
+ ScriptState* script_state,
+ NotShared<DOMArrayBufferView> source) {
+ DCHECK(script_state);
+ DCHECK(source);
+
+ DOMArrayBufferView::ViewType type = source->GetType();
+ size_t offset = source->byteOffset();
+ size_t byte_length = source->byteLength();
+ size_t length = byte_length / source->TypeSize();
+
+ // Explicitly fail if the source buffer is not detachable. On its own,
+ // Transfer() copies non-detachable input buffers.
+ DOMArrayBuffer* buffer = source->buffer();
+ v8::Isolate* isolate = script_state->GetIsolate();
+ if (!buffer->IsDetachable(isolate))
+ return nullptr;
+
+ ArrayBufferContents contents;
+ if (!buffer->Transfer(isolate, contents))
+ return nullptr;
+ DCHECK(source->IsDetached());
+
+ return std::make_unique<NativeIODataBuffer>(
+ std::move(contents), type, offset,
+#if DCHECK_IS_ON()
+ byte_length,
+#endif // DCHECK_IS_ON()
+ length, base::PassKey<NativeIODataBuffer>());
+}
+
+NativeIODataBuffer::NativeIODataBuffer(ArrayBufferContents contents,
+ DOMArrayBufferView::ViewType type,
+ size_t offset,
+#if DCHECK_IS_ON()
+ size_t byte_length,
+#endif // DCHECK_IS_ON()
+ size_t length,
+ base::PassKey<NativeIODataBuffer>)
+ : contents_(std::move(contents)),
+ type_(type),
+ offset_(offset),
+#if DCHECK_IS_ON()
+ byte_length_(byte_length),
+#endif // DCHECK_IS_ON()
+ length_(length) {
+ DCHECK(IsValid());
+ DCHECK(!contents_.IsShared());
+
+ // DataLength() returns 0 when called on an invalid ArrayBufferContents
+ // (backing an empty array). This works as expected.
+ DCHECK_LE(offset, contents_.DataLength());
+#if DCHECK_IS_ON()
+ DCHECK_LE(length, byte_length);
+ DCHECK_LE(byte_length, contents_.DataLength() - offset);
+#endif // DCHECK_IS_ON()
+}
+
+NativeIODataBuffer::~NativeIODataBuffer() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+bool NativeIODataBuffer::IsValid() const {
+ // The ArrayBufferContents is not shared when this instance is constructed. It
+ // should not become shared while the instance is valid, because no other code
+ // can gain access and make it shared.
+ //
+ // ArrayBufferContents::IsShared() returns false for invalid instances, which
+ // works out well for this check.
+ DCHECK(!contents_.IsShared());
+
+ // Transferring the data out of an empty ArrayBuffer yields an invalid
+ // ArrayBufferContents.
+ return length_ == 0 || contents_.IsValid();
+}
+
+NotShared<DOMArrayBufferView> NativeIODataBuffer::Take() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(IsValid());
+
+ DOMArrayBuffer* array_buffer = DOMArrayBuffer::Create(std::move(contents_));
+
+ DOMArrayBufferView* view = nullptr;
+ switch (type_) {
+ case DOMArrayBufferView::kTypeInt8:
+ view = DOMInt8Array::Create(array_buffer, offset_, length_);
+ break;
+
+ case DOMArrayBufferView::kTypeUint8:
+ view = DOMUint8Array::Create(array_buffer, offset_, length_);
+ break;
+
+ case DOMArrayBufferView::kTypeUint8Clamped:
+ view = DOMUint8ClampedArray::Create(array_buffer, offset_, length_);
+ break;
+
+ case DOMArrayBufferView::kTypeInt16:
+ view = DOMInt16Array::Create(array_buffer, offset_, length_);
+ break;
+
+ case DOMArrayBufferView::kTypeUint16:
+ view = DOMUint16Array::Create(array_buffer, offset_, length_);
+ break;
+
+ case DOMArrayBufferView::kTypeInt32:
+ view = DOMInt32Array::Create(array_buffer, offset_, length_);
+ break;
+
+ case DOMArrayBufferView::kTypeUint32:
+ view = DOMUint32Array::Create(array_buffer, offset_, length_);
+ break;
+
+ case DOMArrayBufferView::kTypeFloat32:
+ view = DOMFloat32Array::Create(array_buffer, offset_, length_);
+ break;
+
+ case DOMArrayBufferView::kTypeFloat64:
+ view = DOMFloat64Array::Create(array_buffer, offset_, length_);
+ break;
+
+ case DOMArrayBufferView::kTypeBigInt64:
+ view = DOMBigInt64Array::Create(array_buffer, offset_, length_);
+ break;
+
+ case DOMArrayBufferView::kTypeBigUint64:
+ view = DOMBigUint64Array::Create(array_buffer, offset_, length_);
+ break;
+
+ case DOMArrayBufferView::kTypeDataView:
+ view = DOMDataView::Create(array_buffer, offset_, length_);
+ break;
+ }
+ return NotShared<DOMArrayBufferView>(view);
+}
+
} // namespace blink
diff --git a/third_party/blink/renderer/modules/native_io/native_io_file_utils.h b/third_party/blink/renderer/modules/native_io/native_io_file_utils.h
index 355a67a8125ea11158dfe435a71c1c01b1ece361..a500d38bcdf8340e7c747cbde949db8f980ea272 100644
--- a/third_party/blink/renderer/modules/native_io/native_io_file_utils.h
+++ b/third_party/blink/renderer/modules/native_io/native_io_file_utils.h
@@ -5,11 +5,19 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_FILE_UTILS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_FILE_UTILS_H_
+#include <cstddef>
+#include <memory>
+
+#include "base/sequence_checker.h"
+#include "base/types/pass_key.h"
+#include "third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
namespace blink {
+class ScriptState;
+
// Extracts the read/write operation size from the buffer size.
int NativeIOOperationSize(const DOMArrayBufferView& buffer);
@@ -20,6 +28,121 @@ DOMArrayBufferView* TransferToNewArrayBufferView(
v8::Isolate* isolate,
NotShared<DOMArrayBufferView> source);
+// Provides cross-thread access to the buffer backing a DOMArrayBufferView.
+//
+// This class is necessary because DOMArrayBufferView is garbage-collected,
+// which entails that each DOMArrayBufferView instance can only be safely
+// accessed on the thread where it was created. Note that CrossThreadPersistent
+// can be used to keep a DOMArrayBufferView alive across threads, but the
+// instance cannot be safely accessed on a different thread. See the comments on
+// cppgc::subtle::CrossThreadPersistent for details.
+//
+// An instance takes over a DOMArrayBufferView's backing buffer at construction.
+// The instance exposes the backing buffer via the Data() and DataLength()
+// methods. At some point, the backing buffer is turned back into a
+// DOMArrayBufferView via the Take() method. Once Take() is called, the instance
+// is invalid, and Data() / DataLength() must not be called anymore.
+//
+// An instance should be owned by a single sequence at a time. Changing the
+// owning sequence should be accomplished by PostTask-ing an owning pointer to
+// the instance.
+//
+// Each instance must be destroyed on the same sequence where it was created.
+// Take() must be called on the same sequence where the instance was created.
+class NativeIODataBuffer {
+ public:
+ // Detaches the buffer backing `source`.
+ //
+ // Returns nullptr if detaching failed.
+ static std::unique_ptr<NativeIODataBuffer> Create(
+ ScriptState* script_state,
+ NotShared<DOMArrayBufferView> source);
+
+ // Exposed for std::make_unique. Instances should be obtained from Create().
+ NativeIODataBuffer(ArrayBufferContents contents,
+ DOMArrayBufferView::ViewType type,
+ size_t offset,
+#if DCHECK_IS_ON()
+ size_t byte_length,
+#endif // DCHECK_IS_ON()
+ size_t length,
+ base::PassKey<NativeIODataBuffer>);
+
+ NativeIODataBuffer(const NativeIODataBuffer&) = delete;
+ NativeIODataBuffer& operator=(const NativeIODataBuffer&) = delete;
+
+ ~NativeIODataBuffer();
+
+ // Re-creates the DOMArrayBufferView.
+ //
+ // Must only be called while this instance is onwed by the same sequence where
+ // Create() was called. Must only be called if IsValid() is true.
+ // After the call, IsValid() will return false.
+ NotShared<DOMArrayBufferView> Take();
+
+ // Exposed for DCHECKs.
+ //
+ // Can be called while this instance is owned by any sequence.
+ bool IsValid() const;
+
+ // Returns a raw pointer to the DOMArrayBufferView's view.
+ //
+ // The return type was chosen so that the raw pointer can be conveniently
+ // passed to base::File methods.
+ //
+ // Can be called while this instance is owned by any sequence. Must only be
+ // called if IsValid() is true.
+ char* Data() {
+ DCHECK(IsValid());
+
+ // An invalid ArrayBufferContents (backing an empty array) returns nullptr
+ // when Data() is called. However, in that case, the offset must be zero.
+ DCHECK(contents_.Data() || contents_.DataLength() == 0);
+ DCHECK(contents_.Data() || offset_ == 0);
+
+ // According to the DCHECKs above, this branch isn't strictly needed. The
+ // return statement below the branch will never do pointer arithmetic on
+ // nullptr, because `offset_` is guaranteed to be zero when
+ // the ArrayBufferContents is not valid but this instance is.
+ char* data = static_cast<char*>(contents_.Data());
+ if (!data) {
+ DCHECK_EQ(offset_, 0u);
+ return data;
+ }
+
+ return data + offset_;
+ }
+
+#if DCHECK_IS_ON()
+ // Returns the size of the DOMArrayBufferView's view, in bytes.
+ //
+ // Exposed for DCHECKs around base::File calls.
+ //
+ // Can be called while this instance is owned by any sequence. Must only be
+ // called if IsValid() is true.
+ size_t DataLength() const {
+ DCHECK(IsValid());
+ return byte_length_;
+ }
+#endif // DCHECK_IS_ON()
+
+ private:
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ // May not be valid, as reported by ArrayBufferContents::IsValid().
+ //
+ // If valid, guaranteed not to be shared, as reported by
+ // ArrayBufferContents::IsShared().
+ ArrayBufferContents contents_;
+
+ DOMArrayBufferView::ViewType type_;
+ const size_t offset_;
+#if DCHECK_IS_ON()
+ const size_t byte_length_;
+#endif // DCHECK_IS_ON()
+ const size_t length_;
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_FILE_UTILS_H_

View File

@@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ken Rockot <rockot@google.com>
Date: Wed, 2 Feb 2022 05:45:44 +0000
Subject: Viz: Fix UAF on context loss
(cherry picked from commit 98d246cabe677e1d8287e4d42ce02825417be9e2)
Fixed: 1250655
Change-Id: I2898316635d370fa36b94e0ae2564ed357745b2c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3413372
Auto-Submit: Ken Rockot <rockot@google.com>
Reviewed-by: Kyle Charbonneau <kylechar@chromium.org>
Commit-Queue: Kyle Charbonneau <kylechar@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#963012}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3430523
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Ken Rockot <rockot@google.com>
Cr-Commit-Position: refs/branch-heads/4758@{#1050}
Cr-Branched-From: 4a2cf4baf90326df19c3ee70ff987960d59a386e-refs/heads/main@{#950365}
diff --git a/services/viz/public/cpp/gpu/context_provider_command_buffer.cc b/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
index a31c10c610000415b5a88a0824eea63b45a435cc..1b323f142d934afea0215dea190efaa197cec554 100644
--- a/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
+++ b/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
@@ -478,9 +478,13 @@ const gpu::GpuFeatureInfo& ContextProviderCommandBuffer::GetGpuFeatureInfo()
void ContextProviderCommandBuffer::OnLostContext() {
CheckValidThreadOrLockAcquired();
- // Ensure |this| isn't destroyed in the middle of OnLostContext() if observers
- // drop all references to it.
- scoped_refptr<ContextProviderCommandBuffer> ref(this);
+ // Observers may drop the last persistent references to `this`, but there may
+ // be weak references in use further up the stack. This task is posted to
+ // ensure that destruction is deferred until it's safe.
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce([](scoped_refptr<ContextProviderCommandBuffer>) {},
+ base::WrapRefCounted(this)));
for (auto& observer : observers_)
observer.OnContextLost();

View File

@@ -0,0 +1,183 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jarryd <jarrydg@chromium.org>
Date: Wed, 29 Dec 2021 19:49:22 +0000
Subject: Quota: Use Threadsafe Pressure Callback.
Fixes UAF by removing use of raw ptr to StorageNotificationService.
Instead, the service's interface exposes a method to create a
thread-safe callback to pass to the quota manager instead.
This change also changes the parameter type for the call chain from
url::Origin to blink::StorageKey to match the type Quota is keyed on.
Bug:1275020
(cherry picked from commit e304c0373f9cc4a65d39d7094e4897627e83390e)
Change-Id: Icc696d22fa41324e7a6c056599db635bb5de6291
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3347939
Reviewed-by: Joshua Bell <jsbell@chromium.org>
Reviewed-by: Nasko Oskov <nasko@chromium.org>
Commit-Queue: Jarryd Goodman <jarrydg@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#953375}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3360203
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Owners-Override: Krishna Govind <govind@chromium.org>
Commit-Queue: Krishna Govind <govind@chromium.org>
Cr-Commit-Position: refs/branch-heads/4664@{#1352}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/chrome/browser/storage/storage_notification_service_impl.cc b/chrome/browser/storage/storage_notification_service_impl.cc
index f8b38745827b25e46bfd1b4225bb3c55f2836d02..ceeafe0ad40e69574ccf885e4230ce042ecbaaaa 100644
--- a/chrome/browser/storage/storage_notification_service_impl.cc
+++ b/chrome/browser/storage/storage_notification_service_impl.cc
@@ -10,6 +10,8 @@
#include "build/build_config.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
#if !defined(OS_ANDROID)
#include "chrome/browser/ui/storage_pressure_bubble.h"
@@ -36,8 +38,26 @@ const base::TimeDelta GetThrottlingInterval() {
} // namespace
+StoragePressureNotificationCallback
+StorageNotificationServiceImpl::CreateThreadSafePressureNotificationCallback() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ auto thread_unsafe_callback = base::BindRepeating(
+ &StorageNotificationServiceImpl::MaybeShowStoragePressureNotification,
+ weak_ptr_factory_.GetWeakPtr());
+ return base::BindRepeating(
+ [](StoragePressureNotificationCallback cb, blink::StorageKey key) {
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce([](StoragePressureNotificationCallback callback,
+ blink::StorageKey key) { callback.Run(key); },
+ std::move(cb), key));
+ },
+ std::move(thread_unsafe_callback));
+}
+
void StorageNotificationServiceImpl::MaybeShowStoragePressureNotification(
- const url::Origin origin) {
+ const blink::StorageKey storage_key) {
+ auto origin = storage_key.origin();
if (!disk_pressure_notification_last_sent_at_.is_null() &&
base::TimeTicks::Now() - disk_pressure_notification_last_sent_at_ <
GetThrottlingInterval()) {
diff --git a/chrome/browser/storage/storage_notification_service_impl.h b/chrome/browser/storage/storage_notification_service_impl.h
index 497a3063c835a37fe9141052263cf70c863235fa..44fe169b82ced5e328060f191d608aaa57d3af71 100644
--- a/chrome/browser/storage/storage_notification_service_impl.h
+++ b/chrome/browser/storage/storage_notification_service_impl.h
@@ -5,10 +5,12 @@
#ifndef CHROME_BROWSER_STORAGE_STORAGE_NOTIFICATION_SERVICE_IMPL_H_
#define CHROME_BROWSER_STORAGE_STORAGE_NOTIFICATION_SERVICE_IMPL_H_
+#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/profiles/profile.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/storage_notification_service.h"
+#include "third_party/blink/public/common/storage_key/storage_key.h"
class StorageNotificationServiceImpl
: public content::StorageNotificationService,
@@ -16,13 +18,20 @@ class StorageNotificationServiceImpl
public:
StorageNotificationServiceImpl();
~StorageNotificationServiceImpl() override;
- void MaybeShowStoragePressureNotification(const url::Origin) override;
+ // Called from the UI thread, this method returns a callback that can passed
+ // to any thread, and proxies calls to
+ // `MaybeShowStoragePressureNotification()` back to the UI thread. It wraps a
+ // weak pointer to `this`.
+ StoragePressureNotificationCallback
+ CreateThreadSafePressureNotificationCallback() override;
+ void MaybeShowStoragePressureNotification(const blink::StorageKey) override;
base::TimeTicks GetLastSentAtForTesting() {
return disk_pressure_notification_last_sent_at_;
}
private:
base::TimeTicks disk_pressure_notification_last_sent_at_;
+ base::WeakPtrFactory<StorageNotificationServiceImpl> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_STORAGE_STORAGE_NOTIFICATION_SERVICE_IMPL_H_
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index ba015b7c6439dfb4a0b9e21f580dbb2581483dcb..ae284e031a6e051bda49258d54a2e62332773c70 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -1205,23 +1205,14 @@ void StoragePartitionImpl::Initialize(
StorageNotificationService* storage_notification_service =
browser_context_->GetStorageNotificationService();
if (storage_notification_service) {
- // base::Unretained is safe to use because the BrowserContext is guaranteed
- // to outlive QuotaManager. This is because BrowserContext outlives this
- // StoragePartitionImpl, which destroys the QuotaManager on teardown.
- base::RepeatingCallback<void(const blink::StorageKey)>
- send_notification_function = base::BindRepeating(
- [](StorageNotificationService* service,
- const blink::StorageKey storage_key) {
- GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE,
- base::BindOnce(&StorageNotificationService::
- MaybeShowStoragePressureNotification,
- base::Unretained(service),
- std::move(storage_key.origin())));
- },
- base::Unretained(storage_notification_service));
-
- quota_manager_->SetStoragePressureCallback(send_notification_function);
+ // The weak ptr associated with the pressure notification callback will be
+ // created and evaluated by a task runner on the UI thread, as confirmed by
+ // the DCHECK's above, ensuring that the task runner does not attempt to run
+ // the callback in the case that the storage notification service is already
+ // destructed.
+ quota_manager_->SetStoragePressureCallback(
+ storage_notification_service
+ ->CreateThreadSafePressureNotificationCallback());
}
// Each consumer is responsible for registering its QuotaClient during
diff --git a/content/public/browser/storage_notification_service.h b/content/public/browser/storage_notification_service.h
index 3eec5ef29051008041695bcf7ebbf63787f5bd89..e72adada318f1cb998e2a9e7468a6f2e54742760 100644
--- a/content/public/browser/storage_notification_service.h
+++ b/content/public/browser/storage_notification_service.h
@@ -8,6 +8,15 @@
#include "base/bind.h"
#include "url/origin.h"
+namespace blink {
+class StorageKey;
+}
+
+namespace {
+using StoragePressureNotificationCallback =
+ base::RepeatingCallback<void(const blink::StorageKey)>;
+}
+
namespace content {
// This interface is used to create a connection between the storage layer and
@@ -19,12 +28,15 @@ class StorageNotificationService {
StorageNotificationService() = default;
~StorageNotificationService() = default;
- // This pure virtual function should be implemented in the embedder layer
+ // These pure virtual functions should be implemented in the embedder layer
// where calls to UI and notification code can be implemented. This closure
// is passed to QuotaManager in StoragePartitionImpl, where it is called
// when QuotaManager determines appropriate to alert the user that the device
// is in a state of storage pressure.
- virtual void MaybeShowStoragePressureNotification(const url::Origin) = 0;
+ virtual void MaybeShowStoragePressureNotification(
+ const blink::StorageKey) = 0;
+ virtual StoragePressureNotificationCallback
+ CreateThreadSafePressureNotificationCallback() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(StorageNotificationService);

Some files were not shown because too many files have changed in this diff Show More