Difference between revisions of "Android"

From ArmadeusWiki
Jump to: navigation, search
(creation)
 
(cleanup)
 
(62 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{Under_Construction}}
+
[[Image:Android-logo.png]]
  
This page will sumarize the efforts made to have Android running on the APF boards.
+
This page will summarize the efforts made to have Android running on the APF boards.
  
{{Note| Due to Android requirements (at least an ARM926 core), it is impossible to have it running on the APF9328}}
+
{{Note| Due to Android requirements (at least an ARM926 core), it is impossible to have it running on the APF9328. Currently, only APF27 port was tested. }}
 +
 
 +
==Some readings before starting==
 +
* http://developer.android.com/guide/basics/what-is-android.html
 +
 
 +
==Prerequisites for Android installation==
 +
===Install needed software packages===
 +
* Install these packages to build the kernel image and to format the SD/microSD card
 +
<pre class="host">
 +
sudo apt-get install uboot-mkimage mtd-utils
 +
</pre>
 +
* The Armadeus [[Toolchain]], only for Armadeus patches
 +
 
 +
===Update the environment variables===
 +
Theses environment variables install the Android and Armadeus folder in our home directory, but of course, it can be placed anywhere!
 +
<pre class="config">
 +
export ANDROID_SOURCE=~/android-eclair
 +
export ANDROID_KERNEL=~/android-kernel
 +
export ANDROID_SDK=~/android-sdk-linux
 +
export ARMADEUS=~/armadeus-3.1
 +
export PATH=${PATH}:${ANDROID_SDK}/tools:${ANDROID_SOURCE}/bin
 +
</pre>
 +
 
 +
===Download Android source===
 +
* List of different Android branch: [http://android.git.kernel.org/?p=platform/manifest.git;a=heads heads].
 +
* The [http://source.android.com/source/initializing.html "Initializing a Build Environment"] document describes how to set up your local work/build environment. Follow the given instructions until ''Downloading the Source Tree / Installing Repo'' chapter.
 +
<pre class="host">
 +
$ mkdir -p $ANDROID_SOURCE
 +
$ cd $ANDROID_SOURCE
 +
$ mkdir bin
 +
$ curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > $ANDROID_SOURCE/bin/repo
 +
$ chmod a+x $ANDROID_SOURCE/bin/repo
 +
$ export PATH=$PATH:$ANDROID_SOURCE/bin
 +
##$ repo init -u git://android.git.kernel.org/platform/manifest.git -b eclair-release ???
 +
$ repo init -u https://android.googlesource.com/platform/manifest -b android-2.1_r2
 +
$ repo sync      (will take some time and ~1,5GBytes)
 +
</pre>
 +
 
 +
* Since android-sdk-1.5_r3 branch, the Linux kernel isn't included with the Android source anymore. We can download it in a compressed archive (tar.gz): [http://android.git.kernel.org/?p=kernel/common.git;a=snapshot;h=refs/heads/android-2.6.29;sf=tgz android-kernel-2.6.29] (about 70 MBytes) or from the git repository (more than 300 MBytes):
 +
<pre class="host">
 +
$ mkdir $ANDROID_KERNEL
 +
$ cd $ANDROID_KERNEL
 +
$ git clone git://android.git.kernel.org/kernel/common.git android-2.6.29
 +
</pre>
 +
* If kernel.org is down, you can still get android kernel sources from GitHub mirror (zip file): https://github.com/android/kernel_common/tree/archive/android-2.6.29
 +
* '''Updates ANDROID_KERNEL envt variable''':
 +
ANDROID_KERNEL=$ANDROID_KERNEL/android-2.6.29
 +
 
 +
==Linux Kernel 2.6.29==
 +
===Apply the Armadeus patchset===
 +
* Before compiling the android kernel, we need to patch the source with the Armadeus patches.
 +
{{Warning| Never export ARCH and CROSS_COMPILE environment variables because Android make use them too}}
 +
<strike>
 +
$ $ARMADEUS/buildroot/toolchain/patch-kernel.sh $ANDROID_KERNEL $ARMADEUS/downloads patch-2.6.29.6.bz2
 +
</strike>
 +
<pre class="host">
 +
$ $ARMADEUS/buildroot/toolchain/patch-kernel.sh $ANDROID_KERNEL $ARMADEUS/patches/linux/2.6.29 \*.patch{,.gz,.bz2}
 +
$ mkdir $ANDROID_KERNEL/drivers/armadeus
 +
$ cp -r $ARMADEUS/target/linux/modules/* $ANDROID_KERNEL/drivers/armadeus
 +
</pre>
 +
 
 +
*To generate the Linux kernel, we retrieve the default [[APF27]] Linux configuration and modify it to suit android needs:
 +
<pre class="host">
 +
$ cp $ARMADEUS/buildroot/target/device/armadeus/apf27/apf27-linux-2.6.29.config $ANDROID_KERNEL/arch/arm/configs/apf27_android_defconfig
 +
$ cd $ANDROID_KERNEL
 +
$ make ARCH=arm mrproper    (if not first build)
 +
$ make ARCH=arm apf27_android_defconfig
 +
$ make ARCH=arm menuconfig
 +
</pre>
 +
* Compile it:
 +
<pre class="host">
 +
$ PATH=$PATH:$ARMADEUS/buildroot/output/host/usr/bin          (to have mkimage tool)
 +
$ make ARCH=arm CROSS_COMPILE=$ANDROID_SOURCE/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi- uImage
 +
$ cp $ANDROID_KERNEL/arch/arm/boot/uImage /tftpboot/apf27-linux.bin
 +
</pre>
 +
 
 +
* Make sure your kernel boots normally on your board.
 +
 
 +
===Android kernel configuration===
 +
 
 +
* Then enable some Android specific configuration and make sure that your kernel still boots (with your standard file system):
 +
<pre class="host">
 +
$ cd $ANDROID_KERNEL
 +
$ make ARCH=arm menuconfig
 +
</pre>
 +
 
 +
* Activate the ''Android pmem allocator''
 +
<pre class="config">
 +
Device Drivers  --->
 +
    [*] Misc devices  --->
 +
        [*]  Android pmem allocator
 +
</pre>
 +
* Activate the ''Android drivers''
 +
<pre class="config">
 +
Device Drivers  --->
 +
    [*] Staging drivers  --->
 +
        [ ] Exclude Staging drivers from being built (NEW)
 +
        ...
 +
        Android  --->
 +
            [*] Android Drivers
 +
            [*] Android Binder IPC Driver
 +
            <*> Android log driver 
 +
            [ ] Android RAM buffer console
 +
            [*] Timed output class driver (NEW)
 +
            < >  Android timed gpio driver (NEW)
 +
            [*] Android Low Memory Killer
 +
</pre>
 +
* Activate the ''Anonymous Shared Memory Subsystem''
 +
<pre class="config">
 +
General setup  --->
 +
    [*] Enable the Anonymous Shared Memory Subsystem
 +
</pre>
 +
 
 +
===Power management configuration===
 +
<pre class="config">
 +
Power management options  --->
 +
    [*] Wake lock
 +
    [*]  Wake lock stats (NEW)
 +
    [*]  Userspace wake locks (NEW)
 +
    [*]  Early suspend (NEW)
 +
        User-space screen access (Console switch on early-suspend)  --->
 +
            (X) Sysfs interface
 +
 
 +
Device Drivers  --->
 +
    <*> Power supply class support  --->
 +
</pre>
 +
 
 +
===Touchscreen kernel configuration===
 +
* Activate the wake lock for spi event reach to Android and include in the compiled kernel the touchscreen driver
 +
<pre class="config">
 +
Device Drivers  --->
 +
    Input device support  --->
 +
        [*]  Touchscreens  --->
 +
            <*>  TSC 2102 based touchscreens
 +
    ...
 +
    <*> Hardware Monitoring support  --->
 +
</pre>
 +
 
 +
===Audio kernel configuration===
 +
* Include in the compiled kernel the audio driver
 +
<pre class="config">
 +
Device Drivers  --->
 +
  <*> Sound card support  --->
 +
      --- Sound card support
 +
      <*>  Advanced Linux Sound Architecture  --->
 +
        [*]  ARM sound devices  --->
 +
            --- ARM sound
 +
            <*>  i.MX27 SSI driver
 +
            <*>  TSC210x alsa driver
 +
</pre>
 +
===Modify touchscreen driver===
 +
* Android doesn't use tslib library, so we have to add the calibration data directly in the touchscreen driver.
 +
* Edit ''$ANDROID_KERNEL/drivers/input/touchscreen/tsc2102_ts.c'' and add new definitions for X and Y ranges:
 +
<source lang="c">
 +
#include <linux/spi/tsc2102.h>
 +
 
 +
#define DRIVER_NAME "TSC210x Touchscreen"
 +
+#define X_AXIS_MAX    4000
 +
+#define X_AXIS_MIN    0
 +
+#define Y_AXIS_MAX    4200
 +
+#define Y_AXIS_MIN    100
 +
+#define PRESSURE_MIN  20
 +
+#define PRESSURE_MAX  40000
 +
+#define FACTOR        5000
 +
</source>
 +
 
 +
* Send touch event to Android when the user release the touchscreen:
 +
<source lang="c">
 +
static void tsc210x_touch(int touching)
 +
{
 +
    if (!touching) {
 +
-        input_report_abs(dev, ABS_X, 0);
 +
-        input_report_abs(dev, ABS_Y, 0);
 +
+        input_report_key(dev, BTN_TOUCH, 0);
 +
        input_report_abs(dev, ABS_PRESSURE, 0);
 +
        input_sync(dev);
 +
    }
 +
 
 +
-  input_report_key(dev, BTN_TOUCH, touching);
 +
-
 +
-  do_poke_blanked_console = 1;
 +
}
 +
</source>
 +
<source lang="c">
 +
static void tsc210x_coords(int x, int y, int z1, int z2)
 +
{
 +
    int p;
 +
 
 +
    /* Calculate the touch resistance a la equation #1 */
 +
    if (z1 != 0)
 +
-      p = x * (z2 - z1) / (z1 << 4);
 +
+      p = x * (z2 - z1) / (z1 << 4) * FACTOR;
 +
    else
 +
        p = 1;
 +
       
 +
+  y = Y_AXIS_MAX - y;
 +
+  input_report_key(dev, BTN_TOUCH, 1);
 +
    input_report_abs(dev, ABS_X, x);
 +
    input_report_abs(dev, ABS_Y, y);
 +
    input_report_abs(dev, ABS_PRESSURE, p);
 +
    input_sync(dev);
 +
}
 +
</source>
 +
 
 +
* Calibrate the touchscreen with X and Y ranges
 +
<source lang="c">
 +
static int tsc210x_ts_probe(struct platform_device *pdev)
 +
{
 +
  int status;
 +
 
 +
  dev = input_allocate_device();
 +
  if (!dev)
 +
      return -ENOMEM;
 +
 
 +
  status = tsc210x_touch_cb(tsc210x_touch);
 +
  if (status) {
 +
      goto error;
 +
  }
 +
 
 +
  status = tsc210x_coords_cb(tsc210x_coords);
 +
  if (status) {
 +
      goto error;
 +
  }
 +
 
 +
  dev->name = DRIVER_NAME;
 +
  dev->dev.parent = &pdev->dev;
 +
  dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 +
  dev->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);
 +
  dev->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | BIT_MASK(ABS_PRESSURE);
 +
+  input_set_abs_params(dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
 +
+  input_set_abs_params(dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
 +
+  input_set_abs_params(dev, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0);
 +
  status = input_register_device(dev);
 +
  if (status) {
 +
      printk(KERN_INFO "Unable to register TSC210x as input device !\n");
 +
      goto error;
 +
  }
 +
 
 +
  printk(DRIVER_NAME " driver initialized\n");
 +
  return 0;
 +
 
 +
error:
 +
  input_free_device(dev);
 +
  return status;
 +
}
 +
</source>
 +
 
 +
===Build Android kernel===
 +
* Compile the kernel and generate image kernel for U-Boot loader:
 +
<pre class="host">
 +
$ cd $ANDROID_KERNEL
 +
$ make ARCH=arm CROSS_COMPILE=$ANDROID_SOURCE/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi- uImage
 +
$ cp $ANDROID_KERNEL/arch/arm/boot/uImage $TFTPBOOT/apf27-linux.bin
 +
</pre>
 +
* Check it is still booting on your board.
 +
 
 +
==Android==
 +
===Battery patch===
 +
{{Note| I'm not sure the following changes for Battery are still needed if "Power class supply" is selected in Linux menuconfig (cf above) -- [[User:JulienB|JulienB]] 13:16, 3 November 2011 (UTC)}}
 +
 
 +
At the beginning, reboot happened over again even though Android logo appeared on board.
 +
Result of investigation, we found that battery power was returned with 0 when boot.. Then, we changed to notify full battery to Android by ignoring the information under ''/sys/class/power_supply'' so that to prevent the power down by low battery ''$ANDROID_SOURCE/frameworks/base/services/jni/com_android_server_BatteryService.cpp''
 +
*Change the battery service status as TRUE
 +
<source lang="c">
 +
static void setBooleanField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
 +
{
 +
  const int SIZE = 16;
 +
  char buf[SIZE];
 +
 
 +
  jboolean value = true; /* change false -> true */
 +
  /*!!!comment out!!!
 +
  if (readFromFile(path, buf, SIZE) > 0) {
 +
      if (buf[0] == '1') {
 +
        value = true;
 +
      }
 +
  }
 +
  */
 +
  env->SetBooleanField(obj, fieldID, value);
 +
}
 +
</source>
 +
*Change the volume, voltage and temperature of battery. Return 100%.
 +
<source lang="c">
 +
static void setIntField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
 +
{
 +
  const int SIZE = 128;
 +
  char buf[SIZE];
 +
 
 +
  jint value = 100; /* change 0 -> 100 */
 +
  /*!!!comment out!!!
 +
  if (readFromFile(path, buf, SIZE) > 0) {
 +
      value = atoi(buf);
 +
  }
 +
  */
 +
  env->SetIntField(obj, fieldID, value);
 +
}
 +
</source>
 +
* Change the battery charged status as full and deterioration status as fair.
 +
<source lang="c">
 +
static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
 +
{
 +
  setBooleanField(env, obj, AC_ONLINE_PATH, gFieldIds.mAcOnline);
 +
  setBooleanField(env, obj, USB_ONLINE_PATH, gFieldIds.mUsbOnline);
 +
  setBooleanField(env, obj, BATTERY_PRESENT_PATH, gFieldIds.mBatteryPresent);
 +
 
 +
  setIntField(env, obj, BATTERY_CAPACITY_PATH, gFieldIds.mBatteryLevel);
 +
  setIntField(env, obj, BATTERY_VOLTAGE_PATH, gFieldIds.mBatteryVoltage);
 +
  setIntField(env, obj, BATTERY_TEMPERATURE_PATH, gFieldIds.mBatteryTemperature);
 +
 
 +
  /* Change */
 +
  env->SetIntField(obj, gFieldIds.mBatteryStatus, gConstants.statusFull);
 +
  env->SetIntField(obj, gFieldIds.mBatteryHealth, gConstants.healthGood);
 +
  env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF("1"));
 +
 
 +
  /*!!!comment out!!!
 +
  const int SIZE = 128;
 +
  char buf[SIZE];
 +
 
 +
  if (readFromFile(BATTERY_STATUS_PATH, buf, SIZE) > 0)
 +
      env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));
 +
 
 +
  if (readFromFile(BATTERY_HEALTH_PATH, buf, SIZE) > 0)
 +
      env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf));
 +
 
 +
  if (readFromFile(BATTERY_TECHNOLOGY_PATH, buf, SIZE) > 0)
 +
      env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));
 +
  */
 +
}
 +
</source>
 +
 
 +
===Audio===
 +
For activate the audio, we should retrieve Alsa android module whose not directly add in the source
 +
<pre class="host">
 +
cd $ANDROID_SOURCE/external
 +
git clone git://android.git.kernel.org/platform/external/alsa-lib.git
 +
git clone git://android.git.kernel.org/platform/external/alsa-utils.git
 +
cd $ANDROID_SOURCE/hardware
 +
git clone git://android.git.kernel.org/platform/hardware/alsa_sound.git
 +
</pre>
 +
 
 +
edit ''$ANDROID_SOURCE/build/target/board/generic/BoardConfig.mk'' and modify the audio divers used by Android
 +
<pre class="config">
 +
# HAVE_HTC_AUDIO_DRIVER := true
 +
# BOARD_USES_GENERIC_AUDIO := true
 +
BOARD_USES_ALSA_AUDIO := true
 +
BUILD_WITH_ALSA_UTILS := true
 +
</pre>
 +
 
 +
edit ''$ANDROID_SOURCE/hardware/alsa_sound/AudioHardwareALSA.cpp'' and change bufferSize to 8192 in twice StreamDefaults structures <br>
 +
edit ''$ANDROID_SOURCE/system/core/init/devices.c'' and add audio device in Linux devices
 +
<source lang="c">
 +
static struct perms_ devperms[] = {
 +
    { "/dev/null",          0666,  AID_ROOT,      AID_ROOT,      0 },
 +
...
 +
    { "/dev/qmi1",          0640,  AID_RADIO,      AID_RADIO,      0 },
 +
    { "/dev/qmi2",          0640,  AID_RADIO,      AID_RADIO,      0 },
 +
    // Add this line
 +
    { "/dev/snd/",          0664,  AID_SYSTEM,    AID_AUDIO,      1 },
 +
    { NULL, 0, 0, 0, 0 },
 +
};
 +
</source>
 +
 
 +
<source lang="c">
 +
static void handle_device_event(struct uevent *uevent)
 +
{
 +
    char devpath[96];
 +
    char *base, *name;
 +
    int block;
 +
...
 +
  } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
 +
      base = "/dev/mtd/";
 +
      mkdir(base, 0755);
 +
  // add this conditionnal block
 +
  } else if(!strncmp(uevent->subsystem, "sound", 5)) {
 +
      base = "/dev/snd/";
 +
      mkdir(base, 0755);
 +
  } else if(!strncmp(uevent->subsystem, "misc", 4) &&
 +
            !strncmp(name, "log_", 4)) {
 +
      base = "/dev/log/";
 +
      mkdir(base, 0755);
 +
      name += 4;
 +
  } else
 +
      base = "/dev/";
 +
}
 +
</source>
 +
Add audio files in Android files system
 +
<pre class="host">
 +
mkdir $ANDROID_SOURCE/system/core/rootdir/media
 +
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio
 +
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio/ui
 +
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio/alarms
 +
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio/notifications
 +
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio/ringtones
 +
cp $ANDROID_SOURCE/frameworks/base/data/sounds/effects/* $ANDROID_SOURCE/system/core/rootdir/media/audio/ui/
 +
cp $ANDROID_SOURCE/frameworks/base/data/sounds/Alarm_* $ANDROID_SOURCE/system/core/rootdir/media/audio/alarms/
 +
cp $ANDROID_SOURCE/frameworks/base/data/sounds/notifications/* $ANDROID_SOURCE/system/core/rootdir/media/audio/notifications/
 +
cp $ANDROID_SOURCE/frameworks/base/data/sounds/Ring_* $ANDROID_SOURCE/system/core/rootdir/media/audio/ringtones/
 +
</pre>
 +
 
 +
===Android start up===
 +
Edit ''$ANDROID_SOURCE/system/core/rootdir/init.rc'', comment/remove/change the '''mount roofs''' in read only mode and '''mount yaffs2''' lines like this:
 +
<pre class="config">
 +
# 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
 +
    export ANDROID_ASSETS /system/app
 +
    export ANDROID_DATA /data
 +
    export EXTERNAL_STORAGE /sdcard
 +
    export BOOTCLASSPATH /system/framework/core.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar
 +
 
 +
+    mount rootfs rootfs / rw remount
 +
 
 +
# Backward compatibility
 +
    symlink /system/etc /etc
 +
    symlink /sys/kernel/debug /d
 +
 
 +
# create mountpoints and mount tmpfs on sqlite_stmt_journals
 +
    mkdir /sdcard 0000 system system
 +
    mkdir /system
 +
    mkdir /data 0771 system system
 +
    mkdir /cache 0770 system cache
 +
    mkdir /config 0500 root root
 +
    mkdir /sqlite_stmt_journals 01777 root root
 +
    mount tmpfs tmpfs /sqlite_stmt_journals size=4m
 +
 
 +
-    mount rootfs rootfs / ro remount
 +
 
 +
    write /proc/sys/kernel/panic_on_oops 1
 +
    write /proc/sys/kernel/hung_task_timeout_secs 0
 +
    write /proc/cpu/alignment 4
 +
    write /proc/sys/kernel/sched_latency_ns 10000000
 +
    write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000
 +
    write /proc/sys/kernel/sched_compat_yield 1
 +
    write /proc/sys/kernel/sched_child_runs_first 0
 +
 
 +
...
 +
 
 +
# mount mtd partitions
 +
    # 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
 +
+    # Mount the SD Card partition
 +
+    setprop EXTERNAL_STORAGE_STATE mounted
 +
+    mount vfat /dev/block/mmcblk0p1 /sdcard nosuid nodev
 +
 
 +
    # 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
 +
 
 +
...
 +
 
 +
    # Same reason as /data above
 +
-  mount yaffs2 mtd@cache /cache nosuid nodev
 +
    chown system cache /cache
 +
    chmod 0770 /cache
 +
 
 +
    # This may have been created by the recovery system with odd permissions
 +
    chown system system /cache/recovery
 +
    chmod 0770 /cache/recovery
 +
 
 +
...
 +
</pre>
 +
 
 +
===Compile===
 +
<pre class="host">
 +
$ cd $ANDROID_SOURCE
 +
$ make
 +
</pre>
 +
 
 +
==Making Rootfs==
 +
===Android Root filesystem===
 +
Android emulator has 3 basic images in ''$ANDROID_SOURCE/tools/lib/images'' directory.
 +
* '''ramdisk.img''' is gziped cpio archive. ramdisk.img is a small partition image that is mounted read-only by the kernel at boot time. It only contains /init and a few config files. It is used to start init which will mount the rest of the system images properly and run the init procedure. A Ramdisk is a standard Linux feature. It is made just for the Android and do special things to start up the Android system.
 +
* '''system.img''' is a partition image that will be mounted as / and thus contains all system binaries.
 +
* '''userdata.img''' is a partition image that can be mounted as /data and thus contains all application-specific and user-specific data.
 +
 
 +
===Create the Android root filesystem for APF27===
 +
Android’s root filesystem is generated in ''$ANDROID_SOURCE/out/target/product/generic''. We will create a folder containing all Android files images.
 +
<pre class="host">
 +
$ sudo rm -rf $ANDROID_SOURCE/rootfs/
 +
$ cd $ANDROID_SOURCE/out/target/product/generic
 +
$ mkdir $ANDROID_SOURCE/rootfs
 +
$ cp -a root/* $ANDROID_SOURCE/rootfs/
 +
$ cp -a system/* $ANDROID_SOURCE/rootfs/system/
 +
$ cd $ANDROID_SOURCE/rootfs
 +
$ sudo chown -R root:root .
 +
$ sudo chmod -R a+rwx data system
 +
</pre>
 +
 
 +
===JFFS2 Root file system===
 +
Actually, Android should use a filesystem that supports mmap() function like yaffs2, ext2/3 or ubifs. For our example we will use ext3 on a microSD for data.
 +
 
 +
====Prepare the MMC/µSD card====
 +
We will create two partitions on our SD/microSD card, The first one will use for Android "memory card", the second one will be used for Android filesystem.
 +
First connect your card reader to your workstation, with the SD/microSD card inside. Type the '''dmesg''' command to see which device is used by your workstation.
 +
{{Warning|Using the wrong device to format the SD/microSD card may corrupt your workstation/laptop harddisk !}}
 +
 
 +
* Let’s assume that this device is '''/dev/sdb''':
 +
<pre class="host">
 +
$ dmesg
 +
...
 +
[ 9145.613954]  sdb: sdb1 sdb2
 +
[ 9145.615125] sd 10:0:0:0: [sdc] Attached SCSI removable disk
 +
[ 9145.615258] sd 10:0:0:0: Attached scsi generic sg3 type 0
 +
</pre>
 +
* Launch the ''mount'' command to check your currently mounted partitions. If SD/microSD partitions are mounted, unmount them with ''umount''.
 +
* In a terminal edit partitions with ''fdisk'':
 +
<pre class="host">
 +
$ sudo fdisk /dev/sdb
 +
</pre>
 +
* Delete any existing partition with the d command:
 +
<pre class="host">
 +
Commande (m for help): d
 +
</pre>
 +
* Now, create the boot partition:
 +
<pre class="host">
 +
Command (m for help): n
 +
Command action
 +
  e  extended
 +
  p  primary partition (1-4)
 +
p
 +
Partition number (1-4): 1
 +
First cylinder (1-495, default 1): 1
 +
Last cylinder, +cylinders or +size{K,M,G} (1-239, default 239): +1G
 +
</pre>
 +
* Change its type to FAT32:
 +
<pre class="host">
 +
Command (m for help): t
 +
Selected partition 1
 +
Hex code (type L to list codes): c
 +
Changed system type of partition 1 to c (W95 FAT32 (LBA))
 +
</pre>
 +
* Using the n command again, create a second primary partition filling up the rest of your card (just accept default values).
 +
* Quit ''fdisk'' and save your changes:
 +
<pre class="host">
 +
Command (m for help): w
 +
</pre>
 +
* Now, format the partitions in your card:
 +
<pre class="host">
 +
$ sudo mkfs.vfat -n MemoryCard -F 32 /dev/sdb1
 +
$ sudo mkfs.ext2 -L data /dev/sdb2
 +
</pre>
 +
 
 +
====Boot setup====
 +
<pre class="host">
 +
$ sudo mkfs.jffs2 -n -e 0x20000 --pad=0x700000 -r $ANDROID_SOURCE/rootfs -o $TFTPBOOT/apf27-rootfs.arm.jffs2
 +
</pre>
 +
 
 +
<pre class="host">
 +
$ cd $ANDROID_SOURCE/rootfs
 +
$ sudo mount /dev/sdb2 /media/mmc/
 +
$ sudo cp -a * /media/mmc/
 +
$ sudo umount /media/mmc/
 +
</pre>
 +
 
 +
* The last thing left to do is to specify how the board boots Linux. In the U-boot prompt, make the mmc boot occur on second partition of the SD/microSD card, set the correct rootfs type and add correct init process name:
 +
<pre class="apf">
 +
BIOS> printenv mmcroot     
 +
mmcroot=/dev/mmcblk0p1
 +
BIOS> setenv mmcroot /dev/mmcblk0p2
 +
 
 +
BIOS> printenv mmcrootfstype
 +
mmcrootfstype=ext2
 +
BIOS> setenv mmcrootfstype ext3
 +
 
 +
BIOS> printenv console
 +
console=console=ttySMX0,115200
 +
BIOS> setenv console console=ttySMX0,115200 init=/init
 +
 
 +
BIOS> saveenv
 +
BIOS> run mmcboot
 +
</pre>
 +
 
 +
* if you definitely want to boot android each time on your board, you can do:
 +
<pre class="apf">
 +
BIOS> setenv bootcmd run mmcboot
 +
BIOS> saveenv
 +
</pre>
 +
 
 +
===NFS Boot===
 +
<pre class="apf">
 +
BIOS> setenv rootpath /local/export/android-eclair
 +
BIOS> setenv console console=ttySMX0,115200 init=/init
 +
BIOS> run nfsboot
 +
</pre>
 +
 
 +
[[Image:Apf27_android.JPG‎]]
 +
 
 +
==Debug==
 +
===Prerequisite===
 +
Installing the [http://developer.android.com/sdk/1.6_r1/installing.html Android Development Tools (ADT)]
 +
Trace with '''logcat''' with Eclipse-ADT
 +
<pre class="host">
 +
export ADBHOST=w.x.y.z
 +
adb kill-server
 +
adb start-server
 +
</pre>
 +
 
 +
===Test with Android emulator===
 +
Documentation on Android [http://developer.android.com/guide/developing/tools/emulator.html emulator]
 +
<pre class="host">
 +
cd $ANDROID_SOURCE/kernel
 +
make ARCH=arm goldfish_defconfig
 +
make ARCH=arm CROSS_COMPILE=$ANDROID_SOURCE/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi
 +
</pre>
 +
Create AVD (Android Virtual Device)
 +
<pre class="host">
 +
$ANDROID_SDK/tools/android create avd -n APF27-H -t 4 -s 272x480
 +
$ANDROID_SDK/tools/android create avd -n APF27-L -t 4 -s 480x272
 +
$ANDROID_SOURCE/out/host/linux-x86/bin/emulator -avd APF27-H -sysdir $ANDROID_SOURCE/out/target/product/generic/ -kernel $ANDROID_SOURCE/kernel/arch/arm/boot/zImage -data $ANDROID_SOURCE/out/target/product/generic/userdata.img -ramdisk $ANDROID_SOURCE/out/target/product/generic/ramdisk.img -system $ANDROID_SOURCE/out/target/product/generic/system.img
 +
</pre>
 +
 
 +
==Links==
 +
* http://source.android.com/porting
 +
* [http://elinux.org/Android Android page on elinux.org]
 +
** [http://elinux.org/Android_on_OMAP Android on OMAP portage page on elinux.org]
 +
* [http://wiki.openmoko.org/wiki/Android Android on OpenMoko]
 +
* http://wiki.kldp.org/wiki.php/AndroidPortingOnRealTarget
 +
 
 +
==Thanks==
 +
Thanks to Xavier Romanens and Fabrice Carrel from the [https://www.eia-fr.ch/fr/ Ecole d'ingénieurs et d'architectes de Fribourg] for their contributions.

Latest revision as of 15:28, 3 November 2011

Android-logo.png

This page will summarize the efforts made to have Android running on the APF boards.

Note Note: Due to Android requirements (at least an ARM926 core), it is impossible to have it running on the APF9328. Currently, only APF27 port was tested.


Some readings before starting

Prerequisites for Android installation

Install needed software packages

  • Install these packages to build the kernel image and to format the SD/microSD card
sudo apt-get install uboot-mkimage mtd-utils
  • The Armadeus Toolchain, only for Armadeus patches

Update the environment variables

Theses environment variables install the Android and Armadeus folder in our home directory, but of course, it can be placed anywhere!

export ANDROID_SOURCE=~/android-eclair
export ANDROID_KERNEL=~/android-kernel
export ANDROID_SDK=~/android-sdk-linux
export ARMADEUS=~/armadeus-3.1
export PATH=${PATH}:${ANDROID_SDK}/tools:${ANDROID_SOURCE}/bin

Download Android source

  • List of different Android branch: heads.
  • The "Initializing a Build Environment" document describes how to set up your local work/build environment. Follow the given instructions until Downloading the Source Tree / Installing Repo chapter.
$ mkdir -p $ANDROID_SOURCE
$ cd $ANDROID_SOURCE
$ mkdir bin
$ curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > $ANDROID_SOURCE/bin/repo
$ chmod a+x $ANDROID_SOURCE/bin/repo
$ export PATH=$PATH:$ANDROID_SOURCE/bin
##$ repo init -u git://android.git.kernel.org/platform/manifest.git -b eclair-release ???
$ repo init -u https://android.googlesource.com/platform/manifest -b android-2.1_r2
$ repo sync      (will take some time and ~1,5GBytes)
  • Since android-sdk-1.5_r3 branch, the Linux kernel isn't included with the Android source anymore. We can download it in a compressed archive (tar.gz): android-kernel-2.6.29 (about 70 MBytes) or from the git repository (more than 300 MBytes):
$ mkdir $ANDROID_KERNEL
$ cd $ANDROID_KERNEL
$ git clone git://android.git.kernel.org/kernel/common.git android-2.6.29
ANDROID_KERNEL=$ANDROID_KERNEL/android-2.6.29

Linux Kernel 2.6.29

Apply the Armadeus patchset

  • Before compiling the android kernel, we need to patch the source with the Armadeus patches.
Warning Warning: Never export ARCH and CROSS_COMPILE environment variables because Android make use them too

$ $ARMADEUS/buildroot/toolchain/patch-kernel.sh $ANDROID_KERNEL $ARMADEUS/downloads patch-2.6.29.6.bz2

$ $ARMADEUS/buildroot/toolchain/patch-kernel.sh $ANDROID_KERNEL $ARMADEUS/patches/linux/2.6.29 \*.patch{,.gz,.bz2}
$ mkdir $ANDROID_KERNEL/drivers/armadeus
$ cp -r $ARMADEUS/target/linux/modules/* $ANDROID_KERNEL/drivers/armadeus
  • To generate the Linux kernel, we retrieve the default APF27 Linux configuration and modify it to suit android needs:
$ cp $ARMADEUS/buildroot/target/device/armadeus/apf27/apf27-linux-2.6.29.config $ANDROID_KERNEL/arch/arm/configs/apf27_android_defconfig
$ cd $ANDROID_KERNEL
$ make ARCH=arm mrproper    (if not first build)
$ make ARCH=arm apf27_android_defconfig
$ make ARCH=arm menuconfig
  • Compile it:
$ PATH=$PATH:$ARMADEUS/buildroot/output/host/usr/bin           (to have mkimage tool)
$ make ARCH=arm CROSS_COMPILE=$ANDROID_SOURCE/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi- uImage
$ cp $ANDROID_KERNEL/arch/arm/boot/uImage /tftpboot/apf27-linux.bin
  • Make sure your kernel boots normally on your board.

Android kernel configuration

  • Then enable some Android specific configuration and make sure that your kernel still boots (with your standard file system):
$ cd $ANDROID_KERNEL
$ make ARCH=arm menuconfig
  • Activate the Android pmem allocator
Device Drivers  --->
    [*] Misc devices  --->
        [*]   Android pmem allocator
  • Activate the Android drivers
Device Drivers  --->
    [*] Staging drivers  ---> 
        [ ] Exclude Staging drivers from being built (NEW)
        ...
        Android  --->
            [*] Android Drivers
            [*] Android Binder IPC Driver
            <*> Android log driver  
            [ ] Android RAM buffer console
            [*] Timed output class driver (NEW)
            < >   Android timed gpio driver (NEW)
            [*] Android Low Memory Killer 
  • Activate the Anonymous Shared Memory Subsystem
General setup  --->
    [*] Enable the Anonymous Shared Memory Subsystem

Power management configuration

Power management options  --->
    [*] Wake lock
    [*]   Wake lock stats (NEW)
    [*]   Userspace wake locks (NEW)
    [*]   Early suspend (NEW)
        User-space screen access (Console switch on early-suspend)  --->
            (X) Sysfs interface

Device Drivers  --->
    <*> Power supply class support  --->

Touchscreen kernel configuration

  • Activate the wake lock for spi event reach to Android and include in the compiled kernel the touchscreen driver
Device Drivers  --->
    Input device support  --->
        [*]   Touchscreens  --->
            <*>   TSC 2102 based touchscreens
    ...
    <*> Hardware Monitoring support  --->

Audio kernel configuration

  • Include in the compiled kernel the audio driver
Device Drivers  --->
   <*> Sound card support  --->
      --- Sound card support
      <*>   Advanced Linux Sound Architecture  --->
         [*]   ARM sound devices  --->
            --- ARM sound 
            <*>   i.MX27 SSI driver
            <*>   TSC210x alsa driver

Modify touchscreen driver

  • Android doesn't use tslib library, so we have to add the calibration data directly in the touchscreen driver.
  • Edit $ANDROID_KERNEL/drivers/input/touchscreen/tsc2102_ts.c and add new definitions for X and Y ranges:
#include <linux/spi/tsc2102.h>

#define DRIVER_NAME "TSC210x Touchscreen"
+#define X_AXIS_MAX    4000
+#define X_AXIS_MIN    0
+#define Y_AXIS_MAX    4200
+#define Y_AXIS_MIN    100
+#define PRESSURE_MIN  20
+#define PRESSURE_MAX  40000
+#define FACTOR        5000
  • Send touch event to Android when the user release the touchscreen:
static void tsc210x_touch(int touching)
{
    if (!touching) {
-        input_report_abs(dev, ABS_X, 0);
-        input_report_abs(dev, ABS_Y, 0);
+        input_report_key(dev, BTN_TOUCH, 0);
        input_report_abs(dev, ABS_PRESSURE, 0);
        input_sync(dev);
    }

-   input_report_key(dev, BTN_TOUCH, touching);
-
-   do_poke_blanked_console = 1;
}
static void tsc210x_coords(int x, int y, int z1, int z2)
{
    int p;

    /* Calculate the touch resistance a la equation #1 */
    if (z1 != 0)
-       p = x * (z2 - z1) / (z1 << 4);
+       p = x * (z2 - z1) / (z1 << 4) * FACTOR;
    else
        p = 1;
        
+   y = Y_AXIS_MAX - y;
+   input_report_key(dev, BTN_TOUCH, 1);
    input_report_abs(dev, ABS_X, x);
    input_report_abs(dev, ABS_Y, y);
    input_report_abs(dev, ABS_PRESSURE, p);
    input_sync(dev);
}
  • Calibrate the touchscreen with X and Y ranges
static int tsc210x_ts_probe(struct platform_device *pdev)
{
   int status;

   dev = input_allocate_device();
   if (!dev)
      return -ENOMEM;

   status = tsc210x_touch_cb(tsc210x_touch);
   if (status) {
      goto error;
   }

   status = tsc210x_coords_cb(tsc210x_coords);
   if (status) {
      goto error;
   }

   dev->name = DRIVER_NAME;
   dev->dev.parent = &pdev->dev;
   dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
   dev->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);
   dev->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | BIT_MASK(ABS_PRESSURE);
+  input_set_abs_params(dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
+  input_set_abs_params(dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
+  input_set_abs_params(dev, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0);
   status = input_register_device(dev);
   if (status) {
      printk(KERN_INFO "Unable to register TSC210x as input device !\n");
      goto error;
   }

   printk(DRIVER_NAME " driver initialized\n");
   return 0;

error:
   input_free_device(dev);
   return status;
}

Build Android kernel

  • Compile the kernel and generate image kernel for U-Boot loader:
$ cd $ANDROID_KERNEL
$ make ARCH=arm CROSS_COMPILE=$ANDROID_SOURCE/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi- uImage
$ cp $ANDROID_KERNEL/arch/arm/boot/uImage $TFTPBOOT/apf27-linux.bin
  • Check it is still booting on your board.

Android

Battery patch

Note Note: I'm not sure the following changes for Battery are still needed if "Power class supply" is selected in Linux menuconfig (cf above) -- JulienB 13:16, 3 November 2011 (UTC)


At the beginning, reboot happened over again even though Android logo appeared on board. Result of investigation, we found that battery power was returned with 0 when boot.. Then, we changed to notify full battery to Android by ignoring the information under /sys/class/power_supply so that to prevent the power down by low battery $ANDROID_SOURCE/frameworks/base/services/jni/com_android_server_BatteryService.cpp

  • Change the battery service status as TRUE
static void setBooleanField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
{
   const int SIZE = 16;
   char buf[SIZE];

   jboolean value = true; /* change false -> true */
   /*!!!comment out!!!
   if (readFromFile(path, buf, SIZE) > 0) {
      if (buf[0] == '1') {
         value = true;
      }
   }
   */
   env->SetBooleanField(obj, fieldID, value);
}
  • Change the volume, voltage and temperature of battery. Return 100%.
static void setIntField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
{
   const int SIZE = 128;
   char buf[SIZE];

   jint value = 100; /* change 0 -> 100 */
   /*!!!comment out!!!
   if (readFromFile(path, buf, SIZE) > 0) {
      value = atoi(buf);
   }
   */
   env->SetIntField(obj, fieldID, value);
}
  • Change the battery charged status as full and deterioration status as fair.
static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
{
   setBooleanField(env, obj, AC_ONLINE_PATH, gFieldIds.mAcOnline);
   setBooleanField(env, obj, USB_ONLINE_PATH, gFieldIds.mUsbOnline);
   setBooleanField(env, obj, BATTERY_PRESENT_PATH, gFieldIds.mBatteryPresent);

   setIntField(env, obj, BATTERY_CAPACITY_PATH, gFieldIds.mBatteryLevel);
   setIntField(env, obj, BATTERY_VOLTAGE_PATH, gFieldIds.mBatteryVoltage);
   setIntField(env, obj, BATTERY_TEMPERATURE_PATH, gFieldIds.mBatteryTemperature);

   /* Change */
   env->SetIntField(obj, gFieldIds.mBatteryStatus, gConstants.statusFull);
   env->SetIntField(obj, gFieldIds.mBatteryHealth, gConstants.healthGood);
   env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF("1"));

   /*!!!comment out!!!
   const int SIZE = 128;
   char buf[SIZE];

   if (readFromFile(BATTERY_STATUS_PATH, buf, SIZE) > 0)
      env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));

   if (readFromFile(BATTERY_HEALTH_PATH, buf, SIZE) > 0)
      env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf));

   if (readFromFile(BATTERY_TECHNOLOGY_PATH, buf, SIZE) > 0)
      env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));
   */
}

Audio

For activate the audio, we should retrieve Alsa android module whose not directly add in the source

cd $ANDROID_SOURCE/external
git clone git://android.git.kernel.org/platform/external/alsa-lib.git
git clone git://android.git.kernel.org/platform/external/alsa-utils.git
cd $ANDROID_SOURCE/hardware 
git clone git://android.git.kernel.org/platform/hardware/alsa_sound.git

edit $ANDROID_SOURCE/build/target/board/generic/BoardConfig.mk and modify the audio divers used by Android

 
# HAVE_HTC_AUDIO_DRIVER := true
# BOARD_USES_GENERIC_AUDIO := true
BOARD_USES_ALSA_AUDIO := true
BUILD_WITH_ALSA_UTILS := true

edit $ANDROID_SOURCE/hardware/alsa_sound/AudioHardwareALSA.cpp and change bufferSize to 8192 in twice StreamDefaults structures
edit $ANDROID_SOURCE/system/core/init/devices.c and add audio device in Linux devices

static struct perms_ devperms[] = {
    { "/dev/null",          0666,   AID_ROOT,       AID_ROOT,       0 },
...
    { "/dev/qmi1",          0640,   AID_RADIO,      AID_RADIO,      0 },
    { "/dev/qmi2",          0640,   AID_RADIO,      AID_RADIO,      0 },
    // Add this line
    { "/dev/snd/",          0664,   AID_SYSTEM,     AID_AUDIO,      1 },
    { NULL, 0, 0, 0, 0 },
};
static void handle_device_event(struct uevent *uevent)
{
    char devpath[96];
    char *base, *name;
    int block;
...
   } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
      base = "/dev/mtd/";
      mkdir(base, 0755);
   // add this conditionnal block
   } else if(!strncmp(uevent->subsystem, "sound", 5)) {
      base = "/dev/snd/";
      mkdir(base, 0755);
   } else if(!strncmp(uevent->subsystem, "misc", 4) &&
             !strncmp(name, "log_", 4)) {
      base = "/dev/log/";
      mkdir(base, 0755);
      name += 4;
   } else
      base = "/dev/";
}

Add audio files in Android files system

mkdir $ANDROID_SOURCE/system/core/rootdir/media 
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio 
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio/ui
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio/alarms 
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio/notifications 
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio/ringtones 
cp $ANDROID_SOURCE/frameworks/base/data/sounds/effects/* $ANDROID_SOURCE/system/core/rootdir/media/audio/ui/ 
cp $ANDROID_SOURCE/frameworks/base/data/sounds/Alarm_* $ANDROID_SOURCE/system/core/rootdir/media/audio/alarms/
cp $ANDROID_SOURCE/frameworks/base/data/sounds/notifications/* $ANDROID_SOURCE/system/core/rootdir/media/audio/notifications/
cp $ANDROID_SOURCE/frameworks/base/data/sounds/Ring_* $ANDROID_SOURCE/system/core/rootdir/media/audio/ringtones/

Android start up

Edit $ANDROID_SOURCE/system/core/rootdir/init.rc, comment/remove/change the mount roofs in read only mode and mount yaffs2 lines like this:

 # 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
    export ANDROID_ASSETS /system/app
    export ANDROID_DATA /data
    export EXTERNAL_STORAGE /sdcard
    export BOOTCLASSPATH /system/framework/core.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar

+    mount rootfs rootfs / rw remount

# Backward compatibility
    symlink /system/etc /etc
    symlink /sys/kernel/debug /d

# create mountpoints and mount tmpfs on sqlite_stmt_journals
    mkdir /sdcard 0000 system system
    mkdir /system
    mkdir /data 0771 system system
    mkdir /cache 0770 system cache
    mkdir /config 0500 root root
    mkdir /sqlite_stmt_journals 01777 root root
    mount tmpfs tmpfs /sqlite_stmt_journals size=4m

-    mount rootfs rootfs / ro remount

    write /proc/sys/kernel/panic_on_oops 1
    write /proc/sys/kernel/hung_task_timeout_secs 0
    write /proc/cpu/alignment 4
    write /proc/sys/kernel/sched_latency_ns 10000000
    write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000
    write /proc/sys/kernel/sched_compat_yield 1
    write /proc/sys/kernel/sched_child_runs_first 0

...

# mount mtd partitions
    # 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
+    # Mount the SD Card partition
+    setprop EXTERNAL_STORAGE_STATE mounted
+    mount vfat /dev/block/mmcblk0p1 /sdcard nosuid nodev

    # 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

...

    # Same reason as /data above
-   mount yaffs2 mtd@cache /cache nosuid nodev
    chown system cache /cache
    chmod 0770 /cache

    # This may have been created by the recovery system with odd permissions
    chown system system /cache/recovery
    chmod 0770 /cache/recovery

...

Compile

$ cd $ANDROID_SOURCE
$ make

Making Rootfs

Android Root filesystem

Android emulator has 3 basic images in $ANDROID_SOURCE/tools/lib/images directory.

  • ramdisk.img is gziped cpio archive. ramdisk.img is a small partition image that is mounted read-only by the kernel at boot time. It only contains /init and a few config files. It is used to start init which will mount the rest of the system images properly and run the init procedure. A Ramdisk is a standard Linux feature. It is made just for the Android and do special things to start up the Android system.
  • system.img is a partition image that will be mounted as / and thus contains all system binaries.
  • userdata.img is a partition image that can be mounted as /data and thus contains all application-specific and user-specific data.

Create the Android root filesystem for APF27

Android’s root filesystem is generated in $ANDROID_SOURCE/out/target/product/generic. We will create a folder containing all Android files images.

$ sudo rm -rf $ANDROID_SOURCE/rootfs/
$ cd $ANDROID_SOURCE/out/target/product/generic
$ mkdir $ANDROID_SOURCE/rootfs
$ cp -a root/* $ANDROID_SOURCE/rootfs/
$ cp -a system/* $ANDROID_SOURCE/rootfs/system/
$ cd $ANDROID_SOURCE/rootfs
$ sudo chown -R root:root .
$ sudo chmod -R a+rwx data system

JFFS2 Root file system

Actually, Android should use a filesystem that supports mmap() function like yaffs2, ext2/3 or ubifs. For our example we will use ext3 on a microSD for data.

Prepare the MMC/µSD card

We will create two partitions on our SD/microSD card, The first one will use for Android "memory card", the second one will be used for Android filesystem. First connect your card reader to your workstation, with the SD/microSD card inside. Type the dmesg command to see which device is used by your workstation.

Warning Warning: Using the wrong device to format the SD/microSD card may corrupt your workstation/laptop harddisk !


  • Let’s assume that this device is /dev/sdb:
$ dmesg
...
[ 9145.613954]  sdb: sdb1 sdb2
[ 9145.615125] sd 10:0:0:0: [sdc] Attached SCSI removable disk
[ 9145.615258] sd 10:0:0:0: Attached scsi generic sg3 type 0
  • Launch the mount command to check your currently mounted partitions. If SD/microSD partitions are mounted, unmount them with umount.
  • In a terminal edit partitions with fdisk:
$ sudo fdisk /dev/sdb
  • Delete any existing partition with the d command:
Commande (m for help): d
  • Now, create the boot partition:
Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-495, default 1): 1
Last cylinder, +cylinders or +size{K,M,G} (1-239, default 239): +1G
  • Change its type to FAT32:
Command (m for help): t
Selected partition 1
Hex code (type L to list codes): c
Changed system type of partition 1 to c (W95 FAT32 (LBA))
  • Using the n command again, create a second primary partition filling up the rest of your card (just accept default values).
  • Quit fdisk and save your changes:
Command (m for help): w
  • Now, format the partitions in your card:
$ sudo mkfs.vfat -n MemoryCard -F 32 /dev/sdb1
$ sudo mkfs.ext2 -L data /dev/sdb2

Boot setup

$ sudo mkfs.jffs2 -n -e 0x20000 --pad=0x700000 -r $ANDROID_SOURCE/rootfs -o $TFTPBOOT/apf27-rootfs.arm.jffs2
$ cd $ANDROID_SOURCE/rootfs
$ sudo mount /dev/sdb2 /media/mmc/
$ sudo cp -a * /media/mmc/
$ sudo umount /media/mmc/
  • The last thing left to do is to specify how the board boots Linux. In the U-boot prompt, make the mmc boot occur on second partition of the SD/microSD card, set the correct rootfs type and add correct init process name:
BIOS> printenv mmcroot       
mmcroot=/dev/mmcblk0p1
BIOS> setenv mmcroot /dev/mmcblk0p2

BIOS> printenv mmcrootfstype 
mmcrootfstype=ext2
BIOS> setenv mmcrootfstype ext3

BIOS> printenv console
console=console=ttySMX0,115200
BIOS> setenv console console=ttySMX0,115200 init=/init

BIOS> saveenv
BIOS> run mmcboot
  • if you definitely want to boot android each time on your board, you can do:
BIOS> setenv bootcmd run mmcboot
BIOS> saveenv

NFS Boot

BIOS> setenv rootpath /local/export/android-eclair
BIOS> setenv console console=ttySMX0,115200 init=/init
BIOS> run nfsboot

Apf27 android.JPG

Debug

Prerequisite

Installing the Android Development Tools (ADT) Trace with logcat with Eclipse-ADT

export ADBHOST=w.x.y.z
adb kill-server
adb start-server

Test with Android emulator

Documentation on Android emulator

cd $ANDROID_SOURCE/kernel
make ARCH=arm goldfish_defconfig
make ARCH=arm CROSS_COMPILE=$ANDROID_SOURCE/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi

Create AVD (Android Virtual Device)

$ANDROID_SDK/tools/android create avd -n APF27-H -t 4 -s 272x480
$ANDROID_SDK/tools/android create avd -n APF27-L -t 4 -s 480x272
$ANDROID_SOURCE/out/host/linux-x86/bin/emulator -avd APF27-H -sysdir $ANDROID_SOURCE/out/target/product/generic/ -kernel $ANDROID_SOURCE/kernel/arch/arm/boot/zImage -data $ANDROID_SOURCE/out/target/product/generic/userdata.img -ramdisk $ANDROID_SOURCE/out/target/product/generic/ramdisk.img -system $ANDROID_SOURCE/out/target/product/generic/system.img

Links

Thanks

Thanks to Xavier Romanens and Fabrice Carrel from the Ecole d'ingénieurs et d'architectes de Fribourg for their contributions.