Changeset 245334 in webkit
- Timestamp:
- May 15, 2019 11:29:40 AM (5 years ago)
- Location:
- trunk/Source/WebKit
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebKit/ChangeLog
r245329 r245334 1 2019-05-15 Chris Dumez <cdumez@apple.com> 2 3 [WK2][iOS] UIProcess may get killed because it is taking too long to release its background task after expiration 4 https://bugs.webkit.org/show_bug.cgi?id=197893 5 <rdar://problem/50234105> 6 7 Reviewed by Alex Christensen. 8 9 The UIProcess may get killed because it is taking too long to release its background task after its expiration handler 10 was called. The reason is that the background task's expiration handler was sequentially sending a ProcessWillSuspendImminently 11 synchronous IPC to each of its child processes and only then ends the background task. By the time we receive the response from 12 all child processes, it may be too late and we get killed. 13 14 To address the issue, we now: 15 1. Send the ProcessWillSuspendImminently asynchronously so that all processes can do their processing in parallel 16 2. After 2 seconds, the UIProcess releases the background task (We get killed after ~5 seconds) 17 18 Also, to make sure that the UIProcess supends promptly, we now make sure we never start a new background task *after* 19 the app has been backgrounded. The intention of our background task is too finish critical work (like releasing locked 20 files) after the app gets backgrounded, not to start new work and delay process suspension. 21 22 * NetworkProcess/NetworkProcess.cpp: 23 (WebKit::NetworkProcess::processWillSuspendImminently): 24 * NetworkProcess/NetworkProcess.h: 25 * NetworkProcess/NetworkProcess.messages.in: 26 * UIProcess/Network/NetworkProcessProxy.cpp: 27 (WebKit::NetworkProcessProxy::sendProcessWillSuspendImminently): 28 * UIProcess/WebProcessProxy.cpp: 29 (WebKit::WebProcessProxy::sendProcessWillSuspendImminently): 30 * UIProcess/ios/ProcessAssertionIOS.mm: 31 (-[WKProcessAssertionBackgroundTaskManager init]): 32 (-[WKProcessAssertionBackgroundTaskManager _scheduleReleaseTask]): 33 (-[WKProcessAssertionBackgroundTaskManager _cancelPendingReleaseTask]): 34 (-[WKProcessAssertionBackgroundTaskManager _updateBackgroundTask]): 35 * WebProcess/WebProcess.cpp: 36 (WebKit::WebProcess::didReceiveSyncMessage): 37 (WebKit::WebProcess::processWillSuspendImminently): 38 * WebProcess/WebProcess.h: 39 * WebProcess/WebProcess.messages.in: 40 1 41 2019-05-15 Jiewen Tan <jiewen_tan@apple.com> 2 42 -
trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp
r245297 r245334 1950 1950 } 1951 1951 1952 void NetworkProcess::processWillSuspendImminently( CompletionHandler<void(bool)>&& completionHandler)1953 { 1954 RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::processWillSuspendImminently() ", this);1952 void NetworkProcess::processWillSuspendImminently() 1953 { 1954 RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::processWillSuspendImminently() BEGIN", this); 1955 1955 #if PLATFORM(IOS_FAMILY) && ENABLE(INDEXED_DATABASE) 1956 1956 for (auto& server : m_idbServers.values()) … … 1958 1958 #endif 1959 1959 actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend::No); 1960 completionHandler(true);1960 RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::processWillSuspendImminently() END", this); 1961 1961 } 1962 1962 -
trunk/Source/WebKit/NetworkProcess/NetworkProcess.h
r245149 r245334 182 182 bool canHandleHTTPSServerTrustEvaluation() const { return m_canHandleHTTPSServerTrustEvaluation; } 183 183 184 void processWillSuspendImminently( CompletionHandler<void(bool)>&&);184 void processWillSuspendImminently(); 185 185 void prepareToSuspend(); 186 186 void cancelPrepareToSuspend(); -
trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in
r245149 r245334 78 78 ProcessDidTransitionToForeground() 79 79 80 ProcessWillSuspendImminently() -> (bool handled) Synchronous80 ProcessWillSuspendImminently() 81 81 PrepareToSuspend() 82 82 CancelPrepareToSuspend() -
trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp
r245328 r245334 958 958 void NetworkProcessProxy::sendProcessWillSuspendImminently() 959 959 { 960 if (!canSendMessage()) 961 return; 962 963 bool handled = false; 964 sendSync(Messages::NetworkProcess::ProcessWillSuspendImminently(), Messages::NetworkProcess::ProcessWillSuspendImminently::Reply(handled), 0, 1_s); 960 if (canSendMessage()) 961 send(Messages::NetworkProcess::ProcessWillSuspendImminently(), 0); 965 962 } 966 963 -
trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp
r245328 r245334 1147 1147 void WebProcessProxy::sendProcessWillSuspendImminently() 1148 1148 { 1149 if (!canSendMessage()) 1150 return; 1151 1152 bool handled = false; 1153 sendSync(Messages::WebProcess::ProcessWillSuspendImminently(), Messages::WebProcess::ProcessWillSuspendImminently::Reply(handled), 0, 1_s); 1149 if (canSendMessage()) 1150 send(Messages::WebProcess::ProcessWillSuspendImminently(), 0); 1154 1151 } 1155 1152 -
trunk/Source/WebKit/UIProcess/ios/ProcessAssertionIOS.mm
r245255 r245334 38 38 using WebKit::ProcessAndUIAssertion; 39 39 40 // This gives some time to our child processes to process the ProcessWillSuspendImminently IPC but makes sure we release 41 // the background task before the UIKit timeout (We get killed if we do not release the background task within 5 seconds 42 // on the expiration handler getting called). 43 static const Seconds releaseBackgroundTaskAfterExpirationDelay { 2_s }; 44 40 45 @interface WKProcessAssertionBackgroundTaskManager : NSObject 41 46 … … 51 56 UIBackgroundTaskIdentifier _backgroundTask; 52 57 HashSet<ProcessAndUIAssertion*> _assertionsNeedingBackgroundTask; 53 BOOL _assertionHasExpiredInTheBackground; 58 BOOL _applicationIsBackgrounded; 59 dispatch_block_t _pendingTaskReleaseTask; 54 60 } 55 61 … … 69 75 70 76 [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillEnterForegroundNotification object:[UIApplication sharedApplication] queue:nil usingBlock:^(NSNotification *) { 71 _assertionHasExpiredInTheBackground = NO; 77 _applicationIsBackgrounded = NO; 78 [self _cancelPendingReleaseTask]; 72 79 [self _updateBackgroundTask]; 73 80 }]; 74 81 82 [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:[UIApplication sharedApplication] queue:nil usingBlock:^(NSNotification *) { 83 _applicationIsBackgrounded = YES; 84 }]; 85 75 86 return self; 76 87 } … … 102 113 } 103 114 115 116 - (void)_scheduleReleaseTask 117 { 118 ASSERT(!_pendingTaskReleaseTask); 119 if (_pendingTaskReleaseTask) 120 return; 121 122 RELEASE_LOG(ProcessSuspension, "%p - WKProcessAssertionBackgroundTaskManager - _scheduleReleaseTask because the expiration handler has been called", self); 123 _pendingTaskReleaseTask = dispatch_block_create((dispatch_block_flags_t)0, ^{ 124 _pendingTaskReleaseTask = nil; 125 [self _releaseBackgroundTask]; 126 }); 127 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, releaseBackgroundTaskAfterExpirationDelay.value() * NSEC_PER_SEC), dispatch_get_main_queue(), _pendingTaskReleaseTask); 128 #if !__has_feature(objc_arc) 129 // dispatch_async() does a Block_copy() / Block_release() on behalf of the caller. 130 Block_release(_pendingTaskReleaseTask); 131 #endif 132 } 133 134 - (void)_cancelPendingReleaseTask 135 { 136 if (!_pendingTaskReleaseTask) 137 return; 138 139 RELEASE_LOG(ProcessSuspension, "%p - WKProcessAssertionBackgroundTaskManager - _cancelPendingReleaseTask because the application is foreground again", self); 140 dispatch_block_cancel(_pendingTaskReleaseTask); 141 _pendingTaskReleaseTask = nil; 142 } 143 104 144 - (void)_updateBackgroundTask 105 145 { 106 146 if (!_assertionsNeedingBackgroundTask.isEmpty() && _backgroundTask == UIBackgroundTaskInvalid) { 107 if (_assertionHasExpiredInTheBackground) { 108 RELEASE_LOG_ERROR(ProcessSuspension, "%p - WKProcessAssertionBackgroundTaskManager: Ignored request to start a background task because we're still in the background and the previous task expired", self); 109 // Our invalidation handler would not get called if we tried to re-take a new background assertion at this point, and the UIProcess would get killed (rdar://problem/50001505). 147 if (_applicationIsBackgrounded) { 148 RELEASE_LOG_ERROR(ProcessSuspension, "%p - WKProcessAssertionBackgroundTaskManager: Ignored request to start a new background task because the application is already in the background", self); 110 149 return; 111 150 } … … 122 161 } 123 162 124 // Remember that the assertion has expired in the background so we do not try to re-take it until the application becomes foreground again. 125 _assertionHasExpiredInTheBackground = YES; 126 [self _releaseBackgroundTask]; 163 [self _scheduleReleaseTask]; 127 164 }]; 128 165 } else if (_assertionsNeedingBackgroundTask.isEmpty()) -
trunk/Source/WebKit/WebProcess/WebProcess.cpp
r245299 r245334 733 733 if (messageReceiverMap().dispatchSyncMessage(connection, decoder, replyEncoder)) 734 734 return; 735 736 didReceiveSyncWebProcessMessage(connection, decoder, replyEncoder);737 735 } 738 736 … … 1491 1489 } 1492 1490 1493 void WebProcess::processWillSuspendImminently(CompletionHandler<void(bool)>&& completionHandler) 1494 { 1495 if (parentProcessConnection()->inSendSync()) { 1496 // Avoid reentrency bugs such as rdar://problem/21605505 by just bailing 1497 // if we get an incoming ProcessWillSuspendImminently message when waiting for a 1498 // reply to a sync message. 1499 // FIXME: ProcessWillSuspendImminently should not be a sync message. 1500 return completionHandler(false); 1501 } 1502 1503 RELEASE_LOG(ProcessSuspension, "%p - WebProcess::processWillSuspendImminently()", this); 1491 void WebProcess::processWillSuspendImminently() 1492 { 1493 RELEASE_LOG(ProcessSuspension, "%p - WebProcess::processWillSuspendImminently() BEGIN", this); 1504 1494 actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend::No); 1505 completionHandler(true);1495 RELEASE_LOG(ProcessSuspension, "%p - WebProcess::processWillSuspendImminently() END", this); 1506 1496 } 1507 1497 -
trunk/Source/WebKit/WebProcess/WebProcess.h
r245299 r245334 217 217 void setHiddenPageDOMTimerThrottlingIncreaseLimit(int milliseconds); 218 218 219 void processWillSuspendImminently( CompletionHandler<void(bool)>&&);219 void processWillSuspendImminently(); 220 220 void prepareToSuspend(); 221 221 void cancelPrepareToSuspend(); … … 421 421 // Implemented in generated WebProcessMessageReceiver.cpp 422 422 void didReceiveWebProcessMessage(IPC::Connection&, IPC::Decoder&); 423 void didReceiveSyncWebProcessMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&);424 423 425 424 #if PLATFORM(MAC) -
trunk/Source/WebKit/WebProcess/WebProcess.messages.in
r245151 r245334 97 97 DestroyAutomationSessionProxy() 98 98 99 ProcessWillSuspendImminently() -> (bool handled) Synchronous99 ProcessWillSuspendImminently() 100 100 PrepareToSuspend() 101 101 CancelPrepareToSuspend()
Note: See TracChangeset
for help on using the changeset viewer.