Android devices are inexpensive, highly capable computers which are easy to
purchase discreetly, even though their out-of-the-box privacy leaves something
to be desired. This makes them extremely useful to modify into more fully
fledged single-purpose computers, and it is possible to use them as tiny
servers or even as the basis for computing clusters. In order to do this,
however, the most essential thing you need to know how to do is how to run
applications at boot time, and some of the applications you might want to run
as their native versions and not as Android APK's, for example an SSH server
like Dropbear or OpenSSH or a networking stack like cjdns. Unfortunately, all
the Android variants have slightly different ways of launching startup scripts.
Here, hopefully, is how to find yours and use it to launch an ssh server, so you
can take control of your phone via SSH instead of ADB in order to use our phones
to do USB tethering without having to install ADB on the host computer.
Requirements:
- A rooted Android device, newer ones work more reliably
AND
- A desktop or laptop PC running a copy of the Android SDK
OR
- A Terminal Emulator application
AND
- An app you want to run as an init script on your Android system, for
example, Dropbear. For instructions compiling Dropbear for Android, see this
excellent tutorial
You'll need to push dropbear into a folder in the PATH. To push "dropbear" to
the Android device after compiling:
adb shell 'mount -o remount,rw /system'
adb shell 'chmod o+w /system/etc'
adb push dropbear /system/bin/dropbear
adb shell 'chmod o-w /system/etc'
adb shell 'mount -o remount,ro /system'
This tutorial is written assuming you are executing all these functions on a PC
with the Android SDK.
The Concept
Operating Systems of all types must contain a mechanism for starting essential
programs when the system is booted. These programs are things like desktop
environments and service daemons and on DOS and older versions of Windows for
example, the programs that were launched at boot time were run by
"C:/autoexec.bat". On the best Operating Systems, however, these applications
are launched by the so-called "init system," which exposes an easy to use,
regular interface for adding scripts to be run when the system is launched.
Android uses a script-based init system, which makes our lives a little easier.
In order to add your own programs or scripts to run at boot you will have to do
one of two things.
- Add your custom scripts to the init system and, if necessary, the
boot image.
- Hijack another init script by adding your own code and use it to launch
your own script.
Stock ROM's
Stock ROM's are the hardest ones to run startup scripts on, because they tend to
use many different ways of launching thier startup scripts. In order to track
down clues as to your Android device's way of handling initialization, run the
following command.
adb shell 'ls -l /etc'
This will most likely indicate that /etc/ is a symbolic link to the /system/etc/
directory. Once this is clear, re-mount the /system partition as read-write and
add write permissions to the /system/etc/ directory.
adb shell 'mount -o remount,rw /system'
adb shell 'chmod o+w /system/etc'
Now you have the ability to read and write the files in the /system/etc/
directory. Once you've done that, you need to locate the other init scripts that
have already been set up. You will modify one of these files to also run your
init script.
adb shell 'find /etc -name "*rc"'
adb shell 'find /etc -name "init*"'
These files search for candidates which might be init scripts. You might see the
directory /system/etc/rc.d/, /system/etc/init.d, or /system/etc/init.rc, these
are all possible places where you might be able to embed the launcher for your
application. You'll need to pick one of those files and, at the end, add a line
which starts your application.
adb shell 'echo "dropbear -s -g" >> /path/to/initscript'
Finally, re-mount the system as remove write permissions from the /eystem/etc/
directory and make /system read-only.
adb shell 'chmod o-w /system/etc'
adb shell 'mount -o remount,ro /system'
Android Open Source Project
In order to add your startup script to a running AOSP ROM, you need to overwrite
the init.sh file and add the new script to the /boot partition. In order to do
this, you absolutely need a PC, preferably running GNU/Linux. The first step
you need to undertake is to back up your /boot partition.
Find your partitions by examining /proc/mtd(Preferably. Sometimes it doesn't
exist, but that's a whole article in and of itself.)
adb shell 'cat /proc/mtd'
It will show something like this, which tells you alot of information about the
device's partition table. Look for the line that says "boot" in the name column
and make a note of the device in the "dev" column.
dev: size erasesize name
mtd0: 00040000 00020000 "misc"
mtd1: 00500000 00020000 "recovery"
mtd2: 00280000 00020000 "boot"
mtd3: 04380000 00020000 "system"
mtd4: 04380000 00020000 "cache"
mtd5: 04ac0000 00020000 "userdata"
Now that you know where the boot image is, (On GNU/Linux) run
adb shell 'cat /dev/mtd/mtd2' > ./boot.img
to put the contents of the boot partition into an image file in the current
directory.
Now, Download this script called "split_bootimg.pl" and use it to extract the
ramdisk from boot.img
wget https://gist.githubusercontent.com/jberkel/1087743/raw/5be96af0e1c1346678379b0c0f0330b71df51f25/split_bootimg.pl
./split_bootimg.pl boot.img
Now that you have the two files you need backed up, you need to unpack the
img-ramdisk.gz file. to do this, you need to create a new directory, change into it,
and unzip the boot.img file in the new directory. On GNU/Linux, run the
following commands from the directory containing boot.img.
mkdir boot && cd boot
gunzip -c ../img-ramdisk.gz | cpio -i
Now you have access to the files in the ramdisk and can change and repack them.
Find the file named "init.rc" and add your script to it's contents. Finally,
re-pack the boot image and flash it to the boot partition of the device.
mkbootimg --cmdline 'no_console_suspend=1 console=null' --kernel boot.img-kernel --ramdisk ramdisk-new.gz -o boot-new.img
Upon restarting, your device will now start the application when the phone
is booted up.
CyanogenMod, OmniROM, and Replicant
CyanogenMod-Based Android ROM's are the easiest to modify, and even come with an
accessible mechanism for setting scripts to run after the system is booted.
CyanogenMod keeps a file called "20userinit" in it's /etc/init.d/ directory.
This directory contains files that are executed sequentially when the system
boots up, and you could easily add the script that launches your app here, but
have a look at the contents of 20userinit.(Comments do not exist in original
version, I added them to explain what the code is doing for people unfamiliar
with shell scripting.)
View the contents of /etc/init.d/20userinit"
adb shell "cat /etc/init.d/20userinit"
You will see:
if [ -e /data/local/userinit.sh ]; # Test if there is a file at /data/local/userinit.sh
then # Only if the file exists, execute the following code
log -p -i -t userinit "Executing /data/local/userinit.sh"; # Mark this event in the log
busybox chmod +x /data/local/userinit.sh; # Use busybox to make the script executable
logwrapper /system/bin/sh /data/local/userinit.sh; # Add the output of the userinit.sh script to the log
setprop cm.userinit.active 1; # set the CyanogenMod Userinit Active property to true
fi; # Close if statement
In a nutshell, /etc/init.d/20userinit will run the script
/data/local/userinit.sh, if it exists, which can in turn be used to launch apps
by providing their path and options. So in essence, CyanogenMod has left you a
way to add your own scripts to run after you boot by adding them to this file.
In order to write to this file, use the terminal to direct the output of the
echo command. Remember that ">" starts over at the beginning of the file, and
will overwrite any previous contents, and that ">>" appends the echoed string
into the end of the file without overwriting the contents.
adb shell 'echo "" > /data/local/userinit.sh'
adb shell 'echo "" >> /data/local/userinit.sh'
adb shell 'echo "" >> /data/local/userinit.sh'
adb shell 'su -c "busybox chmod o+x /data/local/userinit.sh"'
Now reboot your device and try connecting to the SSH server. If the server
didn't start, your /etc/init.d/20userinit.sh script may not be marked
executable.
adb shell 'su -c "busybox chmod o+x /etc/init.d/20userinit'
Citations:
Boot Image Information
Stack Overflow Thread