| // Copyright 2022 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.component.sandbox; |
| |
| using zx; |
| using fuchsia.io; |
| |
| /// Maximum number of bytes in a [Data]. |
| @available(added=HEAD) |
| const MAX_DATA_LENGTH uint32 = 8192; |
| |
| /// A token represents a bedrock object. Tokens are reference counted, dropping |
| /// all counts of the token removes the object. |
| @available(added=HEAD) |
| alias Token = zx.Handle:EVENTPAIR; |
| |
| /// Maximum number of items returned by dictionary iterator. |
| @available(added=HEAD) |
| const MAX_DICTIONARY_ITERATOR_CHUNK uint32 = 128; |
| |
| @available(added=HEAD) |
| type Data = flexible union { |
| 1: bytes vector<byte>:MAX_DATA_LENGTH; |
| 2: string string:MAX_DATA_LENGTH; |
| 3: int64 int64; |
| 4: uint64 uint64; |
| }; |
| |
| @available(added=HEAD) |
| type Connector = resource struct { |
| token Token; |
| }; |
| |
| @available(added=HEAD) |
| type DirConnector = resource struct { |
| token Token; |
| }; |
| |
| @available(added=HEAD) |
| type DirEntry = resource struct { |
| token Token; |
| }; |
| |
| @available(added=HEAD) |
| type DictionaryRef = resource struct { |
| token Token; |
| }; |
| |
| @available(added=HEAD) |
| type Unit = struct {}; |
| |
| @available(added=HEAD) |
| type Capability = flexible resource union { |
| 1: unit Unit; |
| 2: handle zx.Handle; |
| 3: data Data; |
| 4: dictionary DictionaryRef; |
| 5: connector Connector; |
| 6: dir_connector DirConnector; |
| 7: directory client_end:fuchsia.io.Directory; |
| 8: dir_entry DirEntry; |
| 9: connector_router client_end:ConnectorRouter; |
| 10: dictionary_router client_end:DictionaryRouter; |
| 11: dir_entry_router client_end:DirEntryRouter; |
| 12: data_router client_end:DataRouter; |
| 13: dir_connector_router client_end:DirConnectorRouter; |
| }; |
| |
| /// The maximum length of a dictionary key. This should coincide with |
| /// fuchsia.component.MAX_NAME_LENGTH. |
| @available(added=HEAD) |
| const MAX_NAME_LENGTH uint64 = fuchsia.io.MAX_NAME_LENGTH; |
| |
| /// The key of a [`DictionaryItem`]. The constraints for valid keys are documented at |
| /// https://fuchsia.dev/reference/cml#names. |
| @available(added=HEAD) |
| alias DictionaryKey = string:MAX_NAME_LENGTH; |
| |
| /// A key-value pair in a [`DictionaryRef`]. |
| @available(added=HEAD) |
| type DictionaryItem = struct { |
| key DictionaryKey; |
| value CapabilityId; |
| }; |
| |
| /// A key-value pair in a [`DictionaryRef`], where the value may be elided. |
| /// This is useful for APIs that may wish to omit the value, for example if it could not be |
| /// duplicated. |
| @available(added=HEAD) |
| type DictionaryOptionalItem = resource struct { |
| key DictionaryKey; |
| value box<WrappedCapabilityId>; |
| }; |
| |
| /// Error returned from [CapabilityStore/Dictionary*] methods. |
| @available(added=HEAD) |
| type DictionaryError = flexible enum { |
| /// The Dictionary does not contain an item with the given key. |
| NOT_FOUND = 1; |
| |
| /// The Dictionary already contains an item with the given key. |
| ALREADY_EXISTS = 2; |
| |
| /// The Capability is invalid. |
| /// |
| /// Capabilities must be created by sandbox, via |
| /// `fuchsia.component.sandbox/CapabilityStore` or returned from other |
| /// Component Framework APIs. |
| BAD_CAPABILITY = 3; |
| |
| /// The key is invalid. The constraints for valid keys are documented at |
| /// https://fuchsia.dev/reference/cml#names. |
| INVALID_KEY = 4; |
| |
| /// A capability that needed to be cloned to perform this operation could |
| /// not be cloned. |
| NOT_CLONEABLE = 5; |
| }; |
| |
| @discoverable(server="platform") |
| @available(added=20) |
| open protocol Dictionary {}; |
| |
| /// A client-assigned id of a [Capability] in a [CapabilityStore]. |
| /// |
| /// The id is relative to the [CapabilityStore]. In the case where two |
| /// [CapabilityStore]s have a capability / assigned to the same id, there is |
| /// no relation between them |
| @available(added=HEAD) |
| alias CapabilityId = uint64; |
| |
| /// A client-assigned id of a new [Capability] in a [CapabilityStore]. Same as [CapabilityId], |
| /// but used to distinguish output parameters in [CapabilityStore] methods. |
| @available(added=HEAD) |
| alias NewCapabilityId = CapabilityId; |
| |
| /// A [CapabilityId] wrapped in a struct. This is useful for putting a [CapabilityId] in a `box<>`, |
| /// which FIDL does not allow for pure integral types. |
| @available(added=HEAD) |
| type WrappedCapabilityId = struct { |
| id CapabilityId; |
| }; |
| |
| @available(added=HEAD) |
| alias WrappedNewCapabilityId = WrappedCapabilityId; |
| |
| /// Protocol that represents the concept of a "capability store", a repository |
| /// for [Capability]s that are held by the component framework runtime. |
| /// |
| /// [CapabilityStore] serves as the main bridge between the component runtime and clients |
| /// that enables them to operate on and exchange [Capability]s. A [CapabilityStore] instance |
| /// contains a set of [Capability]s, each of which has a [CapabilityId] assigned by the client. |
| /// |
| /// Normally, a program would not exchange a [CapabilityStore] or [CapabilityId] with other |
| /// programs -- a [CapabilityStore] connection and its enclosed capabilities are intended to |
| /// be "local" to a program. Instead, if a program wishes to exchange a [Capability] with other |
| /// programs, it should [Export] the [Capability] out of the store, send the [Capability] to the |
| /// target program, which can then [Import] the capability into its own store. |
| /// |
| /// [CapabilityStore] is also used to manage capability lifetimes. The lifetime of a capability is |
| /// scoped to the [CapabilityStore] in which it resides; i.e. to drop the [CapabilityStore] |
| /// connections to release the capabilities instead it. In addition, [CapabilityStore] supports a |
| /// [Drop] API to drop an individual [Capability] reference. (Note that it is possible for a |
| /// some capabilities, like [DictionaryRef], to have multiple references, in which case all of |
| /// the references must be dropped for the underlying resource to be released.) |
| /// |
| /// A note about semantics: the [CapabilityStore] APIs do not return [CapabilityId]s, because |
| /// [CapabilityId]s are assigned by the client. Instead, when a method would semantically return |
| /// a capability, this is expressed by taking the destination [CapabilityId] as an output parameter. |
| @discoverable(server="platform") |
| @available(added=HEAD) |
| open protocol CapabilityStore { |
| /// Duplicates the capability with `id` to `dest_id`. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_NOT_FOUND` if `id` was not a valid capability id in this store. |
| /// - `ID_ALREADY_EXISTS` if a capability with `dest_id` already exists in this store. |
| /// - `NOT_DUPLICATABLE` if `id` could not be duplicated. |
| flexible Duplicate(struct { |
| id CapabilityId; |
| dest_id NewCapabilityId; |
| }) -> () error CapabilityStoreError; |
| |
| /// Drops the capability with `id` from this [`CapabilityStore`]. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_NOT_FOUND` if `id` was not a valid capability id in this store. |
| flexible Drop(struct { |
| id CapabilityId; |
| }) -> () error CapabilityStoreError; |
| |
| /// Exports the capability with the client-assigned identifier `id` to |
| /// `capability`. This operation removes the capability from the store. If |
| /// this is not desired, [Duplicate] the capability first. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_NOT_FOUND` if `id` was not a valid capability id in this store. |
| flexible Export(struct { |
| id CapabilityId; |
| }) -> (resource struct { |
| capability Capability; |
| }) error CapabilityStoreError; |
| |
| /// Imports `capability` into this store with the client-assigned `id`. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_ALREADY_EXISTS` if a capability with `id` already exists in this store. |
| /// - `BAD_CAPABILITY` if `capability` was not a valid [Capability]. |
| flexible Import(resource struct { |
| id NewCapabilityId; |
| capability Capability; |
| }) -> () error CapabilityStoreError; |
| |
| /// Creates a [Connector] from a [Receiver]. Incoming connections to the [Connector] will be |
| /// dispatched to this [Receiver]. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_ALREADY_EXISTS` if a capability with `id` already exists in this store. |
| flexible ConnectorCreate(resource struct { |
| id NewCapabilityId; |
| receiver client_end:Receiver; |
| }) -> () error CapabilityStoreError; |
| |
| /// Open a connection from the provided [Connector] capability that will be dispatched to |
| /// the [Receiver] on the other end. |
| /// |
| /// If there is an error, it will be reported as a zx.Status epitaph on `server_end`. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_NOT_FOUND` if `id` was not a valid capability id in this store. |
| /// - `WRONG_TYPE` if `id` was not a connector capability. |
| flexible ConnectorOpen(resource struct { |
| id CapabilityId; |
| server_end zx.Handle:CHANNEL; |
| }) -> () error CapabilityStoreError; |
| |
| /// Creates a [DirConnector] from a [DirReceiver]. Incoming connections to the [DirConnector] |
| /// will be dispatched to this [DirReceiver]. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_ALREADY_EXISTS` if a capability with `id` already exists in this store. |
| flexible DirConnectorCreate(resource struct { |
| id NewCapabilityId; |
| receiver client_end:DirReceiver; |
| }) -> () error CapabilityStoreError; |
| |
| /// Open a connection from the provided [DirConnector] capability that will be dispatched to |
| /// the [DirReceiver] on the other end. |
| /// |
| /// This method does not take `Open`/`Open3` parameters such as `flags` or `path`. |
| /// Clients that wish to specify these can get an initial connection from this method |
| /// and call `fuchsia.io/Directory.Open` on it. See the [DirReceiver] documentation for |
| /// more information about the expectations of the server side. |
| /// |
| /// If there was an error making the connection, it will be reported as a zx.Status |
| /// epitaph on `server_end`. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_NOT_FOUND` if `id` was not a valid capability id in this store. |
| /// - `WRONG_TYPE` if `id` was not a connector capability. |
| flexible DirConnectorOpen(resource struct { |
| id CapabilityId; |
| server_end server_end:fuchsia.io.Directory; |
| }) -> () error CapabilityStoreError; |
| |
| /// Creates a new empty dictionary in this [`CapabilityStore`] with client-assigned `id`. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_ALREADY_EXISTS` if a capability with `id` already exists in this store. |
| flexible DictionaryCreate(struct { |
| id CapabilityId; |
| }) -> () error CapabilityStoreError; |
| |
| /// Imports a dictionary in the form of a channel. |
| /// |
| /// This is a legacy API to support backward compatibility with APIs that take a [Dictionary] |
| /// channel. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_ALREADY_EXISTS` if a capability with `id` already exists in this store. |
| /// - `BAD_CAPABILITY` if `client_end` was not a valid dictionary channel. |
| flexible DictionaryLegacyImport(resource struct { |
| id NewCapabilityId; |
| client_end zx.Handle:CHANNEL; |
| }) -> () error CapabilityStoreError; |
| |
| /// Binds a channel to the dictionary with `id`. The channel can |
| /// be re-imported into a [CapabilityStore] with [DictionaryImportLegacy]. |
| /// |
| /// This is a legacy API to support backward compatibility with APIs that take a [Dictionary] |
| /// channel. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_NOT_FOUND` if `id` was not a valid capability id in this store. |
| flexible DictionaryLegacyExport(resource struct { |
| id CapabilityId; |
| server_end zx.Handle:CHANNEL; |
| }) -> () error CapabilityStoreError; |
| |
| /// Inserts `item` into the dictionary with `id`. `item.value` is moved into the dictionary and |
| /// its id is released if this call succeeds. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_NOT_FOUND` if `id` was not a valid capability id in this store. |
| /// - `WRONG_TYPE` if `id` was not a dictionary. |
| /// - `INVALID_KEY` if `item.key` was invalid. |
| /// - `ITEM_ALREADY_EXISTS` if the dictionary already contains an item with `item.key`. |
| flexible DictionaryInsert(struct { |
| id CapabilityId; |
| item DictionaryItem; |
| }) -> () error CapabilityStoreError; |
| |
| /// Get a duplicate of a capability from the dictionary with `id`, which is |
| /// loaded into `dest_id`. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_NOT_FOUND` if `id` was not a recognized capability id in this store. |
| /// - `ID_ALREADY_EXISTS` if a capability with `dest_id` already exists in this store. |
| /// - `WRONG_TYPE` if `id` was not a dictionary. |
| /// - `INVALID_KEY` if `item.key` was invalid. |
| /// - `ITEM_NOT_FOUND` if the dictionary does not contain `key`. |
| /// - `NOT_DUPLICATABLE` if the capability could not be duplicated. |
| flexible DictionaryGet(struct { |
| id CapabilityId; |
| key DictionaryKey; |
| dest_id NewCapabilityId; |
| }) -> () error CapabilityStoreError; |
| |
| /// Removes a key from the dictionary with `id`. If `dest_id` is present, loads the value |
| /// into it, otherwise discards the value. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_NOT_FOUND` if `id` was not a valid capability id in this store. |
| /// - `ID_ALREADY_EXISTS` if a capability with `dest_id` already exists in this store. |
| /// - `WRONG_TYPE` if `id` was not a dictionary. |
| /// - `INVALID_KEY` if `key` was invalid. |
| /// - `ITEM_NOT_FOUND` if the dictionary does not contain the key. |
| flexible DictionaryRemove(struct { |
| id CapabilityId; |
| key DictionaryKey; |
| dest_id box<WrappedNewCapabilityId>; |
| }) -> () error CapabilityStoreError; |
| |
| /// Create a new dictionary that contains a duplicate of all the entries in |
| /// the dictionary with `id`, assigning `dest_id` to the new dictionary. |
| /// The runtime of this method is linear in the number of top-level entries |
| /// in the dictionary. |
| /// |
| /// For example, if the dictionary contains nested dictionaries, the newly |
| /// created dictionary will contain references to those same nested |
| /// dictionaries because the entries are duplicated rather than deep-copied. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_NOT_FOUND` if `id` was not a valid capability id in this store. |
| /// - `ID_ALREADY_EXISTS` if a capability with `dest_id` already exists in this store. |
| /// - `WRONG_TYPE` if `id` was not a dictionary. |
| /// - `NOT_DUPLICATABLE` if one of the capabilities in `id` could not be duplicated. |
| flexible DictionaryCopy(struct { |
| id CapabilityId; |
| dest_id NewCapabilityId; |
| }) -> () error CapabilityStoreError; |
| |
| /// Enumerates the keys in the dictionary with `id`. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_NOT_FOUND` if `id` was not a valid capability id in this store. |
| /// - `WRONG_TYPE` if `id` was not a dictionary. |
| flexible DictionaryKeys(resource struct { |
| id CapabilityId; |
| iterator server_end:DictionaryKeysIterator; |
| }) -> () error CapabilityStoreError; |
| |
| /// Enumerates the items (keys and values) in the dictionary with `id`. |
| /// |
| /// Creates a duplicate of each value (capability). If a value could not be duplicated, |
| /// the value will be null. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_NOT_FOUND` if `id` was not a valid capability id in this store. |
| /// - `WRONG_TYPE` if `id` was not a dictionary. |
| flexible DictionaryEnumerate(resource struct { |
| id CapabilityId; |
| iterator server_end:DictionaryEnumerateIterator; |
| }) -> () error CapabilityStoreError; |
| |
| /// Removes all the entries in this dictionary, returning them in `contents` if provided. |
| /// If `contents` is not provided, all the items are discarded without enumerating them. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_NOT_FOUND` if `id` was not a valid capability id in this store. |
| /// - `WRONG_TYPE` if `id` was not a dictionary. |
| flexible DictionaryDrain(resource struct { |
| id CapabilityId; |
| iterator server_end:<DictionaryDrainIterator, optional>; |
| }) -> () error CapabilityStoreError; |
| }; |
| |
| /// Error returned from methods in [CapabilityStore]. |
| @available(added=HEAD) |
| type CapabilityStoreError = flexible enum { |
| /// A capability was not found matching the given key or [CapabilityId]. |
| ID_NOT_FOUND = 1; |
| |
| /// A capability already exists matching the given key or [CapabilityId]. |
| ID_ALREADY_EXISTS = 2; |
| |
| /// A [Capability] was not valid. For example, a `Capability.Dictionary` |
| /// contained an invalid [DictionaryRef]. |
| BAD_CAPABILITY = 3; |
| |
| /// A [CapabilityId] had the wrong type for the requested operation. |
| WRONG_TYPE = 4; |
| |
| /// A capability that needed to be duplicated to perform this operation could |
| /// not be. |
| NOT_DUPLICATABLE = 5; |
| |
| /// An item in a dictionary was not found matching the given key. |
| ITEM_NOT_FOUND = 6; |
| |
| /// An item in a dictionary already exists with the given key. |
| ITEM_ALREADY_EXISTS = 7; |
| |
| /// The key is invalid. The constraints for valid keys are documented at |
| /// https://fuchsia.dev/reference/cml#names. |
| INVALID_KEY = 8; |
| |
| /// One or more arguments were invalid. |
| INVALID_ARGS = 9; |
| }; |
| |
| @available(added=HEAD) |
| open protocol DictionaryKeysIterator { |
| flexible GetNext() -> (resource struct { |
| keys vector<DictionaryKey>:MAX_DICTIONARY_ITERATOR_CHUNK; |
| }); |
| }; |
| |
| @available(added=HEAD) |
| open protocol DictionaryEnumerateIterator { |
| /// Returns the next batch of results for a [Dictionary.Enumerate] call, returning up to |
| /// `limit` results. `limit` can be at most [MAX_DICTIONARY_ITERATOR_CHUNK]. |
| /// |
| /// The value of each of `items` is a duplicate of the original capability |
| /// ([CapabilityStore.Duplicate]), unless it could not be duplicated, it which case it will |
| /// be null. |
| /// |
| /// Each returned capability will be assigned a monotonically increasing [CapabilityId] starting |
| /// from `start_id`. |
| /// |
| /// In addition to the `items`, returns `end_id`, which is one more than the highest id reserved |
| /// by [GetNext]. `end_id` can be used as the `start_id` for the next call to [GetNext]. |
| /// |
| /// If [GetNext] returns an error, the server will also close the channel. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_ALREADY_EXISTS` if some id in the range `[start_id, limit)` already exists in this |
| /// store. |
| /// - `INVALID_ARGS` if `limit` was `0` or greater than `MAX_DICTIONARY_ITERATOR_CHUNK`. |
| flexible GetNext(struct { |
| start_id CapabilityId; |
| limit uint32; |
| }) -> (resource struct { |
| items vector<DictionaryOptionalItem>:MAX_DICTIONARY_ITERATOR_CHUNK; |
| end_id CapabilityId; |
| }) error CapabilityStoreError; |
| }; |
| |
| @available(added=HEAD) |
| open protocol DictionaryDrainIterator { |
| /// Returns the next batch of results for a [Dictionary.Drain] call, returning up to |
| /// `limit` results. `limit` can be at most [MAX_DICTIONARY_ITERATOR_CHUNK]. |
| /// |
| /// Each returned capability will be assigned a monotonically increasing [CapabilityId] starting |
| /// from `start_id`. |
| /// |
| /// In addition to the `items`, returns `end_id`, which is one more than the highest id reserved |
| /// by [GetNext]. `end_id` can be used as the `start_id` for the next call to [GetNext]. |
| /// |
| /// If [GetNext] returns an error, the server will also close the channel. |
| /// |
| /// Errors: |
| /// |
| /// - `ID_ALREADY_EXISTS` if some id in the range `[start_id, limit)` already exists in this |
| /// store. |
| /// - `INVALID_ARGS` if `limit` was `0` or greater than `MAX_DICTIONARY_ITERATOR_CHUNK`. |
| flexible GetNext(struct { |
| start_id CapabilityId; |
| limit uint32; |
| }) -> (resource struct { |
| items vector<DictionaryItem>:MAX_DICTIONARY_ITERATOR_CHUNK; |
| end_id CapabilityId; |
| }) error CapabilityStoreError; |
| }; |
| |
| /// Represents an instance in the component tree, either a component |
| /// instance or component manager's instance. |
| @available(added=HEAD) |
| type InstanceToken = resource struct { |
| token Token; |
| }; |
| |
| /// A request for a route. |
| @available(added=HEAD) |
| type RouteRequest = resource table { |
| /// The component that is requesting the capability. May be omitted for a default request |
| /// (see `*Router.Route`). |
| 1: requesting InstanceToken; |
| /// Metadata associated with this capability request. May be omitted for a default request |
| /// (see `*Router.Route`). |
| 2: metadata DictionaryRef; |
| }; |
| |
| @available(added=HEAD) |
| type RouterError = flexible enum : uint32 { |
| /// The router failed to find the capability. |
| NOT_FOUND = 1; |
| |
| /// The arguments provided to the function are invalid. |
| INVALID_ARGS = 2; |
| |
| /// The operation is not supported. |
| NOT_SUPPORTED = 3; |
| |
| /// An internal error occurred. |
| INTERNAL = 4; |
| }; |
| |
| @available(added=HEAD) |
| type Unavailable = struct {}; |
| |
| @discoverable |
| @available(added=HEAD) |
| open protocol ConnectorRouter { |
| flexible Route(RouteRequest) -> (strict resource union { |
| 1: connector Connector; |
| 2: unavailable Unit; |
| }) error RouterError; |
| }; |
| |
| @discoverable |
| @available(added=HEAD) |
| open protocol DictionaryRouter { |
| flexible Route(RouteRequest) -> (strict resource union { |
| 1: dictionary DictionaryRef; |
| 2: unavailable Unit; |
| }) error RouterError; |
| }; |
| |
| |
| @discoverable |
| @available(added=HEAD) |
| open protocol DirectoryRouter { |
| flexible Route(RouteRequest) -> (strict resource union { |
| 1: directory client_end:fuchsia.io.Directory; |
| 2: unavailable Unit; |
| }) error RouterError; |
| }; |
| |
| @discoverable |
| @available(added=HEAD) |
| open protocol DirEntryRouter { |
| flexible Route(RouteRequest) -> (strict resource union { |
| 1: dir_entry DirEntry; |
| 2: unavailable Unit; |
| }) error RouterError; |
| }; |
| |
| @discoverable |
| @available(added=HEAD) |
| open protocol DataRouter { |
| flexible Route(RouteRequest) -> (strict resource union { |
| 1: data Data; |
| 2: unavailable Unit; |
| }) error RouterError; |
| }; |
| |
| @discoverable |
| @available(added=HEAD) |
| open protocol DirConnectorRouter { |
| flexible Route(RouteRequest) -> (strict resource union { |
| 1: dir_connector DirConnector; |
| 2: unavailable Unit; |
| }) error RouterError; |
| }; |
| |
| /// A receiver is served by components and allows them to receive channels |
| /// from the framework. |
| @discoverable(client="platform") |
| @available(added=HEAD) |
| open protocol Receiver { |
| /// Sends a channel to this receiver. |
| flexible Receive(ProtocolPayload); |
| }; |
| |
| /// A receiver is served by components and allows them to receive directory channels |
| /// framework. |
| @discoverable(client="platform") |
| @available(added=HEAD) |
| open protocol DirReceiver { |
| /// Sends a directory channel to this receiver. |
| /// |
| /// The server should implement this method by forwarding `channel` to a vfs instance |
| /// of the language appropriate `vfs` library. To keep this interface decoupled from |
| /// `fuchsia.io`, it deliberately omits `Open`/`Open3` parameters such as `flags` and |
| /// `path`. If a client wishes to specify these, they can obtain an initial |
| /// [fuchsia.io/Directory] channel first and then call `Open`/`Open3` on it. |
| flexible Receive(resource struct { |
| channel server_end:fuchsia.io.Directory; |
| }); |
| }; |
| |
| /// Contains a protocol open request. |
| @available(added=HEAD) |
| type ProtocolPayload = resource struct { |
| channel zx.Handle:CHANNEL; |
| }; |