Title: [260373] trunk/Source/WebKit
Revision
260373
Author
[email protected]
Date
2020-04-20 10:48:42 -0700 (Mon, 20 Apr 2020)

Log Message

[iOS] Refactor WebKit media playback process assertion logic to minimize chances of leaking them
https://bugs.webkit.org/show_bug.cgi?id=210670

Reviewed by Geoffrey Garen.

Refactor WebKit media playback process assertion logic to minimize chances of leaking them. In particular,
the following changes were made:
1. Instead of the WebProcessPool having a HashMap of media playback process assertions for
   the WebProcess, we now store the assertion on the WebProcessProxy object itself. This is
   less likely to get out of sync and leak.
2. Add a RefCounter to the WebProcessPool to count WebProcesses that have audible media.
   Whenever a WebProcess starts or stops playing audible media, it merely grabs a RefCounter
   token or releases it. The WebProcessPool relies on this counter to decide whether or not
   to take a media playback assertion on behalf of the UIProcess. Since this is token-based
   and the token is stored on the WebProcessProxy object, it makes it less likely to leak
   the assertion.
3. The WebProcessProxy object now has a AudibleMediaActivity data structure wrapping both
   its media playback assertion and its WebProcessWithAudibleMediaToken that it got from
   the WebProcessPool. When the WebProcess shuts down (normally or due to crash/termination),
   we make sure to clear this data structure.
4. Make sure that the WebProcessProxy updates its AudibleMediaActivity whenever a page is
   removed from the WebProcess.

* UIProcess/WebPageProxy.cpp:
* UIProcess/WebProcessPool.cpp:
(WebKit::m_webProcessWithAudibleMediaCounter):
(WebKit::WebProcessPool::disconnectProcess):
(WebKit::WebProcessPool::webProcessWithAudibleMediaToken const):
(WebKit::WebProcessPool::updateAudibleMediaAssertions):
* UIProcess/WebProcessPool.h:
* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::shutDown):
(WebKit::WebProcessProxy::removeWebPage):
(WebKit::WebProcessProxy::updateAudibleMediaAssertions):
* UIProcess/WebProcessProxy.h:

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (260372 => 260373)


--- trunk/Source/WebKit/ChangeLog	2020-04-20 17:15:28 UTC (rev 260372)
+++ trunk/Source/WebKit/ChangeLog	2020-04-20 17:48:42 UTC (rev 260373)
@@ -1,3 +1,41 @@
+2020-04-20  Chris Dumez  <[email protected]>
+
+        [iOS] Refactor WebKit media playback process assertion logic to minimize chances of leaking them
+        https://bugs.webkit.org/show_bug.cgi?id=210670
+
+        Reviewed by Geoffrey Garen.
+
+        Refactor WebKit media playback process assertion logic to minimize chances of leaking them. In particular,
+        the following changes were made:
+        1. Instead of the WebProcessPool having a HashMap of media playback process assertions for
+           the WebProcess, we now store the assertion on the WebProcessProxy object itself. This is
+           less likely to get out of sync and leak.
+        2. Add a RefCounter to the WebProcessPool to count WebProcesses that have audible media.
+           Whenever a WebProcess starts or stops playing audible media, it merely grabs a RefCounter
+           token or releases it. The WebProcessPool relies on this counter to decide whether or not
+           to take a media playback assertion on behalf of the UIProcess. Since this is token-based
+           and the token is stored on the WebProcessProxy object, it makes it less likely to leak
+           the assertion.
+        3. The WebProcessProxy object now has a AudibleMediaActivity data structure wrapping both
+           its media playback assertion and its WebProcessWithAudibleMediaToken that it got from
+           the WebProcessPool. When the WebProcess shuts down (normally or due to crash/termination),
+           we make sure to clear this data structure.
+        4. Make sure that the WebProcessProxy updates its AudibleMediaActivity whenever a page is
+           removed from the WebProcess.
+
+        * UIProcess/WebPageProxy.cpp:
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::m_webProcessWithAudibleMediaCounter):
+        (WebKit::WebProcessPool::disconnectProcess):
+        (WebKit::WebProcessPool::webProcessWithAudibleMediaToken const):
+        (WebKit::WebProcessPool::updateAudibleMediaAssertions):
+        * UIProcess/WebProcessPool.h:
+        * UIProcess/WebProcessProxy.cpp:
+        (WebKit::WebProcessProxy::shutDown):
+        (WebKit::WebProcessProxy::removeWebPage):
+        (WebKit::WebProcessProxy::updateAudibleMediaAssertions):
+        * UIProcess/WebProcessProxy.h:
+
 2020-04-20  Kate Cheney  <[email protected]>
 
         <rdar://problem/62059046>

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (260372 => 260373)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2020-04-20 17:15:28 UTC (rev 260372)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2020-04-20 17:48:42 UTC (rev 260373)
@@ -8929,7 +8929,7 @@
     if ((oldState & MediaProducer::HasAudioOrVideo) != (m_mediaState & MediaProducer::HasAudioOrVideo))
         videoControlsManagerDidChange();
 
-    m_process->webPageMediaStateDidChange(*this);
+    m_process->updateAudibleMediaAssertions();
 }
 
 void WebPageProxy::videoControlsManagerDidChange()

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (260372 => 260373)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2020-04-20 17:15:28 UTC (rev 260372)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2020-04-20 17:48:42 UTC (rev 260373)
@@ -260,6 +260,7 @@
     , m_backgroundWebProcessCounter([this](RefCounterEvent) { updateProcessAssertions(); })
     , m_backForwardCache(makeUniqueRef<WebBackForwardCache>(*this))
     , m_webProcessCache(makeUniqueRef<WebProcessCache>(*this))
+    , m_webProcessWithAudibleMediaCounter([this](RefCounterEvent) { updateAudibleMediaAssertions(); })
 {
     static std::once_flag onceFlag;
     std::call_once(onceFlag, [] {
@@ -1182,7 +1183,6 @@
 void WebProcessPool::disconnectProcess(WebProcessProxy* process)
 {
     ASSERT(m_processes.contains(process));
-    ASSERT(!m_processesPlayingAudibleMedia.contains(process->coreProcessIdentifier()));
 
     if (m_prewarmedProcess == process) {
         ASSERT(m_prewarmedProcess->isPrewarmed());
@@ -2350,48 +2350,31 @@
 }
 #endif
 
-void WebProcessPool::setWebProcessIsPlayingAudibleMedia(WebCore::ProcessIdentifier processID)
+WebProcessWithAudibleMediaToken WebProcessPool::webProcessWithAudibleMediaToken() const
 {
-    auto* process = WebProcessProxy::processForIdentifier(processID);
-    ASSERT(process);
+    return m_webProcessWithAudibleMediaCounter.count();
+}
 
-    WEBPROCESSPOOL_RELEASE_LOG(ProcessSuspension, "setWebProcessIsPlayingAudibleMedia: Web process is now playing audible media (process=%p, PID=%i)", process, process->processIdentifier());
+void WebProcessPool::updateAudibleMediaAssertions()
+{
+    if (!m_webProcessWithAudibleMediaCounter.value()) {
+        WEBPROCESSPOOL_RELEASE_LOG(ProcessSuspension, "updateAudibleMediaAssertions: The number of processes playing audible media now zero. Releasing UI process assertion.");
+        m_audibleMediaActivity = WTF::nullopt;
+        return;
+    }
 
-    if (m_processesPlayingAudibleMedia.isEmpty()) {
-        WEBPROCESSPOOL_RELEASE_LOG(ProcessSuspension, "setWebProcessIsPlayingAudibleMedia: The number of processes playing audible media is now one. Taking UI process assertion.");
+    if (m_audibleMediaActivity)
+        return;
 
-        ASSERT(!m_uiProcessMediaPlaybackAssertion);
-        m_uiProcessMediaPlaybackAssertion = makeUnique<ProcessAssertion>(getCurrentProcessID(), "WebKit Media Playback"_s, ProcessAssertionType::MediaPlayback);
+    WEBPROCESSPOOL_RELEASE_LOG(ProcessSuspension, "updateAudibleMediaAssertions: The number of processes playing audible media is now greater than zero. Taking UI process assertion.");
+    m_audibleMediaActivity = AudibleMediaActivity {
+        makeUniqueRef<ProcessAssertion>(getCurrentProcessID(), "WebKit Media Playback"_s, ProcessAssertionType::MediaPlayback)
 #if ENABLE(GPU_PROCESS)
-        if (GPUProcessProxy::singletonIfCreated())
-            m_gpuProcessMediaPlaybackAssertion = makeUnique<ProcessAssertion>(GPUProcessProxy::singleton().processIdentifier(), "WebKit Media Playback"_s, ProcessAssertionType::MediaPlayback);
+        , GPUProcessProxy::singletonIfCreated() ? makeUnique<ProcessAssertion>(GPUProcessProxy::singleton().processIdentifier(), "WebKit Media Playback"_s, ProcessAssertionType::MediaPlayback) : nullptr
 #endif
-    }
-
-    auto result = m_processesPlayingAudibleMedia.add(processID, nullptr);
-    ASSERT(result.isNewEntry);
-    result.iterator->value = makeUnique<ProcessAssertion>(process->processIdentifier(), "WebKit Media Playback"_s, ProcessAssertionType::MediaPlayback);
+    };
 }
 
-void WebProcessPool::clearWebProcessIsPlayingAudibleMedia(WebCore::ProcessIdentifier processID)
-{
-    auto result = m_processesPlayingAudibleMedia.take(processID);
-    ASSERT_UNUSED(result, result);
-
-    auto* process = WebProcessProxy::processForIdentifier(processID);
-    ASSERT_UNUSED(process, process);
-
-    WEBPROCESSPOOL_RELEASE_LOG(ProcessSuspension, "clearWebProcessIsPlayingAudibleMedia: Web process is no longer playing audible media (process=%p, PID=%i)", process, process->processIdentifier());
-
-    if (m_processesPlayingAudibleMedia.isEmpty()) {
-        WEBPROCESSPOOL_RELEASE_LOG(ProcessSuspension, "clearWebProcessIsPlayingAudibleMedia: The number of processes playing audible media now zero. Releasing UI process assertion.");
-
-        ASSERT(m_uiProcessMediaPlaybackAssertion);
-        m_uiProcessMediaPlaybackAssertion = nullptr;
-        m_gpuProcessMediaPlaybackAssertion = nullptr;
-    }
-}
-
 void WebProcessPool::setUseSeparateServiceWorkerProcess(bool useSeparateServiceWorkerProcess)
 {
     if (m_useSeparateServiceWorkerProcess == useSeparateServiceWorkerProcess)

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.h (260372 => 260373)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.h	2020-04-20 17:15:28 UTC (rev 260372)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.h	2020-04-20 17:48:42 UTC (rev 260373)
@@ -517,8 +517,7 @@
     const Function<void(UserMessage&&, CompletionHandler<void(UserMessage&&)>&&)>& userMessageHandler() const { return m_userMessageHandler; }
 #endif
 
-    void setWebProcessIsPlayingAudibleMedia(WebCore::ProcessIdentifier);
-    void clearWebProcessIsPlayingAudibleMedia(WebCore::ProcessIdentifier);
+    WebProcessWithAudibleMediaToken webProcessWithAudibleMediaToken() const;
 
     void disableDelayedWebProcessLaunch() { m_isDelayedWebProcessLaunchDisabled = true; }
 
@@ -562,6 +561,7 @@
 #endif
 
     void updateProcessAssertions();
+    void updateAudibleMediaAssertions();
 
     // IPC::MessageReceiver.
     // Implemented in generated WebProcessPoolMessageReceiver.cpp
@@ -787,10 +787,16 @@
     Function<void(UserMessage&&, CompletionHandler<void(UserMessage&&)>&&)> m_userMessageHandler;
 #endif
 
-    HashMap<WebCore::ProcessIdentifier, std::unique_ptr<ProcessAssertion>> m_processesPlayingAudibleMedia;
-    std::unique_ptr<ProcessAssertion> m_uiProcessMediaPlaybackAssertion;
-    std::unique_ptr<ProcessAssertion> m_gpuProcessMediaPlaybackAssertion;
+    WebProcessWithAudibleMediaCounter m_webProcessWithAudibleMediaCounter;
 
+    struct AudibleMediaActivity {
+        UniqueRef<ProcessAssertion> uiProcessMediaPlaybackAssertion;
+#if ENABLE(GPU_PROCESS)
+        std::unique_ptr<ProcessAssertion> gpuProcessMediaPlaybackAssertion;
+#endif
+    };
+    Optional<AudibleMediaActivity> m_audibleMediaActivity;
+
 #if PLATFORM(IOS)
     // FIXME: Delayed process launch is currently disabled on iOS for performance reasons (rdar://problem/49074131).
     bool m_isDelayedWebProcessLaunchDisabled { true };

Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp (260372 => 260373)


--- trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp	2020-04-20 17:15:28 UTC (rev 260372)
+++ trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp	2020-04-20 17:48:42 UTC (rev 260373)
@@ -414,6 +414,7 @@
     m_responsivenessTimer.invalidate();
     m_backgroundResponsivenessTimer.invalidate();
     m_activityForHoldingLockedFiles = nullptr;
+    m_audibleMediaActivity = WTF::nullopt;
 
     for (auto& frame : copyToVector(m_frameMap.values()))
         frame->webProcessWillShutDown();
@@ -513,7 +514,7 @@
 
     removeVisitedLinkStoreUser(webPage.visitedLinkStore(), webPage.identifier());
     updateRegistrationWithDataStore();
-
+    updateAudibleMediaAssertions();
     updateBackgroundResponsivenessTimer();
 
     maybeShutDown();
@@ -1382,17 +1383,24 @@
     ASSERT(!m_backgroundToken || !m_foregroundToken);
 }
 
-void WebProcessProxy::webPageMediaStateDidChange(WebPageProxy&)
+void WebProcessProxy::updateAudibleMediaAssertions()
 {
     bool newHasAudibleWebPage = WTF::anyOf(m_pageMap.values(), [] (auto& page) { return page->isPlayingAudio(); });
-    if (m_hasAudibleWebPage == newHasAudibleWebPage)
+
+    bool hasAudibleMediaActivity = !!m_audibleMediaActivity;
+    if (hasAudibleMediaActivity == newHasAudibleWebPage)
         return;
-    m_hasAudibleWebPage = newHasAudibleWebPage;
 
-    if (m_hasAudibleWebPage)
-        processPool().setWebProcessIsPlayingAudibleMedia(coreProcessIdentifier());
-    else
-        processPool().clearWebProcessIsPlayingAudibleMedia(coreProcessIdentifier());
+    if (newHasAudibleWebPage) {
+        RELEASE_LOG(ProcessSuspension, "%p - Taking MediaPlayback assertion for WebProcess with PID %d", this, processIdentifier());
+        m_audibleMediaActivity = AudibleMediaActivity {
+            makeUniqueRef<ProcessAssertion>(processIdentifier(), "WebKit Media Playback"_s, ProcessAssertionType::MediaPlayback),
+            processPool().webProcessWithAudibleMediaToken()
+        };
+    } else {
+        RELEASE_LOG(ProcessSuspension, "%p - Releasing MediaPlayback assertion for WebProcess with PID %d", this, processIdentifier());
+        m_audibleMediaActivity = WTF::nullopt;
+    }
 }
 
 void WebProcessProxy::setIsHoldingLockedFiles(bool isHoldingLockedFiles)

Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.h (260372 => 260373)


--- trunk/Source/WebKit/UIProcess/WebProcessProxy.h	2020-04-20 17:15:28 UTC (rev 260372)
+++ trunk/Source/WebKit/UIProcess/WebProcessProxy.h	2020-04-20 17:48:42 UTC (rev 260373)
@@ -106,6 +106,9 @@
 enum BackgroundWebProcessCounterType { };
 typedef RefCounter<BackgroundWebProcessCounterType> BackgroundWebProcessCounter;
 typedef BackgroundWebProcessCounter::Token BackgroundWebProcessToken;
+enum WebProcessWithAudibleMediaCounterType { };
+using WebProcessWithAudibleMediaCounter = RefCounter<WebProcessWithAudibleMediaCounterType>;
+using WebProcessWithAudibleMediaToken = WebProcessWithAudibleMediaCounter::Token;
 
 class WebProcessProxy : public AuxiliaryProcessProxy, public ResponsivenessTimer::Client, public ThreadSafeRefCounted<WebProcessProxy>, public CanMakeWeakPtr<WebProcessProxy>, private ProcessThrottlerClient {
 public:
@@ -345,7 +348,7 @@
 #endif
 #endif
 
-    void webPageMediaStateDidChange(WebPageProxy&);
+    void updateAudibleMediaAssertions();
 
     void ref() final { ThreadSafeRefCounted::ref(); }
     void deref() final { ThreadSafeRefCounted::deref(); }
@@ -568,7 +571,6 @@
     unsigned m_shutdownPreventingScopeCount { 0 };
     bool m_hasCommittedAnyProvisionalLoads { false };
     bool m_isPrewarmed;
-    bool m_hasAudibleWebPage { false };
 #if ENABLE(ATTACHMENT_ELEMENT) && PLATFORM(IOS_FAMILY)
     bool m_hasIssuedAttachmentElementRelatedSandboxExtensions { false };
 #endif
@@ -593,6 +595,12 @@
     Optional<ServiceWorkerInformation> m_serviceWorkerInformation;
 
     HashMap<WebCore::SleepDisablerIdentifier, std::unique_ptr<WebCore::SleepDisabler>> m_sleepDisablers;
+
+    struct AudibleMediaActivity {
+        UniqueRef<ProcessAssertion> assertion;
+        WebProcessWithAudibleMediaToken token;
+    };
+    Optional<AudibleMediaActivity> m_audibleMediaActivity;
 };
 
 } // namespace WebKit
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to