blob: aa1a421c1c66052443444b35d26905195cac2443 [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 THIRD_PARTY_BLINK_PUBLIC_COMMON_FRAME_USER_ACTIVATION_STATE_H_
#define THIRD_PARTY_BLINK_PUBLIC_COMMON_FRAME_USER_ACTIVATION_STATE_H_
#include "base/time/time_override.h"
#include "third_party/blink/public/common/common_export.h"
#include "third_party/blink/public/mojom/frame/user_activation_notification_type.mojom-forward.h"
namespace blink {
// This class represents the user activation state of a frame. It maintains two
// bits of information: whether this frame has ever seen an activation in its
// lifetime (the sticky bit), and whether this frame has a current activation
// that is neither expired nor consumed (the transient bit). See User
// Activation v2 (UAv2) links below for more info.
//
//
// Tracking User Activation across the Frame Tree
// ==============================================
//
// This state changes in three ways: activation (of both bits) through user
// input notifications, and deactivation (of transient bit only) through expiry
// and consumption.
//
// - A notification update at a frame activates all ancestor frames (sets both
// bits to true). Also see "Same-origin Visibility" below.
//
// - A consumption call deactivates the transient bits in the whole frame tree.
// This exhaustive consumption guarantees that a malicious subframe can't embed
// sub-subframes in a way that could allow multiple consumptions per user
// activation.
//
// - After a certain time limit (few seconds), the transient bit is deactivated.
// (Internally, the class doens't store the transient bit, but stores the bit's
// expiry time instead.)
//
//
// Same-origin Visibility of User Activation
// =========================================
//
// We launched UAv2 with a relaxed visibility model that a user activation is
// visible to all same-origin frames (w.r.t. the originally-activated frame), in
// addition to the ancestor frames as per UAv2. We will remove this relaxation
// after implementing a mechanism for activation transfer
// (https://crbug.com/928838).
//
// Details: Before UAv2, user activation was visible to all same-process frames
// and no cross-process frames (undocumented). The ancestor-only restriction
// with UAv2 caused a few breakages because of reliance on the old assumption,
// see the Type=Bug-Regression bugs blocking the above bug. Once we have a
// workaround for those broken cases (most likely through a postMessage
// transfer), we will go back to the ancestor-only visibility model.
//
//
// State Replication in Browser and Renderers
// ==========================================
//
// The user activation state is replicated in the browser process (in
// |FrameTreeNode|) and in the renderer processes (in |LocalFrame| and
// |RemoteFrame|). The replicated states across the browser and renderer
// processes are kept in sync as follows:
//
// [A] Consumption of activation state for popups starts in the frame tree of
// the browser process and propagate to the renderer trees through direct IPCs
// (one IPC sent to each renderer).
//
// [B] Consumption calls from JS/blink side (e.g. video picture-in-picture)
// update the originating renderer's local frame tree and send an IPC to the
// browser; the browser updates its frame tree and sends IPCs to all other
// renderers each of which then updates its local frame tree.
//
// [B'] Notification updates on user inputs is like [B] (renderer first). These
// should really be like [A] (browser first), see https://crbug.com/848778.
//
// [C] Expiration of an active state is tracked independently in each process.
//
//
// More Info
// =========
//
// - UAv2 explainer: https://mustaqahmed.github.io/user-activation-v2
// - Main design:
// https://docs.google.com/a/chromium.org/document/d/1erpl1yqJlc1pH0QvVVmi1s3WzqQLsEXTLLh6VuYp228
// - Browser-side replication for OOPIFs:
// https://docs.google.com/document/d/1XL3vCedkqL65ueaGVD-kfB5RnnrnTaxLc7kmU91oerg
class BLINK_COMMON_EXPORT UserActivationState {
public:
UserActivationState();
// Marks the user activation state as active, which sets the sticky state to
// true and updates the transient state timestamp to "now".
//
// The |notification_type| parameter is used for histograms only.
void Activate(mojom::UserActivationNotificationType notification_type);
void Clear();
// Returns the sticky activation state, which is |true| if the frame has ever
// seen an activation.
bool HasBeenActive() const;
// Returns the transient activation state, which is |true| if the frame has
// recently been activated and the transient state hasn't been consumed yet.
bool IsActive() const;
// Consumes the transient activation state if available, and returns |true| if
// successfully consumed.
bool ConsumeIfActive();
// Records UMA stats related to consumption. Must be called:
// - before |ConsumeIfActive()| to record correct stats, and
// - only once during consumption propagation to suppress over-counting.
void RecordPreconsumptionUma() const;
private:
void ActivateTransientState();
void DeactivateTransientState();
bool IsActiveInternal() const;
mojom::UserActivationNotificationType EffectiveNotificationType() const;
bool has_been_active_ = false;
base::TimeTicks transient_state_expiry_time_;
// Tracks the expiry of |kInteraction| notification for UMA data.
base::TimeTicks transient_state_expiry_time_for_interaction_;
// Tracks the type of notification for UMA data.
mojom::UserActivationNotificationType first_notification_type_;
mojom::UserActivationNotificationType last_notification_type_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_FRAME_USER_ACTIVATION_STATE_H_