By Jonathan Corbet
January 4, 2012
Toward the end of December, LWN
looked at the
new push to move various subsystems specific to Android kernels into
the mainline. There seems to be broad agreement that merging this code
makes sense, but that agreement becomes rather less clear once the
discussion moves to the merging of specific subsystems. Tim Bird's
request for comments on the Android "logger"
mechanism shows that, even with a relatively simple piece of code, there is
still a lot of room for disagreement and problems can turn out to be larger
than expected.
The logger is a simple device designed to collect log data from
applications and make that data available to developers and the central logging
system. It was designed around a number of goals, most of which are driven
by the untrusted nature of Android applications: the system wants to allow
those applications to send messages to the log in a reliable and
trustworthy manner. So applications should not be able to fake who they
are, consume too much memory with log data, or spam the log at the expense
of data from the kernel or other applications. Writing to the log is also
meant to be a fast operation; lots of log data is generated, but little of it
is read, so the write operation is the one that should be the fastest.
The driver implements a handful of logging "devices" for different streams;
they are known as "main," "events," "radio," and "minor." These devices
are hardwired into the code; there is no way to change the set of devices
at run time. Each device is implemented as a simple ring buffer in kernel
space; writing to the device adds a message to the buffer (annotated with
timestamp and process ID information) while any number of readers can pull
data out of the buffer. Each log has 256KB of memory dedicated to it;
that size, too, is wired into the code. There is a small set of
ioctl() operations provided to get the size of the log or the amount
of unread logging data stored there, or to flush all data from the log.
The first question to be raised was: why is this facility needed at all?
The kernel already has a mechanism for letting user space add entries to
the log stream. In mainline kernels, that is done by writing to
/dev/kmsg; that device takes the data given to it and passes it
straight to printk(). There are a few reasons why Android would
not want to use this interface: it does not allow for the separation of
logging streams (and, thus, is limited to the root account), it does not
add process ID information, and
printk() is quite a bit more expensive than simply copying the
log data into kernel memory. While adding a duplicate logging
infrastructure is obviously problematic, a case could be made that
something like logger should be merged and used as a replacement for
/dev/kmsg.
That said, "something like logger" need not be the logger itself. If
nothing else, it is hard to imagine the current code being merged without
corrections for the most obvious problems: the hardwired log streams, for
example. Logger is entirely unaware of namespaces, making it unsuited
to environments where different process groups may want their own logging
streams. It also does not really succeed in keeping processes from
spamming the logs and overwriting data from other processes; each of the
four streams is
isolated from the others, but applications still end up logging to the same
streams.
There is also the question of whether the user-space API is the right one.
Adding more ioctl() calls to the kernel is never a popular thing
to do. Some participants have suggested that an entirely user-space-based
logging daemon would work just as well. But a user-space solution has some
disadvantages: it would not be able to provide trusted process ID
information, and it would likely be slower. Communicating log data to a
user-space daemon and adding information like time stamps would involve
more system calls than simply logging the data through the kernel. It
would also be hard to merge kernel and user-space log data (and, in
particular, to ensure that the ordering between events is correct) with
a user-space scheme.
Neil Brown suggested that a
filesystem interface could be used instead of logger's char device ABI. A
logging stream could be
established simply by creating a file within that filesystem; regular file
permissions could then be used to control access to the streams. The
ioctl() calls could be replaced with regular filesystem calls;
flushing a log would be done with truncate(), for example. A
filesystem-based logger would, clearly, involve moving to a different
user-space interface, but it seems like it should be able to satisfy the
use case that led to the creation of logger with a more Unix-like ABI.
Android developer Brian Swetland has indicated that there might be interest in
trying out an alternative logging implementation, but it would have to meet
their
needs and it's not something that they would be interested in creating
themselves:
If all discussions of bringing Android kernel support to mainline
end up as another round of "you should just rewrite it all in
userspace" or "you should use this other subsystem that doesn't
actually solve your problem but we think it's close enough", then
there's not a lot of point to having the discussions in the first
place.
If somebody wants to go write a complete compatible replacement
that just drops in, we certainly could take a look at it and see
how it works, but given that the benefits are not clear to us,
we're not interested in going off and doing that work ourselves.
There is another point to consider as well: the longstanding interest in
adding a more structured logging interface to the kernel seems to be
getting stronger. Adding a new logging mechanism that doesn't address the
concerns of translators, documentation writers, and people maintaining
automated network management systems is going to be a hard sell. Kay
Sievers, one of the developers behind "The Journal," has a plan of his own for logging; it involves
adding more structured information to the existing message stream. He
thinks there is no need to add a new, incompatible logging mechanism; he is
also strongly opposed to the idea of separating message streams as logger
does. That separation, he says, just creates problems when messages from
multiple sources need to be merged back together in the correct order.
Brian actually seems receptive to some of
these ideas, but has expressed concerns around rate-limiting and
controlling access to log data. Lennart Poettering believes these needs can be met by the Journal
with a little help from control groups. It seems possible that something
could be done to make both groups happy - though the code to actually do so
has not been posted.
As of this writing, that is where the discussion stands. On the surface,
it looks like another piece of Android technology has gotten tangled up in
unrelated requirements from various kernel developers, with the result that
it will sink like its predecessors. But there is the potential for a
number of possible solutions here. One, of course, would be to simply
merge a moderately cleaned-up logger for Android's use and be done with
it. Another would be to, as Neil suggested, focus on Android's user-space ABI
for logging. If that ABI were formalized in a way that would allow
multiple underlying implementations, the mainline could merge something
other than logger and still be that much closer to being able to run
Android's user space.
Perhaps the most intriguing outcome, though, would come if developers from
Android, the Journal, and others with an interest in structured logging
could get together and agree on what the next generation of logging should
look like. Their solution would be likely to start with a critical mass of
users
from the outset, improving its chances of being merged and adopted by
others. Given the number of structured logging efforts that have
floundered in the past, getting a widely-accepted solution in place would
be a major accomplishment.
(
Log in to post comments)