[Ce-android-mainline] binder re-implementation

NeilBrown neilb at suse.de
Sat Jan 28 04:43:23 UTC 2012


On Fri, 27 Jan 2012 13:51:19 +0000 Arnd Bergmann <arnd at arndb.de> wrote:

> On Thursday 26 January 2012, NeilBrown wrote:
> > One of the big problems with the current binder interface is that it creates
> > a strong tie between a file-descriptor and a process, without actually
> > enforcing that tie.  So if you open the binder device and then fork, it will
> > almost certainly stop behaving correctly.
> 
> I was wondering about this, too. Other possible problems with weakly
> defined semantics that I see are:
> 
> * Opening the binder multiple times from one process. I don't
> think this is meaningful, but I don't know if it is harmless.
> 
> * Passing binder file descriptors through unix sockets while
> passing the same unix socket through the binder in a different
> thread. Is this race-free and deadlock-free?
> 
> > Another big problem - for me at least - is the use of a char device and
> > ioctls.  This is "wrong" from a philosophical perspective, and we could of
> > course argue philosophy all day without getting anywhere so maybe that isn't
> > a useful observation.
> 
> Agreed on both accounts.
> 
> Since we have the same question on a number of the android drivers,
> my personal rule of thumb is:
> 
> - when dealing with an I/O device that can exist multiple times
> in the system and needs fs level user permissions for controlling
> access, use a chardev with ioctls, but
> 
> - when dealing with kernel functionality that is not related to hardware
> and that is not restricted to a specific group of users, use system calls.
> 
> > Maybe a better way to look at it is that this approach effectively bolts
> > binder on the side of linux rather than integrating it properly.  Thus you
> > lose the benefits of a uniform integrated whole.
> > 
> > When I was researching binder for my lwn article:
> >     https://lwn.net/Articles/466304/
> > I spent a while trying to come up with a "good" interface for the same
> > functionality but was never really satisfied with anything I came up with.
> > However I'm tempted to try again .... maybe.
> > 
> > Anyway, my thumbnail sketch would be something like this:
> > 
> > 1/ A new 'address family' to be used with sockets.  Addresses in this family
> >   are comprised of 1 or 2 'cookies' which are either file descriptors or
> >   an internal 'object descriptor'.
> > 
> >   Thus if you open a file and bind(2) to that descriptor, anyone else who
> >   can open the same file can send you a message.
> > 
> >   Also you can send a message containing an 'object reference' and it arrives
> >   at the other end as an 'object descriptor' which can be used in addresses.
> >   This roughly matches the addressing used in binder.
> > 
> >   The optional second 'cookie' is just an object reference but it identifies
> >   a 'transaction' which supports the transaction handling that is implicit in 
> >   the current binder.
> 
> Sorry, I don't understand this part. Do you mean any struct file that
> might be shared between two processes could be used to established a
> binder socket, or what would be the way to identify it?

Not the struct file - the inode behind it.

To implement binder semantics we need two sorts of addresses:
 1 - a well-known address which is used to make first-contact with the 'bus'.
    In android-binder there is only one such address and it is '0'.
    Only a privileged process can bind to '0'.  Anyone can send to '0'.
    For a properly general implementation that can concurrently be used
    by different users and different libraries, there should be an arbitrary
    number of such public addresses.
    I'm suggesting that we use 'struct inode *' as the address, referenced by
    each process via an fd.  Any process with write-access to the inode (i.e
    the open file descriptor was opened for 'write') can bind to it.  Any
    process with read access can send to it.

 2 - private 'object' addresses.  Any process can generate these and can
    send them in messages to other processes.  A process can only send to
    one of these if it has received the address via an incoming message.
    So the first thing a process would do when it starts up is contact some
    broker using a well-known address and ask for the address to whatever
    service it wants, or whatever object it wants to talk to.
    I'm suggesting these be identified with simple numbers just like 'fds'.
    As an 'fd' can use a full 32 bits we would need some way to indicate
    whether the number(s) in the address were 'fd' numbers or 'object'
    numbers.

Having a second (or even a third or fourth) number (fd or object) in the
address would allow limited hierarchical address matching.
So when sending you could have a convention that the 'to' address comprises:
  - target object
  - method identifier

Then if some socket is bound to exactly that pair, it gets the message.
Otherwise if some socket is bound to just the target object it gets the
message.

This mechanism can be used to implement the transaction routing that Andorid
Binder uses. In that case the 'to' address would be:
  - target object
  - transaction identifier

(it actually is more complicated than this - one socket can be bound to lots
of objects... but that is a detail to be fleshed out later).


> 
> > 2/ New 'control messages' that can be sent with sendmsg and received with
> >    recvmsg which pass 'object' references
> > 
> > 3/ A normal code path where a writer blocks until a reader is also ready,
> >    and then the message is copied from the writers iovec into the readers
> >    iovec without ever living in a kernel buffer.
> > 
> > 4/ An extension to aio so that sendmsg/recvmsg messages can be sent async
> >    too.  Then this would be used for async communication.
> 
> I like this.
> > I appreciate that some of the things that I am suggesting we do to sockets
> > are quite a deviation from the norm and you might argue that I am mis-using
> > sockets just as much as the current binder is mis-using char devices.  You
> > might even be right: I am not objective enough to comment.
> > 
> > If there is interest in this (and maybe even if there isn't) I'll try to find
> > time to make it all more concrete and detailed so we can ask some independent
> > by-stander to comment.
> 
> What I've been thinking about before was to either extend the Posix mqueue
> implementation or to add something similar to that, rather than a socket
> family. Have you also considered this? As far as I can tell, both sockets
> and mqueues could serve as the base for the binder kernel interface, but
> I don't understand the binder requirements well enough to judge if there
> are any fundamental differences that we can't work around in message queues.
> 
> 	Arnd

I don't think mqueues are any advantage over sockets.

In particular they have a much poorer concept of address.
Each queue has a single distinct address which is specified when you open the
queue.  Multiple processes specify the same address and so get the same queue
and so can communicate.  Usually one will receive from the queue, others will
send.
To communicate with 3 different services you need 3 different mqueues.

binder needs something more like datagram 'sendto' or 'sendmsg'.  i.e. the
address is associated with the message more than with the socket/queue/fd.
There are potentially lots more addresses than there are open file
descriptors.
An mqueue is like a connected socket.  A binder handle is much more like an
unconnected socket.

NeilBrown
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 828 bytes
Desc: not available
URL: <http://lists.linuxfoundation.org/pipermail/ce-android-mainline/attachments/20120128/b821c677/attachment.sig>


More information about the Ce-android-mainline mailing list