Welcome to the inaugural post to my new little home on the Internet. I have to admit, I was pretty excited when UBM offered me the chance to write a blog about “anything you like”. One can imagine my disappointment, then, when their lawyers followed up with some fine print narrowing the range of subject matter to things that were, “legal, ethical, unlikely to cause physical and/or emotional distress in the reader, and within the author's recognized area of expertise”.
Honestly, that doesn't leave us much to talk about. But with ESC/EELive! 2014 just around the corner, and my being contractually obligated to bring something to teach there, I'm thinking a lot about Android lately. A LOT about Android, actually, and I'm thinking that you probably should too.
A match made in [redacted]
What's not to love about Android? It's an application framework built to run upon the Linux kernel, and was designed from the beginning to be secure, easy to program, and power-efficient on mobile devices with touch screens and modest computational horsepower. And since most of Android is available under licenses that allow for commercial redistribution, you could be tailoring it for one of your new devices after just a few mouse clicks to download the source code.
Just like I am. As I type this, another window on my workstation is churning out comforting streams of compiler messages as the Android framework's build system works its way through itself. In another hour or two, I should have disk images ready for my device.
It's a real pity that it isn't THAT simple, however. In fact, after working with Android for almost four years now, I'm convinced that its excellence for embedded work comes at a pretty heavy price. And if you aren't prepared to pay it, then the experience is like getting so excited to attend a really, really cool conference (hint, hint), that you forget to buy your all-access pass until they're all gone (hint, hint). And I'd hate to see that happen to you (hint, hint).
Divide, or be conquered
Here are a few of the things you can look forward to on your first embedded Android project. First, Android's design makes it impossible to implement anything involving real-time operation within the Android framework itself. Don't bother trying: it simply can't be done. Why? Because the implementation decisions that make real-time operation possible also work against things like power and performance efficiency.
This would seem to be a pretty big problem, given the number of computerized devices out there that need to keep up with the real world. In cell phones, developers work around this problem by running time-critical code in dedicated coprocessors, which are almost always available anyway due to the workloads required to implement RF protocols. That code then communicates with Android using network sockets, USB, or other high-level abstractions, many built upon Linux kernel APIs designed specifically for that purpose.
That's precisely the model you should follow if you want to use Android successfully in your own embedded system: put the stuff that needs real-time scheduling OUTSIDE of Android, either in an external microcontroller, or in a standalone user program or device driver. Run that code on one of the Linux kernel's built-in, real-time schedulers, and then connect it to your non-real-time Android programs through a network socket or similar API.
“Wait a minute, … Linux has real-time schedulers?!”, I hear you ask. Indeed it does! Two of them, in fact, and they have been available in every mainstream Linux kernel since before most people knew Linux existed. They don't deliver the same precision you find in RTOS kernels designed specifically for real-time behavior, but nowadays the difference is small enough that it often just doesn't matter. I plan to make these schedulers the subject of a future article or two, because they offer plenty to talk about.
If you don't succeed, you might have failed
The next thing that may surprise you about Android is that the “Android operating system” isn't really an operating system at all: it's an application framework, plus just enough underpinning to launch that framework when the platform starts up. In particular, Android lacks a way to manage process lifetimes in a comprehensive and flexible way–and that presents serious problems for embedded work.1Fortunately, the omission is a recoverable error as we shall see in a moment.
Except for the smallest devices, all the Linux-based embedded systems I have delivered in recent memory needed more than just the ability to start processes at system initialization, and to restart those processes if they stop unexpectedly. Most of my multi-process designs end up looking like state machines, in fact, where processes come and go based upon cues from the device operator, the environment, and calculated results. These smaller, transient processes are hopefully less complex than a giant, single-process, super-loop strategy, and thereby less likely to hide difficult-to-test critical errors. If you can divide the work up in a robust way, anyway. That will be the subject of a future article or two, I have no doubt.
In my systems, a process dies sometimes because it is supposed to–as when the system switches from an operational mode to a standby mode–and other times because there was a true error encountered and the program crashed. In the latter case, the system usually has to invoke an escape clause of some kind in order to restart things correctly. Regardless, there are almost always supervisory processes that make sure that, no matter how the system arrived at its current state, it will steadfastly refuse to do something unsafe.
In other words, nontrivial embedded Linux machines tend to spend a lot of time supervising and observing processes. You may be able to implement that kind of logic with the process management framework that comes with Android, but I have failed every attempt. Miserably. So eventually, I just stopped trying and found a better way.
Recall that Android is just an application framework that runs on top of the Linux kernel. Within the greater Linux ecosystem, there exist several frameworks designed solely for process lifecycle management: SysVInit, systemd, runit, and so on. Just use one of them instead. I'll explain how in a future article.
Drat, the UBM police have just interrupted to refer me to something they call a “word limit”. I don't know what that means exactly, but now that my concentration is shot it seems as good a time as any to close for now. We'll pick up from here later.
Until next time, I'm taking suggestions for catchy phrases to end my articles with.
Bill Gatliff is a freelance embedded systems consultant, specializing in adapting the Linux kernel and device drivers, and Android, for custom hardware. He also teaches, is a contributing editor for Embedded.com, and is both a Distinguished Faculty and member of the Advisory Panel for the Embedded Systems Conference. That's the former name for Design West, which tells you how long he's been at it. Bill can be reached by email to .
- Conference Registration
- Session info: Android Certificate Program
- Conference Home Page: Design West 2013 (April 22-25, San Jose, Calif.)
 Android has a great life cycle implementation for code that runs inside of Android itself e.g. Activity classes; but that’s not what I’m talking about here.