Implement WebProcess freezer opt-in completely on WebContent process side
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 22 Mar 2019 17:40:51 +0000 (17:40 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 22 Mar 2019 17:40:51 +0000 (17:40 +0000)
https://bugs.webkit.org/show_bug.cgi?id=196149

Reviewed by Brady Eidson.

Implement WebProcess freezer opt-in completely on WebContent process side, we do not need
to involve the UIProcess with this and rely on IPC which may be fragile.

In the future, we may want to set freezable state from the UIProcess when the API supports
it. We can move the logic to be fully on the UIProcess side then. In the mean time, it is
likely best not to rely on IPC and process coordination for this.

* UIProcess/WebProcessProxy.cpp:
(WebKit::globalPageMap):
(WebKit::WebProcessProxy::WebProcessProxy):
(WebKit::WebProcessProxy::setIsInProcessCache):
(WebKit::WebProcessProxy::markIsNoLongerInPrewarmedPool):
(WebKit::WebProcessProxy::didFinishLaunching):
(WebKit::WebProcessProxy::validateFreezerStatus): Deleted.
* UIProcess/WebProcessProxy.h:
(WebKit::WebProcessProxy::removeProvisionalPageProxy):
(WebKit::WebProcessProxy::WebPageProxyMap::WebPageProxyMap): Deleted.
(WebKit::WebProcessProxy::WebPageProxyMap::size const): Deleted.
(WebKit::WebProcessProxy::WebPageProxyMap::values): Deleted.
(WebKit::WebProcessProxy::WebPageProxyMap::values const): Deleted.
(WebKit::WebProcessProxy::WebPageProxyMap::begin): Deleted.
(WebKit::WebProcessProxy::WebPageProxyMap::end): Deleted.
(WebKit::WebProcessProxy::WebPageProxyMap::get): Deleted.
(WebKit::WebProcessProxy::WebPageProxyMap::contains const): Deleted.
(WebKit::WebProcessProxy::WebPageProxyMap::isEmpty const): Deleted.
(WebKit::WebProcessProxy::WebPageProxyMap::set): Deleted.
(WebKit::WebProcessProxy::WebPageProxyMap::take): Deleted.
* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::setIsInProcessCache):
(WebKit::WebProcess::markIsNoLongerPrewarmed):
(WebKit::WebProcess::actualPrepareToSuspend):
(WebKit::WebProcess::setFreezable): Deleted.
* WebProcess/WebProcess.h:
* WebProcess/WebProcess.messages.in:
* WebProcess/cocoa/WebProcessCocoa.mm:
(WebKit::WebProcess::updateProcessName):
(WebKit::WebProcess::shouldFreezeOnSuspension const):
(WebKit::WebProcess::updateFreezerStatus):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@243388 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit/ChangeLog
Source/WebKit/UIProcess/WebProcessProxy.cpp
Source/WebKit/UIProcess/WebProcessProxy.h
Source/WebKit/WebProcess/WebProcess.cpp
Source/WebKit/WebProcess/WebProcess.h
Source/WebKit/WebProcess/WebProcess.messages.in
Source/WebKit/WebProcess/cocoa/WebProcessCocoa.mm

index 4e4d85b..63b9d4a 100644 (file)
@@ -1,5 +1,51 @@
 2019-03-22  Chris Dumez  <cdumez@apple.com>
 
+        Implement WebProcess freezer opt-in completely on WebContent process side
+        https://bugs.webkit.org/show_bug.cgi?id=196149
+
+        Reviewed by Brady Eidson.
+
+        Implement WebProcess freezer opt-in completely on WebContent process side, we do not need
+        to involve the UIProcess with this and rely on IPC which may be fragile.
+
+        In the future, we may want to set freezable state from the UIProcess when the API supports
+        it. We can move the logic to be fully on the UIProcess side then. In the mean time, it is
+        likely best not to rely on IPC and process coordination for this.
+
+        * UIProcess/WebProcessProxy.cpp:
+        (WebKit::globalPageMap):
+        (WebKit::WebProcessProxy::WebProcessProxy):
+        (WebKit::WebProcessProxy::setIsInProcessCache):
+        (WebKit::WebProcessProxy::markIsNoLongerInPrewarmedPool):
+        (WebKit::WebProcessProxy::didFinishLaunching):
+        (WebKit::WebProcessProxy::validateFreezerStatus): Deleted.
+        * UIProcess/WebProcessProxy.h:
+        (WebKit::WebProcessProxy::removeProvisionalPageProxy):
+        (WebKit::WebProcessProxy::WebPageProxyMap::WebPageProxyMap): Deleted.
+        (WebKit::WebProcessProxy::WebPageProxyMap::size const): Deleted.
+        (WebKit::WebProcessProxy::WebPageProxyMap::values): Deleted.
+        (WebKit::WebProcessProxy::WebPageProxyMap::values const): Deleted.
+        (WebKit::WebProcessProxy::WebPageProxyMap::begin): Deleted.
+        (WebKit::WebProcessProxy::WebPageProxyMap::end): Deleted.
+        (WebKit::WebProcessProxy::WebPageProxyMap::get): Deleted.
+        (WebKit::WebProcessProxy::WebPageProxyMap::contains const): Deleted.
+        (WebKit::WebProcessProxy::WebPageProxyMap::isEmpty const): Deleted.
+        (WebKit::WebProcessProxy::WebPageProxyMap::set): Deleted.
+        (WebKit::WebProcessProxy::WebPageProxyMap::take): Deleted.
+        * WebProcess/WebProcess.cpp:
+        (WebKit::WebProcess::setIsInProcessCache):
+        (WebKit::WebProcess::markIsNoLongerPrewarmed):
+        (WebKit::WebProcess::actualPrepareToSuspend):
+        (WebKit::WebProcess::setFreezable): Deleted.
+        * WebProcess/WebProcess.h:
+        * WebProcess/WebProcess.messages.in:
+        * WebProcess/cocoa/WebProcessCocoa.mm:
+        (WebKit::WebProcess::updateProcessName):
+        (WebKit::WebProcess::shouldFreezeOnSuspension const):
+        (WebKit::WebProcess::updateFreezerStatus):
+
+2019-03-22  Chris Dumez  <cdumez@apple.com>
+
         Prewarmed processes should be usable with any website data store
         https://bugs.webkit.org/show_bug.cgi?id=196104
 
index f9e7fcc..ea74141 100644 (file)
@@ -115,10 +115,10 @@ uint64_t WebProcessProxy::generatePageID()
     return ++uniquePageID;
 }
 
-static WebProcessProxy::WebPageProxyMap::MapType& globalPageMap()
+static WebProcessProxy::WebPageProxyMap& globalPageMap()
 {
     ASSERT(isMainThreadOrCheckDisabled());
-    static NeverDestroyed<WebProcessProxy::WebPageProxyMap::MapType> pageMap;
+    static NeverDestroyed<WebProcessProxy::WebPageProxyMap> pageMap;
     return pageMap;
 }
 
@@ -136,7 +136,6 @@ WebProcessProxy::WebProcessProxy(WebProcessPool& processPool, WebsiteDataStore*
     , m_backgroundResponsivenessTimer(*this)
     , m_processPool(processPool, isPrewarmed == IsPrewarmed::Yes ? IsWeak::Yes : IsWeak::No)
     , m_mayHaveUniversalFileReadSandboxExtension(false)
-    , m_pageMap(*this)
     , m_numberOfTimesSuddenTerminationWasDisabled(0)
     , m_throttler(*this, processPool.shouldTakeUIBackgroundAssertion())
     , m_isResponsive(NoOrMaybe::Maybe)
@@ -188,18 +187,6 @@ WebProcessProxy::~WebProcessProxy()
 #endif
 }
 
-void WebProcessProxy::validateFreezerStatus()
-{
-#if PLATFORM(IOS_FAMILY)
-    bool value = !m_isPrewarmed && !m_isInProcessCache && !m_pageMap.isEmpty() && !isServiceWorkerProcess();
-    if (m_currentIsFreezableValue != WTF::nullopt && m_currentIsFreezableValue == value)
-        return;
-
-    m_currentIsFreezableValue = value;
-    send(Messages::WebProcess::SetFreezable(value), 0);
-#endif
-}
-
 void WebProcessProxy::setIsInProcessCache(bool value)
 {
     ASSERT(m_isInProcessCache != value);
@@ -215,8 +202,6 @@ void WebProcessProxy::setIsInProcessCache(bool value)
         RELEASE_ASSERT(m_processPool);
         m_processPool.setIsWeak(IsWeak::No);
     }
-    
-    validateFreezerStatus();
 }
 
 void WebProcessProxy::setWebsiteDataStore(WebsiteDataStore& dataStore)
@@ -400,8 +385,6 @@ void WebProcessProxy::markIsNoLongerInPrewarmedPool()
     RELEASE_ASSERT(m_processPool);
     m_processPool.setIsWeak(IsWeak::No);
 
-    validateFreezerStatus();
-
     send(Messages::WebProcess::MarkIsNoLongerPrewarmed(), 0);
 }
 
@@ -795,8 +778,6 @@ void WebProcessProxy::didFinishLaunching(ProcessLauncher* launcher, IPC::Connect
 
     unblockAccessibilityServerIfNeeded();
 #endif
-
-    validateFreezerStatus();
 }
 
 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
index 01ba243..93ab682 100644 (file)
@@ -96,6 +96,7 @@ enum class AllowProcessCaching { No, Yes };
 class WebProcessProxy : public AuxiliaryProcessProxy, public ResponsivenessTimer::Client, public ThreadSafeRefCounted<WebProcessProxy>, public CanMakeWeakPtr<WebProcessProxy>, private ProcessThrottlerClient {
 public:
     typedef HashMap<uint64_t, RefPtr<WebFrameProxy>> WebFrameProxyMap;
+    typedef HashMap<uint64_t, WebPageProxy*> WebPageProxyMap;
     typedef HashMap<uint64_t, RefPtr<API::UserInitiatedAction>> UserInitiatedActionMap;
 
     enum class IsPrewarmed {
@@ -135,45 +136,6 @@ public:
 
     void addProvisionalPageProxy(ProvisionalPageProxy& provisionalPage) { ASSERT(!m_provisionalPages.contains(&provisionalPage)); m_provisionalPages.add(&provisionalPage); }
     void removeProvisionalPageProxy(ProvisionalPageProxy& provisionalPage) { ASSERT(m_provisionalPages.contains(&provisionalPage)); m_provisionalPages.remove(&provisionalPage); }
-
-    class WebPageProxyMap {
-    public:
-        WebPageProxyMap(WebProcessProxy& proxy)
-            : m_proxy(proxy)
-        {
-        }
-
-        typedef HashMap<uint64_t, WebPageProxy*> MapType;
-        using ValuesConstIteratorRange = MapType::ValuesConstIteratorRange;
-
-        auto size() const { return m_map.size(); }
-        auto values() { return m_map.values(); }
-        auto values() const { return m_map.values(); }
-        auto begin() { return m_map.begin(); }
-        auto end() { return m_map.end(); }
-        auto get(uint64_t key) { return m_map.get(key); }
-        auto contains(uint64_t key) const { return m_map.contains(key); }
-        auto isEmpty() const { return m_map.isEmpty(); }
-
-        auto set(uint64_t key, WebPageProxy* value)
-        {
-            auto result = m_map.set(key, value);
-            m_proxy.validateFreezerStatus();
-            return result;
-        }
-
-        auto take(uint64_t key)
-        {
-            auto result = m_map.take(key);
-            m_proxy.validateFreezerStatus();
-            return result;
-        }
-
-    private:
-        WebProcessProxy& m_proxy;
-        MapType m_map;
-    };
-
     
     typename WebPageProxyMap::ValuesConstIteratorRange pages() const { return m_pageMap.values(); }
     unsigned pageCount() const { return m_pageMap.size(); }
@@ -508,7 +470,6 @@ private:
     unsigned m_suspendedPageCount { 0 };
     bool m_hasCommittedAnyProvisionalLoads { false };
     bool m_isPrewarmed;
-    Optional<bool> m_currentIsFreezableValue;
 
 #if PLATFORM(WATCHOS)
     ProcessThrottler::BackgroundActivityToken m_backgroundActivityTokenForFullscreenFormControls;
index c05bf09..b549c3d 100644 (file)
 #include <JavaScriptCore/RemoteInspector.h>
 #endif
 
-#if PLATFORM(IOS_FAMILY)
-#include <bmalloc/MemoryStatusSPI.h>
-#endif
-
 // This should be less than plugInAutoStartExpirationTimeThreshold in PlugInAutoStartProvider.
 static const Seconds plugInAutoStartExpirationTimeUpdateThreshold { 29 * 24 * 60 * 60 };
 
@@ -507,7 +503,7 @@ void WebProcess::setHasSuspendedPageProxy(bool hasSuspendedPageProxy)
 
 void WebProcess::setIsInProcessCache(bool isInProcessCache)
 {
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
     if (isInProcessCache) {
         ASSERT(m_processType == ProcessType::WebContent);
         m_processType = ProcessType::CachedWebContent;
@@ -524,7 +520,7 @@ void WebProcess::setIsInProcessCache(bool isInProcessCache)
 
 void WebProcess::markIsNoLongerPrewarmed()
 {
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
     ASSERT(m_processType == ProcessType::PrewarmedWebContent);
     m_processType = ProcessType::WebContent;
 
@@ -1469,6 +1465,7 @@ void WebProcess::actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend shou
 
 #if PLATFORM(IOS_FAMILY)
     accessibilityProcessSuspendedNotification(true);
+    updateFreezerStatus();
 #endif
 
     markAllLayersVolatile([this, shouldAcknowledgeWhenReadyToSuspend](bool success) {
@@ -1884,14 +1881,6 @@ void WebProcess::clearCurrentModifierStateForTesting()
     PlatformKeyboardEvent::setCurrentModifierState({ });
 }
 
-void WebProcess::setFreezable(bool freezable)
-{
-#if PLATFORM(IOS_FAMILY)
-    auto result = memorystatus_control(MEMORYSTATUS_CMD_SET_PROCESS_IS_FREEZABLE, getpid(), freezable ? 1 : 0, nullptr, 0);
-    ASSERT_UNUSED(result, !result);
-#endif
-}
-
 #if PLATFORM(IOS_FAMILY)
 void WebProcess::unblockAccessibilityServer(const SandboxExtension::Handle& handle)
 {
index 3d947b1..fea853b 100644 (file)
@@ -411,7 +411,6 @@ private:
     void didReceiveSyncWebProcessMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&);
 
 #if PLATFORM(MAC)
-    void updateProcessName();
     void setScreenProperties(const WebCore::ScreenProperties&);
 #if ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
     void scrollerStylePreferenceChanged(bool useOverlayScrollbars);
@@ -420,8 +419,15 @@ private:
 #endif
 #endif
 
+#if PLATFORM(COCOA)
+    void updateProcessName();
+#endif
+
 #if PLATFORM(IOS)
     void backlightLevelDidChange(float backlightLevel);
+
+    bool shouldFreezeOnSuspension() const;
+    void updateFreezerStatus();
 #endif
 
 #if ENABLE(VIDEO)
@@ -430,7 +436,6 @@ private:
 #endif
 
     void clearCurrentModifierStateForTesting();
-    void setFreezable(bool);
 
     RefPtr<WebConnectionToUIProcess> m_webConnection;
 
@@ -505,12 +510,15 @@ private:
     std::unique_ptr<WebCore::CPUMonitor> m_cpuMonitor;
     Optional<double> m_cpuLimit;
 
-    enum class ProcessType { Inspector, ServiceWorker, PrewarmedWebContent, CachedWebContent, WebContent };
-    ProcessType m_processType { ProcessType::WebContent };
     String m_uiProcessName;
     WebCore::RegistrableDomain m_registrableDomain;
 #endif
 
+#if PLATFORM(COCOA)
+    enum class ProcessType { Inspector, ServiceWorker, PrewarmedWebContent, CachedWebContent, WebContent };
+    ProcessType m_processType { ProcessType::WebContent };
+#endif
+
     HashMap<WebCore::UserGestureToken *, uint64_t> m_userGestureTokens;
 
 #if PLATFORM(WAYLAND)
index 627f19f..a189143 100644 (file)
@@ -162,6 +162,4 @@ messages -> WebProcess LegacyReceiver {
 #if PLATFORM(IOS_FAMILY)
     UnblockAccessibilityServer(WebKit::SandboxExtension::Handle handle)
 #endif
-
-    SetFreezable(bool freezable)
 }
index 3cd3c8b..87f8567 100644 (file)
@@ -62,6 +62,7 @@
 #import <WebCore/NSScrollerImpDetails.h>
 #import <WebCore/PerformanceLogging.h>
 #import <WebCore/RuntimeApplicationChecks.h>
+#import <WebCore/SWContextManager.h>
 #import <algorithm>
 #import <dispatch/dispatch.h>
 #import <objc/runtime.h>
 #endif
 
 #if PLATFORM(IOS_FAMILY)
+#include <bmalloc/MemoryStatusSPI.h>
+#endif
+
+#if PLATFORM(IOS_FAMILY)
 #import "WKAccessibilityWebPageObjectIOS.h"
 #import <UIKit/UIAccessibility.h>
 #import <pal/spi/ios/GraphicsServicesSPI.h>
@@ -237,9 +242,9 @@ void WebProcess::initializeProcessName(const AuxiliaryProcessInitializationParam
 #endif
 }
 
-#if PLATFORM(MAC)
 void WebProcess::updateProcessName()
 {
+#if PLATFORM(MAC)
     NSString *applicationName;
     switch (m_processType) {
     case ProcessType::Inspector:
@@ -273,8 +278,8 @@ void WebProcess::updateProcessName()
         ASSERT(!actualApplicationName.isEmpty());
 #endif
     });
-}
 #endif // PLATFORM(MAC)
+}
 
 static void registerWithAccessibility()
 {
@@ -681,6 +686,36 @@ void WebProcess::accessibilityProcessSuspendedNotification(bool suspended)
 {
     UIAccessibilityPostNotification(kAXPidStatusChangedNotification, @{ @"pid" : @(getpid()), @"suspended" : @(suspended) });
 }
+
+bool WebProcess::shouldFreezeOnSuspension() const
+{
+    switch (m_processType) {
+    case ProcessType::Inspector:
+    case ProcessType::ServiceWorker:
+    case ProcessType::PrewarmedWebContent:
+    case ProcessType::CachedWebContent:
+        return false;
+    case ProcessType::WebContent:
+        break;
+    }
+
+    for (auto& page : m_pageMap.values()) {
+        if (!page->isSuspended())
+            return false;
+    }
+
+    return true;
+}
+
+void WebProcess::updateFreezerStatus()
+{
+    bool isFreezable = shouldFreezeOnSuspension();
+    auto result = memorystatus_control(MEMORYSTATUS_CMD_SET_PROCESS_IS_FREEZABLE, getpid(), isFreezable ? 1 : 0, nullptr, 0);
+    if (result)
+        RELEASE_LOG_ERROR(ProcessSuspension, "%p - WebProcess::updateFreezerStatus() isFreezable: %d, error: %d", this, isFreezable, result);
+    else
+        RELEASE_LOG(ProcessSuspension, "%p - WebProcess::updateFreezerStatus() isFreezable: %d, success", this, isFreezable);
+}
 #endif
 
 #if PLATFORM(MAC) && ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)