ANDROID: rust_binder: add nodes and context managers
An important concept for the binder driver is a "node", which is a type
of object defined by the binder driver that serves as a "binder server".
Whenever you send a transaction, the recipient will be a node.
Binder nodes can exist in many processes. The driver keeps track of this
using two fields in `Process`.
* The `nodes` rbtree. This structure stores all nodes that this process
is the primary owner of. The `process` field of the `Node` struct
will point at the process that has it in its `nodes` rbtree.
* The `node_refs` collection. This keeps track of the nodes from other
processes that this process holds a reference to. A process can only
send transactions to nodes in this collection.
From userspace, we also make a distinction between local nodes owned by
the process itself, and proxy nodes that are owned by a different
process. Generally, a process will refer to local nodes using the
address of the corresponding userspace object, and it will refer to
proxy nodes using a 32-bit id that the kernel assigns to the node. The
32-bit ids are local to each process, so the same node can have a
different 32-bit id in each external process that has a reference to it.
Additionally, a node can also be stored in the context as the "context
manager". There will only be one context manager for each context (that
is, for each file in `/dev/binderfs`). The context manager implicitly
has the id 0 in every other process, which means that all processes are
able to access it by default.
In a later patch, we will add the ability to send nodes from one process
to another as part of a transaction. When this happens, the node is
added to the `node_refs` collection of the target process, and the
process will be able to start using it from then on. Except for the
context manager node, sending nodes in this way is the *only* way for a
process to obtain a reference to a node defined by another process.
Generally, userspace processes are expected to send their nodes to the
context manager process so that the context manager can pass it on to
clients that want to connect to it.
Binder nodes are reference counted through the kernel. This generally
happens in the following manner:
1. Process A owns a binder node, which it stores in an allocation in
userspace. This allocation is reference counted.
2. The kernel owns a `Node` object that holds a reference count to the
userspace object in process A. Changes to this reference count are
communicated to process A using the commands BR_ACQUIRE, BR_RELEASE,
BR_INCREFS, and BR_DECREFS.
3. Other parts of the kernel own a `NodeRef` object that holds a
reference count to the `Node` object. Destroying a `NodeRef` will
decrement the refcount of the associated `Node` in the appropriate
way.
4. Process B owns a proxy node, which is a userspace object. Using a
32-bit id, this proxy node refers to a `NodeRef` object in the
kernel. When the proxy node is destroyed, userspace will use the
commands BC_ACQUIRE, BC_RELEASE, BC_INCREFS, and BC_DECREFS to tell
the kernel to modify the refcount on the `NodeRef` object.
Via the above chain, process B can own a refcount that keeps a node in
process A alive.
There can also be other things than processes than own a `NodeRef`. For
example, the context holds a `NodeRef` to the context manager node. This
keeps the node alive, even if there are no other processes with a
reference to it. In a later patch, we will see other instances of this -
for example, a transaction's allocation will also own a `NodeRef` to any
nodes embedded in it so that they don't go away while the process is
handling the transaction.
There is a potential race condition where the kernel sends BR_ACQUIRE
immediately followed by BR_RELEASE. If these are delivered to two
different userspace threads, then userspace might see them in reverse
order, which could make the refcount drop to zero when it shouldn't. To
prevent this from happening, userspace will respond to BR_ACQUIRE
commands with a BC_ACQUIRE_DONE after incrementing the refcount. The
kernel will postpone BR_RELEASE commands until after userspace has
responded with BC_ACQUIRE_DONE, which ensures that this race cannot
happen.
Link: https://lore.kernel.org/rust-for-linux/20231101-rust-binder-v1-5-08ba9197f637@google.com/
Change-Id: I6dbfaa4a1818663620374e838f47614291c6c596
Co-developed-by:
Wedson Almeida Filho <wedsonaf@gmail.com>
Signed-off-by:
Wedson Almeida Filho <wedsonaf@gmail.com>
Signed-off-by:
Alice Ryhl <aliceryhl@google.com>
Bug: 278052745
Loading
Please sign in to comment