mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
201 Commits
v20.0.0-be
...
20-x-y
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50f600b350 | ||
|
|
99b0c77cd7 | ||
|
|
bd191e1862 | ||
|
|
79115938c6 | ||
|
|
03193df4d3 | ||
|
|
80d0d340c7 | ||
|
|
2bf86bcf65 | ||
|
|
2946432147 | ||
|
|
9b552bfe98 | ||
|
|
aa2f4c094f | ||
|
|
f680f21036 | ||
|
|
4717ae4321 | ||
|
|
8c1af31b74 | ||
|
|
4c27ab0a48 | ||
|
|
b645d63b9b | ||
|
|
ebe47b445f | ||
|
|
4e881baaea | ||
|
|
c3d3f9a03b | ||
|
|
85565c0edd | ||
|
|
7644257bcd | ||
|
|
ec951270bd | ||
|
|
48159db088 | ||
|
|
d1475648cb | ||
|
|
1ce4472ae6 | ||
|
|
d323392955 | ||
|
|
5cfaf82036 | ||
|
|
56dedcc291 | ||
|
|
02506a4cb1 | ||
|
|
8cbac3a861 | ||
|
|
9fa958cb5f | ||
|
|
cb26b3689b | ||
|
|
5456137421 | ||
|
|
9945746f1f | ||
|
|
ec6df2b000 | ||
|
|
e35ad40498 | ||
|
|
c281f15bf6 | ||
|
|
e86b4a6f99 | ||
|
|
f62120aa1b | ||
|
|
b0bd900aa3 | ||
|
|
a4f43aaa4d | ||
|
|
63b3434132 | ||
|
|
c881c3f21b | ||
|
|
5014520e2d | ||
|
|
8bde173814 | ||
|
|
7841595cc6 | ||
|
|
870bf8c1f8 | ||
|
|
e8b8ee1454 | ||
|
|
b9d0a5aee3 | ||
|
|
bc3d0bf0c2 | ||
|
|
a0f608b8b6 | ||
|
|
92a338a273 | ||
|
|
f8ab27474f | ||
|
|
d844933377 | ||
|
|
30046ca08d | ||
|
|
98ab127aa1 | ||
|
|
1008774610 | ||
|
|
782e5adc99 | ||
|
|
806d0840ff | ||
|
|
bdf6126133 | ||
|
|
378110b748 | ||
|
|
117b264db5 | ||
|
|
109009f3e7 | ||
|
|
b2ca7f9c05 | ||
|
|
5382df7ea2 | ||
|
|
aedfdadf1b | ||
|
|
7a70765ba1 | ||
|
|
a7ae2511d2 | ||
|
|
cf9f5ca5b8 | ||
|
|
2e85e7fd69 | ||
|
|
3028dcd785 | ||
|
|
d010bcca86 | ||
|
|
1ba8128c8c | ||
|
|
25e504a7ed | ||
|
|
589199f335 | ||
|
|
c0371ab218 | ||
|
|
50f2f10b94 | ||
|
|
2ee36539ba | ||
|
|
0d05ce8d12 | ||
|
|
9e064fec80 | ||
|
|
619a88cf56 | ||
|
|
080bc57145 | ||
|
|
a03ec151e1 | ||
|
|
0858a08097 | ||
|
|
53b6270320 | ||
|
|
4c44e86fd1 | ||
|
|
543a29c926 | ||
|
|
c0c83d2719 | ||
|
|
a7848809fc | ||
|
|
d8ca287700 | ||
|
|
b0c881f608 | ||
|
|
6620ba4e15 | ||
|
|
1babaec6da | ||
|
|
cbe1debbe2 | ||
|
|
3c73ea5259 | ||
|
|
02622b02a6 | ||
|
|
700906c1f1 | ||
|
|
d19a0ac51b | ||
|
|
25521f6286 | ||
|
|
f89b51fe0a | ||
|
|
2a42cd2f65 | ||
|
|
9e419bc4e9 | ||
|
|
1921f802fd | ||
|
|
06e585d82f | ||
|
|
febee696d6 | ||
|
|
57917c4b5a | ||
|
|
3f7f4de319 | ||
|
|
91bafdd3d5 | ||
|
|
c676831a54 | ||
|
|
a62b98a23f | ||
|
|
cbd39f73f8 | ||
|
|
eb819e0881 | ||
|
|
36885ea919 | ||
|
|
bc09b08664 | ||
|
|
880d06e304 | ||
|
|
cb5b28f833 | ||
|
|
e867b08172 | ||
|
|
4541c432af | ||
|
|
604034a899 | ||
|
|
c256db23ce | ||
|
|
c19f09e92e | ||
|
|
328368be56 | ||
|
|
73deb5f56d | ||
|
|
46c416190b | ||
|
|
046ef10147 | ||
|
|
7c8d5f68d5 | ||
|
|
4be4dc7c4f | ||
|
|
5cfb58161c | ||
|
|
2f116aacfb | ||
|
|
2f5c0f9eec | ||
|
|
c730abc55d | ||
|
|
61f385a89e | ||
|
|
389911d7e2 | ||
|
|
85ae4c4a77 | ||
|
|
bb0a66823b | ||
|
|
e9b721ba51 | ||
|
|
42bb395529 | ||
|
|
7a418ffa43 | ||
|
|
1e14b3ebb8 | ||
|
|
dbaa3528f9 | ||
|
|
44bd6aac3a | ||
|
|
fef7d52e73 | ||
|
|
0bdb5ac85a | ||
|
|
1e54a8d3fe | ||
|
|
5ef4b258ec | ||
|
|
dad125a0e0 | ||
|
|
42e2e54730 | ||
|
|
3795fbaccb | ||
|
|
7358d0fd71 | ||
|
|
f85bd310c8 | ||
|
|
a415eb6f06 | ||
|
|
3f6b9a8fcd | ||
|
|
cc17929ebb | ||
|
|
a85ad0ea38 | ||
|
|
91e09c69bd | ||
|
|
6e27b53527 | ||
|
|
534d313758 | ||
|
|
30b446ca32 | ||
|
|
7e6d0d4c3c | ||
|
|
6eabd3c72b | ||
|
|
f0302c4981 | ||
|
|
3c71a812c3 | ||
|
|
58981b69b1 | ||
|
|
6a451311cd | ||
|
|
09beb48648 | ||
|
|
e6fc453d90 | ||
|
|
305751aa47 | ||
|
|
d8fbdf6b3e | ||
|
|
c84a45f9f2 | ||
|
|
5274c253db | ||
|
|
8e70826af6 | ||
|
|
9afa4194ac | ||
|
|
062f7c0cb1 | ||
|
|
13cfb4ef8f | ||
|
|
39d08c3f2a | ||
|
|
1a6d998c34 | ||
|
|
ab426d5abf | ||
|
|
6ff154c7cc | ||
|
|
910dd786a9 | ||
|
|
d7fedd2961 | ||
|
|
f20a51a87f | ||
|
|
6c29ab10a4 | ||
|
|
b61692d790 | ||
|
|
0e6f172897 | ||
|
|
aa99d73990 | ||
|
|
f1c7562d9c | ||
|
|
08aa57806e | ||
|
|
76450afd47 | ||
|
|
8ac0e2bdec | ||
|
|
c61a14c5d1 | ||
|
|
ecdfca8f13 | ||
|
|
2f9414dcc4 | ||
|
|
816e8e804c | ||
|
|
5f1c3b4d13 | ||
|
|
7b1872dafe | ||
|
|
c10922f15f | ||
|
|
d8edf84cfc | ||
|
|
215ae2b012 | ||
|
|
09c4fdd6d0 | ||
|
|
77d561a8a6 | ||
|
|
3777902abc | ||
|
|
3a079feb87 |
@@ -216,6 +216,7 @@ step-maybe-cleanup-arm64-mac: &step-maybe-cleanup-arm64-mac
|
||||
rm -rf ~/Library/Application\ Support/electron*
|
||||
security delete-generic-password -l "Chromium Safe Storage" || echo "✓ Keychain does not contain password from tests"
|
||||
security delete-generic-password -l "Electron Test Main Safe Storage" || echo "✓ Keychain does not contain password from tests"
|
||||
security delete-generic-password -a "electron-test-safe-storage" || echo "✓ Keychain does not contain password from tests"
|
||||
elif [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then
|
||||
XVFB=/usr/bin/Xvfb
|
||||
/sbin/start-stop-daemon --stop --exec $XVFB || echo "Xvfb not running"
|
||||
@@ -235,6 +236,11 @@ step-depot-tools-get: &step-depot-tools-get
|
||||
name: Get depot tools
|
||||
command: |
|
||||
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
cd depot_tools
|
||||
git fetch --depth 1 origin b7d8efd8bee494f4cfacacc19cf50fc4d4be3900
|
||||
git checkout b7d8efd8bee494f4cfacacc19cf50fc4d4be3900
|
||||
touch .disable_auto_update
|
||||
cd ..
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
# remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
|
||||
sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
@@ -454,7 +460,7 @@ step-delete-git-directories: &step-delete-git-directories
|
||||
command: |
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
cd src
|
||||
( find . -type d -name ".git" -not -path "./third_party/angle/*" -not -path "./third_party/dawn/*" ) | xargs rm -rf
|
||||
( find . -type d -name ".git" -not -path "./third_party/angle/*" -not -path "./third_party/dawn/*" -not -path "./electron/*" ) | xargs rm -rf
|
||||
fi
|
||||
|
||||
# On macOS the yarn install command during gclient sync was run on a linux
|
||||
@@ -812,7 +818,7 @@ step-maybe-zip-symbols: &step-maybe-zip-symbols
|
||||
cd src
|
||||
export BUILD_PATH="$PWD/out/Default"
|
||||
ninja -C out/Default electron:licenses
|
||||
ninja -C out/Default electron:electron_version
|
||||
ninja -C out/Default electron:electron_version_file
|
||||
DELETE_DSYMS_AFTER_ZIP=1 electron/script/zip-symbols.py -b $BUILD_PATH
|
||||
|
||||
step-maybe-cross-arch-snapshot: &step-maybe-cross-arch-snapshot
|
||||
@@ -872,12 +878,12 @@ step-touch-sync-done: &step-touch-sync-done
|
||||
step-maybe-restore-src-cache: &step-maybe-restore-src-cache
|
||||
restore_cache:
|
||||
keys:
|
||||
- v14-src-cache-{{ checksum "src/electron/.depshash" }}
|
||||
- v16-src-cache-{{ checksum "src/electron/.depshash" }}
|
||||
name: Restoring src cache
|
||||
step-maybe-restore-src-cache-marker: &step-maybe-restore-src-cache-marker
|
||||
restore_cache:
|
||||
keys:
|
||||
- v14-src-cache-marker-{{ checksum "src/electron/.depshash" }}
|
||||
- v16-src-cache-marker-{{ checksum "src/electron/.depshash" }}
|
||||
name: Restoring src cache marker
|
||||
|
||||
# Restore exact or closest git cache based on the hash of DEPS and .circle-sync-done
|
||||
@@ -892,14 +898,6 @@ step-maybe-restore-git-cache: &step-maybe-restore-git-cache
|
||||
- v1-git-cache-{{ checksum "src/electron/.circle-sync-done" }}
|
||||
name: Conditionally restoring git cache
|
||||
|
||||
step-restore-out-cache: &step-restore-out-cache
|
||||
restore_cache:
|
||||
paths:
|
||||
- ./src/out/Default
|
||||
keys:
|
||||
- v10-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }}
|
||||
name: Restoring out cache
|
||||
|
||||
step-set-git-cache-path: &step-set-git-cache-path
|
||||
run:
|
||||
name: Set GIT_CACHE_PATH to make gclient to use the cache
|
||||
@@ -917,13 +915,6 @@ step-save-git-cache: &step-save-git-cache
|
||||
key: v1-git-cache-{{ checksum "src/electron/.circle-sync-done" }}-{{ checksum "src/electron/DEPS" }}
|
||||
name: Persisting git cache
|
||||
|
||||
step-save-out-cache: &step-save-out-cache
|
||||
save_cache:
|
||||
paths:
|
||||
- ./src/out/Default
|
||||
key: v10-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }}
|
||||
name: Persisting out cache
|
||||
|
||||
step-run-electron-only-hooks: &step-run-electron-only-hooks
|
||||
run:
|
||||
name: Run Electron Only Hooks
|
||||
@@ -953,13 +944,16 @@ step-minimize-workspace-size-from-checkout: &step-minimize-workspace-size-from-c
|
||||
rm -rf third_party/electron_node/deps/openssl
|
||||
rm -rf third_party/electron_node/deps/v8
|
||||
rm -rf chrome/test/data/xr/webvr_info
|
||||
rm -rf src/third_party/angle/third_party/VK-GL-CTS/src
|
||||
rm -rf src/third_party/swift-toolchain
|
||||
rm -rf src/third_party/swiftshader/tests/regres/testlists
|
||||
|
||||
# Save the src cache based on the deps hash
|
||||
step-save-src-cache: &step-save-src-cache
|
||||
save_cache:
|
||||
paths:
|
||||
- /var/portal
|
||||
key: v14-src-cache-{{ checksum "/var/portal/src/electron/.depshash" }}
|
||||
key: v16-src-cache-{{ checksum "/var/portal/src/electron/.depshash" }}
|
||||
name: Persisting src cache
|
||||
step-make-src-cache-marker: &step-make-src-cache-marker
|
||||
run:
|
||||
@@ -969,7 +963,7 @@ step-save-src-cache-marker: &step-save-src-cache-marker
|
||||
save_cache:
|
||||
paths:
|
||||
- .src-cache-marker
|
||||
key: v14-src-cache-marker-{{ checksum "/var/portal/src/electron/.depshash" }}
|
||||
key: v16-src-cache-marker-{{ checksum "/var/portal/src/electron/.depshash" }}
|
||||
|
||||
step-maybe-early-exit-no-doc-change: &step-maybe-early-exit-no-doc-change
|
||||
run:
|
||||
@@ -1293,9 +1287,6 @@ commands:
|
||||
build:
|
||||
type: boolean
|
||||
default: true
|
||||
use-out-cache:
|
||||
type: boolean
|
||||
default: true
|
||||
restore-src-cache:
|
||||
type: boolean
|
||||
default: true
|
||||
@@ -1418,10 +1409,6 @@ commands:
|
||||
- *step-delete-git-directories
|
||||
|
||||
# Electron app
|
||||
- when:
|
||||
condition: << parameters.use-out-cache >>
|
||||
steps:
|
||||
- *step-restore-out-cache
|
||||
- *step-gn-gen-default
|
||||
- *step-electron-build
|
||||
- *step-maybe-electron-dist-strip
|
||||
@@ -1464,22 +1451,6 @@ commands:
|
||||
condition: << parameters.build >>
|
||||
steps:
|
||||
- move_and_store_all_artifacts
|
||||
- run:
|
||||
name: Remove the big things on macOS, this seems to be better on average
|
||||
command: |
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
mkdir -p src/out/Default
|
||||
cd src/out/Default
|
||||
find . -type f -size +50M -delete
|
||||
mkdir -p gen/electron
|
||||
cd gen/electron
|
||||
# These files do not seem to like being in a cache, let us remove them
|
||||
find . -type f -name '*_pkg_info' -delete
|
||||
fi
|
||||
- when:
|
||||
condition: << parameters.use-out-cache >>
|
||||
steps:
|
||||
- *step-save-out-cache
|
||||
|
||||
- *step-maybe-notify-slack-failure
|
||||
|
||||
@@ -1633,7 +1604,6 @@ jobs:
|
||||
persist: true
|
||||
checkout: false
|
||||
checkout-and-assume-cache: true
|
||||
use-out-cache: false
|
||||
|
||||
linux-x64-testing-asan:
|
||||
executor:
|
||||
@@ -1650,7 +1620,6 @@ jobs:
|
||||
- electron-build:
|
||||
persist: true
|
||||
checkout: true
|
||||
use-out-cache: false
|
||||
build-nonproprietary-ffmpeg: false
|
||||
|
||||
linux-x64-testing-no-run-as-node:
|
||||
@@ -1667,7 +1636,6 @@ jobs:
|
||||
- electron-build:
|
||||
persist: false
|
||||
checkout: true
|
||||
use-out-cache: false
|
||||
|
||||
linux-x64-testing-gn-check:
|
||||
executor:
|
||||
@@ -1718,7 +1686,6 @@ jobs:
|
||||
persist: true
|
||||
checkout: false
|
||||
checkout-and-assume-cache: true
|
||||
use-out-cache: false
|
||||
|
||||
linux-arm-publish:
|
||||
executor:
|
||||
@@ -1761,7 +1728,6 @@ jobs:
|
||||
persist: true
|
||||
checkout: false
|
||||
checkout-and-assume-cache: true
|
||||
use-out-cache: false
|
||||
|
||||
linux-arm64-testing-gn-check:
|
||||
executor:
|
||||
|
||||
2
.github/semantic.yml
vendored
2
.github/semantic.yml
vendored
@@ -1,2 +0,0 @@
|
||||
# Always validate the PR title, and ignore the commits
|
||||
titleOnly: true
|
||||
62
.github/workflows/update_appveyor_image.yml
vendored
Normal file
62
.github/workflows/update_appveyor_image.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: Update AppVeyor Image
|
||||
|
||||
# Run chron daily Mon-Fri
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 8 * * 1-5' # runs 8:00 every business day (see https://crontab.guru)
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
bake-appveyor-image:
|
||||
name: Bake AppVeyor Image
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write # to create a new PR with updated Appveyor images
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Yarn install
|
||||
run: |
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
- name: Set Repo for Commit
|
||||
run: git config --global --add safe.directory $GITHUB_WORKSPACE
|
||||
- name: Check AppVeyor Image
|
||||
env:
|
||||
APPVEYOR_TOKEN: ${{ secrets.APPVEYOR_TOKEN }}
|
||||
run: |
|
||||
node ./script/prepare-appveyor
|
||||
if [ -f ./image_version.txt ]; then
|
||||
echo "APPVEYOR_IMAGE_VERSION="$(cat image_version.txt)"" >> $GITHUB_ENV
|
||||
rm image_version.txt
|
||||
fi
|
||||
- name: (Optionally) Update Appveyor Image
|
||||
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
|
||||
uses: mikefarah/yq@v4.27.2
|
||||
with:
|
||||
cmd: yq '.image = "${{ env.APPVEYOR_IMAGE_VERSION }}"' "appveyor.yml" > "appveyor2.yml"
|
||||
- name: (Optionally) Generate Commit Diff
|
||||
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
|
||||
run: |
|
||||
diff -w -B appveyor.yml appveyor2.yml > appveyor.diff || true
|
||||
patch -f appveyor.yml < appveyor.diff
|
||||
rm appveyor2.yml appveyor.diff
|
||||
- name: (Optionally) Commit and Pull Request
|
||||
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
token: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
|
||||
commit-message: 'build: update appveyor image to latest version'
|
||||
committer: GitHub <noreply@github.com>
|
||||
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
|
||||
signoff: false
|
||||
branch: bump-appveyor-image
|
||||
delete-branch: true
|
||||
title: 'build: update appveyor image to latest version'
|
||||
body: |
|
||||
This PR updates appveyor.yml to the latest baked image, ${{ env.APPVEYOR_IMAGE_VERSION }}.
|
||||
73
BUILD.gn
73
BUILD.gn
@@ -107,6 +107,14 @@ branding = read_file("shell/app/BRANDING.json", "json")
|
||||
electron_project_name = branding.project_name
|
||||
electron_product_name = branding.product_name
|
||||
electron_mac_bundle_id = branding.mac_bundle_id
|
||||
electron_version = exec_script("script/print-version.py",
|
||||
[],
|
||||
"trim string",
|
||||
[
|
||||
".git/packed-refs",
|
||||
".git/HEAD",
|
||||
"script/lib/get-version.js",
|
||||
])
|
||||
|
||||
if (is_mas_build) {
|
||||
assert(is_mac,
|
||||
@@ -233,6 +241,7 @@ action("electron_js2c") {
|
||||
action("generate_config_gypi") {
|
||||
outputs = [ "$root_gen_dir/config.gypi" ]
|
||||
script = "script/generate-config-gypi.py"
|
||||
inputs = [ "//third_party/electron_node/configure.py" ]
|
||||
args = rebase_path(outputs) + [ target_cpu ]
|
||||
}
|
||||
|
||||
@@ -301,12 +310,9 @@ npm_action("electron_version_args") {
|
||||
|
||||
outputs = [ "$target_gen_dir/electron_version.args" ]
|
||||
|
||||
args = rebase_path(outputs)
|
||||
args = rebase_path(outputs) + [ "$electron_version" ]
|
||||
|
||||
inputs = [
|
||||
"ELECTRON_VERSION",
|
||||
"script/generate-version-json.js",
|
||||
]
|
||||
inputs = [ "script/generate-version-json.js" ]
|
||||
}
|
||||
|
||||
templated_file("electron_version_header") {
|
||||
@@ -318,6 +324,39 @@ templated_file("electron_version_header") {
|
||||
args_files = get_target_outputs(":electron_version_args")
|
||||
}
|
||||
|
||||
templated_file("electron_win_rc") {
|
||||
deps = [ ":electron_version_args" ]
|
||||
|
||||
template = "build/templates/electron_rc.tmpl"
|
||||
output = "$target_gen_dir/win-resources/electron.rc"
|
||||
|
||||
args_files = get_target_outputs(":electron_version_args")
|
||||
}
|
||||
|
||||
copy("electron_win_resource_files") {
|
||||
sources = [
|
||||
"shell/browser/resources/win/electron.ico",
|
||||
"shell/browser/resources/win/resource.h",
|
||||
]
|
||||
outputs = [ "$target_gen_dir/win-resources/{{source_file_part}}" ]
|
||||
}
|
||||
|
||||
templated_file("electron_version_file") {
|
||||
deps = [ ":electron_version_args" ]
|
||||
|
||||
template = "build/templates/version_string.tmpl"
|
||||
output = "$root_build_dir/version"
|
||||
|
||||
args_files = get_target_outputs(":electron_version_args")
|
||||
}
|
||||
|
||||
group("electron_win32_resources") {
|
||||
public_deps = [
|
||||
":electron_win_rc",
|
||||
":electron_win_resource_files",
|
||||
]
|
||||
}
|
||||
|
||||
action("electron_fuses") {
|
||||
script = "build/fuses/build.py"
|
||||
|
||||
@@ -402,9 +441,6 @@ source_set("electron_lib") {
|
||||
"//media/mojo/mojom",
|
||||
"//net:extras",
|
||||
"//net:net_resources",
|
||||
"//ppapi/host",
|
||||
"//ppapi/proxy",
|
||||
"//ppapi/shared_impl",
|
||||
"//printing/buildflags",
|
||||
"//services/device/public/cpp/geolocation",
|
||||
"//services/device/public/cpp/hid",
|
||||
@@ -615,8 +651,15 @@ source_set("electron_lib") {
|
||||
}
|
||||
|
||||
if (enable_plugins) {
|
||||
deps += [ "chromium_src:plugins" ]
|
||||
deps += [
|
||||
"chromium_src:plugins",
|
||||
"//ppapi/host",
|
||||
"//ppapi/proxy",
|
||||
"//ppapi/shared_impl",
|
||||
]
|
||||
sources += [
|
||||
"shell/renderer/electron_renderer_pepper_host_factory.cc",
|
||||
"shell/renderer/electron_renderer_pepper_host_factory.h",
|
||||
"shell/renderer/pepper_helper.cc",
|
||||
"shell/renderer/pepper_helper.h",
|
||||
]
|
||||
@@ -749,7 +792,6 @@ if (is_mac) {
|
||||
electron_helper_name = "$electron_product_name Helper"
|
||||
electron_login_helper_name = "$electron_product_name Login Helper"
|
||||
electron_framework_version = "A"
|
||||
electron_version = read_file("ELECTRON_VERSION", "trim string")
|
||||
|
||||
mac_xib_bundle_data("electron_xibs") {
|
||||
sources = [ "shell/common/resources/mac/MainMenu.xib" ]
|
||||
@@ -1183,6 +1225,7 @@ if (is_mac) {
|
||||
":default_app_asar",
|
||||
":electron_app_manifest",
|
||||
":electron_lib",
|
||||
":electron_win32_resources",
|
||||
":packed_resources",
|
||||
"//components/crash/core/app",
|
||||
"//content:sandbox_helper_win",
|
||||
@@ -1216,8 +1259,7 @@ if (is_mac) {
|
||||
|
||||
if (is_win) {
|
||||
sources += [
|
||||
# TODO: we should be generating our .rc files more like how chrome does
|
||||
"shell/browser/resources/win/electron.rc",
|
||||
"$target_gen_dir/win-resources/electron.rc",
|
||||
"shell/browser/resources/win/resource.h",
|
||||
]
|
||||
|
||||
@@ -1399,15 +1441,10 @@ group("licenses") {
|
||||
]
|
||||
}
|
||||
|
||||
copy("electron_version") {
|
||||
sources = [ "ELECTRON_VERSION" ]
|
||||
outputs = [ "$root_build_dir/version" ]
|
||||
}
|
||||
|
||||
dist_zip("electron_dist_zip") {
|
||||
data_deps = [
|
||||
":electron_app",
|
||||
":electron_version",
|
||||
":electron_version_file",
|
||||
":licenses",
|
||||
]
|
||||
if (is_linux) {
|
||||
|
||||
2
DEPS
2
DEPS
@@ -2,7 +2,7 @@ gclient_gn_args_from = 'src'
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'104.0.5112.48',
|
||||
'104.0.5112.124',
|
||||
'node_version':
|
||||
'v16.15.0',
|
||||
'nan_version':
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
20.0.0-beta.12
|
||||
@@ -38,7 +38,7 @@ For more installation options and troubleshooting tips, see
|
||||
|
||||
Each Electron release provides binaries for macOS, Windows, and Linux.
|
||||
|
||||
* macOS (El Capitan and up): Electron provides 64-bit Intel and ARM binaries for macOS. Apple Silicon support was added in Electron 11.
|
||||
* macOS (High Sierra and up): Electron provides 64-bit Intel and ARM binaries for macOS. Apple Silicon support was added in Electron 11.
|
||||
* Windows (Windows 7 and up): Electron provides `ia32` (`x86`), `x64` (`amd64`), and `arm64` binaries for Windows. Windows on ARM support was added in Electron 5.0.8.
|
||||
* Linux: The prebuilt binaries of Electron are built on Ubuntu 20.04. They have also been verified to work on:
|
||||
* Ubuntu 14.04 and newer
|
||||
|
||||
52
appveyor-bake.yml
Normal file
52
appveyor-bake.yml
Normal file
@@ -0,0 +1,52 @@
|
||||
# The config is used to bake appveyor images, not for running CI jobs.
|
||||
# The config expects the following environment variables to be set:
|
||||
# - "APPVEYOR_BAKE_IMAGE" e.g. 'electron-99.0.4767.0'. Name of the image to be baked.
|
||||
# Typically named after the Chromium version on which the image is built.
|
||||
# This can be set dynamically in the prepare-appveyor script.
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electronhq-16-core
|
||||
image: Windows_Default_Appveyor
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
ELECTRON_ENABLE_STACK_DUMPING: 1
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap
|
||||
GOMA_FALLBACK_ON_AUTH_FAILURE: true
|
||||
DEPOT_TOOLS_WIN_TOOLCHAIN: 0
|
||||
PYTHONIOENCODING: UTF-8
|
||||
build_script:
|
||||
- ps: Resize-Partition -DriveLetter C -Size (256GB) # ensure initial partition size
|
||||
- ps: Get-Partition -DriveLetter C
|
||||
- git config --global core.longpaths true
|
||||
- cd ..
|
||||
- mkdir src
|
||||
- ps: git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
- ps: $env:PATH="$pwd\depot_tools;$env:PATH"
|
||||
- update_depot_tools.bat
|
||||
- ps: Move-Item $env:APPVEYOR_BUILD_FOLDER -Destination src\electron
|
||||
- src\electron\script\setup-win-for-dev.bat
|
||||
- >-
|
||||
gclient config
|
||||
--name "src\electron"
|
||||
--unmanaged
|
||||
%GCLIENT_EXTRA_ARGS%
|
||||
"https://github.com/electron/electron"
|
||||
- ps: cd src\electron
|
||||
- ps: node script\generate-deps-hash.js
|
||||
- ps: $depshash = Get-Content .\.depshash -Raw
|
||||
- ps: Copy-Item -path .\.depshash -destination ..\.depshash
|
||||
- ps: cd ..\..
|
||||
- gclient sync --with_branch_heads --with_tags --nohooks
|
||||
- ps: regsvr32 /s "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\DIA SDK\bin\amd64\msdia140.dll"
|
||||
on_image_bake:
|
||||
- ps: >-
|
||||
echo "Baking image: $env:APPVEYOR_BAKE_IMAGE at dir $PWD"
|
||||
- ps: Remove-Item -Recurse -Force $pwd\depot_tools
|
||||
- ps: Remove-Item -Recurse -Force $pwd\src\electron
|
||||
# Uncomment these lines to enable RDP
|
||||
#on_finish:
|
||||
# - ps: >-
|
||||
# $env:APPVEYOR_RDP_PASSWORD = "electron"
|
||||
# $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
286
appveyor-woa.yml
Normal file
286
appveyor-woa.yml
Normal file
@@ -0,0 +1,286 @@
|
||||
# NOTE IF CHANGING THIS FILE, ALSO APPLY THE CHANGE TO appveyor.yml
|
||||
# IF APPLICABLE!!!!
|
||||
#
|
||||
#
|
||||
# The config expects the following environment variables to be set:
|
||||
# - "GN_CONFIG" Build type. One of {'testing', 'release'}.
|
||||
# - "GN_EXTRA_ARGS" Additional gn arguments for a build config,
|
||||
# e.g. 'target_cpu="x86"' to build for a 32bit platform.
|
||||
# https://gn.googlesource.com/gn/+/master/docs/reference.md#target_cpu
|
||||
# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordingly
|
||||
# if you pass a custom value for 'target_cpu'.
|
||||
# - "ELECTRON_RELEASE" Set it to '1' upload binaries on success.
|
||||
# - "NPM_CONFIG_ARCH" E.g. 'x86'. Is used to build native Node.js modules.
|
||||
# Must match 'target_cpu' passed to "GN_EXTRA_ARGS" and "TARGET_ARCH" value.
|
||||
# - "TARGET_ARCH" Choose from {'ia32', 'x64', 'arm', 'arm64', 'mips64el'}.
|
||||
# Is used in some publishing scripts, but does NOT affect the Electron binary.
|
||||
# Must match 'target_cpu' passed to "GN_EXTRA_ARGS" and "NPM_CONFIG_ARCH" value.
|
||||
# - "UPLOAD_TO_STORAGE" Set it to '1' upload a release to the Azure bucket.
|
||||
# Otherwise the release will be uploaded to the GitHub Releases.
|
||||
# (The value is only checked if "ELECTRON_RELEASE" is defined.)
|
||||
#
|
||||
# The publishing scripts expect access tokens to be defined as env vars,
|
||||
# but those are not covered here.
|
||||
#
|
||||
# AppVeyor docs on variables:
|
||||
# https://www.appveyor.com/docs/environment-variables/
|
||||
# https://www.appveyor.com/docs/build-configuration/#secure-variables
|
||||
# https://www.appveyor.com/docs/build-configuration/#custom-environment-variables
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electronhq-16-core
|
||||
image: e-106.0.5249.199
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
ELECTRON_ENABLE_STACK_DUMPING: 1
|
||||
ELECTRON_ALSO_LOG_TO_STDERR: 1
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap
|
||||
GOMA_FALLBACK_ON_AUTH_FAILURE: true
|
||||
DEPOT_TOOLS_WIN_TOOLCHAIN: 0
|
||||
PYTHONIOENCODING: UTF-8
|
||||
|
||||
matrix:
|
||||
|
||||
- job_name: Build Arm on X64 Windows
|
||||
- job_name: Test On Windows On Arm Hardware
|
||||
job_depends_on: Build Arm on X64 Windows
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: base-woa
|
||||
APPVEYOR_BUILD_WORKER_CLOUD: electronhq-woa
|
||||
|
||||
clone_folder: C:\projects\src\electron
|
||||
|
||||
skip_branch_with_pr: true
|
||||
|
||||
# the first failed job cancels other jobs and fails entire build
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
for:
|
||||
|
||||
- matrix:
|
||||
only:
|
||||
- job_name: Build Arm on X64 Windows
|
||||
|
||||
build_script:
|
||||
- ps: |
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild
|
||||
}
|
||||
$global:LASTEXITCODE = 0
|
||||
- cd ..
|
||||
- ps: Write-Host "Building $env:GN_CONFIG build"
|
||||
- git config --global core.longpaths true
|
||||
- ps: >-
|
||||
if (Test-Path -Path "$pwd\depot_tools") {
|
||||
Remove-Item -Recurse -Force $pwd\depot_tools
|
||||
}
|
||||
- ps: >-
|
||||
if (Test-Path -Path "$pwd\build-tools") {
|
||||
Remove-Item -Recurse -Force $pwd\build-tools
|
||||
}
|
||||
- ps: |
|
||||
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
cd depot_tools
|
||||
git fetch --depth 1 origin b7d8efd8bee494f4cfacacc19cf50fc4d4be3900
|
||||
git checkout b7d8efd8bee494f4cfacacc19cf50fc4d4be3900
|
||||
New-Item -Name .disable_auto_update -ItemType File
|
||||
bootstrap\win_tools.bat
|
||||
cd ..
|
||||
- ps: $env:PATH="$pwd\depot_tools;$env:PATH"
|
||||
- ps: >-
|
||||
if (Test-Path -Path "$pwd\src\electron") {
|
||||
Remove-Item -Recurse -Force $pwd\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') {
|
||||
$env:NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] "
|
||||
}
|
||||
- gclient config --name "src\electron" --unmanaged %GCLIENT_EXTRA_ARGS% "https://github.com/electron/electron"
|
||||
# Patches are applied in the image bake. Check depshash to see if patches have changed.
|
||||
- ps: $env:RUN_GCLIENT_SYNC="false"
|
||||
- ps: $depshash_baked = Get-Content .\src\.depshash -Raw
|
||||
- ps: cd src\electron
|
||||
- ps: node script\generate-deps-hash.js
|
||||
- ps: $depshash = Get-Content .\.depshash -Raw
|
||||
- ps: cd ..\..
|
||||
- ps: >-
|
||||
if ($depshash_baked -ne $depshash) {
|
||||
$env:RUN_GCLIENT_SYNC="true"
|
||||
}
|
||||
- if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync --with_branch_heads --with_tags ) else ( gclient runhooks )
|
||||
- cd src
|
||||
- ps: $env:PATH="$pwd\third_party\ninja;$env:PATH"
|
||||
- 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% "
|
||||
- gn check out/Default //electron:electron_lib
|
||||
- gn check out/Default //electron:electron_app
|
||||
- gn check out/Default //electron/shell/common/api:mojo
|
||||
- if DEFINED GN_GOMA_FILE (ninja -j 300 -C out/Default electron:electron_app) else (ninja -C out/Default electron:electron_app)
|
||||
- if "%GN_CONFIG%"=="testing" ( python C:\depot_tools\post_build_ninja_summary.py -C out\Default )
|
||||
- gn gen out/ffmpeg "--args=import(\"//electron/build/args/ffmpeg.gn\") %GN_EXTRA_ARGS%"
|
||||
- ninja -C out/ffmpeg electron:electron_ffmpeg_zip
|
||||
- ninja -C out/Default electron:electron_dist_zip
|
||||
- ninja -C out/Default shell_browser_ui_unittests
|
||||
- gn desc out/Default v8:run_mksnapshot_default args > out/Default/default_mksnapshot_args
|
||||
# Remove unused args from mksnapshot_args
|
||||
- ps: >-
|
||||
Get-Content out/Default/default_mksnapshot_args | Where-Object { -not $_.Contains('--turbo-profiling-input') -And -not $_.Contains('builtins-pgo') } | Set-Content out/Default/mksnapshot_args
|
||||
- ninja -C out/Default electron:electron_mksnapshot_zip
|
||||
- cd out\Default
|
||||
- 7z a mksnapshot.zip mksnapshot_args gen\v8\embedded.S
|
||||
- cd ..\..
|
||||
- ninja -C out/Default electron:hunspell_dictionaries_zip
|
||||
- ninja -C out/Default electron:electron_chromedriver_zip
|
||||
- ninja -C out/Default third_party/electron_node:headers
|
||||
- python %LOCAL_GOMA_DIR%\goma_ctl.py stat
|
||||
- ps: >-
|
||||
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 | Out-File -Encoding utf8 -FilePath .\installed_software.json
|
||||
- python3 electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json
|
||||
- 7z a node_headers.zip out\Default\gen\node_headers
|
||||
- ps: >-
|
||||
if ($env:GN_CONFIG -eq 'release') {
|
||||
# Needed for msdia140.dll on 64-bit windows
|
||||
$env:Path += ";$pwd\third_party\llvm-build\Release+Asserts\bin"
|
||||
ninja -C out/Default electron:electron_symbols
|
||||
}
|
||||
- ps: >-
|
||||
if ($env:GN_CONFIG -eq 'release') {
|
||||
python3 electron\script\zip-symbols.py
|
||||
appveyor-retry appveyor PushArtifact out/Default/symbols.zip
|
||||
} else {
|
||||
# It's useful to have pdb files when debugging testing builds that are
|
||||
# built on CI.
|
||||
7z a pdb.zip out\Default\*.pdb
|
||||
}
|
||||
- python3 electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest
|
||||
|
||||
deploy_script:
|
||||
- cd electron
|
||||
- ps: >-
|
||||
if (Test-Path Env:\ELECTRON_RELEASE) {
|
||||
if (Test-Path Env:\UPLOAD_TO_STORAGE) {
|
||||
Write-Output "Uploading Electron release distribution to azure"
|
||||
& python3 script\release\uploaders\upload.py --verbose --upload_to_storage
|
||||
} else {
|
||||
Write-Output "Uploading Electron release distribution to github releases"
|
||||
& python3 script\release\uploaders\upload.py --verbose
|
||||
}
|
||||
}
|
||||
on_finish:
|
||||
# Uncomment this lines to enable RDP
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
- cd C:\projects\src
|
||||
- if exist out\Default\windows_toolchain_profile.json ( appveyor-retry appveyor PushArtifact out\Default\windows_toolchain_profile.json )
|
||||
- if exist out\Default\dist.zip (appveyor-retry appveyor PushArtifact out\Default\dist.zip)
|
||||
- if exist out\Default\shell_browser_ui_unittests.exe (appveyor-retry appveyor PushArtifact out\Default\shell_browser_ui_unittests.exe)
|
||||
- if exist out\Default\chromedriver.zip (appveyor-retry appveyor PushArtifact out\Default\chromedriver.zip)
|
||||
- if exist out\ffmpeg\ffmpeg.zip (appveyor-retry appveyor PushArtifact out\ffmpeg\ffmpeg.zip)
|
||||
- if exist node_headers.zip (appveyor-retry appveyor PushArtifact node_headers.zip)
|
||||
- if exist out\Default\mksnapshot.zip (appveyor-retry appveyor PushArtifact out\Default\mksnapshot.zip)
|
||||
- if exist out\Default\hunspell_dictionaries.zip (appveyor-retry appveyor PushArtifact out\Default\hunspell_dictionaries.zip)
|
||||
- if exist out\Default\electron.lib (appveyor-retry appveyor PushArtifact out\Default\electron.lib)
|
||||
- ps: >-
|
||||
if ((Test-Path "pdb.zip") -And ($env:GN_CONFIG -ne 'release')) {
|
||||
appveyor-retry appveyor PushArtifact pdb.zip
|
||||
}
|
||||
- matrix:
|
||||
only:
|
||||
- job_name: Test On Windows On Arm Hardware
|
||||
|
||||
environment:
|
||||
IGNORE_YARN_INSTALL_ERROR: 1
|
||||
ELECTRON_TEST_RESULTS_DIR: junit
|
||||
MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap'
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
ELECTRON_SKIP_NATIVE_MODULE_TESTS: true
|
||||
|
||||
build_script:
|
||||
- ps: |
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild
|
||||
}
|
||||
$global:LASTEXITCODE = 0
|
||||
- cd ..
|
||||
- mkdir out\Default
|
||||
- cd ..
|
||||
- ps: |
|
||||
# Download build artifacts
|
||||
$apiUrl = 'https://ci.appveyor.com/api'
|
||||
$build_info = Invoke-RestMethod -Method Get -Uri "$apiUrl/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/builds/$env:APPVEYOR_BUILD_ID"
|
||||
$artifacts_to_download = @('dist.zip','ffmpeg.zip','node_headers.zip','pdb.zip','electron.lib')
|
||||
foreach ($job in $build_info.build.jobs) {
|
||||
if ($job.name -eq "Build Arm on X64 Windows") {
|
||||
$jobId = $job.jobId
|
||||
foreach($artifact_name in $artifacts_to_download) {
|
||||
if ($artifact_name -eq 'shell_browser_ui_unittests.exe' -Or $artifact_name -eq 'electron.lib') {
|
||||
$outfile = "src\out\Default\$artifact_name"
|
||||
} else {
|
||||
$outfile = $artifact_name
|
||||
}
|
||||
Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/$artifact_name" -OutFile $outfile
|
||||
}
|
||||
}
|
||||
}
|
||||
- ps: |
|
||||
$out_default_zips = @('dist.zip','pdb.zip')
|
||||
foreach($zip_name in $out_default_zips) {
|
||||
7z x -y -osrc\out\Default $zip_name
|
||||
}
|
||||
- ps: 7z x -y -osrc\out\ffmpeg ffmpeg.zip
|
||||
- ps: 7z x -y -osrc node_headers.zip
|
||||
|
||||
test_script:
|
||||
# Workaround for https://github.com/appveyor/ci/issues/2420
|
||||
- set "PATH=%PATH%;C:\Program Files\Git\mingw64\libexec\git-core"
|
||||
- ps: |
|
||||
cd src
|
||||
New-Item .\out\Default\gen\node_headers\Release -Type directory
|
||||
Copy-Item -path .\out\Default\electron.lib -destination .\out\Default\gen\node_headers\Release\node.lib
|
||||
- set npm_config_nodedir=%cd%\out\Default\gen\node_headers
|
||||
- set npm_config_arch=arm64
|
||||
- cd electron
|
||||
# Explicitly set npm_config_arch because the .env doesn't persist
|
||||
- ps: >-
|
||||
if ($env:TARGET_ARCH -eq 'ia32') {
|
||||
$env:npm_config_arch = "ia32"
|
||||
}
|
||||
- echo Running main test suite & node script/yarn test --runners=main --enable-logging --disable-features=CalculateNativeWinOcclusion
|
||||
- cd ..
|
||||
- echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg
|
||||
|
||||
on_finish:
|
||||
# Uncomment these lines to enable RDP
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
- if exist electron\electron.log ( appveyor-retry appveyor PushArtifact electron\electron.log )
|
||||
463
appveyor.yml
463
appveyor.yml
@@ -1,9 +1,13 @@
|
||||
# NOTE IF CHANGING THIS FILE, ALSO APPLY THE CHANGE TO appveyor-woa.yml
|
||||
# IF APPLICABLE!!!!
|
||||
#
|
||||
#
|
||||
# The config expects the following environment variables to be set:
|
||||
# - "GN_CONFIG" Build type. One of {'testing', 'release'}.
|
||||
# - "GN_EXTRA_ARGS" Additional gn arguments for a build config,
|
||||
# e.g. 'target_cpu="x86"' to build for a 32bit platform.
|
||||
# https://gn.googlesource.com/gn/+/master/docs/reference.md#target_cpu
|
||||
# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordningly
|
||||
# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordingly
|
||||
# if you pass a custom value for 'target_cpu'.
|
||||
# - "ELECTRON_RELEASE" Set it to '1' upload binaries on success.
|
||||
# - "NPM_CONFIG_ARCH" E.g. 'x86'. Is used to build native Node.js modules.
|
||||
@@ -12,7 +16,7 @@
|
||||
# Is used in some publishing scripts, but does NOT affect the Electron binary.
|
||||
# Must match 'target_cpu' passed to "GN_EXTRA_ARGS" and "NPM_CONFIG_ARCH" value.
|
||||
# - "UPLOAD_TO_STORAGE" Set it to '1' upload a release to the Azure bucket.
|
||||
# Otherwise the release will be uploaded to the Github Releases.
|
||||
# Otherwise the release will be uploaded to the GitHub Releases.
|
||||
# (The value is only checked if "ELECTRON_RELEASE" is defined.)
|
||||
#
|
||||
# The publishing scripts expect access tokens to be defined as env vars,
|
||||
@@ -24,227 +28,258 @@
|
||||
# https://www.appveyor.com/docs/build-configuration/#custom-environment-variables
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electron-16-core
|
||||
image: vs2019bt-16.16.11
|
||||
build_cloud: electronhq-16-core
|
||||
image: e-104.0.5112.124-fix
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\electron\libcc_cache
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
ELECTRON_ENABLE_STACK_DUMPING: 1
|
||||
ELECTRON_ALSO_LOG_TO_STDERR: 1
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap
|
||||
GOMA_FALLBACK_ON_AUTH_FAILURE: true
|
||||
build_script:
|
||||
- ps: >-
|
||||
if(($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME -split "/")[0] -eq ($env:APPVEYOR_REPO_NAME -split "/")[0]) {
|
||||
Write-warning "Skipping PR build for branch"; Exit-AppveyorBuild
|
||||
} else {
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
DEPOT_TOOLS_WIN_TOOLCHAIN: 0
|
||||
PYTHONIOENCODING: UTF-8
|
||||
|
||||
$result = node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH
|
||||
Write-Output $result
|
||||
if ($result.ExitCode -eq 0) {
|
||||
Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild
|
||||
}
|
||||
}
|
||||
- echo "Building $env:GN_CONFIG build"
|
||||
- git config --global core.longpaths true
|
||||
- cd ..
|
||||
- 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') {
|
||||
$env:NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] "
|
||||
}
|
||||
- >-
|
||||
gclient config
|
||||
--name "src\electron"
|
||||
--unmanaged
|
||||
%GCLIENT_EXTRA_ARGS%
|
||||
"https://github.com/electron/electron"
|
||||
- ps: >-
|
||||
if ($env:GN_CONFIG -eq 'release') {
|
||||
$env:RUN_GCLIENT_SYNC="true"
|
||||
} else {
|
||||
cd src\electron
|
||||
node script\generate-deps-hash.js
|
||||
$depshash = Get-Content .\.depshash -Raw
|
||||
$zipfile = "Z:\$depshash.7z"
|
||||
cd ..\..
|
||||
if (Test-Path -Path $zipfile) {
|
||||
# file exists, unzip and then gclient sync
|
||||
7z x -y $zipfile -mmt=30 -aoa
|
||||
if (-not (Test-Path -Path "src\buildtools")) {
|
||||
# the zip file must be corrupt - resync
|
||||
$env:RUN_GCLIENT_SYNC="true"
|
||||
if ($env:TARGET_ARCH -ne 'ia32') {
|
||||
# only save on x64/woa to avoid contention saving
|
||||
$env:SAVE_GCLIENT_SRC="true"
|
||||
matrix:
|
||||
|
||||
- job_name: Build
|
||||
- job_name: Test
|
||||
job_depends_on: Build
|
||||
|
||||
clone_folder: C:\projects\src\electron
|
||||
|
||||
skip_branch_with_pr: true
|
||||
|
||||
# the first failed job cancels other jobs and fails entire build
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
for:
|
||||
|
||||
- matrix:
|
||||
only:
|
||||
- job_name: Build
|
||||
|
||||
build_script:
|
||||
- ps: |
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild
|
||||
}
|
||||
$global:LASTEXITCODE = 0
|
||||
- cd ..
|
||||
- ps: Write-Host "Building $env:GN_CONFIG build"
|
||||
- git config --global core.longpaths true
|
||||
- ps: >-
|
||||
if (Test-Path -Path "$pwd\depot_tools") {
|
||||
Remove-Item -Recurse -Force $pwd\depot_tools
|
||||
}
|
||||
- ps: >-
|
||||
if (Test-Path -Path "$pwd\build-tools") {
|
||||
Remove-Item -Recurse -Force $pwd\build-tools
|
||||
}
|
||||
- ps: |
|
||||
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
cd depot_tools
|
||||
git fetch --depth 1 origin b7d8efd8bee494f4cfacacc19cf50fc4d4be3900
|
||||
git checkout b7d8efd8bee494f4cfacacc19cf50fc4d4be3900
|
||||
New-Item -Name .disable_auto_update -ItemType File
|
||||
bootstrap\win_tools.bat
|
||||
cd ..
|
||||
- ps: $env:PATH="$pwd\depot_tools;$env:PATH"
|
||||
- ps: >-
|
||||
if (Test-Path -Path "$pwd\src\electron") {
|
||||
Remove-Item -Recurse -Force $pwd\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') {
|
||||
$env:NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] "
|
||||
}
|
||||
- gclient config --name "src\electron" --unmanaged %GCLIENT_EXTRA_ARGS% "https://github.com/electron/electron"
|
||||
# Patches are applied in the image bake. Check depshash to see if patches have changed.
|
||||
- ps: $env:RUN_GCLIENT_SYNC="false"
|
||||
- ps: $depshash_baked = Get-Content .\src\.depshash -Raw
|
||||
- ps: cd src\electron
|
||||
- ps: node script\generate-deps-hash.js
|
||||
- ps: $depshash = Get-Content .\.depshash -Raw
|
||||
- ps: cd ..\..
|
||||
- ps: >-
|
||||
if ($depshash_baked -ne $depshash) {
|
||||
$env:RUN_GCLIENT_SYNC="true"
|
||||
}
|
||||
- if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync --with_branch_heads --with_tags ) else ( gclient runhooks )
|
||||
- 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% "
|
||||
- gn check out/Default //electron:electron_lib
|
||||
- gn check out/Default //electron:electron_app
|
||||
- gn check out/Default //electron/shell/common/api:mojo
|
||||
- if DEFINED GN_GOMA_FILE (ninja -j 300 -C out/Default electron:electron_app) else (ninja -C out/Default electron:electron_app)
|
||||
- if "%GN_CONFIG%"=="testing" ( python C:\depot_tools\post_build_ninja_summary.py -C out\Default )
|
||||
- gn gen out/ffmpeg "--args=import(\"//electron/build/args/ffmpeg.gn\") %GN_EXTRA_ARGS%"
|
||||
- ninja -C out/ffmpeg electron:electron_ffmpeg_zip
|
||||
- ninja -C out/Default electron:electron_dist_zip
|
||||
- ninja -C out/Default shell_browser_ui_unittests
|
||||
- gn desc out/Default v8:run_mksnapshot_default args > out/Default/default_mksnapshot_args
|
||||
# Remove unused args from mksnapshot_args
|
||||
- ps: >-
|
||||
Get-Content out/Default/default_mksnapshot_args | Where-Object { -not $_.Contains('--turbo-profiling-input') -And -not $_.Contains('builtins-pgo') } | Set-Content out/Default/mksnapshot_args
|
||||
- ninja -C out/Default electron:electron_mksnapshot_zip
|
||||
- cd out\Default
|
||||
- 7z a mksnapshot.zip mksnapshot_args gen\v8\embedded.S
|
||||
- cd ..\..
|
||||
- ninja -C out/Default electron:hunspell_dictionaries_zip
|
||||
- ninja -C out/Default electron:electron_chromedriver_zip
|
||||
- ninja -C out/Default third_party/electron_node:headers
|
||||
- python %LOCAL_GOMA_DIR%\goma_ctl.py stat
|
||||
- ps: >-
|
||||
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 | Out-File -Encoding utf8 -FilePath .\installed_software.json
|
||||
- python3 electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json
|
||||
- 7z a node_headers.zip out\Default\gen\node_headers
|
||||
- ps: >-
|
||||
if ($env:GN_CONFIG -eq 'release') {
|
||||
# Needed for msdia140.dll on 64-bit windows
|
||||
$env:Path += ";$pwd\third_party\llvm-build\Release+Asserts\bin"
|
||||
ninja -C out/Default electron:electron_symbols
|
||||
}
|
||||
- ps: >-
|
||||
if ($env:GN_CONFIG -eq 'release') {
|
||||
python3 electron\script\zip-symbols.py
|
||||
appveyor-retry appveyor PushArtifact out/Default/symbols.zip
|
||||
} else {
|
||||
# update angle
|
||||
cd src\third_party\angle
|
||||
git remote set-url origin https://chromium.googlesource.com/angle/angle.git
|
||||
git fetch
|
||||
cd ..\..\..
|
||||
# It's useful to have pdb files when debugging testing builds that are
|
||||
# built on CI.
|
||||
7z a pdb.zip out\Default\*.pdb
|
||||
}
|
||||
} else {
|
||||
# file does not exist, gclient sync, then zip
|
||||
$env:RUN_GCLIENT_SYNC="true"
|
||||
if ($env:TARGET_ARCH -ne 'ia32') {
|
||||
# only save on x64/woa to avoid contention saving
|
||||
$env:SAVE_GCLIENT_SRC="true"
|
||||
}
|
||||
}
|
||||
}
|
||||
- if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync )
|
||||
- ps: >-
|
||||
if ($env:SAVE_GCLIENT_SRC -eq 'true') {
|
||||
# archive current source for future use
|
||||
# only run on x64/woa to avoid contention saving
|
||||
$(7z a $zipfile src -xr!android_webview -xr!electron -xr'!*\.git' -xr!third_party\WebKit\LayoutTests! -xr!third_party\blink\web_tests -xr!third_party\blink\perf_tests -slp -t7z -mmt=30)
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-warning "Could not save source to shared drive; continuing anyway"
|
||||
}
|
||||
# build time generation of file gen/angle/angle_commit.h depends on
|
||||
# third_party/angle/.git
|
||||
# https://chromium-review.googlesource.com/c/angle/angle/+/2074924
|
||||
$(7z a $zipfile src\third_party\angle\.git)
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-warning "Failed to add third_party\angle\.git; continuing anyway"
|
||||
}
|
||||
# build time generation of file dawn/common/Version_autogen.h depends on third_party/dawn/.git/HEAD
|
||||
# https://dawn-review.googlesource.com/c/dawn/+/83901
|
||||
$(7z a $zipfile src\third_party\dawn\.git)
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-warning "Failed to add third_party\dawn\.git; continuing anyway"
|
||||
}
|
||||
}
|
||||
- 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% "
|
||||
- gn check out/Default //electron:electron_lib
|
||||
- gn check out/Default //electron:electron_app
|
||||
- gn check out/Default //electron/shell/common/api:mojo
|
||||
- if DEFINED GN_GOMA_FILE (ninja -j 300 -C out/Default electron:electron_app) else (ninja -C out/Default electron:electron_app)
|
||||
- if "%GN_CONFIG%"=="testing" ( python C:\depot_tools\post_build_ninja_summary.py -C out\Default )
|
||||
- gn gen out/ffmpeg "--args=import(\"//electron/build/args/ffmpeg.gn\") %GN_EXTRA_ARGS%"
|
||||
- ninja -C out/ffmpeg electron:electron_ffmpeg_zip
|
||||
- ninja -C out/Default electron:electron_dist_zip
|
||||
- ninja -C out/Default shell_browser_ui_unittests
|
||||
- gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args
|
||||
- ninja -C out/Default electron:electron_mksnapshot_zip
|
||||
- cd out\Default
|
||||
- 7z a mksnapshot.zip mksnapshot_args gen\v8\embedded.S
|
||||
- cd ..\..
|
||||
- ninja -C out/Default electron:hunspell_dictionaries_zip
|
||||
- ninja -C out/Default electron:electron_chromedriver_zip
|
||||
- ninja -C out/Default third_party/electron_node:headers
|
||||
- python %LOCAL_GOMA_DIR%\goma_ctl.py stat
|
||||
- python3 electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json
|
||||
- 7z a node_headers.zip out\Default\gen\node_headers
|
||||
# Temporarily disable symbol generation on 32-bit Windows due to failures
|
||||
- ps: >-
|
||||
if ($env:GN_CONFIG -eq 'release' -And $env:TARGET_ARCH -ne 'ia32') {
|
||||
# Needed for msdia140.dll on 64-bit windows
|
||||
$env:Path += ";$pwd\third_party\llvm-build\Release+Asserts\bin"
|
||||
ninja -C out/Default electron:electron_symbols
|
||||
}
|
||||
- ps: >-
|
||||
if ($env:GN_CONFIG -eq 'release') {
|
||||
if ($env:TARGET_ARCH -ne 'ia32') {
|
||||
python electron\script\zip-symbols.py
|
||||
appveyor-retry appveyor PushArtifact out/Default/symbols.zip
|
||||
}
|
||||
} else {
|
||||
# It's useful to have pdb files when debugging testing builds that are
|
||||
# built on CI.
|
||||
7z a pdb.zip out\Default\*.pdb
|
||||
}
|
||||
- python electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest
|
||||
test_script:
|
||||
# Workaround for https://github.com/appveyor/ci/issues/2420
|
||||
- set "PATH=%PATH%;C:\Program Files\Git\mingw64\libexec\git-core"
|
||||
- ps: >-
|
||||
if ((-Not (Test-Path Env:\TEST_WOA)) -And (-Not (Test-Path Env:\ELECTRON_RELEASE)) -And ($env:GN_CONFIG -in "testing", "release")) {
|
||||
$env:RUN_TESTS="true"
|
||||
}
|
||||
- ps: >-
|
||||
if ($env:RUN_TESTS -eq 'true') {
|
||||
New-Item .\out\Default\gen\node_headers\Release -Type directory
|
||||
Copy-Item -path .\out\Default\electron.lib -destination .\out\Default\gen\node_headers\Release\node.lib
|
||||
} else {
|
||||
echo "Skipping tests for $env:GN_CONFIG build"
|
||||
}
|
||||
- cd electron
|
||||
# CalculateNativeWinOcclusion is disabled due to https://bugs.chromium.org/p/chromium/issues/detail?id=1139022
|
||||
- if "%RUN_TESTS%"=="true" ( echo Running main test suite & node script/yarn test -- --trace-uncaught --runners=main --enable-logging=file --log-file=%cd%\electron.log --disable-features=CalculateNativeWinOcclusion )
|
||||
- if "%RUN_TESTS%"=="true" ( echo Running remote test suite & node script/yarn test -- --trace-uncaught --runners=remote --runTestFilesSeperately --enable-logging=file --log-file=%cd%\electron.log --disable-features=CalculateNativeWinOcclusion )
|
||||
- if "%RUN_TESTS%"=="true" ( echo Running native test suite & node script/yarn test -- --trace-uncaught --runners=native --enable-logging=file --log-file=%cd%\electron.log --disable-features=CalculateNativeWinOcclusion )
|
||||
- cd ..
|
||||
- if "%RUN_TESTS%"=="true" ( echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg )
|
||||
- echo "About to verify mksnapshot"
|
||||
- if "%RUN_TESTS%"=="true" ( echo Verifying mksnapshot & python electron\script\verify-mksnapshot.py --build-dir out\Default --source-root %cd% )
|
||||
- echo "Done verifying mksnapshot"
|
||||
- if "%RUN_TESTS%"=="true" ( echo Verifying chromedriver & python electron\script\verify-chromedriver.py --build-dir out\Default --source-root %cd% )
|
||||
- echo "Done verifying chromedriver"
|
||||
deploy_script:
|
||||
- cd electron
|
||||
- ps: >-
|
||||
if (Test-Path Env:\ELECTRON_RELEASE) {
|
||||
if (Test-Path Env:\UPLOAD_TO_STORAGE) {
|
||||
Write-Output "Uploading Electron release distribution to azure"
|
||||
& python script\release\uploaders\upload.py --verbose --upload_to_storage
|
||||
} else {
|
||||
Write-Output "Uploading Electron release distribution to github releases"
|
||||
& python script\release\uploaders\upload.py --verbose
|
||||
}
|
||||
} elseif (Test-Path Env:\TEST_WOA) {
|
||||
node script/release/ci-release-build.js --job=electron-woa-testing --ci=VSTS --armTest --appveyorJobId=$env:APPVEYOR_JOB_ID $env:APPVEYOR_REPO_BRANCH
|
||||
}
|
||||
on_finish:
|
||||
# Uncomment this lines to enable RDP
|
||||
#- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
- cd ..
|
||||
- if exist out\Default\windows_toolchain_profile.json ( appveyor-retry appveyor PushArtifact out\Default\windows_toolchain_profile.json )
|
||||
- if exist out\Default\dist.zip (appveyor-retry appveyor PushArtifact out\Default\dist.zip)
|
||||
- if exist out\Default\shell_browser_ui_unittests.exe (appveyor-retry appveyor PushArtifact out\Default\shell_browser_ui_unittests.exe)
|
||||
- if exist out\Default\chromedriver.zip (appveyor-retry appveyor PushArtifact out\Default\chromedriver.zip)
|
||||
- if exist out\ffmpeg\ffmpeg.zip (appveyor-retry appveyor PushArtifact out\ffmpeg\ffmpeg.zip)
|
||||
- if exist node_headers.zip (appveyor-retry appveyor PushArtifact node_headers.zip)
|
||||
- if exist out\Default\mksnapshot.zip (appveyor-retry appveyor PushArtifact out\Default\mksnapshot.zip)
|
||||
- if exist out\Default\hunspell_dictionaries.zip (appveyor-retry appveyor PushArtifact out\Default\hunspell_dictionaries.zip)
|
||||
- if exist out\Default\electron.lib (appveyor-retry appveyor PushArtifact out\Default\electron.lib)
|
||||
- ps: >-
|
||||
if ((Test-Path "pdb.zip") -And ($env:GN_CONFIG -ne 'release')) {
|
||||
appveyor-retry appveyor PushArtifact pdb.zip
|
||||
}
|
||||
- python3 electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest
|
||||
|
||||
- if exist electron\electron.log ( appveyor-retry appveyor PushArtifact electron\electron.log )
|
||||
deploy_script:
|
||||
- cd electron
|
||||
- ps: >-
|
||||
if (Test-Path Env:\ELECTRON_RELEASE) {
|
||||
if (Test-Path Env:\UPLOAD_TO_STORAGE) {
|
||||
Write-Output "Uploading Electron release distribution to azure"
|
||||
& python3 script\release\uploaders\upload.py --verbose --upload_to_storage
|
||||
} else {
|
||||
Write-Output "Uploading Electron release distribution to github releases"
|
||||
& python3 script\release\uploaders\upload.py --verbose
|
||||
}
|
||||
}
|
||||
on_finish:
|
||||
# Uncomment this lines to enable RDP
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
- cd C:\projects\src
|
||||
- if exist out\Default\windows_toolchain_profile.json ( appveyor-retry appveyor PushArtifact out\Default\windows_toolchain_profile.json )
|
||||
- if exist out\Default\dist.zip (appveyor-retry appveyor PushArtifact out\Default\dist.zip)
|
||||
- if exist out\Default\shell_browser_ui_unittests.exe (appveyor-retry appveyor PushArtifact out\Default\shell_browser_ui_unittests.exe)
|
||||
- if exist out\Default\chromedriver.zip (appveyor-retry appveyor PushArtifact out\Default\chromedriver.zip)
|
||||
- if exist out\ffmpeg\ffmpeg.zip (appveyor-retry appveyor PushArtifact out\ffmpeg\ffmpeg.zip)
|
||||
- if exist node_headers.zip (appveyor-retry appveyor PushArtifact node_headers.zip)
|
||||
- if exist out\Default\mksnapshot.zip (appveyor-retry appveyor PushArtifact out\Default\mksnapshot.zip)
|
||||
- if exist out\Default\hunspell_dictionaries.zip (appveyor-retry appveyor PushArtifact out\Default\hunspell_dictionaries.zip)
|
||||
- if exist out\Default\electron.lib (appveyor-retry appveyor PushArtifact out\Default\electron.lib)
|
||||
- ps: >-
|
||||
if ((Test-Path "pdb.zip") -And ($env:GN_CONFIG -ne 'release')) {
|
||||
appveyor-retry appveyor PushArtifact pdb.zip
|
||||
}
|
||||
- matrix:
|
||||
only:
|
||||
- job_name: Test
|
||||
|
||||
init:
|
||||
- ps: |
|
||||
if ($env:RUN_TESTS -ne 'true') {
|
||||
Write-warning "Skipping tests for $env:APPVEYOR_PROJECT_NAME"; Exit-AppveyorBuild
|
||||
}
|
||||
build_script:
|
||||
- ps: |
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild
|
||||
}
|
||||
$global:LASTEXITCODE = 0
|
||||
- cd ..
|
||||
- mkdir out\Default
|
||||
- cd ..
|
||||
- ps: |
|
||||
# Download build artifacts
|
||||
$apiUrl = 'https://ci.appveyor.com/api'
|
||||
$build_info = Invoke-RestMethod -Method Get -Uri "$apiUrl/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/builds/$env:APPVEYOR_BUILD_ID"
|
||||
$artifacts_to_download = @('dist.zip','shell_browser_ui_unittests.exe','chromedriver.zip','ffmpeg.zip','node_headers.zip','mksnapshot.zip','electron.lib')
|
||||
foreach ($job in $build_info.build.jobs) {
|
||||
if ($job.name -eq "Build") {
|
||||
$jobId = $job.jobId
|
||||
foreach($artifact_name in $artifacts_to_download) {
|
||||
if ($artifact_name -eq 'shell_browser_ui_unittests.exe' -Or $artifact_name -eq 'electron.lib') {
|
||||
$outfile = "src\out\Default\$artifact_name"
|
||||
} else {
|
||||
$outfile = $artifact_name
|
||||
}
|
||||
Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/$artifact_name" -OutFile $outfile
|
||||
}
|
||||
}
|
||||
}
|
||||
- ps: |
|
||||
$out_default_zips = @('dist.zip','chromedriver.zip','mksnapshot.zip')
|
||||
foreach($zip_name in $out_default_zips) {
|
||||
7z x -y -osrc\out\Default $zip_name
|
||||
}
|
||||
- ps: 7z x -y -osrc\out\ffmpeg ffmpeg.zip
|
||||
- ps: 7z x -y -osrc node_headers.zip
|
||||
|
||||
test_script:
|
||||
# Workaround for https://github.com/appveyor/ci/issues/2420
|
||||
- set "PATH=%PATH%;C:\Program Files\Git\mingw64\libexec\git-core"
|
||||
- ps: |
|
||||
cd src
|
||||
New-Item .\out\Default\gen\node_headers\Release -Type directory
|
||||
Copy-Item -path .\out\Default\electron.lib -destination .\out\Default\gen\node_headers\Release\node.lib
|
||||
- cd electron
|
||||
# Explicitly set npm_config_arch because the .env doesn't persist
|
||||
- ps: >-
|
||||
if ($env:TARGET_ARCH -eq 'ia32') {
|
||||
$env:npm_config_arch = "ia32"
|
||||
}
|
||||
- echo Running main test suite & node script/yarn test -- --trace-uncaught --runners=main --enable-logging=file --log-file=%cd%\electron.log
|
||||
- echo Running native test suite & node script/yarn test -- --trace-uncaught --runners=native --enable-logging=file --log-file=%cd%\electron.log
|
||||
- cd ..
|
||||
- echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg
|
||||
- echo "About to verify mksnapshot"
|
||||
- echo Verifying mksnapshot & python electron\script\verify-mksnapshot.py --build-dir out\Default --source-root %cd%
|
||||
- echo "Done verifying mksnapshot"
|
||||
- echo Verifying chromedriver & python electron\script\verify-chromedriver.py --build-dir out\Default --source-root %cd%
|
||||
- echo "Done verifying chromedriver"
|
||||
|
||||
on_finish:
|
||||
# Uncomment these lines to enable RDP
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
- if exist electron\electron.log ( appveyor-retry appveyor PushArtifact electron\electron.log )
|
||||
@@ -1,121 +0,0 @@
|
||||
steps:
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy Files to: src/electron'
|
||||
inputs:
|
||||
TargetFolder: src/electron
|
||||
|
||||
- bash: |
|
||||
cd src/electron
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
displayName: 'Yarn install'
|
||||
|
||||
- bash: |
|
||||
export ZIP_DEST=$PWD/src/out/Default
|
||||
echo "##vso[task.setvariable variable=ZIP_DEST]$ZIP_DEST"
|
||||
mkdir -p $ZIP_DEST
|
||||
cd src/electron
|
||||
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=dist.zip --dest=$ZIP_DEST
|
||||
cd $ZIP_DEST
|
||||
unzip -o dist.zip
|
||||
xattr -cr Electron.app
|
||||
displayName: 'Download and unzip dist files for test'
|
||||
env:
|
||||
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
|
||||
|
||||
- bash: |
|
||||
export FFMPEG_ZIP_DEST=$PWD/src/out/ffmpeg
|
||||
mkdir -p $FFMPEG_ZIP_DEST
|
||||
cd src/electron
|
||||
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=ffmpeg.zip --dest=$FFMPEG_ZIP_DEST
|
||||
cd $FFMPEG_ZIP_DEST
|
||||
unzip -o ffmpeg.zip
|
||||
displayName: 'Download and unzip ffmpeg for test'
|
||||
env:
|
||||
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
|
||||
|
||||
- bash: |
|
||||
export NODE_HEADERS_DEST=$PWD/src/out/Default/gen
|
||||
mkdir -p $NODE_HEADERS_DEST
|
||||
cd src/electron
|
||||
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=node_headers.tar.gz --dest=$NODE_HEADERS_DEST
|
||||
cd $NODE_HEADERS_DEST
|
||||
tar xzf node_headers.tar.gz
|
||||
displayName: 'Download and untar node header files for test'
|
||||
env:
|
||||
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
|
||||
|
||||
- bash: |
|
||||
export CROSS_ARCH_SNAPSHOTS=$PWD/src/out/Default/cross-arch-snapshots
|
||||
mkdir -p $CROSS_ARCH_SNAPSHOTS
|
||||
cd src/electron
|
||||
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=cross-arch-snapshots/snapshot_blob.bin --dest=$CROSS_ARCH_SNAPSHOTS
|
||||
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=cross-arch-snapshots/v8_context_snapshot.arm64.bin --dest=$CROSS_ARCH_SNAPSHOTS
|
||||
displayName: 'Download cross arch snapshot files'
|
||||
env:
|
||||
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
|
||||
|
||||
- bash: |
|
||||
cd src
|
||||
export ELECTRON_OUT_DIR=Default
|
||||
export npm_config_arch=arm64
|
||||
(cd electron && node script/yarn test --enable-logging --runners main)
|
||||
displayName: 'Run Electron main tests'
|
||||
timeoutInMinutes: 20
|
||||
env:
|
||||
ELECTRON_DISABLE_SECURITY_WARNINGS: 1
|
||||
IGNORE_YARN_INSTALL_ERROR: 1
|
||||
ELECTRON_TEST_RESULTS_DIR: junit
|
||||
|
||||
- bash: |
|
||||
cd src
|
||||
export ELECTRON_OUT_DIR=Default
|
||||
export npm_config_arch=arm64
|
||||
(cd electron && node script/yarn test --enable-logging --runners remote)
|
||||
displayName: 'Run Electron remote tests'
|
||||
timeoutInMinutes: 20
|
||||
condition: succeededOrFailed()
|
||||
env:
|
||||
ELECTRON_DISABLE_SECURITY_WARNINGS: 1
|
||||
IGNORE_YARN_INSTALL_ERROR: 1
|
||||
ELECTRON_TEST_RESULTS_DIR: junit
|
||||
|
||||
- bash: |
|
||||
cd src
|
||||
python electron/script/verify-ffmpeg.py --source-root "$PWD" --build-dir out/Default --ffmpeg-path out/ffmpeg
|
||||
displayName: Verify non proprietary ffmpeg
|
||||
timeoutInMinutes: 5
|
||||
condition: succeededOrFailed()
|
||||
env:
|
||||
TARGET_ARCH: arm64
|
||||
|
||||
- bash: |
|
||||
cd src
|
||||
echo Verify cross arch snapshot
|
||||
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --snapshot-files-dir $PWD/out/Default/cross-arch-snapshots
|
||||
displayName: Verify cross arch snapshot
|
||||
timeoutInMinutes: 5
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Publish Test Results'
|
||||
inputs:
|
||||
testResultsFiles: '*.xml'
|
||||
|
||||
searchFolder: '$(System.DefaultWorkingDirectory)/src/junit/'
|
||||
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- bash: killall Electron || echo "No Electron processes left running"
|
||||
displayName: 'Kill processes left running from last test run'
|
||||
condition: always()
|
||||
|
||||
- bash: |
|
||||
rm -rf ~/Library/Application\ Support/Electron*
|
||||
rm -rf ~/Library/Application\ Support/electron*
|
||||
displayName: 'Delete user app data directories'
|
||||
condition: always()
|
||||
|
||||
- task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3
|
||||
displayName: 'Clean Agent Directories'
|
||||
|
||||
condition: always()
|
||||
@@ -1,130 +0,0 @@
|
||||
workspace:
|
||||
clean: all
|
||||
|
||||
steps:
|
||||
- checkout: self
|
||||
path: src\electron
|
||||
|
||||
- script: |
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
displayName: 'Yarn install'
|
||||
|
||||
- powershell: |
|
||||
$localArtifactPath = "$pwd\dist.zip"
|
||||
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/dist.zip"
|
||||
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
|
||||
& "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -o$(Pipeline.Workspace)\src\out\Default -y $localArtifactPath
|
||||
displayName: 'Download and extract dist.zip for test'
|
||||
env:
|
||||
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
|
||||
|
||||
- powershell: |
|
||||
$localArtifactPath = "$(Pipeline.Workspace)\src\out\Default\shell_browser_ui_unittests.exe"
|
||||
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/shell_browser_ui_unittests.exe"
|
||||
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
|
||||
displayName: 'Download and extract native test executables for test'
|
||||
env:
|
||||
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
|
||||
|
||||
- powershell: |
|
||||
$localArtifactPath = "$pwd\ffmpeg.zip"
|
||||
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/ffmpeg.zip"
|
||||
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
|
||||
& "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -o$(Pipeline.Workspace)\src\out\ffmpeg $localArtifactPath
|
||||
displayName: 'Download and extract ffmpeg.zip for test'
|
||||
env:
|
||||
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
|
||||
|
||||
- powershell: |
|
||||
$localArtifactPath = "$(Pipeline.Workspace)\src\node_headers.zip"
|
||||
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/node_headers.zip"
|
||||
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
|
||||
cd $(Pipeline.Workspace)\src
|
||||
& "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -y node_headers.zip
|
||||
displayName: 'Download node headers for test'
|
||||
env:
|
||||
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
|
||||
|
||||
- powershell: |
|
||||
$localArtifactPath = "$(Pipeline.Workspace)\src\out\Default\electron.lib"
|
||||
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/electron.lib"
|
||||
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
|
||||
displayName: 'Download electron.lib for test'
|
||||
env:
|
||||
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
|
||||
|
||||
# Uncomment the following block if pdb files are needed to debug issues
|
||||
# - powershell: |
|
||||
# try {
|
||||
# $localArtifactPath = "$(Pipeline.Workspace)\src\pdb.zip"
|
||||
# $serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/pdb.zip"
|
||||
# Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
|
||||
# cd $(Pipeline.Workspace)\src
|
||||
# & "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -y pdb.zip
|
||||
# } catch {
|
||||
# Write-Host "There was an exception encountered while downloading pdb files:" $_.Exception.Message
|
||||
# } finally {
|
||||
# $global:LASTEXITCODE = 0
|
||||
# }
|
||||
# displayName: 'Download pdb files for detailed stacktraces'
|
||||
# env:
|
||||
# APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
|
||||
|
||||
- powershell: |
|
||||
New-Item $(Pipeline.Workspace)\src\out\Default\gen\node_headers\Release -Type directory
|
||||
Copy-Item -path $(Pipeline.Workspace)\src\out\Default\electron.lib -destination $(Pipeline.Workspace)\src\out\Default\gen\node_headers\Release\node.lib
|
||||
displayName: 'Setup node headers'
|
||||
|
||||
- script: |
|
||||
cd $(Pipeline.Workspace)\src
|
||||
set npm_config_nodedir=%cd%\out\Default\gen\node_headers
|
||||
set npm_config_arch=arm64
|
||||
cd electron
|
||||
node script/yarn test --runners=main --enable-logging --disable-features=CalculateNativeWinOcclusion
|
||||
displayName: 'Run Electron Main process tests'
|
||||
env:
|
||||
ELECTRON_ENABLE_STACK_DUMPING: true
|
||||
ELECTRON_OUT_DIR: Default
|
||||
IGNORE_YARN_INSTALL_ERROR: 1
|
||||
ELECTRON_TEST_RESULTS_DIR: junit
|
||||
MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap'
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
|
||||
- script: |
|
||||
cd $(Pipeline.Workspace)\src
|
||||
set npm_config_nodedir=%cd%\out\Default\gen\node_headers
|
||||
set npm_config_arch=arm64
|
||||
cd electron
|
||||
node script/yarn test --runners=remote --enable-logging --disable-features=CalculateNativeWinOcclusion
|
||||
displayName: 'Run Electron Remote based tests'
|
||||
env:
|
||||
ELECTRON_OUT_DIR: Default
|
||||
IGNORE_YARN_INSTALL_ERROR: 1
|
||||
ELECTRON_TEST_RESULTS_DIR: junit
|
||||
MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap'
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Publish Test Results'
|
||||
inputs:
|
||||
testResultsFiles: '*.xml'
|
||||
searchFolder: '$(Pipeline.Workspace)/src/junit/'
|
||||
condition: always()
|
||||
|
||||
- script: |
|
||||
cd $(Pipeline.Workspace)\src
|
||||
echo "Verifying non proprietary ffmpeg"
|
||||
python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg
|
||||
displayName: 'Verify ffmpeg'
|
||||
|
||||
- powershell: |
|
||||
Get-Process | Where Name –Like "electron*" | Stop-Process
|
||||
Get-Process | Where Name –Like "msedge*" | Stop-Process
|
||||
displayName: 'Kill processes left running from last test run'
|
||||
condition: always()
|
||||
|
||||
- powershell: |
|
||||
Remove-Item -path $env:APPDATA/Electron* -Recurse -Force -ErrorAction Ignore
|
||||
displayName: 'Delete user app data directories'
|
||||
condition: always()
|
||||
@@ -24,7 +24,11 @@ template("extract_symbols") {
|
||||
assert(defined(invoker.binary), "Need binary to dump")
|
||||
assert(defined(invoker.symbol_dir), "Need directory for symbol output")
|
||||
|
||||
dump_syms_label = "//third_party/breakpad:dump_syms($host_toolchain)"
|
||||
if (host_os == "win" && target_cpu == "x86") {
|
||||
dump_syms_label = "//third_party/breakpad:dump_syms(//build/toolchain/win:win_clang_x64)"
|
||||
} else {
|
||||
dump_syms_label = "//third_party/breakpad:dump_syms($host_toolchain)"
|
||||
}
|
||||
dump_syms_binary = get_label_info(dump_syms_label, "root_out_dir") +
|
||||
"/dump_syms$_host_executable_suffix"
|
||||
|
||||
|
||||
@@ -7,5 +7,6 @@
|
||||
"node_options": "1",
|
||||
"node_cli_inspect": "1",
|
||||
"embedded_asar_integrity_validation": "0",
|
||||
"only_load_app_from_asar": "0"
|
||||
"only_load_app_from_asar": "0",
|
||||
"load_browser_process_specific_v8_snapshot": "0"
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import sys
|
||||
import os
|
||||
import optparse
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
sys.path.append("%s/../../build" % os.path.dirname(os.path.realpath(__file__)))
|
||||
|
||||
@@ -36,56 +34,10 @@ def calculate_hash(root):
|
||||
return CalculateHash('.', None)
|
||||
|
||||
def windows_installed_software():
|
||||
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",
|
||||
]
|
||||
|
||||
proc = subprocess.Popen(
|
||||
["powershell.exe", "-Command", "-"],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
|
||||
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)),
|
||||
)
|
||||
)
|
||||
# file_path = os.path.join(os.getcwd(), 'installed_software.json')
|
||||
# return json.loads(open('installed_software.json').read().decode('utf-8'))
|
||||
f = open('installed_software.json', encoding='utf-8-sig')
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def windows_profile():
|
||||
|
||||
@@ -50,8 +50,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 20,0,0,12
|
||||
PRODUCTVERSION 20,0,0,12
|
||||
FILEVERSION $major,$minor,$patch,$prerelease_number
|
||||
PRODUCTVERSION $major,$minor,$patch,$prerelease_number
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -68,12 +68,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "20.0.0"
|
||||
VALUE "FileVersion", "$major.$minor.$patch"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "20.0.0"
|
||||
VALUE "ProductVersion", "$major.$minor.$patch"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
1
build/templates/version_string.tmpl
Normal file
1
build/templates/version_string.tmpl
Normal file
@@ -0,0 +1 @@
|
||||
$full_version
|
||||
@@ -6,6 +6,7 @@ import("//build/config/ozone.gni")
|
||||
import("//build/config/ui.gni")
|
||||
import("//components/spellcheck/spellcheck_build_features.gni")
|
||||
import("//electron/buildflags/buildflags.gni")
|
||||
import("//ppapi/buildflags/buildflags.gni")
|
||||
import("//printing/buildflags/buildflags.gni")
|
||||
import("//third_party/widevine/cdm/widevine.gni")
|
||||
|
||||
@@ -55,6 +56,14 @@ static_library("chrome") {
|
||||
"//chrome/browser/process_singleton.h",
|
||||
"//chrome/browser/process_singleton_internal.cc",
|
||||
"//chrome/browser/process_singleton_internal.h",
|
||||
"//chrome/browser/themes/browser_theme_pack.cc",
|
||||
"//chrome/browser/themes/browser_theme_pack.h",
|
||||
"//chrome/browser/themes/custom_theme_supplier.cc",
|
||||
"//chrome/browser/themes/custom_theme_supplier.h",
|
||||
"//chrome/browser/themes/theme_properties.cc",
|
||||
"//chrome/browser/themes/theme_properties.h",
|
||||
"//chrome/browser/ui/color/chrome_color_mixers.cc",
|
||||
"//chrome/browser/ui/color/chrome_color_mixers.h",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.cc",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_controller_base.cc",
|
||||
@@ -69,7 +78,11 @@ static_library("chrome") {
|
||||
"//chrome/browser/ui/exclusive_access/keyboard_lock_controller.h",
|
||||
"//chrome/browser/ui/exclusive_access/mouse_lock_controller.cc",
|
||||
"//chrome/browser/ui/exclusive_access/mouse_lock_controller.h",
|
||||
"//chrome/browser/ui/frame/window_frame_util.cc",
|
||||
"//chrome/browser/ui/frame/window_frame_util.h",
|
||||
"//chrome/browser/ui/native_window_tracker.h",
|
||||
"//chrome/browser/ui/ui_features.cc",
|
||||
"//chrome/browser/ui/ui_features.h",
|
||||
"//chrome/browser/ui/views/eye_dropper/eye_dropper.cc",
|
||||
"//chrome/browser/ui/views/eye_dropper/eye_dropper.h",
|
||||
"//chrome/browser/ui/views/eye_dropper/eye_dropper_view.cc",
|
||||
@@ -109,6 +122,8 @@ static_library("chrome") {
|
||||
"//chrome/browser/ui/view_ids.h",
|
||||
"//chrome/browser/win/chrome_process_finder.cc",
|
||||
"//chrome/browser/win/chrome_process_finder.h",
|
||||
"//chrome/browser/win/titlebar_config.cc",
|
||||
"//chrome/browser/win/titlebar_config.h",
|
||||
"//chrome/browser/win/titlebar_config.h",
|
||||
"//chrome/child/v8_crashpad_support_win.cc",
|
||||
"//chrome/child/v8_crashpad_support_win.h",
|
||||
@@ -130,6 +145,7 @@ static_library("chrome") {
|
||||
|
||||
public_deps = [
|
||||
"//chrome/browser:dev_ui_browser_resources",
|
||||
"//chrome/browser/ui/color:mixers",
|
||||
"//chrome/common",
|
||||
"//chrome/common:version_header",
|
||||
"//components/keyed_service/content",
|
||||
@@ -355,15 +371,20 @@ source_set("plugins") {
|
||||
deps += [
|
||||
"//components/strings",
|
||||
"//media:media_buildflags",
|
||||
"//ppapi/buildflags",
|
||||
"//ppapi/host",
|
||||
"//ppapi/proxy",
|
||||
"//ppapi/proxy:ipc",
|
||||
"//ppapi/shared_impl",
|
||||
"//services/device/public/mojom",
|
||||
"//skia",
|
||||
"//storage/browser",
|
||||
]
|
||||
|
||||
if (enable_plugins) {
|
||||
deps += [
|
||||
"//ppapi/buildflags",
|
||||
"//ppapi/host",
|
||||
"//ppapi/proxy",
|
||||
"//ppapi/proxy:ipc",
|
||||
"//ppapi/shared_impl",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# This source set is just so we don't have to depend on all of //chrome/browser
|
||||
|
||||
@@ -83,7 +83,7 @@ function loadApplicationPackage (packagePath: string) {
|
||||
});
|
||||
|
||||
try {
|
||||
// Override app name and version.
|
||||
// Override app's package.json data.
|
||||
packagePath = path.resolve(packagePath);
|
||||
const packageJsonPath = path.join(packagePath, 'package.json');
|
||||
let appPath;
|
||||
@@ -104,6 +104,16 @@ function loadApplicationPackage (packagePath: string) {
|
||||
} else if (packageJson.name) {
|
||||
app.name = packageJson.name;
|
||||
}
|
||||
if (packageJson.desktopName) {
|
||||
app.setDesktopName(packageJson.desktopName);
|
||||
} else {
|
||||
app.setDesktopName(`${app.name}.desktop`);
|
||||
}
|
||||
// Set v8 flags, deliberately lazy load so that apps that do not use this
|
||||
// feature do not pay the price
|
||||
if (packageJson.v8Flags) {
|
||||
require('v8').setFlagsFromString(packageJson.v8Flags);
|
||||
}
|
||||
appPath = packagePath;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ an issue:
|
||||
* [Mac App Store](tutorial/mac-app-store-submission-guide.md)
|
||||
* [Windows Store](tutorial/windows-store-guide.md)
|
||||
* [Snapcraft](tutorial/snapcraft.md)
|
||||
* [ASAR Archives](tutorial/asar-archives.md)
|
||||
* [Updates](tutorial/updates.md)
|
||||
* [Getting Support](tutorial/support.md)
|
||||
|
||||
@@ -82,7 +83,6 @@ These individual tutorials expand on topics discussed in the guide above.
|
||||
* Electron Releases & Developer Feedback
|
||||
* [Versioning Policy](tutorial/electron-versioning.md)
|
||||
* [Release Timelines](tutorial/electron-timelines.md)
|
||||
* [Testing Widevine CDM](tutorial/testing-widevine-cdm.md)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -246,7 +246,8 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
* `trafficLightPosition` [Point](structures/point.md) (optional) _macOS_ -
|
||||
Set a custom position for the traffic light buttons in frameless windows.
|
||||
* `roundedCorners` boolean (optional) _macOS_ - Whether frameless window
|
||||
should have rounded corners on macOS. Default is `true`.
|
||||
should have rounded corners on macOS. Default is `true`. Setting this property
|
||||
to `false` will prevent the window from being fullscreenable.
|
||||
* `fullscreenWindowTitle` boolean (optional) _macOS_ _Deprecated_ - Shows
|
||||
the title in the title bar in full screen mode on macOS for `hiddenInset`
|
||||
titleBarStyle. Default is `false`.
|
||||
@@ -1323,7 +1324,7 @@ win.setSheetOffset(toolbarRect.height)
|
||||
|
||||
Starts or stops flashing the window to attract user's attention.
|
||||
|
||||
#### `win.setSkipTaskbar(skip)`
|
||||
#### `win.setSkipTaskbar(skip)` _macOS_ _Windows_
|
||||
|
||||
* `skip` boolean
|
||||
|
||||
|
||||
@@ -96,14 +96,6 @@ Algorithm][SCA], just like [`window.postMessage`][], so prototype chains will no
|
||||
included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will
|
||||
throw an exception.
|
||||
|
||||
> **NOTE:** Sending non-standard JavaScript types such as DOM objects or
|
||||
> special Electron objects will throw an exception.
|
||||
>
|
||||
> Since the main process does not have support for DOM objects such as
|
||||
> `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over
|
||||
> Electron's IPC to the main process, as the main process would have no way to decode
|
||||
> them. Attempting to send such objects over IPC will result in an error.
|
||||
|
||||
The main process should listen for `channel` with
|
||||
[`ipcMain.handle()`](./ipc-main.md#ipcmainhandlechannel-listener).
|
||||
|
||||
@@ -126,6 +118,21 @@ If you need to transfer a [`MessagePort`][] to the main process, use [`ipcRender
|
||||
|
||||
If you do not need a response to the message, consider using [`ipcRenderer.send`](#ipcrenderersendchannel-args).
|
||||
|
||||
> **Note**
|
||||
> Sending non-standard JavaScript types such as DOM objects or
|
||||
> special Electron objects will throw an exception.
|
||||
>
|
||||
> Since the main process does not have support for DOM objects such as
|
||||
> `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over
|
||||
> Electron's IPC to the main process, as the main process would have no way to decode
|
||||
> them. Attempting to send such objects over IPC will result in an error.
|
||||
|
||||
> **Note**
|
||||
> If the handler in the main process throws an error,
|
||||
> the promise returned by `invoke` will reject.
|
||||
> However, the `Error` object in the renderer process
|
||||
> will not be the same as the one thrown in the main process.
|
||||
|
||||
### `ipcRenderer.sendSync(channel, ...args)`
|
||||
|
||||
* `channel` string
|
||||
|
||||
@@ -10,11 +10,12 @@ An example of implementing a protocol that has the same effect as the
|
||||
```javascript
|
||||
const { app, protocol } = require('electron')
|
||||
const path = require('path')
|
||||
const url = require('url')
|
||||
|
||||
app.whenReady().then(() => {
|
||||
protocol.registerFileProtocol('atom', (request, callback) => {
|
||||
const url = request.url.substr(7)
|
||||
callback({ path: path.normalize(`${__dirname}/${url}`) })
|
||||
const filePath = url.fileURLToPath('file://' + request.url.slice('atom://'.length))
|
||||
callback(filePath)
|
||||
})
|
||||
})
|
||||
```
|
||||
@@ -175,7 +176,7 @@ property.
|
||||
* `handler` Function
|
||||
* `request` [ProtocolRequest](structures/protocol-request.md)
|
||||
* `callback` Function
|
||||
* `response` ProtocolResponse
|
||||
* `response` [ProtocolResponse](structures/protocol-response.md)
|
||||
|
||||
Returns `boolean` - Whether the protocol was successfully registered
|
||||
|
||||
|
||||
@@ -635,9 +635,10 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
|
||||
* `notifications` - Request notification creation and the ability to display them in the user's system tray.
|
||||
* `midi` - Request MIDI access in the `webmidi` API.
|
||||
* `midiSysex` - Request the use of system exclusive messages in the `webmidi` API.
|
||||
* `pointerLock` - Request to directly interpret mouse movements as an input method. Click [here](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API) to know more.
|
||||
* `pointerLock` - Request to directly interpret mouse movements as an input method. Click [here](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API) to know more. These requests always appear to originate from the main frame.
|
||||
* `fullscreen` - Request for the app to enter fullscreen mode.
|
||||
* `openExternal` - Request to open links in external applications.
|
||||
* `window-placement` - Request access to enumerate screens using the [`getScreenDetails`](https://developer.chrome.com/en/articles/multi-screen-window-placement/) API.
|
||||
* `unknown` - An unrecognized permission request
|
||||
* `callback` Function
|
||||
* `permissionGranted` boolean - Allow or deny the permission.
|
||||
@@ -1049,7 +1050,7 @@ is emitted.
|
||||
|
||||
#### `ses.getStoragePath()`
|
||||
|
||||
A `string | null` indicating the absolute file system path where data for this
|
||||
Returns `string | null` - The absolute file system path where data for this
|
||||
session is persisted on disk. For in memory sessions this returns `null`.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
@@ -25,15 +25,20 @@ app.whenReady().then(() => {
|
||||
})
|
||||
```
|
||||
|
||||
__Platform limitations:__
|
||||
__Platform Considerations__
|
||||
|
||||
If you want to keep exact same behaviors on all platforms, you should not
|
||||
rely on the `click` event; instead, always attach a context menu to the tray icon.
|
||||
|
||||
__Linux__
|
||||
|
||||
* On Linux the app indicator will be used if it is supported, otherwise
|
||||
`GtkStatusIcon` will be used instead.
|
||||
* On Linux distributions that only have app indicator support, you have to
|
||||
install `libappindicator1` to make the tray icon work.
|
||||
* The app indicator will be used if it is supported, otherwise
|
||||
`GtkStatusIcon` will be used instead.
|
||||
* App indicator will only be shown when it has a context menu.
|
||||
* When app indicator is used on Linux, the `click` event is ignored.
|
||||
* On Linux in order for changes made to individual `MenuItem`s to take effect,
|
||||
* The `click` event is ignored when using the app indicator.
|
||||
* In order for changes made to individual `MenuItem`s to take effect,
|
||||
you have to call `setContextMenu` again. For example:
|
||||
|
||||
```javascript
|
||||
@@ -55,10 +60,16 @@ app.whenReady().then(() => {
|
||||
})
|
||||
```
|
||||
|
||||
* On Windows it is recommended to use `ICO` icons to get best visual effects.
|
||||
__MacOS__
|
||||
|
||||
If you want to keep exact same behaviors on all platforms, you should not
|
||||
rely on the `click` event and always attach a context menu to the tray icon.
|
||||
* Icons passed to the Tray constructor should be [Template Images](native-image.md#template-image).
|
||||
* To make sure your icon isn't grainy on retina monitors, be sure your `@2x` image is 144dpi.
|
||||
* If you are bundling your application (e.g., with webpack for development), be sure that the file names are not being mangled or hashed. The filename needs to end in Template, and the `@2x` image needs to have the same filename as the standard image, or MacOS will not magically invert your image's colors or use the high density image.
|
||||
* 16x16 (72dpi) and 32x32@2x (144dpi) work well for most icons.
|
||||
|
||||
__Windows__
|
||||
|
||||
* It is recommended to use `ICO` icons to get best visual effects.
|
||||
|
||||
### `new Tray(image, [guid])`
|
||||
|
||||
|
||||
@@ -1635,6 +1635,8 @@ Opens the devtools.
|
||||
When `contents` is a `<webview>` tag, the `mode` would be `detach` by default,
|
||||
explicitly passing an empty `mode` can force using last used dock state.
|
||||
|
||||
On Windows, if Windows Control Overlay is enabled, Devtools will be opened with `mode: 'detach'`.
|
||||
|
||||
#### `contents.closeDevTools()`
|
||||
|
||||
Closes the devtools.
|
||||
|
||||
@@ -144,6 +144,16 @@ ipcRenderer.on('port', (e, msg) => {
|
||||
|
||||
A `string` representing the current URL of the frame.
|
||||
|
||||
#### `frame.origin` _Readonly_
|
||||
|
||||
A `string` representing the current origin of the frame, serialized according
|
||||
to [RFC 6454](https://www.rfc-editor.org/rfc/rfc6454). This may be different
|
||||
from the URL. For instance, if the frame is a child window opened to
|
||||
`about:blank`, then `frame.origin` will return the parent frame's origin, while
|
||||
`frame.url` will return the empty string. Pages without a scheme/host/port
|
||||
triple origin will have the serialized origin of `"null"` (that is, the string
|
||||
containing the letters n, u, l, l).
|
||||
|
||||
#### `frame.top` _Readonly_
|
||||
|
||||
A `WebFrameMain | null` representing top frame in the frame hierarchy to which `frame`
|
||||
|
||||
@@ -135,7 +135,7 @@ is only available in renderer processes.
|
||||
|
||||
If [sub-pixel anti-aliasing](https://alienryderflex.com/sub_pixel/) is deactivated, then fonts on LCD screens can look blurry. Example:
|
||||
|
||||
![subpixel rendering example]
|
||||

|
||||
|
||||
Sub-pixel anti-aliasing needs a non-transparent background of the layer containing the font glyphs. (See [this issue](https://github.com/electron/electron/issues/6344#issuecomment-420371918) for more info).
|
||||
|
||||
@@ -161,4 +161,3 @@ Notice that just setting the background in the CSS does not have the desired eff
|
||||
[indexed-db]: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API
|
||||
[message-port]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort
|
||||
[browser-window]: api/browser-window.md
|
||||
[subpixel rendering example]: images/subpixel-rendering-screenshot.gif
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
contextBridge.exposeInMainWorld('electron', {
|
||||
startDrag: (fileName) => {
|
||||
|
||||
@@ -33,12 +33,16 @@ function createWindow () {
|
||||
if (permission === 'serial' && details.securityOrigin === 'file:///') {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.setDevicePermissionHandler((details) => {
|
||||
if (details.deviceType === 'serial' && details.origin === 'file://') {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
@@ -11,8 +11,8 @@ can either use specialized tooling or manual approaches.
|
||||
## With tooling
|
||||
|
||||
There are a couple tools out there that exist to package and distribute your Electron app.
|
||||
We recommend using [Electron Forge](https://www.electronforge.io). You can check out
|
||||
its documentation directly, or refer to the [Packaging and Distribution](./tutorial-5-packaging.md)
|
||||
We recommend using [Electron Forge](./forge-overview.md). You can check out
|
||||
its [documentation](https://www.electronforge.io) directly, or refer to the [Packaging and Distribution](./tutorial-5-packaging.md)
|
||||
part of the Electron tutorial.
|
||||
|
||||
## Manual packaging
|
||||
|
||||
175
docs/tutorial/asar-archives.md
Normal file
175
docs/tutorial/asar-archives.md
Normal file
@@ -0,0 +1,175 @@
|
||||
---
|
||||
title: ASAR Archives
|
||||
description: What is ASAR archive and how does it affect the application.
|
||||
slug: asar-archives
|
||||
hide_title: false
|
||||
---
|
||||
|
||||
After creating an [application distribution](application-distribution.md), the
|
||||
app's source code are usually bundled into an [ASAR
|
||||
archive](https://github.com/electron/asar), which is a simple extensive archive
|
||||
format designed for Electron apps. By bundling the app we can mitigate issues
|
||||
around long path names on Windows, speed up `require` and conceal your source
|
||||
code from cursory inspection.
|
||||
|
||||
The bundled app runs in a virtual file system and most APIs would just work
|
||||
normally, but for some cases you might want to work on ASAR archives explicitly
|
||||
due to a few caveats.
|
||||
|
||||
## Using ASAR Archives
|
||||
|
||||
In Electron there are two sets of APIs: Node APIs provided by Node.js and Web
|
||||
APIs provided by Chromium. Both APIs support reading files from ASAR archives.
|
||||
|
||||
### Node API
|
||||
|
||||
With special patches in Electron, Node APIs like `fs.readFile` and `require`
|
||||
treat ASAR archives as virtual directories, and the files in it as normal
|
||||
files in the filesystem.
|
||||
|
||||
For example, suppose we have an `example.asar` archive under `/path/to`:
|
||||
|
||||
```sh
|
||||
$ asar list /path/to/example.asar
|
||||
/app.js
|
||||
/file.txt
|
||||
/dir/module.js
|
||||
/static/index.html
|
||||
/static/main.css
|
||||
/static/jquery.min.js
|
||||
```
|
||||
|
||||
Read a file in the ASAR archive:
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
fs.readFileSync('/path/to/example.asar/file.txt')
|
||||
```
|
||||
|
||||
List all files under the root of the archive:
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
fs.readdirSync('/path/to/example.asar')
|
||||
```
|
||||
|
||||
Use a module from the archive:
|
||||
|
||||
```javascript
|
||||
require('./path/to/example.asar/dir/module.js')
|
||||
```
|
||||
|
||||
You can also display a web page in an ASAR archive with `BrowserWindow`:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow()
|
||||
|
||||
win.loadURL('file:///path/to/example.asar/static/index.html')
|
||||
```
|
||||
|
||||
### Web API
|
||||
|
||||
In a web page, files in an archive can be requested with the `file:` protocol.
|
||||
Like the Node API, ASAR archives are treated as directories.
|
||||
|
||||
For example, to get a file with `$.get`:
|
||||
|
||||
```html
|
||||
<script>
|
||||
let $ = require('./jquery.min.js')
|
||||
$.get('file:///path/to/example.asar/file.txt', (data) => {
|
||||
console.log(data)
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
### Treating an ASAR archive as a Normal File
|
||||
|
||||
For some cases like verifying the ASAR archive's checksum, we need to read the
|
||||
content of an ASAR archive as a file. For this purpose you can use the built-in
|
||||
`original-fs` module which provides original `fs` APIs without `asar` support:
|
||||
|
||||
```javascript
|
||||
const originalFs = require('original-fs')
|
||||
originalFs.readFileSync('/path/to/example.asar')
|
||||
```
|
||||
|
||||
You can also set `process.noAsar` to `true` to disable the support for `asar` in
|
||||
the `fs` module:
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
process.noAsar = true
|
||||
fs.readFileSync('/path/to/example.asar')
|
||||
```
|
||||
|
||||
## Limitations of the Node API
|
||||
|
||||
Even though we tried hard to make ASAR archives in the Node API work like
|
||||
directories as much as possible, there are still limitations due to the
|
||||
low-level nature of the Node API.
|
||||
|
||||
### Archives Are Read-only
|
||||
|
||||
The archives can not be modified so all Node APIs that can modify files will not
|
||||
work with ASAR archives.
|
||||
|
||||
### Working Directory Can Not Be Set to Directories in Archive
|
||||
|
||||
Though ASAR archives are treated as directories, there are no actual
|
||||
directories in the filesystem, so you can never set the working directory to
|
||||
directories in ASAR archives. Passing them as the `cwd` option of some APIs
|
||||
will also cause errors.
|
||||
|
||||
### Extra Unpacking on Some APIs
|
||||
|
||||
Most `fs` APIs can read a file or get a file's information from ASAR archives
|
||||
without unpacking, but for some APIs that rely on passing the real file path to
|
||||
underlying system calls, Electron will extract the needed file into a
|
||||
temporary file and pass the path of the temporary file to the APIs to make them
|
||||
work. This adds a little overhead for those APIs.
|
||||
|
||||
APIs that requires extra unpacking are:
|
||||
|
||||
* `child_process.execFile`
|
||||
* `child_process.execFileSync`
|
||||
* `fs.open`
|
||||
* `fs.openSync`
|
||||
* `process.dlopen` - Used by `require` on native modules
|
||||
|
||||
### Fake Stat Information of `fs.stat`
|
||||
|
||||
The `Stats` object returned by `fs.stat` and its friends on files in `asar`
|
||||
archives is generated by guessing, because those files do not exist on the
|
||||
filesystem. So you should not trust the `Stats` object except for getting file
|
||||
size and checking file type.
|
||||
|
||||
### Executing Binaries Inside ASAR archive
|
||||
|
||||
There are Node APIs that can execute binaries like `child_process.exec`,
|
||||
`child_process.spawn` and `child_process.execFile`, but only `execFile` is
|
||||
supported to execute binaries inside ASAR archive.
|
||||
|
||||
This is because `exec` and `spawn` accept `command` instead of `file` as input,
|
||||
and `command`s are executed under shell. There is no reliable way to determine
|
||||
whether a command uses a file in asar archive, and even if we do, we can not be
|
||||
sure whether we can replace the path in command without side effects.
|
||||
|
||||
## Adding Unpacked Files to ASAR archives
|
||||
|
||||
As stated above, some Node APIs will unpack the file to the filesystem when
|
||||
called. Apart from the performance issues, various anti-virus scanners might
|
||||
be triggered by this behavior.
|
||||
|
||||
As a workaround, you can leave various files unpacked using the `--unpack` option.
|
||||
In the following example, shared libraries of native Node.js modules will not be
|
||||
packed:
|
||||
|
||||
```sh
|
||||
$ asar pack app app.asar --unpack *.node
|
||||
```
|
||||
|
||||
After running the command, you will notice that a folder named `app.asar.unpacked`
|
||||
was created together with the `app.asar` file. It contains the unpacked files
|
||||
and should be shipped together with the `app.asar` archive.
|
||||
53
docs/tutorial/asar-integrity.md
Normal file
53
docs/tutorial/asar-integrity.md
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
title: 'ASAR Integrity'
|
||||
description: 'An experimental feature that ensures the validity of ASAR contents at runtime.'
|
||||
slug: asar-integrity
|
||||
hide_title: false
|
||||
---
|
||||
|
||||
## Platform Support
|
||||
|
||||
Currently ASAR integrity checking is only supported on macOS.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Electron Forge / Electron Packager
|
||||
|
||||
If you are using `>= electron-packager@15.4.0` or `>= @electron-forge/core@6.0.0-beta.61` then all these requirements are met for you automatically and you can skip to [Toggling the Fuse](#toggling-the-fuse).
|
||||
|
||||
### Other build systems
|
||||
|
||||
In order to enable ASAR integrity checking you need to ensure that your `app.asar` file was generated by a version of the `asar` npm package that supports asar integrity. Support was introduced in version `3.1.0`.
|
||||
|
||||
Your must then populate a valid `ElectronAsarIntegrity` dictionary block in your packaged apps `Info.plist`. An example is included below.
|
||||
|
||||
```plist
|
||||
<key>ElectronAsarIntegrity</key>
|
||||
<dict>
|
||||
<key>Resources/app.asar</key>
|
||||
<dict>
|
||||
<key>algorithm</key>
|
||||
<string>SHA256</string>
|
||||
<key>hash</key>
|
||||
<string>9d1f61ea03c4bb62b4416387a521101b81151da0cfbe18c9f8c8b818c5cebfac</string>
|
||||
</dict>
|
||||
</dict>
|
||||
```
|
||||
|
||||
Valid `algorithm` values are currently `SHA256` only. The `hash` is a hash of the ASAR header using the given algorithm. The `asar` package exposes a `getRawHeader` method whose result can then be hashed to generate this value.
|
||||
|
||||
## Toggling the Fuse
|
||||
|
||||
ASAR integrity checking is currently disabled by default and can be enabled by toggling a fuse. See [Electron Fuses](fuses.md) for more information on what Electron Fuses are and how they work. When enabling this fuse you typically also want to enable the `onlyLoadAppFromAsar` fuse otherwise the validity checking can be bypassed via the Electron app code search path.
|
||||
|
||||
```js
|
||||
require('@electron/fuses').flipFuses(
|
||||
// E.g. /a/b/Foo.app
|
||||
pathToPackagedApp,
|
||||
{
|
||||
version: FuseVersion.V1,
|
||||
[FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
|
||||
[FuseV1Options.OnlyLoadAppFromAsar]: true
|
||||
}
|
||||
)
|
||||
```
|
||||
@@ -26,10 +26,8 @@ beginners, using a command line tool is likely to be helpful*.
|
||||
|
||||
## electron-forge
|
||||
|
||||
A "complete tool for building modern Electron applications". Electron Forge
|
||||
unifies the existing (and well maintained) build tools for Electron development
|
||||
into a cohesive package so that anyone can jump right in to Electron
|
||||
development.
|
||||
Electron Forge is a tool for packaging and publishing Electron applications. It unifies Electron's tooling ecosystem
|
||||
into a single extensible interface so that anyone can jump right into making Electron apps.
|
||||
|
||||
Forge comes with [a ready-to-use template](https://electronforge.io/templates) using Webpack as a bundler. It includes an example typescript configuration and provides two configuration files to enable easy customization. It uses the same core modules used by the
|
||||
greater Electron community (like [`electron-packager`](https://github.com/electron/electron-packager)) –
|
||||
|
||||
@@ -54,85 +54,11 @@ and notarized requires a few additions to your configuration. [Forge](https://el
|
||||
collection of the official Electron tools, using [`electron-packager`],
|
||||
[`electron-osx-sign`], and [`electron-notarize`] under the hood.
|
||||
|
||||
Let's take a look at an example `package.json` configuration with all required fields. Not all of them are
|
||||
required: the tools will be clever enough to automatically find a suitable `identity`, for instance,
|
||||
but we recommend that you are explicit.
|
||||
|
||||
```json title="package.json" {7}
|
||||
{
|
||||
"name": "my-app",
|
||||
"version": "0.0.1",
|
||||
"config": {
|
||||
"forge": {
|
||||
"packagerConfig": {
|
||||
"osxSign": {
|
||||
"identity": "Developer ID Application: Felix Rieseberg (LT94ZKYDCJ)",
|
||||
"hardened-runtime": true,
|
||||
"entitlements": "entitlements.plist",
|
||||
"entitlements-inherit": "entitlements.plist",
|
||||
"signature-flags": "library"
|
||||
},
|
||||
"osxNotarize": {
|
||||
"appleId": "felix@felix.fun",
|
||||
"appleIdPassword": "my-apple-id-password"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `entitlements.plist` file referenced here needs the following macOS-specific entitlements
|
||||
to assure the Apple security mechanisms that your app is doing these things
|
||||
without meaning any harm:
|
||||
|
||||
```xml title="entitlements.plist"
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.debugger</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
Note that up until Electron 12, the `com.apple.security.cs.allow-unsigned-executable-memory` entitlement was required
|
||||
as well. However, it should not be used anymore if it can be avoided.
|
||||
|
||||
To see all of this in action, check out Electron Fiddle's source code,
|
||||
[especially its `electron-forge` configuration
|
||||
file](https://github.com/electron/fiddle/blob/master/forge.config.js).
|
||||
|
||||
If you plan to access the microphone or camera within your app using Electron's APIs, you'll also
|
||||
need to add the following entitlements:
|
||||
|
||||
```xml title="entitlements.plist"
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.camera</key>
|
||||
<true/>
|
||||
```
|
||||
|
||||
If these are not present in your app's entitlements when you invoke, for example:
|
||||
|
||||
```js title="main.js"
|
||||
const { systemPreferences } = require('electron')
|
||||
const microphone = systemPreferences.askForMediaAccess('microphone')
|
||||
```
|
||||
|
||||
Your app may crash. See the Resource Access section in [Hardened Runtime](https://developer.apple.com/documentation/security/hardened_runtime) for more information and entitlements you may need.
|
||||
|
||||
### Using Electron Builder
|
||||
|
||||
Electron Builder comes with a custom solution for signing your application. You
|
||||
can find [its documentation here](https://www.electron.build/code-signing).
|
||||
Detailed instructions on how to configure your application can be found in the [Electron Forge Code Signing Tutorial](https://www.electronforge.io/guides/code-signing/code-signing-macos).
|
||||
|
||||
### Using Electron Packager
|
||||
|
||||
If you're not using an integrated build pipeline like Forge or Builder, you
|
||||
If you're not using an integrated build pipeline like Forge, you
|
||||
are likely using [`electron-packager`], which includes [`electron-osx-sign`] and
|
||||
[`electron-notarize`].
|
||||
|
||||
@@ -204,36 +130,7 @@ commit it to your source code.
|
||||
|
||||
### Using Electron Forge
|
||||
|
||||
Once you have a code signing certificate file (`.pfx`), you can sign
|
||||
[Squirrel.Windows][maker-squirrel] and [MSI][maker-msi] installers in Electron Forge
|
||||
with the `certificateFile` and `certificatePassword` fields in their respective
|
||||
configuration objects.
|
||||
|
||||
For example, if you keep your Forge config in your `package.json` file and are
|
||||
creating a Squirrel.Windows installer:
|
||||
|
||||
```json {9-15} title='package.json'
|
||||
{
|
||||
"name": "my-app",
|
||||
"version": "0.0.1",
|
||||
//...
|
||||
"config": {
|
||||
"forge": {
|
||||
"packagerConfig": {},
|
||||
"makers": [
|
||||
{
|
||||
"name": "@electron-forge/maker-squirrel",
|
||||
"config": {
|
||||
"certificateFile": "./cert.pfx",
|
||||
"certificatePassword": "this-is-a-secret"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
//...
|
||||
}
|
||||
```
|
||||
Electron Forge is the recommended way to sign your `Squirrel.Windows` and `WiX MSI` installers. Detailed instructions on how to configure your application can be found in the [Electron Forge Code Signing Tutorial](https://www.electronforge.io/guides/code-signing/code-signing-macos).
|
||||
|
||||
### Using electron-winstaller (Squirrel.Windows)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ you can deliver it to your users.
|
||||
## Packaging
|
||||
|
||||
To distribute your app with Electron, you need to package all your resources and assets
|
||||
into an executable and rebrand it. To do this, you can either use specialized tooling
|
||||
into an executable and rebrand it. To do this, you can either use specialized tooling like Electron Forge
|
||||
or do it manually. See the [Application Packaging][application-packaging] tutorial
|
||||
for more information.
|
||||
|
||||
|
||||
@@ -24,10 +24,11 @@ check out our [Electron Versioning](./electron-versioning.md) doc.
|
||||
| 14.0.0 | -- | 2021-May-27 | 2021-Aug-31 | M93 | v14.17 | 🚫 |
|
||||
| 15.0.0 | 2021-Jul-20 | 2021-Sep-01 | 2021-Sep-21 | M94 | v16.5 | 🚫 |
|
||||
| 16.0.0 | 2021-Sep-23 | 2021-Oct-20 | 2021-Nov-16 | M96 | v16.9 | 🚫 |
|
||||
| 17.0.0 | 2021-Nov-18 | 2022-Jan-06 | 2022-Feb-01 | M98 | v16.13 | ✅ |
|
||||
| 17.0.0 | 2021-Nov-18 | 2022-Jan-06 | 2022-Feb-01 | M98 | v16.13 | 🚫 |
|
||||
| 18.0.0 | 2022-Feb-03 | 2022-Mar-03 | 2022-Mar-29 | M100 | v16.13 | ✅ |
|
||||
| 19.0.0 | 2022-Mar-31 | 2022-Apr-26 | 2022-May-24 | M102 | v16.14 | ✅ |
|
||||
| 20.0.0 | 2022-May-26 | 2022-Jun-21 | 2022-Aug-02 | M104 | TBD | ✅ |
|
||||
| 20.0.0 | 2022-May-26 | 2022-Jun-21 | 2022-Aug-02 | M104 | v16.15 | ✅ |
|
||||
| 21.0.0 | 2022-Aug-04 | 2022-Aug-30 | 2022-Sep-27 | M106 | TBD | ✅ |
|
||||
|
||||
**Notes:**
|
||||
|
||||
|
||||
36
docs/tutorial/forge-overview.md
Normal file
36
docs/tutorial/forge-overview.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Distributing Apps With Electron Forge
|
||||
|
||||
Electron Forge is a tool for packaging and publishing Electron applications.
|
||||
It unifies Electron's build tooling ecosystem into
|
||||
a single extensible interface so that anyone can jump right into making Electron apps.
|
||||
|
||||
## Getting started
|
||||
|
||||
The [Electron Forge docs] contain detailed information on taking your application
|
||||
from source code to your end users' machines.
|
||||
This includes:
|
||||
|
||||
* Packaging your application [(package)]
|
||||
* Generating executables and installers for each OS [(make)], and,
|
||||
* Publishing these files to online platforms to download [(publish)].
|
||||
|
||||
For beginners, we recommend following through Electron's [tutorial] to develop, build,
|
||||
package and publish your first Electron app. If you have already developed an app on your machine
|
||||
and want to start on packaging and distribution, start from [step 5] of the tutorial.
|
||||
|
||||
## Getting help
|
||||
|
||||
* If you need help with developing your app, our [community Discord server][discord] is a great place
|
||||
to get advice from other Electron app developers.
|
||||
* If you suspect you're running into a bug with Forge, please check the [GitHub issue tracker]
|
||||
to see if any existing issues match your problem. If not, feel free to fill out our bug report
|
||||
template and submit a new issue.
|
||||
|
||||
[Electron Forge Docs]: https://www.electronforge.io/
|
||||
[step 5]: ./tutorial-5-packaging.md
|
||||
[(package)]: https://www.electronforge.io/cli#package
|
||||
[(make)]: https://www.electronforge.io/cli#make
|
||||
[(publish)]: https://www.electronforge.io/cli#publish
|
||||
[GitHub issue tracker]: https://github.com/electron-userland/electron-forge/issues
|
||||
[discord]: https://discord.gg/APGC3k5yaH
|
||||
[tutorial]: https://www.electronjs.org/docs/latest/tutorial/tutorial-prerequisites
|
||||
@@ -8,6 +8,59 @@ For a subset of Electron functionality it makes sense to disable certain feature
|
||||
|
||||
Fuses are the solution to this problem, at a high level they are "magic bits" in the Electron binary that can be flipped when packaging your Electron app to enable / disable certain features / restrictions. Because they are flipped at package time before you code sign your app the OS becomes responsible for ensuring those bits aren't flipped back via OS level code signing validation (Gatekeeper / App Locker).
|
||||
|
||||
## Current Fuses
|
||||
|
||||
### `runAsNode`
|
||||
|
||||
**Default:** Enabled
|
||||
**@electron/fuses:** `FuseV1Options.RunAsNode`
|
||||
|
||||
The runAsNode fuse toggles whether the `ELECTRON_RUN_AS_NODE` environment variable is respected or not. Please note that if this fuse is disabled then `process.fork` in the main process will not function as expected as it depends on this environment variable to function.
|
||||
|
||||
### `cookieEncryption`
|
||||
|
||||
**Default:** Disabled
|
||||
**@electron/fuses:** `FuseV1Options.EnableCookieEncryption`
|
||||
|
||||
The cookieEncryption fuse toggles whether the cookie store on disk is encrypted using OS level cryptography keys. By default the sqlite database that Chromium uses to store cookies stores the values in plaintext. If you wish to ensure your apps cookies are encrypted in the same way Chrome does then you should enable this fuse. Please note it is a one-way transition, if you enable this fuse existing unencrypted cookies will be encrypted-on-write but if you then disable the fuse again your cookie store will effectively be corrupt and useless. Most apps can safely enable this fuse.
|
||||
|
||||
### `nodeOptions`
|
||||
|
||||
**Default:** Enabled
|
||||
**@electron/fuses:** `FuseV1Options.EnableNodeOptionsEnvironmentVariable`
|
||||
|
||||
The nodeOptions fuse toggles whether the [`NODE_OPTIONS`](https://nodejs.org/api/cli.html#node_optionsoptions) environment variable is respected or not. This environment variable can be used to pass all kinds of custom options to the Node.js runtime and isn't typically used by apps in production. Most apps can safely disable this fuse.
|
||||
|
||||
### `nodeCliInspect`
|
||||
|
||||
**Default:** Enabled
|
||||
**@electron/fuses:** `FuseV1Options.EnableNodeCliInspectArguments`
|
||||
|
||||
The nodeCliInspect fuse toggles whether the `--inspect`, `--inspect-brk`, etc. flags are respected or not. When disabled it also ensures that `SIGUSR1` signal does not initialize the main process inspector. Most apps can safely disable this fuse.
|
||||
|
||||
### `embeddedAsarIntegrityValidation`
|
||||
|
||||
**Default:** Disabled
|
||||
**@electron/fuses:** `FuseV1Options.EnableEmbeddedAsarIntegrityValidation`
|
||||
|
||||
The embeddedAsarIntegrityValidation fuse toggles an experimental feature on macOS that validates the content of the `app.asar` file when it is loaded. This feature is designed to have a minimal performance impact but may marginally slow down file reads from inside the `app.asar` archive.
|
||||
|
||||
For more information on how to use asar integrity validation please read the [Asar Integrity](asar-integrity.md) documentation.
|
||||
|
||||
### `onlyLoadAppFromAsar`
|
||||
|
||||
**Default:** Disabled
|
||||
**@electron/fuses:** `FuseV1Options.OnlyLoadAppFromAsar`
|
||||
|
||||
The onlyLoadAppFromAsar fuse changes the search system that Electron uses to locate your app code. By default Electron will search in the following order `app.asar` -> `app` -> `default_app.asar`. When this fuse is enabled the search order becomes a single entry `app.asar` thus ensuring that when combined with the `embeddedAsarIntegrityValidation` fuse it is impossible to load non-validated code.
|
||||
|
||||
### `loadBrowserProcessSpecificV8Snapshot`
|
||||
|
||||
**Default:** Disabled
|
||||
**@electron/fuses:** `FuseV1Options.LoadBrowserProcessSpecificV8Snapshot`
|
||||
|
||||
The loadBrowserProcessSpecificV8Snapshot fuse changes which V8 snapshot file is used for the browser process. By default Electron's processes will all use the same V8 snapshot file. When this fuse is enabled the browser process uses the file called `browser_v8_context_snapshot.bin` for its V8 snapshot. The other processes will use the V8 snapshot file that they normally do.
|
||||
|
||||
## How do I flip the fuses?
|
||||
|
||||
### The easy way
|
||||
@@ -20,11 +73,18 @@ require('@electron/fuses').flipFuses(
|
||||
require('electron'),
|
||||
// Fuses to flip
|
||||
{
|
||||
runAsNode: false
|
||||
version: FuseVersion.V1,
|
||||
[FuseV1Options.RunAsNode]: false
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
You can validate the fuses have been flipped or check the fuse status of an arbitrary Electron app using the fuses CLI.
|
||||
|
||||
```bash
|
||||
npx @electron/fuses read --app /Applications/Foo.app
|
||||
```
|
||||
|
||||
### The hard way
|
||||
|
||||
#### Quick Glossary
|
||||
|
||||
@@ -44,14 +44,14 @@ are the different categories and what you can expect on each one:
|
||||
application.
|
||||
- **Processes in Electron**: In-depth reference on Electron processes and how to work with them.
|
||||
- **Best Practices**: Important checklists to keep in mind when developing an Electron app.
|
||||
- **How-To Examples**: Quick references to add features to your Electron app.
|
||||
- **Examples**: Quick references to add features to your Electron app.
|
||||
- **Development**: Miscellaneous development guides.
|
||||
- **Distribution**: Learn how to distribute your app to end users.
|
||||
- **Testing and debugging**: How to debug JavaScript, write tests, and other tools used
|
||||
- **Testing And Debugging**: How to debug JavaScript, write tests, and other tools used
|
||||
to create quality Electron applications.
|
||||
- **Resources**: Useful links to better understand how the Electron project works
|
||||
- **References**: Useful links to better understand how the Electron project works
|
||||
and is organized.
|
||||
- **Contributing to Electron**: Compiling Electron and making contributions can be daunting.
|
||||
- **Contributing**: Compiling Electron and making contributions can be daunting.
|
||||
We try to make it easier in this section.
|
||||
|
||||
## Getting help
|
||||
@@ -66,6 +66,7 @@ Are you getting stuck anywhere? Here are a few links to places to look:
|
||||
|
||||
<!-- Links -->
|
||||
|
||||
[tutorial]: tutorial-1-prerequisites.md
|
||||
[api documentation]: ../api/app.md
|
||||
[chromium]: https://www.chromium.org/
|
||||
[discord]: https://discord.com/invite/APGC3k5yaH
|
||||
|
||||
@@ -232,7 +232,7 @@ how to meet the Mac App Store requirements.
|
||||
|
||||
### Upload
|
||||
|
||||
The Application Loader should be used to upload the signed app to iTunes
|
||||
[Apple Transporter][apple-transporter] should be used to upload the signed app to App Store
|
||||
Connect for processing, making sure you have [created a record][create-record]
|
||||
before uploading.
|
||||
|
||||
@@ -345,7 +345,8 @@ Electron uses following cryptographic algorithms:
|
||||
[app-sandboxing]: https://developer.apple.com/app-sandboxing/
|
||||
[app-notarization]: https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution
|
||||
[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html
|
||||
[create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html
|
||||
[create-record]: https://help.apple.com/app-store-connect/#/dev2cd126805
|
||||
[apple-transporter]: https://help.apple.com/itc/transporteruserguide/en.lproj/static.html
|
||||
[submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html
|
||||
[export-compliance]: https://help.apple.com/app-store-connect/#/devc3f64248f
|
||||
[user-selected]: https://developer.apple.com/library/mac/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW6
|
||||
|
||||
@@ -8,8 +8,7 @@ your app.
|
||||
|
||||
Here is a very brief example of what a MessagePort is and how it works:
|
||||
|
||||
```js
|
||||
// renderer.js ///////////////////////////////////////////////////////////////
|
||||
```js title='renderer.js (Renderer Process)'
|
||||
// MessagePorts are created in pairs. A connected pair of message ports is
|
||||
// called a channel.
|
||||
const channel = new MessageChannel()
|
||||
@@ -28,8 +27,7 @@ port2.postMessage({ answer: 42 })
|
||||
ipcRenderer.postMessage('port', null, [port1])
|
||||
```
|
||||
|
||||
```js
|
||||
// main.js ///////////////////////////////////////////////////////////////////
|
||||
```js title='main.js (Main Process)'
|
||||
// In the main process, we receive the port.
|
||||
ipcMain.on('port', (event) => {
|
||||
// When we receive a MessagePort in the main process, it becomes a
|
||||
@@ -84,14 +82,84 @@ process, you can listen for the `close` event by calling `port.on('close',
|
||||
|
||||
## Example use cases
|
||||
|
||||
### Setting up a MessageChannel between two renderers
|
||||
|
||||
In this example, the main process sets up a MessageChannel, then sends each port
|
||||
to a different renderer. This allows renderers to send messages to each other
|
||||
without needing to use the main process as an in-between.
|
||||
|
||||
```js title='main.js (Main Process)'
|
||||
const { BrowserWindow, app, MessageChannelMain } = require('electron')
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
// create the windows.
|
||||
const mainWindow = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
preload: 'preloadMain.js'
|
||||
}
|
||||
})
|
||||
|
||||
const secondaryWindow = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
preload: 'preloadSecondary.js'
|
||||
}
|
||||
})
|
||||
|
||||
// set up the channel.
|
||||
const { port1, port2 } = new MessageChannelMain()
|
||||
|
||||
// once the webContents are ready, send a port to each webContents with postMessage.
|
||||
mainWindow.once('ready-to-show', () => {
|
||||
mainWindow.webContents.postMessage('port', null, [port1])
|
||||
})
|
||||
|
||||
secondaryWindow.once('ready-to-show', () => {
|
||||
secondaryWindow.webContents.postMessage('port', null, [port2])
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
Then, in your preload scripts you receive the port through IPC and set up the
|
||||
listeners.
|
||||
|
||||
```js title='preloadMain.js and preloadSecondary.js (Preload scripts)'
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
ipcRenderer.on('port', e => {
|
||||
// port received, make it globally available.
|
||||
window.electronMessagePort = e.ports[0]
|
||||
|
||||
window.electronMessagePort.onmessage = messageEvent => {
|
||||
// handle message
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
In this example messagePort is bound to the `window` object directly. It is better
|
||||
to use `contextIsolation` and set up specific contextBridge calls for each of your
|
||||
expected messages, but for the simplicity of this example we don't. You can find an
|
||||
example of context isolation further down this page at [Communicating directly between the main process and the main world of a context-isolated page](#communicating-directly-between-the-main-process-and-the-main-world-of-a-context-isolated-page)
|
||||
|
||||
That means window.electronMessagePort is globally available and you can call
|
||||
`postMessage` on it from anywhere in your app to send a message to the other
|
||||
renderer.
|
||||
|
||||
```js title='renderer.js (Renderer Process)'
|
||||
// elsewhere in your code to send a message to the other renderers message handler
|
||||
window.electronMessagePort.postmessage('ping')
|
||||
```
|
||||
|
||||
### Worker process
|
||||
|
||||
In this example, your app has a worker process implemented as a hidden window.
|
||||
You want the app page to be able to communicate directly with the worker
|
||||
process, without the performance overhead of relaying via the main process.
|
||||
|
||||
```js
|
||||
// main.js ///////////////////////////////////////////////////////////////////
|
||||
```js title='main.js (Main Process)'
|
||||
const { BrowserWindow, app, ipcMain, MessageChannelMain } = require('electron')
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
@@ -129,8 +197,7 @@ app.whenReady().then(async () => {
|
||||
})
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- worker.html ------------------------------------------------------------>
|
||||
```html title='worker.html'
|
||||
<script>
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
@@ -153,8 +220,7 @@ ipcRenderer.on('new-client', (event) => {
|
||||
</script>
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- app.html --------------------------------------------------------------->
|
||||
```html title='app.html'
|
||||
<script>
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
@@ -182,9 +248,7 @@ Electron's built-in IPC methods only support two modes: fire-and-forget
|
||||
can implement a "response stream", where a single request responds with a
|
||||
stream of data.
|
||||
|
||||
```js
|
||||
// renderer.js ///////////////////////////////////////////////////////////////
|
||||
|
||||
```js title='renderer.js (Renderer Process)'
|
||||
const makeStreamingRequest = (element, callback) => {
|
||||
// MessageChannels are lightweight--it's cheap to create a new one for each
|
||||
// request.
|
||||
@@ -208,14 +272,12 @@ const makeStreamingRequest = (element, callback) => {
|
||||
}
|
||||
|
||||
makeStreamingRequest(42, (data) => {
|
||||
console.log('got response data:', event.data)
|
||||
console.log('got response data:', data)
|
||||
})
|
||||
// We will see "got response data: 42" 10 times.
|
||||
```
|
||||
|
||||
```js
|
||||
// main.js ///////////////////////////////////////////////////////////////////
|
||||
|
||||
```js title='main.js (Main Process)'
|
||||
ipcMain.on('give-me-a-stream', (event, msg) => {
|
||||
// The renderer has sent us a MessagePort that it wants us to send our
|
||||
// response over.
|
||||
@@ -242,8 +304,7 @@ the renderer are delivered to the isolated world, rather than to the main
|
||||
world. Sometimes you want to deliver messages to the main world directly,
|
||||
without having to step through the isolated world.
|
||||
|
||||
```js
|
||||
// main.js ///////////////////////////////////////////////////////////////////
|
||||
```js title='main.js (Main Process)'
|
||||
const { BrowserWindow, app, MessageChannelMain } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
@@ -278,8 +339,7 @@ app.whenReady().then(async () => {
|
||||
})
|
||||
```
|
||||
|
||||
```js
|
||||
// preload.js ////////////////////////////////////////////////////////////////
|
||||
```js title='preload.js (Preload Script)'
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
// We need to wait until the main world is ready to receive the message before
|
||||
@@ -297,8 +357,7 @@ ipcRenderer.on('main-world-port', async (event) => {
|
||||
})
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- index.html ------------------------------------------------------------->
|
||||
```html title='index.html'
|
||||
<script>
|
||||
window.onmessage = (event) => {
|
||||
// event.source === window means the message is coming from the preload
|
||||
|
||||
@@ -22,7 +22,6 @@ In `preload.js` use the [`contextBridge`] to inject a method `window.electron.st
|
||||
|
||||
```js
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
contextBridge.exposeInMainWorld('electron', {
|
||||
startDrag: (fileName) => {
|
||||
|
||||
@@ -12,28 +12,10 @@ the GPU service and the network service.
|
||||
|
||||
See Chromium's [Sandbox design document][sandbox] for more information.
|
||||
|
||||
## Electron's sandboxing policies
|
||||
|
||||
Electron comes with a mixed sandbox environment, meaning sandboxed processes can run
|
||||
alongside privileged ones. By default, renderer processes are not sandboxed, but
|
||||
utility processes are. Note that as in Chromium, the main (browser) process is
|
||||
privileged and cannot be sandboxed.
|
||||
|
||||
Historically, this mixed sandbox approach was established because having Node.js available
|
||||
in the renderer is an extremely powerful tool for app developers. Unfortunately, this
|
||||
feature is also an equally massive security vulnerability.
|
||||
|
||||
Theoretically, unsandboxed renderers are not a problem for desktop applications that
|
||||
only display trusted code, but they make Electron less secure than Chromium for
|
||||
displaying untrusted web content. However, even purportedly trusted code may be
|
||||
dangerous — there are countless attack vectors that malicious actors can use, from
|
||||
cross-site scripting to content injection to man-in-the-middle attacks on remotely loaded
|
||||
websites, just to name a few. For this reason, we recommend enabling renderer sandboxing
|
||||
for the vast majority of cases under an abundance of caution.
|
||||
|
||||
<!--TODO: update this guide when #28466 is either solved or closed -->
|
||||
Note that there is an active discussion in the issue tracker to enable renderer sandboxing
|
||||
by default. See [#28466][issue-28466]) for details.
|
||||
Starting from Electron 20, the sandbox is enabled for renderer processes without any
|
||||
further configuration. If you want to disable the sandbox for a process, see the
|
||||
[Disabling the sandbox for a single process](#disabling-the-sandbox-for-a-single-process)
|
||||
section.
|
||||
|
||||
## Sandbox behaviour in Electron
|
||||
|
||||
@@ -46,12 +28,17 @@ When renderer processes in Electron are sandboxed, they behave in the same way a
|
||||
regular Chrome renderer would. A sandboxed renderer won't have a Node.js
|
||||
environment initialized.
|
||||
|
||||
<!-- TODO(erickzhao): when we have a solid guide for IPC, link it here -->
|
||||
Therefore, when the sandbox is enabled, renderer processes can only perform privileged
|
||||
tasks (such as interacting with the filesystem, making changes to the system, or spawning
|
||||
subprocesses) by delegating these tasks to the main process via inter-process
|
||||
communication (IPC).
|
||||
|
||||
:::note
|
||||
|
||||
For more info on inter-process communication, check out our [IPC guide](./ipc.md).
|
||||
|
||||
:::
|
||||
|
||||
### Preload scripts
|
||||
|
||||
In order to allow renderer processes to communicate with the main process, preload
|
||||
@@ -66,7 +53,7 @@ but can only import a subset of Electron and Node's built-in modules:
|
||||
|
||||
In addition, the preload script also polyfills certain Node.js primitives as globals:
|
||||
|
||||
* [`Buffer`](https://nodejs.org/api/Buffer.html)
|
||||
* [`Buffer`](https://nodejs.org/api/buffer.html)
|
||||
* [`process`](../api/process.md)
|
||||
* [`clearImmediate`](https://nodejs.org/api/timers.html#timers_clearimmediate_immediate)
|
||||
* [`setImmediate`](https://nodejs.org/api/timers.html#timers_setimmediate_callback_args)
|
||||
@@ -83,13 +70,17 @@ privileged APIs to untrusted code running in the renderer process unless
|
||||
|
||||
## Configuring the sandbox
|
||||
|
||||
### Enabling the sandbox for a single process
|
||||
For most apps, sandboxing is the best choice. In certain use cases that are incompatible with
|
||||
the sandbox (for instance, when using native node modules in the renderer),
|
||||
it is possible to disable the sandbox for specific processes. This comes with security
|
||||
risks, especially if any untrusted code or content is present in the unsandboxed process.
|
||||
|
||||
In Electron, renderer sandboxing can be enabled on a per-process basis with
|
||||
the `sandbox: true` preference in the [`BrowserWindow`][browser-window] constructor.
|
||||
### Disabling the sandbox for a single process
|
||||
|
||||
```js
|
||||
// main.js
|
||||
In Electron, renderer sandboxing can be disabled on a per-process basis with
|
||||
the `sandbox: false` preference in the [`BrowserWindow`][browser-window] constructor.
|
||||
|
||||
```js title='main.js'
|
||||
app.whenReady().then(() => {
|
||||
const win = new BrowserWindow({
|
||||
webPreferences: {
|
||||
@@ -100,17 +91,30 @@ app.whenReady().then(() => {
|
||||
})
|
||||
```
|
||||
|
||||
Sandboxing is also disabled whenever Node.js integration is enabled in the renderer.
|
||||
This can be done through the BrowserWindow constructor with the `nodeIntegration: true` flag.
|
||||
|
||||
```js title='main.js'
|
||||
app.whenReady().then(() => {
|
||||
const win = new BrowserWindow({
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
win.loadURL('https://google.com')
|
||||
})
|
||||
```
|
||||
|
||||
### Enabling the sandbox globally
|
||||
|
||||
If you want to force sandboxing for all renderers, you can also use the
|
||||
[`app.enableSandbox`][enable-sandbox] API. Note that this API has to be called before the
|
||||
app's `ready` event.
|
||||
|
||||
```js
|
||||
// main.js
|
||||
```js title='main.js'
|
||||
app.enableSandbox()
|
||||
app.whenReady().then(() => {
|
||||
// no need to pass `sandbox: true` since `app.enableSandbox()` was called.
|
||||
// any sandbox:false calls are overridden since `app.enableSandbox()` was called.
|
||||
const win = new BrowserWindow()
|
||||
win.loadURL('https://google.com')
|
||||
})
|
||||
@@ -139,16 +143,16 @@ issues:
|
||||
have, to inherit everything we can from Chromium, and to respond quickly to
|
||||
security issues, but Electron cannot be as secure as Chromium without the
|
||||
resources that Chromium is able to dedicate.
|
||||
2. Some security features in Chrome (such as Safe Browsing and Certificate
|
||||
1. Some security features in Chrome (such as Safe Browsing and Certificate
|
||||
Transparency) require a centralized authority and dedicated servers, both of
|
||||
which run counter to the goals of the Electron project. As such, we disable
|
||||
those features in Electron, at the cost of the associated security they
|
||||
would otherwise bring.
|
||||
3. There is only one Chromium, whereas there are many thousands of apps built
|
||||
1. There is only one Chromium, whereas there are many thousands of apps built
|
||||
on Electron, all of which behave slightly differently. Accounting for those
|
||||
differences can yield a huge possibility space, and make it challenging to
|
||||
ensure the security of the platform in unusual use cases.
|
||||
4. We can't push security updates to users directly, so we rely on app vendors
|
||||
1. We can't push security updates to users directly, so we rely on app vendors
|
||||
to upgrade the version of Electron underlying their app in order for
|
||||
security updates to reach users.
|
||||
|
||||
|
||||
@@ -256,7 +256,7 @@ the sandbox in all renderers. Loading, reading or processing any untrusted
|
||||
content in an unsandboxed process, including the main process, is not advised.
|
||||
|
||||
:::info
|
||||
For more information on what `contextIsolation` is and how to enable it please
|
||||
For more information on what Process Sandboxing is and how to enable it please
|
||||
see our dedicated [Process Sandboxing](sandbox.md) document.
|
||||
:::info
|
||||
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
# Testing Widevine CDM
|
||||
|
||||
In Electron you can use the Widevine CDM library shipped with Chrome browser.
|
||||
|
||||
Widevine Content Decryption Modules (CDMs) are how streaming services protect
|
||||
content using HTML5 video to web browsers without relying on an NPAPI plugin
|
||||
like Flash or Silverlight. Widevine support is an alternative solution for
|
||||
streaming services that currently rely on Silverlight for playback of
|
||||
DRM-protected video content. It will allow websites to show DRM-protected video
|
||||
content in Firefox without the use of NPAPI plugins. The Widevine CDM runs in an
|
||||
open-source CDM sandbox providing better user security than NPAPI plugins.
|
||||
|
||||
#### Note on VMP
|
||||
|
||||
As of [`Electron v1.8.0 (Chrome v59)`](https://electronjs.org/releases#1.8.1),
|
||||
the below steps are may only be some of the necessary steps to enable Widevine;
|
||||
any app on or after that version intending to use the Widevine CDM may need to
|
||||
be signed using a license obtained from [Widevine](https://www.widevine.com/)
|
||||
itself.
|
||||
|
||||
Per [Widevine](https://www.widevine.com/):
|
||||
|
||||
> Chrome 59 (and later) includes support for Verified Media Path (VMP). VMP
|
||||
> provides a method to verify the authenticity of a device platform. For browser
|
||||
> deployments, this will provide an additional signal to determine if a
|
||||
> browser-based implementation is reliable and secure.
|
||||
>
|
||||
> The proxy integration guide has been updated with information about VMP and
|
||||
> how to issue licenses.
|
||||
>
|
||||
> Widevine recommends our browser-based integrations (vendors and browser-based
|
||||
> applications) add support for VMP.
|
||||
|
||||
To enable video playback with this new restriction,
|
||||
[castLabs](https://castlabs.com/open-source/downstream/) has created a
|
||||
[fork](https://github.com/castlabs/electron-releases) that has implemented the
|
||||
necessary changes to enable Widevine to be played in an Electron application if
|
||||
one has obtained the necessary licenses from widevine.
|
||||
|
||||
## Getting the library
|
||||
|
||||
Open `chrome://components/` in Chrome browser, find `Widevine Content Decryption Module`
|
||||
and make sure it is up to date, then you can find the library files from the
|
||||
application directory.
|
||||
|
||||
### On Windows
|
||||
|
||||
The library file `widevinecdm.dll` will be under
|
||||
`Program Files(x86)/Google/Chrome/Application/CHROME_VERSION/WidevineCdm/_platform_specific/win_(x86|x64)/`
|
||||
directory.
|
||||
|
||||
### On macOS
|
||||
|
||||
The library file `libwidevinecdm.dylib` will be under
|
||||
`/Applications/Google Chrome.app/Contents/Versions/CHROME_VERSION/Google Chrome Framework.framework/Versions/A/Libraries/WidevineCdm/_platform_specific/mac_(x86|x64)/`
|
||||
directory.
|
||||
|
||||
**Note:** Make sure that chrome version used by Electron is greater than or
|
||||
equal to the `min_chrome_version` value of Chrome's widevine cdm component.
|
||||
The value can be found in `manifest.json` under `WidevineCdm` directory.
|
||||
|
||||
## Using the library
|
||||
|
||||
After getting the library files, you should pass the path to the file
|
||||
with `--widevine-cdm-path` command line switch, and the library's version
|
||||
with `--widevine-cdm-version` switch. The command line switches have to be
|
||||
passed before the `ready` event of `app` module gets emitted.
|
||||
|
||||
Example code:
|
||||
|
||||
```javascript
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
// You have to pass the directory that contains widevine library here, it is
|
||||
// * `libwidevinecdm.dylib` on macOS,
|
||||
// * `widevinecdm.dll` on Windows.
|
||||
app.commandLine.appendSwitch('widevine-cdm-path', '/path/to/widevine_library')
|
||||
// The version of plugin can be got from `chrome://components` page in Chrome.
|
||||
app.commandLine.appendSwitch('widevine-cdm-version', '1.4.8.866')
|
||||
|
||||
let win = null
|
||||
app.whenReady().then(() => {
|
||||
win = new BrowserWindow()
|
||||
win.show()
|
||||
})
|
||||
```
|
||||
|
||||
## Verifying Widevine CDM support
|
||||
|
||||
To verify whether widevine works, you can use following ways:
|
||||
|
||||
* Open https://shaka-player-demo.appspot.com/ and load a manifest that uses
|
||||
`Widevine`.
|
||||
* Open http://www.dash-player.com/demo/drm-test-area/, check whether the page
|
||||
says `bitdash uses Widevine in your browser`, then play the video.
|
||||
@@ -123,7 +123,7 @@ the list of versions in the [electron/releases] repository.
|
||||
[homebrew]: https://brew.sh/
|
||||
[mdn-guide]: https://developer.mozilla.org/en-US/docs/Learn/
|
||||
[node]: https://nodejs.org/
|
||||
[node-guide]: https://nodejs.dev/learn
|
||||
[node-guide]: https://nodejs.dev/en/learn/
|
||||
[node-download]: https://nodejs.org/en/download/
|
||||
[nvm]: https://github.com/nvm-sh/nvm
|
||||
[process-model]: ./process-model.md
|
||||
|
||||
@@ -350,7 +350,7 @@ app.whenReady().then(() => {
|
||||
|
||||
## Optional: Debugging from VS Code
|
||||
|
||||
If you want to debug your application using VS Code, you have need attach VS Code to
|
||||
If you want to debug your application using VS Code, you need to attach VS Code to
|
||||
both the main and renderer processes. Here is a sample configuration for you to
|
||||
run. Create a launch.json configuration in a new `.vscode` folder in your project:
|
||||
|
||||
@@ -369,12 +369,12 @@ run. Create a launch.json configuration in a new `.vscode` folder in your projec
|
||||
"name": "Renderer",
|
||||
"port": 9222,
|
||||
"request": "attach",
|
||||
"type": "pwa-chrome",
|
||||
"type": "chrome",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"name": "Main",
|
||||
"type": "pwa-node",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
|
||||
@@ -398,11 +398,11 @@ What we have done in the `launch.json` file is to create 3 configurations:
|
||||
- `Main` is used to start the main process and also expose port 9222 for remote debugging
|
||||
(`--remote-debugging-port=9222`). This is the port that we will use to attach the debugger
|
||||
for the `Renderer`. Because the main process is a Node.js process, the type is set to
|
||||
`pwa-node` (`pwa-` is the prefix that tells VS Code to use the latest JavaScript debugger).
|
||||
`node`.
|
||||
- `Renderer` is used to debug the renderer process. Because the main process is the one
|
||||
that creates the process, we have to "attach" to it (`"request": "attach"`) instead of
|
||||
creating a new one.
|
||||
The renderer process is a web one, so the debugger we have to use is `pwa-chrome`.
|
||||
The renderer process is a web one, so the debugger we have to use is `chrome`.
|
||||
- `Main + renderer` is a [compound task] that executes the previous ones simultaneously.
|
||||
|
||||
:::caution
|
||||
|
||||
@@ -38,7 +38,25 @@ called a **preload**.
|
||||
## Augmenting the renderer with a preload script
|
||||
|
||||
A BrowserWindow's preload script runs in a context that has access to both the HTML DOM
|
||||
and a Node.js environment. Preload scripts are injected before a web page loads in the renderer,
|
||||
and a limited subset of Node.js and Electron APIs.
|
||||
|
||||
:::info Preload script sandboxing
|
||||
|
||||
From Electron 20 onwards, preload scripts are **sandboxed** by default and no longer have access
|
||||
to a full Node.js environment. Practically, this means that you have a polyfilled `require`
|
||||
function that only has access to a limited set of APIs.
|
||||
|
||||
| Available API | Details |
|
||||
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Electron modules | Renderer process modules |
|
||||
| Node.js modules | [`events`](https://nodejs.org/api/events.html), [`timers`](https://nodejs.org/api/timers.html), [`url`](https://nodejs.org/api/url.html) |
|
||||
| Polyfilled globals | [`Buffer`](https://nodejs.org/api/buffer.html), [`process`](../api/process.md), [`clearImmediate`](https://nodejs.org/api/timers.html#timers_clearimmediate_immediate), [`setImmediate`](https://nodejs.org/api/timers.html#timers_setimmediate_callback_args) |
|
||||
|
||||
For more information, check out the [Process Sandboxing](./sandbox.md) guide.
|
||||
|
||||
:::
|
||||
|
||||
Preload scripts are injected before a web page loads in the renderer,
|
||||
similar to a Chrome extension's [content scripts][content-script]. To add features to your renderer
|
||||
that require privileged access, you can define [global] objects through the
|
||||
[contextBridge][contextbridge] API.
|
||||
|
||||
@@ -64,7 +64,7 @@ into end users' hands.
|
||||
|
||||
[discord]: https://discord.com/invite/APGC3k5yaH
|
||||
[github]: https://github.com/electron/electronjs.org-new/issues/new
|
||||
[how to]: ./examples.md
|
||||
[how-to]: ./examples.md
|
||||
[node-platform]: https://nodejs.org/api/process.html#process_process_platform
|
||||
|
||||
<!-- Tutorial links -->
|
||||
|
||||
@@ -111,6 +111,12 @@ Electron Forge can be configured to create distributables in different OS-specif
|
||||
|
||||
:::
|
||||
|
||||
:::tip Creating and Adding Application Icons
|
||||
|
||||
Setting custom application icons requires a few additions to your config. Check out [Forge's icon tutorial] for more information.
|
||||
|
||||
:::
|
||||
|
||||
:::note Packaging without Electron Forge
|
||||
|
||||
If you want to manually package your code, or if you're just interested understanding the
|
||||
@@ -214,6 +220,7 @@ information.
|
||||
[electron forge]: https://www.electronforge.io
|
||||
[electron forge cli documentation]: https://www.electronforge.io/cli#commands
|
||||
[makers]: https://www.electronforge.io/config/makers
|
||||
[Forge's icon tutorial]: https://www.electronforge.io/guides/create-and-add-icons
|
||||
|
||||
<!-- Tutorial links -->
|
||||
|
||||
|
||||
@@ -672,8 +672,6 @@ filenames = {
|
||||
"shell/renderer/electron_render_frame_observer.h",
|
||||
"shell/renderer/electron_renderer_client.cc",
|
||||
"shell/renderer/electron_renderer_client.h",
|
||||
"shell/renderer/electron_renderer_pepper_host_factory.cc",
|
||||
"shell/renderer/electron_renderer_pepper_host_factory.h",
|
||||
"shell/renderer/electron_sandboxed_renderer_client.cc",
|
||||
"shell/renderer/electron_sandboxed_renderer_client.h",
|
||||
"shell/renderer/guest_view_container.cc",
|
||||
|
||||
@@ -18,4 +18,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,9 +72,8 @@ BrowserWindow.getAllWindows = () => {
|
||||
|
||||
BrowserWindow.getFocusedWindow = () => {
|
||||
for (const window of BrowserWindow.getAllWindows()) {
|
||||
const hasWC = window.webContents && !window.webContents.isDestroyed();
|
||||
if (!window.isDestroyed() && hasWC) {
|
||||
if (window.isFocused() || window.isDevToolsFocused()) return window;
|
||||
if (!window.isDestroyed() && window.webContents && !window.webContents.isDestroyed()) {
|
||||
if (window.isFocused() || window.webContents.isDevToolsFocused()) return window;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -475,12 +475,14 @@ WebContents.prototype.loadURL = function (url, options) {
|
||||
const removeListeners = () => {
|
||||
this.removeListener('did-finish-load', finishListener);
|
||||
this.removeListener('did-fail-load', failListener);
|
||||
this.removeListener('did-navigate-in-page', finishListener);
|
||||
this.removeListener('did-start-navigation', navigationListener);
|
||||
this.removeListener('did-stop-loading', stopLoadingListener);
|
||||
this.removeListener('destroyed', stopLoadingListener);
|
||||
};
|
||||
this.on('did-finish-load', finishListener);
|
||||
this.on('did-fail-load', failListener);
|
||||
this.on('did-navigate-in-page', finishListener);
|
||||
this.on('did-start-navigation', navigationListener);
|
||||
this.on('did-stop-loading', stopLoadingListener);
|
||||
this.on('destroyed', stopLoadingListener);
|
||||
|
||||
23
lib/common/.eslintrc.json
Normal file
23
lib/common/.eslintrc.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"paths": [
|
||||
"electron",
|
||||
"electron/main",
|
||||
"electron/renderer"
|
||||
],
|
||||
"patterns": [
|
||||
"./*",
|
||||
"../*",
|
||||
"@electron/internal/browser/*",
|
||||
"@electron/internal/isolated_renderer/*",
|
||||
"@electron/internal/renderer/*",
|
||||
"@electron/internal/sandboxed_worker/*",
|
||||
"@electron/internal/worker/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import type * as ipcRendererUtilsModule from '@electron/internal/renderer/ipc-renderer-internal-utils';
|
||||
|
||||
const clipboard = process._linkedBinding('electron_common_clipboard');
|
||||
|
||||
18
lib/isolated_renderer/.eslintrc.json
Normal file
18
lib/isolated_renderer/.eslintrc.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"paths": [
|
||||
"electron",
|
||||
"electron/main"
|
||||
],
|
||||
"patterns": [
|
||||
"./*",
|
||||
"../*",
|
||||
"@electron/internal/browser/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
18
lib/renderer/.eslintrc.json
Normal file
18
lib/renderer/.eslintrc.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"paths": [
|
||||
"electron",
|
||||
"electron/main"
|
||||
],
|
||||
"patterns": [
|
||||
"./*",
|
||||
"../*",
|
||||
"@electron/internal/browser/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { ipcRenderer } from 'electron/renderer';
|
||||
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
|
||||
|
||||
import type * as webViewInitModule from '@electron/internal/renderer/web-view/web-view-init';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { internalContextBridge } from '@electron/internal/renderer/api/context-b
|
||||
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
|
||||
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils';
|
||||
import { webFrame } from 'electron/renderer';
|
||||
import { IPC_MESSAGES } from '../common/ipc-messages';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
const { contextIsolationEnabled } = internalContextBridge;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { webFrame, WebFrame } from 'electron';
|
||||
import { webFrame, WebFrame } from 'electron/renderer';
|
||||
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
|
||||
@@ -186,7 +186,10 @@ export class SrcAttribute extends WebViewAttribute {
|
||||
opts.userAgent = useragent;
|
||||
}
|
||||
|
||||
(this.webViewImpl.webviewNode as Electron.WebviewTag).loadURL(this.getValue(), opts);
|
||||
(this.webViewImpl.webviewNode as Electron.WebviewTag).loadURL(this.getValue(), opts)
|
||||
.catch(err => {
|
||||
console.error('Unexpected error while loading URL', err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
18
lib/sandboxed_renderer/.eslintrc.json
Normal file
18
lib/sandboxed_renderer/.eslintrc.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"paths": [
|
||||
"electron",
|
||||
"electron/main"
|
||||
],
|
||||
"patterns": [
|
||||
"./*",
|
||||
"../*",
|
||||
"@electron/internal/browser/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
18
lib/worker/.eslintrc.json
Normal file
18
lib/worker/.eslintrc.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"paths": [
|
||||
"electron",
|
||||
"electron/main"
|
||||
],
|
||||
"patterns": [
|
||||
"./*",
|
||||
"../*",
|
||||
"@electron/internal/browser/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -70,8 +70,22 @@ function isInstalled () {
|
||||
|
||||
// unzips and makes path.txt point at the correct executable
|
||||
function extractFile (zipPath) {
|
||||
return extract(zipPath, { dir: path.join(__dirname, 'dist') })
|
||||
.then(() => fs.promises.writeFile(path.join(__dirname, 'path.txt'), platformPath));
|
||||
const distPath = process.env.ELECTRON_OVERRIDE_DIST_PATH || path.join(__dirname, 'dist');
|
||||
|
||||
return extract(zipPath, { dir: path.join(__dirname, 'dist') }).then(() => {
|
||||
// If the zip contains an "electron.d.ts" file,
|
||||
// move that up
|
||||
const srcTypeDefPath = path.join(distPath, 'electron.d.ts');
|
||||
const targetTypeDefPath = path.join(__dirname, 'electron.d.ts');
|
||||
const hasTypeDefinitions = fs.existsSync(srcTypeDefPath);
|
||||
|
||||
if (hasTypeDefinitions) {
|
||||
fs.renameSync(srcTypeDefPath, targetTypeDefPath);
|
||||
}
|
||||
|
||||
// Write a "path.txt" file.
|
||||
return fs.promises.writeFile(path.join(__dirname, 'path.txt'), platformPath);
|
||||
});
|
||||
}
|
||||
|
||||
function getPlatformPath () {
|
||||
|
||||
12
package.json
12
package.json
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "20.0.0-beta.12",
|
||||
"version": "0.0.0-development",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
"@azure/storage-blob": "^12.9.0",
|
||||
"@electron/docs-parser": "^0.12.4",
|
||||
"@electron/typescript-definitions": "^8.9.5",
|
||||
"@electron/asar": "^3.2.1",
|
||||
"@electron/docs-parser": "^1.0.0",
|
||||
"@electron/typescript-definitions": "^8.10.0",
|
||||
"@octokit/auth-app": "^2.10.0",
|
||||
"@octokit/rest": "^18.0.3",
|
||||
"@primer/octicons": "^10.0.0",
|
||||
@@ -31,7 +32,6 @@
|
||||
"@types/webpack-env": "^1.16.3",
|
||||
"@typescript-eslint/eslint-plugin": "^4.4.1",
|
||||
"@typescript-eslint/parser": "^4.4.1",
|
||||
"asar": "^3.1.0",
|
||||
"aws-sdk": "^2.814.0",
|
||||
"check-for-leaks": "^1.2.1",
|
||||
"colors": "1.4.0",
|
||||
@@ -89,7 +89,7 @@
|
||||
"lint:docs-relative-links": "python3 ./script/check-relative-doc-links.py",
|
||||
"lint:markdownlint": "markdownlint \"*.md\" \"docs/**/*.md\"",
|
||||
"lint:js-in-markdown": "standard-markdown docs",
|
||||
"create-api-json": "electron-docs-parser --dir=./",
|
||||
"create-api-json": "node script/create-api-json.js",
|
||||
"create-typescript-definitions": "npm run create-api-json && electron-typescript-definitions --api=electron-api.json && node spec/ts-smoke/runner.js",
|
||||
"gn-typescript-definitions": "npm run create-typescript-definitions && shx cp electron.d.ts",
|
||||
"pre-flight": "pre-flight",
|
||||
@@ -146,4 +146,4 @@
|
||||
"resolutions": {
|
||||
"nan": "nodejs/nan#16fa32231e2ccd89d2804b3f765319128b20c4ac"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1
patches/angle/.patches
Normal file
1
patches/angle/.patches
Normal file
@@ -0,0 +1 @@
|
||||
cherry-pick-b8636b57b8f2.patch
|
||||
46
patches/angle/cherry-pick-b8636b57b8f2.patch
Normal file
46
patches/angle/cherry-pick-b8636b57b8f2.patch
Normal file
@@ -0,0 +1,46 @@
|
||||
From b8636b57b8f231994ecb3fb14f181c593c83a3fb Mon Sep 17 00:00:00 2001
|
||||
From: Jamie Madill <jmadill@chromium.org>
|
||||
Date: Mon, 29 Aug 2022 16:25:46 -0400
|
||||
Subject: [PATCH] [M106] Vulkan: Ensure we sync the draw FB before beingQuery.
|
||||
|
||||
Bug: chromium:1354271
|
||||
(cherry picked from commit 4ebdac790c76b65abf5703bcef9482c638076195)
|
||||
Change-Id: I7b715a9c28badfe58a0ae1a478d2b4e8bbd23c47
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3956939
|
||||
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
---
|
||||
|
||||
diff --git a/src/libANGLE/State.h b/src/libANGLE/State.h
|
||||
index 168104e..2f498d3 100644
|
||||
--- a/src/libANGLE/State.h
|
||||
+++ b/src/libANGLE/State.h
|
||||
@@ -603,6 +603,11 @@
|
||||
|
||||
bool isRobustResourceInitEnabled() const { return mRobustResourceInit; }
|
||||
|
||||
+ bool isDrawFramebufferBindingDirty() const
|
||||
+ {
|
||||
+ return mDirtyBits.test(DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING);
|
||||
+ }
|
||||
+
|
||||
// Sets the dirty bit for the program executable.
|
||||
angle::Result onProgramExecutableChange(const Context *context, Program *program);
|
||||
// Sets the dirty bit for the program pipeline executable.
|
||||
diff --git a/src/libANGLE/renderer/vulkan/QueryVk.cpp b/src/libANGLE/renderer/vulkan/QueryVk.cpp
|
||||
index 9f475e6..6ef5f72 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/QueryVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/QueryVk.cpp
|
||||
@@ -303,6 +303,13 @@
|
||||
{
|
||||
ContextVk *contextVk = vk::GetImpl(context);
|
||||
|
||||
+ // Ensure that we start with the right RenderPass when we begin a new query.
|
||||
+ if (contextVk->getState().isDrawFramebufferBindingDirty())
|
||||
+ {
|
||||
+ ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
|
||||
+ RenderPassClosureReason::FramebufferBindingChange));
|
||||
+ }
|
||||
+
|
||||
mCachedResultValid = false;
|
||||
|
||||
// Transform feedback query is handled by a CPU-calculated value when emulated.
|
||||
@@ -113,3 +113,52 @@ feat_filter_out_non-shareable_windows_in_the_current_application_in.patch
|
||||
posix_replace_doubleforkandexec_with_forkandspawn.patch
|
||||
fix_allow_guest_webcontents_to_enter_fullscreen.patch
|
||||
disable_freezing_flags_after_init_in_node.patch
|
||||
chore_add_electron_deps_to_gitignores.patch
|
||||
chore_allow_chromium_to_handle_synthetic_mouse_events_for_touch.patch
|
||||
add_maximized_parameter_to_linuxui_getwindowframeprovider.patch
|
||||
fix_mac_build_with_enable_plugins_false.patch
|
||||
fix_windows_build_with_enable_plugins_false.patch
|
||||
remove_default_window_title.patch
|
||||
add_electron_deps_to_license_credits_file.patch
|
||||
feat_add_set_can_resize_mutator.patch
|
||||
cherry-pick-2083e894852c.patch
|
||||
cherry-pick-51daffbf5cd8.patch
|
||||
dpwa_enable_window_controls_overlay_by_default.patch
|
||||
create_browser_v8_snapshot_file_name_fuse.patch
|
||||
cherry-pick-fefd6198da31.patch
|
||||
cherry-pick-1eb1e18ad41d.patch
|
||||
cherry-pick-05a0d99c9715.patch
|
||||
cherry-pick-c83640db21b5.patch
|
||||
fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch
|
||||
cherry-pick-65f0ef609c00.patch
|
||||
cherry-pick-cb9dff93f3d4.patch
|
||||
build_fix_building_with_enable_plugins_false.patch
|
||||
build_allow_electron_to_use_exec_script.patch
|
||||
cherry-pick-d5ffb4dd4112.patch
|
||||
cherry-pick-65d46507a0c9.patch
|
||||
cherry-pick-933cc81c6bad.patch
|
||||
cherry-pick-06c87f9f42ff.patch
|
||||
cherry-pick-67c9cbc784d6.patch
|
||||
cherry-pick-a1cbf05b4163.patch
|
||||
cherry-pick-ac4785387fff.patch
|
||||
cherry-pick-81cb17c24788.patch
|
||||
cherry-pick-9b3d0e2f1aab.patch
|
||||
cherry-pick-1894458e04a2.patch
|
||||
cherry-pick-6b4af5d82083.patch
|
||||
cherry-pick-176c526846cb.patch
|
||||
cherry-pick-65ad70274d4b.patch
|
||||
cherry-pick-f46db6aac3e9.patch
|
||||
cherry-pick-2ef09109c0ec.patch
|
||||
cherry-pick-f98adc846aad.patch
|
||||
cherry-pick-eed5a4de2c40.patch
|
||||
cherry-pick-d1d654d73222.patch
|
||||
cherry-pick-42e15c2055c4.patch
|
||||
cherry-pick-77208afba04d.patch
|
||||
mojo_disable_sync_call_interrupts_in_the_browser.patch
|
||||
mojo_validate_that_a_message_is_allowed_to_use_the_sync_flag.patch
|
||||
cherry-pick-819d876e1bb8.patch
|
||||
cherry-pick-43637378b14e.patch
|
||||
win_fix_touch_mode_detection_dcheck_in_canary.patch
|
||||
cherry-pick-ca2b108a0f1f.patch
|
||||
cherry-pick-d652130c4bc2.patch
|
||||
cherry-pick-e545559df538.patch
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Charles Kerr <charles@charleskerr.com>
|
||||
Date: Tue, 9 Aug 2022 12:35:36 -0500
|
||||
Subject: add electron deps to license credits file
|
||||
|
||||
Ensure that licenses for the dependencies introduced by Electron
|
||||
are included in `LICENSES.chromium.html`
|
||||
|
||||
diff --git a/tools/licenses.py b/tools/licenses.py
|
||||
index a58dbf44370baabbfa2986c734c96a210cc16f1d..1d6934460f788ab76275710e727fb062f5c92b5b 100755
|
||||
--- a/tools/licenses.py
|
||||
+++ b/tools/licenses.py
|
||||
@@ -347,6 +347,32 @@ SPECIAL_CASES = {
|
||||
"License File":
|
||||
"/third_party/swiftshader/third_party/SPIRV-Headers/LICENSE",
|
||||
},
|
||||
+
|
||||
+ os.path.join('third_party', 'electron_node'): {
|
||||
+ "Name": "Node.js",
|
||||
+ "URL": "https://github.com/nodejs/node",
|
||||
+ "License": "MIT",
|
||||
+ "License File": "/third_party/electron_node/LICENSE",
|
||||
+ },
|
||||
+ os.path.join('third_party', 'squirrel.mac'): {
|
||||
+ "Name": "Squirrel",
|
||||
+ "URL": "https://github.com/Squirrel/Squirrel.Mac",
|
||||
+ "License": "MIT",
|
||||
+ "License File": "/third_party/squirrel.mac/LICENSE",
|
||||
+ },
|
||||
+ os.path.join('third_party', 'squirrel.mac', 'vendor', 'mantle'): {
|
||||
+ "Name": "Mantle",
|
||||
+ "URL": "https://github.com/Mantle/Mantle",
|
||||
+ "License": "MIT",
|
||||
+ "License File": "/third_party/squirrel.mac/vendor/mantle/LICENSE.md",
|
||||
+ },
|
||||
+ os.path.join('third_party', 'squirrel.mac', 'vendor', 'ReactiveObjC'): {
|
||||
+ "Name": "ReactiveObjC",
|
||||
+ "URL": "https://github.com/ReactiveCocoa/ReactiveObjC",
|
||||
+ "License": "MIT",
|
||||
+ "License File":
|
||||
+ "/third_party/squirrel.mac/vendor/ReactiveObjC/LICENSE.md",
|
||||
+ },
|
||||
}
|
||||
|
||||
# Special value for 'License File' field used to indicate that the license file
|
||||
@@ -0,0 +1,176 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: msizanoen1 <msizanoen@qtmlabs.xyz>
|
||||
Date: Tue, 19 Jul 2022 05:11:06 +0200
|
||||
Subject: Add maximized parameter to LinuxUI::GetWindowFrameProvider
|
||||
|
||||
This allows ClientFrameViewLinux to instruct the toolkit to draw the window
|
||||
decorations in maximized mode where needed, preventing empty space caused
|
||||
by decoration shadows and rounded titlebars around the window while maximized.
|
||||
|
||||
diff --git a/ui/gtk/gtk_ui.cc b/ui/gtk/gtk_ui.cc
|
||||
index 12193ad9090de969b81fa6aa6bed9520aea5bae1..99ea60219b39a6864bdea45ba0917316bff7f2d9 100644
|
||||
--- a/ui/gtk/gtk_ui.cc
|
||||
+++ b/ui/gtk/gtk_ui.cc
|
||||
@@ -556,13 +556,15 @@ std::unique_ptr<views::NavButtonProvider> GtkUi::CreateNavButtonProvider() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
-views::WindowFrameProvider* GtkUi::GetWindowFrameProvider(bool solid_frame) {
|
||||
+views::WindowFrameProvider* GtkUi::GetWindowFrameProvider(bool solid_frame, bool maximized) {
|
||||
if (!GtkCheckVersion(3, 14))
|
||||
return nullptr;
|
||||
auto& provider =
|
||||
- solid_frame ? solid_frame_provider_ : transparent_frame_provider_;
|
||||
+ maximized
|
||||
+ ? (solid_frame ? solid_maximized_frame_provider_ : transparent_maximized_frame_provider_)
|
||||
+ : (solid_frame ? solid_frame_provider_ : transparent_frame_provider_);
|
||||
if (!provider)
|
||||
- provider = std::make_unique<gtk::WindowFrameProviderGtk>(solid_frame);
|
||||
+ provider = std::make_unique<gtk::WindowFrameProviderGtk>(solid_frame, maximized);
|
||||
return provider.get();
|
||||
}
|
||||
|
||||
diff --git a/ui/gtk/gtk_ui.h b/ui/gtk/gtk_ui.h
|
||||
index 65f9d6c81804d1b0efb88ced4a9c80c000ba0f5a..35d851a054a2b2f9887c77a9faaf16ce1aa363b9 100644
|
||||
--- a/ui/gtk/gtk_ui.h
|
||||
+++ b/ui/gtk/gtk_ui.h
|
||||
@@ -89,7 +89,7 @@ class GtkUi : public views::LinuxUI {
|
||||
bool PreferDarkTheme() const override;
|
||||
bool AnimationsEnabled() const override;
|
||||
std::unique_ptr<views::NavButtonProvider> CreateNavButtonProvider() override;
|
||||
- views::WindowFrameProvider* GetWindowFrameProvider(bool solid_frame) override;
|
||||
+ views::WindowFrameProvider* GetWindowFrameProvider(bool solid_frame, bool maximized) override;
|
||||
base::flat_map<std::string, std::string> GetKeyboardLayoutMap() override;
|
||||
std::string GetCursorThemeName() override;
|
||||
int GetCursorThemeSize() override;
|
||||
@@ -188,6 +188,8 @@ class GtkUi : public views::LinuxUI {
|
||||
// while Chrome is running.
|
||||
std::unique_ptr<views::WindowFrameProvider> solid_frame_provider_;
|
||||
std::unique_ptr<views::WindowFrameProvider> transparent_frame_provider_;
|
||||
+ std::unique_ptr<views::WindowFrameProvider> solid_maximized_frame_provider_;
|
||||
+ std::unique_ptr<views::WindowFrameProvider> transparent_maximized_frame_provider_;
|
||||
};
|
||||
|
||||
} // namespace gtk
|
||||
diff --git a/ui/gtk/window_frame_provider_gtk.cc b/ui/gtk/window_frame_provider_gtk.cc
|
||||
index e4dbdad327eb77994ffd7f068c67336a19897915..d3ae0636455489a7c7443df85cb769952c98aca2 100644
|
||||
--- a/ui/gtk/window_frame_provider_gtk.cc
|
||||
+++ b/ui/gtk/window_frame_provider_gtk.cc
|
||||
@@ -38,16 +38,18 @@ std::string GetThemeName() {
|
||||
return theme_string;
|
||||
}
|
||||
|
||||
-GtkCssContext WindowContext(bool solid_frame, bool focused) {
|
||||
+GtkCssContext WindowContext(bool solid_frame, bool maximized, bool focused) {
|
||||
std::string selector = "#window.background.";
|
||||
selector += solid_frame ? "solid-csd" : "csd";
|
||||
+ if (maximized)
|
||||
+ selector += ".maximized";
|
||||
if (!focused)
|
||||
selector += ":inactive";
|
||||
return AppendCssNodeToStyleContext({}, selector);
|
||||
}
|
||||
|
||||
-GtkCssContext DecorationContext(bool solid_frame, bool focused) {
|
||||
- auto context = WindowContext(solid_frame, focused);
|
||||
+GtkCssContext DecorationContext(bool solid_frame, bool maximized, bool focused) {
|
||||
+ auto context = WindowContext(solid_frame, maximized, focused);
|
||||
// GTK4 renders the decoration directly on the window.
|
||||
if (!GtkCheckVersion(4))
|
||||
context = AppendCssNodeToStyleContext(context, "#decoration");
|
||||
@@ -64,8 +66,8 @@ GtkCssContext DecorationContext(bool solid_frame, bool focused) {
|
||||
return context;
|
||||
}
|
||||
|
||||
-GtkCssContext HeaderContext(bool solid_frame, bool focused) {
|
||||
- auto context = WindowContext(solid_frame, focused);
|
||||
+GtkCssContext HeaderContext(bool solid_frame, bool maximized, bool focused) {
|
||||
+ auto context = WindowContext(solid_frame, maximized, focused);
|
||||
context =
|
||||
AppendCssNodeToStyleContext(context, "#headerbar.header-bar.titlebar");
|
||||
if (!focused)
|
||||
@@ -110,8 +112,8 @@ int ComputeTopCornerRadius() {
|
||||
// need to experimentally determine the corner radius by rendering a sample.
|
||||
// Additionally, in GTK4, the headerbar corners get clipped by the window
|
||||
// rather than the headerbar having its own rounded corners.
|
||||
- auto context = GtkCheckVersion(4) ? DecorationContext(false, false)
|
||||
- : HeaderContext(false, false);
|
||||
+ auto context = GtkCheckVersion(4) ? DecorationContext(false, false, false)
|
||||
+ : HeaderContext(false, false, false);
|
||||
ApplyCssToContext(context, R"(window, headerbar {
|
||||
background-image: none;
|
||||
background-color: black;
|
||||
@@ -169,8 +171,8 @@ void WindowFrameProviderGtk::Asset::CloneFrom(
|
||||
unfocused_bitmap = src.unfocused_bitmap;
|
||||
}
|
||||
|
||||
-WindowFrameProviderGtk::WindowFrameProviderGtk(bool solid_frame)
|
||||
- : solid_frame_(solid_frame) {}
|
||||
+WindowFrameProviderGtk::WindowFrameProviderGtk(bool solid_frame, bool maximized)
|
||||
+ : solid_frame_(solid_frame), maximized_(maximized) {}
|
||||
|
||||
WindowFrameProviderGtk::~WindowFrameProviderGtk() = default;
|
||||
|
||||
@@ -264,7 +266,7 @@ void WindowFrameProviderGtk::PaintWindowFrame(gfx::Canvas* canvas,
|
||||
top_area_height_dip * scale - asset.frame_thickness_px.top();
|
||||
|
||||
auto header = PaintHeaderbar({client_bounds_px.width(), top_area_height_px},
|
||||
- HeaderContext(solid_frame_, focused), scale);
|
||||
+ HeaderContext(solid_frame_, maximized_, focused), scale);
|
||||
image = gfx::ImageSkia::CreateFrom1xBitmap(header);
|
||||
// In GTK4, the headerbar gets clipped by the window.
|
||||
if (GtkCheckVersion(4)) {
|
||||
@@ -296,7 +298,7 @@ void WindowFrameProviderGtk::MaybeUpdateBitmaps(float scale) {
|
||||
|
||||
gfx::Rect frame_bounds_dip(kMaxFrameSizeDip, kMaxFrameSizeDip,
|
||||
2 * kMaxFrameSizeDip, 2 * kMaxFrameSizeDip);
|
||||
- auto focused_context = DecorationContext(solid_frame_, true);
|
||||
+ auto focused_context = DecorationContext(solid_frame_, maximized_, true);
|
||||
frame_bounds_dip.Inset(-GtkStyleContextGetPadding(focused_context));
|
||||
frame_bounds_dip.Inset(-GtkStyleContextGetBorder(focused_context));
|
||||
gfx::Size bitmap_size(BitmapSizePx(asset), BitmapSizePx(asset));
|
||||
@@ -304,7 +306,7 @@ void WindowFrameProviderGtk::MaybeUpdateBitmaps(float scale) {
|
||||
PaintBitmap(bitmap_size, frame_bounds_dip, focused_context, scale);
|
||||
asset.unfocused_bitmap =
|
||||
PaintBitmap(bitmap_size, frame_bounds_dip,
|
||||
- DecorationContext(solid_frame_, false), scale);
|
||||
+ DecorationContext(solid_frame_, maximized_, false), scale);
|
||||
|
||||
// In GTK4, there's no way to obtain the frame thickness from CSS values
|
||||
// directly, so we must determine it experimentally based on the drawn
|
||||
diff --git a/ui/gtk/window_frame_provider_gtk.h b/ui/gtk/window_frame_provider_gtk.h
|
||||
index d3039d73161378197557947aece88d2710c1e486..f7d4605938210b0b75517bb7bcab28b588a16520 100644
|
||||
--- a/ui/gtk/window_frame_provider_gtk.h
|
||||
+++ b/ui/gtk/window_frame_provider_gtk.h
|
||||
@@ -14,7 +14,7 @@ namespace gtk {
|
||||
|
||||
class WindowFrameProviderGtk : public views::WindowFrameProvider {
|
||||
public:
|
||||
- explicit WindowFrameProviderGtk(bool solid_frame);
|
||||
+ explicit WindowFrameProviderGtk(bool solid_frame, bool maximized);
|
||||
|
||||
WindowFrameProviderGtk(const WindowFrameProviderGtk&) = delete;
|
||||
WindowFrameProviderGtk& operator=(const WindowFrameProviderGtk&) = delete;
|
||||
@@ -69,6 +69,9 @@ class WindowFrameProviderGtk : public views::WindowFrameProvider {
|
||||
|
||||
// Cached bitmaps and metrics. The scale is rounded to percent.
|
||||
base::flat_map<int, Asset> assets_;
|
||||
+
|
||||
+ // Whether to draw the window decorations as maximized.
|
||||
+ bool maximized_;
|
||||
};
|
||||
|
||||
} // namespace gtk
|
||||
diff --git a/ui/views/linux_ui/linux_ui.h b/ui/views/linux_ui/linux_ui.h
|
||||
index 7d59a2c9ff87cf9d8cb3ed0b45e34e2831545d28..a6ae4feec8df8f149a9ebbe1c3d2252db73135db 100644
|
||||
--- a/ui/views/linux_ui/linux_ui.h
|
||||
+++ b/ui/views/linux_ui/linux_ui.h
|
||||
@@ -170,7 +170,7 @@ class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory,
|
||||
// if transparency is unsupported and the frame should be rendered opaque.
|
||||
// The returned object is not owned by the caller and will remain alive until
|
||||
// the process ends.
|
||||
- virtual WindowFrameProvider* GetWindowFrameProvider(bool solid_frame) = 0;
|
||||
+ virtual WindowFrameProvider* GetWindowFrameProvider(bool solid_frame, bool maximized) = 0;
|
||||
|
||||
// Returns a map of KeyboardEvent code to KeyboardEvent key values.
|
||||
virtual base::flat_map<std::string, std::string> GetKeyboardLayoutMap() = 0;
|
||||
@@ -0,0 +1,18 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Attard <sattard@salesforce.com>
|
||||
Date: Fri, 21 Oct 2022 16:29:06 -0700
|
||||
Subject: build: allow electron to use exec_script
|
||||
|
||||
This is similar to the //build usecase so we're OK adding ourselves here
|
||||
|
||||
diff --git a/.gn b/.gn
|
||||
index 7d538f812d72e0937e7a031e1c53651c352149c5..1cad40a9825f3c6df67dbcc12d2f9650aad809b2 100644
|
||||
--- a/.gn
|
||||
+++ b/.gn
|
||||
@@ -169,4 +169,6 @@ exec_script_whitelist =
|
||||
|
||||
"//tools/grit/grit_rule.gni",
|
||||
"//tools/gritsettings/BUILD.gn",
|
||||
+
|
||||
+ "//electron/BUILD.gn"
|
||||
]
|
||||
@@ -46,10 +46,10 @@ index bbe8847b3da8d6ec9c5d10bbe875de8c34e060d3..e2e12c141932f52f49d24a0bad4a5300
|
||||
sources += [ "certificate_viewer_stub.cc" ]
|
||||
}
|
||||
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
|
||||
index cd30ea6c938860837d7427fee851974b0ec5831b..d88eb38a8ce9a0f607b85e7efe40fe23f6ab5f08 100644
|
||||
index e791e09b43760ecc3aac9af7bac252233e6bae0b..baacf6bf01fa9df05bd9c2d87d3519666f41fc77 100644
|
||||
--- a/chrome/test/BUILD.gn
|
||||
+++ b/chrome/test/BUILD.gn
|
||||
@@ -5912,7 +5912,6 @@ test("unit_tests") {
|
||||
@@ -5913,7 +5913,6 @@ test("unit_tests") {
|
||||
|
||||
deps += [
|
||||
"//chrome:other_version",
|
||||
@@ -57,7 +57,7 @@ index cd30ea6c938860837d7427fee851974b0ec5831b..d88eb38a8ce9a0f607b85e7efe40fe23
|
||||
"//chrome//services/util_win:unit_tests",
|
||||
"//chrome/app:chrome_dll_resources",
|
||||
"//chrome/browser:chrome_process_finder",
|
||||
@@ -5936,6 +5935,10 @@ test("unit_tests") {
|
||||
@@ -5937,6 +5936,10 @@ test("unit_tests") {
|
||||
"//ui/resources",
|
||||
]
|
||||
|
||||
@@ -68,7 +68,7 @@ index cd30ea6c938860837d7427fee851974b0ec5831b..d88eb38a8ce9a0f607b85e7efe40fe23
|
||||
ldflags = [
|
||||
"/DELAYLOAD:api-ms-win-core-winrt-error-l1-1-0.dll",
|
||||
"/DELAYLOAD:api-ms-win-core-winrt-l1-1-0.dll",
|
||||
@@ -6826,7 +6829,6 @@ test("unit_tests") {
|
||||
@@ -6827,7 +6830,6 @@ test("unit_tests") {
|
||||
}
|
||||
|
||||
deps += [
|
||||
@@ -76,7 +76,7 @@ index cd30ea6c938860837d7427fee851974b0ec5831b..d88eb38a8ce9a0f607b85e7efe40fe23
|
||||
"//chrome/browser:cart_db_content_proto",
|
||||
"//chrome/browser:coupon_db_content_proto",
|
||||
"//chrome/browser/media/router:test_support",
|
||||
@@ -6932,6 +6934,10 @@ test("unit_tests") {
|
||||
@@ -6933,6 +6935,10 @@ test("unit_tests") {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Milan Burda <miburda@microsoft.com>
|
||||
Date: Sun, 30 Oct 2022 22:32:39 +0100
|
||||
Subject: build: fix building with enable_plugins = false
|
||||
|
||||
This issue is fixed in latest Chromium
|
||||
|
||||
diff --git a/tools/ipc_fuzzer/message_lib/BUILD.gn b/tools/ipc_fuzzer/message_lib/BUILD.gn
|
||||
index 00618d9f81cabd5084218431658fd91d22fb4208..26be64a51fc5767e0ee97681a0b3f2dfd74159fe 100644
|
||||
--- a/tools/ipc_fuzzer/message_lib/BUILD.gn
|
||||
+++ b/tools/ipc_fuzzer/message_lib/BUILD.gn
|
||||
@@ -3,6 +3,7 @@
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//components/nacl/features.gni")
|
||||
+import("//ppapi/buildflags/buildflags.gni")
|
||||
import("//remoting/remoting_enable.gni")
|
||||
|
||||
static_library("ipc_message_lib") {
|
||||
@@ -22,7 +23,6 @@ static_library("ipc_message_lib") {
|
||||
"//ipc",
|
||||
"//media/cast:net",
|
||||
"//media/gpu/ipc/common",
|
||||
- "//ppapi/proxy:ipc",
|
||||
"//skia",
|
||||
"//third_party/blink/public:blink",
|
||||
"//third_party/blink/public:blink_headers",
|
||||
@@ -49,4 +49,7 @@ static_library("ipc_message_lib") {
|
||||
if (enable_remoting) {
|
||||
public_deps += [ "//remoting/host" ]
|
||||
}
|
||||
+ if (enable_plugins) {
|
||||
+ public_deps += [ "//ppapi/proxy:ipc" ]
|
||||
+ }
|
||||
}
|
||||
@@ -9,10 +9,10 @@ potentially prevent a window from being created.
|
||||
TODO(loc): this patch is currently broken.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
index b857d325233430a5b79b3022d33823486e558309..83cc6ded4b3354f37b8e1dc0d9e4f3289863fa09 100644
|
||||
index 28c7136b21d058e3daa7570af558f5a415b000a7..d1b7d15a7e4dede5b030e4ae9fb2ab8aa8196446 100644
|
||||
--- a/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
@@ -6966,6 +6966,7 @@ void RenderFrameHostImpl::CreateNewWindow(
|
||||
@@ -7006,6 +7006,7 @@ void RenderFrameHostImpl::CreateNewWindow(
|
||||
last_committed_origin_, params->window_container_type,
|
||||
params->target_url, params->referrer.To<Referrer>(),
|
||||
params->frame_name, params->disposition, *params->features,
|
||||
@@ -21,10 +21,10 @@ index b857d325233430a5b79b3022d33823486e558309..83cc6ded4b3354f37b8e1dc0d9e4f328
|
||||
&no_javascript_access);
|
||||
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index 33f6efe4df4eecabcbcd08f908ed3ef12d056eb2..0e1e25d40ebf3ca92c57dfdfb52c5269198aa6f7 100644
|
||||
index cb74ef64fc8d4014fb57f098df6440dda5e896d4..c7d376b31e0fb570c934c6a8846e37bf1f3b3262 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -3947,6 +3947,14 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
@@ -3965,6 +3965,14 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
}
|
||||
auto* new_contents_impl = new_contents.get();
|
||||
|
||||
@@ -39,7 +39,7 @@ index 33f6efe4df4eecabcbcd08f908ed3ef12d056eb2..0e1e25d40ebf3ca92c57dfdfb52c5269
|
||||
new_contents_impl->GetController().SetSessionStorageNamespace(
|
||||
partition_config, session_storage_namespace);
|
||||
|
||||
@@ -3991,12 +3999,6 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
@@ -4009,12 +4017,6 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
AddWebContentsDestructionObserver(new_contents_impl);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ index 9c3a03faeee19f6f0a250680db36906ee64bf55a..0450700d02c74e047fa5124aa43b9f75
|
||||
|
||||
// Operation result when the renderer asks the browser to create a new window.
|
||||
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
|
||||
index 69bcd725d0f86bf3b175fde86bd2dbd85b59f002..b72d89b19024a9074108dde4c5c9cd0f45b719bb 100644
|
||||
index c1beba6701e68255c212e56d78ae8259e2ffdab9..9f77c2a5df8f25876f875c4a7148d82c3dd79db8 100644
|
||||
--- a/content/public/browser/content_browser_client.cc
|
||||
+++ b/content/public/browser/content_browser_client.cc
|
||||
@@ -595,6 +595,8 @@ bool ContentBrowserClient::CanCreateWindow(
|
||||
@@ -81,7 +81,7 @@ index 69bcd725d0f86bf3b175fde86bd2dbd85b59f002..b72d89b19024a9074108dde4c5c9cd0f
|
||||
bool opener_suppressed,
|
||||
bool* no_javascript_access) {
|
||||
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
|
||||
index d0b7aed3162b8ea7673ab3ef31d2a3302f4e6456..6328fc21548f2b8277b461f9938dbcc50f6853f1 100644
|
||||
index a49794184baa977ddf03cd911f8d8d7d671df65f..7997c0de85315e30b350316f33e598a0221d583f 100644
|
||||
--- a/content/public/browser/content_browser_client.h
|
||||
+++ b/content/public/browser/content_browser_client.h
|
||||
@@ -164,6 +164,7 @@ class NetworkService;
|
||||
|
||||
34
patches/chromium/cherry-pick-05a0d99c9715.patch
Normal file
34
patches/chromium/cherry-pick-05a0d99c9715.patch
Normal file
@@ -0,0 +1,34 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: David Bokan <bokan@chromium.org>
|
||||
Date: Thu, 28 Jul 2022 18:09:13 +0000
|
||||
Subject: Prevent handling input for provisional frames
|
||||
|
||||
Bug: 1347644,1322812
|
||||
Change-Id: Ifd60f6aa593ce23ca6cbb65552fc9fb8f8690035
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3791883
|
||||
Commit-Queue: David Bokan <bokan@chromium.org>
|
||||
Reviewed-by: Dave Tapuska <dtapuska@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1029361}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
|
||||
index fe775337fbc22817d7489df143821eea2d9425ec..13a241273090e54fabdba9d82510e36d2386c4a4 100644
|
||||
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
|
||||
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
|
||||
@@ -2460,10 +2460,15 @@ WebInputEventResult WebFrameWidgetImpl::HandleInputEvent(
|
||||
DCHECK(!WebInputEvent::IsTouchEventType(input_event.GetType()));
|
||||
CHECK(LocalRootImpl());
|
||||
|
||||
+ // Clients shouldn't be dispatching events to a provisional frame but this
|
||||
+ // can happen. Ensure that event handling can assume we're in a committed
|
||||
+ // frame.
|
||||
+ if (IsProvisional())
|
||||
+ return WebInputEventResult::kHandledSuppressed;
|
||||
+
|
||||
// Only record metrics for the root frame.
|
||||
- if (ForTopMostMainFrame()) {
|
||||
+ if (ForTopMostMainFrame())
|
||||
GetPage()->GetVisualViewport().StartTrackingPinchStats();
|
||||
- }
|
||||
|
||||
// If a drag-and-drop operation is in progress, ignore input events except
|
||||
// PointerCancel and GestureLongPress.
|
||||
153
patches/chromium/cherry-pick-06c87f9f42ff.patch
Normal file
153
patches/chromium/cherry-pick-06c87f9f42ff.patch
Normal file
@@ -0,0 +1,153 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Rune Lillesveen <futhark@chromium.org>
|
||||
Date: Fri, 14 Oct 2022 09:52:34 +0000
|
||||
Subject: Avoid layout roots in subtrees skipped for style recalc
|
||||
|
||||
Layout roots are laid out from inner to outer in LocalFrameView. DOM
|
||||
mutations may have added layout roots inside size container subtrees
|
||||
before style recalc. If we decide to postpone style recalc until layout
|
||||
of the size container, it means we may try to layout a root inside a
|
||||
subtree skipped for style recalc. That causes a DCHECK and possibly
|
||||
other issues.
|
||||
|
||||
This also fixes the use-after-poison issue 1365330.
|
||||
|
||||
(cherry picked from commit 0f0f1e99201fadb3c68518350e1cd6af1b665346)
|
||||
|
||||
Bug: 1371820, 1365330
|
||||
Change-Id: Ia48890c08aacfe7b9a3e660817702abce0570564
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3934847
|
||||
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
|
||||
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1055853}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3953455
|
||||
Auto-Submit: Rune Lillesveen <futhark@chromium.org>
|
||||
Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org>
|
||||
Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5249@{#836}
|
||||
Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
|
||||
index f51b8878eb0abe23889a07277efeaf7cdf961cc8..ddcef20b47357e58acae08b4183db6187b046f80 100644
|
||||
--- a/third_party/blink/renderer/core/css/style_engine.cc
|
||||
+++ b/third_party/blink/renderer/core/css/style_engine.cc
|
||||
@@ -2808,6 +2808,7 @@ void StyleEngine::RecalcStyle(StyleRecalcChange change,
|
||||
const StyleRecalcContext& style_recalc_context) {
|
||||
DCHECK(GetDocument().documentElement());
|
||||
ScriptForbiddenScope forbid_script;
|
||||
+ SkipStyleRecalcScope skip_scope(*this);
|
||||
CheckPseudoHasCacheScope check_pseudo_has_cache_scope(&GetDocument());
|
||||
Element& root_element = style_recalc_root_.RootElement();
|
||||
Element* parent = FlatTreeTraversal::ParentElement(root_element);
|
||||
@@ -3400,4 +3401,17 @@ void StyleEngine::MarkForLayoutTreeChangesAfterDetach() {
|
||||
parent_for_detached_subtree_ = nullptr;
|
||||
}
|
||||
|
||||
+bool StyleEngine::AllowSkipStyleRecalcForScope() const {
|
||||
+ if (InContainerQueryStyleRecalc())
|
||||
+ return true;
|
||||
+ if (LocalFrameView* view = GetDocument().View()) {
|
||||
+ // Existing layout roots before starting style recalc may end up being
|
||||
+ // inside skipped subtrees if we allowed skipping. If we start out with an
|
||||
+ // empty list, any added ones will be a result of an element style recalc,
|
||||
+ // which means the will not be inside a skipped subtree.
|
||||
+ return !view->IsSubtreeLayout();
|
||||
+ }
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
} // namespace blink
|
||||
diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h
|
||||
index a6c325b69e5bc43c657519f4c0730f6e2efd4f71..f7ccc6c2b7b306d76bba60cf46da91a5b291c29e 100644
|
||||
--- a/third_party/blink/renderer/core/css/style_engine.h
|
||||
+++ b/third_party/blink/renderer/core/css/style_engine.h
|
||||
@@ -178,6 +178,20 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
|
||||
base::AutoReset<bool> allow_marking_;
|
||||
};
|
||||
|
||||
+ // Set up the condition for allowing to skip style recalc before starting
|
||||
+ // RecalcStyle().
|
||||
+ class SkipStyleRecalcScope {
|
||||
+ STACK_ALLOCATED();
|
||||
+
|
||||
+ public:
|
||||
+ explicit SkipStyleRecalcScope(StyleEngine& engine)
|
||||
+ : allow_skip_(&engine.allow_skip_style_recalc_,
|
||||
+ engine.AllowSkipStyleRecalcForScope()) {}
|
||||
+
|
||||
+ private:
|
||||
+ base::AutoReset<bool> allow_skip_;
|
||||
+ };
|
||||
+
|
||||
explicit StyleEngine(Document&);
|
||||
~StyleEngine() override;
|
||||
|
||||
@@ -342,6 +356,10 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
|
||||
|
||||
bool MarkReattachAllowed() const;
|
||||
|
||||
+ // Returns true if we can skip style recalc for a size container subtree and
|
||||
+ // resume it during layout.
|
||||
+ bool SkipStyleRecalcAllowed() const { return allow_skip_style_recalc_; }
|
||||
+
|
||||
CSSFontSelector* GetFontSelector() { return font_selector_; }
|
||||
|
||||
void RemoveFontFaceRules(const HeapVector<Member<const StyleRuleFontFace>>&);
|
||||
@@ -743,6 +761,9 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
|
||||
Element& changed_element,
|
||||
bool for_pseudo_change);
|
||||
|
||||
+ // Initialization value for SkipStyleRecalcScope.
|
||||
+ bool AllowSkipStyleRecalcForScope() const;
|
||||
+
|
||||
Member<Document> document_;
|
||||
|
||||
// Tracks the number of currently loading top-level stylesheets. Sheets loaded
|
||||
@@ -812,6 +833,9 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
|
||||
// AllowMarkStyleDirtyFromRecalcScope.
|
||||
bool allow_mark_for_reattach_from_rebuild_layout_tree_{false};
|
||||
|
||||
+ // Set to true if we are allowed to skip recalc for a size container subtree.
|
||||
+ bool allow_skip_style_recalc_{false};
|
||||
+
|
||||
// See enum ViewportUnitFlag.
|
||||
unsigned viewport_unit_dirty_flags_{0};
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
|
||||
index 8e5c4aab2e37ed0acda0ef56273d007fbaa58780..2df360c33c54e12af341b77771fcda95e562fa92 100644
|
||||
--- a/third_party/blink/renderer/core/dom/element.cc
|
||||
+++ b/third_party/blink/renderer/core/dom/element.cc
|
||||
@@ -3532,6 +3532,10 @@ bool Element::SkipStyleRecalcForContainer(
|
||||
const ComputedStyle& style,
|
||||
const StyleRecalcChange& child_change) {
|
||||
DCHECK(RuntimeEnabledFeatures::CSSContainerSkipStyleRecalcEnabled());
|
||||
+
|
||||
+ if (!GetDocument().GetStyleEngine().SkipStyleRecalcAllowed())
|
||||
+ return false;
|
||||
+
|
||||
if (!child_change.TraversePseudoElements(*this)) {
|
||||
// If none of the children or pseudo elements need to be traversed for style
|
||||
// recalc, there is no point in marking the subtree as skipped.
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/crashtests/chrome-layout-root-crash.html b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/crashtests/chrome-layout-root-crash.html
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e3e709a240bd870250b2747c94fe96880bdf52e3
|
||||
--- /dev/null
|
||||
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/crashtests/chrome-layout-root-crash.html
|
||||
@@ -0,0 +1,17 @@
|
||||
+<!doctype html>
|
||||
+<html class="reftest-wait">
|
||||
+<link rel="help" href="https://crbug.com/1371820">
|
||||
+<style>
|
||||
+ body, div, img { container-type: size; }
|
||||
+</style>
|
||||
+<p>Pass if no crash.</p>
|
||||
+<div id="div"><img id="img" alt="a"></div>
|
||||
+<script>
|
||||
+ requestAnimationFrame(() => requestAnimationFrame(() => {
|
||||
+ // Adds a layout root inside the div size container.
|
||||
+ img.alt = img.src = "b";
|
||||
+ // Marks div size container for layout which skips style recalc for the sub-tree.
|
||||
+ div.style.width = "500px";
|
||||
+ document.documentElement.classList.remove("reftest-wait");
|
||||
+ }));
|
||||
+</script>
|
||||
192
patches/chromium/cherry-pick-176c526846cb.patch
Normal file
192
patches/chromium/cherry-pick-176c526846cb.patch
Normal file
@@ -0,0 +1,192 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Robert Sesek <rsesek@chromium.org>
|
||||
Date: Fri, 18 Nov 2022 19:31:38 +0000
|
||||
Subject: Fix a data race leading to use-after-free in mojo::ChannelMac
|
||||
ShutDown
|
||||
|
||||
(cherry picked from commit bd8a1e43aa93d5bb7674cb5a431e7375f7e2f192)
|
||||
|
||||
Bug: 1378564
|
||||
Change-Id: I67041b1e2ef08dd0ee1ccbf6d534249c539b74db
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4027242
|
||||
Commit-Queue: Robert Sesek <rsesek@chromium.org>
|
||||
Reviewed-by: Ken Rockot <rockot@google.com>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1071700}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4035114
|
||||
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Auto-Submit: Robert Sesek <rsesek@chromium.org>
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/5359@{#881}
|
||||
Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933}
|
||||
|
||||
diff --git a/mojo/core/channel_mac.cc b/mojo/core/channel_mac.cc
|
||||
index 686dea5c783af06e41c290b03db251ca584d9a72..a24d5ab4ea9ae63f652acc2f903e577d45b1f0ee 100644
|
||||
--- a/mojo/core/channel_mac.cc
|
||||
+++ b/mojo/core/channel_mac.cc
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "base/mac/scoped_mach_vm.h"
|
||||
#include "base/message_loop/message_pump_for_io.h"
|
||||
#include "base/task/current_thread.h"
|
||||
+#include "base/thread_annotations.h"
|
||||
#include "base/trace_event/typed_macros.h"
|
||||
|
||||
extern "C" {
|
||||
@@ -167,7 +168,10 @@ class ChannelMac : public Channel,
|
||||
vm_allocate(mach_task_self(), &address, size,
|
||||
VM_MAKE_TAG(VM_MEMORY_MACH_MSG) | VM_FLAGS_ANYWHERE);
|
||||
MACH_CHECK(kr == KERN_SUCCESS, kr) << "vm_allocate";
|
||||
- send_buffer_.reset(address, size);
|
||||
+ {
|
||||
+ base::AutoLock lock(write_lock_);
|
||||
+ send_buffer_.reset(address, size);
|
||||
+ }
|
||||
|
||||
kr = vm_allocate(mach_task_self(), &address, size,
|
||||
VM_MAKE_TAG(VM_MEMORY_MACH_MSG) | VM_FLAGS_ANYWHERE);
|
||||
@@ -207,7 +211,11 @@ class ChannelMac : public Channel,
|
||||
|
||||
watch_controller_.StopWatchingMachPort();
|
||||
|
||||
- send_buffer_.reset();
|
||||
+ {
|
||||
+ base::AutoLock lock(write_lock_);
|
||||
+ send_buffer_.reset();
|
||||
+ reject_writes_ = true;
|
||||
+ }
|
||||
receive_buffer_.reset();
|
||||
incoming_handles_.clear();
|
||||
|
||||
@@ -315,7 +323,7 @@ class ChannelMac : public Channel,
|
||||
SendPendingMessagesLocked();
|
||||
}
|
||||
|
||||
- void SendPendingMessagesLocked() {
|
||||
+ void SendPendingMessagesLocked() EXCLUSIVE_LOCKS_REQUIRED(write_lock_) {
|
||||
// If a previous send failed due to the receiver's kernel message queue
|
||||
// being full, attempt to send that failed message first.
|
||||
if (send_buffer_contains_message_ && !reject_writes_) {
|
||||
@@ -342,7 +350,8 @@ class ChannelMac : public Channel,
|
||||
}
|
||||
}
|
||||
|
||||
- bool SendMessageLocked(MessagePtr message) {
|
||||
+ bool SendMessageLocked(MessagePtr message)
|
||||
+ EXCLUSIVE_LOCKS_REQUIRED(write_lock_) {
|
||||
DCHECK(!send_buffer_contains_message_);
|
||||
base::BufferIterator<char> buffer(
|
||||
reinterpret_cast<char*>(send_buffer_.address()), send_buffer_.size());
|
||||
@@ -437,7 +446,8 @@ class ChannelMac : public Channel,
|
||||
return MachMessageSendLocked(header);
|
||||
}
|
||||
|
||||
- bool MachMessageSendLocked(mach_msg_header_t* header) {
|
||||
+ bool MachMessageSendLocked(mach_msg_header_t* header)
|
||||
+ EXCLUSIVE_LOCKS_REQUIRED(write_lock_) {
|
||||
kern_return_t kr = mach_msg(header, MACH_SEND_MSG | MACH_SEND_TIMEOUT,
|
||||
header->msgh_size, 0, MACH_PORT_NULL,
|
||||
/*timeout=*/0, MACH_PORT_NULL);
|
||||
@@ -659,7 +669,7 @@ class ChannelMac : public Channel,
|
||||
}
|
||||
|
||||
// Marks the channel as unaccepting of new messages and shuts it down.
|
||||
- void OnWriteErrorLocked(Error error) {
|
||||
+ void OnWriteErrorLocked(Error error) EXCLUSIVE_LOCKS_REQUIRED(write_lock_) {
|
||||
reject_writes_ = true;
|
||||
io_task_runner_->PostTask(
|
||||
FROM_HERE, base::BindOnce(&ChannelMac::OnError, this, error));
|
||||
@@ -701,17 +711,17 @@ class ChannelMac : public Channel,
|
||||
// Lock that protects the following members.
|
||||
base::Lock write_lock_;
|
||||
// Whether writes should be rejected due to an internal error.
|
||||
- bool reject_writes_ = false;
|
||||
+ bool reject_writes_ GUARDED_BY(write_lock_) = false;
|
||||
// IO buffer for sending Mach messages.
|
||||
- base::mac::ScopedMachVM send_buffer_;
|
||||
+ base::mac::ScopedMachVM send_buffer_ GUARDED_BY(write_lock_);
|
||||
// If a message timed out during send in MachMessageSendLocked(), this will
|
||||
// be true to indicate that |send_buffer_| contains a message that must
|
||||
// be sent. If this is true, then other calls to Write() queue messages onto
|
||||
// |pending_messages_|.
|
||||
- bool send_buffer_contains_message_ = false;
|
||||
+ bool send_buffer_contains_message_ GUARDED_BY(write_lock_) = false;
|
||||
// When |handshake_done_| is false or |send_buffer_contains_message_| is true,
|
||||
// calls to Write() will enqueue messages here.
|
||||
- base::circular_deque<MessagePtr> pending_messages_;
|
||||
+ base::circular_deque<MessagePtr> pending_messages_ GUARDED_BY(write_lock_);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
diff --git a/mojo/core/channel_unittest.cc b/mojo/core/channel_unittest.cc
|
||||
index e9dee384440ee5a0500e86c522eef19c12bd8045..47422267cbaa0d3f90be6adc851a0651c1b74133 100644
|
||||
--- a/mojo/core/channel_unittest.cc
|
||||
+++ b/mojo/core/channel_unittest.cc
|
||||
@@ -712,6 +712,69 @@ TEST(ChannelTest, SendToDeadMachPortName) {
|
||||
}
|
||||
#endif // BUILDFLAG(IS_MAC)
|
||||
|
||||
+TEST(ChannelTest, ShutDownStress) {
|
||||
+ base::test::SingleThreadTaskEnvironment task_environment(
|
||||
+ base::test::TaskEnvironment::MainThreadType::IO);
|
||||
+
|
||||
+ // Create a second IO thread for Channel B.
|
||||
+ base::Thread peer_thread("channel_b_io");
|
||||
+ peer_thread.StartWithOptions(
|
||||
+ base::Thread::Options(base::MessagePumpType::IO, 0));
|
||||
+
|
||||
+ // Create two channels, A and B, which run on different threads.
|
||||
+ PlatformChannel platform_channel;
|
||||
+
|
||||
+ CallbackChannelDelegate delegate_a;
|
||||
+ scoped_refptr<Channel> channel_a = Channel::Create(
|
||||
+ &delegate_a, ConnectionParams(platform_channel.TakeLocalEndpoint()),
|
||||
+ Channel::HandlePolicy::kRejectHandles,
|
||||
+ task_environment.GetMainThreadTaskRunner());
|
||||
+ channel_a->Start();
|
||||
+
|
||||
+ scoped_refptr<Channel> channel_b = Channel::Create(
|
||||
+ nullptr, ConnectionParams(platform_channel.TakeRemoteEndpoint()),
|
||||
+ Channel::HandlePolicy::kRejectHandles, peer_thread.task_runner());
|
||||
+ channel_b->Start();
|
||||
+
|
||||
+ base::WaitableEvent go_event;
|
||||
+
|
||||
+ // Warm up the channel to ensure that A and B are connected, then quit.
|
||||
+ channel_b->Write(Channel::Message::CreateMessage(0, 0));
|
||||
+ {
|
||||
+ base::RunLoop run_loop;
|
||||
+ delegate_a.set_on_message(run_loop.QuitClosure());
|
||||
+ run_loop.Run();
|
||||
+ }
|
||||
+
|
||||
+ // Block the peer thread while some tasks are queued up from the test main
|
||||
+ // thread.
|
||||
+ peer_thread.task_runner()->PostTask(
|
||||
+ FROM_HERE,
|
||||
+ base::BindOnce(&base::WaitableEvent::Wait, base::Unretained(&go_event)));
|
||||
+
|
||||
+ // First, write some messages for Channel B.
|
||||
+ for (int i = 0; i < 500; ++i) {
|
||||
+ channel_b->Write(Channel::Message::CreateMessage(0, 0));
|
||||
+ }
|
||||
+
|
||||
+ // Then shut down channel B.
|
||||
+ channel_b->ShutDown();
|
||||
+
|
||||
+ // Un-block the peer thread.
|
||||
+ go_event.Signal();
|
||||
+
|
||||
+ // And then flood the channel with messages. This will suss out data races
|
||||
+ // during Channel B's shutdown, since Writes can happen across threads
|
||||
+ // without a PostTask.
|
||||
+ for (int i = 0; i < 1000; ++i) {
|
||||
+ channel_b->Write(Channel::Message::CreateMessage(0, 0));
|
||||
+ }
|
||||
+
|
||||
+ // Explicitly join the thread to wait for pending tasks, which may reference
|
||||
+ // stack variables, to complete.
|
||||
+ peer_thread.Stop();
|
||||
+}
|
||||
+
|
||||
} // namespace
|
||||
} // namespace core
|
||||
} // namespace mojo
|
||||
37
patches/chromium/cherry-pick-1894458e04a2.patch
Normal file
37
patches/chromium/cherry-pick-1894458e04a2.patch
Normal file
@@ -0,0 +1,37 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Joshua Peraza <jperaza@chromium.org>
|
||||
Date: Thu, 3 Nov 2022 21:18:35 +0000
|
||||
Subject: Validate number of bytes read
|
||||
|
||||
Original commit:
|
||||
https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3994208
|
||||
|
||||
(cherry picked from commit 7585111a6c1dfa502f3ca1e3d27aed066e479fd9)
|
||||
|
||||
Bug: chromium:1380083
|
||||
Change-Id: If9708ccdbf6957ef169b35f8f89e2b0744d066d7
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4000305
|
||||
Reviewed-by: Mark Mentovai <mark@chromium.org>
|
||||
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/branch-heads/5359@{#529}
|
||||
Cr-Original-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4004067
|
||||
Cr-Commit-Position: refs/branch-heads/5249@{#905}
|
||||
Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826}
|
||||
|
||||
diff --git a/third_party/crashpad/crashpad/util/linux/ptrace_client.cc b/third_party/crashpad/crashpad/util/linux/ptrace_client.cc
|
||||
index 1863841f73f64d89391646f5c3e5fc2e2766a6cc..32cc35d9567117fe0eb6f1ec4736ac4a15ddfd83 100644
|
||||
--- a/third_party/crashpad/crashpad/util/linux/ptrace_client.cc
|
||||
+++ b/third_party/crashpad/crashpad/util/linux/ptrace_client.cc
|
||||
@@ -331,6 +331,11 @@ ssize_t PtraceClient::ReadUpTo(VMAddress address, size_t size, void* buffer) {
|
||||
return total_read;
|
||||
}
|
||||
|
||||
+ if (static_cast<size_t>(bytes_read) > size) {
|
||||
+ LOG(ERROR) << "invalid size " << bytes_read;
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
if (!LoggingReadFileExactly(sock_, buffer_c, bytes_read)) {
|
||||
return -1;
|
||||
}
|
||||
184
patches/chromium/cherry-pick-1eb1e18ad41d.patch
Normal file
184
patches/chromium/cherry-pick-1eb1e18ad41d.patch
Normal file
@@ -0,0 +1,184 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Anders Hartvoll Ruud <andruud@chromium.org>
|
||||
Date: Tue, 20 Sep 2022 17:43:47 +0000
|
||||
Subject: Add CSSTokenizer-created strings to CSSVariableData's backing strings
|
||||
|
||||
When computing the value of a registered custom property, we create
|
||||
a CSSVariableData object equivalent to the computed CSSValue by
|
||||
serializing that CSSValue to a String, then tokenizing that value.
|
||||
|
||||
The problem is that CSSTokenizer can create *new* string objects
|
||||
during the tokenization process (see calls to CSSTokenizer::
|
||||
RegisterString), without communicating that fact to the call-site.
|
||||
|
||||
Therefore, this CL adds a way to access those strings so they can
|
||||
be added to the backing strings of the CSSVariableData.
|
||||
|
||||
Also added a DCHECK to verify that we don't have any tokens with
|
||||
non-backed string pointers.
|
||||
|
||||
Fixed: 1358907
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3892782
|
||||
Reviewed-by: Steinar H Gunderson <sesse@chromium.org>
|
||||
Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1046868}
|
||||
Change-Id: Ifb6d194508e99030a5a3ed5fbad5496b7263bdc1
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3905727
|
||||
Auto-Submit: Anders Hartvoll Ruud <andruud@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5249@{#518}
|
||||
Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/css/css_variable_data.cc b/third_party/blink/renderer/core/css/css_variable_data.cc
|
||||
index a2294cc70c59ac0357dddf0f7719cc3c09d23554..b3a61b312eb5f0360e8aa4cb706c60f0085fead9 100644
|
||||
--- a/third_party/blink/renderer/core/css/css_variable_data.cc
|
||||
+++ b/third_party/blink/renderer/core/css/css_variable_data.cc
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "third_party/blink/renderer/core/css/css_variable_data.h"
|
||||
|
||||
+#include "base/containers/span.h"
|
||||
#include "third_party/blink/renderer/core/css/css_syntax_definition.h"
|
||||
#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
|
||||
#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
|
||||
@@ -109,6 +110,51 @@ void CSSVariableData::ConsumeAndUpdateTokens(const CSSParserTokenRange& range) {
|
||||
UpdateTokens<UChar>(range, backing_string, tokens_);
|
||||
}
|
||||
|
||||
+#if EXPENSIVE_DCHECKS_ARE_ON()
|
||||
+
|
||||
+namespace {
|
||||
+
|
||||
+template <typename CharacterType>
|
||||
+bool IsSubspan(base::span<const CharacterType> inner,
|
||||
+ base::span<const CharacterType> outer) {
|
||||
+ // Note that base::span uses CheckedContiguousIterator, which restricts
|
||||
+ // which comparisons are allowed. Therefore we must avoid begin()/end() here.
|
||||
+ return inner.data() >= outer.data() &&
|
||||
+ (inner.data() + inner.size()) <= (outer.data() + outer.size());
|
||||
+}
|
||||
+
|
||||
+bool TokenValueIsBacked(const CSSParserToken& token,
|
||||
+ const String& backing_string) {
|
||||
+ StringView value = token.Value();
|
||||
+ if (value.Is8Bit() != backing_string.Is8Bit())
|
||||
+ return false;
|
||||
+ return value.Is8Bit() ? IsSubspan(value.Span8(), backing_string.Span8())
|
||||
+ : IsSubspan(value.Span16(), backing_string.Span16());
|
||||
+}
|
||||
+
|
||||
+bool TokenValueIsBacked(const CSSParserToken& token,
|
||||
+ const Vector<String>& backing_strings) {
|
||||
+ DCHECK(token.HasStringBacking());
|
||||
+ for (const String& backing_string : backing_strings) {
|
||||
+ if (TokenValueIsBacked(token, backing_string)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
+void CSSVariableData::VerifyStringBacking() const {
|
||||
+ for (const CSSParserToken& token : tokens_) {
|
||||
+ DCHECK(!token.HasStringBacking() ||
|
||||
+ TokenValueIsBacked(token, backing_strings_))
|
||||
+ << "Token value is not backed: " << token.Value().ToString();
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#endif // EXPENSIVE_DCHECKS_ARE_ON()
|
||||
+
|
||||
CSSVariableData::CSSVariableData(const CSSTokenizedValue& tokenized_value,
|
||||
bool is_animation_tainted,
|
||||
bool needs_variable_resolution,
|
||||
@@ -120,6 +166,9 @@ CSSVariableData::CSSVariableData(const CSSTokenizedValue& tokenized_value,
|
||||
base_url_(base_url.IsValid() ? base_url.GetString() : String()),
|
||||
charset_(charset) {
|
||||
ConsumeAndUpdateTokens(tokenized_value.range);
|
||||
+#if EXPENSIVE_DCHECKS_ARE_ON()
|
||||
+ VerifyStringBacking();
|
||||
+#endif // EXPENSIVE_DCHECKS_ARE_ON()
|
||||
}
|
||||
|
||||
const CSSValue* CSSVariableData::ParseForSyntax(
|
||||
diff --git a/third_party/blink/renderer/core/css/css_variable_data.h b/third_party/blink/renderer/core/css/css_variable_data.h
|
||||
index f042f85736c2c49f8337c29cb742976c5e97a14b..7be7d201313ec3e591e2c45c9fd5bda327856645 100644
|
||||
--- a/third_party/blink/renderer/core/css/css_variable_data.h
|
||||
+++ b/third_party/blink/renderer/core/css/css_variable_data.h
|
||||
@@ -100,11 +100,18 @@ class CORE_EXPORT CSSVariableData : public RefCounted<CSSVariableData> {
|
||||
has_font_units_(has_font_units),
|
||||
has_root_font_units_(has_root_font_units),
|
||||
base_url_(base_url),
|
||||
- charset_(charset) {}
|
||||
+ charset_(charset) {
|
||||
+#if EXPENSIVE_DCHECKS_ARE_ON()
|
||||
+ VerifyStringBacking();
|
||||
+#endif // EXPENSIVE_DCHECKS_ARE_ON()
|
||||
+ }
|
||||
CSSVariableData(const CSSVariableData&) = delete;
|
||||
CSSVariableData& operator=(const CSSVariableData&) = delete;
|
||||
|
||||
void ConsumeAndUpdateTokens(const CSSParserTokenRange&);
|
||||
+#if EXPENSIVE_DCHECKS_ARE_ON()
|
||||
+ void VerifyStringBacking() const;
|
||||
+#endif // EXPENSIVE_DCHECKS_ARE_ON()
|
||||
|
||||
// tokens_ may have raw pointers to string data, we store the String objects
|
||||
// owning that data in backing_strings_ to keep it alive alongside the
|
||||
diff --git a/third_party/blink/renderer/core/css/parser/css_tokenizer.h b/third_party/blink/renderer/core/css/parser/css_tokenizer.h
|
||||
index 817bcbd4b6b9a9a5519bb92d6870c5b16a19278f..682a44a478bcd0ee3aa1638601650fd420033625 100644
|
||||
--- a/third_party/blink/renderer/core/css/parser/css_tokenizer.h
|
||||
+++ b/third_party/blink/renderer/core/css/parser/css_tokenizer.h
|
||||
@@ -33,6 +33,7 @@ class CORE_EXPORT CSSTokenizer {
|
||||
wtf_size_t Offset() const { return input_.Offset(); }
|
||||
wtf_size_t PreviousOffset() const { return prev_offset_; }
|
||||
StringView StringRangeAt(wtf_size_t start, wtf_size_t length) const;
|
||||
+ const Vector<String>& StringPool() const { return string_pool_; }
|
||||
|
||||
private:
|
||||
CSSParserToken TokenizeSingle();
|
||||
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
|
||||
index 6739b9de4b500d6173c04966905e26f856594502..f0082d88d70d4ea76604cfac77c09727de134f2a 100644
|
||||
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
|
||||
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
|
||||
@@ -2176,6 +2176,10 @@ StyleBuilderConverter::ConvertRegisteredPropertyVariableData(
|
||||
|
||||
Vector<String> backing_strings;
|
||||
backing_strings.push_back(text);
|
||||
+ // CSSTokenizer may allocate new strings for some tokens (e.g. for escapes)
|
||||
+ // and produce tokens that point to those strings. We need to retain those
|
||||
+ // strings (if any) as well.
|
||||
+ backing_strings.AppendVector(tokenizer.StringPool());
|
||||
|
||||
const bool has_font_units = false;
|
||||
const bool has_root_font_units = false;
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html
|
||||
index f03b257246e520bd93055203a5cb27188babc8ca..168495247a3b16a2203fb361f662b6db83044d09 100644
|
||||
--- a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html
|
||||
+++ b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html
|
||||
@@ -167,4 +167,6 @@ test_computed_value('<resolution>', '1dppx', '1dppx');
|
||||
test_computed_value('<resolution>', '96dpi', '1dppx');
|
||||
test_computed_value('<resolution>', 'calc(1dppx + 96dpi)', '2dppx');
|
||||
|
||||
+test_computed_value('*', 'url(why)', 'url(why)');
|
||||
+
|
||||
</script>
|
||||
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt
|
||||
index 3823a752b99f506d11c50aee36474c6c51c849cd..eeed0dfc0def17b1ba636f7f6a076caf770e1327 100644
|
||||
--- a/third_party/blink/web_tests/platform/generic/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt
|
||||
+++ b/third_party/blink/web_tests/platform/generic/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt
|
||||
@@ -1,5 +1,5 @@
|
||||
This is a testharness.js-based test.
|
||||
-Found 60 tests; 59 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
|
||||
+Found 61 tests; 60 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
|
||||
PASS <length> values computed are correctly via var()-reference
|
||||
PASS <length> values computed are correctly via var()-reference when font-size is inherited
|
||||
PASS <length> values are computed correctly when font-size is inherited [14em]
|
||||
@@ -60,5 +60,6 @@ PASS * values are computed correctly [50dpi]
|
||||
PASS <resolution> values are computed correctly [1dppx]
|
||||
PASS <resolution> values are computed correctly [96dpi]
|
||||
FAIL <resolution> values are computed correctly [calc(1dppx + 96dpi)] assert_equals: expected "2dppx" but got "0dppx"
|
||||
+PASS * values are computed correctly [url(why)]
|
||||
Harness: the test ran to completion.
|
||||
|
||||
29
patches/chromium/cherry-pick-2083e894852c.patch
Normal file
29
patches/chromium/cherry-pick-2083e894852c.patch
Normal file
@@ -0,0 +1,29 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Anton Bikineev <bikineev@chromium.org>
|
||||
Date: Sun, 10 Jul 2022 22:17:03 +0000
|
||||
Subject: Fix heap-overflow in blink::TableLayoutAlgorithmAuto::InsertSpanCell
|
||||
|
||||
The CL fixes size confusion between Member<> and raw pointers.
|
||||
|
||||
The bug was found (and the fix was proposed) by m.cooolie@gmail.com.
|
||||
|
||||
Bug: 1341539
|
||||
Change-Id: I99d524fd65c2d6305693d09ad274c23178271269
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3751138
|
||||
Reviewed-by: Kentaro Hara <haraken@chromium.org>
|
||||
Commit-Queue: Anton Bikineev <bikineev@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1022529}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc b/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
|
||||
index 1e1575cf47027584a9d06d7c5f6046fa15990b10..1a4a06a4761c52b8dd9ae9052b7c51b9236694a5 100644
|
||||
--- a/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
|
||||
+++ b/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
|
||||
@@ -673,7 +673,7 @@ void TableLayoutAlgorithmAuto::InsertSpanCell(LayoutTableCell* cell) {
|
||||
span > span_cells_[pos]->ColSpan())
|
||||
pos++;
|
||||
memmove(span_cells_.data() + pos + 1, span_cells_.data() + pos,
|
||||
- (size - pos - 1) * sizeof(LayoutTableCell*));
|
||||
+ (size - pos - 1) * sizeof(decltype(span_cells_)::value_type));
|
||||
span_cells_[pos] = cell;
|
||||
}
|
||||
|
||||
364
patches/chromium/cherry-pick-2ef09109c0ec.patch
Normal file
364
patches/chromium/cherry-pick-2ef09109c0ec.patch
Normal file
@@ -0,0 +1,364 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jun Kokatsu <jkokatsu@google.com>
|
||||
Date: Thu, 22 Sep 2022 22:16:55 +0000
|
||||
Subject: Unify security check for Javascript URL navigation
|
||||
|
||||
This change unifies CSP and Trusted Types check for Javascript URL
|
||||
navigations.
|
||||
|
||||
Bug: 1365082
|
||||
Change-Id: I46aea31a918c6397ea71fd5ab345bc9dc19d91c2
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3905476
|
||||
Auto-Submit: Jun Kokatsu <jkokatsu@google.com>
|
||||
Commit-Queue: Jun Kokatsu <jkokatsu@google.com>
|
||||
Reviewed-by: Nate Chapin <japhet@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1050416}
|
||||
|
||||
diff --git a/third_party/blink/renderer/bindings/core/v8/script_controller.cc b/third_party/blink/renderer/bindings/core/v8/script_controller.cc
|
||||
index 5ad3d687829db7ed64424b0f593e3aab7951e37e..da289bc7ffc4416ad817b0f344bc24cc0f084582 100644
|
||||
--- a/third_party/blink/renderer/bindings/core/v8/script_controller.cc
|
||||
+++ b/third_party/blink/renderer/bindings/core/v8/script_controller.cc
|
||||
@@ -164,34 +164,9 @@ void ScriptController::ExecuteJavaScriptURL(
|
||||
const DOMWrapperWorld* world_for_csp) {
|
||||
DCHECK(url.ProtocolIsJavaScript());
|
||||
|
||||
- const int kJavascriptSchemeLength = sizeof("javascript:") - 1;
|
||||
- String script_source = DecodeURLEscapeSequences(
|
||||
- url.GetString(), DecodeURLMode::kUTF8OrIsomorphic);
|
||||
-
|
||||
if (!window_->GetFrame())
|
||||
return;
|
||||
|
||||
- auto* policy = window_->GetContentSecurityPolicyForWorld(world_for_csp);
|
||||
- if (csp_disposition == network::mojom::CSPDisposition::CHECK &&
|
||||
- !policy->AllowInline(ContentSecurityPolicy::InlineType::kNavigation,
|
||||
- nullptr, script_source, String() /* nonce */,
|
||||
- window_->Url(), EventHandlerPosition().line_)) {
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- // TODO(crbug.com/896041): Investigate how trusted type checks can be
|
||||
- // implemented for isolated worlds.
|
||||
- const bool should_bypass_trusted_type_check =
|
||||
- csp_disposition == network::mojom::CSPDisposition::DO_NOT_CHECK ||
|
||||
- ContentSecurityPolicy::ShouldBypassMainWorldDeprecated(world_for_csp);
|
||||
- script_source = script_source.Substring(kJavascriptSchemeLength);
|
||||
- if (!should_bypass_trusted_type_check) {
|
||||
- script_source = TrustedTypesCheckForJavascriptURLinNavigation(
|
||||
- script_source, window_.Get());
|
||||
- if (script_source.IsEmpty())
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
bool had_navigation_before =
|
||||
window_->GetFrame()->Loader().HasProvisionalNavigation();
|
||||
|
||||
@@ -199,6 +174,9 @@ void ScriptController::ExecuteJavaScriptURL(
|
||||
// Step 6. "Let baseURL be settings's API base URL." [spec text]
|
||||
const KURL base_url = window_->BaseURL();
|
||||
|
||||
+ String script_source = window_->CheckAndGetJavascriptUrl(
|
||||
+ world_for_csp, url, nullptr /* element */, csp_disposition);
|
||||
+
|
||||
// Step 7. "Let script be the result of creating a classic script given
|
||||
// scriptSource, settings, baseURL, and the default classic script fetch
|
||||
// options." [spec text]
|
||||
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
|
||||
index 2f0615ee1454946d6f46f6626ce9b860a0e04fee..3eab00e4410e749aecdf600097cb68df22dcf072 100644
|
||||
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
|
||||
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
|
||||
@@ -415,6 +415,39 @@ bool LocalDOMWindow::CanExecuteScripts(
|
||||
return script_enabled;
|
||||
}
|
||||
|
||||
+String LocalDOMWindow::CheckAndGetJavascriptUrl(
|
||||
+ const DOMWrapperWorld* world,
|
||||
+ const KURL& url,
|
||||
+ Element* element,
|
||||
+ network::mojom::CSPDisposition csp_disposition) {
|
||||
+ const int kJavascriptSchemeLength = sizeof("javascript:") - 1;
|
||||
+ String decoded_url = DecodeURLEscapeSequences(
|
||||
+ url.GetString(), DecodeURLMode::kUTF8OrIsomorphic);
|
||||
+ String script_source = decoded_url.Substring(kJavascriptSchemeLength);
|
||||
+
|
||||
+ if (csp_disposition == network::mojom::CSPDisposition::DO_NOT_CHECK)
|
||||
+ return script_source;
|
||||
+
|
||||
+ // Check the CSP of the caller (the "source browsing context") if required,
|
||||
+ // as per https://html.spec.whatwg.org/C/#javascript-protocol.
|
||||
+ if (!GetContentSecurityPolicyForWorld(world)->AllowInline(
|
||||
+ ContentSecurityPolicy::InlineType::kNavigation, element, decoded_url,
|
||||
+ String() /* nonce */, Url(), OrdinalNumber::First()))
|
||||
+ return String();
|
||||
+
|
||||
+ // TODO(crbug.com/896041): Investigate how trusted type checks can be
|
||||
+ // implemented for isolated worlds.
|
||||
+ if (ContentSecurityPolicy::ShouldBypassMainWorldDeprecated(world))
|
||||
+ return script_source;
|
||||
+
|
||||
+ // https://w3c.github.io/webappsec-trusted-types/dist/spec/#require-trusted-types-for-pre-navigation-check
|
||||
+ // 4.9.1.1. require-trusted-types-for Pre-Navigation check
|
||||
+ script_source =
|
||||
+ TrustedTypesCheckForJavascriptURLinNavigation(script_source, this);
|
||||
+
|
||||
+ return script_source;
|
||||
+}
|
||||
+
|
||||
void LocalDOMWindow::ExceptionThrown(ErrorEvent* event) {
|
||||
MainThreadDebugger::Instance()->ExceptionThrown(this, event);
|
||||
}
|
||||
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h
|
||||
index dcc065abe83948ca3d906f676365226dd82c732d..da06213cfbe2bd156509cd1ff67d600d528c34b0 100644
|
||||
--- a/third_party/blink/renderer/core/frame/local_dom_window.h
|
||||
+++ b/third_party/blink/renderer/core/frame/local_dom_window.h
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include "services/metrics/public/cpp/ukm_recorder.h"
|
||||
#include "services/metrics/public/cpp/ukm_source_id.h"
|
||||
+#include "services/network/public/mojom/content_security_policy.mojom-blink.h"
|
||||
#include "third_party/blink/public/common/frame/fullscreen_request_token.h"
|
||||
#include "third_party/blink/public/common/frame/payment_request_token.h"
|
||||
#include "third_party/blink/public/common/metrics/post_message_counter.h"
|
||||
@@ -211,6 +212,16 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
|
||||
mojom::blink::PermissionsPolicyFeature feature,
|
||||
UseCounterImpl::PermissionsPolicyUsageType type);
|
||||
|
||||
+ // Checks if navigation to Javascript URL is allowed. This check should run
|
||||
+ // before any action is taken (e.g. creating new window) for all
|
||||
+ // same-origin navigations.
|
||||
+ String CheckAndGetJavascriptUrl(
|
||||
+ const DOMWrapperWorld* world,
|
||||
+ const KURL& url,
|
||||
+ Element* element,
|
||||
+ network::mojom::CSPDisposition csp_disposition =
|
||||
+ network::mojom::CSPDisposition::CHECK);
|
||||
+
|
||||
Document* InstallNewDocument(const DocumentInit&);
|
||||
|
||||
// EventTarget overrides:
|
||||
diff --git a/third_party/blink/renderer/core/frame/location.cc b/third_party/blink/renderer/core/frame/location.cc
|
||||
index a1aeede568cfe33267d87fa68f096d20a83d50f9..92740842827d470d63da34dd90bdb937321c1a83 100644
|
||||
--- a/third_party/blink/renderer/core/frame/location.cc
|
||||
+++ b/third_party/blink/renderer/core/frame/location.cc
|
||||
@@ -270,23 +270,6 @@ void Location::SetLocation(const String& url,
|
||||
return;
|
||||
}
|
||||
|
||||
- // Check the source browsing context's CSP to fulfill the CSP check
|
||||
- // requirement of https://html.spec.whatwg.org/C/#navigate for javascript
|
||||
- // URLs. Although the spec states we should perform this check on task
|
||||
- // execution, there are concerns about the correctness of that statement,
|
||||
- // see http://github.com/whatwg/html/issues/2591.
|
||||
- if (completed_url.ProtocolIsJavaScript()) {
|
||||
- String script_source = DecodeURLEscapeSequences(
|
||||
- completed_url.GetString(), DecodeURLMode::kUTF8OrIsomorphic);
|
||||
- if (!incumbent_window->GetContentSecurityPolicyForCurrentWorld()
|
||||
- ->AllowInline(ContentSecurityPolicy::InlineType::kNavigation,
|
||||
- nullptr /* element */, script_source,
|
||||
- String() /* nonce */, incumbent_window->Url(),
|
||||
- OrdinalNumber::First())) {
|
||||
- return;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
V8DOMActivityLogger* activity_logger =
|
||||
V8DOMActivityLogger::CurrentActivityLoggerIfIsolatedWorld();
|
||||
if (activity_logger) {
|
||||
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
|
||||
index e2398389b2064f0d804977ea9f5233cf34da5dae..49601b48571fbaebda29b6c2848a65275e4fd861 100644
|
||||
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
|
||||
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
|
||||
@@ -547,19 +547,12 @@ bool FrameLoader::AllowRequestForThisFrame(const FrameLoadRequest& request) {
|
||||
|
||||
const KURL& url = request.GetResourceRequest().Url();
|
||||
if (url.ProtocolIsJavaScript()) {
|
||||
- // Check the CSP of the caller (the "source browsing context") if required,
|
||||
- // as per https://html.spec.whatwg.org/C/#javascript-protocol.
|
||||
- bool javascript_url_is_allowed =
|
||||
- request.GetOriginWindow()
|
||||
- ->GetContentSecurityPolicyForWorld(request.JavascriptWorld().get())
|
||||
- ->AllowInline(ContentSecurityPolicy::InlineType::kNavigation,
|
||||
- frame_->DeprecatedLocalOwner(), url.GetString(),
|
||||
- String() /* nonce */,
|
||||
- request.GetOriginWindow()->Url(),
|
||||
- OrdinalNumber::First());
|
||||
-
|
||||
- if (!javascript_url_is_allowed)
|
||||
+ if (request.GetOriginWindow()
|
||||
+ ->CheckAndGetJavascriptUrl(request.JavascriptWorld().get(), url,
|
||||
+ frame_->DeprecatedLocalOwner())
|
||||
+ .IsEmpty()) {
|
||||
return false;
|
||||
+ }
|
||||
|
||||
if (frame_->Owner() && ((frame_->Owner()->GetFramePolicy().sandbox_flags &
|
||||
network::mojom::blink::WebSandboxFlags::kOrigin) !=
|
||||
diff --git a/third_party/blink/renderer/core/page/create_window.cc b/third_party/blink/renderer/core/page/create_window.cc
|
||||
index c526aab02f300a32404253537df6ff6c506664f8..36796587c96a51bc90f460def64358ec9788c72e 100644
|
||||
--- a/third_party/blink/renderer/core/page/create_window.cc
|
||||
+++ b/third_party/blink/renderer/core/page/create_window.cc
|
||||
@@ -294,15 +294,11 @@ Frame* CreateNewWindow(LocalFrame& opener_frame,
|
||||
request.SetFrameType(mojom::RequestContextFrameType::kAuxiliary);
|
||||
|
||||
const KURL& url = request.GetResourceRequest().Url();
|
||||
- auto* csp_for_world = opener_window.GetContentSecurityPolicyForCurrentWorld();
|
||||
- if (url.ProtocolIsJavaScript() && csp_for_world) {
|
||||
- String script_source = DecodeURLEscapeSequences(
|
||||
- url.GetString(), DecodeURLMode::kUTF8OrIsomorphic);
|
||||
-
|
||||
- if (!csp_for_world->AllowInline(
|
||||
- ContentSecurityPolicy::InlineType::kNavigation,
|
||||
- nullptr /* element */, script_source, String() /* nonce */,
|
||||
- opener_window.Url(), OrdinalNumber::First())) {
|
||||
+ if (url.ProtocolIsJavaScript()) {
|
||||
+ if (opener_window
|
||||
+ .CheckAndGetJavascriptUrl(request.JavascriptWorld().get(), url,
|
||||
+ nullptr /* element */)
|
||||
+ .IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/support/frame-without-trusted-types.html b/third_party/blink/web_tests/external/wpt/trusted-types/support/frame-without-trusted-types.html
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..25cf073e79fa48f4311c3729f0b39d9be2a64e7c
|
||||
--- /dev/null
|
||||
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/support/frame-without-trusted-types.html
|
||||
@@ -0,0 +1,6 @@
|
||||
+<!DOCTYPE html>
|
||||
+<head>
|
||||
+</head>
|
||||
+<body>
|
||||
+</body>
|
||||
+</html>
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-report-only-support.html b/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-report-only-support.html
|
||||
index d00d0538753a74411feeec42d5682082031c09d4..5f7856fabb7bb16085ffaffffbf6d7553179e8f3 100644
|
||||
--- a/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-report-only-support.html
|
||||
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-report-only-support.html
|
||||
@@ -5,7 +5,8 @@
|
||||
<p>Support page for trusted-types-navigation-report-only.*.html tests.</p>
|
||||
<a id="anchor" href="#">link</a>
|
||||
<script>
|
||||
- if (location.search == "?defaultpolicy") {
|
||||
+ const params = new URLSearchParams(location.search);
|
||||
+ if (!!params.get("defaultpolicy")) {
|
||||
trustedTypes.createPolicy("default", {
|
||||
createScript: s => s.replace("continue", "defaultpolicywashere"),
|
||||
});
|
||||
@@ -36,9 +37,17 @@
|
||||
// won't disturb delivery of that event to the opener.
|
||||
const anchor = document.getElementById("anchor");
|
||||
anchor.href = target;
|
||||
+
|
||||
+ if (!!params.get("frame")) {
|
||||
+ const frame = document.createElement("iframe");
|
||||
+ frame.src = "frame-without-trusted-types.html";
|
||||
+ frames.name = "frame";
|
||||
+ document.body.appendChild(frame);
|
||||
+ anchor.target = "frame";
|
||||
+ }
|
||||
+
|
||||
if (!location.hash) {
|
||||
document.addEventListener("DOMContentLoaded", _ => anchor.click());
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
-
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-support.html b/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-support.html
|
||||
index cd41f3968e7c74f84a7541506053808073ce541d..5e02e6d4bf5aff9fa4f0b4b897a35726ed24168b 100644
|
||||
--- a/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-support.html
|
||||
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-support.html
|
||||
@@ -5,7 +5,8 @@
|
||||
<p>Support page for trusted-types-navigation.*.html tests.</p>
|
||||
<a id="anchor" href="#">link</a>
|
||||
<script>
|
||||
- if (location.search == "?defaultpolicy") {
|
||||
+ const params = new URLSearchParams(location.search);
|
||||
+ if (!!params.get("defaultpolicy")) {
|
||||
trustedTypes.createPolicy("default", {
|
||||
createScript: s => s.replace("continue", "defaultpolicywashere"),
|
||||
});
|
||||
@@ -35,8 +36,16 @@
|
||||
|
||||
const anchor = document.getElementById("anchor");
|
||||
anchor.href = target;
|
||||
+
|
||||
+ if (!!params.get("frame")) {
|
||||
+ const frame = document.createElement("iframe");
|
||||
+ frame.src = "frame-without-trusted-types.html";
|
||||
+ frames.name = "frame";
|
||||
+ document.body.appendChild(frame);
|
||||
+ anchor.target = "frame";
|
||||
+ }
|
||||
+
|
||||
if (!location.hash)
|
||||
document.addEventListener("DOMContentLoaded", _ => anchor.click());
|
||||
</script>
|
||||
</body>
|
||||
-
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-navigation.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-navigation.tentative.html
|
||||
index 4e784611dd64ecf2f9995403b1d4e5a19f8b4548..2113711902ae787cb3ad5d0e44eaed0fc2e99b87 100644
|
||||
--- a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-navigation.tentative.html
|
||||
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-navigation.tentative.html
|
||||
@@ -38,10 +38,10 @@
|
||||
}, "Navigate a window with javascript:-urls in enforcing mode.");
|
||||
|
||||
promise_test(t => {
|
||||
- openWindow(t, "support/navigation-support.html?defaultpolicy");
|
||||
+ openWindow(t, "support/navigation-support.html?defaultpolicy=1");
|
||||
return Promise.all([
|
||||
- expectLoadedAsMessage("navigation-support.html?defaultpolicy"),
|
||||
- expectLoadedAsMessage("navigation-support.html?defaultpolicy&defaultpolicywashere"),
|
||||
+ expectLoadedAsMessage("navigation-support.html?defaultpolicy=1"),
|
||||
+ expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&defaultpolicywashere"),
|
||||
]);
|
||||
}, "Navigate a window with javascript:-urls w/ default policy in enforcing mode.");
|
||||
|
||||
@@ -55,12 +55,46 @@
|
||||
}, "Navigate a window with javascript:-urls in report-only mode.");
|
||||
|
||||
promise_test(t => {
|
||||
- const page = "navigation-report-only-support.html?defaultpolicy";
|
||||
+ const page = "navigation-report-only-support.html?defaultpolicy=1";
|
||||
openWindow(t, `support/${page}`);
|
||||
return Promise.all([
|
||||
expectLoadedAsMessage(page),
|
||||
- expectLoadedAsMessage("navigation-support.html?defaultpolicy#defaultpolicywashere"),
|
||||
+ expectLoadedAsMessage("navigation-support.html?defaultpolicy=1#defaultpolicywashere"),
|
||||
]);
|
||||
}, "Navigate a window with javascript:-urls w/ default policy in report-only mode.");
|
||||
+
|
||||
+ promise_test(t => {
|
||||
+ openWindow(t, "support/navigation-support.html?frame=1");
|
||||
+ return Promise.all([
|
||||
+ expectLoadedAsMessage("navigation-support.html?frame=1"),
|
||||
+ expectViolationAsMessage("Location href"),
|
||||
+ ]);
|
||||
+ }, "Navigate a frame with javascript:-urls in enforcing mode.");
|
||||
+
|
||||
+ promise_test(t => {
|
||||
+ openWindow(t, "support/navigation-support.html?defaultpolicy=1&frame=1");
|
||||
+ return Promise.all([
|
||||
+ expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&frame=1"),
|
||||
+ expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&frame=1&defaultpolicywashere"),
|
||||
+ ]);
|
||||
+ }, "Navigate a frame with javascript:-urls w/ default policy in enforcing mode.");
|
||||
+
|
||||
+ promise_test(t => {
|
||||
+ const page = "navigation-report-only-support.html?frame=1"
|
||||
+ openWindow(t, `support/${page}`);
|
||||
+ return Promise.all([
|
||||
+ expectLoadedAsMessage(page),
|
||||
+ expectLoadedAsMessage("navigation-support.html?frame=1#continue"),
|
||||
+ ]);
|
||||
+ }, "Navigate a frame with javascript:-urls in report-only mode.");
|
||||
+
|
||||
+ promise_test(t => {
|
||||
+ const page = "navigation-report-only-support.html?defaultpolicy=1&frame=1";
|
||||
+ openWindow(t, `support/${page}`);
|
||||
+ return Promise.all([
|
||||
+ expectLoadedAsMessage(page),
|
||||
+ expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&frame=1#defaultpolicywashere"),
|
||||
+ ]);
|
||||
+ }, "Navigate a frame with javascript:-urls w/ default policy in report-only mode.");
|
||||
</script>
|
||||
</body>
|
||||
115
patches/chromium/cherry-pick-42e15c2055c4.patch
Normal file
115
patches/chromium/cherry-pick-42e15c2055c4.patch
Normal file
@@ -0,0 +1,115 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Joey Arhar <jarhar@chromium.org>
|
||||
Date: Tue, 22 Nov 2022 00:12:31 +0000
|
||||
Subject: Avoid use-after-free in ValidationMessageOverlayDelegate
|
||||
|
||||
When ValidationMessageOverlayDelegate calls
|
||||
ForceSynchronousDocumentInstall, it can somehow cause another validation
|
||||
overlay to be created and delete the ValidationMessageOverlayDelegate.
|
||||
This patch avoids additional code from being run inside the deleted
|
||||
ValidationMessageOverlayDelegate.
|
||||
|
||||
(cherry picked from commit a37b66ded21af7ff1442bddd2ec3a0845535b3d6)
|
||||
|
||||
Fixed: 1382581
|
||||
Change-Id: I044f91ecb55c77c4a5c40030b6856fc9a8ac7f6f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4019655
|
||||
Reviewed-by: David Baron <dbaron@chromium.org>
|
||||
Commit-Queue: Joey Arhar <jarhar@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1071652}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4043489
|
||||
Commit-Queue: David Baron <dbaron@chromium.org>
|
||||
Auto-Submit: Joey Arhar <jarhar@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5359@{#911}
|
||||
Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc b/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc
|
||||
index 33575769b1fa9361c91d27815832f467f7a7f19c..a8a1df886fd8accfdf9fcf9d06ba24e11f16293a 100644
|
||||
--- a/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc
|
||||
+++ b/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc
|
||||
@@ -85,6 +85,8 @@ ValidationMessageOverlayDelegate::~ValidationMessageOverlayDelegate() {
|
||||
EventDispatchForbiddenScope::AllowUserAgentEvents allow_events;
|
||||
page_->WillBeDestroyed();
|
||||
}
|
||||
+ if (destroyed_ptr_)
|
||||
+ *destroyed_ptr_ = true;
|
||||
}
|
||||
|
||||
LocalFrameView& ValidationMessageOverlayDelegate::FrameView() const {
|
||||
@@ -175,7 +177,18 @@ void ValidationMessageOverlayDelegate::CreatePage(const FrameOverlay& overlay) {
|
||||
WriteDocument(data.get());
|
||||
float zoom_factor = anchor_->GetDocument().GetFrame()->PageZoomFactor();
|
||||
frame->SetPageZoomFactor(zoom_factor);
|
||||
+
|
||||
+ // ForceSynchronousDocumentInstall can cause another call to
|
||||
+ // ValidationMessageClientImpl::ShowValidationMessage, which will hide this
|
||||
+ // validation message and may even delete this. In order to avoid continuing
|
||||
+ // when this is destroyed, |destroyed| will be set to true in the destructor.
|
||||
+ bool destroyed = false;
|
||||
+ DCHECK(!destroyed_ptr_);
|
||||
+ destroyed_ptr_ = &destroyed;
|
||||
frame->ForceSynchronousDocumentInstall("text/html", data);
|
||||
+ if (destroyed)
|
||||
+ return;
|
||||
+ destroyed_ptr_ = nullptr;
|
||||
|
||||
Element& main_message = GetElementById("main-message");
|
||||
main_message.setTextContent(message_);
|
||||
diff --git a/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h b/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h
|
||||
index 9db786a4fbd12bc6aeefc520143f872965ad7df8..26e96d8ffad11938dcc3dc5b059f2c7ebf077b94 100644
|
||||
--- a/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h
|
||||
+++ b/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h
|
||||
@@ -72,6 +72,10 @@ class CORE_EXPORT ValidationMessageOverlayDelegate
|
||||
String sub_message_;
|
||||
TextDirection message_dir_;
|
||||
TextDirection sub_message_dir_;
|
||||
+
|
||||
+ // Used by CreatePage() to determine if this has been deleted in the middle of
|
||||
+ // the function.
|
||||
+ bool* destroyed_ptr_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace blink
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/reportValidity-crash.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/reportValidity-crash.html
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..d6bab924adc9fb481235af10d706cbf4d4ef2df9
|
||||
--- /dev/null
|
||||
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/reportValidity-crash.html
|
||||
@@ -0,0 +1,37 @@
|
||||
+<!DOCTYPE html>
|
||||
+<html>
|
||||
+
|
||||
+<head>
|
||||
+<script>
|
||||
+Object.prototype.__defineGetter__('then', prom);
|
||||
+var prom_count = 0;
|
||||
+function prom() {
|
||||
+prom_count++;
|
||||
+if (prom_count > 2) return;
|
||||
+var v14 = x37.animate({},100);
|
||||
+v14.reverse();
|
||||
+v14.ready;
|
||||
+v14.currentTime = 0;
|
||||
+x57.reportValidity();
|
||||
+}
|
||||
+function f0() {
|
||||
+var v38 = x37.animate({},300);
|
||||
+v38.ready;
|
||||
+x57.prepend(x78);
|
||||
+}
|
||||
+function f1() {
|
||||
+var x57 = document.getElementById("x57");
|
||||
+x57.disabled = false;
|
||||
+}
|
||||
+</script>
|
||||
+</head>
|
||||
+
|
||||
+<body>
|
||||
+<fieldset id="x37">
|
||||
+<canvas onfocusin="f0()" >
|
||||
+<input id="x78" autofocus="" onfocusout="f1()" >
|
||||
+</canvas>
|
||||
+<select id="x57" disabled="" required=""></select>
|
||||
+</body>
|
||||
+
|
||||
+</html>
|
||||
104
patches/chromium/cherry-pick-43637378b14e.patch
Normal file
104
patches/chromium/cherry-pick-43637378b14e.patch
Normal file
@@ -0,0 +1,104 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Maks Orlovich <morlovich@chromium.org>
|
||||
Date: Tue, 22 Nov 2022 22:18:55 +0000
|
||||
Subject: Align NetworkContext::SetNetworkConditions better with devtools
|
||||
emulateNetworkConditions
|
||||
|
||||
The former used values of 0 to disable particular throttles, while the
|
||||
later documents -1, and looks to be pretty much a direct client, and the
|
||||
only one. So make NetworkService handle everything <= 0 as a disable,
|
||||
clamping at intake of config.
|
||||
|
||||
Bug: 1382033
|
||||
|
||||
(cherry picked from commit ce463c2c939818a12bbcec5e2c91c35f2a0a1f0e)
|
||||
|
||||
Change-Id: I2fd3f075d5071cb0cf647838782115b5c00405bf
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4035891
|
||||
Reviewed-by: Ken Buchanan <kenrb@chromium.org>
|
||||
Reviewed-by: Eric Orth <ericorth@chromium.org>
|
||||
Commit-Queue: Maks Orlovich <morlovich@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1073566}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4048289
|
||||
Cr-Commit-Position: refs/branch-heads/5414@{#188}
|
||||
Cr-Branched-From: 4417ee59d7bf6df7a9c9ea28f7722d2ee6203413-refs/heads/main@{#1070088}
|
||||
|
||||
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
|
||||
index b6a2ed2857ee9cb838542d76a5c3031a28483a8b..7f41b5a1cf98576bce93b14196cf7dfabf7aaa93 100644
|
||||
--- a/services/network/public/mojom/network_context.mojom
|
||||
+++ b/services/network/public/mojom/network_context.mojom
|
||||
@@ -554,11 +554,11 @@ struct NetworkConditions {
|
||||
// response received.
|
||||
mojo_base.mojom.TimeDelta latency;
|
||||
|
||||
- // Maximal aggregated download throughput (bytes/sec). 0 disables download
|
||||
+ // Maximal aggregated download throughput (bytes/sec). <=0 disables download
|
||||
// throttling.
|
||||
double download_throughput;
|
||||
|
||||
- // Maximal aggregated upload throughput (bytes/sec). 0 disables upload
|
||||
+ // Maximal aggregated upload throughput (bytes/sec). <=0 disables upload
|
||||
// throttling.
|
||||
double upload_throughput;
|
||||
};
|
||||
diff --git a/services/network/throttling/network_conditions.cc b/services/network/throttling/network_conditions.cc
|
||||
index 71cd4ac0e52cc1f262c5b58caf20448b57b6b64f..18b2b6e0efdc2e17dbbbfaa411b4ab49ec787bc4 100644
|
||||
--- a/services/network/throttling/network_conditions.cc
|
||||
+++ b/services/network/throttling/network_conditions.cc
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "services/network/throttling/network_conditions.h"
|
||||
|
||||
+#include <algorithm>
|
||||
+
|
||||
namespace network {
|
||||
|
||||
NetworkConditions::NetworkConditions() : NetworkConditions(false) {}
|
||||
@@ -16,9 +18,9 @@ NetworkConditions::NetworkConditions(bool offline,
|
||||
double download_throughput,
|
||||
double upload_throughput)
|
||||
: offline_(offline),
|
||||
- latency_(latency),
|
||||
- download_throughput_(download_throughput),
|
||||
- upload_throughput_(upload_throughput) {}
|
||||
+ latency_(std::max(latency, 0.0)),
|
||||
+ download_throughput_(std::max(download_throughput, 0.0)),
|
||||
+ upload_throughput_(std::max(upload_throughput, 0.0)) {}
|
||||
|
||||
NetworkConditions::~NetworkConditions() {}
|
||||
|
||||
diff --git a/services/network/throttling/network_conditions.h b/services/network/throttling/network_conditions.h
|
||||
index f8c8214b34bafcb1f656dd3a39a0cf17fea821ea..c5232231d308b09105234101f4bc575491505372 100644
|
||||
--- a/services/network/throttling/network_conditions.h
|
||||
+++ b/services/network/throttling/network_conditions.h
|
||||
@@ -28,6 +28,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkConditions {
|
||||
bool IsThrottling() const;
|
||||
|
||||
bool offline() const { return offline_; }
|
||||
+
|
||||
+ // These are 0 if the corresponding throttle is disabled, >0 otherwise.
|
||||
double latency() const { return latency_; }
|
||||
double download_throughput() const { return download_throughput_; }
|
||||
double upload_throughput() const { return upload_throughput_; }
|
||||
diff --git a/services/network/throttling/throttling_controller_unittest.cc b/services/network/throttling/throttling_controller_unittest.cc
|
||||
index fbe2c6d20d1d5362a77bd951e87b3fe41be13098..e834f8bdc13b5691b1e458dcafead482a0537e14 100644
|
||||
--- a/services/network/throttling/throttling_controller_unittest.cc
|
||||
+++ b/services/network/throttling/throttling_controller_unittest.cc
|
||||
@@ -297,7 +297,7 @@ TEST(ThrottlingControllerTest, DownloadOnly) {
|
||||
ThrottlingControllerTestHelper helper;
|
||||
TestCallback* callback = helper.callback();
|
||||
|
||||
- helper.SetNetworkState(false, 10000000, 0);
|
||||
+ helper.SetNetworkState(false, 10000000, -1);
|
||||
int rv = helper.Start(false);
|
||||
EXPECT_EQ(rv, net::ERR_IO_PENDING);
|
||||
helper.FastForwardUntilNoTasksRemain();
|
||||
@@ -316,7 +316,7 @@ TEST(ThrottlingControllerTest, UploadOnly) {
|
||||
ThrottlingControllerTestHelper helper;
|
||||
TestCallback* callback = helper.callback();
|
||||
|
||||
- helper.SetNetworkState(false, 0, 1000000);
|
||||
+ helper.SetNetworkState(false, -2, 1000000);
|
||||
int rv = helper.Start(true);
|
||||
EXPECT_EQ(rv, net::OK);
|
||||
helper.FastForwardUntilNoTasksRemain();
|
||||
45
patches/chromium/cherry-pick-51daffbf5cd8.patch
Normal file
45
patches/chromium/cherry-pick-51daffbf5cd8.patch
Normal file
@@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Yutaka Hirano <yhirano@chromium.org>
|
||||
Date: Mon, 4 Jul 2022 11:48:20 +0000
|
||||
Subject: Fix UAF on network::URLLoader
|
||||
|
||||
network::URLLoader::SetUpUpload calls NotifyCompleted asynchronously,
|
||||
as it can be called in the constructor and we don't want to run
|
||||
NotifyCompleted in the constructor.
|
||||
|
||||
The problem is that it attaches a raw pointer to the method, which leads to a use-after-free problem if the URLLoader is destructed before
|
||||
NotifyCompleted is called.
|
||||
|
||||
Use weak pointers instead of raw pointers to avoid the problem.
|
||||
|
||||
Bug: 1340253
|
||||
Change-Id: Iacb1e772bf7a8e3de4a7bb9de342fea9ba0f3f3c
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3740150
|
||||
Reviewed-by: Kenichi Ishibashi <bashi@chromium.org>
|
||||
Commit-Queue: Yutaka Hirano <yhirano@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1020539}
|
||||
|
||||
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
|
||||
index 62201fd4f11ce500b3a9d82fffe7776bf8a15eb0..433edfd8be00d912ffe482283d0e0d1b093b8039 100644
|
||||
--- a/services/network/url_loader.cc
|
||||
+++ b/services/network/url_loader.cc
|
||||
@@ -989,8 +989,8 @@ void URLLoader::OpenFilesForUpload(const ResourceRequest& request) {
|
||||
// initializing before getting deleted.
|
||||
base::SequencedTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE,
|
||||
- base::BindOnce(&URLLoader::NotifyCompleted, base::Unretained(this),
|
||||
- net::ERR_ACCESS_DENIED));
|
||||
+ base::BindOnce(&URLLoader::NotifyCompleted,
|
||||
+ weak_ptr_factory_.GetWeakPtr(), net::ERR_ACCESS_DENIED));
|
||||
return;
|
||||
}
|
||||
url_request_->LogBlockedBy("Opening Files");
|
||||
@@ -1009,7 +1009,7 @@ void URLLoader::SetUpUpload(const ResourceRequest& request,
|
||||
// initializing before getting deleted.
|
||||
base::SequencedTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, base::BindOnce(&URLLoader::NotifyCompleted,
|
||||
- base::Unretained(this), error_code));
|
||||
+ weak_ptr_factory_.GetWeakPtr(), error_code));
|
||||
return;
|
||||
}
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner =
|
||||
78
patches/chromium/cherry-pick-65ad70274d4b.patch
Normal file
78
patches/chromium/cherry-pick-65ad70274d4b.patch
Normal file
@@ -0,0 +1,78 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ilya Nikolaevskiy <ilnik@chromium.org>
|
||||
Date: Mon, 14 Nov 2022 12:33:49 +0000
|
||||
Subject: Fix UAF in VideoCaptureDeviceWin::FrameReceived
|
||||
|
||||
(cherry picked from commit d08a3822658cb4ca4261659f1487069a14b51bd9)
|
||||
|
||||
Bug: 1381401
|
||||
Change-Id: Ib742ec7b86d3c419f37f12694bf9cd5f3f03305c
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4013158
|
||||
Reviewed-by: Markus Handell <handellm@google.com>
|
||||
Commit-Queue: Ilya Nikolaevskiy <ilnik@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1069054}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4023295
|
||||
Cr-Commit-Position: refs/branch-heads/5359@{#809}
|
||||
Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933}
|
||||
|
||||
diff --git a/media/capture/video/win/video_capture_device_win.cc b/media/capture/video/win/video_capture_device_win.cc
|
||||
index df0aef940a007a594c328f10a2ea26e1d381505f..b220ded61ed5c501426ccc5c128dd4494c448b2f 100644
|
||||
--- a/media/capture/video/win/video_capture_device_win.cc
|
||||
+++ b/media/capture/video/win/video_capture_device_win.cc
|
||||
@@ -866,34 +866,35 @@ void VideoCaptureDeviceWin::FrameReceived(const uint8_t* buffer,
|
||||
const VideoCaptureFormat& format,
|
||||
base::TimeDelta timestamp,
|
||||
bool flip_y) {
|
||||
+ // We always calculate camera rotation for the first frame. We also cache
|
||||
+ // the latest value to use when AutoRotation is turned off.
|
||||
+ // To avoid potential deadlock, do this without holding a lock.
|
||||
+ if (!camera_rotation_.has_value() || IsAutoRotationEnabled())
|
||||
+ camera_rotation_ = GetCameraRotation(device_descriptor_.facing);
|
||||
+
|
||||
{
|
||||
base::AutoLock lock(lock_);
|
||||
if (state_ != kCapturing)
|
||||
return;
|
||||
- }
|
||||
|
||||
- if (first_ref_time_.is_null())
|
||||
- first_ref_time_ = base::TimeTicks::Now();
|
||||
+ if (first_ref_time_.is_null())
|
||||
+ first_ref_time_ = base::TimeTicks::Now();
|
||||
|
||||
- // There is a chance that the platform does not provide us with the timestamp,
|
||||
- // in which case, we use reference time to calculate a timestamp.
|
||||
- if (timestamp == kNoTimestamp)
|
||||
- timestamp = base::TimeTicks::Now() - first_ref_time_;
|
||||
+ // There is a chance that the platform does not provide us with the
|
||||
+ // timestamp, in which case, we use reference time to calculate a timestamp.
|
||||
+ if (timestamp == kNoTimestamp)
|
||||
+ timestamp = base::TimeTicks::Now() - first_ref_time_;
|
||||
|
||||
- // We always calculate camera rotation for the first frame. We also cache the
|
||||
- // latest value to use when AutoRotation is turned off.
|
||||
- if (!camera_rotation_.has_value() || IsAutoRotationEnabled())
|
||||
- camera_rotation_ = GetCameraRotation(device_descriptor_.facing);
|
||||
-
|
||||
- // TODO(julien.isorce): retrieve the color space information using the
|
||||
- // DirectShow api, AM_MEDIA_TYPE::VIDEOINFOHEADER2::dwControlFlags. If
|
||||
- // AMCONTROL_COLORINFO_PRESENT, then reinterpret dwControlFlags as a
|
||||
- // DXVA_ExtendedFormat. Then use its fields DXVA_VideoPrimaries,
|
||||
- // DXVA_VideoTransferMatrix, DXVA_VideoTransferFunction and
|
||||
- // DXVA_NominalRangeto build a gfx::ColorSpace. See http://crbug.com/959992.
|
||||
- client_->OnIncomingCapturedData(buffer, length, format, gfx::ColorSpace(),
|
||||
- camera_rotation_.value(), flip_y,
|
||||
- base::TimeTicks::Now(), timestamp);
|
||||
+ // TODO(julien.isorce): retrieve the color space information using the
|
||||
+ // DirectShow api, AM_MEDIA_TYPE::VIDEOINFOHEADER2::dwControlFlags. If
|
||||
+ // AMCONTROL_COLORINFO_PRESENT, then reinterpret dwControlFlags as a
|
||||
+ // DXVA_ExtendedFormat. Then use its fields DXVA_VideoPrimaries,
|
||||
+ // DXVA_VideoTransferMatrix, DXVA_VideoTransferFunction and
|
||||
+ // DXVA_NominalRangeto build a gfx::ColorSpace. See http://crbug.com/959992.
|
||||
+ client_->OnIncomingCapturedData(buffer, length, format, gfx::ColorSpace(),
|
||||
+ camera_rotation_.value(), flip_y,
|
||||
+ base::TimeTicks::Now(), timestamp);
|
||||
+ }
|
||||
|
||||
while (!take_photo_callbacks_.empty()) {
|
||||
TakePhotoCallback cb = std::move(take_photo_callbacks_.front());
|
||||
115
patches/chromium/cherry-pick-65d46507a0c9.patch
Normal file
115
patches/chromium/cherry-pick-65d46507a0c9.patch
Normal file
@@ -0,0 +1,115 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: evliu <evliu@google.com>
|
||||
Date: Mon, 14 Nov 2022 20:05:12 +0000
|
||||
Subject: Replace raw pointer to LocalMuter with weak ptr
|
||||
|
||||
This CL replaces a raw pointer to LocalMuter with a weak ptr. Additional
|
||||
info about this bug here: http://crbug/1377783
|
||||
|
||||
(cherry picked from commit 9989b93eb12c93b9351d5bf2872c1069ef5f7d01)
|
||||
|
||||
Bug: 1377783
|
||||
Change-Id: Id821ea800ba12f1cfae4677fc591c12dec112852
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3997421
|
||||
Reviewed-by: Paul Semel <paulsemel@chromium.org>
|
||||
Reviewed-by: Olga Sharonova <olka@chromium.org>
|
||||
Commit-Queue: Evan Liu <evliu@google.com>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1068776}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4024547
|
||||
Auto-Submit: Evan Liu <evliu@google.com>
|
||||
Owners-Override: Srinivas Sista <srinivassista@chromium.org>
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Reviewed-by: Evan Liu <evliu@google.com>
|
||||
Cr-Commit-Position: refs/branch-heads/5359@{#824}
|
||||
Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933}
|
||||
|
||||
diff --git a/services/audio/local_muter.h b/services/audio/local_muter.h
|
||||
index a484c7dfd60883b07c8fc61da768edf508ac53af..b108e32306a264be4d51027c4419efc70a5dbe0c 100644
|
||||
--- a/services/audio/local_muter.h
|
||||
+++ b/services/audio/local_muter.h
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
+#include "base/memory/weak_ptr.h"
|
||||
#include "base/sequence_checker.h"
|
||||
#include "base/unguessable_token.h"
|
||||
#include "media/mojo/mojom/audio_stream_factory.mojom.h"
|
||||
@@ -46,6 +47,8 @@ class LocalMuter final : public media::mojom::LocalMuter,
|
||||
|
||||
bool HasReceivers() { return !receivers_.empty(); }
|
||||
|
||||
+ base::WeakPtr<LocalMuter> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
|
||||
+
|
||||
private:
|
||||
// Runs the |all_bindings_lost_callback_| when |bindings_| becomes empty.
|
||||
void OnBindingLost();
|
||||
@@ -57,6 +60,8 @@ class LocalMuter final : public media::mojom::LocalMuter,
|
||||
base::RepeatingClosure all_bindings_lost_callback_;
|
||||
|
||||
SEQUENCE_CHECKER(sequence_checker_);
|
||||
+
|
||||
+ base::WeakPtrFactory<LocalMuter> weak_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
diff --git a/services/audio/stream_factory.cc b/services/audio/stream_factory.cc
|
||||
index 48152cb64769ab1a76920d2581f373b57fef85c9..60ff2766809d4c43c021e47cfa5087b9dbe089b8 100644
|
||||
--- a/services/audio/stream_factory.cc
|
||||
+++ b/services/audio/stream_factory.cc
|
||||
@@ -181,8 +181,9 @@ void StreamFactory::BindMuter(
|
||||
if (it == muters_.end()) {
|
||||
auto muter_ptr = std::make_unique<LocalMuter>(&coordinator_, group_id);
|
||||
muter = muter_ptr.get();
|
||||
- muter->SetAllBindingsLostCallback(base::BindRepeating(
|
||||
- &StreamFactory::DestroyMuter, base::Unretained(this), muter));
|
||||
+ muter->SetAllBindingsLostCallback(
|
||||
+ base::BindRepeating(&StreamFactory::DestroyMuter,
|
||||
+ base::Unretained(this), muter_ptr->GetWeakPtr()));
|
||||
muters_.emplace_back(std::move(muter_ptr));
|
||||
} else {
|
||||
muter = it->get();
|
||||
@@ -254,9 +255,10 @@ void StreamFactory::DestroyOutputStream(OutputStream* stream) {
|
||||
DCHECK_EQ(1u, erased);
|
||||
}
|
||||
|
||||
-void StreamFactory::DestroyMuter(LocalMuter* muter) {
|
||||
+void StreamFactory::DestroyMuter(base::WeakPtr<LocalMuter> muter) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
|
||||
- DCHECK(muter);
|
||||
+ if (!muter)
|
||||
+ return;
|
||||
|
||||
// Output streams have a task posting before destruction (see the OnError
|
||||
// function in output_stream.cc). To ensure that stream destruction and
|
||||
@@ -265,13 +267,11 @@ void StreamFactory::DestroyMuter(LocalMuter* muter) {
|
||||
// Otherwise, a "destroy all streams, then destroy the muter" sequence may
|
||||
// result in a brief blip of audio.
|
||||
auto do_destroy = [](base::WeakPtr<StreamFactory> weak_this,
|
||||
- LocalMuter* muter) {
|
||||
- if (weak_this) {
|
||||
-
|
||||
+ base::WeakPtr<LocalMuter> muter) {
|
||||
+ if (weak_this && muter) {
|
||||
const auto it =
|
||||
std::find_if(weak_this->muters_.begin(), weak_this->muters_.end(),
|
||||
- base::MatchesUniquePtr(muter));
|
||||
- DCHECK(it != weak_this->muters_.end());
|
||||
+ base::MatchesUniquePtr(muter.get()));
|
||||
|
||||
// The LocalMuter can still have receivers if a receiver was bound after
|
||||
// DestroyMuter is called but before the do_destroy task is run.
|
||||
diff --git a/services/audio/stream_factory.h b/services/audio/stream_factory.h
|
||||
index 2207c72cb39e666e5c207016035a9d295d708aa0..b6119025f043e433455b35ee71e2b130299d1d21 100644
|
||||
--- a/services/audio/stream_factory.h
|
||||
+++ b/services/audio/stream_factory.h
|
||||
@@ -110,7 +110,7 @@ class StreamFactory final : public media::mojom::AudioStreamFactory {
|
||||
|
||||
void DestroyInputStream(InputStream* stream);
|
||||
void DestroyOutputStream(OutputStream* stream);
|
||||
- void DestroyMuter(LocalMuter* muter);
|
||||
+ void DestroyMuter(base::WeakPtr<LocalMuter> muter);
|
||||
void DestroyLoopbackStream(LoopbackStream* stream);
|
||||
|
||||
SEQUENCE_CHECKER(owning_sequence_);
|
||||
46
patches/chromium/cherry-pick-65f0ef609c00.patch
Normal file
46
patches/chromium/cherry-pick-65f0ef609c00.patch
Normal file
@@ -0,0 +1,46 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Paicu <andypaicu@chromium.org>
|
||||
Date: Thu, 6 Oct 2022 21:04:23 +0000
|
||||
Subject: Fix UAF issue around permission status observer list
|
||||
|
||||
(cherry picked from commit 4df595127d95d4b0bf115be1ab4604d95b75273c)
|
||||
|
||||
(cherry picked from commit 1dc5dda6112bdd811c923520cc728a474583409e)
|
||||
|
||||
Bug: 1363040
|
||||
Change-Id: I1f64a901b83aa834ae652c8041456e9b7d253c1f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3907744
|
||||
Reviewed-by: Kamila Hasanbega <hkamila@chromium.org>
|
||||
Commit-Queue: Andy Paicu <andypaicu@chromium.org>
|
||||
Cr-Original-Original-Commit-Position: refs/heads/main@{#1049058}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3929034
|
||||
Reviewed-by: Illia Klimov <elklm@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/branch-heads/5304@{#483}
|
||||
Cr-Original-Branched-From: 5d7b1fc9cb7103d9c82eed647cf4be38cf09738b-refs/heads/main@{#1047731}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3936291
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/5249@{#764}
|
||||
Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/permissions/permission_status_listener.cc b/third_party/blink/renderer/modules/permissions/permission_status_listener.cc
|
||||
index 424314c1dd49bd693643e41adb537f7a9d01e5d2..946e28ac3139a1927ac36281f04cec9f5faf76d2 100644
|
||||
--- a/third_party/blink/renderer/modules/permissions/permission_status_listener.cc
|
||||
+++ b/third_party/blink/renderer/modules/permissions/permission_status_listener.cc
|
||||
@@ -62,7 +62,17 @@ void PermissionStatusListener::OnPermissionStatusChange(
|
||||
|
||||
status_ = status;
|
||||
|
||||
+ // The `observers_` list can change in response to permission status change
|
||||
+ // events as the observers map to PermissionStatus JS objects which can be
|
||||
+ // created and destroyed in the JS event handler function. To avoid UAF and
|
||||
+ // list modification issues, a temporary snapshot of the observers is made and
|
||||
+ // used instead.
|
||||
+ HeapHashSet<WeakMember<Observer>> observers;
|
||||
for (const auto& observer : observers_) {
|
||||
+ observers.insert(observer);
|
||||
+ }
|
||||
+
|
||||
+ for (const auto& observer : observers) {
|
||||
if (observer)
|
||||
observer->OnPermissionStatusChange(status);
|
||||
else
|
||||
622
patches/chromium/cherry-pick-67c9cbc784d6.patch
Normal file
622
patches/chromium/cherry-pick-67c9cbc784d6.patch
Normal file
@@ -0,0 +1,622 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Lukasz Anforowicz <lukasza@chromium.org>
|
||||
Date: Tue, 30 Aug 2022 19:18:15 +0000
|
||||
Subject: Validate `source_context` in ExtensionHostMsg_OpenChannelToNativeApp.
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
After this CL, the Browser process will verify `source_context` in the
|
||||
IPC payload of the ExtensionHostMsg_OpenChannelToNativeApp message and
|
||||
avoid processing malformed or spoofed IPCs.
|
||||
|
||||
Change-Id: I9466dc076c4d07dbb4bec38973000dc0418565f6
|
||||
Bug: 1356234
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3854987
|
||||
Commit-Queue: Łukasz Anforowicz <lukasza@chromium.org>
|
||||
Reviewed-by: Devlin Cronin <rdevlin.cronin@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1041118}
|
||||
|
||||
diff --git a/chrome/browser/extensions/extension_security_exploit_browsertest.cc b/chrome/browser/extensions/extension_security_exploit_browsertest.cc
|
||||
index 19c9c52fa5a796c93e80f77029727d64acfdfa07..4e5215739f8533d25831f3302515861df179525f 100644
|
||||
--- a/chrome/browser/extensions/extension_security_exploit_browsertest.cc
|
||||
+++ b/chrome/browser/extensions/extension_security_exploit_browsertest.cc
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/test/bind.h"
|
||||
+#include "build/build_config.h"
|
||||
#include "chrome/browser/chrome_content_browser_client.h"
|
||||
#include "chrome/browser/extensions/extension_browsertest.h"
|
||||
#include "chrome/browser/extensions/extension_tab_util.h"
|
||||
@@ -40,6 +41,10 @@
|
||||
#include "third_party/blink/public/mojom/service_worker/service_worker_database.mojom-forward.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
+#if !(BUILDFLAG(IS_FUCHSIA))
|
||||
+#include "chrome/browser/extensions/api/messaging/native_messaging_test_util.h"
|
||||
+#endif
|
||||
+
|
||||
namespace extensions {
|
||||
|
||||
// Waits for a kill of the given RenderProcessHost and returns the
|
||||
@@ -233,6 +238,10 @@ class OpenChannelToExtensionExploitTest : public ExtensionBrowserTest {
|
||||
return ipc_message_waiter_->WaitForMessage();
|
||||
}
|
||||
|
||||
+ content::WebContents* active_web_contents() {
|
||||
+ return browser()->tab_strip_model()->GetActiveWebContents();
|
||||
+ }
|
||||
+
|
||||
// Asks the `extension_id` to inject `content_script` into `web_contents`.
|
||||
// Returns true if the content script execution started successfully.
|
||||
bool ExecuteProgrammaticContentScript(content::WebContents* web_contents,
|
||||
@@ -246,63 +255,86 @@ class OpenChannelToExtensionExploitTest : public ExtensionBrowserTest {
|
||||
browser()->profile(), extension_id, background_script);
|
||||
}
|
||||
|
||||
+ const Extension& active_extension() { return *active_extension_; }
|
||||
const ExtensionId& active_extension_id() { return active_extension_->id(); }
|
||||
|
||||
const ExtensionId& spoofed_extension_id() { return spoofed_extension_->id(); }
|
||||
|
||||
private:
|
||||
+ // Installs an `active_extension` and a separate, but otherwise identical
|
||||
+ // `spoofed_extension` (the only difference will be the extension id).
|
||||
void InstallTestExtensions() {
|
||||
- // Install an `active_extension` and a separate, but otherwise identical
|
||||
- // `spoofed_extension` (the only difference will be the extension id).
|
||||
- auto install_extension = [this](TestExtensionDir& dir) -> const Extension* {
|
||||
+ auto install_extension =
|
||||
+ [this](TestExtensionDir& dir,
|
||||
+ const char* extra_manifest_bits) -> const Extension* {
|
||||
const char kManifestTemplate[] = R"(
|
||||
{
|
||||
+ %s
|
||||
"name": "ContentScriptTrackerBrowserTest - Programmatic",
|
||||
"version": "1.0",
|
||||
"manifest_version": 2,
|
||||
- "permissions": [ "tabs", "<all_urls>" ],
|
||||
+ "permissions": [
|
||||
+ "tabs",
|
||||
+ "<all_urls>",
|
||||
+ "nativeMessaging"
|
||||
+ ],
|
||||
"background": {"scripts": ["background_script.js"]}
|
||||
} )";
|
||||
- dir.WriteManifest(kManifestTemplate);
|
||||
+ dir.WriteManifest(
|
||||
+ base::StringPrintf(kManifestTemplate, extra_manifest_bits));
|
||||
dir.WriteFile(FILE_PATH_LITERAL("background_script.js"), "");
|
||||
+ dir.WriteFile(FILE_PATH_LITERAL("page.html"), "<p>page</p>");
|
||||
return LoadExtension(dir.UnpackedPath());
|
||||
};
|
||||
- TestExtensionDir active_dir;
|
||||
- TestExtensionDir spoofed_dir;
|
||||
- active_extension_ = install_extension(active_dir);
|
||||
- spoofed_extension_ = install_extension(spoofed_dir);
|
||||
+#if !(BUILDFLAG(IS_FUCHSIA))
|
||||
+ // The key below corresponds to the extension ID used by
|
||||
+ // ScopedTestNativeMessagingHost::kExtensionId.
|
||||
+ const char kActiveExtensionKey[] = R"(
|
||||
+ "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcBHwzDvyBQ6bDppkIs9MP4ksKqCMyXQ/A52JivHZKh4YO/9vJsT3oaYhSpDCE9RPocOEQvwsHsFReW2nUEc6OLLyoCFFxIb7KkLGsmfakkut/fFdNJYh0xOTbSN8YvLWcqph09XAY2Y/f0AL7vfO1cuCqtkMt8hFrBGWxDdf9CQIDAQAB",
|
||||
+ )";
|
||||
+#else
|
||||
+ // Native messaging is not available on Fuchsia (i.e.
|
||||
+ // //chrome/browser/extensions/BUILD.gn excludes
|
||||
+ // api/messaging/native_messaging_test_util.h on Fuchsia).
|
||||
+ const char kActiveExtensionKey[] = "";
|
||||
+#endif
|
||||
+ active_extension_ = install_extension(active_dir_, kActiveExtensionKey);
|
||||
+ spoofed_extension_ = install_extension(spoofed_dir_, "");
|
||||
ASSERT_TRUE(active_extension_);
|
||||
ASSERT_TRUE(spoofed_extension_);
|
||||
+#if !(BUILDFLAG(IS_FUCHSIA))
|
||||
+ ASSERT_EQ(active_extension_id(),
|
||||
+ ScopedTestNativeMessagingHost::kExtensionId);
|
||||
+#endif
|
||||
ASSERT_NE(active_extension_id(), spoofed_extension_id());
|
||||
}
|
||||
|
||||
using OpenChannelMessageWaiter =
|
||||
ExtensionMessageWaiter<ExtensionHostMsg_OpenChannelToExtension>;
|
||||
- std::unique_ptr<OpenChannelMessageWaiter> StartInterceptingIpcs(
|
||||
- const GURL& test_page_url) {
|
||||
// Start capturing IPC messages in all future/new RenderProcessHosts.
|
||||
- auto ipc_message_waiter = std::make_unique<OpenChannelMessageWaiter>();
|
||||
+ ipc_message_waiter_ = std::make_unique<OpenChannelMessageWaiter>();
|
||||
|
||||
// Navigate to an arbitrary, mostly empty test page. Make sure that a new
|
||||
// RenderProcessHost is created to make sure it is covered by the
|
||||
- // `ipc_message_waiter`. (A WebUI -> http navigation should swap the
|
||||
+ // `ipc_message_waiter_`. (A WebUI -> http navigation should swap the
|
||||
// RenderProcessHost on all platforms.)
|
||||
- content::WebContents* web_contents =
|
||||
- browser()->tab_strip_model()->GetActiveWebContents();
|
||||
+ GURL test_page_url =
|
||||
+ embedded_test_server()->GetURL("foo.com", "/title1.html");
|
||||
int old_process_id =
|
||||
- web_contents->GetPrimaryMainFrame()->GetProcess()->GetID();
|
||||
+ active_web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID();
|
||||
EXPECT_TRUE(
|
||||
ui_test_utils::NavigateToURL(browser(), GURL("chrome://version")));
|
||||
EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), test_page_url));
|
||||
int new_process_id =
|
||||
- web_contents->GetPrimaryMainFrame()->GetProcess()->GetID();
|
||||
+ active_web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID();
|
||||
EXPECT_NE(old_process_id, new_process_id);
|
||||
|
||||
// Only intercept messages from `active_extension`'s content script running
|
||||
// in the main frame's process.
|
||||
std::string matching_extension_id = active_extension_id();
|
||||
- int matching_process_id = new_process_id;
|
||||
- ipc_message_waiter->SetIpcMatcher(base::BindLambdaForTesting(
|
||||
+ int matching_process_id =
|
||||
+ active_web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID();
|
||||
+ ipc_message_waiter_->SetIpcMatcher(base::BindLambdaForTesting(
|
||||
[matching_extension_id, matching_process_id](
|
||||
int captured_render_process_id,
|
||||
const ExtensionHostMsg_OpenChannelToExtension::Param& param) {
|
||||
@@ -319,12 +351,19 @@ class OpenChannelToExtensionExploitTest : public ExtensionBrowserTest {
|
||||
|
||||
return true;
|
||||
}));
|
||||
+ }
|
||||
|
||||
- return ipc_message_waiter;
|
||||
+ // Waits for ExtensionHostMsg_OpenChannelToExtension IPC and returns its
|
||||
+ // payload.
|
||||
+ ExtensionHostMsg_OpenChannelToExtension::Param WaitForMessage() {
|
||||
+ return ipc_message_waiter_->WaitForMessage();
|
||||
}
|
||||
|
||||
+ private:
|
||||
std::unique_ptr<OpenChannelMessageWaiter> ipc_message_waiter_;
|
||||
|
||||
+ TestExtensionDir active_dir_;
|
||||
+ TestExtensionDir spoofed_dir_;
|
||||
raw_ptr<const Extension> active_extension_ = nullptr;
|
||||
raw_ptr<const Extension> spoofed_extension_ = nullptr;
|
||||
};
|
||||
@@ -340,24 +379,22 @@ IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest,
|
||||
|
||||
// Trigger sending of a valid ExtensionHostMsg_OpenChannelToExtension IPC
|
||||
// from a content script of an `active_extension_id`.
|
||||
- content::WebContents* web_contents =
|
||||
- browser()->tab_strip_model()->GetActiveWebContents();
|
||||
ASSERT_TRUE(ExecuteProgrammaticContentScript(
|
||||
- web_contents, active_extension_id(),
|
||||
+ active_web_contents(), active_extension_id(),
|
||||
"chrome.runtime.sendMessage({greeting: 'hello'}, (response) => {});"));
|
||||
|
||||
// Capture the IPC.
|
||||
auto [source_context, info, channel_name, port_id] = WaitForMessage();
|
||||
-
|
||||
- // Mutate the IPC payload.
|
||||
EXPECT_EQ(MessagingEndpoint::Type::kTab, info.source_endpoint.type);
|
||||
EXPECT_EQ(active_extension_id(), info.source_endpoint.extension_id);
|
||||
+
|
||||
+ // Mutate the IPC payload.
|
||||
info.source_endpoint.extension_id = spoofed_extension_id();
|
||||
|
||||
// Inject the malformed/mutated IPC and verify that the renderer is terminated
|
||||
// as expected.
|
||||
content::RenderProcessHost* main_frame_process =
|
||||
- web_contents->GetPrimaryMainFrame()->GetProcess();
|
||||
+ active_web_contents()->GetPrimaryMainFrame()->GetProcess();
|
||||
RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
|
||||
IPC::IpcSecurityTestUtil::PwnMessageReceived(
|
||||
main_frame_process->GetChannel(),
|
||||
@@ -371,24 +408,22 @@ IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest,
|
||||
FromContentScript_UnexpectedNativeAppType) {
|
||||
// Trigger sending of a valid ExtensionHostMsg_OpenChannelToExtension IPC
|
||||
// from a content script of an `active_extension_id`.
|
||||
- content::WebContents* web_contents =
|
||||
- browser()->tab_strip_model()->GetActiveWebContents();
|
||||
ASSERT_TRUE(ExecuteProgrammaticContentScript(
|
||||
- web_contents, active_extension_id(),
|
||||
+ active_web_contents(), active_extension_id(),
|
||||
"chrome.runtime.sendMessage({greeting: 'hello'}, (response) => {});"));
|
||||
|
||||
// Capture the IPC.
|
||||
auto [source_context, info, channel_name, port_id] = WaitForMessage();
|
||||
-
|
||||
- // Mutate the IPC payload.
|
||||
EXPECT_EQ(MessagingEndpoint::Type::kTab, info.source_endpoint.type);
|
||||
EXPECT_EQ(active_extension_id(), info.source_endpoint.extension_id);
|
||||
+
|
||||
+ // Mutate the IPC payload.
|
||||
info.source_endpoint.type = MessagingEndpoint::Type::kNativeApp;
|
||||
|
||||
// Inject the malformed/mutated IPC and verify that the renderer is terminated
|
||||
// as expected.
|
||||
content::RenderProcessHost* main_frame_process =
|
||||
- web_contents->GetPrimaryMainFrame()->GetProcess();
|
||||
+ active_web_contents()->GetPrimaryMainFrame()->GetProcess();
|
||||
RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
|
||||
IPC::IpcSecurityTestUtil::PwnMessageReceived(
|
||||
main_frame_process->GetChannel(),
|
||||
@@ -401,24 +436,22 @@ IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest,
|
||||
FromContentScript_UnexpectedExtensionType) {
|
||||
// Trigger sending of a valid ExtensionHostMsg_OpenChannelToExtension IPC
|
||||
// from a content script of an `active_extension_id`.
|
||||
- content::WebContents* web_contents =
|
||||
- browser()->tab_strip_model()->GetActiveWebContents();
|
||||
ASSERT_TRUE(ExecuteProgrammaticContentScript(
|
||||
- web_contents, active_extension_id(),
|
||||
+ active_web_contents(), active_extension_id(),
|
||||
"chrome.runtime.sendMessage({greeting: 'hello'}, (response) => {});"));
|
||||
|
||||
// Capture the IPC.
|
||||
auto [source_context, info, channel_name, port_id] = WaitForMessage();
|
||||
-
|
||||
- // Mutate the IPC payload.
|
||||
EXPECT_EQ(MessagingEndpoint::Type::kTab, info.source_endpoint.type);
|
||||
EXPECT_EQ(active_extension_id(), info.source_endpoint.extension_id);
|
||||
+
|
||||
+ // Mutate the IPC payload.
|
||||
info.source_endpoint.type = MessagingEndpoint::Type::kExtension;
|
||||
|
||||
// Inject the malformed/mutated IPC and verify that the renderer is terminated
|
||||
// as expected.
|
||||
content::RenderProcessHost* main_frame_process =
|
||||
- web_contents->GetPrimaryMainFrame()->GetProcess();
|
||||
+ active_web_contents()->GetPrimaryMainFrame()->GetProcess();
|
||||
RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
|
||||
IPC::IpcSecurityTestUtil::PwnMessageReceived(
|
||||
main_frame_process->GetChannel(),
|
||||
@@ -432,25 +465,23 @@ IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest,
|
||||
FromContentScript_NoExtensionIdForExtensionType) {
|
||||
// Trigger sending of a valid ExtensionHostMsg_OpenChannelToExtension IPC
|
||||
// from a content script of an `active_extension_id`.
|
||||
- content::WebContents* web_contents =
|
||||
- browser()->tab_strip_model()->GetActiveWebContents();
|
||||
ASSERT_TRUE(ExecuteProgrammaticContentScript(
|
||||
- web_contents, active_extension_id(),
|
||||
+ active_web_contents(), active_extension_id(),
|
||||
"chrome.runtime.sendMessage({greeting: 'hello'}, (response) => {});"));
|
||||
|
||||
// Capture the IPC.
|
||||
auto [source_context, info, channel_name, port_id] = WaitForMessage();
|
||||
-
|
||||
- // Mutate the IPC payload.
|
||||
EXPECT_EQ(MessagingEndpoint::Type::kTab, info.source_endpoint.type);
|
||||
EXPECT_EQ(active_extension_id(), info.source_endpoint.extension_id);
|
||||
+
|
||||
+ // Mutate the IPC payload.
|
||||
info.source_endpoint.type = MessagingEndpoint::Type::kExtension;
|
||||
info.source_endpoint.extension_id = absl::nullopt;
|
||||
|
||||
// Inject the malformed/mutated IPC and verify that the renderer is terminated
|
||||
// as expected.
|
||||
content::RenderProcessHost* main_frame_process =
|
||||
- web_contents->GetPrimaryMainFrame()->GetProcess();
|
||||
+ active_web_contents()->GetPrimaryMainFrame()->GetProcess();
|
||||
RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
|
||||
IPC::IpcSecurityTestUtil::PwnMessageReceived(
|
||||
main_frame_process->GetChannel(),
|
||||
@@ -464,18 +495,16 @@ IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest,
|
||||
FromContentScript_UnexpectedWorkerContext) {
|
||||
// Trigger sending of a valid ExtensionHostMsg_OpenChannelToExtension IPC
|
||||
// from a content script of an `active_extension_id`.
|
||||
- content::WebContents* web_contents =
|
||||
- browser()->tab_strip_model()->GetActiveWebContents();
|
||||
ASSERT_TRUE(ExecuteProgrammaticContentScript(
|
||||
- web_contents, active_extension_id(),
|
||||
+ active_web_contents(), active_extension_id(),
|
||||
"chrome.runtime.sendMessage({greeting: 'hello'}, (response) => {});"));
|
||||
|
||||
// Capture the IPC.
|
||||
auto [source_context, info, channel_name, port_id] = WaitForMessage();
|
||||
-
|
||||
- // Mutate the IPC payload.
|
||||
EXPECT_TRUE(source_context.is_for_render_frame());
|
||||
EXPECT_FALSE(source_context.is_for_service_worker());
|
||||
+
|
||||
+ // Mutate the IPC payload.
|
||||
source_context.frame = absl::nullopt;
|
||||
source_context.worker = PortContext::WorkerContext(
|
||||
/* thread_id = */ 123, /* version_id = */ 456,
|
||||
@@ -484,7 +513,7 @@ IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest,
|
||||
// Inject the malformed/mutated IPC and verify that the renderer is terminated
|
||||
// as expected.
|
||||
content::RenderProcessHost* main_frame_process =
|
||||
- web_contents->GetPrimaryMainFrame()->GetProcess();
|
||||
+ active_web_contents()->GetPrimaryMainFrame()->GetProcess();
|
||||
RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
|
||||
IPC::IpcSecurityTestUtil::PwnMessageReceived(
|
||||
main_frame_process->GetChannel(),
|
||||
@@ -494,4 +523,98 @@ IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest,
|
||||
kill_waiter.Wait());
|
||||
}
|
||||
|
||||
+// Native messaging is not available on Fuchsia (i.e.
|
||||
+// //chrome/browser/extensions/BUILD.gn excludes
|
||||
+// api/messaging/native_messaging_test_util.h on Fuchsia).
|
||||
+#if !(BUILDFLAG(IS_FUCHSIA))
|
||||
+
|
||||
+// Test suite for covering ExtensionHostMsg_OpenChannelToNativeApp IPC.
|
||||
+class OpenChannelToNativeAppExploitTest
|
||||
+ : public ExtensionSecurityExploitBrowserTest {
|
||||
+ public:
|
||||
+ OpenChannelToNativeAppExploitTest() = default;
|
||||
+
|
||||
+ using OpenChannelMessageWaiter =
|
||||
+ ExtensionMessageWaiter<ExtensionHostMsg_OpenChannelToNativeApp>;
|
||||
+ void SetUpOnMainThread() override {
|
||||
+ // Set up ExtensionMessageWaiter *before* installing the extensions (i.e.
|
||||
+ // *before* the corresponding RenderProcessHost objects are created).
|
||||
+ ipc_message_waiter_ = std::make_unique<OpenChannelMessageWaiter>();
|
||||
+
|
||||
+ // SetUpOnMainThread in the base class will install the test extensions.
|
||||
+ ExtensionSecurityExploitBrowserTest::SetUpOnMainThread();
|
||||
+
|
||||
+ // Register a (fake, test-only) native messaging host.
|
||||
+ test_native_messaging_host_.RegisterTestHost(/* user_level= */ false);
|
||||
+
|
||||
+ // Navigate the test tab to an extension page.
|
||||
+ GURL test_page_url = active_extension().GetResourceURL("page.html");
|
||||
+ EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), test_page_url));
|
||||
+
|
||||
+ // Only intercept messages from the test process.
|
||||
+ int matching_process_id =
|
||||
+ active_web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID();
|
||||
+ ipc_message_waiter_->SetIpcMatcher(base::BindLambdaForTesting(
|
||||
+ [matching_process_id](
|
||||
+ int captured_render_process_id,
|
||||
+ const ExtensionHostMsg_OpenChannelToNativeApp::Param& param) {
|
||||
+ if (captured_render_process_id != matching_process_id)
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+ }));
|
||||
+ }
|
||||
+
|
||||
+ // Waits for ExtensionHostMsg_OpenChannelToNativeApp IPC and returns its
|
||||
+ // payload.
|
||||
+ ExtensionHostMsg_OpenChannelToNativeApp::Param WaitForMessage() {
|
||||
+ return ipc_message_waiter_->WaitForMessage();
|
||||
+ }
|
||||
+
|
||||
+ private:
|
||||
+ ScopedTestNativeMessagingHost test_native_messaging_host_;
|
||||
+ std::unique_ptr<OpenChannelMessageWaiter> ipc_message_waiter_;
|
||||
+};
|
||||
+
|
||||
+IN_PROC_BROWSER_TEST_F(OpenChannelToNativeAppExploitTest,
|
||||
+ SourceContextWithSpoofedExtensionId) {
|
||||
+ // Trigger sending of a valid ExtensionHostMsg_OpenChannelToNativeApp IPC
|
||||
+ // from a frame of an `active_extension`.
|
||||
+ const char kScript[] = R"(
|
||||
+ var message = {text: 'Hello!'};
|
||||
+ var host = $1;
|
||||
+ chrome.runtime.sendNativeMessage(host, message);
|
||||
+ )";
|
||||
+ ASSERT_EQ(
|
||||
+ active_extension().origin(),
|
||||
+ active_web_contents()->GetPrimaryMainFrame()->GetLastCommittedOrigin());
|
||||
+ ASSERT_TRUE(content::ExecuteScript(
|
||||
+ active_web_contents(),
|
||||
+ content::JsReplace(kScript, ScopedTestNativeMessagingHost::kHostName)));
|
||||
+
|
||||
+ // Capture the IPC.
|
||||
+ auto [source_context, native_app_name, port_id] = WaitForMessage();
|
||||
+ EXPECT_EQ(native_app_name, ScopedTestNativeMessagingHost::kHostName);
|
||||
+ EXPECT_TRUE(source_context.is_for_render_frame());
|
||||
+
|
||||
+ // Mutate the IPC payload.
|
||||
+ source_context = PortContext::ForWorker(123, // thread_id
|
||||
+ 456, // version_id
|
||||
+ spoofed_extension_id());
|
||||
+
|
||||
+ // Inject the malformed/mutated IPC and verify that the renderer is terminated
|
||||
+ // as expected.
|
||||
+ content::RenderProcessHost* main_frame_process =
|
||||
+ active_web_contents()->GetPrimaryMainFrame()->GetProcess();
|
||||
+ RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
|
||||
+ IPC::IpcSecurityTestUtil::PwnMessageReceived(
|
||||
+ main_frame_process->GetChannel(),
|
||||
+ ExtensionHostMsg_OpenChannelToNativeApp(source_context, native_app_name,
|
||||
+ port_id));
|
||||
+ EXPECT_EQ(bad_message::EMF_INVALID_EXTENSION_ID_FOR_WORKER_CONTEXT,
|
||||
+ kill_waiter.Wait());
|
||||
+}
|
||||
+
|
||||
+#endif // !(BUILDFLAG(IS_FUCHSIA)) - native messaging is available
|
||||
+
|
||||
} // namespace extensions
|
||||
diff --git a/docs/security/compromised-renderers.md b/docs/security/compromised-renderers.md
|
||||
index b7e56be454f2d42dc4ae4ac875586a01f2354d9a..2155a399e0e432fedc2792b6893440efd7fca572 100644
|
||||
--- a/docs/security/compromised-renderers.md
|
||||
+++ b/docs/security/compromised-renderers.md
|
||||
@@ -213,14 +213,21 @@ Compromised renderers shouldn’t be able to:
|
||||
- Spoof the `MessageEvent.origin` seen by a recipient of a `postMessage`.
|
||||
- Bypass enforcement of the `targetOrigin` argument of `postMessage`.
|
||||
- Send or receive `BroadcastChannel` messages for another origin.
|
||||
-- Spoof the `MessageSender.origin` seen by a recipient of a
|
||||
- `chrome.runtime.sendMessage`
|
||||
- (see also [MessageSender documentation](https://developers.chrome.com/extensions/runtime#type-MessageSender) and [content script security guidance](https://groups.google.com/a/chromium.org/forum/#!topic/chromium-extensions/0ei-UCHNm34)).
|
||||
+- Spoof the `MessageSender.origin`, nor `MessageSender.id` (i.e. an
|
||||
+ extension id which can differ from the origin when the message is sent
|
||||
+ from a content script), as seen by a recipient of a
|
||||
+ `chrome.runtime.sendMessage`.
|
||||
+ See also [MessageSender documentation](https://developers.chrome.com/extensions/runtime#type-MessageSender) and [content script security guidance](https://groups.google.com/a/chromium.org/forum/#!topic/chromium-extensions/0ei-UCHNm34).
|
||||
+- Spoof the id of a Chrome extension initiating
|
||||
+ [native messaging](https://developer.chrome.com/docs/apps/nativeMessaging/)
|
||||
+ communication.
|
||||
|
||||
Protection techniques:
|
||||
- Using `CanAccessDataForOrigin` to verify IPCs sent by a renderer process
|
||||
(e.g. in `RenderFrameProxyHost::OnRouteMessageEvent` or
|
||||
`BroadcastChannelProvider::ConnectToChannel`).
|
||||
+- Using `ContentScriptTracker` to check if IPCs from a given renderer process
|
||||
+ can legitimately claim to act on behalf content scripts of a given extension.
|
||||
|
||||
**Known gaps in protection**:
|
||||
- Spoofing of `MessageSender.id` object
|
||||
diff --git a/extensions/browser/api/messaging/messaging_api_message_filter.cc b/extensions/browser/api/messaging/messaging_api_message_filter.cc
|
||||
index 5469f5e91bfbb98aece208e9fffa8139dc9dacdf..e57cffb46d74229fff2534f7bb9f9fa3ddbc3d26 100644
|
||||
--- a/extensions/browser/api/messaging/messaging_api_message_filter.cc
|
||||
+++ b/extensions/browser/api/messaging/messaging_api_message_filter.cc
|
||||
@@ -156,6 +156,16 @@ bool IsValidSourceContext(RenderProcessHost& process,
|
||||
}
|
||||
}
|
||||
|
||||
+ // This function doesn't validate frame-flavoured `source_context`s, because
|
||||
+ // PortContext::FrameContext only contains frame's `routing_id` and therefore
|
||||
+ // inherently cannot spoof frames in another process (a frame is identified
|
||||
+ // by its `routing_id` *and* the `process_id` of the Renderer process hosting
|
||||
+ // the frame; the latter is trustworthy / doesn't come from an IPC payload).
|
||||
+
|
||||
+ // This function doesn't validate native app `source_context`s, because
|
||||
+ // `PortContext::ForNativeHost()` is called with trustoworthy inputs (e.g. it
|
||||
+ // doesn't take input from IPCs sent by a Renderer process).
|
||||
+
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -227,6 +237,18 @@ void MessagingAPIMessageFilter::Shutdown() {
|
||||
shutdown_notifier_subscription_ = {};
|
||||
}
|
||||
|
||||
+content::RenderProcessHost* MessagingAPIMessageFilter::GetRenderProcessHost() {
|
||||
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
+ if (!browser_context_)
|
||||
+ return nullptr;
|
||||
+
|
||||
+ // The IPC might race with RenderProcessHost destruction. This may only
|
||||
+ // happen in scenarios that are already inherently racey, so returning nullptr
|
||||
+ // (and dropping the IPC) is okay and won't lead to any additional risk of
|
||||
+ // data loss.
|
||||
+ return content::RenderProcessHost::FromID(render_process_id_);
|
||||
+}
|
||||
+
|
||||
void MessagingAPIMessageFilter::OverrideThreadForMessage(
|
||||
const IPC::Message& message,
|
||||
BrowserThread::ID* thread) {
|
||||
@@ -272,19 +294,14 @@ void MessagingAPIMessageFilter::OnOpenChannelToExtension(
|
||||
const std::string& channel_name,
|
||||
const PortId& port_id) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
- if (!browser_context_)
|
||||
- return;
|
||||
-
|
||||
- // The IPC might race with RenderProcessHost destruction. This may only
|
||||
- // happen in scenarios that are already inherently racey, so dropping the IPC
|
||||
- // is okay and won't lead to any additional risk of data loss.
|
||||
- auto* process = content::RenderProcessHost::FromID(render_process_id_);
|
||||
+ auto* process = GetRenderProcessHost();
|
||||
if (!process)
|
||||
return;
|
||||
TRACE_EVENT("extensions", "MessageFilter::OnOpenChannelToExtension",
|
||||
ChromeTrackEvent::kRenderProcessHost, *process);
|
||||
|
||||
ScopedExternalConnectionInfoCrashKeys info_crash_keys(info);
|
||||
+ debug::ScopedPortContextCrashKeys port_context_crash_keys(source_context);
|
||||
if (!IsValidMessagingSource(*process, info.source_endpoint) ||
|
||||
!IsValidSourceContext(*process, source_context)) {
|
||||
return;
|
||||
@@ -303,7 +320,14 @@ void MessagingAPIMessageFilter::OnOpenChannelToNativeApp(
|
||||
const std::string& native_app_name,
|
||||
const PortId& port_id) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
- if (!browser_context_)
|
||||
+ auto* process = GetRenderProcessHost();
|
||||
+ if (!process)
|
||||
+ return;
|
||||
+ TRACE_EVENT("extensions", "MessageFilter::OnOpenChannelToNativeApp",
|
||||
+ ChromeTrackEvent::kRenderProcessHost, *process);
|
||||
+
|
||||
+ debug::ScopedPortContextCrashKeys port_context_crash_keys(source_context);
|
||||
+ if (!IsValidSourceContext(*process, source_context))
|
||||
return;
|
||||
|
||||
ChannelEndpoint source_endpoint(browser_context_, render_process_id_,
|
||||
diff --git a/extensions/browser/api/messaging/messaging_api_message_filter.h b/extensions/browser/api/messaging/messaging_api_message_filter.h
|
||||
index 6a0ccd698629f650d68f2b4ee168aa2b3b3a116c..3358187387cd9a5765a7bd4e522aeecfd787e06b 100644
|
||||
--- a/extensions/browser/api/messaging/messaging_api_message_filter.h
|
||||
+++ b/extensions/browser/api/messaging/messaging_api_message_filter.h
|
||||
@@ -14,6 +14,7 @@ struct ExtensionMsg_TabTargetConnectionInfo;
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
+class RenderProcessHost;
|
||||
}
|
||||
|
||||
namespace extensions {
|
||||
@@ -40,6 +41,11 @@ class MessagingAPIMessageFilter : public content::BrowserMessageFilter {
|
||||
|
||||
void Shutdown();
|
||||
|
||||
+ // Returns the process that the IPC came from, or `nullptr` if the IPC should
|
||||
+ // be dropped (in case the IPC arrived racily after the process or its
|
||||
+ // BrowserContext already got destructed).
|
||||
+ content::RenderProcessHost* GetRenderProcessHost();
|
||||
+
|
||||
// content::BrowserMessageFilter implementation:
|
||||
void OverrideThreadForMessage(const IPC::Message& message,
|
||||
content::BrowserThread::ID* thread) override;
|
||||
diff --git a/extensions/common/api/messaging/port_context.cc b/extensions/common/api/messaging/port_context.cc
|
||||
index 6872179450d8295de7f15dc1437e9d6edefe4fde..319e2f34eca730c5eb7cf94ef8cdede0ddc3f8e1 100644
|
||||
--- a/extensions/common/api/messaging/port_context.cc
|
||||
+++ b/extensions/common/api/messaging/port_context.cc
|
||||
@@ -40,4 +40,27 @@ PortContext PortContext::ForNativeHost() {
|
||||
return PortContext();
|
||||
}
|
||||
|
||||
+namespace debug {
|
||||
+
|
||||
+namespace {
|
||||
+
|
||||
+base::debug::CrashKeyString* GetServiceWorkerExtensionIdCrashKey() {
|
||||
+ static auto* crash_key = base::debug::AllocateCrashKeyString(
|
||||
+ "PortContext-worker-extension_id", base::debug::CrashKeySize::Size64);
|
||||
+ return crash_key;
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
+ScopedPortContextCrashKeys::ScopedPortContextCrashKeys(
|
||||
+ const PortContext& port_context) {
|
||||
+ if (port_context.is_for_service_worker()) {
|
||||
+ extension_id_.emplace(GetServiceWorkerExtensionIdCrashKey(),
|
||||
+ port_context.worker->extension_id);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+ScopedPortContextCrashKeys::~ScopedPortContextCrashKeys() = default;
|
||||
+
|
||||
+} // namespace debug
|
||||
} // namespace extensions
|
||||
diff --git a/extensions/common/api/messaging/port_context.h b/extensions/common/api/messaging/port_context.h
|
||||
index b2e9f057b531d90dc256773959cd586953e4915c..53d94c2ad73c58d45b186a32989e2f4864e67d79 100644
|
||||
--- a/extensions/common/api/messaging/port_context.h
|
||||
+++ b/extensions/common/api/messaging/port_context.h
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
+#include "base/debug/crash_logging.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
|
||||
namespace extensions {
|
||||
@@ -59,6 +60,19 @@ struct PortContext {
|
||||
absl::optional<WorkerContext> worker;
|
||||
};
|
||||
|
||||
+namespace debug {
|
||||
+
|
||||
+class ScopedPortContextCrashKeys {
|
||||
+ public:
|
||||
+ explicit ScopedPortContextCrashKeys(const PortContext& port_context);
|
||||
+ ~ScopedPortContextCrashKeys();
|
||||
+
|
||||
+ private:
|
||||
+ absl::optional<base::debug::ScopedCrashKeyString> extension_id_;
|
||||
+};
|
||||
+
|
||||
+} // namespace debug
|
||||
+
|
||||
} // namespace extensions
|
||||
|
||||
#endif // EXTENSIONS_COMMON_API_MESSAGING_PORT_CONTEXT_H_
|
||||
292
patches/chromium/cherry-pick-6b4af5d82083.patch
Normal file
292
patches/chromium/cherry-pick-6b4af5d82083.patch
Normal file
@@ -0,0 +1,292 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Peng Huang <penghuang@chromium.org>
|
||||
Date: Wed, 23 Nov 2022 00:16:49 +0000
|
||||
Subject: Fix potential OOB problem with validating command decoder
|
||||
|
||||
Bug: 1392715
|
||||
Change-Id: If51b10cc08e5b3ca4b6012b97261347a5e4c134e
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4048203
|
||||
Auto-Submit: Peng Huang <penghuang@chromium.org>
|
||||
Commit-Queue: Peng Huang <penghuang@chromium.org>
|
||||
Reviewed-by: Geoff Lang <geofflang@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1074966}
|
||||
|
||||
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
||||
index a36b9901b50cd99ac641d70d2f316362006e45e7..73148877e2b8b28374ffd32aa10361d21e4911e4 100644
|
||||
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
||||
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
||||
@@ -8595,10 +8595,18 @@ void GLES2DecoderImpl::DoFramebufferTexture2DCommon(
|
||||
service_id = texture_ref->service_id();
|
||||
}
|
||||
|
||||
+ bool valid_target = false;
|
||||
+ if (texture_ref) {
|
||||
+ valid_target = texture_manager()->ValidForTextureTarget(
|
||||
+ texture_ref->texture(), level, 0, 0, 1);
|
||||
+ } else {
|
||||
+ valid_target = texture_manager()->ValidForTarget(textarget, level, 0, 0, 1);
|
||||
+ }
|
||||
+
|
||||
if ((level > 0 && !feature_info_->IsWebGL2OrES3Context() &&
|
||||
!(fbo_render_mipmap_explicitly_enabled_ &&
|
||||
feature_info_->feature_flags().oes_fbo_render_mipmap)) ||
|
||||
- !texture_manager()->ValidForTarget(textarget, level, 0, 0, 1)) {
|
||||
+ !valid_target) {
|
||||
LOCAL_SET_GL_ERROR(
|
||||
GL_INVALID_VALUE,
|
||||
name, "level out of range");
|
||||
@@ -8670,8 +8678,8 @@ void GLES2DecoderImpl::DoFramebufferTextureLayer(
|
||||
"texture is neither TEXTURE_3D nor TEXTURE_2D_ARRAY");
|
||||
return;
|
||||
}
|
||||
- if (!texture_manager()->ValidForTarget(texture_target, level,
|
||||
- 0, 0, layer)) {
|
||||
+ if (!texture_manager()->ValidForTextureTarget(texture_ref->texture(), level,
|
||||
+ 0, 0, layer)) {
|
||||
LOCAL_SET_GL_ERROR(
|
||||
GL_INVALID_VALUE, function_name, "invalid level or layer");
|
||||
return;
|
||||
@@ -14757,11 +14765,6 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage(
|
||||
LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, "imageSize < 0");
|
||||
return error::kNoError;
|
||||
}
|
||||
- if (!texture_manager()->ValidForTarget(target, level, width, height, depth) ||
|
||||
- border != 0) {
|
||||
- LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, "dimensions out of range");
|
||||
- return error::kNoError;
|
||||
- }
|
||||
TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
|
||||
&state_, target);
|
||||
if (!texture_ref) {
|
||||
@@ -14770,6 +14773,12 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage(
|
||||
return error::kNoError;
|
||||
}
|
||||
Texture* texture = texture_ref->texture();
|
||||
+ if (!texture_manager()->ValidForTextureTarget(texture, level, width, height,
|
||||
+ depth) ||
|
||||
+ border != 0) {
|
||||
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, "dimensions out of range");
|
||||
+ return error::kNoError;
|
||||
+ }
|
||||
if (texture->IsImmutable()) {
|
||||
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name, "texture is immutable");
|
||||
return error::kNoError;
|
||||
@@ -15139,10 +15148,6 @@ error::Error GLES2DecoderImpl::DoCompressedTexSubImage(
|
||||
LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, "imageSize < 0");
|
||||
return error::kNoError;
|
||||
}
|
||||
- if (!texture_manager()->ValidForTarget(target, level, width, height, depth)) {
|
||||
- LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, "dimensions out of range");
|
||||
- return error::kNoError;
|
||||
- }
|
||||
TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
|
||||
&state_, target);
|
||||
if (!texture_ref) {
|
||||
@@ -15150,7 +15155,14 @@ error::Error GLES2DecoderImpl::DoCompressedTexSubImage(
|
||||
GL_INVALID_OPERATION, func_name, "no texture bound at target");
|
||||
return error::kNoError;
|
||||
}
|
||||
+
|
||||
Texture* texture = texture_ref->texture();
|
||||
+ if (!texture_manager()->ValidForTextureTarget(texture, level, width, height,
|
||||
+ depth)) {
|
||||
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, "dimensions out of range");
|
||||
+ return error::kNoError;
|
||||
+ }
|
||||
+
|
||||
GLenum type = 0;
|
||||
GLenum internal_format = 0;
|
||||
if (!texture->GetLevelType(target, level, &type, &internal_format)) {
|
||||
@@ -15275,7 +15287,8 @@ void GLES2DecoderImpl::DoCopyTexImage2D(
|
||||
GL_INVALID_OPERATION, func_name, "texture is immutable");
|
||||
return;
|
||||
}
|
||||
- if (!texture_manager()->ValidForTarget(target, level, width, height, 1) ||
|
||||
+ if (!texture_manager()->ValidForTextureTarget(texture, level, width, height,
|
||||
+ 1) ||
|
||||
border != 0) {
|
||||
LOCAL_SET_GL_ERROR(
|
||||
GL_INVALID_VALUE, func_name, "dimensions out of range");
|
||||
@@ -17848,8 +17861,8 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM(
|
||||
}
|
||||
|
||||
// Check that this type of texture is allowed.
|
||||
- if (!texture_manager()->ValidForTarget(source_target, source_level,
|
||||
- source_width, source_height, 1)) {
|
||||
+ if (!texture_manager()->ValidForTextureTarget(
|
||||
+ source_texture, source_level, source_width, source_height, 1)) {
|
||||
LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "Bad dimensions");
|
||||
return;
|
||||
}
|
||||
@@ -18016,8 +18029,8 @@ void GLES2DecoderImpl::CopySubTextureHelper(const char* function_name,
|
||||
}
|
||||
|
||||
// Check that this type of texture is allowed.
|
||||
- if (!texture_manager()->ValidForTarget(source_target, source_level,
|
||||
- source_width, source_height, 1)) {
|
||||
+ if (!texture_manager()->ValidForTextureTarget(
|
||||
+ source_texture, source_level, source_width, source_height, 1)) {
|
||||
LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name,
|
||||
"source texture bad dimensions");
|
||||
return;
|
||||
@@ -18257,11 +18270,20 @@ void GLES2DecoderImpl::TexStorageImpl(GLenum target,
|
||||
return;
|
||||
}
|
||||
}
|
||||
+ TextureRef* texture_ref =
|
||||
+ texture_manager()->GetTextureInfoForTarget(&state_, target);
|
||||
+ if (!texture_ref) {
|
||||
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
|
||||
+ "unknown texture for target");
|
||||
+ return;
|
||||
+ }
|
||||
+ Texture* texture = texture_ref->texture();
|
||||
// The glTexStorage entry points require width, height, and depth to be
|
||||
// at least 1, but the other texture entry points (those which use
|
||||
- // ValidForTarget) do not. So we have to add an extra check here.
|
||||
+ // ValidForTextureTarget) do not. So we have to add an extra check here.
|
||||
bool is_invalid_texstorage_size = width < 1 || height < 1 || depth < 1;
|
||||
- if (!texture_manager()->ValidForTarget(target, 0, width, height, depth) ||
|
||||
+ if (!texture_manager()->ValidForTextureTarget(texture, 0, width, height,
|
||||
+ depth) ||
|
||||
is_invalid_texstorage_size) {
|
||||
LOCAL_SET_GL_ERROR(
|
||||
GL_INVALID_VALUE, function_name, "dimensions out of range");
|
||||
@@ -18274,14 +18296,6 @@ void GLES2DecoderImpl::TexStorageImpl(GLenum target,
|
||||
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, "too many levels");
|
||||
return;
|
||||
}
|
||||
- TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
|
||||
- &state_, target);
|
||||
- if (!texture_ref) {
|
||||
- LOCAL_SET_GL_ERROR(
|
||||
- GL_INVALID_OPERATION, function_name, "unknown texture for target");
|
||||
- return;
|
||||
- }
|
||||
- Texture* texture = texture_ref->texture();
|
||||
if (texture->IsAttachedToFramebuffer()) {
|
||||
framebuffer_state_.clear_state_dirty = true;
|
||||
}
|
||||
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
|
||||
index b20b875b6b37c36623b41e648e393ded96bae93b..f5df8270a8192d36b95e619248c128167455ef46 100644
|
||||
--- a/gpu/command_buffer/service/texture_manager.cc
|
||||
+++ b/gpu/command_buffer/service/texture_manager.cc
|
||||
@@ -1641,7 +1641,7 @@ void Texture::Update() {
|
||||
return;
|
||||
|
||||
if (face_infos_.empty() ||
|
||||
- static_cast<size_t>(base_level_) >= face_infos_[0].level_infos.size()) {
|
||||
+ static_cast<size_t>(base_level_) >= MaxValidMipLevel()) {
|
||||
texture_complete_ = false;
|
||||
cube_complete_ = false;
|
||||
return;
|
||||
@@ -2028,8 +2028,7 @@ bool Texture::CanRenderTo(const FeatureInfo* feature_info, GLint level) const {
|
||||
// the time.
|
||||
if (face_infos_.size() == 6 && !cube_complete())
|
||||
return false;
|
||||
- DCHECK(level >= 0 &&
|
||||
- level < static_cast<GLint>(face_infos_[0].level_infos.size()));
|
||||
+ DCHECK(level >= 0 && level < static_cast<GLint>(MaxValidMipLevel()));
|
||||
if (level > base_level_ && !texture_complete()) {
|
||||
return false;
|
||||
}
|
||||
@@ -2064,7 +2063,7 @@ void Texture::SetCompatibilitySwizzle(const CompatibilitySwizzle* swizzle) {
|
||||
|
||||
void Texture::ApplyFormatWorkarounds(const FeatureInfo* feature_info) {
|
||||
if (feature_info->gl_version_info().NeedsLuminanceAlphaEmulation()) {
|
||||
- if (static_cast<size_t>(base_level_) >= face_infos_[0].level_infos.size())
|
||||
+ if (static_cast<size_t>(base_level_) >= MaxValidMipLevel())
|
||||
return;
|
||||
const Texture::LevelInfo& info = face_infos_[0].level_infos[base_level_];
|
||||
SetCompatibilitySwizzle(GetCompatibilitySwizzleInternal(info.format));
|
||||
@@ -2298,8 +2297,11 @@ scoped_refptr<TextureRef>
|
||||
return default_texture;
|
||||
}
|
||||
|
||||
-bool TextureManager::ValidForTarget(
|
||||
- GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth) {
|
||||
+bool TextureManager::ValidForTarget(GLenum target,
|
||||
+ GLint level,
|
||||
+ GLsizei width,
|
||||
+ GLsizei height,
|
||||
+ GLsizei depth) {
|
||||
if (level < 0 || level >= MaxLevelsForTarget(target))
|
||||
return false;
|
||||
GLsizei max_size = MaxSizeForTarget(target) >> level;
|
||||
@@ -2319,6 +2321,18 @@ bool TextureManager::ValidForTarget(
|
||||
(target != GL_TEXTURE_2D || (depth == 1));
|
||||
}
|
||||
|
||||
+bool TextureManager::ValidForTextureTarget(const Texture* texture,
|
||||
+ GLint level,
|
||||
+ GLsizei width,
|
||||
+ GLsizei height,
|
||||
+ GLsizei depth) {
|
||||
+ if (texture->target() == 0)
|
||||
+ return false;
|
||||
+ if (level < 0 || static_cast<size_t>(level) >= texture->MaxValidMipLevel())
|
||||
+ return false;
|
||||
+ return ValidForTarget(texture->target(), level, width, height, depth);
|
||||
+}
|
||||
+
|
||||
void TextureManager::SetTarget(TextureRef* ref, GLenum target) {
|
||||
DCHECK(ref);
|
||||
ref->texture()->SetTarget(target, MaxLevelsForTarget(target));
|
||||
@@ -2802,14 +2816,6 @@ bool TextureManager::ValidateTexImage(ContextState* state,
|
||||
args.internal_format, args.level)) {
|
||||
return false;
|
||||
}
|
||||
- if (!ValidForTarget(args.target, args.level,
|
||||
- args.width, args.height, args.depth) ||
|
||||
- args.border != 0) {
|
||||
- ERRORSTATE_SET_GL_ERROR(
|
||||
- error_state, GL_INVALID_VALUE, function_name,
|
||||
- "dimensions out of range");
|
||||
- return false;
|
||||
- }
|
||||
if ((GLES2Util::GetChannelsForFormat(args.format) &
|
||||
(GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && args.pixels
|
||||
&& !feature_info_->IsWebGL2OrES3Context()) {
|
||||
@@ -2832,7 +2838,13 @@ bool TextureManager::ValidateTexImage(ContextState* state,
|
||||
"texture is immutable");
|
||||
return false;
|
||||
}
|
||||
-
|
||||
+ if (!ValidForTextureTarget(local_texture_ref->texture(), args.level,
|
||||
+ args.width, args.height, args.depth) ||
|
||||
+ args.border != 0) {
|
||||
+ ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, function_name,
|
||||
+ "dimensions out of range");
|
||||
+ return false;
|
||||
+ }
|
||||
Buffer* buffer = state->bound_pixel_unpack_buffer.get();
|
||||
if (buffer) {
|
||||
if (buffer->GetMappedRange()) {
|
||||
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
|
||||
index c78c914cbad58abb17439354eeb9f77a9891f21d..8f68e70e6d1c9a4b75f6bec0df7179320bc167c0 100644
|
||||
--- a/gpu/command_buffer/service/texture_manager.h
|
||||
+++ b/gpu/command_buffer/service/texture_manager.h
|
||||
@@ -470,6 +470,11 @@ class GPU_GLES2_EXPORT Texture final : public TextureBase {
|
||||
sampler_state_.min_filter != GL_LINEAR;
|
||||
}
|
||||
|
||||
+ size_t MaxValidMipLevel() const {
|
||||
+ DCHECK(!face_infos_.empty());
|
||||
+ return face_infos_[0].level_infos.size();
|
||||
+ }
|
||||
+
|
||||
private:
|
||||
friend class MailboxManagerTest;
|
||||
friend class TextureManager;
|
||||
@@ -932,6 +937,11 @@ class GPU_GLES2_EXPORT TextureManager
|
||||
bool ValidForTarget(
|
||||
GLenum target, GLint level,
|
||||
GLsizei width, GLsizei height, GLsizei depth);
|
||||
+ bool ValidForTextureTarget(const Texture* texture,
|
||||
+ GLint level,
|
||||
+ GLsizei width,
|
||||
+ GLsizei height,
|
||||
+ GLsizei depth);
|
||||
|
||||
// True if this texture meets all the GLES2 criteria for rendering.
|
||||
// See section 3.8.2 of the GLES2 spec.
|
||||
42
patches/chromium/cherry-pick-77208afba04d.patch
Normal file
42
patches/chromium/cherry-pick-77208afba04d.patch
Normal file
@@ -0,0 +1,42 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jaroslav Sevcik <jarin@chromium.org>
|
||||
Date: Thu, 1 Dec 2022 14:15:52 +0000
|
||||
Subject: Make WidgetBase::BeginMainFrame resilient to disposed 'this'
|
||||
|
||||
This patch makes sure that WidgetBase::BeginMainFrame can finish
|
||||
execution even if processing the RAF-throttled handlers
|
||||
(DispatchRafAlignedInput) destroys 'this' instance.
|
||||
|
||||
(cherry picked from commit af6e22c14bec7ad64115b24ece6d423f144214ca)
|
||||
|
||||
Bug: chromium:1381871
|
||||
Change-Id: I81aa4ba697f80f8666bb2a3b5542cac210b1efa9
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4030809
|
||||
Reviewed-by: Dave Tapuska <dtapuska@chromium.org>
|
||||
Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1072864}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4068023
|
||||
Auto-Submit: Jaroslav Sevcik <jarin@chromium.org>
|
||||
Commit-Queue: Dave Tapuska <dtapuska@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5359@{#1053}
|
||||
Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933}
|
||||
|
||||
diff --git a/third_party/blink/renderer/platform/widget/widget_base.cc b/third_party/blink/renderer/platform/widget/widget_base.cc
|
||||
index e32cbe6473e1e51f4c523b68263cffd1bfb5527c..be585e22e071b078a62552b9fc3e72d1dd8eb036 100644
|
||||
--- a/third_party/blink/renderer/platform/widget/widget_base.cc
|
||||
+++ b/third_party/blink/renderer/platform/widget/widget_base.cc
|
||||
@@ -861,8 +861,14 @@ void WidgetBase::BeginMainFrame(base::TimeTicks frame_time) {
|
||||
if (ShouldRecordBeginMainFrameMetrics()) {
|
||||
raf_aligned_input_start_time = base::TimeTicks::Now();
|
||||
}
|
||||
+
|
||||
+ auto weak_this = weak_ptr_factory_.GetWeakPtr();
|
||||
widget_input_handler_manager_->input_event_queue()->DispatchRafAlignedInput(
|
||||
frame_time);
|
||||
+ // DispatchRafAlignedInput could have detached the frame.
|
||||
+ if (!weak_this)
|
||||
+ return;
|
||||
+
|
||||
if (ShouldRecordBeginMainFrameMetrics()) {
|
||||
client_->RecordDispatchRafAlignedInputTime(raf_aligned_input_start_time);
|
||||
}
|
||||
43
patches/chromium/cherry-pick-819d876e1bb8.patch
Normal file
43
patches/chromium/cherry-pick-819d876e1bb8.patch
Normal file
@@ -0,0 +1,43 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ted Meyer <tmathmeyer@chromium.org>
|
||||
Date: Sat, 3 Dec 2022 00:09:22 +0000
|
||||
Subject: Fix UAF caused by vector operations during iteration
|
||||
|
||||
MediaInspectorContextImpl::CullPlayers iterates through dead_players_
|
||||
to remove their events, but this can cause a GC event which can
|
||||
end up adding more players to the |dead_players_| vector, causing
|
||||
it to get re-allocated and it's iterators invalidated.
|
||||
|
||||
We can fix this simply by not using an iterator, and removing elements
|
||||
from the vector before we trigger any GC operations that might cause
|
||||
other changes to the vector.
|
||||
|
||||
Bug: 1383991
|
||||
|
||||
Change-Id: I59f5824c156ff58cf6b55ac9b942c8efdb1ed65a
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4064295
|
||||
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
|
||||
Commit-Queue: Ted (Chromium) Meyer <tmathmeyer@chromium.org>
|
||||
Reviewed-by: Thomas Guilbert <tguilbert@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1078842}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/inspector/inspector_media_context_impl.cc b/third_party/blink/renderer/core/inspector/inspector_media_context_impl.cc
|
||||
index c0965693783d5cc0eade67fc78f026cec2942792..6e89262ca229b89407c3f6fff2ab5bf74be460e0 100644
|
||||
--- a/third_party/blink/renderer/core/inspector/inspector_media_context_impl.cc
|
||||
+++ b/third_party/blink/renderer/core/inspector/inspector_media_context_impl.cc
|
||||
@@ -109,9 +109,13 @@ void MediaInspectorContextImpl::TrimPlayer(const WebString& playerId) {
|
||||
|
||||
void MediaInspectorContextImpl::CullPlayers(const WebString& prefer_keep) {
|
||||
// Erase all the dead players, but only erase the required number of others.
|
||||
- for (const auto& playerId : dead_players_)
|
||||
+ while (!dead_players_.IsEmpty()) {
|
||||
+ auto playerId = dead_players_.back();
|
||||
+ // remove it first, since |RemovePlayer| can cause a GC event which can
|
||||
+ // potentially caues more players to get added to |dead_players_|.
|
||||
+ dead_players_.pop_back();
|
||||
RemovePlayer(playerId);
|
||||
- dead_players_.clear();
|
||||
+ }
|
||||
|
||||
while (!expendable_players_.IsEmpty()) {
|
||||
if (total_event_count_ <= kMaxCachedPlayerEvents)
|
||||
115
patches/chromium/cherry-pick-81cb17c24788.patch
Normal file
115
patches/chromium/cherry-pick-81cb17c24788.patch
Normal file
@@ -0,0 +1,115 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Christoph Schwering <schwering@google.com>
|
||||
Date: Fri, 4 Nov 2022 00:56:32 +0000
|
||||
Subject: Handle misaligned FormData, FormStructure.
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This CL handles the case where the fields of the cached FormStructure
|
||||
and the FormData are misaligned in
|
||||
BrowserAutofillManager::WillFillCreditCardNumber.
|
||||
|
||||
(cherry picked from commit 1ad751f7dfa30a12a85824c291394b73c5c47eff)
|
||||
|
||||
Bug: 1376637, 1376639
|
||||
Change-Id: Id7c3357a274b4d6624009ecf52b95a24cf3bfa1d
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3965141
|
||||
Commit-Queue: Christoph Schwering <schwering@google.com>
|
||||
Quick-Run: Christoph Schwering <schwering@google.com>
|
||||
Reviewed-by: Dominic Battré <battre@chromium.org>
|
||||
Auto-Submit: Christoph Schwering <schwering@google.com>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1061790}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4003032
|
||||
Commit-Queue: Dominic Battré <battre@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5249@{#907}
|
||||
Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826}
|
||||
|
||||
diff --git a/chrome/test/data/autofill/captured_sites/testcases.json b/chrome/test/data/autofill/captured_sites/testcases.json
|
||||
index bb7ac2a638a410b3e83b9871314eae27aa8ef229..2e69d8f8532760103b9cccd5efc4ca7a4ad016a1 100644
|
||||
--- a/chrome/test/data/autofill/captured_sites/testcases.json
|
||||
+++ b/chrome/test/data/autofill/captured_sites/testcases.json
|
||||
@@ -17,7 +17,7 @@
|
||||
{ "site_name": "bath_and_body_works" },
|
||||
{ "site_name": "beachbody" },
|
||||
{ "site_name": "bed_bath_beyond" },
|
||||
- { "site_name": "belk" },
|
||||
+ { "site_name": "belk", "bug_number": 1376637 },
|
||||
{ "site_name": "bestbuy" },
|
||||
{ "site_name": "bhphotovideo", "bug_number":1173033 },
|
||||
{ "site_name": "bloomingdales" },
|
||||
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc
|
||||
index 2dad433c7deb91a2d06f7a10077c9197bd2eba98..0a6e94a1f5327600c1c13cd6fd7586c7ca09037e 100644
|
||||
--- a/components/autofill/core/browser/browser_autofill_manager.cc
|
||||
+++ b/components/autofill/core/browser/browser_autofill_manager.cc
|
||||
@@ -1069,26 +1069,36 @@ void BrowserAutofillManager::OnAskForValuesToFillImpl(
|
||||
|
||||
bool BrowserAutofillManager::WillFillCreditCardNumber(
|
||||
const FormData& form,
|
||||
- const FormFieldData& field) {
|
||||
+ const FormFieldData& triggered_field_data) {
|
||||
FormStructure* form_structure = nullptr;
|
||||
- AutofillField* autofill_field = nullptr;
|
||||
- if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field))
|
||||
+ AutofillField* triggered_field = nullptr;
|
||||
+ if (!GetCachedFormAndField(form, triggered_field_data, &form_structure,
|
||||
+ &triggered_field)) {
|
||||
return false;
|
||||
+ }
|
||||
|
||||
- if (autofill_field->Type().GetStorableType() == CREDIT_CARD_NUMBER)
|
||||
+ if (triggered_field->Type().GetStorableType() == CREDIT_CARD_NUMBER)
|
||||
return true;
|
||||
|
||||
- DCHECK_EQ(form_structure->field_count(), form.fields.size());
|
||||
- for (size_t i = 0; i < form_structure->field_count(); ++i) {
|
||||
- if (form_structure->field(i)->section == autofill_field->section &&
|
||||
- form_structure->field(i)->Type().GetStorableType() ==
|
||||
- CREDIT_CARD_NUMBER &&
|
||||
- form.fields[i].value.empty() && !form.fields[i].is_autofilled) {
|
||||
- return true;
|
||||
- }
|
||||
- }
|
||||
+ // `form` is the latest version of the form received from the renderer and may
|
||||
+ // be more up to date than the `form_structure` in the cache. Therefore, we
|
||||
+ // need to validate for each `field` in the cache we try to fill whether
|
||||
+ // it still exists in the renderer and whether it is fillable.
|
||||
+ auto IsFillableField = [&form](FieldGlobalId id) {
|
||||
+ auto it = base::ranges::find(form.fields, id, &FormFieldData::global_id);
|
||||
+ return it != form.fields.end() && it->value.empty() && !it->is_autofilled;
|
||||
+ };
|
||||
|
||||
- return false;
|
||||
+ auto IsFillableCreditCardNumberField = [&triggered_field,
|
||||
+ &IsFillableField](const auto& field) {
|
||||
+ return field->Type().GetStorableType() == CREDIT_CARD_NUMBER &&
|
||||
+ field->section == triggered_field->section &&
|
||||
+ IsFillableField(field->global_id());
|
||||
+ };
|
||||
+
|
||||
+ // This runs O(N^2) in the worst case, but usually there aren't too many
|
||||
+ // credit card number fields in a form.
|
||||
+ return base::ranges::any_of(*form_structure, IsFillableCreditCardNumberField);
|
||||
}
|
||||
|
||||
void BrowserAutofillManager::FillOrPreviewCreditCardForm(
|
||||
diff --git a/components/autofill/core/browser/browser_autofill_manager.h b/components/autofill/core/browser/browser_autofill_manager.h
|
||||
index d6d33df90907dd1521108cfbae1ecbd430bb4e8e..03f92c993a05122b0df1e3b6afdad50edd9e1b41 100644
|
||||
--- a/components/autofill/core/browser/browser_autofill_manager.h
|
||||
+++ b/components/autofill/core/browser/browser_autofill_manager.h
|
||||
@@ -475,11 +475,11 @@ class BrowserAutofillManager : public AutofillManager,
|
||||
// profile does not exist.
|
||||
AutofillProfile* GetProfile(int unique_id);
|
||||
|
||||
- // Determines whether a fill on |form| initiated from |field| will wind up
|
||||
- // filling a credit card number. This is useful to determine if we will need
|
||||
- // to unmask a card.
|
||||
+ // Determines whether a fill on |form| initiated from |triggered_field| will
|
||||
+ // wind up filling a credit card number. This is useful to determine if we
|
||||
+ // will need to unmask a card.
|
||||
bool WillFillCreditCardNumber(const FormData& form,
|
||||
- const FormFieldData& field);
|
||||
+ const FormFieldData& triggered_field);
|
||||
|
||||
// Fills or previews the credit card form.
|
||||
// Assumes the form and field are valid.
|
||||
323
patches/chromium/cherry-pick-933cc81c6bad.patch
Normal file
323
patches/chromium/cherry-pick-933cc81c6bad.patch
Normal file
@@ -0,0 +1,323 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Xiaocheng Hu <xiaochengh@chromium.org>
|
||||
Date: Sat, 10 Sep 2022 05:53:49 +0000
|
||||
Subject: Remove symlinks from FileChooserImpl folder upload result
|
||||
|
||||
FileChooserImpl is the browser-side implementation of
|
||||
<input type=file>. When uploading a whole folder, it
|
||||
currently uses DirectoryLister to list all the files in a
|
||||
directory. The result also includes resolved symbolic links
|
||||
(which may even hide deep in some subfolder), which is not a
|
||||
desired behavior.
|
||||
|
||||
Therefore, this patch removes all symbolic links from the
|
||||
result by checking each file against `base::IsLink()`. Since
|
||||
the function needs blocking calls to access file data, the
|
||||
job is sent to a worker pool thread.
|
||||
|
||||
Fixed: 1345275
|
||||
Change-Id: I8ab58214c87944408c64b177e915247a7485925b
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3866767
|
||||
Reviewed-by: Austin Sullivan <asully@chromium.org>
|
||||
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
|
||||
Reviewed-by: Mason Freed <masonf@chromium.org>
|
||||
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1045491}
|
||||
|
||||
diff --git a/content/browser/web_contents/file_chooser_impl.cc b/content/browser/web_contents/file_chooser_impl.cc
|
||||
index 7a3ea45d32c97980c141662f6a071cc517a15ad8..1aa19f7a735b444f2c33d5084edcdd14e3c2f5c5 100644
|
||||
--- a/content/browser/web_contents/file_chooser_impl.cc
|
||||
+++ b/content/browser/web_contents/file_chooser_impl.cc
|
||||
@@ -4,8 +4,11 @@
|
||||
|
||||
#include "content/browser/web_contents/file_chooser_impl.h"
|
||||
|
||||
+#include "base/files/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
+#include "base/ranges/algorithm.h"
|
||||
+#include "base/task/thread_pool.h"
|
||||
#include "content/browser/child_process_security_policy_impl.h"
|
||||
#include "content/browser/renderer_host/back_forward_cache_disable.h"
|
||||
#include "content/browser/renderer_host/render_frame_host_delegate.h"
|
||||
@@ -18,6 +21,19 @@
|
||||
|
||||
namespace content {
|
||||
|
||||
+namespace {
|
||||
+
|
||||
+std::vector<blink::mojom::FileChooserFileInfoPtr> RemoveSymlinks(
|
||||
+ std::vector<blink::mojom::FileChooserFileInfoPtr> files) {
|
||||
+ auto new_end = base::ranges::remove_if(
|
||||
+ files, &base::IsLink,
|
||||
+ [](const auto& file) { return file->get_native_file()->file_path; });
|
||||
+ files.erase(new_end, files.end());
|
||||
+ return files;
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
FileChooserImpl::FileSelectListenerImpl::~FileSelectListenerImpl() {
|
||||
#if DCHECK_IS_ON()
|
||||
if (!was_file_select_listener_function_called_) {
|
||||
@@ -51,8 +67,20 @@ void FileChooserImpl::FileSelectListenerImpl::FileSelected(
|
||||
"FileSelectListener::FileSelectionCanceled()";
|
||||
was_file_select_listener_function_called_ = true;
|
||||
#endif
|
||||
- if (owner_)
|
||||
- owner_->FileSelected(std::move(files), base_dir, mode);
|
||||
+ if (!owner_)
|
||||
+ return;
|
||||
+
|
||||
+ if (mode != blink::mojom::FileChooserParams::Mode::kUploadFolder) {
|
||||
+ owner_->FileSelected(base_dir, mode, std::move(files));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ base::ThreadPool::PostTaskAndReplyWithResult(
|
||||
+ FROM_HERE,
|
||||
+ {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
|
||||
+ base::BindOnce(&RemoveSymlinks, std::move(files)),
|
||||
+ base::BindOnce(&FileChooserImpl::FileSelected, owner_->GetWeakPtr(),
|
||||
+ base_dir, mode));
|
||||
}
|
||||
|
||||
void FileChooserImpl::FileSelectListenerImpl::FileSelectionCanceled() {
|
||||
@@ -162,9 +190,9 @@ void FileChooserImpl::EnumerateChosenDirectory(
|
||||
}
|
||||
|
||||
void FileChooserImpl::FileSelected(
|
||||
- std::vector<blink::mojom::FileChooserFileInfoPtr> files,
|
||||
const base::FilePath& base_dir,
|
||||
- blink::mojom::FileChooserParams::Mode mode) {
|
||||
+ blink::mojom::FileChooserParams::Mode mode,
|
||||
+ std::vector<blink::mojom::FileChooserFileInfoPtr> files) {
|
||||
listener_impl_ = nullptr;
|
||||
if (!render_frame_host_) {
|
||||
std::move(callback_).Run(nullptr);
|
||||
diff --git a/content/browser/web_contents/file_chooser_impl.h b/content/browser/web_contents/file_chooser_impl.h
|
||||
index b9f11f9e6a0b548cb5ab8ca721ae823e079ce6fa..b628b29a5f84264e62bb3fa9e92550787b8342de 100644
|
||||
--- a/content/browser/web_contents/file_chooser_impl.h
|
||||
+++ b/content/browser/web_contents/file_chooser_impl.h
|
||||
@@ -37,6 +37,8 @@ class CONTENT_EXPORT FileChooserImpl : public blink::mojom::FileChooser,
|
||||
|
||||
// FileSelectListener overrides:
|
||||
|
||||
+ // TODO(xiaochengh): Move |file| to the end of the argument list to match
|
||||
+ // the argument ordering of FileChooserImpl::FileSelected().
|
||||
void FileSelected(std::vector<blink::mojom::FileChooserFileInfoPtr> files,
|
||||
const base::FilePath& base_dir,
|
||||
blink::mojom::FileChooserParams::Mode mode) override;
|
||||
@@ -68,9 +70,9 @@ class CONTENT_EXPORT FileChooserImpl : public blink::mojom::FileChooser,
|
||||
|
||||
~FileChooserImpl() override;
|
||||
|
||||
- void FileSelected(std::vector<blink::mojom::FileChooserFileInfoPtr> files,
|
||||
- const base::FilePath& base_dir,
|
||||
- blink::mojom::FileChooserParams::Mode mode);
|
||||
+ void FileSelected(const base::FilePath& base_dir,
|
||||
+ blink::mojom::FileChooserParams::Mode mode,
|
||||
+ std::vector<blink::mojom::FileChooserFileInfoPtr> files);
|
||||
|
||||
void FileSelectionCanceled();
|
||||
|
||||
@@ -82,6 +84,10 @@ class CONTENT_EXPORT FileChooserImpl : public blink::mojom::FileChooser,
|
||||
const base::FilePath& directory_path,
|
||||
EnumerateChosenDirectoryCallback callback) override;
|
||||
|
||||
+ base::WeakPtr<FileChooserImpl> GetWeakPtr() {
|
||||
+ return weak_factory_.GetWeakPtr();
|
||||
+ }
|
||||
+
|
||||
private:
|
||||
explicit FileChooserImpl(RenderFrameHostImpl* render_frame_host);
|
||||
|
||||
@@ -95,6 +101,8 @@ class CONTENT_EXPORT FileChooserImpl : public blink::mojom::FileChooser,
|
||||
raw_ptr<RenderFrameHostImpl> render_frame_host_;
|
||||
scoped_refptr<FileSelectListenerImpl> listener_impl_;
|
||||
base::OnceCallback<void(blink::mojom::FileChooserResultPtr)> callback_;
|
||||
+
|
||||
+ base::WeakPtrFactory<FileChooserImpl> weak_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace content
|
||||
diff --git a/content/browser/web_contents/file_chooser_impl_browsertest.cc b/content/browser/web_contents/file_chooser_impl_browsertest.cc
|
||||
index ced9bfd8fe905acbb6ab5c3e52a9882fc23a7303..f7519189638ece437c4285ddd490be3ea59e638d 100644
|
||||
--- a/content/browser/web_contents/file_chooser_impl_browsertest.cc
|
||||
+++ b/content/browser/web_contents/file_chooser_impl_browsertest.cc
|
||||
@@ -5,14 +5,18 @@
|
||||
#include "content/browser/web_contents/file_chooser_impl.h"
|
||||
|
||||
#include "base/bind.h"
|
||||
+#include "base/files/file_util.h"
|
||||
+#include "base/path_service.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "content/browser/renderer_host/render_frame_host_impl.h"
|
||||
#include "content/public/browser/web_contents_delegate.h"
|
||||
+#include "content/public/common/content_paths.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
#include "content/public/test/browser_test_utils.h"
|
||||
#include "content/public/test/content_browser_test.h"
|
||||
#include "content/public/test/content_browser_test_utils.h"
|
||||
#include "content/shell/browser/shell.h"
|
||||
+#include "content/test/content_browser_test_utils_internal.h"
|
||||
#include "url/gurl.h"
|
||||
#include "url/url_constants.h"
|
||||
|
||||
@@ -143,11 +147,52 @@ IN_PROC_BROWSER_TEST_F(FileChooserImplBrowserTest,
|
||||
->SetListenerFunctionCalledTrueForTesting();
|
||||
std::vector<blink::mojom::FileChooserFileInfoPtr> files;
|
||||
files.emplace_back(blink::mojom::FileChooserFileInfoPtr(nullptr));
|
||||
- chooser->FileSelected(std::move(files), base::FilePath(),
|
||||
- blink::mojom::FileChooserParams::Mode::kOpen);
|
||||
+ chooser->FileSelected(base::FilePath(),
|
||||
+ blink::mojom::FileChooserParams::Mode::kOpen,
|
||||
+ std::move(files));
|
||||
|
||||
// Test passes if this run_loop.Run() returns instead of timing out.
|
||||
run_loop.Run();
|
||||
}
|
||||
|
||||
+// https://crbug.com/1345275
|
||||
+IN_PROC_BROWSER_TEST_F(FileChooserImplBrowserTest, UploadFolderWithSymlink) {
|
||||
+ EXPECT_TRUE(NavigateToURL(
|
||||
+ shell(), GetTestUrl(".", "file_input_webkitdirectory.html")));
|
||||
+
|
||||
+ // The folder contains a regular file and a symbolic link.
|
||||
+ // When uploading the folder, the symbolic link should be excluded.
|
||||
+ base::FilePath dir_test_data;
|
||||
+ ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &dir_test_data));
|
||||
+ base::FilePath folder_to_upload =
|
||||
+ dir_test_data.AppendASCII("file_chooser").AppendASCII("dir_with_symlink");
|
||||
+
|
||||
+ base::FilePath text_file = folder_to_upload.AppendASCII("text_file.txt");
|
||||
+ base::FilePath symlink_file = folder_to_upload.AppendASCII("symlink");
|
||||
+
|
||||
+ // Skip the test if symbolic links are not supported.
|
||||
+ {
|
||||
+ base::ScopedAllowBlockingForTesting allow_blocking;
|
||||
+ if (!base::IsLink(symlink_file))
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ std::unique_ptr<FileChooserDelegate> delegate(
|
||||
+ new FileChooserDelegate({text_file, symlink_file}, base::OnceClosure()));
|
||||
+ shell()->web_contents()->SetDelegate(delegate.get());
|
||||
+ EXPECT_TRUE(ExecJs(shell(),
|
||||
+ "(async () => {"
|
||||
+ " let listener = new Promise("
|
||||
+ " resolve => fileinput.onchange = resolve);"
|
||||
+ " fileinput.click();"
|
||||
+ " await listener;"
|
||||
+ "})()"));
|
||||
+
|
||||
+ EXPECT_EQ(
|
||||
+ 1, EvalJs(shell(), "document.getElementById('fileinput').files.length;"));
|
||||
+ EXPECT_EQ(
|
||||
+ "text_file.txt",
|
||||
+ EvalJs(shell(), "document.getElementById('fileinput').files[0].name;"));
|
||||
+}
|
||||
+
|
||||
} // namespace content
|
||||
diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc
|
||||
index d8e63b56c8ac89a08cd7c40cabb156eb4d1923aa..c70d088bfd007e9a6cd9cfcb6f92b07b99653048 100644
|
||||
--- a/content/test/content_browser_test_utils_internal.cc
|
||||
+++ b/content/test/content_browser_test_utils_internal.cc
|
||||
@@ -446,9 +446,14 @@ Shell* OpenPopup(const ToRenderFrameHost& opener,
|
||||
return new_shell_observer.GetShell();
|
||||
}
|
||||
|
||||
+FileChooserDelegate::FileChooserDelegate(std::vector<base::FilePath> files,
|
||||
+ base::OnceClosure callback)
|
||||
+ : files_(std::move(files)), callback_(std::move(callback)) {}
|
||||
+
|
||||
FileChooserDelegate::FileChooserDelegate(const base::FilePath& file,
|
||||
base::OnceClosure callback)
|
||||
- : file_(file), callback_(std::move(callback)) {}
|
||||
+ : FileChooserDelegate(std::vector<base::FilePath>(1, file),
|
||||
+ std::move(callback)) {}
|
||||
|
||||
FileChooserDelegate::~FileChooserDelegate() = default;
|
||||
|
||||
@@ -456,16 +461,18 @@ void FileChooserDelegate::RunFileChooser(
|
||||
RenderFrameHost* render_frame_host,
|
||||
scoped_refptr<content::FileSelectListener> listener,
|
||||
const blink::mojom::FileChooserParams& params) {
|
||||
- // Send the selected file to the renderer process.
|
||||
- auto file_info = blink::mojom::FileChooserFileInfo::NewNativeFile(
|
||||
- blink::mojom::NativeFileInfo::New(file_, std::u16string()));
|
||||
+ // Send the selected files to the renderer process.
|
||||
std::vector<blink::mojom::FileChooserFileInfoPtr> files;
|
||||
- files.push_back(std::move(file_info));
|
||||
- listener->FileSelected(std::move(files), base::FilePath(),
|
||||
- blink::mojom::FileChooserParams::Mode::kOpen);
|
||||
+ for (const auto& file : files_) {
|
||||
+ auto file_info = blink::mojom::FileChooserFileInfo::NewNativeFile(
|
||||
+ blink::mojom::NativeFileInfo::New(file, std::u16string()));
|
||||
+ files.push_back(std::move(file_info));
|
||||
+ }
|
||||
+ listener->FileSelected(std::move(files), base::FilePath(), params.mode);
|
||||
|
||||
params_ = params.Clone();
|
||||
- std::move(callback_).Run();
|
||||
+ if (callback_)
|
||||
+ std::move(callback_).Run();
|
||||
}
|
||||
|
||||
FrameTestNavigationManager::FrameTestNavigationManager(
|
||||
diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h
|
||||
index 73be6e8a2f458128b08aae34d951c7a80139997d..43c6aabc5414d0cc12fb5a03142e8b20e2a7fab3 100644
|
||||
--- a/content/test/content_browser_test_utils_internal.h
|
||||
+++ b/content/test/content_browser_test_utils_internal.h
|
||||
@@ -176,9 +176,11 @@ Shell* OpenPopup(const ToRenderFrameHost& opener,
|
||||
class FileChooserDelegate : public WebContentsDelegate {
|
||||
public:
|
||||
// Constructs a WebContentsDelegate that mocks a file dialog.
|
||||
- // The mocked file dialog will always reply that the user selected |file|.
|
||||
- // |callback| is invoked when RunFileChooser() is called.
|
||||
+ // The mocked file dialog will always reply that the user selected |file| or
|
||||
+ // |files|. |callback| is invoked when RunFileChooser() is called.
|
||||
FileChooserDelegate(const base::FilePath& file, base::OnceClosure callback);
|
||||
+ FileChooserDelegate(std::vector<base::FilePath> files,
|
||||
+ base::OnceClosure callback);
|
||||
~FileChooserDelegate() override;
|
||||
|
||||
// Implementation of WebContentsDelegate::RunFileChooser.
|
||||
@@ -190,7 +192,7 @@ class FileChooserDelegate : public WebContentsDelegate {
|
||||
const blink::mojom::FileChooserParams& params() const { return *params_; }
|
||||
|
||||
private:
|
||||
- base::FilePath file_;
|
||||
+ std::vector<base::FilePath> files_;
|
||||
base::OnceClosure callback_;
|
||||
blink::mojom::FileChooserParamsPtr params_;
|
||||
};
|
||||
diff --git a/content/test/data/file_chooser/dir_with_symlink/symlink b/content/test/data/file_chooser/dir_with_symlink/symlink
|
||||
new file mode 120000
|
||||
index 0000000000000000000000000000000000000000..7857c689f7043265b4e6d4dcdf6d40d0be2d3d60
|
||||
--- /dev/null
|
||||
+++ b/content/test/data/file_chooser/dir_with_symlink/symlink
|
||||
@@ -0,0 +1 @@
|
||||
+../linked_text_file.txt
|
||||
\ No newline at end of file
|
||||
diff --git a/content/test/data/file_chooser/dir_with_symlink/text_file.txt b/content/test/data/file_chooser/dir_with_symlink/text_file.txt
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..8e27be7d6154a1f68ea9160ef0e18691d20560dc
|
||||
--- /dev/null
|
||||
+++ b/content/test/data/file_chooser/dir_with_symlink/text_file.txt
|
||||
@@ -0,0 +1 @@
|
||||
+text
|
||||
diff --git a/content/test/data/file_chooser/linked_text_file.txt b/content/test/data/file_chooser/linked_text_file.txt
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..9a1f4bc60917c014eac1464ad664a0271c288b84
|
||||
--- /dev/null
|
||||
+++ b/content/test/data/file_chooser/linked_text_file.txt
|
||||
@@ -0,0 +1 @@
|
||||
+linked text file
|
||||
diff --git a/content/test/data/file_input_webkitdirectory.html b/content/test/data/file_input_webkitdirectory.html
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..5b7bb501f7eb5d9f28751f36380e4ad01d2da0c7
|
||||
--- /dev/null
|
||||
+++ b/content/test/data/file_input_webkitdirectory.html
|
||||
@@ -0,0 +1 @@
|
||||
+<input type="file" id="fileinput" webkitdirectory />
|
||||
119
patches/chromium/cherry-pick-9b3d0e2f1aab.patch
Normal file
119
patches/chromium/cherry-pick-9b3d0e2f1aab.patch
Normal file
@@ -0,0 +1,119 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Corentin Wallez <cwallez@chromium.org>
|
||||
Date: Tue, 29 Nov 2022 14:07:46 +0000
|
||||
Subject: Keep a reference to the transfer buffer in Dawn read/write handles.
|
||||
|
||||
Previously the Dawn read/write handles in the GPU process only contained
|
||||
a pointer to the inside of a shmem region owned by a gpu::Buffer that
|
||||
had a different lifetime. This could allow a renderer process to
|
||||
deallocate the memory from underneath the handle which is bad.
|
||||
|
||||
Fix this by keepind a scoped_refptr to the gpu::Buffer inside the
|
||||
read/write handles to extend the lifetime of the shmem to be at least as
|
||||
big as the handle's.
|
||||
|
||||
Fixed: chromium:1393177
|
||||
Change-Id: I9d9c18d5155a46e0e3a01d385d221a6370bd2bea
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4056276
|
||||
Reviewed-by: Austin Eng <enga@chromium.org>
|
||||
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1076828}
|
||||
|
||||
diff --git a/gpu/command_buffer/service/dawn_service_memory_transfer_service.cc b/gpu/command_buffer/service/dawn_service_memory_transfer_service.cc
|
||||
index a15b6f9b3b345079d8cf8251ca5f77b6e7ef647a..10941d9f65c66e50303cf7293180c29fced8ffe2 100644
|
||||
--- a/gpu/command_buffer/service/dawn_service_memory_transfer_service.cc
|
||||
+++ b/gpu/command_buffer/service/dawn_service_memory_transfer_service.cc
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "gpu/command_buffer/common/dawn_memory_transfer_handle.h"
|
||||
+#include "gpu/command_buffer/service/command_buffer_service.h"
|
||||
#include "gpu/command_buffer/service/common_decoder.h"
|
||||
|
||||
namespace gpu {
|
||||
@@ -16,8 +17,8 @@ namespace {
|
||||
class ReadHandleImpl
|
||||
: public dawn::wire::server::MemoryTransferService::ReadHandle {
|
||||
public:
|
||||
- ReadHandleImpl(void* ptr, uint32_t size)
|
||||
- : ReadHandle(), ptr_(ptr), size_(size) {}
|
||||
+ ReadHandleImpl(scoped_refptr<Buffer> buffer, void* ptr, uint32_t size)
|
||||
+ : buffer_(std::move(buffer)), ptr_(ptr), size_(size) {}
|
||||
|
||||
~ReadHandleImpl() override = default;
|
||||
|
||||
@@ -44,6 +45,8 @@ class ReadHandleImpl
|
||||
}
|
||||
|
||||
private:
|
||||
+ scoped_refptr<gpu::Buffer> buffer_;
|
||||
+ // Pointer to client-visible shared memory owned by buffer_.
|
||||
raw_ptr<void> ptr_;
|
||||
uint32_t size_;
|
||||
};
|
||||
@@ -51,8 +54,8 @@ class ReadHandleImpl
|
||||
class WriteHandleImpl
|
||||
: public dawn::wire::server::MemoryTransferService::WriteHandle {
|
||||
public:
|
||||
- WriteHandleImpl(const void* ptr, uint32_t size)
|
||||
- : WriteHandle(), ptr_(ptr), size_(size) {}
|
||||
+ WriteHandleImpl(scoped_refptr<Buffer> buffer, const void* ptr, uint32_t size)
|
||||
+ : buffer_(std::move(buffer)), ptr_(ptr), size_(size) {}
|
||||
|
||||
~WriteHandleImpl() override = default;
|
||||
|
||||
@@ -82,7 +85,9 @@ class WriteHandleImpl
|
||||
}
|
||||
|
||||
private:
|
||||
- raw_ptr<const void> ptr_; // Pointer to client-visible shared memory.
|
||||
+ scoped_refptr<gpu::Buffer> buffer_;
|
||||
+ // Pointer to client-visible shared memory owned by buffer_.
|
||||
+ raw_ptr<const void> ptr_;
|
||||
uint32_t size_;
|
||||
};
|
||||
|
||||
@@ -111,13 +116,19 @@ bool DawnServiceMemoryTransferService::DeserializeReadHandle(
|
||||
int32_t shm_id = handle->shm_id;
|
||||
uint32_t shm_offset = handle->shm_offset;
|
||||
|
||||
- void* ptr = decoder_->GetAddressAndCheckSize(shm_id, shm_offset, size);
|
||||
+ scoped_refptr<gpu::Buffer> buffer =
|
||||
+ decoder_->command_buffer_service()->GetTransferBuffer(shm_id);
|
||||
+ if (buffer == nullptr) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ void* ptr = buffer->GetDataAddress(shm_offset, size);
|
||||
if (ptr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DCHECK(read_handle);
|
||||
- *read_handle = new ReadHandleImpl(ptr, size);
|
||||
+ *read_handle = new ReadHandleImpl(std::move(buffer), ptr, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -139,13 +150,19 @@ bool DawnServiceMemoryTransferService::DeserializeWriteHandle(
|
||||
int32_t shm_id = handle->shm_id;
|
||||
uint32_t shm_offset = handle->shm_offset;
|
||||
|
||||
- void* ptr = decoder_->GetAddressAndCheckSize(shm_id, shm_offset, size);
|
||||
+ scoped_refptr<gpu::Buffer> buffer =
|
||||
+ decoder_->command_buffer_service()->GetTransferBuffer(shm_id);
|
||||
+ if (buffer == nullptr) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ const void* ptr = buffer->GetDataAddress(shm_offset, size);
|
||||
if (ptr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DCHECK(write_handle);
|
||||
- *write_handle = new WriteHandleImpl(ptr, size);
|
||||
+ *write_handle = new WriteHandleImpl(std::move(buffer), ptr, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
102
patches/chromium/cherry-pick-a1cbf05b4163.patch
Normal file
102
patches/chromium/cherry-pick-a1cbf05b4163.patch
Normal file
@@ -0,0 +1,102 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Matt Wolenetz <wolenetz@chromium.org>
|
||||
Date: Fri, 4 Nov 2022 22:06:47 +0000
|
||||
Subject: webcodecs: Fix race in VE.isConfigSupported() promise resolution
|
||||
|
||||
If the context is destroyed before VideoEncoder calls `done_callback`, bad
|
||||
things can happen. That's why we extract a callback runner before doing
|
||||
anything asynchronous. Since we hold a ref-counted pointer to the
|
||||
runner it should be safe now.
|
||||
|
||||
(cherry picked from commit 2acf28478008315f302fd52b571623e784be707b)
|
||||
|
||||
Bug: 1375059
|
||||
Change-Id: I984ab27e03e50bd5ae4bf0eb13431834b14f89b7
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3965544
|
||||
Commit-Queue: Eugene Zemtsov <eugene@chromium.org>
|
||||
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1061737}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4005574
|
||||
Reviewed-by: Matthew Wolenetz <wolenetz@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5249@{#911}
|
||||
Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
|
||||
index 5332ae4094c5a8062cb1b8c830869095b964eabc..8f2be276b702bf5a3071b1bf44a9a5419880acf1 100644
|
||||
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
|
||||
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
|
||||
@@ -68,6 +68,7 @@
|
||||
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
|
||||
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
|
||||
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
|
||||
+#include "third_party/blink/renderer/platform/wtf/cross_thread_copier_base.h"
|
||||
#include "third_party/blink/renderer/platform/wtf/cross_thread_copier_std.h"
|
||||
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
|
||||
|
||||
@@ -100,16 +101,6 @@ namespace {
|
||||
constexpr const char kCategory[] = "media";
|
||||
constexpr int kMaxActiveEncodes = 5;
|
||||
|
||||
-// Use this function in cases when we can't immediately delete |ptr| because
|
||||
-// there might be its methods on the call stack.
|
||||
-template <typename T>
|
||||
-void DeleteLater(ScriptState* state, std::unique_ptr<T> ptr) {
|
||||
- DCHECK(state->ContextIsValid());
|
||||
- auto* context = ExecutionContext::From(state);
|
||||
- auto runner = context->GetTaskRunner(TaskType::kInternalDefault);
|
||||
- runner->DeleteSoon(FROM_HERE, std::move(ptr));
|
||||
-}
|
||||
-
|
||||
bool IsAcceleratedConfigurationSupported(
|
||||
media::VideoCodecProfile profile,
|
||||
const media::VideoEncoder::Options& options,
|
||||
@@ -979,6 +970,7 @@ void VideoEncoder::ResetInternal() {
|
||||
}
|
||||
|
||||
static void isConfigSupportedWithSoftwareOnly(
|
||||
+ ScriptState* script_state,
|
||||
ScriptPromiseResolver* resolver,
|
||||
VideoEncoderSupport* support,
|
||||
VideoEncoderTraits::ParsedConfig* config) {
|
||||
@@ -1003,22 +995,25 @@ static void isConfigSupportedWithSoftwareOnly(
|
||||
return;
|
||||
}
|
||||
|
||||
- auto done_callback = [](std::unique_ptr<media::VideoEncoder> sw_encoder,
|
||||
+ auto done_callback = [](std::unique_ptr<media::VideoEncoder> encoder,
|
||||
ScriptPromiseResolver* resolver,
|
||||
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
|
||||
VideoEncoderSupport* support,
|
||||
media::EncoderStatus status) {
|
||||
support->setSupported(status.is_ok());
|
||||
resolver->Resolve(support);
|
||||
- DeleteLater(resolver->GetScriptState(), std::move(sw_encoder));
|
||||
+ runner->DeleteSoon(FROM_HERE, std::move(encoder));
|
||||
};
|
||||
|
||||
+ auto* context = ExecutionContext::From(script_state);
|
||||
+ auto runner = context->GetTaskRunner(TaskType::kInternalDefault);
|
||||
auto* software_encoder_raw = software_encoder.get();
|
||||
software_encoder_raw->Initialize(
|
||||
config->profile, config->options, base::DoNothing(),
|
||||
- ConvertToBaseOnceCallback(
|
||||
- CrossThreadBindOnce(done_callback, std::move(software_encoder),
|
||||
- WrapCrossThreadPersistent(resolver),
|
||||
- WrapCrossThreadPersistent(support))));
|
||||
+ ConvertToBaseOnceCallback(CrossThreadBindOnce(
|
||||
+ done_callback, std::move(software_encoder),
|
||||
+ WrapCrossThreadPersistent(resolver), std::move(runner),
|
||||
+ WrapCrossThreadPersistent(support))));
|
||||
}
|
||||
|
||||
static void isConfigSupportedWithHardwareOnly(
|
||||
@@ -1105,7 +1100,8 @@ ScriptPromise VideoEncoder::isConfigSupported(ScriptState* script_state,
|
||||
promises.push_back(resolver->Promise());
|
||||
auto* support = VideoEncoderSupport::Create();
|
||||
support->setConfig(config_copy);
|
||||
- isConfigSupportedWithSoftwareOnly(resolver, support, parsed_config);
|
||||
+ isConfigSupportedWithSoftwareOnly(script_state, resolver, support,
|
||||
+ parsed_config);
|
||||
}
|
||||
|
||||
// Wait for all |promises| to resolve and check if any of them have
|
||||
285
patches/chromium/cherry-pick-ac4785387fff.patch
Normal file
285
patches/chromium/cherry-pick-ac4785387fff.patch
Normal file
@@ -0,0 +1,285 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Tapuska <dtapuska@chromium.org>
|
||||
Date: Thu, 3 Nov 2022 23:16:16 +0000
|
||||
Subject: Fix PauseOrFreezeOnWorkerThread with nested Worklets.
|
||||
|
||||
Worklets can use the same backing thread which means we can have
|
||||
nested WorkerThreads paused. If a parent WorkerThread gets deallocated
|
||||
make sure we don't access anything after it is deallocated once the
|
||||
nested event queue is released.
|
||||
|
||||
BUG=1372695
|
||||
|
||||
(cherry picked from commit ff5696ba4bc0f8782e3de40e04685507d9f17fd2)
|
||||
|
||||
Change-Id: I176b8f750da5a41d19d1b3a623944d9a2ed4a441
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3953152
|
||||
Commit-Queue: Dave Tapuska <dtapuska@chromium.org>
|
||||
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1059485}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4004562
|
||||
Cr-Commit-Position: refs/branch-heads/5249@{#906}
|
||||
Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
|
||||
index c54d0a91447717f014f44d36e004d9092e98f8bb..dbe40e69a276983bc2df5dcddd7b9b483d2534b1 100644
|
||||
--- a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
|
||||
+++ b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
|
||||
@@ -234,6 +234,7 @@ class ThreadedWorkletMessagingProxyForTest
|
||||
|
||||
private:
|
||||
friend class ThreadedWorkletTest;
|
||||
+ FRIEND_TEST_ALL_PREFIXES(ThreadedWorkletTest, NestedRunLoopTermination);
|
||||
|
||||
std::unique_ptr<WorkerThread> CreateWorkerThread() final {
|
||||
return std::make_unique<ThreadedWorkletThreadForTest>(WorkletObjectProxy());
|
||||
@@ -280,6 +281,16 @@ class ThreadedWorkletTest : public testing::Test {
|
||||
}
|
||||
Document& GetDocument() { return page_->GetDocument(); }
|
||||
|
||||
+ void WaitForReady(WorkerThread* worker_thread) {
|
||||
+ base::WaitableEvent child_waitable;
|
||||
+ PostCrossThreadTask(
|
||||
+ *worker_thread->GetTaskRunner(TaskType::kInternalTest), FROM_HERE,
|
||||
+ CrossThreadBindOnce(&base::WaitableEvent::Signal,
|
||||
+ CrossThreadUnretained(&child_waitable)));
|
||||
+
|
||||
+ child_waitable.Wait();
|
||||
+ }
|
||||
+
|
||||
private:
|
||||
std::unique_ptr<DummyPageHolder> page_;
|
||||
Persistent<ThreadedWorkletMessagingProxyForTest> messaging_proxy_;
|
||||
@@ -403,4 +414,40 @@ TEST_F(ThreadedWorkletTest, TaskRunner) {
|
||||
test::EnterRunLoop();
|
||||
}
|
||||
|
||||
+TEST_F(ThreadedWorkletTest, NestedRunLoopTermination) {
|
||||
+ MessagingProxy()->Start();
|
||||
+
|
||||
+ ThreadedWorkletMessagingProxyForTest* second_messaging_proxy =
|
||||
+ MakeGarbageCollected<ThreadedWorkletMessagingProxyForTest>(
|
||||
+ GetExecutionContext());
|
||||
+
|
||||
+ // Get a nested event loop where the first one is on the stack
|
||||
+ // and the second is still alive.
|
||||
+ second_messaging_proxy->Start();
|
||||
+
|
||||
+ // Wait until the workers are setup and ready to accept work before we
|
||||
+ // pause them.
|
||||
+ WaitForReady(GetWorkerThread());
|
||||
+ WaitForReady(second_messaging_proxy->GetWorkerThread());
|
||||
+
|
||||
+ // Pause the second worker, then the first.
|
||||
+ second_messaging_proxy->GetWorkerThread()->Pause();
|
||||
+ GetWorkerThread()->Pause();
|
||||
+
|
||||
+ // Resume then terminate the second worker.
|
||||
+ second_messaging_proxy->GetWorkerThread()->Resume();
|
||||
+ second_messaging_proxy->GetWorkerThread()->Terminate();
|
||||
+ second_messaging_proxy = nullptr;
|
||||
+
|
||||
+ // Now resume the first worker.
|
||||
+ GetWorkerThread()->Resume();
|
||||
+
|
||||
+ // Make sure execution still works without crashing.
|
||||
+ PostCrossThreadTask(
|
||||
+ *GetWorkerThread()->GetTaskRunner(TaskType::kInternalTest), FROM_HERE,
|
||||
+ CrossThreadBindOnce(&ThreadedWorkletThreadForTest::TestTaskRunner,
|
||||
+ CrossThreadUnretained(GetWorkerThread())));
|
||||
+ test::EnterRunLoop();
|
||||
+}
|
||||
+
|
||||
} // namespace blink
|
||||
diff --git a/third_party/blink/renderer/core/workers/worker_thread.cc b/third_party/blink/renderer/core/workers/worker_thread.cc
|
||||
index 892b3e58443f1a82a6a41c6d52df7d2d701b377d..3a98c2d192e1e47d1586d1dab1fc9e9dc9daf83b 100644
|
||||
--- a/third_party/blink/renderer/core/workers/worker_thread.cc
|
||||
+++ b/third_party/blink/renderer/core/workers/worker_thread.cc
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
-#include "base/auto_reset.h"
|
||||
#include "base/metrics/histogram_functions.h"
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
@@ -593,6 +592,7 @@ void WorkerThread::InitializeOnWorkerThread(
|
||||
const absl::optional<WorkerBackingThreadStartupData>& thread_startup_data,
|
||||
std::unique_ptr<WorkerDevToolsParams> devtools_params) {
|
||||
DCHECK(IsCurrentThread());
|
||||
+ backing_thread_weak_factory_.emplace(this);
|
||||
worker_reporting_proxy_.WillInitializeWorkerContext();
|
||||
{
|
||||
TRACE_EVENT0("blink.worker", "WorkerThread::InitializeWorkerContext");
|
||||
@@ -728,11 +728,13 @@ void WorkerThread::PrepareForShutdownOnWorkerThread() {
|
||||
SetThreadState(ThreadState::kReadyToShutdown);
|
||||
}
|
||||
|
||||
+ backing_thread_weak_factory_ = absl::nullopt;
|
||||
if (pause_or_freeze_count_ > 0) {
|
||||
DCHECK(nested_runner_);
|
||||
pause_or_freeze_count_ = 0;
|
||||
nested_runner_->QuitNow();
|
||||
}
|
||||
+ pause_handle_.reset();
|
||||
|
||||
{
|
||||
v8::HandleScope handle_scope(GetIsolate());
|
||||
@@ -883,8 +885,7 @@ void WorkerThread::PauseOrFreezeOnWorkerThread(
|
||||
if (pause_or_freeze_count_ > 1)
|
||||
return;
|
||||
|
||||
- std::unique_ptr<scheduler::WorkerScheduler::PauseHandle> pause_handle =
|
||||
- GetScheduler()->Pause();
|
||||
+ pause_handle_ = GetScheduler()->Pause();
|
||||
{
|
||||
// Since the nested message loop runner needs to be created and destroyed on
|
||||
// the same thread we allocate and destroy a new message loop runner each
|
||||
@@ -892,13 +893,20 @@ void WorkerThread::PauseOrFreezeOnWorkerThread(
|
||||
// the worker thread such that the resume/terminate can quit this runner.
|
||||
std::unique_ptr<Platform::NestedMessageLoopRunner> nested_runner =
|
||||
Platform::Current()->CreateNestedMessageLoopRunner();
|
||||
- base::AutoReset<Platform::NestedMessageLoopRunner*> nested_runner_autoreset(
|
||||
- &nested_runner_, nested_runner.get());
|
||||
+ auto weak_this = backing_thread_weak_factory_->GetWeakPtr();
|
||||
+ nested_runner_ = nested_runner.get();
|
||||
nested_runner->Run();
|
||||
+
|
||||
+ // Careful `this` may be destroyed.
|
||||
+ if (!weak_this) {
|
||||
+ return;
|
||||
+ }
|
||||
+ nested_runner_ = nullptr;
|
||||
}
|
||||
GlobalScope()->SetDefersLoadingForResourceFetchers(LoaderFreezeMode::kNone);
|
||||
GlobalScope()->SetIsInBackForwardCache(false);
|
||||
GlobalScope()->SetLifecycleState(mojom::blink::FrameLifecycleState::kRunning);
|
||||
+ pause_handle_.reset();
|
||||
}
|
||||
|
||||
void WorkerThread::ResumeOnWorkerThread() {
|
||||
diff --git a/third_party/blink/renderer/core/workers/worker_thread.h b/third_party/blink/renderer/core/workers/worker_thread.h
|
||||
index 834aabc12fe0c43f69bb3a5fa669571c84847c6d..2431c406268a3631df157a24c3fd7accf184cccc 100644
|
||||
--- a/third_party/blink/renderer/core/workers/worker_thread.h
|
||||
+++ b/third_party/blink/renderer/core/workers/worker_thread.h
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include "base/gtest_prod_util.h"
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
+#include "base/memory/weak_ptr.h"
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "base/task/single_thread_task_runner.h"
|
||||
#include "base/thread_annotations.h"
|
||||
@@ -80,7 +81,7 @@ struct WorkerMainScriptLoadParameters;
|
||||
// abstract class. Multiple WorkerThreads may share one WorkerBackingThread for
|
||||
// worklets.
|
||||
//
|
||||
-// WorkerThread start and termination must be initiated on the main thread and
|
||||
+// WorkerThread start and termination must be initiated on the parent thread and
|
||||
// an actual task is executed on the worker thread.
|
||||
//
|
||||
// When termination starts, (debugger) tasks on WorkerThread are handled as
|
||||
@@ -103,7 +104,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver {
|
||||
~WorkerThread() override;
|
||||
|
||||
// Starts the underlying thread and creates the global scope. Called on the
|
||||
- // main thread.
|
||||
+ // parent thread.
|
||||
// Startup data for WorkerBackingThread is absl::nullopt if |this| doesn't own
|
||||
// the underlying WorkerBackingThread.
|
||||
// TODO(nhiroki): We could separate WorkerBackingThread initialization from
|
||||
@@ -115,14 +116,14 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver {
|
||||
std::unique_ptr<WorkerDevToolsParams>);
|
||||
|
||||
// Posts a task to evaluate a top-level classic script on the worker thread.
|
||||
- // Called on the main thread after Start().
|
||||
+ // Called on the parent thread after Start().
|
||||
void EvaluateClassicScript(const KURL& script_url,
|
||||
const String& source_code,
|
||||
std::unique_ptr<Vector<uint8_t>> cached_meta_data,
|
||||
const v8_inspector::V8StackTraceId& stack_id);
|
||||
|
||||
// Posts a task to fetch and run a top-level classic script on the worker
|
||||
- // thread. Called on the main thread after Start().
|
||||
+ // thread. Called on the parent thread after Start().
|
||||
void FetchAndRunClassicScript(
|
||||
const KURL& script_url,
|
||||
std::unique_ptr<WorkerMainScriptLoadParameters>
|
||||
@@ -133,7 +134,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver {
|
||||
const v8_inspector::V8StackTraceId& stack_id);
|
||||
|
||||
// Posts a task to fetch and run a top-level module script on the worker
|
||||
- // thread. Called on the main thread after Start().
|
||||
+ // thread. Called on the parent thread after Start().
|
||||
void FetchAndRunModuleScript(
|
||||
const KURL& script_url,
|
||||
std::unique_ptr<WorkerMainScriptLoadParameters>
|
||||
@@ -154,7 +155,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver {
|
||||
// Terminates the worker thread. Subclasses of WorkerThread can override this
|
||||
// to do cleanup. The default behavior is to call Terminate() and
|
||||
// synchronously call EnsureScriptExecutionTerminates() to ensure the thread
|
||||
- // is quickly terminated. Called on the main thread.
|
||||
+ // is quickly terminated. Called on the parent thread.
|
||||
virtual void TerminateForTesting();
|
||||
|
||||
// Thread::TaskObserver.
|
||||
@@ -181,7 +182,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver {
|
||||
void DebuggerTaskStarted();
|
||||
void DebuggerTaskFinished();
|
||||
|
||||
- // Callable on both the main thread and the worker thread.
|
||||
+ // Callable on both the parent thread and the worker thread.
|
||||
const base::UnguessableToken& GetDevToolsWorkerToken() const {
|
||||
return devtools_worker_token_;
|
||||
}
|
||||
@@ -325,7 +326,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver {
|
||||
// already shutting down. Does not terminate if a debugger task is running,
|
||||
// because the debugger task is guaranteed to finish and it heavily uses V8
|
||||
// API calls which would crash after forcible script termination. Called on
|
||||
- // the main thread.
|
||||
+ // the parent thread.
|
||||
void EnsureScriptExecutionTerminates(ExitCode) LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// These are called in this order during worker thread startup.
|
||||
@@ -410,7 +411,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver {
|
||||
// A unique identifier among all WorkerThreads.
|
||||
const int worker_thread_id_;
|
||||
|
||||
- // Set on the main thread.
|
||||
+ // Set on the parent thread.
|
||||
bool requested_to_terminate_ GUARDED_BY(mutex_) = false;
|
||||
|
||||
ThreadState thread_state_ GUARDED_BY(mutex_) = ThreadState::kNotStarted;
|
||||
@@ -444,7 +445,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver {
|
||||
TaskTypeTraits>;
|
||||
TaskRunnerHashMap worker_task_runners_;
|
||||
|
||||
- // This lock protects shared states between the main thread and the worker
|
||||
+ // This lock protects shared states between the parent thread and the worker
|
||||
// thread. See thread-safety annotations (e.g., GUARDED_BY) in this header
|
||||
// file.
|
||||
Mutex mutex_;
|
||||
@@ -453,6 +454,10 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver {
|
||||
// only on the worker thread.
|
||||
int pause_or_freeze_count_ = 0;
|
||||
|
||||
+ // The `PauseHandle` needs to be destroyed before the scheduler is destroyed
|
||||
+ // otherwise we will hit a DCHECK.
|
||||
+ std::unique_ptr<scheduler::WorkerScheduler::PauseHandle> pause_handle_;
|
||||
+
|
||||
// A nested message loop for handling pausing. Pointer is not owned. Used only
|
||||
// on the worker thread.
|
||||
Platform::NestedMessageLoopRunner* nested_runner_ = nullptr;
|
||||
@@ -479,6 +484,12 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver {
|
||||
HashSet<std::unique_ptr<InterruptData>> pending_interrupts_
|
||||
GUARDED_BY(mutex_);
|
||||
|
||||
+ // Since the WorkerThread is allocated and deallocated on the parent thread,
|
||||
+ // we need a WeakPtrFactory that is allocated and cleared on the backing
|
||||
+ // thread.
|
||||
+ absl::optional<base::WeakPtrFactory<WorkerThread>>
|
||||
+ backing_thread_weak_factory_;
|
||||
+
|
||||
THREAD_CHECKER(parent_thread_checker_);
|
||||
};
|
||||
|
||||
122
patches/chromium/cherry-pick-c83640db21b5.patch
Normal file
122
patches/chromium/cherry-pick-c83640db21b5.patch
Normal file
@@ -0,0 +1,122 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Attard <samuel.r.attard@gmail.com>
|
||||
Date: Wed, 5 Oct 2022 06:03:23 +0000
|
||||
Subject: build: set DTSDKBuild correctly when generating plist files
|
||||
|
||||
Currently we set DTSDKBuild to the version of the SDK used to build
|
||||
Chromium. This value is supposed to be the build version (this is
|
||||
what xcode sets it to for instance). We read this value out of the
|
||||
SDK directly and use it instead.
|
||||
|
||||
Change-Id: Ieb7990f13095683ad8c026f027b2605ae39523a4
|
||||
|
||||
diff --git a/build/config/mac/mac_sdk.gni b/build/config/mac/mac_sdk.gni
|
||||
index 7b1761607c853ae79619d6b872167a00a39f8236..c8e07ad62519236ead55c9b7ce1b1a4c3d5491af 100644
|
||||
--- a/build/config/mac/mac_sdk.gni
|
||||
+++ b/build/config/mac/mac_sdk.gni
|
||||
@@ -40,6 +40,11 @@ declare_args() {
|
||||
# will fail.
|
||||
mac_sdk_official_version = "12.3"
|
||||
|
||||
+ # The SDK build version used when making official builds. This is a single
|
||||
+ # exact version found at "System/Library/CoreServices/SystemVersion.plist"
|
||||
+ # inside the SDK.
|
||||
+ mac_sdk_official_build_version = "21E226"
|
||||
+
|
||||
# Production builds should use hermetic Xcode. If you want to do production
|
||||
# builds with system Xcode to test new SDKs, set this.
|
||||
# Don't set this on any bots.
|
||||
@@ -101,11 +106,13 @@ if (use_system_xcode) {
|
||||
find_sdk_args = [
|
||||
"--print_sdk_path",
|
||||
"--print_bin_path",
|
||||
+ "--print_sdk_build",
|
||||
mac_sdk_min,
|
||||
]
|
||||
find_sdk_lines =
|
||||
exec_script("//build/mac/find_sdk.py", find_sdk_args, "list lines")
|
||||
- mac_sdk_version = find_sdk_lines[2]
|
||||
+ mac_sdk_version = find_sdk_lines[3]
|
||||
+ mac_sdk_build_version = find_sdk_lines[2]
|
||||
if (mac_sdk_path == "") {
|
||||
mac_sdk_path = find_sdk_lines[0]
|
||||
mac_bin_path = find_sdk_lines[1]
|
||||
@@ -114,6 +121,7 @@ if (use_system_xcode) {
|
||||
}
|
||||
} else {
|
||||
mac_sdk_version = mac_sdk_official_version
|
||||
+ mac_sdk_build_version = mac_sdk_official_build_version
|
||||
_dev = _hermetic_xcode_path + "/Contents/Developer"
|
||||
_sdk = "MacOSX${mac_sdk_version}.sdk"
|
||||
mac_sdk_path = _dev + "/Platforms/MacOSX.platform/Developer/SDKs/$_sdk"
|
||||
diff --git a/build/config/mac/rules.gni b/build/config/mac/rules.gni
|
||||
index 03073f830401c4891376a3b59e2e7a870e3d34b7..04d403054c1a83fcbbc70be7cfd239ecbec315d3 100644
|
||||
--- a/build/config/mac/rules.gni
|
||||
+++ b/build/config/mac/rules.gni
|
||||
@@ -41,7 +41,7 @@ template("mac_info_plist") {
|
||||
apple_info_plist(target_name) {
|
||||
format = "xml1"
|
||||
extra_substitutions = [
|
||||
- "MAC_SDK_BUILD=$mac_sdk_version",
|
||||
+ "MAC_SDK_BUILD=$mac_sdk_build_version",
|
||||
"MAC_SDK_NAME=$mac_sdk_name$mac_sdk_version",
|
||||
"MACOSX_DEPLOYMENT_TARGET=$mac_deployment_target",
|
||||
"CHROMIUM_MIN_SYSTEM_VERSION=$mac_min_system_version",
|
||||
diff --git a/build/mac/find_sdk.py b/build/mac/find_sdk.py
|
||||
index d86f3109357a9246d570cb02992dc82552ba7c20..b2400c7e8c70957e364444f509880900ce3b641f 100755
|
||||
--- a/build/mac/find_sdk.py
|
||||
+++ b/build/mac/find_sdk.py
|
||||
@@ -24,6 +24,7 @@ Sample Output:
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
+import plistlib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
@@ -51,6 +52,9 @@ def main():
|
||||
parser.add_option("--print_bin_path",
|
||||
action="store_true", dest="print_bin_path", default=False,
|
||||
help="Additionally print the path the toolchain bin dir.")
|
||||
+ parser.add_option("--print_sdk_build",
|
||||
+ action="store_true", dest="print_sdk_build", default=False,
|
||||
+ help="Additionally print the build version of the SDK.")
|
||||
options, args = parser.parse_args()
|
||||
if len(args) != 1:
|
||||
parser.error('Please specify a minimum SDK version')
|
||||
@@ -80,20 +84,30 @@ def main():
|
||||
if not sdks:
|
||||
raise Exception('No %s+ SDK found' % min_sdk_version)
|
||||
best_sdk = sorted(sdks, key=parse_version)[0]
|
||||
+ sdk_name = 'MacOSX' + best_sdk + '.sdk'
|
||||
+ sdk_path = os.path.join(sdk_dir, sdk_name)
|
||||
|
||||
if options.print_sdk_path:
|
||||
- sdk_name = 'MacOSX' + best_sdk + '.sdk'
|
||||
- print(os.path.join(sdk_dir, sdk_name))
|
||||
+ print(sdk_path)
|
||||
|
||||
if options.print_bin_path:
|
||||
bin_path = 'Toolchains/XcodeDefault.xctoolchain/usr/bin/'
|
||||
print(os.path.join(dev_dir, bin_path))
|
||||
|
||||
- return best_sdk
|
||||
+ if options.print_sdk_build:
|
||||
+ system_version_plist = os.path.join(sdk_path,
|
||||
+ 'System/Library/CoreServices/SystemVersion.plist')
|
||||
+ with open(system_version_plist, 'rb') as f:
|
||||
+ system_version_info = plistlib.load(f)
|
||||
+ if 'ProductBuildVersion' not in system_version_info:
|
||||
+ raise Exception('Failed to determine ProductBuildVersion' +
|
||||
+ 'for SDK at path %s' % system_version_plist)
|
||||
+ print(system_version_info['ProductBuildVersion'])
|
||||
+
|
||||
+ print(best_sdk)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if sys.platform != 'darwin':
|
||||
raise Exception("This script only runs on Mac")
|
||||
- print(main())
|
||||
- sys.exit(0)
|
||||
+ sys.exit(main())
|
||||
116
patches/chromium/cherry-pick-ca2b108a0f1f.patch
Normal file
116
patches/chromium/cherry-pick-ca2b108a0f1f.patch
Normal file
@@ -0,0 +1,116 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Harald Alvestrand <hta@chromium.org>
|
||||
Date: Wed, 18 Jan 2023 08:02:48 +0000
|
||||
Subject: Delete PeerConnectionHandler in PeerConnection finalizer
|
||||
|
||||
Also guard against removal of PC during PeerConnectionHandler
|
||||
call that may cause garbage collection.
|
||||
|
||||
(cherry picked from commit 5066dd66309d884762e5fb9be04b59582893d09a)
|
||||
|
||||
Bug: chromium:1405256
|
||||
Change-Id: I9adf7b219e2026e07ccc0868c1a85f3b35cd9d26
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4154578
|
||||
Commit-Queue: Harald Alvestrand <hta@chromium.org>
|
||||
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
|
||||
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1091801}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4176372
|
||||
Auto-Submit: Harald Alvestrand <hta@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5481@{#418}
|
||||
Cr-Branched-From: 130f3e4d850f4bc7387cfb8d08aa993d288a67a9-refs/heads/main@{#1084008}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
|
||||
index bcb9e9f13cfa525499023e369cefe0ed23f47abc..cf01e7144fc2901c88f320ea7b1c093dfb6ab8b1 100644
|
||||
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
|
||||
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
|
||||
@@ -819,10 +819,11 @@ RTCPeerConnection::~RTCPeerConnection() {
|
||||
}
|
||||
|
||||
void RTCPeerConnection::Dispose() {
|
||||
- // Promptly clears the handler's pointer to |this|
|
||||
+ // Promptly clears the handler
|
||||
// so that content/ doesn't access it in a lazy sweeping phase.
|
||||
+ // Other references to the handler use a weak pointer, preventing access.
|
||||
if (peer_handler_) {
|
||||
- peer_handler_->CloseAndUnregister();
|
||||
+ peer_handler_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
|
||||
index 7662f2cda29b6265705a4f83dbf76ccaf50ab576..48bd8a4eee90b07a38c7f09f260da30c9e7e34bc 100644
|
||||
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
|
||||
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
|
||||
@@ -771,6 +771,8 @@ class RTCPeerConnectionHandler::WebRtcSetDescriptionObserverImpl
|
||||
if (handler_) {
|
||||
handler_->OnModifySctpTransport(std::move(states.sctp_transport_state));
|
||||
}
|
||||
+ // Since OnSessionDescriptionsUpdated can fire events, it may cause
|
||||
+ // garbage collection. Ensure that handler_ is still valid.
|
||||
if (handler_) {
|
||||
handler_->OnModifyTransceivers(
|
||||
states.signaling_state, std::move(states.transceiver_states),
|
||||
@@ -1128,6 +1130,8 @@ bool RTCPeerConnectionHandler::Initialize(
|
||||
CHECK(!initialize_called_);
|
||||
initialize_called_ = true;
|
||||
|
||||
+ // Prevent garbage collection of client_ during processing.
|
||||
+ auto* client_on_stack = client_;
|
||||
peer_connection_tracker_ = PeerConnectionTracker::From(*frame);
|
||||
|
||||
configuration_ = server_configuration;
|
||||
@@ -1165,8 +1169,8 @@ bool RTCPeerConnectionHandler::Initialize(
|
||||
peer_connection_tracker_->RegisterPeerConnection(this, configuration_,
|
||||
options, frame_);
|
||||
}
|
||||
-
|
||||
- return true;
|
||||
+ // Gratuitous usage of client_on_stack to prevent compiler errors.
|
||||
+ return !!client_on_stack;
|
||||
}
|
||||
|
||||
bool RTCPeerConnectionHandler::InitializeForTest(
|
||||
@@ -2229,9 +2233,11 @@ void RTCPeerConnectionHandler::OnSessionDescriptionsUpdated(
|
||||
pending_remote_description,
|
||||
std::unique_ptr<webrtc::SessionDescriptionInterface>
|
||||
current_remote_description) {
|
||||
+ // Prevent garbage collection of client_ during processing.
|
||||
+ auto* client_on_stack = client_;
|
||||
if (!client_ || is_closed_)
|
||||
return;
|
||||
- client_->DidChangeSessionDescriptions(
|
||||
+ client_on_stack->DidChangeSessionDescriptions(
|
||||
pending_local_description
|
||||
? CreateWebKitSessionDescription(pending_local_description.get())
|
||||
: nullptr,
|
||||
@@ -2552,8 +2558,12 @@ void RTCPeerConnectionHandler::OnIceCandidate(const String& sdp,
|
||||
int sdp_mline_index,
|
||||
int component,
|
||||
int address_family) {
|
||||
+ // In order to ensure that the RTCPeerConnection is not garbage collected
|
||||
+ // from under the function, we keep a pointer to it on the stack.
|
||||
+ auto* client_on_stack = client_;
|
||||
DCHECK(task_runner_->RunsTasksInCurrentSequence());
|
||||
TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnIceCandidateImpl");
|
||||
+ // This line can cause garbage collection.
|
||||
auto* platform_candidate = MakeGarbageCollected<RTCIceCandidatePlatform>(
|
||||
sdp, sdp_mid, sdp_mline_index);
|
||||
if (peer_connection_tracker_) {
|
||||
@@ -2573,7 +2583,7 @@ void RTCPeerConnectionHandler::OnIceCandidate(const String& sdp,
|
||||
}
|
||||
}
|
||||
if (!is_closed_)
|
||||
- client_->DidGenerateICECandidate(platform_candidate);
|
||||
+ client_on_stack->DidGenerateICECandidate(platform_candidate);
|
||||
}
|
||||
|
||||
void RTCPeerConnectionHandler::OnIceCandidateError(
|
||||
@@ -2585,7 +2595,6 @@ void RTCPeerConnectionHandler::OnIceCandidateError(
|
||||
const String& error_text) {
|
||||
DCHECK(task_runner_->RunsTasksInCurrentSequence());
|
||||
TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnIceCandidateError");
|
||||
-
|
||||
if (peer_connection_tracker_) {
|
||||
peer_connection_tracker_->TrackIceCandidateError(
|
||||
this, address, port, host_candidate, url, error_code, error_text);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user