Compilar Android Cupcake (1.5) en Ubuntu Karmic (10.9)

Introducción

Android es una plataforma extensa y el proceso de compilación es complejo. Está muy probado así que lo normal es que estemos en la plataforma que estemos, encontraremos experiencias sobre que tocar para que toco compile bien.

En esta página nos referiremos a Ubuntu Karmic y a la rama Cupcake (1.5) de Android, y según el tiempo lo permita, iremos incluyendo otros entornos si los necesitamos.

Resumen de alto nivel

Una ROM de Android es una distro de Linux compilada desde cero. Muy similar a Linux From Scratch. En el proceso para Cyanogen se crean todo el sistema completo, incluyendo el sistema de recuperación (recovery.img), el sistema de arranque (núcleo + ramdisk, boot.img) y el sistema base con las aplicaciones (system.img).

En la compilación de la plataforma se incluyes pues:

Para compilar necesitamos Java y gcc y g++. El proceso de compilación es largo y necesitamos bastante disco duro (10 GB). Además, necesitamos el móvil destino para poder extraer de él algunos ficheros binarios como los drivers de la parte de radio.

Una vez acabado el proceso deberemos de juntar todo en un fichero de actualización, "update.zip", para poder instalarlo de forma cómoda sobre el móvil. También podríamos hacer paso a paso con fastboot.

Antes de compilar

Tengo aún por probar si ya funciona con JDK6 ya que 1.5 ya no tiene ni soporte. En tiempo de compilación se comprueba y es necesario JDK 1.5. Así se instalar en Ubuntu posterior a jaunty.

Descarga de Cupcake

Es recomendable manejarnos bien con git.

$ mkdir cupcake
$ cd cupcake
$ repo init -u git://android.git.kernel.org/platform/manifest.git -b cupcake
$ repo sync 
$ make

Con esto lo que hemos hecho es bajarnos el repositorio entero y luego irnos a la rama cupcake. Dentro de este mismo repositorio podemos saltar a otras ramas. Por ejemplo, si quisiéramos irnos a Android 2.0 saltaríamos a eclair con:

$ repo sync
$ repo init -u git://android.git.kernel.org/platform/manifest.git -b eclair

Tras descargar todos los ficheros, son 2.1 GB aprox, comenzará el proceso de compilación.

Una vez completado el proceso nos genera los ficheros:

tree -L 1 out/target/product/generic/
out/target/product/generic/
|-- android-info.txt
|-- clean_steps.mk
|-- data
|-- installed-files.txt
|-- obj
|-- previous_build_config.mk
|-- ramdisk.img
|-- root
|-- symbols
|-- system
|-- system.img
`-- userdata.img

Tenemos tres ficheros "img" que serán los que hay que utilizar para crear el sistema.

Compilando Android 2.2 (Froyo)

El proceso para compilar Android 2.2, aka Froyo, es idéntico y se terminan generando los ficheros

find . -name "*.img"
./out/target/product/generic/userdata.img
./out/target/product/generic/ramdisk.img
./out/target/product/generic/system.img

Compilando Android 2.2 (Froyo) para x86

Existe un proyecto donde preparan Android para ser ejecutado en plataformas x86, algo que es natural ya que es la arquitectura más habitual en GNU/Linux. En dicho proyecto lo que hacen es generar a partir del núcleo y fuentes del sistema Android una ISO en CD desde la que poder ejecutar en modo "live" el sistema en una plataforma x86, o donde poder instalarla. También se puede generar una imagen para ser usada desde USB.

export PATH=$PATH:/sbin (para que encuentre tune2fs)
sudo apt-get install genisoimage
acs@macitong:~/devel/android/x86$ repo init -u git://android-x86.git.sf.net/gitroot/android-x86/manifest.git -b froyo-x86
Getting repo ...
   from git://android.git.kernel.org/tools/repo.git
remote: Counting objects: 1090, done.
....
From git://android-x86.git.sf.net/gitroot/android-x86/manifest
 * [new branch]      donut-x86  -> origin/donut-x86
 * [new branch]      eclair-x86 -> origin/eclair-x86
 * [new branch]      froyo-x86  -> origin/froyo-x86
 * [new branch]      master     -> origin/master
....
acs@macitong:~/devel/android/x86$ repo sync
Initializing project platform/bionic ...
remote: Counting objects: 5350, done
...
make iso_img TARGET_PRODUCT=generic_x86
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=2.2
TARGET_PRODUCT=generic_x86
TARGET_BUILD_VARIANT=eng
TARGET_SIMULATOR=
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=x86
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=MASTER
============================================
Checking build tools versions...
...
292592 extents written (571 MB)
ls -l out/target/product/generic_x86/generic_x86.iso 
-rw-r--r-- 1 acs acs 599228416 ago  9 22:28 out/target/product/generic_x86/generic_x86.is
make usb_img TARGET_PRODUCT=generic_x86
I/diskutils( 9648): Wrote 620490752 bytes to out/target/product/generic_x86/generic_x86_usb.img @ 1048576
File edit complete. Wrote 1 images.

Ya tenemos tanto una ISO como un sistema USB autoarrancable con android 2.2 para x86.

Si queremos probar todo en una máquina virtual, nos hacemos una ISO pero con una imagen preparada para máquina virtual, donde le ratón debe de ser el puntero y no la pantalla táctil:

make iso_img TARGET_PRODUCT=vm
ls -l out/target/product/vm/vm.iso 
-rw-r--r-- 1 acs acs 572549120 ago 10 00:55 out/target/product/vm/vm.iso

Luego nos creamos una nueva máquina virtual en virtual box y ponemos esta ISO como dentro del CD de dicha máquina, arrancamos y podemos probar en modo "live" o instalar android 2.2 en ella.

Vamos a meter en un llavero USB la imagen USB autoarracanble. Para ello metemos un llavero USB de 1GB (sin datos importantes) en el ordenador con dicha imagen y ejecutamos:

dd if=devel/android/x86/generic_x86_usb.img of=/dev/sdb
1213944+0 registros de entrada
1213944+0 registros de salida
621539328 bytes (622 MB) copiados, 280,915 s, 2,2 MB/s

Luego arrancamos desde USB y ya procedemos con el proceso de Instalación.

Manejando el entorno de compilación

La compilación de Android es un proceso bastante lento. Si realizamos cambios nos gustaría lograr que fuera incremental. Vamos a realizar un estudio de esto:

¿Qué hacer ahora?

Ya somos capaces de compilar la plataforma Android, pero por ejemplo, no incluye el núcleo, a diferencia de cyanogen donde aún se incluye.

Si tenemos un HTC Magic o Dream en la propia web de Android o en este artículo nos indican los próximos pasos a dar. Vamos a ir de tener el sistema genérico con sus aplicaciones a la parte de hardware. Esto es ya lo que les toca hacer a los diferentes fabricantes para asegurarse de que Android funciona en su hardware.

Compilando el núcleo y drivers en Android

Vamos a centrarnos en el HTC Magic (Saphire) que rooteado pasa a ser un Google IO. Aquí tenemos unas buenas instrucciones de HTC para jugar con él. Lo que hay que hacer es meter un núcleo y drivers necesario para manejar todo el hardware del HTC.

Los núcleos de Android de Qualcomm MSM7xxx chipsets los podemos obtener del repositorio git. De momento nos vamos a centrar en esta plataforma. Para bajarnos los núcleos:

cd kernel/
git clone git://android.git.kernel.org/kernel/msm.git
Initialized empty Git repository in /home/acs/devel/android/kernel/msm/.git/
remote: Counting objects: 1391835, done.
...
kernel/msm$ git checkout -b -t android-msm-2.6.32 origin/android-msm-2.6.32
Checking out files: 100% (26417/26417), done.
Branch android-msm-2.6.32 set up to track remote branch android-msm-2.6.32 from origin.
Switched to a new branch 'android-msm-2.6.32'

Una vez descargado los núcleos nos tenemos que ir a la rama que queremos compilar, en este caso la 2.6.32. El objetivo es tener este núcleo compilado para el HTC Nexus One.

Hay información sobre Android en el directorio doc del kernel.

Hay que hacer "cross compiling". Dentro de "cupcake" tenemos el entorno de compilación cruzada en:

prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/
prebuilt/linux-x86/toolchain/arm-eabi-4.3.1/bin/

pero estas versiones son demasiado antiguas. Nos podemos bajar del repo de android la versión 4.4 que sí que funciona.

Con añadir al PATH la versión que queramos será suficiente.

export PATH=$PATH:/home/acs/devel/android/cupcake/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/

Antes de comenzar a compilar el núcleo cogemos el fichero de configuración del propio terminal HTC Nexus One:

adb pull /proc/config.gz /tmp
112 KB/s (9314 bytes in 0.080s)
...
kernel/msm$ gunzip /tmp/config.gz

aunque es para la versión: "# Linux kernel version: 2.6.29" y bastante reciente "# Wed Jan 20 10:23:49 2010".

Este fichero de configuración es el que tenemos que copiar como ".config" al directorio principal de las fuentes del núcleo.

Luego, a la hora de compilar el núcleo, ejecutamos:

kernel/msm$ ARCH=arm CROSS_COMPILE=arm-eabi- make zImage
...
scripts/kconfig/conf -s arch/arm/Kconfig
*
* Restart config...
*
*
* RCU Subsystem
*
RCU Implementation
> 1. Tree-based hierarchical RCU (TREE_RCU)
  2. Preemptable tree-based hierarchical RCU (TREE_PREEMPT_RCU) (NEW)
choice[1-2]: 
...

Nos pregunta las opciones nuevas entre 2.6.29 y 2.6.32. Dejamos las opciones por defecto. Una vez configurado el núcleo comienza la compilación y todo termina bien con:

...
 LD      vmlinux.o
  MODPOST vmlinux.o
  GEN     .version
  CHK     include/linux/compile.h
  UPD     include/linux/compile.h
  CC      init/version.o
  LD      init/built-in.o
  LD      .tmp_vmlinux1
  KSYM    .tmp_kallsyms1.S
  AS      .tmp_kallsyms1.o
  LD      .tmp_vmlinux2
  KSYM    .tmp_kallsyms2.S
  AS      .tmp_kallsyms2.o
  LD      vmlinux
  SYSMAP  System.map
  SYSMAP  .tmp_System.map
  OBJCOPY arch/arm/boot/Image
  Kernel: arch/arm/boot/Image is ready
....
  Kernel: arch/arm/boot/zImage is ready
  Building modules, stage 2.
 MODPOST 1 modules
  CC      drivers/net/wireless/bcm4329/bcm4329.mod.o
  LD [M]  drivers/net/wireless/bcm4329/bcm4329.ko

Ahora tenemos que crear la imagen que nos permita seleccionarlo para iniciar con este núcleo desde el móvil.

Una vez compilado el núcleo, si queremos arrancar con la nueva imagen podemos utilizar "fastboot":

root@rayito:/home/acs/devel/android/kernel/msm# fastboot boot arch/arm/boot/zImage 
creating boot image...
creating boot image - 2000896 bytes
downloading 'boot.img'... OKAY
booting... OKAY

Y con esto se iniciará el sistema en Android utilizando este núcleo que acabamos de compilar.

Todo parece haber funcionado. Comprobemos que tenemos dentro del móvil:

adb pull /proc/config.gz /tmp
* daemon not running. starting it now *
* daemon started successfully *
error: device not found

Veamos si somos capaces de ver dentro del dispositivo el núcleo que tiene funcionando ...

2.6.32-26379-gadab5b4
acs@rayito #1

Claramente este es el núcleo que acabo de compilar así que todo ha funcionado de forma correcta!

Tras unas pruebas funcionales:

Bueno, nos tocará terminar de ajustar algunas cosas de módulos adicionales para que funcione todo, pero creo que el camino está bastante despejado. Puede que añadiendo ramdisk.img se solucionen estos problemas.

http://wiki.acsblog.es/acswiki/CompilarAndroid?action=AttachFile&do=view&target=P1010094.JPG

En realidad como hemos sabido posteriormente, utilizando el método de inicio con "fastboot" no funciona la carga de módulos e incluso la wifi metida dentro del núcleo, tampoco. La solución es crear un boot.img con el nuevo núcleo y flashearlo.

Soporte wifi en Android

El soporte wifi en Android requiere de algunas cosas específicas de Android.

Instalando Android + núcleo en el emulador

Instalando todo en un teléfono real

Otros proyectos

CompilarAndroid (last edited 2010-10-05 16:32:25 by AlvaroDelCastillo)