Monday, April 13, 2015

Android: How to run a script or system application at boot

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.

  1. Add your custom scripts to the init system and, if necessary, the boot image.
  2. 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

2 comments:

 
Cmotc © | Partner: Toxigon ©
CMotC © 2015 - Designed by Templateism.com