Skip to content
Permalink
Browse files
[iOS] The UIProcess may get killed for trying to stay runnable in the…
… background for more than 30 seconds

https://bugs.webkit.org/show_bug.cgi?id=197385
<rdar://problem/50001505>

Reviewed by Geoffrey Garen.

If the UIProcess holds a background assertion for itself for 30 seconds, the assertion's invalidation handler
will get called and it is our responsibility to release this assertion or the UIProcess will get killed by the
system. The logic in ProcessAssertion would normally do that but it would also happily try and re-take another
background process assertion shortly after the previous one expired (and before the UIProcess got suspended).
When doing so, the new background assertion would expire right away and we would get killed without its
invalidation handler getting called.

To address the issue, the logic in ProcessAssertion will now prevent taking a new background assertion after
one expires and until the application becomes foreground again.

* UIProcess/ios/ProcessAssertionIOS.mm:
(-[WKProcessAssertionBackgroundTaskManager init]):
(-[WKProcessAssertionBackgroundTaskManager _updateBackgroundTask]):


Canonical link: https://commits.webkit.org/211586@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@244761 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
cdumez committed Apr 29, 2019
1 parent 213bb42 commit c6c96b174fd3e325fca065a16770bf933edaa254
Showing 2 changed files with 36 additions and 0 deletions.
@@ -1,3 +1,25 @@
2019-04-29 Chris Dumez <cdumez@apple.com>

[iOS] The UIProcess may get killed for trying to stay runnable in the background for more than 30 seconds
https://bugs.webkit.org/show_bug.cgi?id=197385
<rdar://problem/50001505>

Reviewed by Geoffrey Garen.

If the UIProcess holds a background assertion for itself for 30 seconds, the assertion's invalidation handler
will get called and it is our responsibility to release this assertion or the UIProcess will get killed by the
system. The logic in ProcessAssertion would normally do that but it would also happily try and re-take another
background process assertion shortly after the previous one expired (and before the UIProcess got suspended).
When doing so, the new background assertion would expire right away and we would get killed without its
invalidation handler getting called.

To address the issue, the logic in ProcessAssertion will now prevent taking a new background assertion after
one expires and until the application becomes foreground again.

* UIProcess/ios/ProcessAssertionIOS.mm:
(-[WKProcessAssertionBackgroundTaskManager init]):
(-[WKProcessAssertionBackgroundTaskManager _updateBackgroundTask]):

2019-04-29 Alex Christensen <achristensen@webkit.org>

<rdar://problem/50299396> Fix internal High Sierra build
@@ -50,6 +50,7 @@ @implementation WKProcessAssertionBackgroundTaskManager
{
UIBackgroundTaskIdentifier _backgroundTask;
HashSet<ProcessAndUIAssertion*> _assertionsNeedingBackgroundTask;
BOOL _assertionHasExpiredInTheBackground;
}

+ (WKProcessAssertionBackgroundTaskManager *)shared
@@ -66,6 +67,11 @@ - (instancetype)init

_backgroundTask = UIBackgroundTaskInvalid;

[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillEnterForegroundNotification object:[UIApplication sharedApplication] queue:nil usingBlock:^(NSNotification *) {
_assertionHasExpiredInTheBackground = NO;
[self _updateBackgroundTask];
}];

return self;
}

@@ -98,6 +104,11 @@ - (void)_notifyAssertionsOfImminentSuspension
- (void)_updateBackgroundTask
{
if (!_assertionsNeedingBackgroundTask.isEmpty() && _backgroundTask == UIBackgroundTaskInvalid) {
if (_assertionHasExpiredInTheBackground) {
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);
// 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).
return;
}
RELEASE_LOG(ProcessSuspension, "%p - WKProcessAssertionBackgroundTaskManager - beginBackgroundTaskWithName", self);
_backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"com.apple.WebKit.ProcessAssertion" expirationHandler:^{
RELEASE_LOG_ERROR(ProcessSuspension, "Background task expired while holding WebKit ProcessAssertion (isMainThread? %d).", RunLoop::isMain());
@@ -109,6 +120,9 @@ - (void)_updateBackgroundTask
[self _notifyAssertionsOfImminentSuspension];
});
}

// Remember that the assertion has expired in the background so we do not try to re-take it until the application becomes foreground again.
_assertionHasExpiredInTheBackground = YES;
[self _releaseBackgroundTask];
}];
} else if (_assertionsNeedingBackgroundTask.isEmpty())

0 comments on commit c6c96b1

Please sign in to comment.