PSA: New C++ FIDL server APIs (alternative to BindServer)

26 views
Skip to first unread message

Yifei Teng

unread,
Dec 5, 2022, 6:18:16 PM12/5/22
to fidl-dev

Please read on if you use the new C++ FIDL bindings (aka LLCPP).


TLDR: if you've enjoyed the fidl::Binding from HLCPP, now there's a counterpart in the new C++ bindings fidl::ServerBinding. We also improved fidl::BindServer along the way.

fidl::ServerBinding

fidl::ServerBinding<Protocol> owns a FIDL server connection. When creating a binding, you would specify a pointer to the server implementation. Destroying the binding synchronously stops message dispatch and the FIDL runtime would no longer access the server implementation. Thus the idiomatic usage of a ServerBinding is to ensure that they're destroyed together, for example by embedding the binding as a member variable of a server implementation:


// Example of implementing the `fuchsia.my.library/MyProtocol` protocol with natural types.

//

// |binding_| owns the connection and borrows the containing |Impl| object.

class Impl : public fidl::Server<fuchsia_my_library::MyProtocol> {

 public:

  Impl(fidl::ServerEnd<fuchsia_my_library::Protocol> server_end, async_dispatcher_t* dispatcher)

      : binding_(dispatcher, std::move(server_end), this, std::mem_fn(&Impl::OnFidlClosed)) {}


  void OnFidlClosed(fidl::UnbindInfo info) override {

    // Handle connection closing..

  }


  // More method implementations omitted...

 private:

  fidl::ServerBinding<fuchsia_my_library::MyProtocol> binding_;

};


The last argument of a ServerBinding constructor is a CloseHandler, which is a callable that takes fidl::UnbindInfo. The close handler is invoked whenever the connection is closed due to errors or because the user initiated closing via a completer, unless the binding object is destroyed.


Therefore, under the idiomatic usage style above, the CloseHandler always notifies the server of connection closure, unless the user destroyed the server object proactively, in which case CloseHandler is discarded to prevent use-after-free errors. This could be a useful funnel to manage other kinds of resources whose lifecycle is tied to a FIDL connection.


Folks who have used fidl::BindServer may be familiar with some of its limitations:


  • fidl::BindServer returns a fidl::ServerBindingRef<Protocol> that does not own the connection. Discarding a server binding ref does nothing.

  • fidl::BindServer takes an on-unbound callback that is called asynchronously after unbinding completes and at which point the server object may already be destroyed, thus susceptible to use-after-free errors.


Those limitations were because fidl::BindServer was designed to support multithreaded usage and for a model where the binding owns the server object, which doesn't apply to all the FIDL server scenarios. With fidl::ServerBinding, we are addressing both limitations and filling the gap where the server object would like to own the binding instead. Both APIs are here to stay, and complement each other.


Head over to the FIDL examples to see how to use fidl::ServerBinding in a non-trivial application.


Finally, in order to guarantee that message dispatch is synchronously stopped when the binding is destroyed, fidl::ServerBinding does not support multithreaded/parallel usages. It is thread-unsafe, and would panic if it detects certain patterns of parallel access.

fidl::BindServer

fidl::BindServer can now infer the protocol from the provided server endpoint argument. Previously, if you would like to implement two FIDL protocols on the same server implementation object, calls to fidl::BindServer became ambiguous. Now fidl::BindServer is able to figure out which "facet" of the server implementation it should bind to, based on the protocol type inside the fidl::ServerEnd<SomeProtocol> endpoint argument. Unless you are working with code that has not migrated to typed channels, there is no need to explicitly add a template parameter when calling fidl::BindServer.


See the migrations in this CL for more details.

Driver FIDL bindings

Both improvements above apply to driver FIDL bindings in the V2 driver runtime. For example, you may use fdf::ServerBinding if you were previously using fdf::BindServer.

Questions and feedback

We're happy to answer or discuss them at fidl...@fuchsia.dev.



Cheers,

Yifei


Abdulla Kamar

unread,
Dec 5, 2022, 8:15:03 PM12/5/22
to Yifei Teng, fidl-dev
In the Canvas example, you have "new InstanceImpl". Is the type stored derived from the return type? That is to say, can I use a unique_ptr instead of a raw ptr?

--
All posts must follow the Fuchsia Code of Conduct https://fuchsia.dev/fuchsia-src/CODE_OF_CONDUCT or may be removed.
---
You received this message because you are subscribed to the Google Groups "fidl-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fidl-dev+u...@fuchsia.dev.
To view this discussion on the web visit https://groups.google.com/a/fuchsia.dev/d/msgid/fidl-dev/CANbn4XASPpoKYuAmnwJ8i_TbcUj6CiPSwnG2URAi4RUdAw%3DQ-g%40mail.gmail.com.

Yifei Teng

unread,
Dec 5, 2022, 8:35:04 PM12/5/22
to Abdulla Kamar, fidl-dev
`fidl::ServerBinding` only supports raw pointers to the server implementation, since it's intended to be owned by the server implementation. Though, that does not exclude using a `std::unique_ptr<Impl>` to manage the server implementation. The binding would be owned by the `Impl` which is in turn owned by the unique pointer.

If you need instead the binding to own the server (e.g. if the connection is closed, then the server is automatically destroyed), consider using `fidl::BindServer` which can take ownership of a `std::unique_ptr<Impl>`. Would that work for your case?

Cheers,
Yifei
Reply all
Reply to author
Forward
0 new messages