Changeset 212619 in webkit
- Timestamp:
- Feb 19, 2017, 6:38:43 PM (8 years ago)
- Location:
- trunk/Source/WebKit2
- Files:
-
- 2 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebKit2/CMakeLists.txt
r211744 r212619 286 286 UIProcess/StatisticsRequest.cpp 287 287 UIProcess/TextCheckerCompletion.cpp 288 UIProcess/UnresponsiveWebProcessTerminator.cpp 288 289 UIProcess/UserMediaPermissionCheckProxy.cpp 289 290 UIProcess/UserMediaPermissionRequestManagerProxy.cpp -
trunk/Source/WebKit2/ChangeLog
r212608 r212619 1 2017-02-19 Chris Dumez <cdumez@apple.com> 2 3 [WK2] Support termination of unresponsive WebContent processes that are in the background 4 https://bugs.webkit.org/show_bug.cgi?id=168479 5 <rdar://problem/30558745> 6 7 Reviewed by Antti Koivisto. 8 9 Support termination of unresponsive WebContent processes that are in the background. 10 This protects us against cases where a background tab is unresponsive and has high CPU 11 usage, thus draining the battery without the user knowing about it (e.g. 12 <rdar://problem/29808005>). 13 14 The feature works as follows: 15 - If a WebProcessProxy has pages but none of them are visible, then it will check 16 regularly if its associated WebContent process is still responsive. 17 - Every time we find that the WebContent process is responsive, we exponentially 18 back off the timer to avoid waking up the process too often. The timer initially 19 uses a 20 seconds interval and can back off up to 8 hours. 20 - If the WebContent process is unresponsive, then we terminate it. No notification 21 is shown to the user and the termination is not immediately observable since the 22 tab is not visible and its title remains. The tab is not immediately reloaded 23 so as to avoid getting back into a bad state in the background (and have a 24 yo-yo effect). 25 - If the user switches to a tab that was previously killed for being unresponsive 26 while in the background, we will then reload the tab in a fresh WebContent 27 process. The crash banner will only be shown if the tab has ever been visible. 28 If it wasn't ever visible (e.g. session restore case), then it will look as if 29 the tab loads for the first time when the user switches to it. 30 31 The functionality is disabled by default and can be enabled by the client via the new 32 WKContextSetUnresponsiveBackgroundProcessesTerminationEnabled() private API. 33 34 * CMakeLists.txt: 35 * UIProcess/API/APIProcessPoolConfiguration.cpp: 36 (API::ProcessPoolConfiguration::copy): 37 * UIProcess/API/APIProcessPoolConfiguration.h: 38 * UIProcess/API/C/WKContext.cpp: 39 (WKContextSetUnresponsiveBackgroundProcessesTerminationEnabled): 40 * UIProcess/API/C/WKContextPrivate.h: 41 * UIProcess/UnresponsiveWebProcessTerminator.cpp: Added. 42 (WebKit::UnresponsiveWebProcessTerminator::UnresponsiveWebProcessTerminator): 43 (WebKit::UnresponsiveWebProcessTerminator::updateState): 44 (WebKit::pagesCopy): 45 (WebKit::UnresponsiveWebProcessTerminator::timerFired): 46 * UIProcess/UnresponsiveWebProcessTerminator.h: Added. 47 (WebKit::UnresponsiveWebProcessTerminator::shouldBeActive): 48 * UIProcess/WebPageProxy.cpp: 49 (WebKit::WebPageProxy::reattachToWebProcess): 50 (WebKit::WebPageProxy::reloadAfterBeingKilledInBackground): 51 (WebKit::WebPageProxy::dispatchActivityStateChange): 52 (WebKit::WebPageProxy::terminateProcess): 53 (WebKit::WebPageProxy::resetStateAfterProcessExited): 54 * UIProcess/WebPageProxy.h: 55 * UIProcess/WebProcessProxy.cpp: 56 (WebKit::WebProcessProxy::WebProcessProxy): 57 (WebKit::m_backgroundResponsivenessTimer): 58 (WebKit::WebProcessProxy::createWebPage): 59 (WebKit::WebProcessProxy::addExistingWebPage): 60 (WebKit::WebProcessProxy::removeWebPage): 61 (WebKit::WebProcessProxy::updateBackgroundResponsivenessTimer): 62 * UIProcess/WebProcessProxy.h: 63 (WebKit::WebProcessProxy::visiblePageCount): 64 * WebKit2.xcodeproj/project.pbxproj: 65 1 66 2017-02-18 Michael Catanzaro <mcatanzaro@igalia.com> 2 67 -
trunk/Source/WebKit2/UIProcess/API/APIProcessPoolConfiguration.cpp
r207346 r212619 97 97 copy->m_cacheModel = this->m_cacheModel; 98 98 copy->m_diskCacheSpeculativeValidationEnabled = this->m_diskCacheSpeculativeValidationEnabled; 99 copy->m_unresponsiveBackgroundProcessesTerminationEnabled = this->m_unresponsiveBackgroundProcessesTerminationEnabled; 99 100 copy->m_diskCacheSizeOverride = this->m_diskCacheSizeOverride; 100 101 copy->m_applicationCacheDirectory = this->m_applicationCacheDirectory; -
trunk/Source/WebKit2/UIProcess/API/APIProcessPoolConfiguration.h
r207346 r212619 55 55 bool diskCacheSpeculativeValidationEnabled() const { return m_diskCacheSpeculativeValidationEnabled; } 56 56 void setDiskCacheSpeculativeValidationEnabled(bool enabled) { m_diskCacheSpeculativeValidationEnabled = enabled; } 57 58 bool unresponsiveBackgroundProcessesTerminationEnabled() const { return m_unresponsiveBackgroundProcessesTerminationEnabled; } 59 void setUnresponsiveBackgroundProcessesTerminationEnabled(bool enabled) { m_unresponsiveBackgroundProcessesTerminationEnabled = enabled; } 57 60 58 61 WebKit::CacheModel cacheModel() const { return m_cacheModel; } … … 122 125 unsigned m_maximumProcessCount { 0 }; 123 126 bool m_diskCacheSpeculativeValidationEnabled { false }; 127 bool m_unresponsiveBackgroundProcessesTerminationEnabled { false }; 124 128 WebKit::CacheModel m_cacheModel { WebKit::CacheModelPrimaryWebBrowser }; 125 129 int64_t m_diskCacheSizeOverride { -1 }; -
trunk/Source/WebKit2/UIProcess/API/C/WKContext.cpp
r211946 r212619 398 398 } 399 399 400 void WKContextSetUnresponsiveBackgroundProcessesTerminationEnabled(WKContextRef contextRef, bool value) 401 { 402 toImpl(contextRef)->configuration().setUnresponsiveBackgroundProcessesTerminationEnabled(value); 403 } 404 400 405 WKCookieManagerRef WKContextGetCookieManager(WKContextRef contextRef) 401 406 { -
trunk/Source/WebKit2/UIProcess/API/C/WKContextPrivate.h
r203674 r212619 63 63 WK_EXPORT void WKContextSetDiskCacheSpeculativeValidationEnabled(WKContextRef context, bool value); 64 64 65 WK_EXPORT void WKContextSetUnresponsiveBackgroundProcessesTerminationEnabled(WKContextRef context, bool value); 66 65 67 WK_EXPORT void WKContextSetIconDatabasePath(WKContextRef context, WKStringRef iconDatabasePath); 66 68 -
trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp
r212608 r212619 713 713 714 714 m_isValid = true; 715 m_wasKilledForBeingUnresponsiveWhileInBackground = false; 715 716 m_process->removeWebPage(m_pageID); 716 717 m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID); … … 1514 1515 } 1515 1516 1517 void WebPageProxy::reloadAfterBeingKilledInBackground() 1518 { 1519 ASSERT(!isValid()); 1520 1521 RELEASE_LOG_IF_ALLOWED("%p - Reloading tab that was killed in the background", this); 1522 1523 // Only report as a crash if the page was ever visible, otherwise silently reload. 1524 if (m_hasEverBeenVisible) 1525 processDidCrash(); 1526 else 1527 reattachToWebProcessForReload(); 1528 } 1529 1516 1530 void WebPageProxy::dispatchActivityStateChange() 1517 1531 { … … 1520 1534 #endif 1521 1535 1522 if (!isValid()) 1523 return; 1536 if (!isValid()) { 1537 if (m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible && m_wasKilledForBeingUnresponsiveWhileInBackground) 1538 reloadAfterBeingKilledInBackground(); 1539 return; 1540 } 1524 1541 1525 1542 // If the visibility state may have changed, then so may the visually idle & occluded agnostic state. … … 1553 1570 updateThrottleState(); 1554 1571 1555 // If we've started the responsiveness timer as part of telling the web process to update the backing store1556 // state, it might not send back a reply (since it won't paint anything if the web page is hidden) so we1557 // stop the unresponsiveness timer here.1558 if ((changed & ActivityState::IsVisible) && !isViewVisible())1559 m_process->responsivenessTimer().stop();1560 1561 1572 #if ENABLE(POINTER_LOCK) 1562 1573 if (((changed & ActivityState::IsVisible) && !isViewVisible()) || ((changed & ActivityState::WindowIsActive) && !m_pageClient.isViewWindowActive()) … … 1564 1575 requestPointerUnlock(); 1565 1576 #endif 1577 1578 if (changed & ActivityState::IsVisible) { 1579 if (isViewVisible()) { 1580 m_hasEverBeenVisible = true; 1581 m_visiblePageToken = m_process->visiblePageToken(); 1582 } else { 1583 m_visiblePageToken = nullptr; 1584 1585 // If we've started the responsiveness timer as part of telling the web process to update the backing store 1586 // state, it might not send back a reply (since it won't paint anything if the web page is hidden) so we 1587 // stop the unresponsiveness timer here. 1588 m_process->responsivenessTimer().stop(); 1589 } 1590 } 1566 1591 1567 1592 if (changed & ActivityState::IsInWindow) { … … 2370 2395 } 2371 2396 2372 void WebPageProxy::terminateProcess( )2397 void WebPageProxy::terminateProcess(TerminationReason terminationReason) 2373 2398 { 2374 2399 // NOTE: This uses a check of m_isValid rather than calling isValid() since … … 2379 2404 m_process->requestTermination(); 2380 2405 resetStateAfterProcessExited(); 2406 m_wasKilledForBeingUnresponsiveWhileInBackground = terminationReason == TerminationReason::UnresponsiveWhileInBackground; 2381 2407 } 2382 2408 … … 5449 5475 #endif 5450 5476 m_pageIsUserObservableCount = nullptr; 5477 m_visiblePageToken = nullptr; 5451 5478 5452 5479 m_isValid = false; -
trunk/Source/WebKit2/UIProcess/WebPageProxy.h
r212608 r212619 234 234 typedef GenericCallback<API::SerializedScriptValue*, bool, const WebCore::ExceptionDetails&> ScriptValueCallback; 235 235 236 enum VisibleWebPageCounterType { }; 237 using VisibleWebPageCounter = RefCounter<VisibleWebPageCounterType>; 238 using VisibleWebPageToken = VisibleWebPageCounter::Token; 239 236 240 #if PLATFORM(GTK) 237 241 typedef GenericCallback<API::Error*> PrintFinishedCallback; … … 672 676 double estimatedProgress() const; 673 677 674 void terminateProcess(); 678 enum class TerminationReason { UnresponsiveWhileInBackground, Other }; 679 void terminateProcess(TerminationReason = TerminationReason::Other); 675 680 676 681 SessionState sessionState(const std::function<bool (WebBackForwardListItem&)>& = nullptr) const; … … 1571 1576 void viewDidLeaveWindow(); 1572 1577 void viewDidEnterWindow(); 1578 void reloadAfterBeingKilledInBackground(); 1573 1579 1574 1580 #if PLATFORM(MAC) … … 1926 1932 ProcessSuppressionDisabledToken m_preventProcessSuppressionCount; 1927 1933 HiddenPageThrottlingAutoIncreasesCounter::Token m_hiddenPageDOMTimerThrottlingAutoIncreasesCount; 1934 VisibleWebPageToken m_visiblePageToken; 1928 1935 1929 1936 WebCore::ScrollPinningBehavior m_scrollPinningBehavior; … … 1944 1951 bool m_needsHiddenContentEditableQuirk { false }; 1945 1952 bool m_needsPlainTextQuirk { false }; 1953 bool m_hasEverBeenVisible { false }; 1946 1954 1947 1955 #if ENABLE(MEDIA_SESSION) … … 1969 1977 1970 1978 bool m_isUsingHighPerformanceWebGL { false }; 1979 bool m_wasKilledForBeingUnresponsiveWhileInBackground { false }; 1971 1980 1972 1981 WeakPtrFactory<WebPageProxy> m_weakPtrFactory; -
trunk/Source/WebKit2/UIProcess/WebProcessProxy.cpp
r212183 r212619 37 37 #include "TextChecker.h" 38 38 #include "TextCheckerState.h" 39 #include "UnresponsiveWebProcessTerminator.h" 39 40 #include "UserData.h" 40 41 #include "WebBackForwardListItem.h" … … 102 103 , m_throttler(*this) 103 104 , m_isResponsive(NoOrMaybe::Maybe) 105 , m_visiblePageCounter([this](RefCounterEvent) { updateBackgroundResponsivenessTimer(); }) 106 , m_backgroundResponsivenessTimer(processPool.configuration().unresponsiveBackgroundProcessesTerminationEnabled() ? std::make_unique<UnresponsiveWebProcessTerminator>(*this) : nullptr) 104 107 { 105 108 WebPasteboardProxy::singleton().addWebProcessProxy(*this); … … 256 259 globalPageMap().set(pageID, webPage.ptr()); 257 260 261 updateBackgroundResponsivenessTimer(); 262 258 263 return webPage; 259 264 } … … 266 271 m_pageMap.set(pageID, webPage); 267 272 globalPageMap().set(pageID, webPage); 273 274 updateBackgroundResponsivenessTimer(); 268 275 } 269 276 … … 272 279 m_pageMap.remove(pageID); 273 280 globalPageMap().remove(pageID); 281 282 updateBackgroundResponsivenessTimer(); 274 283 275 284 Vector<uint64_t> itemIDsToRemove; … … 707 716 } 708 717 return result; 718 } 719 720 auto WebProcessProxy::visiblePageToken() const -> VisibleWebPageToken 721 { 722 return m_visiblePageCounter.count(); 709 723 } 710 724 … … 1074 1088 } 1075 1089 1090 void WebProcessProxy::updateBackgroundResponsivenessTimer() 1091 { 1092 if (m_backgroundResponsivenessTimer) 1093 m_backgroundResponsivenessTimer->updateState(); 1094 } 1095 1076 1096 #if !PLATFORM(COCOA) 1077 1097 const HashSet<String>& WebProcessProxy::platformPathsWithAssumedReadAccess() -
trunk/Source/WebKit2/UIProcess/WebProcessProxy.h
r212183 r212619 56 56 57 57 class NetworkProcessProxy; 58 class UnresponsiveWebProcessTerminator; 58 59 class WebBackForwardListItem; 59 60 class WebPageGroup; … … 84 85 WTF::IteratorRange<WebPageProxyMap::const_iterator::Values> pages() const { return m_pageMap.values(); } 85 86 unsigned pageCount() const { return m_pageMap.size(); } 87 unsigned visiblePageCount() const { return m_visiblePageCounter.value(); } 86 88 87 89 void addVisitedLinkStore(VisitedLinkStore&); … … 100 102 void disconnectFramesFromPage(WebPageProxy*); // Including main frame. 101 103 size_t frameCountInPage(WebPageProxy*) const; // Including main frame. 104 105 VisibleWebPageToken visiblePageToken() const; 102 106 103 107 void updateTextCheckerState(); … … 190 194 static const HashSet<String>& platformPathsWithAssumedReadAccess(); 191 195 196 void updateBackgroundResponsivenessTimer(); 197 192 198 // IPC::Connection::Client 193 199 friend class WebConnectionToWebProcess; … … 248 254 enum class NoOrMaybe { No, Maybe } m_isResponsive; 249 255 Vector<std::function<void(bool webProcessIsResponsive)>> m_isResponsiveCallbacks; 256 257 VisibleWebPageCounter m_visiblePageCounter; 258 std::unique_ptr<UnresponsiveWebProcessTerminator> m_backgroundResponsivenessTimer; 250 259 }; 251 260 -
trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj
r212557 r212619 900 900 41FAF5F91E3C1025001AE678 /* LibWebRTCResolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41FAF5F71E3C0B47001AE678 /* LibWebRTCResolver.cpp */; }; 901 901 4450AEC01DC3FAE5009943F2 /* SharedMemoryCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4450AEBF1DC3FAE5009943F2 /* SharedMemoryCocoa.cpp */; }; 902 46A2B6081E5676A600C3DEDA /* UnresponsiveWebProcessTerminator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 46A2B6061E5675A200C3DEDA /* UnresponsiveWebProcessTerminator.cpp */; }; 903 46A2B6091E5676A600C3DEDA /* UnresponsiveWebProcessTerminator.h in Headers */ = {isa = PBXBuildFile; fileRef = 46A2B6071E5675A200C3DEDA /* UnresponsiveWebProcessTerminator.h */; }; 902 904 4A3CC18A19B063E700D14AEF /* UserMediaPermissionRequestManagerProxy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4A410F3919AF7B04002EBAB5 /* UserMediaPermissionRequestManagerProxy.cpp */; }; 903 905 4A3CC18B19B0640F00D14AEF /* UserMediaPermissionRequestManagerProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A410F3A19AF7B04002EBAB5 /* UserMediaPermissionRequestManagerProxy.h */; }; … … 3051 3053 41FAF5F71E3C0B47001AE678 /* LibWebRTCResolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibWebRTCResolver.cpp; path = Network/webrtc/LibWebRTCResolver.cpp; sourceTree = "<group>"; }; 3052 3054 4450AEBF1DC3FAE5009943F2 /* SharedMemoryCocoa.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SharedMemoryCocoa.cpp; path = cocoa/SharedMemoryCocoa.cpp; sourceTree = "<group>"; }; 3055 46A2B6061E5675A200C3DEDA /* UnresponsiveWebProcessTerminator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnresponsiveWebProcessTerminator.cpp; sourceTree = "<group>"; }; 3056 46A2B6071E5675A200C3DEDA /* UnresponsiveWebProcessTerminator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnresponsiveWebProcessTerminator.h; sourceTree = "<group>"; }; 3053 3057 4A410F3519AF7AC3002EBAB5 /* WKUserMediaPermissionRequest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKUserMediaPermissionRequest.cpp; sourceTree = "<group>"; }; 3054 3058 4A410F3619AF7AC3002EBAB5 /* WKUserMediaPermissionRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKUserMediaPermissionRequest.h; sourceTree = "<group>"; }; … … 6458 6462 1BB417C912C00CCA002BE67B /* TextCheckerCompletion.cpp */, 6459 6463 1CC417C912C00CCA002BE67B /* TextCheckerCompletion.h */, 6464 46A2B6061E5675A200C3DEDA /* UnresponsiveWebProcessTerminator.cpp */, 6465 46A2B6071E5675A200C3DEDA /* UnresponsiveWebProcessTerminator.h */, 6460 6466 07297F9C1C17BBEA003F0735 /* UserMediaPermissionCheckProxy.cpp */, 6461 6467 07297F9D1C17BBEA003F0735 /* UserMediaPermissionCheckProxy.h */, … … 7965 7971 1A5705111BE410E600874AF1 /* BlockSPI.h in Headers */, 7966 7972 BC3065FA1259344E00E71278 /* CacheModel.h in Headers */, 7973 46A2B6091E5676A600C3DEDA /* UnresponsiveWebProcessTerminator.h in Headers */, 7967 7974 1AA2E51D12E4C05E00BC4966 /* CGUtilities.h in Headers */, 7968 7975 1A2D956F12848564001EB962 /* ChildProcess.h in Headers */, … … 9646 9653 5C20CB9D1BB0DCFA00895BB1 /* NetworkSessionCocoa.mm in Sources */, 9647 9654 31A2EC551489982E00810D71 /* NotificationPermissionRequest.cpp in Sources */, 9655 46A2B6081E5676A600C3DEDA /* UnresponsiveWebProcessTerminator.cpp in Sources */, 9648 9656 3131261E148FF82C00BA2A39 /* NotificationPermissionRequestManager.cpp in Sources */, 9649 9657 31A2EC501489980500810D71 /* NotificationPermissionRequestManagerProxy.cpp in Sources */,
Note:
See TracChangeset
for help on using the changeset viewer.