blob: e87db74560e64886047285e638ab57e0ad25b53f [file] [log] [blame]
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ProcessThrottler_h
#define ProcessThrottler_h
#include "Logging.h"
#include "ProcessAssertion.h"
#include <wtf/ProcessID.h>
#include <wtf/RefCounter.h>
#include <wtf/RunLoop.h>
#include <wtf/UniqueRef.h>
#include <wtf/Variant.h>
#include <wtf/WeakPtr.h>
namespace WebKit {
enum UserObservablePageCounterType { };
typedef RefCounter<UserObservablePageCounterType> UserObservablePageCounter;
enum ProcessSuppressionDisabledCounterType { };
typedef RefCounter<ProcessSuppressionDisabledCounterType> ProcessSuppressionDisabledCounter;
typedef ProcessSuppressionDisabledCounter::Token ProcessSuppressionDisabledToken;
enum class IsSuspensionImminent : bool { No, Yes };
class ProcessThrottlerClient;
class ProcessThrottler : public CanMakeWeakPtr<ProcessThrottler>, private ProcessAssertion::Client {
public:
ProcessThrottler(ProcessThrottlerClient&, bool shouldTakeUIBackgroundAssertion);
~ProcessThrottler();
enum class ActivityType { Background, Foreground };
template<ActivityType type> class Activity {
WTF_MAKE_FAST_ALLOCATED;
public:
Activity(ProcessThrottler& throttler, ASCIILiteral name)
: m_throttler(&throttler)
, m_name(name)
{
throttler.addActivity(*this);
RELEASE_LOG(ProcessSuspension, "[PID: %d] %p - ProcessThrottler Starting %{public}s activity %p / '%{public}s'", m_throttler->m_processIdentifier, m_throttler, type == ActivityType::Foreground ? "foreground" : "background", this, m_name.characters());
}
~Activity()
{
if (isValid())
invalidate();
}
bool isValid() const { return !!m_throttler; }
private:
friend class ProcessThrottler;
void invalidate()
{
ASSERT(isValid());
RELEASE_LOG(ProcessSuspension, "[PID: %d] %p - ProcessThrottler Ending %{public}s activity %p / '%{public}s'", m_throttler->m_processIdentifier, m_throttler, type == ActivityType::Foreground ? "foreground" : "background", this, m_name.characters());
m_throttler->removeActivity(*this);
m_throttler = nullptr;
}
ProcessThrottler* m_throttler { nullptr };
ASCIILiteral m_name;
};
using ForegroundActivity = Activity<ActivityType::Foreground>;
UniqueRef<ForegroundActivity> foregroundActivity(ASCIILiteral name);
using BackgroundActivity = Activity<ActivityType::Background>;
UniqueRef<BackgroundActivity> backgroundActivity(ASCIILiteral name);
using ActivityVariant = Variant<std::nullptr_t, UniqueRef<BackgroundActivity>, UniqueRef<ForegroundActivity>>;
static bool isValidBackgroundActivity(const ActivityVariant&);
static bool isValidForegroundActivity(const ActivityVariant&);
void didConnectToProcess(ProcessID);
bool shouldBeRunnable() const { return m_foregroundActivities.size() || m_backgroundActivities.size(); }
private:
AssertionState expectedAssertionState();
void updateAssertionIfNeeded();
void updateAssertionStateNow();
void setAssertionState(AssertionState);
void prepareToSuspendTimeoutTimerFired();
void sendPrepareToSuspendIPC(IsSuspensionImminent);
void processReadyToSuspend();
void addActivity(ForegroundActivity&);
void addActivity(BackgroundActivity&);
void removeActivity(ForegroundActivity&);
void removeActivity(BackgroundActivity&);
void invalidateAllActivities();
// ProcessAssertionClient
void uiAssertionWillExpireImminently() override;
void clearPendingRequestToSuspend();
ProcessThrottlerClient& m_process;
ProcessID m_processIdentifier { 0 };
std::unique_ptr<ProcessAssertion> m_assertion;
RunLoop::Timer<ProcessThrottler> m_prepareToSuspendTimeoutTimer;
HashSet<ForegroundActivity*> m_foregroundActivities;
HashSet<BackgroundActivity*> m_backgroundActivities;
Optional<uint64_t> m_pendingRequestToSuspendID;
bool m_shouldTakeUIBackgroundAssertion;
};
inline auto ProcessThrottler::foregroundActivity(ASCIILiteral name) -> UniqueRef<ForegroundActivity>
{
return makeUniqueRef<ForegroundActivity>(*this, name);
}
inline auto ProcessThrottler::backgroundActivity(ASCIILiteral name) -> UniqueRef<BackgroundActivity>
{
return makeUniqueRef<BackgroundActivity>(*this, name);
}
} // namespace WebKit
#endif // ProcessThrottler_h