Title: [244761] trunk/Source/WebKit
Revision
244761
Author
[email protected]
Date
2019-04-29 15:40:48 -0700 (Mon, 29 Apr 2019)

Log Message

[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]):

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (244760 => 244761)


--- trunk/Source/WebKit/ChangeLog	2019-04-29 22:25:03 UTC (rev 244760)
+++ trunk/Source/WebKit/ChangeLog	2019-04-29 22:40:48 UTC (rev 244761)
@@ -1,3 +1,25 @@
+2019-04-29  Chris Dumez  <[email protected]>
+
+        [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  <[email protected]>
 
         <rdar://problem/50299396> Fix internal High Sierra build

Modified: trunk/Source/WebKit/UIProcess/ios/ProcessAssertionIOS.mm (244760 => 244761)


--- trunk/Source/WebKit/UIProcess/ios/ProcessAssertionIOS.mm	2019-04-29 22:25:03 UTC (rev 244760)
+++ trunk/Source/WebKit/UIProcess/ios/ProcessAssertionIOS.mm	2019-04-29 22:40:48 UTC (rev 244761)
@@ -50,6 +50,7 @@
 {
     UIBackgroundTaskIdentifier _backgroundTask;
     HashSet<ProcessAndUIAssertion*> _assertionsNeedingBackgroundTask;
+    BOOL _assertionHasExpiredInTheBackground;
 }
 
 + (WKProcessAssertionBackgroundTaskManager *)shared
@@ -66,6 +67,11 @@
 
     _backgroundTask = UIBackgroundTaskInvalid;
 
+    [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillEnterForegroundNotification object:[UIApplication sharedApplication] queue:nil usingBlock:^(NSNotification *) {
+        _assertionHasExpiredInTheBackground = NO;
+        [self _updateBackgroundTask];
+    }];
+
     return self;
 }
 
@@ -98,6 +104,11 @@
 - (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 @@
                     [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())
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to