Skip to content
Permalink
Browse files
Start/stop ProcessStateMonitor with ApplicationStateTracker
https://bugs.webkit.org/show_bug.cgi?id=241427

Reviewed by Geoffrey Garen.

We want ProcessStateMonitor to be started when application is in background and to be stopped when application is in
foreground. In r294405, we start/stop ProcessStateMonitor on receiving UIApplicationDidEnterBackgroundNotification and
UIApplicationWillEnterForegroundNotification notifications. However, UIApplicationWillEnterForegroundNotification can be
sent later than UISceneWillEnterForegroundNotification. In ApplicationStateTracke, we start creating foreground activity
for web process on receiving UISceneWillEnterForegroundNotification. At this time,
UIApplicationWillEnterForegroundNotification may not be received yet and ProcessStateMonitor may still be
working. ProcessStateMonitor may forbid creating new activity after it sets process shouldSuspend (see r294405), so we
need to make sure ProcessStateMonitor is stopped before starting new foreground activity.

To achieve that, we now decide when to start/stop ProcessStateMonitor with ApplicationStateTracker. We start
ProcessStateMonitor when all trackers are in the background, and stop it when at least one tracker is in foreground.

* Source/WebKit/UIProcess/ApplicationStateTracker.mm:
(WebKit::allApplicationStateTrackers):
(WebKit::updateApplicationBackgroundState):
(WebKit::ApplicationStateTracker::ApplicationStateTracker):
(WebKit::ApplicationStateTracker::~ApplicationStateTracker):
(WebKit::ApplicationStateTracker::applicationDidEnterBackground):
(WebKit::ApplicationStateTracker::applicationWillEnterForeground):
* Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm:
(WebKit::WebProcessPool::setProcessesShouldSuspend):
* Source/WebKit/UIProcess/ProcessAssertion.h:
* Source/WebKit/UIProcess/WebProcessPool.h:
* Source/WebKit/UIProcess/ios/ProcessAssertionIOS.mm:
(-[WKProcessAssertionBackgroundTaskManager _releaseBackgroundTask]):
(-[WKProcessAssertionBackgroundTaskManager setProcessStateMonitorEnabled:]):
(WebKit::ProcessAndUIAssertion::setProcessStateMonitorEnabled):
* Source/WebKit/UIProcess/ios/ProcessStateMonitor.mm:
(WebKit::ProcessStateMonitor::checkRemainingRunTime):
* Source/WebKit/UIProcess/ios/WebProcessProxyIOS.mm:
(WebKit::WebProcessProxy::platformInitialize):

Canonical link: https://commits.webkit.org/251498@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@295493 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
szewai committed Jun 13, 2022
1 parent 199b01f commit d5a19d183b733b93b0a202ea65651a2614200998
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 2 deletions.
@@ -30,6 +30,7 @@

#import "EndowmentStateTracker.h"
#import "Logging.h"
#import "ProcessAssertion.h"
#import "SandboxUtilities.h"
#import "UIKitSPI.h"
#import <wtf/ObjCRuntimeExtras.h>
@@ -50,6 +51,28 @@ - (BOOL)_isHostedInAnotherProcess;

namespace WebKit {

static WeakHashSet<ApplicationStateTracker>& allApplicationStateTrackers()
{
static NeverDestroyed<WeakHashSet<ApplicationStateTracker>> trackers;
return trackers;
}

static void updateApplicationBackgroundState()
{
static bool s_isApplicationInBackground = false;
auto isAnyStateTrackerInForeground = []() -> bool {
return WTF::anyOf(allApplicationStateTrackers(), [](auto& tracker) {
return !tracker.isInBackground();
});
};
bool isApplicationInBackground = !isAnyStateTrackerInForeground();
if (s_isApplicationInBackground == isApplicationInBackground)
return;

s_isApplicationInBackground = isApplicationInBackground;
ProcessAndUIAssertion::setProcessStateMonitorEnabled(isApplicationInBackground);
}

ApplicationType applicationType(UIWindow *window)
{
if (_UIApplicationIsExtension())
@@ -161,6 +184,9 @@ ApplicationType applicationType(UIWindow *window)
break;
}
}

allApplicationStateTrackers().add(*this);
updateApplicationBackgroundState();
}

ApplicationStateTracker::~ApplicationStateTracker()
@@ -173,11 +199,15 @@ ApplicationType applicationType(UIWindow *window)
[notificationCenter removeObserver:m_willEnterForegroundObserver];
[notificationCenter removeObserver:m_willBeginSnapshotSequenceObserver];
[notificationCenter removeObserver:m_didCompleteSnapshotSequenceObserver];

allApplicationStateTrackers().remove(*this);
updateApplicationBackgroundState();
}

void ApplicationStateTracker::applicationDidEnterBackground()
{
m_isInBackground = true;
updateApplicationBackgroundState();

if (auto view = m_view.get())
wtfObjCMsgSend<void>(view.get(), m_didEnterBackgroundSelector);
@@ -192,6 +222,7 @@ ApplicationType applicationType(UIWindow *window)
void ApplicationStateTracker::applicationWillEnterForeground()
{
m_isInBackground = false;
updateApplicationBackgroundState();

if (auto view = m_view.get())
wtfObjCMsgSend<void>(view.get(), m_willEnterForegroundSelector);
@@ -992,8 +992,12 @@ void setCaptivePortalModeEnabledGloballyForTesting(std::optional<bool> enabledFo
{
WEBPROCESSPOOL_RELEASE_LOG(ProcessSuspension, "setProcessesShouldSuspend: Processes should suspend %d", shouldSuspend);

if (m_processesShouldSuspend == shouldSuspend)
return;

m_processesShouldSuspend = shouldSuspend;
for (auto& process : m_processes)
process->throttler().setAllowsActivities(!shouldSuspend);
process->throttler().setAllowsActivities(!m_processesShouldSuspend);
}

#endif
@@ -124,6 +124,9 @@ class ProcessAndUIAssertion final : public ProcessAssertion {
void uiAssertionWillExpireImminently();

void setUIAssertionExpirationHandler(Function<void()>&& handler) { m_uiAssertionExpirationHandler = WTFMove(handler); }
#if PLATFORM(IOS_FAMILY)
static void setProcessStateMonitorEnabled(bool);
#endif

private:
ProcessAndUIAssertion(ProcessID, const String& reason, ProcessAssertionType);
@@ -515,6 +515,9 @@ class WebProcessPool final
Ref<WebProcessProxy> createNewWebProcess(WebsiteDataStore*, WebProcessProxy::CaptivePortalMode, WebProcessProxy::IsPrewarmed = WebProcessProxy::IsPrewarmed::No, WebCore::CrossOriginMode = WebCore::CrossOriginMode::Shared);

bool hasAudibleMediaActivity() const { return !!m_audibleMediaActivity; }
#if PLATFORM(IOS_FAMILY)
bool processesShouldSuspend() const { return m_processesShouldSuspend; }
#endif

private:
void platformInitialize();
@@ -803,6 +806,10 @@ class WebProcessPool final
#if ENABLE(IPC_TESTING_API)
IPCTester m_ipcTester;
#endif

#if PLATFORM(IOS_FAMILY)
bool m_processesShouldSuspend { false };
#endif
};

template<typename T>
@@ -29,6 +29,7 @@
#if PLATFORM(IOS_FAMILY)

#import "Logging.h"
#import "ProcessStateMonitor.h"
#import "RunningBoardServicesSPI.h"
#import "WebProcessPool.h"
#import <UIKit/UIApplication.h>
@@ -64,6 +65,7 @@ + (WKProcessAssertionBackgroundTaskManager *)shared;

- (void)addAssertionNeedingBackgroundTask:(ProcessAndUIAssertion&)assertion;
- (void)removeAssertionNeedingBackgroundTask:(ProcessAndUIAssertion&)assertion;
- (void)setProcessStateMonitorEnabled:(BOOL)enabled;

@end

@@ -73,6 +75,7 @@ @implementation WKProcessAssertionBackgroundTaskManager
std::atomic<bool> _backgroundTaskWasInvalidated;
WeakHashSet<ProcessAndUIAssertion> _assertionsNeedingBackgroundTask;
dispatch_block_t _pendingTaskReleaseTask;
std::unique_ptr<WebKit::ProcessStateMonitor> m_processStateMonitor;
}

+ (WKProcessAssertionBackgroundTaskManager *)shared
@@ -242,14 +245,32 @@ - (void)_releaseBackgroundTask
return;

RELEASE_LOG(ProcessSuspension, "%p - WKProcessAssertionBackgroundTaskManager: endBackgroundTask", self);
if (processHasActiveRunTimeLimitation())
if (processHasActiveRunTimeLimitation()) {
WebKit::WebProcessPool::notifyProcessPoolsApplicationIsAboutToSuspend();
if (m_processStateMonitor)
m_processStateMonitor->processWillBeSuspendedImmediately();
}

[_backgroundTask removeObserver:self];
[_backgroundTask invalidate];
_backgroundTask = nullptr;
}

- (void)setProcessStateMonitorEnabled:(BOOL)enabled
{
if (!enabled) {
m_processStateMonitor = nullptr;
return;
}

if (!m_processStateMonitor) {
m_processStateMonitor = makeUnique<WebKit::ProcessStateMonitor>([](bool suspended) {
for (auto& processPool : WebKit::WebProcessPool::allProcessPools())
processPool->setProcessesShouldSuspend(suspended);
});
}
}

@end

typedef void(^RBSAssertionInvalidationCallbackType)();
@@ -454,6 +475,11 @@ - (void)assertion:(RBSAssertion *)assertion didInvalidateWithError:(NSError *)er
updateRunInBackgroundCount();
}

void ProcessAndUIAssertion::setProcessStateMonitorEnabled(bool enabled)
{
[[WKProcessAssertionBackgroundTaskManager shared] setProcessStateMonitorEnabled:enabled];
}

ProcessAndUIAssertion::~ProcessAndUIAssertion()
{
if (m_isHoldingBackgroundTask)
@@ -117,6 +117,8 @@

void ProcessStateMonitor::checkRemainingRunTime()
{
#if !PLATFORM(IOS_FAMILY_SIMULATOR)
// runTime is meaningful only on device.
double remainingRunTime = [[[RBSProcessHandle currentProcess] activeLimitations] runTime];
if (remainingRunTime == RBSProcessTimeLimitationNone)
return processDidBecomeRunning();
@@ -125,6 +127,7 @@
return processWillBeSuspendedImmediately();

processWillBeSuspended(Seconds(remainingRunTime - maxPrepareForSuspensionDelayInSecond));
#endif
}

} // namespace WebKit
@@ -44,6 +44,8 @@
#if HAVE(STYLUS_DEVICE_OBSERVATION)
[[WKStylusDeviceObserver sharedInstance] start];
#endif

m_throttler.setAllowsActivities(!m_processPool->processesShouldSuspend());
}

void WebProcessProxy::platformDestroy()

0 comments on commit d5a19d1

Please sign in to comment.