blob: 60115435cdeeaad9e6c2317ff7c47ea8f71a6bca [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/// The system activity governor (SAG) is a subsystem of the power framework
/// that manages the execution and suspend state of the hardware platform. It
/// also allows observers to watch for suspend/resume transitions of the
/// platform.
///
/// Other components can create dependencies on SAG's power elements with
/// [`fuchsia.power.broker/ElementControl`] to influence SAG's behavior
/// including preventing system suspension.
///
/// The power elements that SAG creates and manages are as follows:
/// * [`fuchsia.power.system/ExecutionState`]
/// * [`fuchsia.power.system/ApplicationActivity`]
/// * [`fuchsia.power.system/Cpu`]
///
/// # Internal Dependency Diagram
/// ```
/// +--------------------+ +---------------------------------+
/// | **ExecutionState** | | **ApplicationActivity** |
/// +--------------------+ +---------------------------------+
/// | ACTIVE |<-----------------| ACTIVE |
/// +--------------------+ +---------------------------------+
/// +--------------| SUSPENDING | | INACTIVE |
/// | | | +---------------------------------+
/// | +--------------------+
/// | | INACTIVE |
/// | +--------------------+
/// |
/// | +---------------------------------+
/// | | **CPU** |
/// | +---------------------------------+
/// +--->| ACTIVE |
/// +---------------------------------+
/// | INACTIVE |
/// +---------------------------------+
/// ```
///
/// # Usage
///
/// To prevent system suspension, a component can create an assertive dependency
/// using the `assertive_dependency_token` from `ApplicationActivity`. If the
/// dependency causes the power level of `ApplicationActivity` to be raised to
/// [`fuchsia.power.system/ApplicationActivityPowerLevel.ACTIVE`], SAG will not
/// trigger system suspension until their power levels drop to `INACTIVE`.
///
/// If a component is managing a power element that requires the platform to be
/// in a specific state, an opportunistic dependency can be created on
/// `ExecutionState`. When `ExecutionState` changes its power level, all
/// dependent power elements will power down first. Ideally, this forces the
/// entire system into a configuration with a lower power consumption as the
/// power level of `ExecutionState` decreases.
@available(added=26)
library fuchsia.power.system;
using fuchsia.power.broker;
using zx;
// TODO(https://fxbug.dev/339474151): Update this when EventPair is the standard
// token for leases in Power Broker.
@available(added=26)
alias LeaseToken = zx.Handle:<EVENTPAIR, zx.Rights.TRANSFER | zx.Rights.DUPLICATE | zx.Rights.WAIT>;
@available(added=26)
const MAX_ELEMENT_NAME_LEN uint8 = 64;
/// Errors returned by `ActivityGovernor/AcquireWakeLease`.
@available(added=26)
type AcquireWakeLeaseError = flexible enum : uint32 {
/// The service encountered an error while attempting to issue a wake lease.
INTERNAL = 1;
/// The name for the wake lease is empty or invalid.
INVALID_NAME = 2;
};
/// Holds a token to the execution state power element.
///
/// Power elements intentionally cannot take assertive dependencies on this power
/// element. Elements that need to force the execution state to ACTIVE can use
/// ApplicationActivity which provides more semantic meaning to the
/// dependencies.
///
/// [`fuchsia.power.system/ExecutionStateLevel`] defines the power levels supported by this power element.
@available(added=HEAD)
type ExecutionState = resource table {
1: opportunistic_dependency_token fuchsia.power.broker.DependencyToken;
};
/// Execution state power levels
///
/// Elements should take an opportunistic dependency on `ExecutionStateLevel::ACTIVE`
/// to ensure that the element will be suspended when the rest of the system
/// suspends.
///
/// Drivers can take an opportunistic dependency on either
/// `ExecutionStateLevel::SUSPENDING` or `ExecutionStateLevel::ACTIVE` and
/// request a persistent lease on this state to ensure that their element's
/// power level is always activated when the system comes out of a suspend
/// state.
@available(added=HEAD)
type ExecutionStateLevel = flexible enum : uint8 {
INACTIVE = 0;
SUSPENDING = 1;
ACTIVE = 2;
};
/// Holds tokens to the CPU power element.
///
/// [`fuchsia.power.system/CpuLevel`] defines the power levels supported by this power element.
@available(added=HEAD)
type Cpu = resource table {
1: assertive_dependency_token fuchsia.power.broker.DependencyToken;
};
/// CPU power levels
///
/// Elements should take an assertive dependency on `CpuLevel::ACTIVE`
/// to ensure that the element will be suspended before the CPU suspends.
@available(added=HEAD)
type CpuLevel = flexible enum : uint8 {
INACTIVE = 0;
ACTIVE = 1;
};
/// Holds tokens to the application activity power element.
///
/// [`fuchsia.power.system/ApplicationActivityLevel`] defines the power levels supported by this power element.
@available(added=HEAD)
type ApplicationActivity = resource table {
1: assertive_dependency_token fuchsia.power.broker.DependencyToken;
};
/// Application activity power levels
///
/// Elements that need to keep the system from suspending should take an assertive
/// dependency on `ApplicationActivityLevel::ACTIVE`. When these components are
/// performing work, they should request a lease to ensure the system remains
/// active, and drop the lease when they are done.
@available(added=HEAD)
type ApplicationActivityLevel = flexible enum : uint8 {
INACTIVE = 0;
ACTIVE = 1;
};
/// A collection of power elements that are managed by the activity governor.
@available(added=HEAD)
type PowerElements = resource table {
1: execution_state ExecutionState;
3: application_activity ApplicationActivity;
};
/// Error codes for responses from `AddExecutionStateDependency` in
/// [`fuchsia.power.system/CpuElementManager`].
@available(added=HEAD)
type AddExecutionStateDependencyError = flexible enum {
/// Required arguments are either not given or are not valid.
INVALID_ARGS = 1;
/// The server is not in a state to handle the request.
BAD_STATE = 2;
};
/// Error codes for responses from `RegisterSuspendBlocker` in
/// [`fuchsia.power.system/ActivityGovernor`].
@available(added=27)
type RegisterSuspendBlockerError = flexible enum {
/// The service encountered an error while attempting to issue a wake lease.
INTERNAL = 1;
/// Required arguments are either not given or are not valid.
INVALID_ARGS = 2;
};
/// An entity that blocks suspend until it handles transitions across hardware
/// platform suspend and resume.
@available(added=27)
open protocol SuspendBlocker {
/// Called after system activity governor begins operations to suspend the
/// hardware platform.
///
/// The server is expected to respond once it has performed the operations
/// it needs to prepare itself for suspend, if any. All dependencies of
/// `ExecutionStateLevel::SUSPENDING` are guaranteed to be satisified for
/// the duration of this call and may be revoked once the server replies.
///
/// Operations to suspend the hardware platform may vary between different
/// hardware platforms and product configurations. At a minimum, the client
/// and server MUST assume that general code execution continues
/// until a reply to this call is received by the client. If the
/// SuspendBlocker wants to preempt suspend operations, it MUST call
/// `ActivityGovernor.AcquireWakeLease` before replying to this call.
///
/// SuspendBlocker MUST NOT call
/// `ActivityGovernor.TakeApplicationActivityLease` nor perform any action
/// that blocks on raising Execution State above its Inactive level.
/// (However, AcquireWakeLease does _not_ block in this way and is safe to
/// call.) Doing so will currently result in a deadlock. This constraint
/// will eventually be removed; see https://fxbug.dev/391429689.
flexible BeforeSuspend() -> ();
/// Called after system activity governor is aware that the hardware
/// platform has resumed.
///
/// All dependencies of `ExecutionStateLevel::SUSPENDING` are guaranteed to
/// be satisified when this call is issued, and the `BeforeSuspend` method
/// will be invoked before that guarantee is removed.
///
/// SAG does not block on the response to this method, so the SuspendBlocker
/// may safely take actions that block on raising Execution State's power
/// level. In particular, it is not affected by https://fxbug.dev/391429689.
flexible AfterResume() -> ();
};
/// A service for exposing events and power elements managed by the system
/// activity governor (SAG).
///
/// SAG is responsible for managing the execution state of the hardware
/// platform. The hardware platform consists of the components required to
/// execute code on the device. This typically includes the CPU, memory,
/// operating system, and other components required for these components to
/// function (clock trees, power domains, etc.).
@available(added=26)
@discoverable
open protocol ActivityGovernor {
// TODO(b/315994898): Provide tokens more granularly once client usage
// patterns are better understood.
/// Gets the power elements owned by the activity governor.
///
/// If an error occurs while the server is registering a power element with
/// the power broker or an error occurs while creating a token for a power
/// element, then the channel to `ActivityGovernor` will be closed by the
/// server and no response will be returned.
@available(added=HEAD)
flexible GetPowerElements() -> (PowerElements);
/// Creates a lease that blocks suspension of the hardware platform.
///
/// The hardware platform will not suspend as long as a valid
/// [`LeaseToken`] exists.
///
/// If an error occurs while creating a token for the wake lease, then the
/// channel to `ActivityGovernor` will be closed by the server and no
/// response will be returned.
@available(added=HEAD, deprecated=HEAD, note="Use AcquireWakeLease instead")
flexible TakeWakeLease(struct {
/// The name of the lease.
///
/// The name is not required to be globally unique.
name string:fuchsia.power.broker.MAX_ELEMENT_NAME_LEN;
}) -> (resource struct {
/// The token that blocks hardware platform suspension.
token LeaseToken;
});
/// Creates a lease that blocks suspension of the hardware platform.
///
/// The hardware platform will not suspend as long as a valid
/// [`LeaseToken`] exists.
@available(added=26)
flexible AcquireWakeLease(struct {
/// The name of the lease.
///
/// The name cannot be empty but is not required to be globally unique.
name string:MAX_ELEMENT_NAME_LEN;
}) -> (resource struct {
/// The token that blocks hardware platform suspension.
token LeaseToken;
}) error AcquireWakeLeaseError;
/// Creates a lease that blocks suspension of the hardware platform.
/// WARNING: Suspension can only be considered blocked after the client
/// receives the response to this call. This means, for example, an
/// interrupt should only be ack'ed or a different wake lease dropped only
/// **after** getting an error-free response.
///
/// The hardware platform will remain resumed until `server_token` observes
/// `PEER_CLOSED`, indicating all handles to the client side of the
/// `LeaseToken` are closed.
@available(added=HEAD)
flexible AcquireWakeLeaseWithToken(resource struct {
/// The name of the lease.
///
/// The name cannot be empty but is not required to be globally unique.
name string:MAX_ELEMENT_NAME_LEN;
/// The server side of the token that blocks hardware platform
/// suspension. The caller should give out handles to the client side
/// of the `LeaseToken` which is peered to this `server_token`.
server_token LeaseToken;
}) -> () error AcquireWakeLeaseError;
/// Creates a lease that blocks the system from dropping below the Application
/// Activity 'Active' state. In particular, this blocks suspension of the
/// hardware platform.
///
/// This method is _not_ safe to call during SuspendBlocker.BeforeSuspend.
///
/// If an error occurs while creating a token for the activity lease, then the
/// channel to `ActivityGovernor` will be closed by the server and no
/// response will be returned.
@available(added=HEAD)
flexible TakeApplicationActivityLease(struct {
/// The name of the lease.
///
/// The name is not required to be globally unique.
name string:fuchsia.power.broker.MAX_ELEMENT_NAME_LEN;
}) -> (resource struct {
/// The token that blocks application activity from dropping below the
/// 'Active' state.
token LeaseToken;
});
/// Registers a suspend blocker.
///
/// On successful registration, a wake lease token is returned. This token
/// prevents hardware platform suspension while it exists. Clients are
/// expected to perform any initialization of the given `suspend_blocker`
/// server while holding this token. Additionally, this means the first call
/// `suspend_blocker` will get is `BeforeSuspend`.
///
/// To unregister, close the `SuspendBlocker` channel.
///
/// If any required field of the table is missing, the error
/// [`RegisterSuspendBlockerError.INVALID_ARGS`] is returned.
///
/// If an error occurs while registering `suspend_blocker`, it will be
/// dropped, closing the channel.
@available(added=27)
flexible RegisterSuspendBlocker(resource table {
/// The client end of the SuspendBlocker service.
///
/// Required.
1: suspend_blocker client_end:SuspendBlocker;
/// The name of the suspend blocker.
///
/// Required.
///
/// The name cannot be empty but is not required to be globally unique.
2: name string:MAX_ELEMENT_NAME_LEN;
}) -> (resource struct {
/// The token that blocks hardware platform suspension.
token LeaseToken;
}) error RegisterSuspendBlockerError;
};
/// A service that processes notification about the system boot state.
@discoverable
open protocol BootControl {
/// Notify the SAG that the system has booted. SAG will not suspend the
/// hardware platform until this method is called at least once per boot.
flexible SetBootComplete() -> ();
};
/// A service that provides access to CPU-related power elements.
@available(added=HEAD)
@discoverable
open protocol CpuElementManager {
/// Gets the assertive dependency token for the CPU power element.
flexible GetCpuDependencyToken() -> (Cpu);
/// Adds a dependency from the Execution State power element to the target
/// power element identified by [`dependency_token`] at [`power_level`].
///
/// Once the Execution State power element is created, future calls will
/// return [`fuchsia.power.system/AddExecutionStateDependencyError.BAD_STATE`]
/// and no changes to Execution State dependencies will be made.
///
/// If any required entries in the request are missing, the server will
/// return [`fuchsia.power.system/AddExecutionStateDependencyError.INVALID_ARGS`].
flexible AddExecutionStateDependency(resource table {
/// The assertive dependency token representing the target power element
/// of the dependency.
/// Required.
1: dependency_token fuchsia.power.broker.DependencyToken;
/// The power level of the target power element.
/// Required.
2: power_level fuchsia.power.broker.PowerLevel;
}) -> () error AddExecutionStateDependencyError;
};