Friday, August 28, 2009

The init process and init.rc

In this post I will wrap up the analysis of what is going on at boot by looking at the Android init process and the init.rc file. If we start with the source you will find the code for the init process under /system/core/init in the source tree. The init process is what will set up all native services and this is similar to a regular Linux system boot. At this stage we are not executing in the actual android runtime. There is however some Android specifics going on already at this level. One example of this is that the init.rc script is written in a specific format called the Android init language. This is covered in the readme file that is kept in the same directory as the init source. Since I have not seen very much about it on the net though I will post some of the main concepts here. I will also give a small example on how to add your own native service at startup.

The Android init language
The language used by the init process has four classes of statements. These are actions, commands, services and options. Actions are associated to commands in the way that an action is a sequence of commands. An action also need something called a trigger in that the sequence of commands will be executed when the trigger event has occured. An exemple may look like:
on boot
ifup lo
hostname localhost
domainname localdomain
This action will run a command sequence to set up basic networking once it receives the boot trigger. The supported commands include export, chmod, chown and a few others. The complete list of available commands can be found in the readme file.
Services are programs that are launched by init. They are associated with options which control how they are started. The syntax for starting a service is:
service < name > < pathname > [< argument > ]*
< option >
< option >
...
There is a number of options available and a few of them are:
critical - this is a critical process and init will restart the device if it exists more than four times in four minutes
user < username > - change to this username before executing the service
group < groupname > [< groupname > ]* - change to groupname before executing the service
setenv < name > < value > - set environment variable < name > to < value > in the launched process
The init script is also the place where some important system properties are set. This is done with the setprop command and include things like the memory thresholds for applications, tcp buffer sizes etc.
The init.rc file itself is found in the root directory on a device and in the source tree it is kept under system/core/rootfs. The below example is the actual init.rc file that I have shortened significantly. The basic concepts are clearly illustrated. First there is an action on init where a long sequence of commands is run. As you can see it is accepted to use comments and they are preceded by #. A number of variables are setup during init and file systems are mounted. The next step is the boot action where networking is set up and properties assigned to the system. Then there is a list of services to be started by init.
on init
sysclktz 0
loglevel 3
# setup the global environment
export PATH /sbin:/system/sbin:/system/bin:/system/xbin
export LD_LIBRARY_PATH /system/lib
export ANDROID_BOOTLOGO 1
export ANDROID_ROOT /system
...
# mount mtd partitions
1. 
Mount /system rw first to give the filesystem a chance to save a checkpoint
mount yaffs2 mtd@system /system
mount yaffs2 mtd@system /system ro remount
2. 
We chown/chmod /data again so because mount is run as root + defaults
mount yaffs2 mtd@userdata /data nosuid nodev
chown system system /data
chmod 0771 /data
...
on boot
# basic network init
ifup lo
hostname localhost
domainname localdomain
# set RLIMIT_NICE to allow priorities from 19 to -20
setrlimit 13 40 40
# Define the oom_adj values for the classes of processes that can be
# killed by the kernel. These are used in ActivityManagerService.
setprop ro.FOREGROUND_APP_ADJ 0
setprop ro.VISIBLE_APP_ADJ 1
setprop ro.SECONDARY_SERVER_ADJ 2
setprop ro.BACKUP_APP_ADJ 2
setprop ro.HOME_APP_ADJ 4
setprop ro.HIDDEN_APP_MIN_ADJ 7
setprop ro.CONTENT_PROVIDER_ADJ 14
setprop ro.EMPTY_APP_ADJ 15
...
## Daemon processes to be run by init.
##
service console /system/bin/sh
console
# adbd is controlled by the persist.service.adb.enable system property
service adbd /sbin/adbd
disabled

Starting your own service at boot.
Normally there is not much need to do things in the init script and start services of your own. What is provided in the system goes a long way and often it may be better to add something to the Android runtime instead of using the native services. If you have a reason to add something or just what to try things out however it is relatively straight forward to add a native service to that init sequence. I have created a simple example that writes the time elapsed since it started to the log. It wakes up every three seconds. The code for exampleservice.c looks like:
#define LOG_TAG "Example Service"
#include < utils/log.h >
#include < unistd.h >
int main(int argc, char **argv)
{
    LOGI("Service started");
    int elapsed = 0;
    while(1)
    {
         sleep(3);
         elapsed += 3;
         LOGI("Service elapsed time is %d", elapsed);
    }
}
Place this somewhere in the platform build system and build as an executable. The build system will place the output in the /system/bin folder on the device. Now all that is needed is to add the following to the init.rc script:
service exampleservice /system/bin/exampleservice
user exampleservice
group exampleservice
oneshot
and your service will start on init. It is also possible to write your own file using the Android init language that enables your services and variables. Then just add a line to import the file in init.rc and you are done.
/Mattias

Tuesday, August 25, 2009

Back after the summer with some NDK comments

Time to pick up on the blog again after a summer where parts of the team have been on vacation and others have been hard at work in a couple of projects. In the mean time the Android platform has continued to evolve and a few things can be mentioned here:

1. The kernel has been removed from the Android manifest file and now requires a separate git pull if you are interested in it:

git clone git://android.git.kernel.org/kernel/common.git

This will save some time when syncing the repo and since the kernel was built outside the Android build system anyway it makes sense to keep it separated.

2. The NDK (Native Development Kit) was released allowing some support for native code in Android applications.
Making it possible to use native functionality in applications have been on the wish list for a long time and this is the first step in that direction. The list of supported API:s is very short though. The NDK currently supports:
  • libc (C library) headers
  • libm (math library) headers
  • JNI interface headers
  • libz (Zlib compression) headers
  • liblog (Android logging) header
  • A Minimal set of headers for C++ support
A c library combined with math and some logging capabilities provide enough for a some powerful algorithm implementations but to be of broader interest some more API:s are probably necessary. Natural candidates would be graphics support (openGL) and maybe some codecs. Currently the NDK is a good way to experiment with native functionality without going through the hoops of learning all about the platform and build system. For some applications it may also be exactly what is needed.

It looks like things will be picking up for the Android team during the fall and we aim to keep posting interesting tidbits here.

/Mattias