blob: 09ef152f75a22e080fed3d5dc2e760b6205cf424 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef InteractiveDetector_h
#define InteractiveDetector_h
#include "base/macros.h"
#include "core/CoreExport.h"
#include "core/paint/FirstMeaningfulPaintDetector.h"
#include "platform/LongTaskDetector.h"
#include "platform/PODInterval.h"
#include "platform/Supplementable.h"
#include "platform/Timer.h"
#include "platform/heap/Handle.h"
#include "platform/wtf/Optional.h"
namespace blink {
class Document;
class WebInputEvent;
// Detects when a page reaches First Idle and Time to Interactive. See
// https://goo.gl/SYt55W for detailed description and motivation of First Idle
// and Time to Interactive.
// TODO(crbug.com/631203): This class currently only detects Time to
// Interactive. Implement First Idle.
class CORE_EXPORT InteractiveDetector
: public GarbageCollectedFinalized<InteractiveDetector>,
public Supplement<Document>,
public LongTaskObserver {
USING_GARBAGE_COLLECTED_MIXIN(InteractiveDetector);
public:
// This class can be easily switched out to allow better testing of
// InteractiveDetector.
class CORE_EXPORT NetworkActivityChecker {
public:
NetworkActivityChecker(Document* document) : document_(document) {}
virtual int GetActiveConnections();
virtual ~NetworkActivityChecker() = default;
private:
WeakPersistent<Document> document_;
DISALLOW_COPY_AND_ASSIGN(NetworkActivityChecker);
};
static InteractiveDetector* From(Document&);
virtual ~InteractiveDetector();
// Calls to CurrentTimeTicksInSeconds is expensive, so we try not to call it
// unless we really have to. If we already have the event time available, we
// pass it in as an argument.
void OnResourceLoadBegin(WTF::Optional<TimeTicks> load_begin_time);
void OnResourceLoadEnd(WTF::Optional<TimeTicks> load_finish_time);
void SetNavigationStartTime(TimeTicks navigation_start_time);
void OnFirstMeaningfulPaintDetected(
TimeTicks fmp_time,
FirstMeaningfulPaintDetector::HadUserInput user_input_before_fmp);
void OnDomContentLoadedEnd(TimeTicks dcl_time);
void OnInvalidatingInputEvent(TimeTicks invalidation_time);
void OnFirstInputDelay(TimeDelta delay_seconds);
// Returns Interactive Time if already detected, or 0.0 otherwise.
TimeTicks GetInteractiveTime() const;
// Returns the time when page interactive was detected. The detection time can
// be useful to make decisions about metric invalidation in scenarios like tab
// backgrounding.
TimeTicks GetInteractiveDetectionTime() const;
// Returns the first time interactive detector received a significant input
// that may cause observers to discard the interactive time value.
TimeTicks GetFirstInvalidatingInputTime() const;
// The duration between the hardware timestamp and being queued on the main
// thread for the first click, tap or key press.
TimeDelta GetFirstInputDelay() const;
void HandleForFirstInputDelay(const WebInputEvent&);
virtual void Trace(Visitor*);
private:
friend class InteractiveDetectorTest;
explicit InteractiveDetector(Document&, NetworkActivityChecker*);
TimeTicks interactive_time_;
TimeTicks interactive_detection_time_;
// Page event times that Interactive Detector depends on.
// Null TimeTicks values indicate the event has not been detected yet.
struct {
TimeTicks first_meaningful_paint;
TimeTicks dom_content_loaded_end;
TimeTicks nav_start;
TimeTicks first_invalidating_input;
TimeDelta first_input_delay;
bool first_meaningful_paint_invalidated = false;
} page_event_times_;
// Stores sufficiently long quiet windows on main thread and network.
std::vector<PODInterval<TimeTicks>> main_thread_quiet_windows_;
std::vector<PODInterval<TimeTicks>> network_quiet_windows_;
// Start times of currently active main thread and network quiet windows.
// Values of 0.0 implies main thread or network is not quiet at the moment.
TimeTicks active_main_thread_quiet_window_start_;
TimeTicks active_network_quiet_window_start_;
// Adds currently active quiet main thread and network quiet windows to the
// vectors. Should be called before calling
// FindInteractiveCandidate.
void AddCurrentlyActiveQuietIntervals(TimeTicks current_time);
// Undoes AddCurrentlyActiveQuietIntervals.
void RemoveCurrentlyActiveQuietIntervals();
std::unique_ptr<NetworkActivityChecker> network_activity_checker_;
int ActiveConnections();
void BeginNetworkQuietPeriod(TimeTicks current_time);
void EndNetworkQuietPeriod(TimeTicks current_time);
// Updates current network quietness tracking information. Opens and closes
// network quiet windows as necessary.
void UpdateNetworkQuietState(double request_count,
WTF::Optional<TimeTicks> current_time);
TaskRunnerTimer<InteractiveDetector> time_to_interactive_timer_;
TimeTicks time_to_interactive_timer_fire_time_;
void StartOrPostponeCITimer(TimeTicks timer_fire_time);
void TimeToInteractiveTimerFired(TimerBase*);
void CheckTimeToInteractiveReached();
void OnTimeToInteractiveDetected();
// Finds a window of length kTimeToInteractiveWindowSeconds after lower_bound
// such that both main thread and network are quiet. Returns the end of last
// long task before that quiet window, or lower_bound, whichever is bigger -
// this is called the Interactive Candidate. Returns 0.0 if no such quiet
// window is found.
TimeTicks FindInteractiveCandidate(TimeTicks lower_bound);
// LongTaskObserver implementation
void OnLongTaskDetected(TimeTicks start_time, TimeTicks end_time) override;
// The duration between the hardware timestamp and when we received the event
// for the previous pointer down. Only non-zero if we've received a pointer
// down event, and haven't yet reported the first input delay.
base::TimeDelta pending_pointerdown_delay_;
DISALLOW_COPY_AND_ASSIGN(InteractiveDetector);
};
} // namespace blink
#endif