mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58f180201e | ||
|
|
767f98b213 | ||
|
|
c8da588479 | ||
|
|
d9538c7fd4 | ||
|
|
c51aec4911 | ||
|
|
73d9a14c6f | ||
|
|
02f9078c92 | ||
|
|
9a77e2b07b | ||
|
|
e2e85fb8fc | ||
|
|
4e68a33c60 | ||
|
|
6e1e2399c7 | ||
|
|
99413641d1 | ||
|
|
ab0f3fd8ff | ||
|
|
9ce16a44db | ||
|
|
f551883fb8 | ||
|
|
3ec9f58c8e | ||
|
|
a52eaeb6e1 | ||
|
|
08ce5bbd33 | ||
|
|
488fbfe469 | ||
|
|
705a9a39c4 | ||
|
|
d98b2a760c | ||
|
|
e48e899807 | ||
|
|
d84ef8bfb3 | ||
|
|
a8cdc21731 | ||
|
|
fc06c55bc0 | ||
|
|
f459315060 |
@@ -337,6 +337,7 @@ step-setup-goma-for-build: &step-setup-goma-for-build
|
||||
npm install
|
||||
mkdir third_party
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
|
||||
export GOMA_FALLBACK_ON_AUTH_FAILURE=true
|
||||
third_party/goma/goma_ctl.py ensure_start
|
||||
echo 'export GN_GOMA_FILE='`node -e "console.log(require('./src/utils/goma.js').gnFilePath)"` >> $BASH_ENV
|
||||
echo 'export LOCAL_GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV
|
||||
|
||||
@@ -1 +1 @@
|
||||
12.0.14
|
||||
12.0.16
|
||||
@@ -718,6 +718,10 @@ Corresponds to the points in time when the spinner of the tab starts spinning.
|
||||
|
||||
Corresponds to the points in time when the spinner of the tab stops spinning.
|
||||
|
||||
### Event: 'did-attach'
|
||||
|
||||
Fired when attached to the embedder web contents.
|
||||
|
||||
### Event: 'dom-ready'
|
||||
|
||||
Fired when document in the given frame is loaded.
|
||||
|
||||
@@ -1,92 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<title>app.setAsDefaultProtocol Demo</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<section>
|
||||
<header>
|
||||
<h1>
|
||||
Protocol Handler
|
||||
</h1>
|
||||
<h3>The <code>app</code> module provides methods for handling protocols.</h3>
|
||||
<p>These methods allow you to set and unset the protocols your app should be the default app for. Similar to when a browser asks to be your default for viewing web pages.</p>
|
||||
<h1>App Default Protocol Demo</h1>
|
||||
|
||||
<p>Open the <a href="https://electronjs.org/docs/api/app">full app API documentation<span class="u-visible-to-screen-reader">(opens in new window)</span></a> in your browser.</p>
|
||||
</header>
|
||||
<p>The protocol API allows us to register a custom protocol and intercept existing protocol requests.</p>
|
||||
<p>These methods allow you to set and unset the protocols your app should be the default app for. Similar to when a
|
||||
browser asks to be your default for viewing web pages.</p>
|
||||
|
||||
<div >
|
||||
<button id="open-in-browser" class="js-container-target demo-toggle-button">Launch current page in browser
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS <span class="demo-meta-divider">|</span> Process: Main</div>
|
||||
</button>
|
||||
<section id='open-app-link'>
|
||||
<a href="electron-api-demos://open">Now... launch the app from a web link</a>
|
||||
</section>
|
||||
<div >
|
||||
<p>You can set your app as the default app to open for a specific protocol. For instance, in this demo we set this app as the default for <code>electron-api-demos://</code>. The demo button above will launch a page in your default browser with a link. Click that link and it will re-launch this app.</p>
|
||||
<h5>Packaging</h5>
|
||||
<p>This feature will only work on macOS when your app is packaged. It will not work when you're launching it in development from the command-line. When you package your app you'll need to make sure the macOS <code>plist</code> for the app is updated to include the new protocol handler. If you're using <code>electron-packager</code> then you can add the flag <code>--extend-info</code> with a path to the <code>plist</code> you've created. The one for this app is below.</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code>
|
||||
const {shell} = require('electron')
|
||||
const path = require('path')
|
||||
const protocolHandlerBtn = document.getElementById('protocol-handler')
|
||||
protocolHandlerBtn.addEventListener('click', () => {
|
||||
const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked')
|
||||
const pagePath = path.join('file://', pageDirectory, '../../sections/system/protocol-link.html')
|
||||
shell.openExternal(pagePath)
|
||||
})
|
||||
</code></pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre><code>
|
||||
const {app, dialog} = require('electron')
|
||||
const path = require('path')
|
||||
<p>Open the <a href="https://www.electronjs.org/docs/api/protocol">full protocol API documentation</a> in your
|
||||
browser.</p>
|
||||
|
||||
if (process.defaultApp) {
|
||||
if (process.argv.length >= 2) {
|
||||
app.setAsDefaultProtocolClient('electron-api-demos', process.execPath, [path.resolve(process.argv[1])])
|
||||
}
|
||||
} else {
|
||||
app.setAsDefaultProtocolClient('electron-api-demos')
|
||||
}
|
||||
-----
|
||||
|
||||
app.on('open-url', (event, url) => {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
|
||||
})
|
||||
<h3>Demo</h3>
|
||||
<p>
|
||||
First: Launch current page in browser
|
||||
<button id="open-in-browser" class="js-container-target demo-toggle-button">
|
||||
Click to Launch Browser
|
||||
</button>
|
||||
</p>
|
||||
|
||||
</code></pre>
|
||||
<h5>macOS plist</h5>
|
||||
<pre><code>
|
||||
<?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>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>electron-api-demos</string>
|
||||
</array>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Electron API Demos Protocol</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>ElectronTeamID</key>
|
||||
<string>VEKTX9H2N7</string>
|
||||
</dict>
|
||||
</plist>
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
require('./renderer.js')
|
||||
</script>
|
||||
</section>
|
||||
<p>
|
||||
Then: Launch the app from a web link!
|
||||
<a href="electron-fiddle://open">Click here to launch the app</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
|
||||
<p>You can set your app as the default app to open for a specific protocol. For instance, in this demo we set this app
|
||||
as the default for <code>electron-fiddle://</code>. The demo button above will launch a page in your default
|
||||
browser with a link. Click that link and it will re-launch this app.</p>
|
||||
|
||||
|
||||
<h3>Packaging</h3>
|
||||
<p>This feature will only work on macOS when your app is packaged. It will not work when you're launching it in
|
||||
development from the command-line. When you package your app you'll need to make sure the macOS <code>plist</code>
|
||||
for the app is updated to include the new protocol handler. If you're using <code>electron-packager</code> then you
|
||||
can add the flag <code>--extend-info</code> with a path to the <code>plist</code> you've created. The one for this
|
||||
app is below:</p>
|
||||
|
||||
<p>
|
||||
<h5>macOS plist</h5>
|
||||
<pre><code>
|
||||
<?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>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>electron-api-demos</string>
|
||||
</array>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Electron API Demos Protocol</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>ElectronTeamID</key>
|
||||
<string>VEKTX9H2N7</string>
|
||||
</dict>
|
||||
</plist>
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
|
||||
<!-- You can also require other files to run in this process -->
|
||||
<script src="./renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -1,10 +1,39 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, dialog } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain, shell } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
let mainWindow;
|
||||
|
||||
if (process.defaultApp) {
|
||||
if (process.argv.length >= 2) {
|
||||
app.setAsDefaultProtocolClient('electron-fiddle', process.execPath, [path.resolve(process.argv[1])])
|
||||
}
|
||||
} else {
|
||||
app.setAsDefaultProtocolClient('electron-fiddle')
|
||||
}
|
||||
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
|
||||
if (!gotTheLock) {
|
||||
app.quit()
|
||||
} else {
|
||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||
// Someone tried to run a second instance, we should focus our window.
|
||||
if (mainWindow) {
|
||||
if (mainWindow.isMinimized()) mainWindow.restore()
|
||||
mainWindow.focus()
|
||||
}
|
||||
})
|
||||
|
||||
// Create mainWindow, load the rest of the app, etc...
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
})
|
||||
|
||||
app.on('open-url', (event, url) => {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
|
||||
})
|
||||
}
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
@@ -12,58 +41,23 @@ function createWindow () {
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
|
||||
if (process.defaultApp) {
|
||||
if (process.argv.length >= 2) {
|
||||
app.setAsDefaultProtocolClient('electron-api-demos', process.execPath, [path.resolve(process.argv[1])])
|
||||
}
|
||||
} else {
|
||||
app.setAsDefaultProtocolClient('electron-api-demos')
|
||||
}
|
||||
|
||||
app.on('open-url', (event, url) => {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
|
||||
// Handle window controls via IPC
|
||||
ipcMain.on('shell:open', () => {
|
||||
const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked')
|
||||
const pagePath = path.join('file://', pageDirectory, 'index.html')
|
||||
shell.openExternal(pagePath)
|
||||
})
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// All of the Node.js APIs are available in the preload process.
|
||||
// It has the same sandbox as a Chrome extension.
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
|
||||
// Set up context bridge between the renderer process and the main process
|
||||
contextBridge.exposeInMainWorld(
|
||||
'shell',
|
||||
{
|
||||
open: () => ipcRenderer.send('shell:open'),
|
||||
}
|
||||
)
|
||||
@@ -1,14 +1,8 @@
|
||||
const { shell } = require('electron')
|
||||
const path = require('path')
|
||||
// This file is required by the index.html file and will
|
||||
// be executed in the renderer process for that window.
|
||||
// All APIs exposed by the context bridge are available here.
|
||||
|
||||
const openInBrowserButton = document.getElementById('open-in-browser')
|
||||
const openAppLink = document.getElementById('open-app-link')
|
||||
// Hides openAppLink when loaded inside Electron
|
||||
openAppLink.style.display = 'none'
|
||||
|
||||
openInBrowserButton.addEventListener('click', () => {
|
||||
console.log('clicked')
|
||||
const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked')
|
||||
const pagePath = path.join('file://', pageDirectory, 'index.html')
|
||||
shell.openExternal(pagePath)
|
||||
})
|
||||
// Binds the buttons to the context bridge API.
|
||||
document.getElementById('open-in-browser').addEventListener('click', () => {
|
||||
shell.open();
|
||||
});
|
||||
175
docs/tutorial/launch-app-from-url-in-another-app.md
Normal file
175
docs/tutorial/launch-app-from-url-in-another-app.md
Normal file
@@ -0,0 +1,175 @@
|
||||
---
|
||||
title: launch-app-from-URL-in-another-app
|
||||
description: This guide will take you through the process of setting your electron app as the default handler for a specific protocol.
|
||||
slug: launch-app-from-url-in-another-app
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Launching Your Electron App From A URL In Another App
|
||||
|
||||
## Overview
|
||||
|
||||
<!-- ✍ Update this section if you want to provide more details -->
|
||||
|
||||
This guide will take you through the process of setting your electron app as the default
|
||||
handler for a specific [protocol](https://www.electronjs.org/docs/api/protocol).
|
||||
|
||||
By the end of this tutorial, we will have set our app to intercept and handle
|
||||
any clicked URLs that start with a specific protocol. In this guide, the protocol
|
||||
we will use will be "`electron-fiddle://`".
|
||||
|
||||
## Examples
|
||||
|
||||
### Main Process (main.js)
|
||||
|
||||
First we will import the required modules from `electron`. These modules help control our application life and create a native browser window.
|
||||
|
||||
```js
|
||||
const { app, BrowserWindow, shell } = require('electron')
|
||||
const path = require('path')
|
||||
```
|
||||
|
||||
Next, we will proceed to register our application to handle all "`electron-fiddle://`" protocols.
|
||||
|
||||
```js
|
||||
if (process.defaultApp) {
|
||||
if (process.argv.length >= 2) {
|
||||
app.setAsDefaultProtocolClient('electron-fiddle', process.execPath, [path.resolve(process.argv[1])])
|
||||
}
|
||||
} else {
|
||||
app.setAsDefaultProtocolClient('electron-fiddle')
|
||||
}
|
||||
```
|
||||
|
||||
We will now define the function in charge of creating our browser window and load our application's `index.html` file.
|
||||
|
||||
```js
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.loadFile('index.html')
|
||||
}
|
||||
```
|
||||
|
||||
In this next step, we will create our `BrowserWindow` and tell our application how to handle an event in which an external protocol is clicked.
|
||||
|
||||
This code will be different in WindowsOS compared to MacOS and Linux. This is due to Windows requiring additional code in order to open the contents of the protocol link within the same electron instance. Read more about this [here](https://www.electronjs.org/docs/api/app#apprequestsingleinstancelock).
|
||||
|
||||
### Windows code:
|
||||
|
||||
```js
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
|
||||
if (!gotTheLock) {
|
||||
app.quit()
|
||||
} else {
|
||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||
// Someone tried to run a second instance, we should focus our window.
|
||||
if (mainWindow) {
|
||||
if (mainWindow.isMinimized()) mainWindow.restore()
|
||||
mainWindow.focus()
|
||||
}
|
||||
})
|
||||
|
||||
// Create mainWindow, load the rest of the app, etc...
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
})
|
||||
|
||||
// handling the protocol. In this case, we choose to show an Error Box.
|
||||
app.on('open-url', (event, url) => {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### MacOS and Linux code:
|
||||
|
||||
```js
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
})
|
||||
|
||||
// handling the protocol. In this case, we choose to show an Error Box.
|
||||
app.on('open-url', (event, url) => {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
|
||||
})
|
||||
```
|
||||
|
||||
Finally, we will add some additional code to handle when someone closes our application
|
||||
|
||||
```js
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
```
|
||||
|
||||
## Important Note:
|
||||
|
||||
### Packaging
|
||||
|
||||
This feature will only work on macOS when your app is packaged. It will not work when you're launching it in development from the command-line. When you package your app you'll need to make sure the macOS `plist` for the app is updated to include the new protocol handler. If you're using [`electron-packager`](https://github.com/electron/electron-packager) then you
|
||||
can add the flag `--extend-info` with a path to the `plist` you've created. The one for this app is below:
|
||||
|
||||
### Plist
|
||||
|
||||
```XML
|
||||
<p>
|
||||
<h5>macOS plist</h5>
|
||||
<pre><code>
|
||||
<?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>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>electron-api-demos</string>
|
||||
</array>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Electron API Demos Protocol</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>ElectronTeamID</key>
|
||||
<string>VEKTX9H2N7</string>
|
||||
</dict>
|
||||
</plist>
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
After you start your electron app, you can now enter in a URL in your browser that contains the custom protocol, for example `"electron-fiddle://open"` and observe that the application will respond and show an error dialog box.
|
||||
|
||||
<!--
|
||||
Because Electron examples usually require multiple files (HTML, CSS, JS
|
||||
for the main and renderer process, etc.), we use this custom code block
|
||||
for Fiddle (https://www.electronjs.org/fiddle).
|
||||
Please modify any of the files in the referenced folder to fit your
|
||||
example.
|
||||
The content in this codeblock will not be rendered in the website so you
|
||||
can leave it empty.
|
||||
-->
|
||||
|
||||
```fiddle docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app
|
||||
|
||||
```
|
||||
|
||||
<!-- ✍ Explanation of the code below -->
|
||||
@@ -223,7 +223,7 @@ app.on('window-all-closed', function () {
|
||||
|
||||
[node-platform]: https://nodejs.org/api/process.html#process_process_platform
|
||||
[window-all-closed]: ../api/app.md#event-window-all-closed
|
||||
[window-all-closed]: ../api/app.md#appquit
|
||||
[app-quit]: ../api/app.md#appquit
|
||||
|
||||
#### Open a window if none are open (macOS)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "12.0.14",
|
||||
"version": "12.0.16",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -138,3 +138,9 @@ cherry-pick-910e9e40d376.patch
|
||||
cherry-pick-d9556a80a790.patch
|
||||
cherry-pick-ee6aee64e24c.patch
|
||||
webview_fullscreen.patch
|
||||
set_svgimage_page_after_document_install.patch
|
||||
cherry-pick-e60cc80ff744.patch
|
||||
cherry-pick-3feda0244490.patch
|
||||
cherry-pick-cd98d7c0dae9.patch
|
||||
replace_first_of_two_waitableevents_in_creditcardaccessmanager.patch
|
||||
cherry-pick-ac9dc1235e28.patch
|
||||
|
||||
38
patches/chromium/cherry-pick-3feda0244490.patch
Normal file
38
patches/chromium/cherry-pick-3feda0244490.patch
Normal file
@@ -0,0 +1,38 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Reilly Grant <reillyg@chromium.org>
|
||||
Date: Mon, 28 Jun 2021 21:55:24 +0000
|
||||
Subject: serial: Fix parent class tracing for SerialPort
|
||||
|
||||
When SerialPort was updated to be ActiveScriptWrappable and an
|
||||
EventTarget the Trace method was not updated to call the parent class
|
||||
trace methods.
|
||||
|
||||
(cherry picked from commit 4059ecc3a5352601a4d79196f90c8ca19262afe1)
|
||||
|
||||
Bug: 1220078
|
||||
Change-Id: If6967a913268bce86d4488359a9418a814530f84
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2965255
|
||||
Auto-Submit: Reilly Grant <reillyg@chromium.org>
|
||||
Commit-Queue: Tom Sepez <tsepez@chromium.org>
|
||||
Reviewed-by: Tom Sepez <tsepez@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#893039}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2992740
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Commit-Queue: Reilly Grant <reillyg@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4472@{#1531}
|
||||
Cr-Branched-From: 3d60439cfb36485e76a1c5bb7f513d3721b20da1-refs/heads/master@{#870763}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/serial/serial_port.cc b/third_party/blink/renderer/modules/serial/serial_port.cc
|
||||
index b485935f6cfd1b397d86acb90ebf344e22e18a2c..835ac5f3526d1a933f81e3546344aa409a5eec09 100644
|
||||
--- a/third_party/blink/renderer/modules/serial/serial_port.cc
|
||||
+++ b/third_party/blink/renderer/modules/serial/serial_port.cc
|
||||
@@ -508,7 +508,8 @@ void SerialPort::Trace(Visitor* visitor) const {
|
||||
visitor->Trace(open_resolver_);
|
||||
visitor->Trace(signal_resolvers_);
|
||||
visitor->Trace(close_resolver_);
|
||||
- ScriptWrappable::Trace(visitor);
|
||||
+ EventTargetWithInlineData::Trace(visitor);
|
||||
+ ActiveScriptWrappable<SerialPort>::Trace(visitor);
|
||||
}
|
||||
|
||||
bool SerialPort::HasPendingActivity() const {
|
||||
103
patches/chromium/cherry-pick-ac9dc1235e28.patch
Normal file
103
patches/chromium/cherry-pick-ac9dc1235e28.patch
Normal file
@@ -0,0 +1,103 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ilya Nikolaevskiy <ilnik@chromium.org>
|
||||
Date: Mon, 17 May 2021 08:34:41 +0000
|
||||
Subject: Add locks and empty string checks to FakeV4L2Impl
|
||||
|
||||
FakeV4L2Impl is crashed by fuzzer with some weird ASAN errors, which
|
||||
turned out to be a threading issue.
|
||||
|
||||
Bug: 1205059,1196302
|
||||
Change-Id: Ieb3a917c9a4549b655862e69214774e183a70bc3
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2883613
|
||||
Reviewed-by: Ricky Liang <jcliang@chromium.org>
|
||||
Commit-Queue: Ilya Nikolaevskiy <ilnik@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#883390}
|
||||
|
||||
diff --git a/media/capture/video/linux/fake_v4l2_impl.cc b/media/capture/video/linux/fake_v4l2_impl.cc
|
||||
index 4a976815d009e68b3740aa71e8c8fd641bf91493..09647474bed3c7c7b34cd9fb161edd2a7d2e170f 100644
|
||||
--- a/media/capture/video/linux/fake_v4l2_impl.cc
|
||||
+++ b/media/capture/video/linux/fake_v4l2_impl.cc
|
||||
@@ -380,10 +380,16 @@ FakeV4L2Impl::~FakeV4L2Impl() = default;
|
||||
|
||||
void FakeV4L2Impl::AddDevice(const std::string& device_name,
|
||||
const FakeV4L2DeviceConfig& config) {
|
||||
+ base::AutoLock lock(lock_);
|
||||
device_configs_.emplace(device_name, config);
|
||||
}
|
||||
|
||||
int FakeV4L2Impl::open(const char* device_name, int flags) {
|
||||
+ if (!device_name)
|
||||
+ return kInvalidId;
|
||||
+
|
||||
+ base::AutoLock lock(lock_);
|
||||
+
|
||||
std::string device_name_as_string(device_name);
|
||||
auto device_configs_iter = device_configs_.find(device_name_as_string);
|
||||
if (device_configs_iter == device_configs_.end())
|
||||
@@ -403,6 +409,7 @@ int FakeV4L2Impl::open(const char* device_name, int flags) {
|
||||
}
|
||||
|
||||
int FakeV4L2Impl::close(int fd) {
|
||||
+ base::AutoLock lock(lock_);
|
||||
auto device_iter = opened_devices_.find(fd);
|
||||
if (device_iter == opened_devices_.end())
|
||||
return kErrorReturnValue;
|
||||
@@ -412,6 +419,7 @@ int FakeV4L2Impl::close(int fd) {
|
||||
}
|
||||
|
||||
int FakeV4L2Impl::ioctl(int fd, int request, void* argp) {
|
||||
+ base::AutoLock lock(lock_);
|
||||
auto device_iter = opened_devices_.find(fd);
|
||||
if (device_iter == opened_devices_.end())
|
||||
return EBADF;
|
||||
@@ -518,6 +526,7 @@ void* FakeV4L2Impl::mmap(void* /*start*/,
|
||||
int flags,
|
||||
int fd,
|
||||
off_t offset) {
|
||||
+ base::AutoLock lock(lock_);
|
||||
if (flags & MAP_FIXED) {
|
||||
errno = EINVAL;
|
||||
return MAP_FAILED;
|
||||
@@ -543,10 +552,12 @@ void* FakeV4L2Impl::mmap(void* /*start*/,
|
||||
}
|
||||
|
||||
int FakeV4L2Impl::munmap(void* start, size_t length) {
|
||||
+ base::AutoLock lock(lock_);
|
||||
return kSuccessReturnValue;
|
||||
}
|
||||
|
||||
int FakeV4L2Impl::poll(struct pollfd* ufds, unsigned int nfds, int timeout) {
|
||||
+ base::AutoLock lock(lock_);
|
||||
if (nfds != 1) {
|
||||
// We only support polling of a single device.
|
||||
errno = EINVAL;
|
||||
diff --git a/media/capture/video/linux/fake_v4l2_impl.h b/media/capture/video/linux/fake_v4l2_impl.h
|
||||
index 0a035a97dd8761b08eb4cfdbe2865efc346f0e23..ae7167f95163581c756ab4951717fd4352c67757 100644
|
||||
--- a/media/capture/video/linux/fake_v4l2_impl.h
|
||||
+++ b/media/capture/video/linux/fake_v4l2_impl.h
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
+#include "base/synchronization/lock.h"
|
||||
#include "media/capture/capture_export.h"
|
||||
#include "media/capture/video/linux/v4l2_capture_device.h"
|
||||
#include "media/capture/video/video_capture_device_descriptor.h"
|
||||
@@ -52,11 +53,13 @@ class CAPTURE_EXPORT FakeV4L2Impl : public V4L2CaptureDevice {
|
||||
private:
|
||||
class OpenedDevice;
|
||||
|
||||
- int next_id_to_return_from_open_;
|
||||
- std::map<std::string, FakeV4L2DeviceConfig> device_configs_;
|
||||
- std::map<std::string, int> device_name_to_open_id_map_;
|
||||
+ base::Lock lock_;
|
||||
+
|
||||
+ int next_id_to_return_from_open_ GUARDED_BY(lock_);
|
||||
+ std::map<std::string, FakeV4L2DeviceConfig> device_configs_ GUARDED_BY(lock_);
|
||||
+ std::map<std::string, int> device_name_to_open_id_map_ GUARDED_BY(lock_);
|
||||
std::map<int /*value returned by open()*/, std::unique_ptr<OpenedDevice>>
|
||||
- opened_devices_;
|
||||
+ opened_devices_ GUARDED_BY(lock_);
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
50
patches/chromium/cherry-pick-cd98d7c0dae9.patch
Normal file
50
patches/chromium/cherry-pick-cd98d7c0dae9.patch
Normal file
@@ -0,0 +1,50 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Peng Huang <penghuang@chromium.org>
|
||||
Date: Wed, 7 Jul 2021 20:50:53 +0000
|
||||
Subject: Fix UAF problem in SharedImageInterfaceInProcess
|
||||
|
||||
(cherry picked from commit 38b4905f8d877b27bc2d4ccd4cfc0f82b636deea)
|
||||
|
||||
Bug: 1216822
|
||||
Change-Id: I8ae1f7c406e1899e500ee7ddeaaf18230b1cbcb2
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2971144
|
||||
Commit-Queue: Peng Huang <penghuang@chromium.org>
|
||||
Commit-Queue: Vasiliy Telezhnikov <vasilyt@chromium.org>
|
||||
Auto-Submit: Peng Huang <penghuang@chromium.org>
|
||||
Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#893931}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3011895
|
||||
Auto-Submit: Mason Freed <masonf@chromium.org>
|
||||
Reviewed-by: Peng Huang <penghuang@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4515@{#1369}
|
||||
Cr-Branched-From: 488fc70865ddaa05324ac00a54a6eb783b4bc41c-refs/heads/master@{#885287}
|
||||
|
||||
diff --git a/gpu/ipc/shared_image_interface_in_process.cc b/gpu/ipc/shared_image_interface_in_process.cc
|
||||
index 54f9777201827e4bca5221af373e39dc021ac6a4..53c2dc489c50367986c46a34e8aaf48b68888ec7 100644
|
||||
--- a/gpu/ipc/shared_image_interface_in_process.cc
|
||||
+++ b/gpu/ipc/shared_image_interface_in_process.cc
|
||||
@@ -86,6 +86,8 @@ void SharedImageInterfaceInProcess::DestroyOnGpu(
|
||||
sync_point_client_state_->Destroy();
|
||||
sync_point_client_state_ = nullptr;
|
||||
}
|
||||
+
|
||||
+ context_state_ = nullptr;
|
||||
completion->Signal();
|
||||
}
|
||||
|
||||
diff --git a/gpu/ipc/shared_image_interface_in_process.h b/gpu/ipc/shared_image_interface_in_process.h
|
||||
index 8d74513f041564a416c20cab5616c9453555c547..c169b5a86af3e02ec869aae9cf1bfb150fa2ad69 100644
|
||||
--- a/gpu/ipc/shared_image_interface_in_process.h
|
||||
+++ b/gpu/ipc/shared_image_interface_in_process.h
|
||||
@@ -229,10 +229,7 @@ class GL_IN_PROCESS_CONTEXT_EXPORT SharedImageInterfaceInProcess
|
||||
// Accessed on GPU thread.
|
||||
// TODO(weiliangc): Check whether can be removed when !UsesSync().
|
||||
MailboxManager* mailbox_manager_;
|
||||
- // Used to check if context is lost at destruction time.
|
||||
- // TODO(weiliangc): SharedImageInterface should become active observer of
|
||||
- // whether context is lost.
|
||||
- SharedContextState* context_state_;
|
||||
+ scoped_refptr<SharedContextState> context_state_;
|
||||
// Created and only used by this SharedImageInterface.
|
||||
SyncPointManager* sync_point_manager_;
|
||||
scoped_refptr<SyncPointClientState> sync_point_client_state_;
|
||||
35
patches/chromium/cherry-pick-e60cc80ff744.patch
Normal file
35
patches/chromium/cherry-pick-e60cc80ff744.patch
Normal file
@@ -0,0 +1,35 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shrek Shao <shrekshao@google.com>
|
||||
Date: Tue, 29 Jun 2021 01:17:03 +0000
|
||||
Subject: Fix multidraw validation drawcount + offset out of bounds
|
||||
|
||||
(cherry picked from commit 7d0a12ce19fed024d56b95a692d888fe3ef14e2f)
|
||||
|
||||
Bug: 1219886
|
||||
Change-Id: I8a84664150758370d9a77ee22ac5549bead0e37e
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2977850
|
||||
Reviewed-by: Kenneth Russell <kbr@chromium.org>
|
||||
Commit-Queue: Kenneth Russell <kbr@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#895423}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2988885
|
||||
Reviewed-by: Shrek Shao <shrekshao@google.com>
|
||||
Reviewed-by: Austin Eng <enga@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4515@{#1101}
|
||||
Cr-Branched-From: 488fc70865ddaa05324ac00a54a6eb783b4bc41c-refs/heads/master@{#885287}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc b/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc
|
||||
index 91de853db2b382a7797d22cf741a84f463a2d5f2..c3cae01c63046ce4b8be2c0b03243e9105ed4f23 100644
|
||||
--- a/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc
|
||||
+++ b/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc
|
||||
@@ -34,6 +34,11 @@ bool WebGLMultiDrawCommon::ValidateArray(WebGLExtensionScopedContext* scoped,
|
||||
outOfBoundsDescription);
|
||||
return false;
|
||||
}
|
||||
+ if (static_cast<uint64_t>(drawcount) + offset > size) {
|
||||
+ scoped->Context()->SynthesizeGLError(GL_INVALID_OPERATION, function_name,
|
||||
+ "drawcount plus offset out of bounds");
|
||||
+ return false;
|
||||
+ }
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,574 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dominic Battre <battre@chromium.org>
|
||||
Date: Wed, 7 Jul 2021 20:02:45 +0000
|
||||
Subject: Replace first of two WaitableEvents in CreditCardAccessManager
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
(cherry picked from commit 48cf01e4039fecbe119d8223d1f6072aaf44f258)
|
||||
|
||||
Bug: 1214234
|
||||
Change-Id: I38171be7b38982f25abfbb3dff7a41f19a167764
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3001123
|
||||
Reviewed-by: Jared Saul <jsaul@google.com>
|
||||
Commit-Queue: Dominic Battré <battre@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#898237}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3011066
|
||||
Reviewed-by: Dominic Battré <battre@chromium.org>
|
||||
Reviewed-by: Prudhvi Kumar Bommana <pbommana@google.com>
|
||||
Owners-Override: Prudhvi Kumar Bommana <pbommana@google.com>
|
||||
Cr-Commit-Position: refs/branch-heads/4515@{#1366}
|
||||
Cr-Branched-From: 488fc70865ddaa05324ac00a54a6eb783b4bc41c-refs/heads/master@{#885287}
|
||||
|
||||
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
|
||||
index 5031372d31e25f8f14905ab1be721c4aaefed7c5..d6254700a20445078cc4c4fa0e821cd2fc3b1a7b 100644
|
||||
--- a/components/autofill/core/browser/BUILD.gn
|
||||
+++ b/components/autofill/core/browser/BUILD.gn
|
||||
@@ -237,6 +237,8 @@ static_library("browser") {
|
||||
"payments/payments_util.cc",
|
||||
"payments/payments_util.h",
|
||||
"payments/risk_data_loader.h",
|
||||
+ "payments/wait_for_signal_or_timeout.cc",
|
||||
+ "payments/wait_for_signal_or_timeout.h",
|
||||
"payments/strike_database.cc",
|
||||
"payments/strike_database.h",
|
||||
"payments/strike_database_integrator_base.cc",
|
||||
@@ -680,6 +682,7 @@ source_set("unit_tests") {
|
||||
"payments/payments_client_unittest.cc",
|
||||
"payments/payments_service_url_unittest.cc",
|
||||
"payments/payments_util_unittest.cc",
|
||||
+ "payments/wait_for_signal_or_timeout_unittest.cc",
|
||||
"payments/strike_database_integrator_test_strike_database_unittest.cc",
|
||||
"payments/strike_database_unittest.cc",
|
||||
"personal_data_manager_unittest.cc",
|
||||
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.cc b/components/autofill/core/browser/payments/credit_card_access_manager.cc
|
||||
index 560f30b57c88049842390095ca53eb2e4302bf63..7cab68d4cc6696329dd4739f51e809aa7877cb53 100644
|
||||
--- a/components/autofill/core/browser/payments/credit_card_access_manager.cc
|
||||
+++ b/components/autofill/core/browser/payments/credit_card_access_manager.cc
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "base/task/post_task.h"
|
||||
#include "base/task/task_traits.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
-#include "base/threading/sequenced_task_runner_handle.h"
|
||||
#include "base/time/time.h"
|
||||
#include "build/build_config.h"
|
||||
#include "components/autofill/core/browser/autofill_client.h"
|
||||
@@ -46,12 +45,6 @@ constexpr int64_t kUnmaskDetailsResponseTimeoutMs = 3 * 1000; // 3 sec
|
||||
// Time to wait between multiple calls to GetUnmaskDetails().
|
||||
constexpr int64_t kDelayForGetUnmaskDetails = 3 * 60 * 1000; // 3 min
|
||||
|
||||
-// Used for asynchronously waiting for |event| to be signaled.
|
||||
-bool WaitForEvent(base::WaitableEvent* event) {
|
||||
- event->declare_only_used_while_idle();
|
||||
- return event->TimedWait(
|
||||
- base::TimeDelta::FromMilliseconds(kUnmaskDetailsResponseTimeoutMs));
|
||||
-}
|
||||
} // namespace
|
||||
|
||||
CreditCardAccessManager::CreditCardAccessManager(
|
||||
@@ -64,9 +57,6 @@ CreditCardAccessManager::CreditCardAccessManager(
|
||||
payments_client_(client_->GetPaymentsClient()),
|
||||
personal_data_manager_(personal_data_manager),
|
||||
form_event_logger_(form_event_logger),
|
||||
- ready_to_start_authentication_(
|
||||
- base::WaitableEvent::ResetPolicy::AUTOMATIC,
|
||||
- base::WaitableEvent::InitialState::NOT_SIGNALED),
|
||||
can_fetch_unmask_details_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
|
||||
base::WaitableEvent::InitialState::SIGNALED) {
|
||||
}
|
||||
@@ -329,12 +319,10 @@ void CreditCardAccessManager::FetchCreditCard(
|
||||
|
||||
// Wait for |ready_to_start_authentication_| to be signaled by
|
||||
// OnDidGetUnmaskDetails() or until timeout before calling Authenticate().
|
||||
- auto task_runner = base::ThreadPool::CreateTaskRunner({base::MayBlock()});
|
||||
- cancelable_authenticate_task_tracker_.PostTaskAndReplyWithResult(
|
||||
- task_runner.get(), FROM_HERE,
|
||||
- base::BindOnce(&WaitForEvent, &ready_to_start_authentication_),
|
||||
+ ready_to_start_authentication_.OnEventOrTimeOut(
|
||||
base::BindOnce(&CreditCardAccessManager::Authenticate,
|
||||
- weak_ptr_factory_.GetWeakPtr()));
|
||||
+ weak_ptr_factory_.GetWeakPtr()),
|
||||
+ base::TimeDelta::FromMilliseconds(kUnmaskDetailsResponseTimeoutMs));
|
||||
} else {
|
||||
Authenticate(get_unmask_details_returned);
|
||||
}
|
||||
@@ -699,7 +687,6 @@ void CreditCardAccessManager::HandleDialogUserResponse(
|
||||
case WebauthnDialogCallbackType::kVerificationCancelled:
|
||||
// TODO(crbug.com/949269): Add tests and logging for canceling verify
|
||||
// pending dialog.
|
||||
- cancelable_authenticate_task_tracker_.TryCancelAll();
|
||||
payments_client_->CancelRequest();
|
||||
SignalCanFetchUnmaskDetails();
|
||||
ready_to_start_authentication_.Reset();
|
||||
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.h b/components/autofill/core/browser/payments/credit_card_access_manager.h
|
||||
index 6bdf8b8c647f885aad5784f737e117b3a55bd2be..99f6581b7320312776f52383b8e8e3b7845268a8 100644
|
||||
--- a/components/autofill/core/browser/payments/credit_card_access_manager.h
|
||||
+++ b/components/autofill/core/browser/payments/credit_card_access_manager.h
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "components/autofill/core/browser/metrics/credit_card_form_event_logger.h"
|
||||
#include "components/autofill/core/browser/payments/credit_card_cvc_authenticator.h"
|
||||
#include "components/autofill/core/browser/payments/payments_client.h"
|
||||
+#include "components/autofill/core/browser/payments/wait_for_signal_or_timeout.h"
|
||||
#include "components/autofill/core/browser/personal_data_manager.h"
|
||||
|
||||
#if !defined(OS_IOS)
|
||||
@@ -295,11 +296,7 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester,
|
||||
// Resets when PrepareToFetchCreditCard() is called, if not already reset.
|
||||
// Signaled when OnDidGetUnmaskDetails() is called or after timeout.
|
||||
// Authenticate() is called when signaled.
|
||||
- base::WaitableEvent ready_to_start_authentication_;
|
||||
-
|
||||
- // Tracks the Authenticate() task that is signaled by
|
||||
- // |ready_to_start_authentication_|, allowing it to be canceled if necessary.
|
||||
- base::CancelableTaskTracker cancelable_authenticate_task_tracker_;
|
||||
+ WaitForSignalOrTimeout ready_to_start_authentication_;
|
||||
|
||||
// Required to avoid any unnecessary preflight calls to Payments servers.
|
||||
// Initial state is signaled. Resets when PrepareToFetchCreditCard() is
|
||||
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
|
||||
index faa396e337d60167d759f9a616f4a901ac5b9db6..39507d6f45e318d632d73583ebaf9048120ae15a 100644
|
||||
--- a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
|
||||
+++ b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
|
||||
@@ -139,8 +139,23 @@ class CreditCardAccessManagerTest : public testing::Test {
|
||||
public:
|
||||
CreditCardAccessManagerTest()
|
||||
: task_environment_(
|
||||
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME,
|
||||
base::test::TaskEnvironment::MainThreadType::DEFAULT,
|
||||
- base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED) {}
|
||||
+ base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED) {
|
||||
+ // Advance the mock clock to 2021-01-01, 00:00:00.000.
|
||||
+ base::Time year_2021;
|
||||
+ CHECK(base::Time::FromUTCExploded({.year = 2021,
|
||||
+ .month = 1,
|
||||
+ .day_of_week = 4,
|
||||
+ .day_of_month = 1,
|
||||
+ .hour = 0,
|
||||
+ .minute = 0,
|
||||
+ .second = 0,
|
||||
+ .millisecond = 0},
|
||||
+ &year_2021));
|
||||
+ task_environment_.AdvanceClock(year_2021 -
|
||||
+ task_environment_.GetMockClock()->Now());
|
||||
+ }
|
||||
|
||||
void SetUp() override {
|
||||
autofill_client_.SetPrefs(test::PrefServiceForTesting());
|
||||
@@ -930,6 +945,7 @@ TEST_F(CreditCardAccessManagerTest,
|
||||
|
||||
ResetFetchCreditCard();
|
||||
credit_card_access_manager_->PrepareToFetchCreditCard();
|
||||
+ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(4));
|
||||
WaitForCallbacks();
|
||||
|
||||
credit_card_access_manager_->FetchCreditCard(local_card,
|
||||
@@ -950,6 +966,7 @@ TEST_F(CreditCardAccessManagerTest,
|
||||
credit_card_access_manager_->PrepareToFetchCreditCard();
|
||||
credit_card_access_manager_->FetchCreditCard(server_card,
|
||||
accessor_->GetWeakPtr());
|
||||
+ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(4));
|
||||
WaitForCallbacks();
|
||||
|
||||
histogram_tester.ExpectUniqueSample(
|
||||
@@ -1023,6 +1040,8 @@ TEST_F(CreditCardAccessManagerTest, Metrics_LoggingTimedOutCvcFallback) {
|
||||
|
||||
// Mock a delayed response.
|
||||
InvokeDelayedGetUnmaskDetailsResponse();
|
||||
+
|
||||
+ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(4));
|
||||
WaitForCallbacks();
|
||||
|
||||
histogram_tester.ExpectUniqueSample(
|
||||
@@ -1044,6 +1063,7 @@ TEST_F(CreditCardAccessManagerTest, Metrics_LoggingTimedOutCvcFallback) {
|
||||
credit_card_access_manager_->PrepareToFetchCreditCard();
|
||||
credit_card_access_manager_->FetchCreditCard(server_card,
|
||||
accessor_->GetWeakPtr());
|
||||
+ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(4));
|
||||
WaitForCallbacks();
|
||||
|
||||
histogram_tester.ExpectUniqueSample(
|
||||
diff --git a/components/autofill/core/browser/payments/wait_for_signal_or_timeout.cc b/components/autofill/core/browser/payments/wait_for_signal_or_timeout.cc
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..713a53e0f006e51f5d9bd64466712bf75b3ba095
|
||||
--- /dev/null
|
||||
+++ b/components/autofill/core/browser/payments/wait_for_signal_or_timeout.cc
|
||||
@@ -0,0 +1,78 @@
|
||||
+// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+#include "components/autofill/core/browser/payments/wait_for_signal_or_timeout.h"
|
||||
+
|
||||
+#include "base/threading/sequenced_task_runner_handle.h"
|
||||
+
|
||||
+WaitForSignalOrTimeout::WaitForSignalOrTimeout() = default;
|
||||
+WaitForSignalOrTimeout::~WaitForSignalOrTimeout() = default;
|
||||
+
|
||||
+void WaitForSignalOrTimeout::Signal() {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
|
||||
+ SignalHandler(/*triggered_by_signal=*/true);
|
||||
+}
|
||||
+
|
||||
+bool WaitForSignalOrTimeout::IsSignaled() const {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
|
||||
+ return state_ == State::kSignalReceived || state_ == State::kDone;
|
||||
+}
|
||||
+
|
||||
+void WaitForSignalOrTimeout::OnEventOrTimeOut(Callback callback,
|
||||
+ base::TimeDelta timeout) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
|
||||
+ switch (state_) {
|
||||
+ case State::kInitialState:
|
||||
+ callback_ = std::move(callback);
|
||||
+ ++generation_id_; // Invalidate previous OnTimeOut tasks.
|
||||
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
|
||||
+ FROM_HERE,
|
||||
+ base::BindOnce(&WaitForSignalOrTimeout::OnTimeOut,
|
||||
+ weak_factory_.GetWeakPtr(), generation_id_),
|
||||
+ timeout);
|
||||
+ break;
|
||||
+
|
||||
+ case State::kSignalReceived:
|
||||
+ state_ = State::kDone;
|
||||
+ std::move(callback).Run(
|
||||
+ /*triggered_by_signal=*/in_state_signal_received_due_to_signal_call_);
|
||||
+ break;
|
||||
+
|
||||
+ case State::kDone:
|
||||
+ Reset();
|
||||
+ OnEventOrTimeOut(std::move(callback), timeout);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void WaitForSignalOrTimeout::Reset() {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
|
||||
+ state_ = State::kInitialState;
|
||||
+ ++generation_id_;
|
||||
+ callback_ = Callback();
|
||||
+}
|
||||
+
|
||||
+void WaitForSignalOrTimeout::OnTimeOut(int generation_id) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
|
||||
+ if (generation_id == generation_id_)
|
||||
+ SignalHandler(/*triggered_by_signal=*/false);
|
||||
+}
|
||||
+
|
||||
+void WaitForSignalOrTimeout::SignalHandler(bool triggered_by_signal) {
|
||||
+ switch (state_) {
|
||||
+ case State::kInitialState:
|
||||
+ if (callback_.is_null()) {
|
||||
+ state_ = State::kSignalReceived;
|
||||
+ in_state_signal_received_due_to_signal_call_ = triggered_by_signal;
|
||||
+ } else {
|
||||
+ state_ = State::kDone;
|
||||
+ std::move(callback_).Run(triggered_by_signal);
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case State::kSignalReceived:
|
||||
+ case State::kDone:
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/components/autofill/core/browser/payments/wait_for_signal_or_timeout.h b/components/autofill/core/browser/payments/wait_for_signal_or_timeout.h
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6b2c451245441f784938e4132e2ab03e7d85f9b6
|
||||
--- /dev/null
|
||||
+++ b/components/autofill/core/browser/payments/wait_for_signal_or_timeout.h
|
||||
@@ -0,0 +1,100 @@
|
||||
+// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_WAIT_FOR_SIGNAL_OR_TIMEOUT_H_
|
||||
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_WAIT_FOR_SIGNAL_OR_TIMEOUT_H_
|
||||
+
|
||||
+#include "base/callback.h"
|
||||
+#include "base/memory/weak_ptr.h"
|
||||
+#include "base/sequence_checker.h"
|
||||
+#include "base/time/time.h"
|
||||
+
|
||||
+// A WaitForSignalOrTimeout waits for Signal() or a time out and calls a
|
||||
+// callback when either of these happens for the first time.
|
||||
+//
|
||||
+// The WaitForSignalOrTimeout is Reset()-able and ensures that the callback will
|
||||
+// be called at most once (unless Reset() resets the state). The
|
||||
+// WaitForSignalOrTimeout can be destroyed at any time without negative
|
||||
+// side-effects. The callback won't be called in this case. If the Signal()
|
||||
+// arrives before a call for OnEventOrTimeOut(), the callback will be called
|
||||
+// immediately. If a second Signal() arrives, nothing happens. The
|
||||
+// WaitForSignalOrTimeout must be used on single task sequence.
|
||||
+//
|
||||
+// This class provides the bare minimum needed for a Payment task. If there are
|
||||
+// more use cases, feel free to spice it up and move it to base/.
|
||||
+class WaitForSignalOrTimeout {
|
||||
+ public:
|
||||
+ // The passed boolean is true if the callback happened by a call of Signal()
|
||||
+ // (as opposed to a timeout).
|
||||
+ using Callback = base::OnceCallback<void(bool)>;
|
||||
+
|
||||
+ WaitForSignalOrTimeout();
|
||||
+ ~WaitForSignalOrTimeout();
|
||||
+ WaitForSignalOrTimeout(const WaitForSignalOrTimeout&) = delete;
|
||||
+ WaitForSignalOrTimeout& operator=(const WaitForSignalOrTimeout&) = delete;
|
||||
+
|
||||
+ // Triggers |callback_| if it has not been called before, or registers that
|
||||
+ // the signal occurred, so that |callback| of OnEventOrTimeOut() can be
|
||||
+ // called immediately.
|
||||
+ void Signal();
|
||||
+
|
||||
+ // Returns whether Signal() was called at least once or a timeout happened,
|
||||
+ // and Reset() has not been called afterwards. Note that this function does
|
||||
+ // not discriminate whether Signal() was called or a timeout happened.
|
||||
+ // The |callback_|'s parameter has this distinction, though.
|
||||
+ bool IsSignaled() const;
|
||||
+
|
||||
+ // Registers the |callback| and calls it immediately if Signal() was called
|
||||
+ // already. Starts a timeout task, so that |callback| is called if no call of
|
||||
+ // Signal() is observed within |timeout|. A previous timeout is replaced by a
|
||||
+ // new one.
|
||||
+ void OnEventOrTimeOut(Callback callback, base::TimeDelta timeout);
|
||||
+
|
||||
+ // Resets the state machine so that no Signal() was observed, no callback is
|
||||
+ // registered and no timeout task is running.
|
||||
+ void Reset();
|
||||
+
|
||||
+ private:
|
||||
+ enum class State {
|
||||
+ // Signal() has not been called, yet.
|
||||
+ kInitialState,
|
||||
+ // Signal() has been called, but callback is not specified.
|
||||
+ kSignalReceived,
|
||||
+ // callback has been called.
|
||||
+ kDone,
|
||||
+ };
|
||||
+
|
||||
+ // Internal callback for the timeout. |generation_id| is a generation counter
|
||||
+ // to ensure that old, delayed timeout tasks are ignored.
|
||||
+ void OnTimeOut(int generation_id);
|
||||
+
|
||||
+ // Handler for Signal() and OnTimeOut(). Calls |callback_| if appropriate.
|
||||
+ // The parameter is true if this function is called via Signal() and false if
|
||||
+ // the function is called via OnTimeOut(). This parameter is passed to
|
||||
+ // callback.
|
||||
+ void SignalHandler(bool triggered_by_signal);
|
||||
+
|
||||
+ State state_ = State::kInitialState;
|
||||
+
|
||||
+ // This variable is only valid if state_ == State::kSignalReceived. It is
|
||||
+ // true if we moved into this state due to a Signal() call, and false if
|
||||
+ // we moved into this state due to an OnTimeOut() call.
|
||||
+ bool in_state_signal_received_due_to_signal_call_;
|
||||
+
|
||||
+ // As the base::ThreadPool does not support cancelable tasks, we just rely on
|
||||
+ // a generation counter. Every time Reset() or OnEventOrTimeOut() are called,
|
||||
+ // the generation id is incremented. If outdated delayed OnTimeOut() tasks
|
||||
+ // trickle in, we recognize them as tasks for which the |generation_id|
|
||||
+ // parameter is less than the current generation_id_ and ignore them.
|
||||
+ int generation_id_ = 0;
|
||||
+
|
||||
+ // Callback to be called in case of a Signal() or a time out.
|
||||
+ Callback callback_;
|
||||
+
|
||||
+ SEQUENCE_CHECKER(my_sequence_checker_);
|
||||
+
|
||||
+ base::WeakPtrFactory<WaitForSignalOrTimeout> weak_factory_{this};
|
||||
+};
|
||||
+
|
||||
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_WAIT_FOR_SIGNAL_OR_TIMEOUT_H_
|
||||
diff --git a/components/autofill/core/browser/payments/wait_for_signal_or_timeout_unittest.cc b/components/autofill/core/browser/payments/wait_for_signal_or_timeout_unittest.cc
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..eda3fd362221cb9c08c893af02ce33a2826c5d6f
|
||||
--- /dev/null
|
||||
+++ b/components/autofill/core/browser/payments/wait_for_signal_or_timeout_unittest.cc
|
||||
@@ -0,0 +1,188 @@
|
||||
+// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+#include "components/autofill/core/browser/payments/wait_for_signal_or_timeout.h"
|
||||
+
|
||||
+#include "base/test/task_environment.h"
|
||||
+#include "testing/gtest/include/gtest/gtest.h"
|
||||
+
|
||||
+class WaitForSignalOrTimeoutTest : public testing::Test {
|
||||
+ public:
|
||||
+ WaitForSignalOrTimeoutTest() = default;
|
||||
+ ~WaitForSignalOrTimeoutTest() override = default;
|
||||
+
|
||||
+ WaitForSignalOrTimeout::Callback GetCallback() {
|
||||
+ return base::BindOnce(&WaitForSignalOrTimeoutTest::Callback,
|
||||
+ base::Unretained(this));
|
||||
+ }
|
||||
+
|
||||
+ protected:
|
||||
+ void Callback(bool triggered_by_signal) {
|
||||
+ callbacks_++;
|
||||
+ last_callback_triggered_by_signal_ = triggered_by_signal;
|
||||
+ }
|
||||
+
|
||||
+ // Number of observed callbacks.
|
||||
+ int callbacks_ = 0;
|
||||
+
|
||||
+ bool last_callback_triggered_by_signal_ = false;
|
||||
+
|
||||
+ base::test::TaskEnvironment task_env_{
|
||||
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
|
||||
+};
|
||||
+
|
||||
+// WaitForSignalOrTimeout is initialized with a callback and then the Signal()
|
||||
+// happens.
|
||||
+TEST_F(WaitForSignalOrTimeoutTest, InitThenSignal) {
|
||||
+ WaitForSignalOrTimeout wait;
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+ wait.Signal();
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_TRUE(last_callback_triggered_by_signal_);
|
||||
+
|
||||
+ // Another signal call should be ignored.
|
||||
+ wait.Signal();
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+
|
||||
+ // Also the pending timeout should not trigger further callbacks.
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35));
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+}
|
||||
+
|
||||
+// A Signal() is registered before the callback.
|
||||
+TEST_F(WaitForSignalOrTimeoutTest, SignalThenInit) {
|
||||
+ WaitForSignalOrTimeout wait;
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+
|
||||
+ // Trigger the signal before a callback handler is registered.
|
||||
+ wait.Signal();
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+
|
||||
+ // Once the callback handler is registered, it should be called immediately.
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ EXPECT_TRUE(last_callback_triggered_by_signal_);
|
||||
+
|
||||
+ // Another signal call should be ignored.
|
||||
+ wait.Signal();
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+
|
||||
+ // Also the pending timeout should not trigger further callbacks.
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35));
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+}
|
||||
+
|
||||
+// A timeout occurs before Signal() is called.
|
||||
+TEST_F(WaitForSignalOrTimeoutTest, InitThenTimeout) {
|
||||
+ WaitForSignalOrTimeout wait;
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35));
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ EXPECT_FALSE(last_callback_triggered_by_signal_);
|
||||
+
|
||||
+ // A late signal will be ignored.
|
||||
+ wait.Signal();
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+}
|
||||
+
|
||||
+// The WaitForSignalOrTimeout gets destroyed before a Signal() or timeout
|
||||
+// happens.
|
||||
+TEST_F(WaitForSignalOrTimeoutTest, DestroyedBeforeSignal) {
|
||||
+ {
|
||||
+ WaitForSignalOrTimeout wait;
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ }
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35));
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+}
|
||||
+
|
||||
+// The WaitForSignalOrTimeout gets signaled, reset, and signaled again.
|
||||
+TEST_F(WaitForSignalOrTimeoutTest, Reset) {
|
||||
+ WaitForSignalOrTimeout wait;
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+ wait.Signal();
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_TRUE(last_callback_triggered_by_signal_);
|
||||
+
|
||||
+ wait.Reset();
|
||||
+
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+
|
||||
+ // This signal does not trigger a callback because none is registered.
|
||||
+ wait.Signal();
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ // Now the callback happens immediately.
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ EXPECT_EQ(2, callbacks_);
|
||||
+ EXPECT_TRUE(last_callback_triggered_by_signal_);
|
||||
+
|
||||
+ wait.Reset();
|
||||
+
|
||||
+ // Finally, we simulate a timeout after the reset.
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35));
|
||||
+ EXPECT_EQ(3, callbacks_);
|
||||
+ EXPECT_FALSE(last_callback_triggered_by_signal_);
|
||||
+}
|
||||
+
|
||||
+TEST_F(WaitForSignalOrTimeoutTest, OnEventOrTimeOutCalledTwice) {
|
||||
+ WaitForSignalOrTimeout wait;
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+
|
||||
+ // Wait some time but not long enough for the timeout to trigger.
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(25));
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+
|
||||
+ // This resets the state machine (currently waiting for a signal or timeout)
|
||||
+ // and starts a new wait.
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+
|
||||
+ // Wait some time but not long enough for the timeout to trigger.
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(25));
|
||||
+ // The first timeout should not have triggered anything.
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+
|
||||
+ // Wait some more time for the second timeout to kick in.
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(10));
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_FALSE(last_callback_triggered_by_signal_);
|
||||
+
|
||||
+ // This resets the state machine (currently in done state) once more and
|
||||
+ // starts a new wait.
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+
|
||||
+ // Wait some time but not long enough for the timeout to trigger.
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(25));
|
||||
+ // The first timeout should not have triggered anything.
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+
|
||||
+ // Wait some more time for the second timeout to kick in.
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(10));
|
||||
+ EXPECT_EQ(2, callbacks_);
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_FALSE(last_callback_triggered_by_signal_);
|
||||
+}
|
||||
@@ -0,0 +1,48 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Fredrik=20S=C3=B6derqvist?= <fs@opera.com>
|
||||
Date: Fri, 9 Jul 2021 08:44:55 +0000
|
||||
Subject: Set SVGImage::page_ after document install
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
We can end up having the associated ImageResource call
|
||||
SVGImage::ResetAnimation() before the Document has been associated with
|
||||
the SVGImage's LocalFrame, but after the link to the initial Document
|
||||
was severed, if a GC is triggered within that window and ends up
|
||||
collecting the last observer of the ImageResource.
|
||||
|
||||
By assigning |SVGImage::page_| after the installing the document, we
|
||||
close this hole since SVGImage::RootElement() (called by
|
||||
SVGImage::ResetAnimation()) will now observe a null Page and return null
|
||||
without attempting to dereference the document.
|
||||
|
||||
Bug: 1216190
|
||||
Change-Id: I26e08848e5b9bd52e3377841eee35e4acc03d320
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3010140
|
||||
Reviewed-by: Stephen Chenney <schenney@chromium.org>
|
||||
Commit-Queue: Fredrik Söderquist <fs@opera.com>
|
||||
Cr-Commit-Position: refs/heads/master@{#899922}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image.cc b/third_party/blink/renderer/core/svg/graphics/svg_image.cc
|
||||
index 2ce8a78b3537c72206e2d3e6d55f9cc1fc5d3208..0dec91614edb0caa6f8e473f027c3be7b8bf1e4e 100644
|
||||
--- a/third_party/blink/renderer/core/svg/graphics/svg_image.cc
|
||||
+++ b/third_party/blink/renderer/core/svg/graphics/svg_image.cc
|
||||
@@ -830,12 +830,15 @@ Image::SizeAvailability SVGImage::DataChanged(bool all_data_received) {
|
||||
// SVG Images are transparent.
|
||||
frame->View()->SetBaseBackgroundColor(Color::kTransparent);
|
||||
|
||||
- page_ = page;
|
||||
-
|
||||
TRACE_EVENT0("blink", "SVGImage::dataChanged::load");
|
||||
|
||||
frame->ForceSynchronousDocumentInstall("image/svg+xml", Data());
|
||||
|
||||
+ // Set up our Page reference after installing our document. This avoids
|
||||
+ // tripping on a non-existing (null) Document if a GC is triggered during the
|
||||
+ // set up and ends up collecting the last owner/observer of this image.
|
||||
+ page_ = page;
|
||||
+
|
||||
// Intrinsic sizing relies on computed style (e.g. font-size and
|
||||
// writing-mode).
|
||||
frame->GetDocument()->UpdateStyleAndLayoutTree();
|
||||
@@ -19,5 +19,7 @@
|
||||
|
||||
"src/electron/patches/angle": "src/third_party/angle",
|
||||
|
||||
"src/electron/patches/usrsctp": "src/third_party/usrsctp/usrsctplib"
|
||||
"src/electron/patches/usrsctp": "src/third_party/usrsctp/usrsctplib",
|
||||
|
||||
"src/electron/patches/sqlite": "src/third_party/sqlite/src"
|
||||
}
|
||||
|
||||
1
patches/sqlite/.patches
Normal file
1
patches/sqlite/.patches
Normal file
@@ -0,0 +1 @@
|
||||
utf-8_q_when_20constructing_20the_20synthensized_20select_20sta.patch
|
||||
@@ -0,0 +1,178 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: drh <>
|
||||
Date: Wed, 19 May 2021 21:55:56 +0000
|
||||
Subject: When constructing the synthensized SELECT statement that is used to
|
||||
choose the rows in an UPDATE FROM, make sure the first table is really the
|
||||
table being updated, and not some common-table expression that happens to
|
||||
have the same name. [forum:/forumpost/a274248080|forum post a274248080]. More
|
||||
changes associated with CTE name resolution are pending.
|
||||
|
||||
FossilOrigin-Name: 0f0959c6f95046e8e7887716e0a7de95da18d1e926ab1f919527083a56541db5
|
||||
(cherry picked from commit 1168f810929ede4d8d323a6acf721ff9cd89de90)
|
||||
|
||||
diff --git a/amalgamation/sqlite3.c b/amalgamation/sqlite3.c
|
||||
index 6b4a7899d336d07cf150530440755d25207b594f..d19e25f98d37686a7fd1bfefe4bd044575abf5d4 100644
|
||||
--- a/amalgamation/sqlite3.c
|
||||
+++ b/amalgamation/sqlite3.c
|
||||
@@ -1173,7 +1173,7 @@ extern "C" {
|
||||
*/
|
||||
#define SQLITE_VERSION "3.34.0"
|
||||
#define SQLITE_VERSION_NUMBER 3034000
|
||||
-#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 b7738010bc8ef02ba84820368e557306390a33c38adaa5c7703154bae3edalt1"
|
||||
+#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 571f9642d6a6caff9ea5ea572e2f1275e75c8385fbe1b7fb41cf72e4c13ealt1"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
@@ -111305,7 +111305,7 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem(
|
||||
struct SrcList_item *p
|
||||
){
|
||||
const char *zDb;
|
||||
- assert( p->pSchema==0 || p->zDatabase==0 );
|
||||
+ /* assert( p->pSchema==0 || p->zDatabase==0 ); FIX-ME */
|
||||
if( p->pSchema ){
|
||||
int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
|
||||
zDb = pParse->db->aDb[iDb].zDbSName;
|
||||
@@ -138346,6 +138346,10 @@ static void updateFromSelect(
|
||||
|
||||
assert( pTabList->nSrc>1 );
|
||||
if( pSrc ){
|
||||
+ if( pSrc->a[0].zDatabase==0 ){
|
||||
+ int iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
+ pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iSchema].zDbSName);
|
||||
+ }
|
||||
pSrc->a[0].iCursor = -1;
|
||||
pSrc->a[0].pTab->nTabRef--;
|
||||
pSrc->a[0].pTab = 0;
|
||||
@@ -231234,9 +231238,9 @@ SQLITE_API int sqlite3_stmt_init(
|
||||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
|
||||
|
||||
/************** End of stmt.c ************************************************/
|
||||
-#if __LINE__!=231237
|
||||
+#if __LINE__!=231241
|
||||
#undef SQLITE_SOURCE_ID
|
||||
-#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 b7738010bc8ef02ba84820368e557306390a33c38adaa5c7703154bae3edalt2"
|
||||
+#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 571f9642d6a6caff9ea5ea572e2f1275e75c8385fbe1b7fb41cf72e4c13ealt2"
|
||||
#endif
|
||||
/* Return the source-id for this library */
|
||||
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
|
||||
diff --git a/amalgamation/sqlite3.h b/amalgamation/sqlite3.h
|
||||
index 44be7872663c9216b30ce6e13b1683ca2d807bd6..4935dd32d6aab4261b758c4c199ef0ad18c23ce9 100644
|
||||
--- a/amalgamation/sqlite3.h
|
||||
+++ b/amalgamation/sqlite3.h
|
||||
@@ -125,7 +125,7 @@ extern "C" {
|
||||
*/
|
||||
#define SQLITE_VERSION "3.34.0"
|
||||
#define SQLITE_VERSION_NUMBER 3034000
|
||||
-#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 b7738010bc8ef02ba84820368e557306390a33c38adaa5c7703154bae3edalt1"
|
||||
+#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 571f9642d6a6caff9ea5ea572e2f1275e75c8385fbe1b7fb41cf72e4c13ealt1"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
diff --git a/amalgamation_dev/sqlite3.c b/amalgamation_dev/sqlite3.c
|
||||
index d30c9b7dea35e5b4785f78b8bc5789fbc56bba84..f4c985513fb7cac3930fe9706ddfc5c440dd3e85 100644
|
||||
--- a/amalgamation_dev/sqlite3.c
|
||||
+++ b/amalgamation_dev/sqlite3.c
|
||||
@@ -1173,7 +1173,7 @@ extern "C" {
|
||||
*/
|
||||
#define SQLITE_VERSION "3.34.0"
|
||||
#define SQLITE_VERSION_NUMBER 3034000
|
||||
-#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 b7738010bc8ef02ba84820368e557306390a33c38adaa5c7703154bae3edalt1"
|
||||
+#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 571f9642d6a6caff9ea5ea572e2f1275e75c8385fbe1b7fb41cf72e4c13ealt1"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
@@ -111318,7 +111318,7 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem(
|
||||
struct SrcList_item *p
|
||||
){
|
||||
const char *zDb;
|
||||
- assert( p->pSchema==0 || p->zDatabase==0 );
|
||||
+ /* assert( p->pSchema==0 || p->zDatabase==0 ); FIX-ME */
|
||||
if( p->pSchema ){
|
||||
int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
|
||||
zDb = pParse->db->aDb[iDb].zDbSName;
|
||||
@@ -138359,6 +138359,10 @@ static void updateFromSelect(
|
||||
|
||||
assert( pTabList->nSrc>1 );
|
||||
if( pSrc ){
|
||||
+ if( pSrc->a[0].zDatabase==0 ){
|
||||
+ int iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
+ pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iSchema].zDbSName);
|
||||
+ }
|
||||
pSrc->a[0].iCursor = -1;
|
||||
pSrc->a[0].pTab->nTabRef--;
|
||||
pSrc->a[0].pTab = 0;
|
||||
@@ -231747,9 +231751,9 @@ SQLITE_API int sqlite3_stmt_init(
|
||||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
|
||||
|
||||
/************** End of stmt.c ************************************************/
|
||||
-#if __LINE__!=231750
|
||||
+#if __LINE__!=231754
|
||||
#undef SQLITE_SOURCE_ID
|
||||
-#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 b7738010bc8ef02ba84820368e557306390a33c38adaa5c7703154bae3edalt2"
|
||||
+#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 571f9642d6a6caff9ea5ea572e2f1275e75c8385fbe1b7fb41cf72e4c13ealt2"
|
||||
#endif
|
||||
/* Return the source-id for this library */
|
||||
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
|
||||
diff --git a/amalgamation_dev/sqlite3.h b/amalgamation_dev/sqlite3.h
|
||||
index 44be7872663c9216b30ce6e13b1683ca2d807bd6..4935dd32d6aab4261b758c4c199ef0ad18c23ce9 100644
|
||||
--- a/amalgamation_dev/sqlite3.h
|
||||
+++ b/amalgamation_dev/sqlite3.h
|
||||
@@ -125,7 +125,7 @@ extern "C" {
|
||||
*/
|
||||
#define SQLITE_VERSION "3.34.0"
|
||||
#define SQLITE_VERSION_NUMBER 3034000
|
||||
-#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 b7738010bc8ef02ba84820368e557306390a33c38adaa5c7703154bae3edalt1"
|
||||
+#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 571f9642d6a6caff9ea5ea572e2f1275e75c8385fbe1b7fb41cf72e4c13ealt1"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
diff --git a/manifest b/manifest
|
||||
index 6c9cbb5ed81ca973f03931cea4d861209dee7037..76872d8b3a63cf623a1903ac0ccfc9b80f5c47d3 100644
|
||||
--- a/manifest
|
||||
+++ b/manifest
|
||||
@@ -483,7 +483,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c ee14224322b9e4172d01e691e2f289f6c630ae39b7906f84b72dc780b9e42a76
|
||||
F src/btree.h dcdff4037d75b3f032a5de0d922fcfaf35d48589417f634fa8627362709315f9
|
||||
F src/btreeInt.h ffd66480520d9d70222171b3a026d78b80833b5cea49c89867949f3e023d5f43
|
||||
-F src/build.c f6449d4e85e998e14d3f537e8ea898dca2fcb83c277db3e60945af9b9177db81
|
||||
+F src/build.c 0803beedb8312c4ee4d60e63390ad0480a4ef471a329a56f8887a4b6ffc66da5
|
||||
F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c e98518d2d3d4029a13c805e07313fb60c877be56db76e90dd5f3af73085d0ce6
|
||||
@@ -606,7 +606,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 4dc01b267593537e2a0d0efe9f80dabe24c5b6f7627bc6971c487fa6a1dacbbf
|
||||
F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda
|
||||
F src/trigger.c 515e79206d40d1d4149129318582e79a6e9db590a7b74e226fdb5b2a6c7e1b10
|
||||
-F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580
|
||||
+F src/update.c 3e767f6605ed3adf6085d7e3eb8bbcf7e845b60ebf5590720123b24f907d7414
|
||||
F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002
|
||||
diff --git a/src/build.c b/src/build.c
|
||||
index 9779e93732b6d2f50cf5ac3822df1fbe6802eaa6..29d8ea66c105f9098c49ade70246828c92465f96 100644
|
||||
--- a/src/build.c
|
||||
+++ b/src/build.c
|
||||
@@ -451,7 +451,7 @@ Table *sqlite3LocateTableItem(
|
||||
struct SrcList_item *p
|
||||
){
|
||||
const char *zDb;
|
||||
- assert( p->pSchema==0 || p->zDatabase==0 );
|
||||
+ /* assert( p->pSchema==0 || p->zDatabase==0 ); FIX-ME */
|
||||
if( p->pSchema ){
|
||||
int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
|
||||
zDb = pParse->db->aDb[iDb].zDbSName;
|
||||
diff --git a/src/update.c b/src/update.c
|
||||
index f8cb2afedb6f9f2931d29d266f65fabcd2cd443c..3e0ec2544a274356c68416d978c8585a143bf8a4 100644
|
||||
--- a/src/update.c
|
||||
+++ b/src/update.c
|
||||
@@ -220,6 +220,10 @@ static void updateFromSelect(
|
||||
|
||||
assert( pTabList->nSrc>1 );
|
||||
if( pSrc ){
|
||||
+ if( pSrc->a[0].zDatabase==0 ){
|
||||
+ int iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
+ pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iSchema].zDbSName);
|
||||
+ }
|
||||
pSrc->a[0].iCursor = -1;
|
||||
pSrc->a[0].pTab->nTabRef--;
|
||||
pSrc->a[0].pTab = 0;
|
||||
@@ -24,3 +24,5 @@ cherry-pick-d0aadee1a60a.patch
|
||||
m90-lts_squashed_multiple_commits.patch
|
||||
cherry-pick-b9ad6a864c79.patch
|
||||
cherry-pick-50de6a8ddad9.patch
|
||||
cherry-pick-e76178b896f2.patch
|
||||
merged_compiler_fix_a_bug_in.patch
|
||||
|
||||
65
patches/v8/cherry-pick-e76178b896f2.patch
Normal file
65
patches/v8/cherry-pick-e76178b896f2.patch
Normal file
@@ -0,0 +1,65 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Victor Gomes <victorgomes@chromium.org>
|
||||
Date: Mon, 31 May 2021 13:16:54 +0200
|
||||
Subject: Merged: [JSON] Fix GC issue in BuildJsonObject
|
||||
|
||||
We must ensure that the sweeper is not running or has already swept
|
||||
mutable_double_buffer. Otherwise the GC can add it to the free list.
|
||||
|
||||
Change-Id: If0fc7617acdb6690f0567215b78f8728e1643ec0
|
||||
No-Try: true
|
||||
No-Presubmit: true
|
||||
No-Tree-Checks: true
|
||||
Bug: v8:11837, chromium:1214842
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2993033
|
||||
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/9.1@{#75}
|
||||
Cr-Branched-From: 0e4ac64a8cf298b14034a22f9fe7b085d2cb238d-refs/heads/9.1.269@{#1}
|
||||
Cr-Branched-From: f565e72d5ba88daae35a59d0f978643e2343e912-refs/heads/master@{#73847}
|
||||
|
||||
diff --git a/src/heap/heap.cc b/src/heap/heap.cc
|
||||
index 3f4348b063995eb5c23ddd8af2aa2ac900a88723..5239523c23d63c2af57a3a9795939bd582d7d10c 100644
|
||||
--- a/src/heap/heap.cc
|
||||
+++ b/src/heap/heap.cc
|
||||
@@ -2125,6 +2125,10 @@ void Heap::CompleteSweepingYoung(GarbageCollector collector) {
|
||||
array_buffer_sweeper()->EnsureFinished();
|
||||
}
|
||||
|
||||
+void Heap::EnsureSweepingCompleted() {
|
||||
+ mark_compact_collector()->EnsureSweepingCompleted();
|
||||
+}
|
||||
+
|
||||
void Heap::UpdateCurrentEpoch(GarbageCollector collector) {
|
||||
if (IsYoungGenerationCollector(collector)) {
|
||||
epoch_young_ = next_epoch();
|
||||
diff --git a/src/heap/heap.h b/src/heap/heap.h
|
||||
index 7dc9ef7d447521012c9b110e4fc94589ada3e6f4..b56641f2e1c51197a68d7c96d5bfca428feb1484 100644
|
||||
--- a/src/heap/heap.h
|
||||
+++ b/src/heap/heap.h
|
||||
@@ -1068,6 +1068,8 @@ class Heap {
|
||||
void CompleteSweepingFull();
|
||||
void CompleteSweepingYoung(GarbageCollector collector);
|
||||
|
||||
+ void EnsureSweepingCompleted();
|
||||
+
|
||||
IncrementalMarking* incremental_marking() {
|
||||
return incremental_marking_.get();
|
||||
}
|
||||
diff --git a/src/json/json-parser.cc b/src/json/json-parser.cc
|
||||
index c0109bb77a01f7b6e8e23cd1b2f5d85c4473385b..c9844251cc8659587b3de85066cb0ea993d87014 100644
|
||||
--- a/src/json/json-parser.cc
|
||||
+++ b/src/json/json-parser.cc
|
||||
@@ -633,6 +633,11 @@ Handle<Object> JsonParser<Char>::BuildJsonObject(
|
||||
DCHECK_EQ(mutable_double_address, end);
|
||||
}
|
||||
#endif
|
||||
+ // Before setting the length of mutable_double_buffer back to zero, we
|
||||
+ // must ensure that the sweeper is not running or has already swept the
|
||||
+ // object's page. Otherwise the GC can add the contents of
|
||||
+ // mutable_double_buffer to the free list.
|
||||
+ isolate()->heap()->EnsureSweepingCompleted();
|
||||
mutable_double_buffer->set_length(0);
|
||||
}
|
||||
}
|
||||
35
patches/v8/merged_compiler_fix_a_bug_in.patch
Normal file
35
patches/v8/merged_compiler_fix_a_bug_in.patch
Normal file
@@ -0,0 +1,35 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Georg Neis <neis@chromium.org>
|
||||
Date: Tue, 13 Jul 2021 17:26:47 +0200
|
||||
Subject: Merged: [compiler] Fix a bug in
|
||||
CodeGenerator::AddTranslationForOperand
|
||||
|
||||
(cherry picked from commit 374354bfe4a30740b96936b33e522d6fcd1cda67)
|
||||
|
||||
Bug: chromium:1228407
|
||||
No-Try: true
|
||||
No-Presubmit: true
|
||||
No-Tree-Checks: true
|
||||
Change-Id: I358d8736b7b5f87300496cbb39a7689d8207d85f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3027260
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Reviewed-by: Adam Klein <adamk@chromium.org>
|
||||
Commit-Queue: Adam Klein <adamk@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/9.1@{#77}
|
||||
Cr-Branched-From: 0e4ac64a8cf298b14034a22f9fe7b085d2cb238d-refs/heads/9.1.269@{#1}
|
||||
Cr-Branched-From: f565e72d5ba88daae35a59d0f978643e2343e912-refs/heads/master@{#73847}
|
||||
|
||||
diff --git a/src/compiler/backend/code-generator.cc b/src/compiler/backend/code-generator.cc
|
||||
index 83f8fbc4e8fdbbfea81ae5b368f0dbcf5b32b5bb..647444fa58b559cda4aaf257b0a477282eafd569 100644
|
||||
--- a/src/compiler/backend/code-generator.cc
|
||||
+++ b/src/compiler/backend/code-generator.cc
|
||||
@@ -1389,7 +1389,8 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation,
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
- if (literal.object().equals(info()->closure())) {
|
||||
+ if (literal.object().equals(info()->closure()) &&
|
||||
+ info()->function_context_specializing()) {
|
||||
translation->StoreJSFrameFunction();
|
||||
} else {
|
||||
int literal_id = DefineDeoptimizationLiteral(literal);
|
||||
@@ -9,7 +9,8 @@ const rootPackageJson = require('../../package.json');
|
||||
|
||||
const { Octokit } = require('@octokit/rest');
|
||||
const octokit = new Octokit({
|
||||
userAgent: 'electron-npm-publisher'
|
||||
userAgent: 'electron-npm-publisher',
|
||||
auth: process.env.ELECTRON_GITHUB_TOKEN
|
||||
});
|
||||
|
||||
if (!process.env.ELECTRON_NPM_OTP) {
|
||||
|
||||
@@ -524,4 +524,8 @@ async function validateChecksums (validationArgs) {
|
||||
`shasums defined in ${validationArgs.shaSumFile}.`);
|
||||
}
|
||||
|
||||
makeRelease(args.validateRelease);
|
||||
makeRelease(args.validateRelease)
|
||||
.catch((err) => {
|
||||
console.error('Error occurred while making release:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -103,7 +103,75 @@ namespace crash_reporter {
|
||||
extern const char kCrashpadProcess[];
|
||||
}
|
||||
|
||||
// In 32-bit builds, the main thread starts with the default (small) stack size.
|
||||
// The ARCH_CPU_32_BITS blocks here and below are in support of moving the main
|
||||
// thread to a fiber with a larger stack size.
|
||||
#if defined(ARCH_CPU_32_BITS)
|
||||
// The information needed to transfer control to the large-stack fiber and later
|
||||
// pass the main routine's exit code back to the small-stack fiber prior to
|
||||
// termination.
|
||||
struct FiberState {
|
||||
HINSTANCE instance;
|
||||
LPVOID original_fiber;
|
||||
int fiber_result;
|
||||
};
|
||||
|
||||
// A PFIBER_START_ROUTINE function run on a large-stack fiber that calls the
|
||||
// main routine, stores its return value, and returns control to the small-stack
|
||||
// fiber. |params| must be a pointer to a FiberState struct.
|
||||
void WINAPI FiberBinder(void* params) {
|
||||
auto* fiber_state = static_cast<FiberState*>(params);
|
||||
// Call the wWinMain routine from the fiber. Reusing the entry point minimizes
|
||||
// confusion when examining call stacks in crash reports - seeing wWinMain on
|
||||
// the stack is a handy hint that this is the main thread of the process.
|
||||
fiber_state->fiber_result =
|
||||
wWinMain(fiber_state->instance, nullptr, nullptr, 0);
|
||||
// Switch back to the main thread to exit.
|
||||
::SwitchToFiber(fiber_state->original_fiber);
|
||||
}
|
||||
#endif // defined(ARCH_CPU_32_BITS)
|
||||
|
||||
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
|
||||
#if defined(ARCH_CPU_32_BITS)
|
||||
enum class FiberStatus { kConvertFailed, kCreateFiberFailed, kSuccess };
|
||||
FiberStatus fiber_status = FiberStatus::kSuccess;
|
||||
// GetLastError result if fiber conversion failed.
|
||||
DWORD fiber_error = ERROR_SUCCESS;
|
||||
if (!::IsThreadAFiber()) {
|
||||
// Make the main thread's stack size 4 MiB so that it has roughly the same
|
||||
// effective size as the 64-bit build's 8 MiB stack.
|
||||
constexpr size_t kStackSize = 4 * 1024 * 1024; // 4 MiB
|
||||
// Leak the fiber on exit.
|
||||
LPVOID original_fiber =
|
||||
::ConvertThreadToFiberEx(nullptr, FIBER_FLAG_FLOAT_SWITCH);
|
||||
if (original_fiber) {
|
||||
FiberState fiber_state = {instance, original_fiber};
|
||||
// Create a fiber with a bigger stack and switch to it. Leak the fiber on
|
||||
// exit.
|
||||
LPVOID big_stack_fiber = ::CreateFiberEx(
|
||||
0, kStackSize, FIBER_FLAG_FLOAT_SWITCH, FiberBinder, &fiber_state);
|
||||
if (big_stack_fiber) {
|
||||
::SwitchToFiber(big_stack_fiber);
|
||||
// The fibers must be cleaned up to avoid obscure TLS-related shutdown
|
||||
// crashes.
|
||||
::DeleteFiber(big_stack_fiber);
|
||||
::ConvertFiberToThread();
|
||||
// Control returns here after Chrome has finished running on FiberMain.
|
||||
return fiber_state.fiber_result;
|
||||
}
|
||||
fiber_status = FiberStatus::kCreateFiberFailed;
|
||||
} else {
|
||||
fiber_status = FiberStatus::kConvertFailed;
|
||||
}
|
||||
// If we reach here then creating and switching to a fiber has failed. This
|
||||
// probably means we are low on memory and will soon crash. Try to report
|
||||
// this error once crash reporting is initialized.
|
||||
fiber_error = ::GetLastError();
|
||||
base::debug::Alias(&fiber_error);
|
||||
}
|
||||
// If we are already a fiber then continue normal execution.
|
||||
#endif // defined(ARCH_CPU_32_BITS)
|
||||
|
||||
struct Arguments {
|
||||
int argc = 0;
|
||||
wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
|
||||
@@ -198,6 +266,11 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
|
||||
return crashpad_status;
|
||||
}
|
||||
|
||||
#if defined(ARCH_CPU_32_BITS)
|
||||
// Intentionally crash if converting to a fiber failed.
|
||||
CHECK_EQ(fiber_status, FiberStatus::kSuccess);
|
||||
#endif // defined(ARCH_CPU_32_BITS)
|
||||
|
||||
if (!electron::CheckCommandLineArguments(arguments.argc, arguments.argv))
|
||||
return -1;
|
||||
|
||||
|
||||
@@ -3583,9 +3583,7 @@ void WebContents::UpdateHtmlApiFullscreen(bool fullscreen) {
|
||||
manager->ForEachGuest(
|
||||
web_contents(), base::BindRepeating([](content::WebContents* guest) {
|
||||
WebContents* api_web_contents = WebContents::From(guest);
|
||||
// Use UpdateHtmlApiFullscreen instead of SetXXX becuase there is no
|
||||
// need to interact with the owner window.
|
||||
api_web_contents->UpdateHtmlApiFullscreen(false);
|
||||
api_web_contents->SetHtmlApiFullscreen(false);
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -70,11 +70,15 @@ void LoginHandler::EmitEvent(
|
||||
details.Set("firstAuthAttempt", first_auth_attempt);
|
||||
details.Set("responseHeaders", response_headers.get());
|
||||
|
||||
auto weak_this = weak_factory_.GetWeakPtr();
|
||||
bool default_prevented =
|
||||
api_web_contents->Emit("login", std::move(details), auth_info,
|
||||
base::BindOnce(&LoginHandler::CallbackFromJS,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
if (!default_prevented && auth_required_callback_) {
|
||||
// ⚠️ NB, if CallbackFromJS is called during Emit(), |this| will have been
|
||||
// deleted. Check the weak ptr before accessing any member variables to
|
||||
// prevent UAF.
|
||||
if (weak_this && !default_prevented && auth_required_callback_) {
|
||||
std::move(auth_required_callback_).Run(base::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,7 +498,7 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
|
||||
// Use an NSEvent monitor to listen for the wheel event.
|
||||
BOOL __block began = NO;
|
||||
wheel_event_monitor_ = [NSEvent
|
||||
addLocalMonitorForEventsMatchingMask:NSScrollWheelMask
|
||||
addLocalMonitorForEventsMatchingMask:NSEventMaskScrollWheel
|
||||
handler:^(NSEvent* event) {
|
||||
if ([[event window] windowNumber] !=
|
||||
[window_ windowNumber])
|
||||
@@ -539,7 +539,10 @@ void NativeWindowMac::Cleanup() {
|
||||
DCHECK(!IsClosed());
|
||||
ui::NativeTheme::GetInstanceForNativeUi()->RemoveObserver(this);
|
||||
display::Screen::GetScreen()->RemoveObserver(this);
|
||||
[NSEvent removeMonitor:wheel_event_monitor_];
|
||||
if (wheel_event_monitor_) {
|
||||
[NSEvent removeMonitor:wheel_event_monitor_];
|
||||
wheel_event_monitor_ = nil;
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::RedrawTrafficLights() {
|
||||
@@ -959,7 +962,7 @@ void NativeWindowMac::SetAspectRatio(double aspect_ratio,
|
||||
|
||||
// Reset the behaviour to default if aspect_ratio is set to 0 or less.
|
||||
if (aspect_ratio > 0.0)
|
||||
[window_ setAspectRatio:NSMakeSize(aspect_ratio, 1.0)];
|
||||
[window_ setContentAspectRatio:NSMakeSize(aspect_ratio, 1.0)];
|
||||
else
|
||||
[window_ setResizeIncrements:NSMakeSize(1.0, 1.0)];
|
||||
}
|
||||
@@ -1781,8 +1784,6 @@ gfx::Rect NativeWindowMac::WindowBoundsToContentBounds(
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetActive(bool is_key) {
|
||||
if (is_key)
|
||||
widget()->Activate();
|
||||
is_active_ = is_key;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,8 +50,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 12,0,14,0
|
||||
PRODUCTVERSION 12,0,14,0
|
||||
FILEVERSION 12,0,16,0
|
||||
PRODUCTVERSION 12,0,16,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -68,12 +68,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "12.0.14"
|
||||
VALUE "FileVersion", "12.0.16"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "12.0.14"
|
||||
VALUE "ProductVersion", "12.0.16"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
||||
@@ -4256,6 +4256,20 @@ describe('BrowserWindow module', () => {
|
||||
await leaveFullScreen;
|
||||
expect(w.isFullScreen()).to.be.false('isFullScreen');
|
||||
});
|
||||
|
||||
it('multiple windows inherit correct fullscreen state', async () => {
|
||||
const w = new BrowserWindow();
|
||||
const enterFullScreen = emittedOnce(w, 'enter-full-screen');
|
||||
w.setFullScreen(true);
|
||||
await enterFullScreen;
|
||||
expect(w.isFullScreen()).to.be.true('isFullScreen');
|
||||
await delay();
|
||||
const w2 = new BrowserWindow({ show: false });
|
||||
const enterFullScreen2 = emittedOnce(w2, 'enter-full-screen');
|
||||
w2.show();
|
||||
await enterFullScreen2;
|
||||
expect(w2.isFullScreen()).to.be.true('isFullScreen');
|
||||
});
|
||||
});
|
||||
|
||||
describe('closable state', () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const { app, BrowserWindow } = require('electron');
|
||||
|
||||
app.once('ready', () => {
|
||||
app.once('ready', async () => {
|
||||
const w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
@@ -8,9 +8,12 @@ app.once('ready', () => {
|
||||
nodeIntegration: true
|
||||
}
|
||||
});
|
||||
w.webContents.once('crashed', () => {
|
||||
app.quit();
|
||||
w.webContents.once('render-process-gone', (_, details) => {
|
||||
if (details.reason === 'crashed') {
|
||||
process.exit(0);
|
||||
} else {
|
||||
process.exit(details.exitCode);
|
||||
}
|
||||
});
|
||||
w.webContents.loadURL('about:blank');
|
||||
w.webContents.executeJavaScript('process.crash()');
|
||||
await w.webContents.loadURL('chrome://checkcrash');
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as url from 'url';
|
||||
import { BrowserWindow, session, ipcMain, app, WebContents } from 'electron/main';
|
||||
import { closeAllWindows } from './window-helpers';
|
||||
import { emittedOnce, emittedUntil } from './events-helpers';
|
||||
import { ifdescribe } from './spec-helpers';
|
||||
import { ifdescribe, ifit, delay } from './spec-helpers';
|
||||
import { expect } from 'chai';
|
||||
|
||||
const features = process._linkedBinding('electron_common_features');
|
||||
@@ -184,6 +184,26 @@ describe('<webview> tag', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('did-attach event', () => {
|
||||
it('is emitted when a webview has been attached', async () => {
|
||||
const w = new BrowserWindow({
|
||||
webPreferences: {
|
||||
webviewTag: true
|
||||
}
|
||||
});
|
||||
await w.loadURL('about:blank');
|
||||
const message = await w.webContents.executeJavaScript(`new Promise((resolve, reject) => {
|
||||
const webview = new WebView()
|
||||
webview.setAttribute('src', 'about:blank')
|
||||
webview.addEventListener('did-attach', (e) => {
|
||||
resolve('ok')
|
||||
})
|
||||
document.body.appendChild(webview)
|
||||
})`);
|
||||
expect(message).to.equal('ok');
|
||||
});
|
||||
});
|
||||
|
||||
describe('did-change-theme-color event', () => {
|
||||
it('emits when theme color changes', async () => {
|
||||
const w = new BrowserWindow({
|
||||
@@ -409,6 +429,35 @@ describe('<webview> tag', function () {
|
||||
await parentFullscreen;
|
||||
expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.true();
|
||||
});
|
||||
|
||||
// FIXME(zcbenz): Fullscreen events do not work on Linux.
|
||||
// This test is flaky on arm64 macOS.
|
||||
ifit(process.platform !== 'linux' && process.arch !== 'arm64')('exiting fullscreen should unfullscreen window', async () => {
|
||||
const [w, webview] = await loadWebViewWindow();
|
||||
const enterFullScreen = emittedOnce(w, 'enter-full-screen');
|
||||
await webview.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
|
||||
await enterFullScreen;
|
||||
|
||||
const leaveFullScreen = emittedOnce(w, 'leave-full-screen');
|
||||
await webview.executeJavaScript('document.exitFullscreen()', true);
|
||||
await leaveFullScreen;
|
||||
await delay(0);
|
||||
expect(w.isFullScreen()).to.be.false();
|
||||
});
|
||||
|
||||
// Sending ESC via sendInputEvent only works on Windows.
|
||||
ifit(process.platform === 'win32')('pressing ESC should unfullscreen window', async () => {
|
||||
const [w, webview] = await loadWebViewWindow();
|
||||
const enterFullScreen = emittedOnce(w, 'enter-full-screen');
|
||||
await webview.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
|
||||
await enterFullScreen;
|
||||
|
||||
const leaveFullScreen = emittedOnce(w, 'leave-full-screen');
|
||||
w.webContents.sendInputEvent({ type: 'keyDown', keyCode: 'Escape' });
|
||||
await leaveFullScreen;
|
||||
await delay(0);
|
||||
expect(w.isFullScreen()).to.be.false();
|
||||
});
|
||||
});
|
||||
|
||||
describe('nativeWindowOpen option', () => {
|
||||
|
||||
18
yarn.lock
18
yarn.lock
@@ -4900,7 +4900,7 @@ minimist@^1.2.5:
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
minipass@^2.2.1, minipass@^2.3.5:
|
||||
minipass@^2.2.1:
|
||||
version "2.3.5"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848"
|
||||
integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==
|
||||
@@ -4908,6 +4908,14 @@ minipass@^2.2.1, minipass@^2.3.5:
|
||||
safe-buffer "^5.1.2"
|
||||
yallist "^3.0.0"
|
||||
|
||||
minipass@^2.8.6:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6"
|
||||
integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==
|
||||
dependencies:
|
||||
safe-buffer "^5.1.2"
|
||||
yallist "^3.0.0"
|
||||
|
||||
minizlib@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614"
|
||||
@@ -7613,13 +7621,13 @@ tapable@^1.0.0, tapable@^1.1.3:
|
||||
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
|
||||
|
||||
tar@^4, tar@^4.4.7:
|
||||
version "4.4.10"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1"
|
||||
integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==
|
||||
version "4.4.15"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.15.tgz#3caced4f39ebd46ddda4d6203d48493a919697f8"
|
||||
integrity sha512-ItbufpujXkry7bHH9NpQyTXPbJ72iTlXgkBAYsAjDXk3Ds8t/3NfO5P4xZGy7u+sYuQUbimgzswX4uQIEeNVOA==
|
||||
dependencies:
|
||||
chownr "^1.1.1"
|
||||
fs-minipass "^1.2.5"
|
||||
minipass "^2.3.5"
|
||||
minipass "^2.8.6"
|
||||
minizlib "^1.2.1"
|
||||
mkdirp "^0.5.0"
|
||||
safe-buffer "^5.1.2"
|
||||
|
||||
Reference in New Issue
Block a user