- Revision
- 202696
- Author
- cdu...@apple.com
- Date
- 2016-06-30 13:17:30 -0700 (Thu, 30 Jun 2016)
Log Message
[iOS] Process suspension is prevented for 30 seconds after closing a tab
https://bugs.webkit.org/show_bug.cgi?id=159280
<rdar://problem/27014867>
Reviewed by Gavin Barraclough.
When closing a tab, ConnectionTerminationWatchdog takes a background
assertion on behalf of the WebContent process and only releases it
after 30 seconds, allowing for the WebContent process to exit cleanly
without worrying about getting suspended too early.
However, the child process normally exits much sooner than this and
we end up holding a process assertion for no reason for a full 30
seconds anyway. This patch addresses the issue by registering an
invalidation handler with the BKSProcessAssertion and releasing our
our assertion in such case. The invalidation handler gets called
as soon as the child process exits.
* Platform/spi/ios/AssertionServicesSPI.h:
* UIProcess/ProcessAssertion.cpp:
(WebKit::ProcessAssertion::ProcessAssertion):
* UIProcess/ProcessAssertion.h:
(WebKit::ProcessAssertion::ProcessAssertion):
(WebKit::ProcessAssertion::validity):
* UIProcess/ios/ProcessAssertionIOS.mm:
(WebKit::ProcessAssertion::ProcessAssertion):
(WebKit::ProcessAssertion::~ProcessAssertion):
(WebKit::ProcessAndUIAssertion::updateRunInBackgroundCount):
(WebKit::ProcessAndUIAssertion::ProcessAndUIAssertion):
(WebKit::ProcessAssertion::setState): Deleted.
Modified Paths
Diff
Modified: trunk/Source/WebKit2/ChangeLog (202695 => 202696)
--- trunk/Source/WebKit2/ChangeLog 2016-06-30 19:15:15 UTC (rev 202695)
+++ trunk/Source/WebKit2/ChangeLog 2016-06-30 20:17:30 UTC (rev 202696)
@@ -1,3 +1,36 @@
+2016-06-30 Chris Dumez <cdu...@apple.com>
+
+ [iOS] Process suspension is prevented for 30 seconds after closing a tab
+ https://bugs.webkit.org/show_bug.cgi?id=159280
+ <rdar://problem/27014867>
+
+ Reviewed by Gavin Barraclough.
+
+ When closing a tab, ConnectionTerminationWatchdog takes a background
+ assertion on behalf of the WebContent process and only releases it
+ after 30 seconds, allowing for the WebContent process to exit cleanly
+ without worrying about getting suspended too early.
+
+ However, the child process normally exits much sooner than this and
+ we end up holding a process assertion for no reason for a full 30
+ seconds anyway. This patch addresses the issue by registering an
+ invalidation handler with the BKSProcessAssertion and releasing our
+ our assertion in such case. The invalidation handler gets called
+ as soon as the child process exits.
+
+ * Platform/spi/ios/AssertionServicesSPI.h:
+ * UIProcess/ProcessAssertion.cpp:
+ (WebKit::ProcessAssertion::ProcessAssertion):
+ * UIProcess/ProcessAssertion.h:
+ (WebKit::ProcessAssertion::ProcessAssertion):
+ (WebKit::ProcessAssertion::validity):
+ * UIProcess/ios/ProcessAssertionIOS.mm:
+ (WebKit::ProcessAssertion::ProcessAssertion):
+ (WebKit::ProcessAssertion::~ProcessAssertion):
+ (WebKit::ProcessAndUIAssertion::updateRunInBackgroundCount):
+ (WebKit::ProcessAndUIAssertion::ProcessAndUIAssertion):
+ (WebKit::ProcessAssertion::setState): Deleted.
+
2016-06-30 Tim Horton <timothy_hor...@apple.com>
Keep track of when a WKWebView is blank before the initial non-empty layout
Modified: trunk/Source/WebKit2/Platform/spi/ios/AssertionServicesSPI.h (202695 => 202696)
--- trunk/Source/WebKit2/Platform/spi/ios/AssertionServicesSPI.h 2016-06-30 19:15:15 UTC (rev 202695)
+++ trunk/Source/WebKit2/Platform/spi/ios/AssertionServicesSPI.h 2016-06-30 20:17:30 UTC (rev 202696)
@@ -72,6 +72,7 @@
};
typedef uint32_t BKSProcessAssertionReason;
+typedef void (^BKSProcessAssertionInvalidationHandler)(void);
typedef void (^BKSProcessAssertionAcquisitionHandler)(BOOL acquired);
@interface BKSProcessAssertion : NSObject
@@ -80,6 +81,8 @@
@interface BKSProcessAssertion ()
@property (nonatomic, assign) BKSProcessAssertionFlags flags;
- (id)initWithPID:(pid_t)pid flags:(BKSProcessAssertionFlags)flags reason:(BKSProcessAssertionReason)reason name:(NSString *)name withHandler:(BKSProcessAssertionAcquisitionHandler)handler;
+
+@property (nonatomic, copy) BKSProcessAssertionInvalidationHandler invalidationHandler;
- (void)invalidate;
@end
Modified: trunk/Source/WebKit2/UIProcess/ProcessAssertion.cpp (202695 => 202696)
--- trunk/Source/WebKit2/UIProcess/ProcessAssertion.cpp 2016-06-30 19:15:15 UTC (rev 202695)
+++ trunk/Source/WebKit2/UIProcess/ProcessAssertion.cpp 2016-06-30 20:17:30 UTC (rev 202696)
@@ -30,7 +30,7 @@
namespace WebKit {
-ProcessAssertion::ProcessAssertion(pid_t, AssertionState assertionState)
+ProcessAssertion::ProcessAssertion(pid_t, AssertionState assertionState, std::function<void()>)
: m_assertionState(assertionState)
{
}
Modified: trunk/Source/WebKit2/UIProcess/ProcessAssertion.h (202695 => 202696)
--- trunk/Source/WebKit2/UIProcess/ProcessAssertion.h 2016-06-30 19:15:15 UTC (rev 202695)
+++ trunk/Source/WebKit2/UIProcess/ProcessAssertion.h 2016-06-30 20:17:30 UTC (rev 202696)
@@ -26,6 +26,8 @@
#ifndef ProcessAssertion_h
#define ProcessAssertion_h
+#include <functional>
+
#if PLATFORM(IOS) && !PLATFORM(IOS_SIMULATOR)
#include <wtf/RetainPtr.h>
OBJC_CLASS BKSProcessAssertion;
@@ -47,7 +49,7 @@
class ProcessAssertion {
public:
- ProcessAssertion(pid_t, AssertionState);
+ ProcessAssertion(pid_t, AssertionState, std::function<void()> invalidationCallback = { });
~ProcessAssertion();
void setClient(ProcessAssertionClient& client) { m_client = &client; }
@@ -56,9 +58,16 @@
AssertionState state() const { return m_assertionState; }
void setState(AssertionState);
+#if PLATFORM(IOS) && !PLATFORM(IOS_SIMULATOR)
+protected:
+ enum class Validity { No, Yes, Unset };
+ Validity validity() const { return m_validity; }
+#endif
+
private:
#if PLATFORM(IOS) && !PLATFORM(IOS_SIMULATOR)
RetainPtr<BKSProcessAssertion> m_assertion;
+ Validity m_validity { Validity::Unset };
#endif
AssertionState m_assertionState;
ProcessAssertionClient* m_client { nullptr };
Modified: trunk/Source/WebKit2/UIProcess/ios/ProcessAssertionIOS.mm (202695 => 202696)
--- trunk/Source/WebKit2/UIProcess/ios/ProcessAssertionIOS.mm 2016-06-30 19:15:15 UTC (rev 202695)
+++ trunk/Source/WebKit2/UIProcess/ios/ProcessAssertionIOS.mm 2016-06-30 20:17:30 UTC (rev 202696)
@@ -143,21 +143,28 @@
}
}
-ProcessAssertion::ProcessAssertion(pid_t pid, AssertionState assertionState)
+ProcessAssertion::ProcessAssertion(pid_t pid, AssertionState assertionState, std::function<void()> invalidationCallback)
+ : m_assertionState(assertionState)
{
- m_assertionState = assertionState;
-
BKSProcessAssertionAcquisitionHandler handler = ^(BOOL acquired) {
if (!acquired) {
- LOG_ERROR("Unable to acquire assertion for process %d", pid);
+ LOG_ALWAYS_ERROR(true, "Unable to acquire assertion for process %d", pid);
ASSERT_NOT_REACHED();
+ m_validity = Validity::No;
+ invalidationCallback();
}
};
m_assertion = adoptNS([[BKSProcessAssertion alloc] initWithPID:pid flags:flagsForState(assertionState) reason:BKSProcessAssertionReasonExtension name:@"Web content visible" withHandler:handler]);
+ m_assertion.get().invalidationHandler = ^() {
+ m_validity = Validity::No;
+ invalidationCallback();
+ };
}
ProcessAssertion::~ProcessAssertion()
{
+ m_assertion.get().invalidationHandler = nil;
+
if (ProcessAssertionClient* client = this->client())
[[WKProcessAssertionBackgroundTaskManager shared] removeClient:*client];
[m_assertion invalidate];
@@ -174,7 +181,7 @@
void ProcessAndUIAssertion::updateRunInBackgroundCount()
{
- bool shouldHoldBackgroundAssertion = state() != AssertionState::Suspended;
+ bool shouldHoldBackgroundAssertion = validity() != Validity::No && state() != AssertionState::Suspended;
if (shouldHoldBackgroundAssertion) {
if (!m_isHoldingBackgroundAssertion)
@@ -188,7 +195,7 @@
}
ProcessAndUIAssertion::ProcessAndUIAssertion(pid_t pid, AssertionState assertionState)
- : ProcessAssertion(pid, assertionState)
+ : ProcessAssertion(pid, assertionState, [this] { updateRunInBackgroundCount(); })
{
updateRunInBackgroundCount();
}
@@ -219,7 +226,7 @@
namespace WebKit {
-ProcessAssertion::ProcessAssertion(pid_t, AssertionState assertionState)
+ProcessAssertion::ProcessAssertion(pid_t, AssertionState assertionState, std::function<void()>)
: m_assertionState(assertionState)
{
}