Commit 79adc2fa authored by Becca Hughes's avatar Becca Hughes Committed by Commit Bot

Autoplay: Allow autoplay in extension iframes

If an extension has an <iframe> it should be allowed to autoplay.

BUG=821284

Change-Id: I1e11cbdef6a81acf5ea3e6d3dcaadc8c13464c16
Reviewed-on: https://chromium-review.googlesource.com/962803Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarMounir Lamouri <mlamouri@chromium.org>
Reviewed-by: default avatarDevlin <rdevlin.cronin@chromium.org>
Reviewed-by: default avatarCharlie Reis <creis@chromium.org>
Commit-Queue: Becca Hughes <beccahughes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#551018}
parent a060a3f3
......@@ -3,6 +3,14 @@
// found in the LICENSE file.
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/ui/extensions/browser_action_test_util.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "extensions/test/result_catcher.h"
#include "extensions/test/test_extension_dir.h"
#include "media/base/media_switches.h"
class AutoplayExtensionBrowserTest : public ExtensionApiTest {
......@@ -18,3 +26,56 @@ class AutoplayExtensionBrowserTest : public ExtensionApiTest {
IN_PROC_BROWSER_TEST_F(AutoplayExtensionBrowserTest, AutoplayAllowed) {
ASSERT_TRUE(RunExtensionTest("autoplay")) << message_;
}
IN_PROC_BROWSER_TEST_F(AutoplayExtensionBrowserTest, AutoplayAllowedInIframe) {
ASSERT_TRUE(StartEmbeddedTestServer());
const extensions::Extension* extension =
LoadExtension(test_data_dir_.AppendASCII("autoplay_iframe"));
ASSERT_TRUE(extension) << message_;
std::unique_ptr<BrowserActionTestUtil> browser_action_test_util =
BrowserActionTestUtil::Create(browser());
extensions::ResultCatcher catcher;
content::WindowedNotificationObserver popup_observer(
content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
content::NotificationService::AllSources());
browser_action_test_util->Press(0);
popup_observer.Wait();
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
IN_PROC_BROWSER_TEST_F(AutoplayExtensionBrowserTest,
AutoplayAllowedInHostedApp) {
ASSERT_TRUE(StartEmbeddedTestServer());
GURL app_url = embedded_test_server()->GetURL(
"/extensions/autoplay_hosted_app/main.html");
constexpr const char kHostedAppManifest[] =
R"( { "name": "Hosted App Autoplay Test",
"version": "1",
"manifest_version": 2,
"app": {
"launch": {
"web_url": "%s"
}
}
} )";
extensions::TestExtensionDir test_app_dir;
test_app_dir.WriteManifest(
base::StringPrintf(kHostedAppManifest, app_url.spec().c_str()));
const extensions::Extension* extension =
LoadExtension(test_app_dir.UnpackedPath());
ASSERT_TRUE(extension) << message_;
Browser* app_browser = LaunchAppBrowser(extension);
content::WebContents* web_contents =
app_browser->tab_strip_model()->GetActiveWebContents();
EXPECT_TRUE(content::WaitForLoadStop(web_contents));
bool result = false;
EXPECT_TRUE(content::ExecuteScriptWithoutUserGestureAndExtractBool(
web_contents, "runTest();", &result));
EXPECT_TRUE(result);
}
......@@ -26,6 +26,8 @@
#include "extensions/common/extension_messages.h"
#include "extensions/common/extension_urls.h"
#include "extensions/common/switches.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/platform/autoplay.mojom.h"
using content::BrowserContext;
......@@ -169,4 +171,25 @@ void ChromeExtensionWebContentsObserver::ReloadIfTerminated(
}
}
void ChromeExtensionWebContentsObserver::ReadyToCommitNavigation(
content::NavigationHandle* navigation_handle) {
const ExtensionRegistry* registry = ExtensionRegistry::Get(
navigation_handle->GetWebContents()->GetBrowserContext());
// If the top most frame is an extension, packaged app, hosted app, etc. then
// the main frame and all iframes should be able to autoplay without
// restriction. <webview> should still have autoplay blocked though.
GURL url = navigation_handle->IsInMainFrame()
? navigation_handle->GetURL()
: navigation_handle->GetWebContents()->GetLastCommittedURL();
if (registry->enabled_extensions().GetExtensionOrAppByURL(url)) {
blink::mojom::AutoplayConfigurationClientAssociatedPtr client;
navigation_handle->GetRenderFrameHost()
->GetRemoteAssociatedInterfaces()
->GetInterface(&client);
client->AddAutoplayFlags(url::Origin::Create(navigation_handle->GetURL()),
blink::mojom::kAutoplayFlagForceAllow);
}
}
} // namespace extensions
......@@ -21,8 +21,8 @@ class RenderFrameHost;
namespace extensions {
// An ExtensionWebContentsObserver that adds support for the extension error
// console, reloading crashed extensions and routing extension messages between
// renderers.
// console, reloading crashed extensions, routing extension messages between
// renderers and updating autoplay policy.
class ChromeExtensionWebContentsObserver
: public ExtensionWebContentsObserver,
public content::WebContentsUserData<ChromeExtensionWebContentsObserver> {
......@@ -47,6 +47,8 @@ class ChromeExtensionWebContentsObserver
void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
void ReadyToCommitNavigation(
content::NavigationHandle* navigation_handle) override;
// Silence a warning about hiding a virtual function.
bool OnMessageReceived(const IPC::Message& message,
......
......@@ -39,11 +39,6 @@ void SetPreferences(const extensions::Extension* extension,
// Enable WebGL features that regular pages can't access, since they add
// more risk of fingerprinting.
webkit_prefs->privileged_webgl_extensions_enabled = true;
// Autoplay restrictions should not apply to extensions, packaged apps,
// hosted apps, etc. However, they should not apply to apps' webviews.
webkit_prefs->autoplay_policy =
content::AutoplayPolicy::kNoUserGestureRequired;
}
} // namespace extension_webkit_preferences
<!--
* Copyright 2018 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.
-->
<!DOCTYPE html>
<html>
<body>
<iframe></iframe>
<script src=main.js></script>
</body>
</html>
// Copyright 2018 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.
function runTest() {
var guestUrl = '/extensions/autoplay_iframe/frame.html';
var iframe = document.querySelector('iframe');
iframe.addEventListener('load', function() {
window.addEventListener('message', (e) => {
window.domAutomationController.send(
('autoplayed' == e.data || 'NotSupportedError' == e.data));
}, {once: true});
iframe.contentWindow.postMessage('start', '*');
}, {once: true});
iframe.src = guestUrl;
}
<!--
* Copyright 2018 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.
-->
<!DOCTYPE html>
<html>
<body>
<script src=frame.js></script>
</body>
</html>
// Copyright 2018 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.
window.addEventListener('message', function() {
var audio = document.createElement('audio');
audio.src = 'test.mp4';
audio.play().then(() => {
top.postMessage('autoplayed', '*');
}, e => {
top.postMessage(e.name, '*');
});
});
<!--
* Copyright 2018 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.
-->
<!DOCTYPE html>
<html>
<body>
<iframe></iframe>
<script src=main.js></script>
</body>
</html>
// Copyright 2018 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.
chrome.test.getConfig(function(config) {
var guestUrl = 'http://localhost:' + config.testServer.port +
'/extensions/autoplay_iframe/frame.html';
var iframe = document.querySelector('iframe');
iframe.addEventListener('load', function() {
window.addEventListener('message', (e) => {
chrome.test.assertTrue('autoplayed' == e.data
|| 'NotSupportedError' == e.data);
chrome.test.notifyPass();
}, {once: true});
iframe.contentWindow.postMessage('start', '*');
}, {once: true});
iframe.src = guestUrl;
});
{
"name": "<iframe> autoplay policy api tests.",
"version": "1",
"content_security_policy": "frame-src http://localhost:*/; object-src 'self'; script-src 'self'",
"manifest_version": 2,
"browser_action": {
"default_popup": "main.html"
}
}
......@@ -348,3 +348,4 @@
-DeclarativeNetRequestResourceTypeBrowserTest.Test2/0
-DeclarativeNetRequestResourceTypeBrowserTest.Test2/1
-MediaEngagementSessionRestoreBrowserTest.RestoredSession_Playback_MEI
-AutoplayExtensionBrowserTest.*
......@@ -6,11 +6,14 @@ module blink.mojom;
import "url/mojom/origin.mojom";
const int32 kAutoplayFlagNone = 0x00000;
const int32 kAutoplayFlagNone = 0x00000;
// This flag indicates a page has high media engagement.
const int32 kAutoplayFlagHighMediaEngagement = 0x00001;
// This flag indicates a page should always be allowed to autoplay.
const int32 kAutoplayFlagForceAllow = 0x00002;
interface AutoplayConfigurationClient {
// The browser tells the renderer that an origin has specific autoplay flags.
AddAutoplayFlags(url.mojom.Origin origin, int32 flags);
......
......@@ -90,6 +90,9 @@ AutoplayPolicy::Type AutoplayPolicy::GetAutoplayPolicyForDocument(
// static
bool AutoplayPolicy::IsDocumentAllowedToPlay(const Document& document) {
if (DocumentHasForceAllowFlag(document))
return true;
if (!document.GetFrame())
return false;
......@@ -123,6 +126,14 @@ bool AutoplayPolicy::DocumentHasHighMediaEngagement(const Document& document) {
mojom::blink::kAutoplayFlagHighMediaEngagement;
}
// static
bool AutoplayPolicy::DocumentHasForceAllowFlag(const Document& document) {
if (!document.GetPage())
return false;
return document.GetPage()->AutoplayFlags() &
mojom::blink::kAutoplayFlagForceAllow;
}
AutoplayPolicy::AutoplayPolicy(HTMLMediaElement* element)
: locked_pending_user_gesture_(false),
locked_pending_user_gesture_if_cross_origin_experiment_enabled_(true),
......
......@@ -46,6 +46,9 @@ class AutoplayPolicy final : public GarbageCollected<AutoplayPolicy> {
// Returns true if the given |document| has high media engagement.
static bool DocumentHasHighMediaEngagement(const Document&);
// Returns true if the given |document| should force allow autoplay.
static bool DocumentHasForceAllowFlag(const Document&);
explicit AutoplayPolicy(HTMLMediaElement*);
void VideoWillBeDrawnToCanvas() const;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment