Android has its own init system with a special init.rc configuration file. This file uses its own syntax which, unlike shell scripts used in classical sysvinit, does not allow you to do everything you might need. Instead, it has its own (rather limited) set of actions that it can do (like mkdir, chmod, chown, etc). There is, however, exec keyword defined that should execute specified command (could be a shell script) but unfortunately, it is not implemented (I mean, the keyword is recognized by it does nothing).

The situation was weird to me first time I saw it (back in Android 2.2) but since implementing basic exec action is not really hard, I just added it to the android init system without much thinking and was using it for some time now. It can be something like:

void exec_start(int nargs, char** args)
{
    pid_t pid;
    int status, i;
    if (nargs < 2 || args == NULL) return; 
    args++;
    pid=fork();
    if(pid == 0) {
        execvp(args[0], args);
        ERROR("Exec (%s) failed \n", args[0]);
        _exit(1);
    } else if(pid > 0) {
        waitpid(pid, &status, 0);
        INFO("Child exited with status %d \n", status);
    } else { 
        ERROR("Failed to start '%s'\n", args[0]);
    }
}

This made it possible to do something like this in init.rc:

chmod 0750 /system/bin/script.sh
exec /system/bin/script.sh

The init system runs script.sh script and blocks until it finishes.

The devices I’m working on right now are based on Android 4.0 which is still missing exec implementation by default. This made me rethink the whole problem again. Am I the only person who wants to run some shell scripts in init.rc on Android? Then I figured out that it is possible to do this in default Android init.rc - we can use init’s service concept:

chmod 0750 /system/bin/script.sh
start script
[...]
service script /system/bin/script.sh
    disabled
    oneshot

It does need some more lines and makes it less readable for me (the actual executable path is in different place of the file than the call that uses it) but it definitely works. As an added bonus, you get all the environment variables (like very useful ANDROID_PROPERTY_WORKSPACE or BOOTCLASSPATH) properly set without thinking about it when implementing exec action (this is missing in my simple implementation of exec) and restarting of the script if it dies (if you need it).

It’s so simple, I don’t know why I didn’t use this from the start.