WebKit Bugzilla
Attachment 371194 Details for
Bug 198488
: [iOS] Do not prevent app suspension for more than 20 seconds after getting backgrounded
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-198488-20190603103927.patch (text/plain), 8.47 KB, created by
Chris Dumez
on 2019-06-03 10:39:30 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Chris Dumez
Created:
2019-06-03 10:39:30 PDT
Size:
8.47 KB
patch
obsolete
>Subversion Revision: 246036 >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index 3638a0682ed018fabaabb5c75b40302d57e2d0e6..71608b231e0c2065428ca716c14d7a664a5945c3 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,24 @@ >+2019-06-03 Chris Dumez <cdumez@apple.com> >+ >+ [iOS] Do not prevent app suspension for more than 20 seconds after getting backgrounded >+ https://bugs.webkit.org/show_bug.cgi?id=198488 >+ <rdar://problem/50837208> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Do not prevent app suspension for more than 20 seconds after getting backgrounded on iOS. We >+ do this by implementing our own expiration handler which notifies our child processes of >+ their imminent suspension before ending the background task that was preventing suspension. >+ >+ * UIProcess/ios/ProcessAssertionIOS.mm: >+ (isBackgroundState): >+ (-[WKProcessAssertionBackgroundTaskManager init]): >+ (-[WKProcessAssertionBackgroundTaskManager _scheduleTimeoutTask]): >+ (-[WKProcessAssertionBackgroundTaskManager _cancelTimeoutTask]): >+ (-[WKProcessAssertionBackgroundTaskManager _backgroundTaskExpired]): >+ (-[WKProcessAssertionBackgroundTaskManager _updateBackgroundTask]): >+ (-[WKProcessAssertionBackgroundTaskManager _releaseBackgroundTask]): >+ > 2019-06-03 Darin Adler <darin@apple.com> > > Finish cleanup of String::number for floating point >diff --git a/Source/WebKit/UIProcess/ios/ProcessAssertionIOS.mm b/Source/WebKit/UIProcess/ios/ProcessAssertionIOS.mm >index 2aca868bb8b5713159c91d2abe5feca9461cc72f..3e0de9fb3dfca8061802fd6d3dc9e4454eda3c57 100644 >--- a/Source/WebKit/UIProcess/ios/ProcessAssertionIOS.mm >+++ b/Source/WebKit/UIProcess/ios/ProcessAssertionIOS.mm >@@ -41,6 +41,7 @@ using WebKit::ProcessAndUIAssertion; > // the background task before the UIKit timeout (We get killed if we do not release the background task within 5 seconds > // on the expiration handler getting called). > static const Seconds releaseBackgroundTaskAfterExpirationDelay { 2_s }; >+static const Seconds maximumBackgroundTaskDuration { 20_s }; > > @interface WKProcessAssertionBackgroundTaskManager : NSObject > >@@ -57,6 +58,7 @@ @implementation WKProcessAssertionBackgroundTaskManager > HashSet<ProcessAndUIAssertion*> _assertionsNeedingBackgroundTask; > BOOL _applicationIsBackgrounded; > dispatch_block_t _pendingTaskReleaseTask; >+ dispatch_block_t _pendingTimeoutTask; > } > > + (WKProcessAssertionBackgroundTaskManager *)shared >@@ -65,6 +67,11 @@ + (WKProcessAssertionBackgroundTaskManager *)shared > return shared; > } > >+static bool isBackgroundState(BKSApplicationState state) >+{ >+ return state == BKSApplicationStateBackgroundRunning || state == BKSApplicationStateBackgroundTaskSuspended; >+} >+ > - (instancetype)init > { > self = [super init]; >@@ -73,14 +80,27 @@ - (instancetype)init > > _backgroundTask = UIBackgroundTaskInvalid; > >- [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillEnterForegroundNotification object:[UIApplication sharedApplication] queue:nil usingBlock:^(NSNotification *) { >+ auto applicationStateMonitor = adoptNS([[BKSApplicationStateMonitor alloc] init]); >+ _applicationIsBackgrounded = isBackgroundState([applicationStateMonitor mostElevatedApplicationStateForPID:getpid()]); >+ >+ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; >+ UIApplication *application = [UIApplication sharedApplication]; >+ >+ [notificationCenter addObserverForName:UIApplicationWillEnterForegroundNotification object:application queue:nil usingBlock:^(NSNotification *) { >+ RELEASE_LOG(ProcessSuspension, "%p - WKProcessAssertionBackgroundTaskManager: Application will enter foreground", self); > _applicationIsBackgrounded = NO; > [self _cancelPendingReleaseTask]; >+ [self _cancelTimeoutTask]; > [self _updateBackgroundTask]; > }]; > >- [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:[UIApplication sharedApplication] queue:nil usingBlock:^(NSNotification *) { >+ [notificationCenter addObserverForName:UIApplicationDidEnterBackgroundNotification object:application queue:nil usingBlock:^(NSNotification *) { >+ RELEASE_LOG(ProcessSuspension, "%p - WKProcessAssertionBackgroundTaskManager: Application did enter background", self); > _applicationIsBackgrounded = YES; >+ >+ // We do not want to keep the app awake for more than 20 seconds after it gets backgrounded, so start the timeout timer now. >+ if (_backgroundTask != UIBackgroundTaskInvalid) >+ [self _scheduleTimeoutTask]; > }]; > > return self; >@@ -112,6 +132,36 @@ - (void)_notifyAssertionsOfImminentSuspension > assertion->uiAssertionWillExpireImminently(); > } > >+- (void)_scheduleTimeoutTask >+{ >+ ASSERT(_backgroundTask != UIBackgroundTaskInvalid); >+ >+ if (_pendingTimeoutTask) >+ return; >+ >+ RELEASE_LOG(ProcessSuspension, "%p - WKProcessAssertionBackgroundTaskManager - _scheduleTimeoutTask", self); >+ _pendingTimeoutTask = dispatch_block_create((dispatch_block_flags_t)0, ^{ >+ _pendingTimeoutTask = nil; >+ RELEASE_LOG_ERROR(ProcessSuspension, "Background task was running for too long so WebKit will end it shortly."); >+ [self _backgroundTaskExpired]; >+ }); >+ >+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, maximumBackgroundTaskDuration.value() * NSEC_PER_SEC), dispatch_get_main_queue(), _pendingTimeoutTask); >+#if !__has_feature(objc_arc) >+ // dispatch_async() does a Block_copy() / Block_release() on behalf of the caller. >+ Block_release(_pendingTimeoutTask); >+#endif >+} >+ >+- (void)_cancelTimeoutTask >+{ >+ if (!_pendingTimeoutTask) >+ return; >+ >+ RELEASE_LOG(ProcessSuspension, "%p - WKProcessAssertionBackgroundTaskManager - _cancelTimeoutTask", self); >+ dispatch_block_cancel(_pendingTimeoutTask); >+ _pendingTimeoutTask = nil; >+} > > - (void)_scheduleReleaseTask > { >@@ -141,6 +191,24 @@ - (void)_cancelPendingReleaseTask > _pendingTaskReleaseTask = nil; > } > >+- (void)_backgroundTaskExpired >+{ >+ RELEASE_LOG_ERROR(ProcessSuspension, "%p - WKProcessAssertionBackgroundTaskManager - _backgroundTaskExpired", self); >+ [self _cancelTimeoutTask]; >+ >+ // Tell our child processes they will suspend imminently. >+ if (RunLoop::isMain()) >+ [self _notifyAssertionsOfImminentSuspension]; >+ else { >+ // The expiration handler gets called on a non-main thread when the underlying assertion could not be taken (rdar://problem/27278419). >+ dispatch_sync(dispatch_get_main_queue(), ^{ >+ [self _notifyAssertionsOfImminentSuspension]; >+ }); >+ } >+ >+ [self _scheduleReleaseTask]; >+} >+ > - (void)_updateBackgroundTask > { > if (!_assertionsNeedingBackgroundTask.isEmpty() && _backgroundTask == UIBackgroundTaskInvalid) { >@@ -150,17 +218,8 @@ - (void)_updateBackgroundTask > } > 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()); >- // The expiration handler gets called on a non-main thread when the underlying assertion could not be taken (rdar://problem/27278419). >- if (RunLoop::isMain()) >- [self _notifyAssertionsOfImminentSuspension]; >- else { >- dispatch_sync(dispatch_get_main_queue(), ^{ >- [self _notifyAssertionsOfImminentSuspension]; >- }); >- } >- >- [self _scheduleReleaseTask]; >+ RELEASE_LOG_ERROR(ProcessSuspension, "Background task expired while holding WebKit ProcessAssertion (isMainThread? %d, _applicationIsBackgrounded? %d).", RunLoop::isMain(), _applicationIsBackgrounded); >+ [self _backgroundTaskExpired]; > }]; > } else if (_assertionsNeedingBackgroundTask.isEmpty()) > [self _releaseBackgroundTask]; >@@ -173,6 +232,8 @@ - (void)_releaseBackgroundTask > > RELEASE_LOG(ProcessSuspension, "%p - WKProcessAssertionBackgroundTaskManager - endBackgroundTask", self); > [[UIApplication sharedApplication] endBackgroundTask:_backgroundTask]; >+ [self _cancelPendingReleaseTask]; >+ [self _cancelTimeoutTask]; > _backgroundTask = UIBackgroundTaskInvalid; > } >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 198488
:
371194
|
371201
|
371227
|
371230