Playing BusyBox on a virtual Android device (Intermediate)
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.
Getting ready
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
.
How to do it...
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 BusyBoxash.
Startash
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 intoramdisk/
.$ 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 intoramdisk/
.#!/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 achmod
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 defaultPATH
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 thels
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 usetelnetd
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:3333of 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 lettelnetd
spawn/bin/ash
rather than/bin/login
, then no login progress will be required. Let's starttelnetd
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:
How it works...
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.
There's more...
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