-
Book Overview & Buying
-
Table Of Contents
Instant Optimizing Embedded Systems Using BusyBox
This recipe uses a virtual Android device as the target platform that we just created to show the usage of BusyBox applets on an embedded platform. It will replace the Android toolbox mksh shell-based console with the more powerful BusyBox ash shell-based console. It starts a remote shell and a web service on it with BusyBox telnetd and httpd respectively.
The console based on BusyBox ash gives a more powerful shell environment. Not only can the applets be run on this console, but new shell scripts can also be written in such a shell environment.
The remote shell is useful for remote development and maintenance, and the web service is helpful for system monitoring. Both of them have common use cases in an embedded system.
At this stage, we aren't constructing a full bootable filesystem from scratch, but only using the BusyBox applets. So, for simplicity and ease of testing, we will install our compiled BusyBox binary and scripts into an existing Android ramdisk image.
At first, get a copy of the existing ramdisk.img; its path can be found at ~/.android/avd/busybox-avd.avd/hardware-qemu.ini; for example, adt-bundle-linux-x86_64/sdk/system-images/android-17/armeabi-v7a/ramdisk.img.
Three examples will be shown in this section to demonstrate the usage of the BusyBox applets on a virtual Android device.
Replace the console based on Android mksh with the BusyBox ash console.
Since the Android toolbox mksh shell is too lightweight, and the Android toolbox (the BusyBox-like toolset software) itself only provides a few of the applets, here it only shows us how to replace it with BusyBox ash. Start ash as the default console, and eventually build a more powerful shell environment.
At first, decompress the original ramdisk image with the following steps:
$ mv ramdisk.img ramdisk.img.gz $ gunzip ramdisk.img.gz $ mkdir ramdisk/ && cd ramdisk/ $ cpio -i -F ../ramdisk.img
Second, get a prebuilt BusyBox binary, busybox-armv7l, and put it into ramdisk/.
$ wget http://busybox.net/downloads/binaries/latest/busybox-armv7l $ cp busybox-armv7l ramdisk/
Third, to install BusyBox at runtime, let's prepare a script and name it busybox-console.sh, and add it into ramdisk/.
#!/system/bin/sh # busybox-console.sh -- Install busybox to /bin and start /bin/ash # remount root file system for read and write mount -o remount,rw / mkdir /bin chmod 0777 /bin/ chmod 0777 /busybox-armv7l /busybox-armv7l --install -s /bin export SHELL=/bin/ash /bin/ash
It remounts the root filesystem to be readable and writable and allows us to install BusyBox with ––install to /bin at runtime; lastly, it starts /bin/ash.
$ cp busybox-console.sh ramdisk/
Then start a service in init.rc to launch the previous script. Add a chmod command to make sure the previous script is executable.
$ cd ramdisk/ $ sed -i '/loglevel/a \\n chmod 0777 /busybox-console.sh' init.rc
Let the BusyBox applets be executed directly without the full path.
Append the installation directory of the BusyBox applet, /bin, to the default PATH environment.
$ sed -i -e "s#export PATH #export PATH /bin:#g" init.rc
Replace the original console service with our console service that is based on ash.
$ sed -i -e "s#service console.*#service console /bin/busybox.sh#g" init.rc
Now back up the old ramdisk and recompress a new one.
$ mv ramdisk.img ramdisk-backup.img $ cd ramdisk/ $ find . | cpio -H newc -o | gzip -9 > ../ramdisk.img
Lastly, run the emulator to start with our new ramdisk and with the BusyBox ash console.
$ emulator @busybox-emulator -ramdisk ./ramdisk.img -shell -show-kernel / # echo $SHELL /bin/ash / # ls /bin [ fold mke2fs setsid (truncated to fit in the text) / # which ls /bin/ls
This code only lists a part of the applets installed. As we can see, the shell becomes /bin/ash. The applets are installed under /bin and the ls command is not the one provided by Android toolbox (/system/bin/ls) but the one (/bin/ls) installed by BusyBox. This indicates that we have successfully changed the console service to our own.
The writing of new shell scripts under this shell environment based on ash will be introduced in the Enhancing system stability of an embedded (Android) system recipe.
Start a remote shell with BusyBox telnetd:
A real embedded system may have no serial port and adb and no local cable connected, but a network connection with Wi-Fi or 3G; accessing such systems may need a remote shell. As a lot of remote shells exist, such as SSH and Telnet, and since BusyBox doesn't provide an SSH daemon but telnetd, we use telnetd as an example here.
Firstly, start the service on an emulator from a virtual serial port.
/ # echo "Hello, telnetd" > /data/telnetd.issue / # telnetd -f /data/telnetd.issue -p 3333 / # ps | grep telnetd | grep -v grep 731 0 0:00 telnetd -f /data/telnetd.issue -p 3333
Second, build an emulated network connection. Android emulator does not provide a standalone full emulated network stack but a port-redirection-based network stack. In order to use the network service, the adb forward command should be used to enable the port redirection feature.
Say you want to access the telnetd service seen previously. The remote tcp:3333
of the emulator must be redirected to a port of our desktop development system (for example, tcp:3333) by running the following command:
$ adb forward tcp:3333 tcp:3333
Third, log in to the telnet service and issue the following command on the development system:
$ telnet localhost 3333 Hello, telnetd localhost login:
It means it really logs in and gets a prompt, Hello, telnetd. However, without a user account and the password, we cannot log in. To avoid setting up a username and password, we can simply let telnetd spawn /bin/ash rather than /bin/login, then no login progress will be required. Let's start telnetd on the emulator as follows:
/ # telnetd -p 3333 -f /data/telnetd.issue -l /bin/ash
Log in to the shell directly and experiment with our Android device remotely.
Start a web server with httpd:
Firstly, start httpd at /data/www, and create a simple HTML page on the target platform from a virtual serial port as follows:
/ # mkdir /data/www / # httpd -h /data/www -p 8080 / # cat > /data/www/index.html <!doctype html><html><head><title>BusyBox</title></head><body><h1>Hello, Busybox Http Server Works.</h1></body></html>
Second, just like telnetd, make a port redirection from the emulator to the development system.
# adb forward tcp:8080 tcp:8080
Lastly, let's access the httpd service with any modern web browser on our development system. Here we use the Chromium browser as an example:

BusyBox applets cover the standard coreutils, console tools, e2fsprogs, procps, SELinux, editors, modutils, debianutils, login-utils, networking, sysklogd, util-linux, findutils, mailutils, printutils, and even a tiny shell interpreter. This recipe shows how to install some of them at runtime on an existing Android system and demonstrates the working of these three applets: ash, telnetd, and httpd.
To add more function for an embedded system, the other applets may also need to be configured via the configuration utility and used based on their full usage information with the --help command.
In order to start the previously mentioned service during boot, we can add httpd and telnetd in the previous /busybox-console.sh script.
# Start httpd service httpd -h /data/www -p 8080 # Start telnetd service telnetd -f /data/telnetd.issue -p 3333 -l /bin/ash
To access them, we must also forward the remote ports to the development system as follows:
$ adb forward tcp:3333 tcp:3333 $ adb forward tcp:8080 tcp:8080
Change the font size
Change margin width
Change background colour