| // Copyright 2018 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. |
| |
| library fuchsia.sysmem; |
| |
| using zx; |
| |
| /// A BufferCollectionToken is not a BufferCollection, but rather a way to |
| /// identify a potential shared BufferCollection prior to the BufferCollection |
| /// being allocated. |
| /// |
| /// We use a channel for the BufferCollectionToken instead of a single eventpair |
| /// (pair) because this way we can detect error conditions like a participant |
| /// dying mid-create. |
| [Discoverable, ForDeprecatedCBindings] |
| protocol BufferCollectionToken { |
| /// The initiator or a participant can send Duplicate() as part of creating |
| /// another participant-side handle to the same logical |
| /// BufferCollectionToken. |
| /// |
| /// This method is used to hand the logical token to all participants so all |
| /// participants can provide constraints to sysmem for the overall |
| /// BufferCollection to achieve the goal of allocating buffers compatible |
| /// with all participants. |
| /// |
| /// The Duplicate() message is intentionally available only on |
| /// BufferCollectionToken not BufferCollection. |
| /// |
| /// The token is separate from BufferCollection so that participants contact |
| /// sysmem directly, so that participants are only trusting their environment |
| /// for who sysmem is (fake token mitigation), not an initiator. Only after |
| /// successful BindSharedCollection does a participant know that the token |
| /// was a real sysmem token. In contrast, if we had Duplicate() directly on |
| /// BufferCollection, an initiator could attempt to serve the |
| /// BufferCollection channel itself, which would allow for some problematic |
| /// possibilities. |
| /// |
| /// All the BufferCollectionToken channels of a logical token must be turned |
| /// in via BindSharedCollection() for a BufferCollection to be successfully |
| /// created. Else the BufferCollection channel will close. |
| /// |
| /// When a client calls BindSharedCollection() to turn in a |
| /// BufferCollectionToken, the server will process all Duplicate() messages |
| /// before closing down the BufferCollectionToken. This allows the client |
| /// to Duplicate() and immediately turn in the BufferCollectionToken using |
| /// BindSharedCollection, then later transfer the client end of token_request |
| /// to another participant - the server will notice the existence of the |
| /// token_request before considering this BufferCollectionToken fully closed. |
| /// |
| /// `rights_attenuation_mask` rights bits that are zero in this mask will be |
| /// absent in the buffer VMO rights obtainable via the client end of |
| /// token_request. This allows an initiator or intermediary participant |
| /// to attenuate the rights available to a participant. This may not be the |
| /// only mechanism that attenuates rights on the VMO handles obtainable via |
| /// the client end of token_request. This does not allow a participant |
| /// to gain rights that the participant doesn't already have. The value |
| /// ZX_RIGHT_SAME_RIGHTS can be used to specify that no attenuation should |
| /// be applied. |
| /// |
| /// `token_request` is the server end of a BufferCollectionToken channel. |
| /// The client end of this channel acts as another handle to the same logical |
| /// BufferCollectionToken. Typically the sender of Duplicate() will transfer |
| /// the client end corresponding to collection_request to a/another |
| /// participant running in a separate process, but it's also fine for the |
| /// additional logical participant to be in the same process. |
| /// |
| /// After sending one or more Duplicate() messages, and before sending the |
| /// created tokens to other participants (or to other Allocator channels), |
| /// the client should send a Sync() and wait for its response. The Sync() |
| /// call can be made on the token, or on the BufferCollection obtained by |
| /// passing this token to BindSharedCollection(). Either will ensure that |
| /// the server knows about the tokens created via Duplicate() before the |
| /// other participant sends the token to the server via separate Allocator |
| /// channel. If a client is using FIDL C generated code and doesn't want to |
| /// block waiting for a response message, the other option is to notice |
| /// arrival of the BufferCollectionEvents::OnBufferCollectionCreated() event |
| /// after turning in this token for a BufferCollection. |
| // |
| // TODO(dustingreen): Consider other mechanisms to ensure the token created |
| // here is recognized by the server. |
| Duplicate(uint32 rights_attenuation_mask, |
| request<BufferCollectionToken> token_request); |
| |
| /// Ensure that previous Duplicate() messages have been received server side, |
| /// so that it's safe to send the client end of token_request to another |
| /// participant knowing the server will recognize the token when it's sent |
| /// into BindSharedCollection by the other participant. |
| /// |
| /// Other options include waiting for each Duplicate() to complete |
| /// individually (using separate call to BufferCollectionToken.Sync() after |
| /// each), or calling Sync() on BufferCollection after this token has |
| /// been turned in via BindSharedCollection(), or noticing arrival of |
| /// BufferCollectionEvents::OnDuplicatedTokensKnownByServer(). |
| /// |
| /// Calling BufferCollectionToken.Sync() on a token that isn't/wasn't a |
| /// valid sysmem token risks the Sync() hanging forever. See |
| /// ValidateBufferCollectionToken() for one way to mitigate the possiblity |
| /// of a hostile/fake BufferCollectionToken at the cost of one round trip. |
| /// |
| /// Another way to mitigate is to avoid calling Sync() on the token, and |
| /// instead later deal with potential failure of BufferCollection.Sync() if |
| /// the original token was invalid. This option can be preferable from a |
| /// performance point of view, but requires client code to delay sending |
| /// tokens duplicated from this token until after client code has converted |
| /// this token to a BufferCollection and received successful response from |
| /// BufferCollection.Sync() (or received OnDuplicatedTokensKnownByServer()). |
| /// |
| /// Prefer using BufferCollection.Sync() instead, when feasible (see above). |
| /// When BufferCollection.Sync() isn't feasible, the caller must already |
| /// know that this token is/was valid, or BufferCollectionToken.Sync() may |
| /// hang forever. See ValidateBufferCollectionToken() to check token |
| /// validity first if the token isn't already known to be (is/was) valid. |
| Sync() -> (); |
| |
| /// Normally a participant will convert the token into a BufferCollection |
| /// view, but a particpant is also free to Close() the token (and then close |
| /// the channel immediately or shortly later in response to server closing |
| /// its end), which avoids causing LogicalBufferCollection failure. |
| /// Normally an unexpected token channel close will cause |
| /// LogicalBufferCollection failure. |
| Close(); |
| |
| /// Set a name for VMOs in this buffer collection. The name may be truncated shorter. The name |
| /// only affects VMOs allocated after it's set - this call does not rename existing VMOs. If |
| /// multiple clients set different names then the larger priority value will win. |
| [Transitional] |
| SetName(uint32 priority, string:64 name); |
| |
| /// Set information about the current client that can be used by sysmem to |
| /// help debug leaking memory and hangs waiting for constraints. |name| can |
| /// be an arbitrary string, but the current process name (see |
| /// fsl::GetCurrentProcessName()) is a good default. |id| can be an arbitrary |
| /// id, but the current process ID (see fsl::GetCurrentProcessKoid()) is a |
| /// good default. |
| SetDebugClientInfo(string:64 name, uint64 id); |
| |
| /// Sysmem logs a warning if not all clients have set constraints 5 seconds |
| /// after creating a collection. Clients can call this method to change |
| /// when the log is printed. If multiple client set the deadline, it's |
| /// unspecified which deadline will take effect. |
| SetDebugTimeoutLogDeadline(zx.time deadline); |
| }; |
| |
| /// BufferCollection is a connection directly from a participant to sysmem re. |
| /// a logical BufferCollection; typically the logical BufferCollection is shared |
| /// with other participants. In other words, an instance of the BufferCollection |
| /// interface is a view of a "LogicalBufferCollection". |
| /// |
| /// This connection exists to facilitate async indication of when the logical |
| /// BufferCollection has been populated with buffers. |
| /// |
| /// Also, the channel's closure by the server is an indication to the client |
| /// that the client should close all VMO handles that were obtained from the |
| /// BufferCollection ASAP. |
| /// |
| /// Also, this interface may in future allow specifying constraints in other |
| /// ways, and may allow for back-and-forth negotiation of constraints to some |
| /// degree. |
| /// |
| /// This interface may in future allow for more than 64 VMO handles per |
| /// BufferCollection, but currently the limit is 64. |
| /// |
| /// This interface may in future allow for allocating/deallocating single |
| /// buffers. |
| /// |
| /// Some initiators may wait a short duration until all old logical |
| /// BufferCollection VMO handles have closed (or until the short duration times |
| /// out) before allocating a new BufferCollection, to help control physical |
| /// memory fragmentation and avoid overlap of buffer allocation lifetimes for |
| /// the old and new collections. Collections can be large enough that it's worth |
| /// avoiding allocation overlap (in time). |
| [Discoverable, ForDeprecatedCBindings] |
| protocol BufferCollection { |
| /// At least for now, the only way to get events from a BufferCollection is |
| /// to set a reverse BufferCollectionEvents channel. This can be sent up to |
| /// once at any point during BufferCollection channel lifetime. All events |
| /// are one-shot events, and will be sent immediately via `events` if the |
| /// one-shot event's condition has already become true (once true will stay |
| /// true; only goes from false to true once). |
| /// |
| /// `events` is the client end of a BufferCollectionEvents which will be sent |
| /// one-way messages indicating events relevant to this BufferCollection |
| /// channel (some may be specific to this BufferCollection channel and some |
| /// may be relevant to the overall logical BufferCollection). |
| SetEventSink(BufferCollectionEvents events); |
| |
| /// See comments on BufferCollectionToken::Sync(). |
| Sync() -> (); |
| |
| /// Provide BufferCollectionConstraints to the logical BufferCollection. |
| /// |
| /// Participants with read but not write can only call SetConstraints() once. |
| /// |
| /// Participants with write can call SetConstraints() more than once. The |
| /// initial buffer allocation will use the constraints in the first call to |
| /// SetConstraints(). Among other things, this allows a decoder to attempt |
| /// to allocate a new buffer that's larger to hold an output frame that's |
| /// larger. |
| /// |
| /// Sometimes the initiator is a participant only in the sense of wanting to |
| /// keep an eye on success/failure to populate with buffers, and zx.status on |
| /// failure. In that case, `has_constraints` can be false, and `constraints` |
| /// will be ignored. |
| /// |
| /// VMO handles will not be provided to the client that sends null |
| /// constraints - that can be intentional for an initiator that doesn't need |
| /// VMO handles. Not having VMO handles doesn't prevent the initator from |
| /// adjusting which portion of a buffer is considered valid and similar, but |
| /// the initiator can't hold a VMO handle open to prevent the logical |
| /// BufferCollection from cleaning up if the logical BufferCollection needs |
| /// to go away regardless of the initiator's degree of involvement for |
| /// whatever reason. |
| /// |
| /// For population of buffers to be attempted, all holders of a |
| /// BufferCollection client channel need to call SetConstraints() before |
| /// sysmem will attempt to allocate buffers. |
| /// |
| /// `has_constraints` if false, the constraints are effectively null, and |
| /// `constraints` are ignored. The sender of null constraints won't get any |
| /// VMO handles in BufferCollectionInfo, but can still find out how many |
| /// buffers were allocated and can still refer to buffers by their |
| /// buffer_index. |
| /// |
| /// `constraints` are constraints on the buffer collection. |
| SetConstraints(bool has_constraints, |
| BufferCollectionConstraints constraints); |
| |
| /// This request completes when buffers have been allocated, responds with |
| /// some failure detail if allocation has been attempted but failed. |
| /// |
| /// The following must occur before buffers will be allocated: |
| /// * All BufferCollectionToken(s) of the logical BufferCollectionToken |
| /// must be turned in via BindSharedCollection(). |
| /// * All BufferCollection(s) of the logical BufferCollection must have had |
| /// SetConstraints() sent to them. |
| /// |
| /// A caller using C generated FIDL code who wishes not to block a thread in |
| /// a zx_channel_call() for a potentially fairly long duration on this |
| /// message/response can use SetEventSink() and |
| /// BufferCollectionEvents.OnBuffersPopulated() instead. |
| /// |
| /// This method is still legal to call despite use of OnBuffersPopulated(), |
| /// but in that case the additional BufferCollectionInfo returned here will |
| /// include handles that are redundant with other handles in the |
| /// BufferCollectionInfo delivered via OnBuffersPopulated() (separate handle |
| /// but same underlying VMO objects), so most clients that bother calling |
| /// SetEventSink() will prefer to receive BufferCollectionInfo via |
| /// OnBuffersPopulated(). This method is mostly here for clients that don't |
| /// call SetEventSink(). |
| /// |
| /// Returns `ZX_OK` if successful. |
| /// Returns `ZX_ERR_NO_MEMORY` if the request is valid but cannot be |
| /// fulfilled due to resource exhaustion. |
| /// Returns `ZX_ERR_ACCESS_DENIED` if the caller is not permitted to |
| /// obtain the buffers it requested. |
| /// Returns `ZX_ERR_INVALID_ARGS` if the request is malformed. |
| /// Returns `ZX_ERR_NOT_SUPPORTED` if request is valid but cannot be |
| /// satisfied, perhaps due to hardware limitations. |
| /// |
| /// `buffer_collection_info` has the VMO handles and other related info. |
| WaitForBuffersAllocated() |
| -> (zx.status status, BufferCollectionInfo_2 buffer_collection_info); |
| |
| /// This returns the same result code as WaitForBuffersAllocated if the |
| /// buffer collection has been allocated or failed, or `ZX_ERR_UNAVAILABLE` |
| /// if WaitForBuffersAllocated would block. |
| CheckBuffersAllocated() -> (zx.status status); |
| |
| /// The CloseBuffer() doesn't immediately force all VMO handles to that |
| /// buffer to close, but it does close any handle held by sysmem, and does |
| /// notify all participants of the desire to close the buffer at which point |
| /// each participant that's listening may close their handle to the buffer. |
| /// |
| /// Only a particpant with write can do this. Coordination among multiple |
| /// participants with write is outside of the scope of this interface. |
| /// |
| /// `buffer_index` indicates which buffer to close. If the buffer is already |
| /// closed this has no effect (idempotent). |
| CloseSingleBuffer(uint64 buffer_index); |
| |
| /// This allocates a new buffer that is consistent with the most recent call |
| /// to SetConstraints(), if possible. If not possible, this indicates the |
| /// failure via OnNewBufferAllocated(). |
| /// |
| /// Only a participant with write can do this. Coordination among multiple |
| /// participants with write is outside the scope of this interface. |
| /// |
| /// The participant is (intentionally) never informed of other participant's |
| /// constraints. |
| AllocateSingleBuffer(uint64 buffer_index); |
| |
| /// Completes when AllocateBuffer is done. Callers who wish to avoid |
| /// blocking a thread while waiting can use OnAllocateSingleBufferDone() |
| /// instead. |
| WaitForSingleBufferAllocated(uint64 buffer_index) |
| -> (zx.status status, SingleBufferInfo buffer_info); |
| |
| /// A participant can use this message to have sysmem verify that this |
| /// buffer_index exists. This message is intentionally ignored by the |
| /// server if the buffer_index _does_ exist. In that case, the client will |
| /// see OnAllocateSingleBufferDone() soon with status == `ZX_OK` (if the |
| /// client hasn't already seen that message). If on the other hand the |
| /// buffer_index does not exist, this message causes the server to send |
| /// OnAllocateSingleBufferDone() with status == `ZX_ERR_NOT_FOUND`. A |
| /// particpant will typically use this when the participant receives a new |
| /// buffer_index that the participant doesn't yet know about, to ensure that |
| /// the participant won't be waiting forever for the |
| /// OnAllocateSingleBufferDone() message regarding this buffer_index. |
| CheckSingleBufferAllocated(uint64 buffer_index); |
| |
| /// The server handles unexpected failure of a BufferCollection by failing |
| /// the whole LogicalBufferCollection. Partly this is to expedite closing |
| /// VMO handles. If a participant would like to cleanly close a |
| /// BufferCollection view without causing LogicalBufferCollection failure, |
| /// the participant can send Close() before closing the client end of the |
| /// BufferCollection channel. If this is the last BufferCollection view, the |
| /// LogicalBufferCollection will still go away. |
| Close(); |
| |
| /// Set a name for VMOs in this buffer collection. The name may be truncated shorter. The name |
| /// only affects VMOs allocated after it's set - this call does not rename existing VMOs. If |
| /// multiple clients set different names then the larger priority value will win. |
| SetName(uint32 priority, string:64 name); |
| |
| /// See BufferCollectionToken.SetClientDebugInfo. |
| SetDebugClientInfo(string:64 name, uint64 id); |
| |
| /// Optionally sent before SetConstraints() to set constraints related to |
| /// clear (not encrypted, not in protected/secure memory) aux buffers. This |
| /// is only valid when sent before SetConstraints(). Invalid settings may |
| /// not result in channel closure until SetConstraints() is received by |
| /// sysmem. |
| SetConstraintsAuxBuffers( |
| BufferCollectionConstraintsAuxBuffers constraints); |
| |
| /// Allows getting any aux buffers allocated after using |
| /// SetConstraintsAuxBuffers(). |
| /// |
| /// Sending this message is not permitted until at least one of the |
| /// following has occurred: |
| /// * WaitForBuffersAllocated() completing |
| /// * OnBuffersAllocated() being received |
| /// |
| /// On failure, status will be a failing status and |
| /// buffer_collection_info_aux_buffers won't be filled out, and won't have |
| /// any handles. |
| /// |
| /// On success, status will be ZX_OK, and buffer_count will be the same as |
| /// the main buffer_count from WaitForBuffersAllocated() or |
| /// OnBuffersAllocated(). |
| /// |
| /// If a participant specified "allow_clear_aux_buffers_for_secure" true but |
| /// "need_clear_aux_buffers_for_secure" false (or not set), the participant |
| /// can determine if aux buffers were allocated by looking at buffer[0].vmo. |
| /// If buffer 0 has no vmo, aux VMOs were not allocated. The resulting |
| /// status will still be ZX_OK in this case, and buffer_count will still be |
| /// filled out to match the main buffer_count. |
| /// |
| /// It's legal for a participant that set |
| /// "allow_clear_aux_buffers_for_secure" false to call GetAuxBuffers(), in |
| /// which case buffer[0].vmo will not be set. |
| GetAuxBuffers() |
| -> (zx.status status, |
| BufferCollectionInfo_2 buffer_collection_info_aux_buffers); |
| }; |
| |
| /// This interface intentionally doesn't include any event for |
| /// OnOldBufferClosed(), because such an event could arrive at a participant too |
| /// soon to be useful. Instead, such an indication should be made in-band within |
| /// FIDL interfaces that deliver packets to downstream participants. |
| [Discoverable, ForDeprecatedCBindings] |
| protocol BufferCollectionEvents { |
| /// See comments on BufferCollectionToken::Sync(). |
| /// |
| /// This message only indicates that the server has reached the point where |
| /// it knows about previously created tokens Duplicate()ed from the token |
| /// used to create this BufferCollection. |
| OnDuplicatedTokensKnownByServer(); |
| |
| /// This event inidicates that buffer allocation is over, whether succesful |
| /// or failed. |
| /// |
| /// This event will eventually be sent by the server (unless the |
| /// BufferCollection channel closes first). |
| /// |
| /// `status`: |
| /// `ZX_OK` if successful. |
| /// `ZX_ERR_NO_MEMORY` if the request is valid but cannot be fulfilled due to |
| /// resource exhaustion. |
| /// `ZX_ERR_ACCESS_DENIED` if the caller is not permitted to obtain the |
| /// buffers it requested. |
| /// `ZX_ERR_INVALID_ARGS` if the request is malformed. |
| /// `ZX_ERR_NOT_SUPPORTED` if request is valid but cannot be satisfied, |
| /// perhaps due to hardware limitations. |
| /// |
| /// `buffer_collection_info` The buffer information, including VMO handles. |
| /// If `status` is not `ZX_OK`, `buffer_collection_info` is default |
| /// initialized and contains no meaningful information. |
| OnBuffersAllocated(zx.status status, |
| BufferCollectionInfo_2 buffer_collection_info); |
| |
| /// A participant can learn when a new buffer is allocated via this event. |
| /// The only participant that will see a failing status is the participant |
| /// that attempted the single buffer allocation. Other participants will |
| /// only see successful single buffer allocations. |
| /// |
| /// `status`: |
| /// |
| /// `ZX_OK` if successful. This can be seen by any participant (whether |
| /// sender of AllocateSingleBuffer() or not.) |
| /// |
| /// `ZX_ERR_NOT_FOUND` if the buffer_index sent via |
| /// CheckSingleBufferAllocated() isn't known to the server. This can be seen |
| /// by any participant (whether sender of AllocateSingleBuffer() or not.) |
| /// |
| /// These error codes are only ever seen by the sender of |
| /// AllocateSingleBuffer(): |
| /// |
| /// `ZX_ERR_NO_MEMORY` if the request is valid but cannot be fulfilled due to |
| /// resource exhaustion. |
| /// `ZX_ERR_ACCESS_DENIED` if the caller is not permitted to obtain the |
| /// buffers it requested. |
| /// `ZX_ERR_INVALID_ARGS` if the request is malformed. |
| /// `ZX_ERR_NOT_SUPPORTED` if request is valid but cannot be satisfied, |
| /// perhaps due to hardware limitations. |
| OnAllocateSingleBufferDone(zx.status status, |
| SingleBufferInfo buffer_info); |
| }; |