BusyBox can be used as a toolbox on existing systems, and it is also often used to build a bootable embedded system.
Let's build a standalone system with BusyBox from scratch and launch it on a virtual Android device with an Android emulator.
This recipe will use BusyBox to build our own filesystem and compress it to a gzipped cpio
package, just like ramdisk.img
, which we used in the previous recipe.
To boot such a new system, a new Linux kernel image should be compiled from Google Android-specific Linux kernel source code. Clone the source code for preparation.
$ cd ~/tools/busybox/ $ git clone https://android.googlesource.com/kernel/goldfish.git
The source code is specifically designed for Android goldfish hardware; the Android emulator won't run on other hardware.
To cross-compile an Android Linux kernel, the cross-compiler arm-linux-gnueabi-gcc
should have been installed when going through the Compiling BusyBox recipe.
Based on the Installing BusyBox recipe, let's build our own filesystem: ramdisk.img
with BusyBox from scratch, cross-compile our own Linux kernel image, and then boot them on the Android emulator:
Build a minimal Linux filesystem with BusyBox. To build a minimal bootable filesystem, the standard Linux filesystem directory architecture should be prepared at first.
Apart from the
/bin
,/sbin
, and/usr
directories that are created by default, the/dev
,/proc
,/sys
, and/etc
directories must be created manually:$ cd ~/tools/busybox/ramdisk/ $ mkdir dev sys etc proc
/etc
contains the configuration files for the Linux system. It includes two important files:inittab
andfstab
.inittab
can be used byinit
to determine which programs should be run andfstab
describes the filesystems mounting parameters. Theinit
process is the first process invoked by the Linux kernel after the kernel finishes its initialization (to learn more about the generic boot sequence of a Linux system, read the manual page of the boot process by running theman boot
command):$ cat > ./etc/inittab ::sysinit:/etc/init.d/rcS ttyS2::askfirst:/bin/sh ::restart:/sbin/init $ cat > ./etc/fstab proc /proc proc defaults 0 0 sysfs /sys sysfs defaults 0 0 $ mkdir ./etc/init.d $ cat > ./etc/init.d/rcS #!/bin/sh mount -a echo /sbin/mdev > /proc/sys/kernel/hotplug mdev -s $ chmod 777 ./etc/init.d/rcS $ ln -s ./sbin/init init
With the previous setting, during the booting of our Linux system, the
init
process parses ourinittab
file and runs/etc/init.d/rcS
as the first action. It mounts all filesystems specified infstab
, and starts the minimalmdev
device management tool (like the more famous tool,udev
) to create all device nodes exported by low-level drivers under/dev
for late operations. It also creates a console with/bin/sh
, and attaches it atttyS2
. Since/sbin/init
is the first user process, the/etc/inittab
also let it respawn for system availability.Lastly, the console based on
/bin/sh
is provided as the basic shell environment for the user interaction.Package the filesystem into an image and name it
ramdisk.img
.Now, let's compress it with the following command:
$ cd ramdisk/ $ find . | cpio -H newc -o | gzip -9 > ../ramdisk.img
Cross-compile a new Android Linux kernel.
To start our own ramdisk, since it doesn't work with the prebuilt kernel image (zImage) in Android ADT (Android Development Toolkit), we should build our own Linux kernel image from the Android Linux kernel source code. Go to the just downloaded
goldfish/
directory and compile it as follows:$ cd ~/tools/busybox/goldfish/ $ git checkout android-goldfish-3.4 $ make goldfish_armv7_defconfig $ export CROSS_COMPILE=arm-linux-gnueabi- $ make zImage $ cp arch/arm/boot/zImage ~/tools/busybox/
Run our new embedded system on a virtual Android device.
Now, start our own kernel image with the just-built minimal filesystem as follows:
$ emulator @busybox-avd -shell -show-kernel -no-window \ -kernel ./zImage -ramdisk ./ramdisk.img Uncompressing Linux... done, booting the kernel. ... Please press Enter to activate this console.
According to this message, we can press Enter to activate the console terminal and execute the commands that we want to run.
The ramdisk.img
is an archive of format gzipped cpio
, which is extracted as the default root filesystem when the kernel boots up. It generally contains a file named init
, which will run after the kernel boots up. This init
command parses the initialization configuration, /etc/inittab
, and eventually starts the console based on the ash
shell, and provides the applets' running environment.
In real embedded development with the minimal filesystem built with BusyBox and their built-in applets, we are able to verify the function and robustness of their device drivers through their exported /dev
, /sys
, and /proc
interfaces.
With the help of the ash
applet, shell scripts can be written to perform test automation to enhance the stability of an embedded system. With the help of the built-in PowerTop, bootchartd, top, iostat, devmem, and some other external utilities, the other aspects of an embedded system can be optimized to provide better user experience. The test automation and system optimization will be discussed in the coming recipes.