Arquitectura Software de Android

Arranque de Android

Nada mejor que comenzar a entender la arquitectura software de Android que estudiando su arranque. Android tiene diversas formas de iniciar:

Arranque Normal

El arranque en general de las arquitecturas basadas en ARM lo podemos ver documentado en el núcleo Linux.

El arranque en Android tiene dos fases (IPL y SPL):

Hasta donde he investigado el SPL no se encuentra disponible en código fuente y las versiones que existen son evoluciones unas de otras, modificadas con editores hexadecimales probablemente.

Algunas referencias:

Particiones

Una vez iniciado el sistema tenemos el siguiente esquema de particiones:

# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 000e0000 00020000 "misc"
mtd1: 00500000 00020000 "recovery"
mtd2: 00280000 00020000 "boot"
mtd3: 09100000 00020000 "system"
mtd4: 05f00000 00020000 "cache"
mtd5: 0c440000 00020000 "userdata"
mtd6: 20000000 00020000 "msm_nand"

De todas estas particiones las que están montadas son:

# mount  | grep mtd
/dev/block/mtdblock3 on /system type yaffs2 (ro,relatime)
/dev/block/mtdblock5 on /data type yaffs2 (rw,nosuid,nodev,relatime)
/dev/block/mtdblock4 on /cache type yaffs2 (rw,nosuid,nodev,relatime)

e inicialmente tienen la ocupación en Cyanogen:

# df -h
Filesystem                Size      Used Available Use% Mounted on
/dev/block/mtdblock3    145.0M     95.7M     49.3M  66% /system
/dev/block/mtdblock5    196.3M      2.2M    194.0M   1% /data
/dev/block/mtdblock4     95.0M     24.1M     70.9M  25% /cache

Las particiones son de tipo "yaffs2" y el almacenamiento "/dev/block/mtdblock" es un disco FLASH RAM de tipo MTD. La FLASH que lleva el N1 es de 512 MB. En el N1 y viendo las trazas del núcleo vemos que es una NAND FLASH (msm_nand).

Estructura de directorios

Me he compilado el comando "tree" para que funcione en Android. Dejo adjunto a este fichero el "tree.c" modificado para que compile para Android y el binario compilado.

# tree -L 2 -I "proc|sys|sdcard|dev"
.
|-- cache
|   |-- dalvik-cache
|   |-- lost+found
|   `-- recovery
|-- config
|-- d -> /sys/kernel/debug
|-- data
|   |-- anr
|   |-- app
|   |-- app-private
|   |-- backup
|   |-- dalvik-cache
|   |-- data
|   |-- dontpanic
|   |-- local
|   |-- lost+found
|   |-- misc
|   |-- property
|   `-- system
|-- default.prop
|-- etc -> /system/etc
|-- init
|-- init.goldfish.rc
|-- init.mahimahi.rc
|-- init.rc
|-- root
|-- sbin
|   `-- adbd
|-- sqlite_stmt_journals
`-- system
    |-- app
    |-- bin
    |-- build.prop
    |-- etc
    |-- fonts
    |-- framework
    |-- lib
    |-- lost+found
    |-- media
    |-- usr
    `-- xbin

34 directories, 7 files

La estructura de directorios no es la habitual en una distribución de GNU/Linux y se ve que está poco pulida. Por ejemplo, si consultamos el PATH que viene definido por defecto definido en init.rc

/usr/bin:/usr/sbin:/bin:/sbin:/system/sbin:/system/bin:/system/xbin:/system/xbin/bb:/data/local/bin

hay directorios que no existen, como "/usr/*" o "/data/local/bin". ¿Qué motivación habrá llevado a no seguir FHS adoptado por LSB y seguido en las distros de Linux?

Despliegue de aplicaciones

Vamos a tomar como ejemplo una aplicación y veamos como está distribuida. Por ejemplo, el Navegador que se incluye por defecto que es software libre. Si lanzamos el navegador utilizando la interfaz de android y vemos los procesos en ejecución:

# ps | grep browser
app_31    516   75    167272 29596 ffffffff afe0dc84 S com.android.browser

Vemos que es una aplicación lanzada desde una clase Java "com.android.browser". Las aplicaciones Android que funcionan por encima de Dalvik, las normales, las encontramos en el directorio:

# pwd
/system/app
# ls
AccountAndSyncSettings.apk   MagicSmokeWallpapers.apk
ApplicationsProvider.apk     MediaProvider.apk
Bluetooth.apk                MediaUploader.apk
Browser.apk                  Mms.apk
Calculator.apk               Music.apk
Calendar.apk                 PackageInstaller.apk
CalendarProvider.apk         Phone.apk
Camera.apk                   PicoTts.apk
CertInstaller.apk            Provision.apk
Contacts.apk                 Settings.apk
ContactsProvider.apk         SettingsProvider.apk
DeskClock.apk                SoundRecorder.apk
Development.apk              SpareParts.apk
DownloadProvider.apk         Superuser.apk
DrmProvider.apk              TelephonyProvider.apk
Email.apk                    Term.apk
Gallery3D.apk                TtsService.apk
GenieWidget.apk              UserDictionaryProvider.apk
GlobalSearch.apk             VisualizationWallpapers.apk
GoogleSearch.apk             VoiceDialer.apk
HTMLViewer.apk               VpnServices.apk
HtcCopyright.apk             com.amazon.mp3.apk
LatinIME.apk                 googlevoice.apk
Launcher2.apk                kickback.apk
LiveWallpapers.apk           soundback.apk
LiveWallpapersPicker.apk     talkback.apk

Ya veremos que las que instalemos nosotros van al directorio "/data/app".

Las aplicaciones están empaquetadas según el formato "apk". Si nos fijamos en nuestra aplicación:

# ls -l Browser.apk
-rw-r--r--    1 root     root        724753 Aug  1  2008 Browser.apk

Si la copiamos al ordenador y estudiamos este fichero:

adb pull /system/app/Browser.apk .
file Browser.apk 
Browser.apk: Zip archive data, at least v2.0 to extract
mkdir Browser
cd Browser
unzip ../Browser.apk 
Archive:  ../Browser.apk
  inflating: META-INF/MANIFEST.MF
...

tree -L 2
.
|-- AndroidManifest.xml
|-- META-INF
|   |-- CERT.RSA
|   |-- CERT.SF
|   `-- MANIFEST.MF
|-- assets
|   `-- html
|-- classes.dex
|-- res
|   |-- anim
|   |-- drawable
|   |-- drawable-hdpi
|   |-- layout
|   |-- layout-land
|   |-- menu
|   `-- xml
`-- resources.arsc

Vemos el fichero "AndroidManifest.xml" en formato XML binario (tiene interés su modificación para personalizar cosas), la firma (keytool -printcert META-INF/CERT.RSA para verla), el directorio assets (no tengo claro su objetivo), las clases de la aplicación y los recursos.

El fichero que contiene las clases es "classes.dex". Para ver sus contenidos hay que utilizar la herramienta dexdump que podemos obtener del entorno de compilación de Android

ls -l  cupcake/out/host/linux-x86/bin/dexdump 
-rwxr-xr-x 1 acs acs 200598 2010-02-16 00:07 cupcake/out/host/linux-x86/bin/dexdump
acs@rayito:/tmp/Browser$ dexdump classes.dex | grep "Class descriptor"
  Class descriptor  : 'Lcom/android/browser/ActiveTabsPage$1;'
  Class descriptor  : 'Lcom/android/browser/ActiveTabsPage$CloseHolder;'
...
  Class descriptor  : 'Lcom/google/android/providers/GoogleSettings;'

Con la opción "-d" además de mostrar la información de las clases, nos muestra el código de las mismas. El fichero ".dex" se genera de forma automática desde las clases Java con la herramienta "dx".

Arquitectura Detallada de una aplicación Android

Creación de una Distribución/ROM completa de Android

Con todo lo estudiado hasta el momento estamos en posición de ver que hace falta para crear una distribución Android completa.

Un sistema Android iniciado en modo normal tiene tres bloques fundamentales:

Si miramos que incluye una ROM de Android, en este caso la de Cyanogen:

unzip  -l update-cm-5.0.4.1-N1-signed.zip > Ficheros
vi Ficheros
Archive:  update-cm-5.0.4.1-N1-signed.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
    57852  2008-02-28 21:33   META-INF/MANIFEST.MF
    57905  2008-02-28 21:33   META-INF/CERT.SF
     1714  2008-02-28 21:33   META-INF/CERT.RSA
     8057  2010-02-13 17:48   META-INF/com/google/android/update-script
     2388  2010-02-26 09:32   backuptool.sh
  2428928  2010-02-27 05:27   boot.img
   171511  2010-02-26 10:41   system/app/AccountAndSyncSettings.apk
...
     5416  2010-02-26 09:07   system/xbin/timeinfo
---------                     -------
 96353022                     672 files

Vemos que lleva la imagen con el núcleo y el ramdisk de inicio y luego el directorio "/system" sin llevar aplicaciones específicas de usuario.

¿Cómo se hace el boot.img? Esto está descrito en este documento. Utilizando las herramientas indicadas podemos analizar ese boot.img:

unzip update-cm-5.0.4.1-N1-signed.zip boot.img
Archive:  update-cm-5.0.4.1-N1-signed.zip
  inflating: boot.img
./unpack-bootimg.pl boot.img 

kernel written to boot.img-kernel.gz
ramdisk written to boot.img-ramdisk.cpio.gz
502 bloques

extracted ramdisk contents to directory boot.img-ramdisk/
ls -l boot.img-kernel.gz
-rw-r--r-- 1 acs acs 2265088 2010-03-07 15:15 boot.img-kernel.gz
tree boot.img-ramdisk
boot.img-ramdisk
|-- data
|-- default.prop
|-- dev
|-- init
|-- init.goldfish.rc
|-- init.mahimahi.rc
|-- init.rc
|-- proc
|-- sbin
|   `-- adbd
|-- sys
`-- system

Si queremos por ejemplo modificar el inicio de la distro, basta con modificar los contenidos del ramdisk y crear una nueva boot.img con el kernel y ese nuevo ramdisk.

Vamos a comenzar a trabajar con la comunidad de Cyanogen en todos estos temas.

Tablets

A parte de los móviles vamos a comenzar a trabajar también con tabletas:

Actualizaciones a un sistema Android

Referencias

ArquitecturaSWAndroid (last edited 2010-07-29 10:22:56 by AlvaroDelCastillo)