<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[245335] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/245335">245335</a></dd>
<dt>Author</dt> <dd>youenn@apple.com</dd>
<dt>Date</dt> <dd>2019-05-15 11:44:36 -0700 (Wed, 15 May 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>getUserMedia sandbox extensions should not be revoked when a getUserMedia allowed request is being processed
https://bugs.webkit.org/show_bug.cgi?id=197851

Reviewed by Alex Christensen.

Source/WebCore:

Add a completion handler to create a new capture stream.
This is used by WK2 layer to acknowledge the pending capture request is completed.
Just after the completion handler, make sure to update the document media state.
This is done to ensure that, should capture failing, the UIProcess
knows about it and can manage proper sandbox extension revocation.

Test: fast/mediastream/gum-stop-track.html

* Modules/mediastream/UserMediaRequest.cpp:
(WebCore::UserMediaRequest::allow):
(WebCore::UserMediaRequest::PendingActivationMediaStream::PendingActivationMediaStream):
(WebCore::UserMediaRequest::PendingActivationMediaStream::~PendingActivationMediaStream):
* Modules/mediastream/UserMediaRequest.h:
(WebCore::UserMediaRequest::PendingActivationMediaStream::create):
* platform/mock/MockRealtimeMediaSourceCenter.cpp:
(WebCore::MockRealtimeMediaSourceCenter::mockRealtimeMediaSourceCenterEnabled):
* platform/mock/MockRealtimeMediaSourceCenter.h:

Source/WebKit:

Before the patch, stopping capture in a document and quickly triggering a new capture
might fail as the UIProcess would grant access and revoke sandbox access based on the fact
the page is no longer capturing.
To fix that issue, keep a state in the UIProcess to not revoke sandbox extensions in case of
capture being started.
Add an IPC message back to tell UIProcess when an allowed capture is finished.
Just after doing that, make sure the document is updating the media state to UIProcess, which will trigger proper sandbox extension handling.

This should also trigger the case of an allowed getUserMedia call that fails to start for some reason.
In that case, the patch will automatically trigger a document media state refresh which will trigger a sandbox revokation.

Covered by added test that exercise a newly added debug assertion.
This assertion ensures that we revoke extensions while a document is not capturing.

* UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
(WebKit::UserMediaPermissionRequestManagerProxy::~UserMediaPermissionRequestManagerProxy):
(WebKit::UserMediaPermissionRequestManagerProxy::grantAccess):
(WebKit::UserMediaPermissionRequestManagerProxy::captureStateChanged):
* UIProcess/UserMediaPermissionRequestManagerProxy.h:
* UIProcess/UserMediaProcessManager.cpp:
(WebKit::UserMediaProcessManager::willCreateMediaStream):
(WebKit::UserMediaProcessManager::revokeSandboxExtensionsIfNeeded):
* UIProcess/UserMediaProcessManager.h:
* UIProcess/WebPageProxy.h:
(WebKit::WebPageProxy::isCapturingAudio const):
(WebKit::WebPageProxy::isCapturingVideo const):
* WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp:
(WebKit::UserMediaPermissionRequestManager::userMediaAccessWasGranted):
* WebProcess/MediaStream/UserMediaPermissionRequestManager.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::userMediaAccessWasGranted):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:
* WebProcess/WebProcess.cpp:
(WebKit::checkDocumentsCaptureStateConsistency):
(WebKit::WebProcess::revokeUserMediaDeviceSandboxExtensions):

LayoutTests:

* fast/mediastream/gum-stop-track-expected.txt: Added.
* fast/mediastream/gum-stop-track.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesmediastreamUserMediaRequestcpp">trunk/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesmediastreamUserMediaRequesth">trunk/Source/WebCore/Modules/mediastream/UserMediaRequest.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmockMockRealtimeMediaSourceCentercpp">trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmockMockRealtimeMediaSourceCenterh">trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h</a></li>
<li><a href="#trunkSourceWebKitChangeLog">trunk/Source/WebKit/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitUIProcessUserMediaPermissionRequestManagerProxycpp">trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessUserMediaPermissionRequestManagerProxyh">trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessUserMediaProcessManagercpp">trunk/Source/WebKit/UIProcess/UserMediaProcessManager.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessUserMediaProcessManagerh">trunk/Source/WebKit/UIProcess/UserMediaProcessManager.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebPageProxyh">trunk/Source/WebKit/UIProcess/WebPageProxy.h</a></li>
<li><a href="#trunkSourceWebKitWebProcessMediaStreamUserMediaPermissionRequestManagercpp">trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp</a></li>
<li><a href="#trunkSourceWebKitWebProcessMediaStreamUserMediaPermissionRequestManagerh">trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.h</a></li>
<li><a href="#trunkSourceWebKitWebProcessWebPageWebPagecpp">trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp</a></li>
<li><a href="#trunkSourceWebKitWebProcessWebPageWebPageh">trunk/Source/WebKit/WebProcess/WebPage/WebPage.h</a></li>
<li><a href="#trunkSourceWebKitWebProcessWebPageWebPagemessagesin">trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in</a></li>
<li><a href="#trunkSourceWebKitWebProcessWebProcesscpp">trunk/Source/WebKit/WebProcess/WebProcess.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastmediastreamgumstoptrackexpectedtxt">trunk/LayoutTests/fast/mediastream/gum-stop-track-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastmediastreamgumstoptrackhtml">trunk/LayoutTests/fast/mediastream/gum-stop-track.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/LayoutTests/ChangeLog 2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2019-05-15  Youenn Fablet  <youenn@apple.com>
+
+        getUserMedia sandbox extensions should not be revoked when a getUserMedia allowed request is being processed
+        https://bugs.webkit.org/show_bug.cgi?id=197851
+
+        Reviewed by Alex Christensen.
+
+        * fast/mediastream/gum-stop-track-expected.txt: Added.
+        * fast/mediastream/gum-stop-track.html: Added.
+
</ins><span class="cx"> 2019-05-15  Fujii Hironori  <Hironori.Fujii@sony.com>
</span><span class="cx"> 
</span><span class="cx">         Unreviewed test gardening for WinCairo
</span></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamgumstoptrackexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/mediastream/gum-stop-track-expected.txt (0 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/gum-stop-track-expected.txt                           (rev 0)
+++ trunk/LayoutTests/fast/mediastream/gum-stop-track-expected.txt      2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -0,0 +1,3 @@
</span><ins>+
+PASS Call getUserMedia and track.stop in a loop 
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamgumstoptrackhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/mediastream/gum-stop-track.html (0 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/gum-stop-track.html                           (rev 0)
+++ trunk/LayoutTests/fast/mediastream/gum-stop-track.html      2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -0,0 +1,20 @@
</span><ins>+<!DOCTYPE HTML>
+<html>
+    <head>
+        <script src="../../resources/testharness.js"></script>
+        <script src="../../resources/testharnessreport.js"></script>
+    </head>
+    <body>
+        <script>
+promise_test(async (test) => {
+    if (window.testRunner)
+        testRunner.setUserMediaPermission(true);
+
+    for (var cptr = 0; cptr < 5; ++cptr) {
+        const stream = await navigator.mediaDevices.getUserMedia({audio:false, video:true});
+        stream.getTracks().forEach((track) => track.stop());
+    }
+}, "Call getUserMedia and track.stop in a loop");
+        </script>
+    </body>
+</html>
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebCore/ChangeLog      2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -1,3 +1,28 @@
</span><ins>+2019-05-15  Youenn Fablet  <youenn@apple.com>
+
+        getUserMedia sandbox extensions should not be revoked when a getUserMedia allowed request is being processed
+        https://bugs.webkit.org/show_bug.cgi?id=197851
+
+        Reviewed by Alex Christensen.
+
+        Add a completion handler to create a new capture stream.
+        This is used by WK2 layer to acknowledge the pending capture request is completed.
+        Just after the completion handler, make sure to update the document media state.
+        This is done to ensure that, should capture failing, the UIProcess
+        knows about it and can manage proper sandbox extension revocation.
+
+        Test: fast/mediastream/gum-stop-track.html
+
+        * Modules/mediastream/UserMediaRequest.cpp:
+        (WebCore::UserMediaRequest::allow):
+        (WebCore::UserMediaRequest::PendingActivationMediaStream::PendingActivationMediaStream):
+        (WebCore::UserMediaRequest::PendingActivationMediaStream::~PendingActivationMediaStream):
+        * Modules/mediastream/UserMediaRequest.h:
+        (WebCore::UserMediaRequest::PendingActivationMediaStream::create):
+        * platform/mock/MockRealtimeMediaSourceCenter.cpp:
+        (WebCore::MockRealtimeMediaSourceCenter::mockRealtimeMediaSourceCenterEnabled):
+        * platform/mock/MockRealtimeMediaSourceCenter.h:
+
</ins><span class="cx"> 2019-05-15  Simon Fraser  <simon.fraser@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Move RenderLayerCompositor's OverlapMap to its own file
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediastreamUserMediaRequestcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp    2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp       2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -47,6 +47,7 @@
</span><span class="cx"> #include "SchemeRegistry.h"
</span><span class="cx"> #include "Settings.h"
</span><span class="cx"> #include "UserMediaController.h"
</span><ins>+#include <wtf/Scope.h>
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -214,11 +215,14 @@
</span><span class="cx">     controller->requestUserMediaAccess(*this);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void UserMediaRequest::allow(CaptureDevice&& audioDevice, CaptureDevice&& videoDevice, String&& deviceIdentifierHashSalt)
</del><ins>+void UserMediaRequest::allow(CaptureDevice&& audioDevice, CaptureDevice&& videoDevice, String&& deviceIdentifierHashSalt, CompletionHandler<void()>&& completionHandler)
</ins><span class="cx"> {
</span><span class="cx">     RELEASE_LOG(MediaStream, "UserMediaRequest::allow %s %s", audioDevice ? audioDevice.persistentId().utf8().data() : "", videoDevice ? videoDevice.persistentId().utf8().data() : "");
</span><span class="cx"> 
</span><del>-    auto callback = [this, protector = makePendingActivity(*this)](RefPtr<MediaStreamPrivate>&& privateStream) mutable {
</del><ins>+    auto callback = [this, protector = makePendingActivity(*this), completionHandler = WTFMove(completionHandler)](RefPtr<MediaStreamPrivate>&& privateStream) mutable {
+        auto scopeExit = makeScopeExit([&] {
+            completionHandler();
+        });
</ins><span class="cx">         if (!m_scriptExecutionContext)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="lines">@@ -235,7 +239,8 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        m_pendingActivationMediaStream = PendingActivationMediaStream::create(WTFMove(protector), *this, WTFMove(stream));
</del><ins>+        scopeExit.release();
+        m_pendingActivationMediaStream = PendingActivationMediaStream::create(WTFMove(protector), *this, WTFMove(stream), WTFMove(completionHandler));
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     auto& document = downcast<Document>(*scriptExecutionContext());
</span><span class="lines">@@ -330,10 +335,11 @@
</span><span class="cx">     return downcast<Document>(m_scriptExecutionContext);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-UserMediaRequest::PendingActivationMediaStream::PendingActivationMediaStream(Ref<PendingActivity<UserMediaRequest>>&& protectingUserMediaRequest, UserMediaRequest& userMediaRequest, Ref<MediaStream>&& stream)
</del><ins>+UserMediaRequest::PendingActivationMediaStream::PendingActivationMediaStream(Ref<PendingActivity<UserMediaRequest>>&& protectingUserMediaRequest, UserMediaRequest& userMediaRequest, Ref<MediaStream>&& stream, CompletionHandler<void()>&& completionHandler)
</ins><span class="cx">     : m_protectingUserMediaRequest(WTFMove(protectingUserMediaRequest))
</span><span class="cx">     , m_userMediaRequest(userMediaRequest)
</span><span class="cx">     , m_mediaStream(WTFMove(stream))
</span><ins>+    , m_completionHandler(WTFMove(completionHandler))
</ins><span class="cx"> {
</span><span class="cx">     m_mediaStream->privateStream().addObserver(*this);
</span><span class="cx">     m_mediaStream->startProducingData();
</span><span class="lines">@@ -342,6 +348,9 @@
</span><span class="cx"> UserMediaRequest::PendingActivationMediaStream::~PendingActivationMediaStream()
</span><span class="cx"> {
</span><span class="cx">     m_mediaStream->privateStream().removeObserver(*this);
</span><ins>+    m_completionHandler();
+    if (auto* document = m_mediaStream->document())
+        document->updateIsPlayingMedia();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void UserMediaRequest::PendingActivationMediaStream::characteristicsChanged()
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediastreamUserMediaRequesth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediastream/UserMediaRequest.h (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediastream/UserMediaRequest.h      2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebCore/Modules/mediastream/UserMediaRequest.h 2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -40,6 +40,7 @@
</span><span class="cx"> #include "MediaConstraints.h"
</span><span class="cx"> #include "MediaStreamPrivate.h"
</span><span class="cx"> #include "MediaStreamRequest.h"
</span><ins>+#include <wtf/CompletionHandler.h>
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -54,7 +55,7 @@
</span><span class="cx">     void start();
</span><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT void setAllowedMediaDeviceUIDs(const String& audioDeviceUID, const String& videoDeviceUID);
</span><del>-    WEBCORE_EXPORT void allow(CaptureDevice&& audioDevice, CaptureDevice&& videoDevice, String&& deviceIdentifierHashSalt);
</del><ins>+    WEBCORE_EXPORT void allow(CaptureDevice&& audioDevice, CaptureDevice&& videoDevice, String&& deviceIdentifierHashSalt, CompletionHandler<void()>&&);
</ins><span class="cx"> 
</span><span class="cx">     enum MediaAccessDenialReason { NoConstraints, UserMediaDisabled, NoCaptureDevices, InvalidConstraint, HardwareError, PermissionDenied, InvalidAccess, IllegalConstraint, OtherFailure };
</span><span class="cx">     WEBCORE_EXPORT void deny(MediaAccessDenialReason, const String& errorMessage = emptyString());
</span><span class="lines">@@ -83,14 +84,14 @@
</span><span class="cx"> 
</span><span class="cx">     class PendingActivationMediaStream : public RefCounted<PendingActivationMediaStream>, private MediaStreamPrivate::Observer {
</span><span class="cx">     public:
</span><del>-        static Ref<PendingActivationMediaStream> create(Ref<PendingActivity<UserMediaRequest>>&& protectingUserMediaRequest, UserMediaRequest& userMediaRequest, Ref<MediaStream>&& stream)
</del><ins>+        static Ref<PendingActivationMediaStream> create(Ref<PendingActivity<UserMediaRequest>>&& protectingUserMediaRequest, UserMediaRequest& userMediaRequest, Ref<MediaStream>&& stream, CompletionHandler<void()>&& completionHandler)
</ins><span class="cx">         {
</span><del>-            return adoptRef(*new PendingActivationMediaStream { WTFMove(protectingUserMediaRequest), userMediaRequest, WTFMove(stream) });
</del><ins>+            return adoptRef(*new PendingActivationMediaStream { WTFMove(protectingUserMediaRequest), userMediaRequest, WTFMove(stream), WTFMove(completionHandler) });
</ins><span class="cx">         }
</span><span class="cx">         ~PendingActivationMediaStream();
</span><span class="cx"> 
</span><span class="cx">     private:
</span><del>-        PendingActivationMediaStream(Ref<PendingActivity<UserMediaRequest>>&&, UserMediaRequest&, Ref<MediaStream>&&);
</del><ins>+        PendingActivationMediaStream(Ref<PendingActivity<UserMediaRequest>>&&, UserMediaRequest&, Ref<MediaStream>&&, CompletionHandler<void()>&&);
</ins><span class="cx"> 
</span><span class="cx">         void characteristicsChanged() final;
</span><span class="cx"> 
</span><span class="lines">@@ -97,6 +98,7 @@
</span><span class="cx">         Ref<PendingActivity<UserMediaRequest>> m_protectingUserMediaRequest;
</span><span class="cx">         UserMediaRequest& m_userMediaRequest;
</span><span class="cx">         Ref<MediaStream> m_mediaStream;
</span><ins>+        CompletionHandler<void()> m_completionHandler;
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     Vector<String> m_videoDeviceUIDs;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmockMockRealtimeMediaSourceCentercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp     2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp        2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -208,6 +208,14 @@
</span><span class="cx">         center.unsetDisplayCaptureFactory(mock.displayCaptureFactory());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool MockRealtimeMediaSourceCenter::mockRealtimeMediaSourceCenterEnabled()
+{
+    MockRealtimeMediaSourceCenter& mock = singleton();
+    RealtimeMediaSourceCenter& center = RealtimeMediaSourceCenter::singleton();
+
+    return &center.audioCaptureFactory() == &mock.audioCaptureFactory() || &center.videoCaptureFactory() == &mock.videoCaptureFactory() || &center.displayCaptureFactory() == &mock.displayCaptureFactory();
+}
+
</ins><span class="cx"> static void createCaptureDevice(const MockMediaDevice& device)
</span><span class="cx"> {
</span><span class="cx">     deviceListForDevice(device).append(MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(device.type(), device.persistentId).value());
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmockMockRealtimeMediaSourceCenterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h       2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h  2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -41,6 +41,7 @@
</span><span class="cx">     WEBCORE_EXPORT static MockRealtimeMediaSourceCenter& singleton();
</span><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT static void setMockRealtimeMediaSourceCenterEnabled(bool);
</span><ins>+    WEBCORE_EXPORT static bool mockRealtimeMediaSourceCenterEnabled();
</ins><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT static void setDevices(Vector<MockMediaDevice>&&);
</span><span class="cx">     WEBCORE_EXPORT static void addDevice(const MockMediaDevice&);
</span></span></pre></div>
<a id="trunkSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/ChangeLog (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/ChangeLog    2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebKit/ChangeLog       2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -1,3 +1,47 @@
</span><ins>+2019-05-15  Youenn Fablet  <youenn@apple.com>
+
+        getUserMedia sandbox extensions should not be revoked when a getUserMedia allowed request is being processed
+        https://bugs.webkit.org/show_bug.cgi?id=197851
+
+        Reviewed by Alex Christensen.
+
+        Before the patch, stopping capture in a document and quickly triggering a new capture
+        might fail as the UIProcess would grant access and revoke sandbox access based on the fact
+        the page is no longer capturing.
+        To fix that issue, keep a state in the UIProcess to not revoke sandbox extensions in case of
+        capture being started.
+        Add an IPC message back to tell UIProcess when an allowed capture is finished.
+        Just after doing that, make sure the document is updating the media state to UIProcess, which will trigger proper sandbox extension handling.
+
+        This should also trigger the case of an allowed getUserMedia call that fails to start for some reason.
+        In that case, the patch will automatically trigger a document media state refresh which will trigger a sandbox revokation.
+
+        Covered by added test that exercise a newly added debug assertion.
+        This assertion ensures that we revoke extensions while a document is not capturing.
+
+        * UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
+        (WebKit::UserMediaPermissionRequestManagerProxy::~UserMediaPermissionRequestManagerProxy):
+        (WebKit::UserMediaPermissionRequestManagerProxy::grantAccess):
+        (WebKit::UserMediaPermissionRequestManagerProxy::captureStateChanged):
+        * UIProcess/UserMediaPermissionRequestManagerProxy.h:
+        * UIProcess/UserMediaProcessManager.cpp:
+        (WebKit::UserMediaProcessManager::willCreateMediaStream):
+        (WebKit::UserMediaProcessManager::revokeSandboxExtensionsIfNeeded):
+        * UIProcess/UserMediaProcessManager.h:
+        * UIProcess/WebPageProxy.h:
+        (WebKit::WebPageProxy::isCapturingAudio const):
+        (WebKit::WebPageProxy::isCapturingVideo const):
+        * WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp:
+        (WebKit::UserMediaPermissionRequestManager::userMediaAccessWasGranted):
+        * WebProcess/MediaStream/UserMediaPermissionRequestManager.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::userMediaAccessWasGranted):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+        * WebProcess/WebProcess.cpp:
+        (WebKit::checkDocumentsCaptureStateConsistency):
+        (WebKit::WebProcess::revokeUserMediaDeviceSandboxExtensions):
+
</ins><span class="cx"> 2019-05-15  Chris Dumez  <cdumez@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [WK2][iOS] UIProcess may get killed because it is taking too long to release its background task after expiration
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessUserMediaPermissionRequestManagerProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp 2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp    2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -83,7 +83,7 @@
</span><span class="cx"> UserMediaPermissionRequestManagerProxy::~UserMediaPermissionRequestManagerProxy()
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(MEDIA_STREAM)
</span><del>-    UserMediaProcessManager::singleton().endedCaptureSession(*this);
</del><ins>+    UserMediaProcessManager::singleton().revokeSandboxExtensionsIfNeeded(page().process());
</ins><span class="cx">     proxies().remove(this);
</span><span class="cx"> #endif
</span><span class="cx">     invalidatePendingRequests();
</span><span class="lines">@@ -295,7 +295,12 @@
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    m_page.process().send(Messages::WebPage::UserMediaAccessWasGranted(request.userMediaID(), request.audioDevice(), request.videoDevice(), request.deviceIdentifierHashSalt()), m_page.pageID());
</del><ins>+    ++m_hasPendingCapture;
+    m_page.process().connection()->sendWithAsyncReply(Messages::WebPage::UserMediaAccessWasGranted { request.userMediaID(), request.audioDevice(), request.videoDevice(), request.deviceIdentifierHashSalt() }, [this, weakThis = makeWeakPtr(this)] {
+        if (!weakThis)
+            return;
+        --m_hasPendingCapture;
+    }, m_page.pageID());
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="lines">@@ -632,14 +637,9 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MEDIA_STREAM)
</span><del>-    bool wasCapturingAudio = oldState & MediaProducer::AudioCaptureMask;
-    bool wasCapturingVideo = oldState & MediaProducer::VideoCaptureMask;
-    bool isCapturingAudio = newState & MediaProducer::AudioCaptureMask;
-    bool isCapturingVideo = newState & MediaProducer::VideoCaptureMask;
</del><ins>+    if (!m_hasPendingCapture)
+        UserMediaProcessManager::singleton().revokeSandboxExtensionsIfNeeded(page().process());
</ins><span class="cx"> 
</span><del>-    if ((wasCapturingAudio && !isCapturingAudio) || (wasCapturingVideo && !isCapturingVideo))
-        UserMediaProcessManager::singleton().endedCaptureSession(*this);
-
</del><span class="cx">     if (m_captureState == (newState & activeCaptureMask))
</span><span class="cx">         return;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessUserMediaPermissionRequestManagerProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h   2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h      2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -144,6 +144,7 @@
</span><span class="cx">     const void* m_logIdentifier;
</span><span class="cx"> #endif
</span><span class="cx">     bool m_hasFilteredDeviceList { false };
</span><ins>+    uint64_t m_hasPendingCapture { 0 };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> String convertEnumerationToString(UserMediaPermissionRequestManagerProxy::RequestAction);
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessUserMediaProcessManagercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/UserMediaProcessManager.cpp (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/UserMediaProcessManager.cpp        2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebKit/UIProcess/UserMediaProcessManager.cpp   2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -72,27 +72,27 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx"> #if ENABLE(SANDBOX_EXTENSIONS) && USE(APPLE_INTERNAL_SDK)
</span><del>-    if (!proxy.page().preferences().mockCaptureDevicesEnabled()) {
-        auto& process = proxy.page().process();
-        size_t extensionCount = 0;
</del><ins>+    auto& process = proxy.page().process();
+    size_t extensionCount = 0;
</ins><span class="cx"> 
</span><del>-        if (withAudio && !process.hasAudioCaptureExtension())
-            extensionCount++;
-        else
-            withAudio = false;
</del><ins>+    if (withAudio && !process.hasAudioCaptureExtension())
+        extensionCount++;
+    else
+        withAudio = false;
</ins><span class="cx"> 
</span><del>-        if (withVideo && !process.hasVideoCaptureExtension())
-            extensionCount++;
-        else
-            withVideo = false;
</del><ins>+    if (withVideo && !process.hasVideoCaptureExtension())
+        extensionCount++;
+    else
+        withVideo = false;
</ins><span class="cx"> 
</span><del>-        if (extensionCount) {
-            SandboxExtension::HandleArray handles;
</del><ins>+    if (extensionCount) {
+        SandboxExtension::HandleArray handles;
+        Vector<String> ids;
+
+        if (!proxy.page().preferences().mockCaptureDevicesEnabled()) {
</ins><span class="cx">             handles.allocate(extensionCount);
</span><ins>+            ids.reserveInitialCapacity(extensionCount);
</ins><span class="cx"> 
</span><del>-            Vector<String> ids;
-            ids.reserveCapacity(extensionCount);
-
</del><span class="cx">             if (withAudio && SandboxExtension::createHandleForGenericExtension(audioExtensionPath, handles[--extensionCount]))
</span><span class="cx">                 ids.append(audioExtensionPath);
</span><span class="cx"> 
</span><span class="lines">@@ -103,16 +103,16 @@
</span><span class="cx">                 WTFLogAlways("Could not create a required sandbox extension, capture will fail!");
</span><span class="cx">                 return false;
</span><span class="cx">             }
</span><ins>+        }
</ins><span class="cx"> 
</span><del>-            for (const auto& id : ids)
-                RELEASE_LOG(WebRTC, "UserMediaProcessManager::willCreateMediaStream - granting extension %s", id.utf8().data());
</del><ins>+        for (const auto& id : ids)
+            RELEASE_LOG(WebRTC, "UserMediaProcessManager::willCreateMediaStream - granting extension %s", id.utf8().data());
</ins><span class="cx"> 
</span><del>-            if (withAudio)
-                process.grantAudioCaptureExtension();
-            if (withVideo)
-                process.grantVideoCaptureExtension();
-            process.send(Messages::WebProcess::GrantUserMediaDeviceSandboxExtensions(MediaDeviceSandboxExtensions(ids, WTFMove(handles))), proxy.page().pageID());
-        }
</del><ins>+        if (withAudio)
+            process.grantAudioCaptureExtension();
+        if (withVideo)
+            process.grantVideoCaptureExtension();
+        process.send(Messages::WebProcess::GrantUserMediaDeviceSandboxExtensions(MediaDeviceSandboxExtensions(ids, WTFMove(handles))), 0);
</ins><span class="cx">     }
</span><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(proxy);
</span><span class="lines">@@ -125,20 +125,17 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void UserMediaProcessManager::endedCaptureSession(UserMediaPermissionRequestManagerProxy& proxy)
</del><ins>+void UserMediaProcessManager::revokeSandboxExtensionsIfNeeded(WebProcessProxy& process)
</ins><span class="cx"> {
</span><span class="cx"> #if ENABLE(SANDBOX_EXTENSIONS)
</span><span class="cx">     bool hasAudioCapture = false;
</span><span class="cx">     bool hasVideoCapture = false;
</span><span class="cx"> 
</span><del>-    auto& process = proxy.page().process();
-    UserMediaPermissionRequestManagerProxy::forEach([&hasAudioCapture, &hasVideoCapture, &proxy, &process](auto& managerProxy) {
-        if (&proxy == &managerProxy || &process != &managerProxy.page().process())
</del><ins>+    UserMediaPermissionRequestManagerProxy::forEach([&hasAudioCapture, &hasVideoCapture, &process](auto& managerProxy) {
+        if (&process != &managerProxy.page().process())
</ins><span class="cx">             return;
</span><del>-        if (managerProxy.page().hasActiveAudioStream())
-            hasAudioCapture = true;
-        if (managerProxy.page().hasActiveVideoStream())
-            hasVideoCapture = true;
</del><ins>+        hasAudioCapture |= managerProxy.page().isCapturingAudio();
+        hasVideoCapture |= managerProxy.page().isCapturingVideo();
</ins><span class="cx">     });
</span><span class="cx"> 
</span><span class="cx">     if (hasAudioCapture && hasVideoCapture)
</span><span class="lines">@@ -160,7 +157,7 @@
</span><span class="cx">     for (const auto& id : params)
</span><span class="cx">         RELEASE_LOG(WebRTC, "UserMediaProcessManager::endedCaptureSession - revoking extension %s", id.utf8().data());
</span><span class="cx"> 
</span><del>-    process.send(Messages::WebProcess::RevokeUserMediaDeviceSandboxExtensions(params), proxy.page().pageID());
</del><ins>+    process.send(Messages::WebProcess::RevokeUserMediaDeviceSandboxExtensions(params), 0);
</ins><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessUserMediaProcessManagerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/UserMediaProcessManager.h (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/UserMediaProcessManager.h  2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebKit/UIProcess/UserMediaProcessManager.h     2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -38,7 +38,7 @@
</span><span class="cx">     bool willCreateMediaStream(UserMediaPermissionRequestManagerProxy&, bool withAudio, bool withVideo);
</span><span class="cx">     void muteCaptureMediaStreamsExceptIn(WebPageProxy&);
</span><span class="cx"> 
</span><del>-    void endedCaptureSession(UserMediaPermissionRequestManagerProxy&);
</del><ins>+    void revokeSandboxExtensionsIfNeeded(WebProcessProxy&);
</ins><span class="cx"> 
</span><span class="cx">     void setCaptureEnabled(bool);
</span><span class="cx">     bool captureEnabled() const { return m_captureEnabled; }
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebPageProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/WebPageProxy.h     2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h        2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -1297,6 +1297,8 @@
</span><span class="cx">     bool isPlayingAudio() const { return !!(m_mediaState & WebCore::MediaProducer::IsPlayingAudio); }
</span><span class="cx">     void isPlayingMediaDidChange(WebCore::MediaProducer::MediaStateFlags, uint64_t);
</span><span class="cx">     void updatePlayingMediaDidChange(WebCore::MediaProducer::MediaStateFlags);
</span><ins>+    bool isCapturingAudio() const { return m_mediaState & WebCore::MediaProducer::AudioCaptureMask; }
+    bool isCapturingVideo() const { return m_mediaState & WebCore::MediaProducer::VideoCaptureMask; }
</ins><span class="cx">     bool hasActiveAudioStream() const { return m_mediaState & WebCore::MediaProducer::HasActiveAudioCaptureDevice; }
</span><span class="cx">     bool hasActiveVideoStream() const { return m_mediaState & WebCore::MediaProducer::HasActiveVideoCaptureDevice; }
</span><span class="cx">     WebCore::MediaProducer::MediaStateFlags mediaStateFlags() const { return m_mediaState; }
</span></span></pre></div>
<a id="trunkSourceWebKitWebProcessMediaStreamUserMediaPermissionRequestManagercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp 2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp    2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -137,7 +137,7 @@
</span><span class="cx">     m_userMediaRequestToIDMap.remove(&request);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void UserMediaPermissionRequestManager::userMediaAccessWasGranted(uint64_t requestID, CaptureDevice&& audioDevice, CaptureDevice&& videoDevice, String&& deviceIdentifierHashSalt)
</del><ins>+void UserMediaPermissionRequestManager::userMediaAccessWasGranted(uint64_t requestID, CaptureDevice&& audioDevice, CaptureDevice&& videoDevice, String&& deviceIdentifierHashSalt, CompletionHandler<void()>&& completionHandler)
</ins><span class="cx"> {
</span><span class="cx">     auto request = m_idToUserMediaRequestMap.take(requestID);
</span><span class="cx">     if (!request)
</span><span class="lines">@@ -144,7 +144,7 @@
</span><span class="cx">         return;
</span><span class="cx">     removeMediaRequestFromMaps(*request);
</span><span class="cx"> 
</span><del>-    request->allow(WTFMove(audioDevice), WTFMove(videoDevice), WTFMove(deviceIdentifierHashSalt));
</del><ins>+    request->allow(WTFMove(audioDevice), WTFMove(videoDevice), WTFMove(deviceIdentifierHashSalt), WTFMove(completionHandler));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void UserMediaPermissionRequestManager::userMediaAccessWasDenied(uint64_t requestID, WebCore::UserMediaRequest::MediaAccessDenialReason reason, String&& invalidConstraint)
</span></span></pre></div>
<a id="trunkSourceWebKitWebProcessMediaStreamUserMediaPermissionRequestManagerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.h (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.h   2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.h      2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -42,7 +42,7 @@
</span><span class="cx"> 
</span><span class="cx">     void startUserMediaRequest(WebCore::UserMediaRequest&);
</span><span class="cx">     void cancelUserMediaRequest(WebCore::UserMediaRequest&);
</span><del>-    void userMediaAccessWasGranted(uint64_t, WebCore::CaptureDevice&& audioDevice, WebCore::CaptureDevice&& videoDevice, String&& deviceIdentifierHashSalt);
</del><ins>+    void userMediaAccessWasGranted(uint64_t, WebCore::CaptureDevice&& audioDevice, WebCore::CaptureDevice&& videoDevice, String&& deviceIdentifierHashSalt, CompletionHandler<void()>&&);
</ins><span class="cx">     void userMediaAccessWasDenied(uint64_t, WebCore::UserMediaRequest::MediaAccessDenialReason, String&&);
</span><span class="cx"> 
</span><span class="cx">     void enumerateMediaDevices(WebCore::MediaDevicesEnumerationRequest&);
</span></span></pre></div>
<a id="trunkSourceWebKitWebProcessWebPageWebPagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp       2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp  2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -4153,9 +4153,9 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MEDIA_STREAM)
</span><span class="cx"> 
</span><del>-void WebPage::userMediaAccessWasGranted(uint64_t userMediaID, WebCore::CaptureDevice&& audioDevice, WebCore::CaptureDevice&& videoDevice, String&& mediaDeviceIdentifierHashSalt)
</del><ins>+void WebPage::userMediaAccessWasGranted(uint64_t userMediaID, WebCore::CaptureDevice&& audioDevice, WebCore::CaptureDevice&& videoDevice, String&& mediaDeviceIdentifierHashSalt, CompletionHandler<void()>&& completionHandler)
</ins><span class="cx"> {
</span><del>-    m_userMediaPermissionRequestManager->userMediaAccessWasGranted(userMediaID, WTFMove(audioDevice), WTFMove(videoDevice), WTFMove(mediaDeviceIdentifierHashSalt));
</del><ins>+    m_userMediaPermissionRequestManager->userMediaAccessWasGranted(userMediaID, WTFMove(audioDevice), WTFMove(videoDevice), WTFMove(mediaDeviceIdentifierHashSalt), WTFMove(completionHandler));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebPage::userMediaAccessWasDenied(uint64_t userMediaID, uint64_t reason, String&& invalidConstraint)
</span></span></pre></div>
<a id="trunkSourceWebKitWebProcessWebPageWebPageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h 2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h    2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -1445,7 +1445,7 @@
</span><span class="cx">     void didReceiveNotificationPermissionDecision(uint64_t notificationID, bool allowed);
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MEDIA_STREAM)
</span><del>-    void userMediaAccessWasGranted(uint64_t userMediaID, WebCore::CaptureDevice&& audioDeviceUID, WebCore::CaptureDevice&& videoDeviceUID, String&& mediaDeviceIdentifierHashSalt);
</del><ins>+    void userMediaAccessWasGranted(uint64_t userMediaID, WebCore::CaptureDevice&& audioDeviceUID, WebCore::CaptureDevice&& videoDeviceUID, String&& mediaDeviceIdentifierHashSalt, CompletionHandler<void()>&&);
</ins><span class="cx">     void userMediaAccessWasDenied(uint64_t userMediaID, uint64_t reason, String&& invalidConstraint);
</span><span class="cx"> 
</span><span class="cx">     void didCompleteMediaDeviceEnumeration(uint64_t userMediaID, const Vector<WebCore::CaptureDevice>& devices, String&& deviceIdentifierHashSalt, bool originHasPersistentAccess);
</span></span></pre></div>
<a id="trunkSourceWebKitWebProcessWebPageWebPagemessagesin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in       2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in  2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -351,7 +351,7 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MEDIA_STREAM)
</span><span class="cx">     # MediaSteam
</span><del>-    UserMediaAccessWasGranted(uint64_t userMediaID, WebCore::CaptureDevice audioDevice, WebCore::CaptureDevice videoDevice, String mediaDeviceIdentifierHashSalt)
</del><ins>+    UserMediaAccessWasGranted(uint64_t userMediaID, WebCore::CaptureDevice audioDevice, WebCore::CaptureDevice videoDevice, String mediaDeviceIdentifierHashSalt) -> () Async
</ins><span class="cx">     UserMediaAccessWasDenied(uint64_t userMediaID, uint64_t reason, String invalidConstraint)
</span><span class="cx">     DidCompleteMediaDeviceEnumeration(uint64_t userMediaID, Vector<WebCore::CaptureDevice> devices, String mediaDeviceIdentifierHashSalt, bool hasPersistentAccess)
</span><span class="cx">     CaptureDevicesChanged()
</span></span></pre></div>
<a id="trunkSourceWebKitWebProcessWebProcesscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebProcess/WebProcess.cpp (245334 => 245335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebProcess/WebProcess.cpp    2019-05-15 18:29:40 UTC (rev 245334)
+++ trunk/Source/WebKit/WebProcess/WebProcess.cpp       2019-05-15 18:44:36 UTC (rev 245335)
</span><span class="lines">@@ -1857,11 +1857,30 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static inline void checkDocumentsCaptureStateConsistency(const Vector<String>& extensionIDs)
+{
+#if !ASSERT_DISABLED
+    bool isCapturingAudio = WTF::anyOf(Document::allDocumentsMap().values(), [](auto* document) {
+        return document->mediaState() & MediaProducer::AudioCaptureMask;
+    });
+    bool isCapturingVideo = WTF::anyOf(Document::allDocumentsMap().values(), [](auto* document) {
+        return document->mediaState() & MediaProducer::VideoCaptureMask;
+    });
+
+    if (isCapturingAudio)
+        ASSERT(extensionIDs.findMatching([](auto& id) { return id.contains("microphone"); }) == notFound);
+    if (isCapturingVideo)
+        ASSERT(extensionIDs.findMatching([](auto& id) { return id.contains("camera"); }) == notFound);
+#endif
+}
+
</ins><span class="cx"> void WebProcess::revokeUserMediaDeviceSandboxExtensions(const Vector<String>& extensionIDs)
</span><span class="cx"> {
</span><ins>+    checkDocumentsCaptureStateConsistency(extensionIDs);
+
</ins><span class="cx">     for (const auto& extensionID : extensionIDs) {
</span><span class="cx">         auto extension = m_mediaCaptureSandboxExtensions.take(extensionID);
</span><del>-        ASSERT(extension);
</del><ins>+        ASSERT(extension || MockRealtimeMediaSourceCenter::mockRealtimeMediaSourceCenterEnabled());
</ins><span class="cx">         if (extension) {
</span><span class="cx">             extension->revoke();
</span><span class="cx">             RELEASE_LOG(WebRTC, "UserMediaPermissionRequestManager::revokeUserMediaDeviceSandboxExtensions - revoked extension %s", extensionID.utf8().data());
</span></span></pre>
</div>
</div>

</body>
</html>