| // 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. |
| // Draft Prototype of Protocols to be used by Power Broker. |
| // None of these protocols should be considered fully baked at this time |
| // and should be expected to change in the future as we gain information |
| // through this prototype testbed about coverage and usability. |
| @available(added=HEAD) |
| library fuchsia.power.broker; |
| |
| using zx; |
| |
| /// Used to describe the power level of an element. |
| /// Could extend this further to support additional types of power |
| /// levels, such as ACPI. |
| alias PowerLevel = uint8; |
| |
| /// BinaryPowerLevel is a well-known set of PowerLevels with only two |
| /// states: OFF and ON. |
| type BinaryPowerLevel = strict enum : PowerLevel { |
| OFF = 0; |
| ON = 1; |
| }; |
| |
| type DependencyType = strict enum { |
| ACTIVE = 1; |
| PASSIVE = 2; |
| }; |
| |
| const MAX_ELEMENT_NAME_LEN uint16 = 1024; |
| |
| /// A token that represents the right to add a dependency upon another |
| /// element. Should first be registered with Power Broker via |
| /// ElementControl.RegisterDependencyToken of the required element. |
| alias DependencyToken = zx.Handle:EVENT; |
| |
| /// Power dependency from an already specified element's PowerLevel to another. |
| /// The dependent Element should already be known from context. |
| type LevelDependency = resource struct { |
| dependency_type DependencyType; |
| dependent_level PowerLevel; |
| /// Must supply a token registered via the RegisterDependencyToken call of |
| /// the required element's ElementControl protocol. |
| requires_token DependencyToken; |
| requires_level PowerLevel; |
| }; |
| |
| /// This is the primary initial protocol used by Power Element Owners to |
| /// communicate with Power Broker. Power Element Owners should add the |
| /// elements they own to the Power Topology through AddElement. All further |
| /// interactions with Power Broker are done through channels opened by the |
| /// AddElement call, which are scoped to the added element. |
| @discoverable |
| open protocol Topology { |
| /// Called by a Power Element owner to register a new Power Element and |
| /// open control channels for that element. |
| flexible AddElement(ElementSchema) -> (resource struct { |
| /// ElementControl channel for this element. |
| /// When this channel is dropped, the element will be removed from the |
| /// topology. All channels associated with this element will be |
| /// closed and all tokens registered to this element will be |
| /// unregistered. |
| element_control_channel client_end:ElementControl; |
| }) error AddElementError; |
| }; |
| |
| /// Passed to Topology.AddElement. |
| type ElementSchema = resource table { |
| /// Human-readable name for logging and debug purposes. |
| 1: element_name string:MAX_ELEMENT_NAME_LEN; |
| /// The initial current power level of the element. |
| 2: initial_current_level PowerLevel; |
| /// All power levels that are valid for this element. Any level not |
| /// specified here will be treated as invalid. |
| 3: valid_levels vector<PowerLevel>:MAX_VALID_POWER_LEVELS; |
| /// List of dependencies for this element's power levels. |
| /// Note: dependencies UPON this element's levels cannot be added here. |
| 4: dependencies vector<LevelDependency>:MAX_DEPENDENCIES_IN_ADD_ELEMENT; |
| /// List of active dependency tokens to register for this element. |
| /// These tokens will allow other element owners to create active |
| /// dependencies upon this element by passing them as the |
| /// requires_token of a LevelDependency. |
| 5: active_dependency_tokens_to_register vector<DependencyToken>:MAX_TOKENS_IN_ADD_ELEMENT; |
| /// List of passive dependency tokens to register for this element. |
| /// These tokens will allow other element owners to create passive |
| /// dependencies upon this element by passing them as the |
| /// requires_token of a LevelDependency. |
| 6: passive_dependency_tokens_to_register vector<DependencyToken>:MAX_TOKENS_IN_ADD_ELEMENT; |
| /// Channels on which Power Broker will send required power levels and |
| /// receive current level updates. |
| 7: level_control_channels LevelControlChannels; |
| /// Optional. If passed, this will be treated as a consumer element and |
| /// Leases for this element can be requested via this channel. |
| 8: lessor_channel server_end:Lessor; |
| }; |
| |
| type LevelControlChannels = resource struct { |
| /// Channel on which Power Broker will receive current level updates |
| /// for this element. |
| current server_end:CurrentLevel; |
| /// Channel on which Power Broker will send required power levels |
| /// for this element. |
| required server_end:RequiredLevel; |
| }; |
| |
| // Limitations on vector length for the sake of bounding request size. |
| const MAX_DEPENDENCIES_IN_ADD_ELEMENT uint16 = 128; |
| const MAX_TOKENS_IN_ADD_ELEMENT uint16 = 128; |
| const MAX_VALID_POWER_LEVELS uint16 = 256; |
| |
| type AddElementError = flexible enum { |
| INTERNAL = 1; |
| INVALID = 2; |
| NOT_AUTHORIZED = 3; |
| }; |
| |
| /// Provides element-scoped access to an element previously added via |
| /// Topology.AddElement. |
| open protocol ElementControl { |
| /// Register a new Status channel on which Power Broker will send |
| /// read-only updates of the element's current power level. This method |
| /// is intended to allow element owners to give read-only access to the |
| /// element's current power level to clients by opening and transferring |
| /// this channel. |
| flexible OpenStatusChannel(resource struct { |
| status_channel server_end:Status; |
| }); |
| |
| /// Adds an active or passive dependency of this element upon another |
| /// element. |
| flexible AddDependency(LevelDependency) -> () error ModifyDependencyError; |
| |
| /// Removes an active or passive dependency of this element upon another |
| /// element. |
| flexible RemoveDependency(LevelDependency) -> () error ModifyDependencyError; |
| |
| /// Register a token which will permit the bearer to add either an |
| /// active or passive dependency upon this element, depending on the |
| /// dependency_type specified. |
| flexible RegisterDependencyToken(resource struct { |
| token DependencyToken; |
| dependency_type DependencyType; |
| }) -> () error RegisterDependencyTokenError; |
| |
| /// Unregister a token previously registered via RegisterDependencyToken. |
| flexible UnregisterDependencyToken(resource struct { |
| token DependencyToken; |
| }) -> () error UnregisterDependencyTokenError; |
| }; |
| |
| type ModifyDependencyError = flexible enum { |
| ALREADY_EXISTS = 1; |
| INVALID = 2; |
| NOT_AUTHORIZED = 3; |
| NOT_FOUND = 4; |
| }; |
| |
| type RegisterDependencyTokenError = flexible enum { |
| ALREADY_IN_USE = 1; |
| INTERNAL = 2; |
| }; |
| |
| type UnregisterDependencyTokenError = flexible enum { |
| NOT_AUTHORIZED = 1; |
| NOT_FOUND = 2; |
| }; |
| |
| /// Element Permissions |
| type Permissions = strict bits : uint32 { |
| MODIFY_ACTIVE_DEPENDENT = 0b00000001; |
| MODIFY_PASSIVE_DEPENDENT = 0b0000010; |
| MODIFY_DEPENDENCY = 0b00000100; |
| }; |
| |
| /// CurrentLevel and RequiredLevel must both be used by all managed |
| /// Power Elements as part of the power level handshake with Power Broker: |
| /// * The element operator calls RequiredLevel.Watch to receive the next |
| /// required level from Power Broker. |
| /// * The operator makes the changes necessary to transition to the new |
| /// required level. |
| /// * The operator calls CurrentLevel.Update to inform Power Broker |
| /// that it has completed the transition to the new level. |
| /// Established via Topology.AddElement. |
| open protocol CurrentLevel { |
| /// Sent by the element on initial startup and whenever there is a change |
| /// in power level. |
| flexible Update(resource struct { |
| current_level PowerLevel; |
| }) -> () error CurrentLevelError; |
| }; |
| |
| type CurrentLevelError = flexible enum { |
| NOT_AUTHORIZED = 1; |
| }; |
| |
| /// Part of the power level handshake with Power Broker used for receiving |
| /// required levels from Power Broker. See above note on CurrentLevel. |
| /// Established via Topology.AddElement. |
| open protocol RequiredLevel { |
| /// Returns the required power level for this element. The first call on |
| /// this channel will return immediately. Subsequent calls will block until |
| /// the required power level has changed. |
| flexible Watch() -> (resource struct { |
| required_level PowerLevel; |
| }) error RequiredLevelError; |
| }; |
| |
| type RequiredLevelError = flexible enum { |
| INTERNAL = 1; |
| NOT_AUTHORIZED = 2; |
| UNKNOWN = 3; |
| }; |
| |
| // Unique ID provided by Power Broker (currently a UUID but subject to change). |
| alias LeaseId = string:64; |
| |
| /// Provides element-scoped access to request leases to raise the levels of an |
| /// element previously added via Topology.AddElement. |
| open protocol Lessor { |
| /// Request made to indicate client intends to raise the given element |
| /// to the given power level and wants to have its direct and transitive |
| /// power dependencies satisfied. |
| flexible Lease(resource struct { |
| /// Power level of this element to be raised to. |
| level PowerLevel; |
| }) -> (resource struct { |
| /// Channel for actions to be taken on the lease. |
| /// When this channel is closed, the lease will be dropped. |
| lease_control client_end:LeaseControl; |
| }) error LeaseError; |
| }; |
| |
| type LeaseError = flexible enum { |
| INTERNAL = 1; |
| NOT_AUTHORIZED = 2; |
| }; |
| |
| type LeaseStatus = flexible enum { |
| UNKNOWN = 0; |
| PENDING = 1; |
| SATISFIED = 2; |
| }; |
| |
| /// Provides lease-scoped access to actions that can be taken on a lease |
| /// previously acquired via Lessor.Lease. Closing this control channel drops |
| /// the lease. |
| /// TODO(https://fxbug.dev/339474151): Switch from a protocol to an eventpair. |
| open protocol LeaseControl { |
| /// Get the current status of the lease. |
| /// If last_status is UNKNOWN, the call will return immediately |
| /// with the current status. Otherwise, the call will block |
| /// until the current status differs from last_status. |
| flexible WatchStatus(struct { |
| last_status LeaseStatus; |
| }) -> (struct { |
| status LeaseStatus; |
| }); |
| }; |
| |
| /// Provides read-only access to the current PowerLevel of an element and the |
| /// ability to watch changes to an element's power level. A new channel to |
| /// this protocol can be obtained by calling OpenStatus on the element's |
| /// ElementControl channel (and passed to other clients who need access |
| /// to the element's current power level). |
| open protocol Status { |
| /// Returns the current power level for this element. The first call on |
| /// this channel will return immediately. Subsequent calls will block until |
| /// the current power level has changed. |
| flexible WatchPowerLevel() -> (resource struct { |
| current_level PowerLevel; |
| }) error StatusError; |
| }; |
| |
| type StatusError = flexible enum { |
| UNKNOWN = 1; |
| }; |
| |
| /// PowerLevel name lengths are limited to reduce Inspect space usage |
| const MAX_LEVEL_NAME_LEN uint16 = 16; |
| |
| /// Status client endpoint and a plaintext name for a specific Power Element. Names are |
| /// expected to be unique between elements and persistent across reboots of the same build, |
| /// but consistency is not guaranteed between different builds. |
| type ElementStatusEndpoint = resource table { |
| 1: identifier string:MAX_ELEMENT_NAME_LEN; |
| 2: status client_end:Status; |
| }; |
| |
| /// Mapping of a plaintext name to a PowerLevel. Names are expected to be unique between |
| /// elements and persistent across reboots of the same build, but consistency is not |
| /// guaranteed between different builds. |
| type PowerLevelName = table { |
| 1: level PowerLevel; |
| 2: name string:MAX_LEVEL_NAME_LEN; |
| }; |
| |
| /// Mapping of a vector of [`fuchsia.power.broker/PowerLevelName`] to a Power Element via |
| /// its plaintext name. Names are expected to be unique between elements and persistent |
| /// across reboots of the same build, but consistency is not guaranteed between different builds. |
| type ElementPowerLevelNames = table { |
| 1: identifier string:MAX_ELEMENT_NAME_LEN; |
| 2: levels vector<PowerLevelName>:MAX_VALID_POWER_LEVELS; |
| }; |
| |
| /// Provides an interface to retrieve information about PowerElements managed by a component. |
| @discoverable |
| open protocol ElementInfoProvider { |
| /// Returns mappings of PowerLevels to plaintext names for each element managed |
| /// by a component. Returns an error if no mappings can be returned. |
| flexible GetElementPowerLevelNames() -> (resource struct { |
| level_names vector<ElementPowerLevelNames>:MAX; |
| }) error ElementInfoProviderError; |
| |
| /// Returns available Status client endpoints and stable identifiers for each |
| /// element managed by a component. Returns an error if no endpoints can be |
| /// returned (i.e. no elements were able to implement the Status channel). |
| flexible GetStatusEndpoints() -> (resource struct { |
| endpoints vector<ElementStatusEndpoint>:MAX; |
| }) error ElementInfoProviderError; |
| }; |
| |
| type ElementInfoProviderError = flexible enum { |
| UNKNOWN = 0; |
| FAILED = 1; |
| }; |
| |
| service ElementInfoProviderService { |
| status_provider client_end:ElementInfoProvider; |
| }; |