Linux Embedded

Le blog des technologies libres et embarquées

Customisation d’AOSP

Introduction

La distribution AOSP fournit une version standard d’Android pour un certain nombre de plate-formes (NEXUS, émulateur, Pandaboard, …). De même, de nombreux « forks » d’AOSP sont proposés par les fabricants de matériel afin de fournir un BSP Android adapté. Il est fréquent d’avoir à adapter ce BSP aux contraintes du produit et cette tâche peut aller de la simple « customisation » (modification de l’image de fond d’écran au démarrage ou de l’animation de chargement) à l’ajout de pilotes noyau ou d’applications dédiées. Les même techniques peuvent bien entendu être utilisées pour ajouter à AOSP une nouvelle cible dérivée d’une cible existante, comme lors du développement d’une carte spéciale en partant d’une carte d’évaluation.

Dans cet article nous allons décrire brièvement les techniques de customisation d’AOSP en utilisant l’exemple de diverses plate-formes comme la Beaglebone Black (BB Black), la Pandaboard, la Wandboard (i.MX6) ou bien l’émulateur Android goldfish.

Les différents fichiers de configuration

Comme nous l’avons vu dans les premiers articles, AOSP utilise un principe de configuration assez simple basé sur des fichiers Makefile (syntaxe GNU-Make) et des scripts shell. Le répertoire device des sources AOSP contient la majorité des configurations des différentes plate-formes supportées. Pour un constructeur donné, les fichiers de configuration sont localisés dans device/<constructeur>, soit par exemple device/ti. Nous présentons ci-dessous un extrait du BSP Android (rowboat) pour les cartes Beaglebone à base de processeurs TI (Sitara).

$ ls -l device/ti 
total 16 
drwxrwxr-x 8 pierre pierre 4096 Dec  3 18:10 am335xevm 
drwxrwxr-x 8 pierre pierre 4096 Dec  3 18:10 am335xevm_sk 
drwxrwxr-x 6 pierre pierre 4096 Dec  3 18:10 beaglebone 
drwxrwxr-x 5 pierre pierre 4096 Mar 10 14:18 beagleboneblack

Nous pouvons explorer le contenu du répertoire correspondant à la BB Black. Nous avons placé en gras les fichiers les plus importants.

$ cd device/ti/beagleboneblack/ 
$ ls 
Android.mk          egl.cfg                media_profiles.xml 
AndroidProducts.mk  fstab.am335xevm        mixer_paths.xml 
BoardConfig.mk      gpio-keys.kl           overlay 
CleanSpec.mk        init.am335xevm.rc      ti-tsc.idc 
audio_policy.conf   init.am335xevm.usb.rc  ueventd.am335xevm.rc 
beagleboneblack.mk  liblights              vold.fstab 
device.mk           media_codecs.xml

Le fichier AndroidProducts.mk définit la liste des cibles concernées, soit uniquement la BB Black dans notre cas ce qui nous ramène au fichier beagleboneblack.mk .

$ cat AndroidProducts.mk
...
PRODUCT_MAKEFILES := $(LOCAL_DIR)/beagleboneblack.mk

Dans le cas de la BB Black, ce fichier est relativement bref ce qui nous permet de le présenter entièrement. Une première partie concerne la modification de variables d’environnement (en gras) ce qui permet d’ajouter des paquets à l’image ou bien modifier certaines propriétés Android. Lors de la compilation d’AOSP, les propriétés seront ajoutées au fichier system/build.prop.

# Live Wallpapers 
PRODUCT_PACKAGES += \ 
        LiveWallpapers \ 
        LiveWallpapersPicker \ 
        MagicSmokeWallpapers \ 
        VisualizationWallpapers \ 
        librs_jni 

PRODUCT_PROPERTY_OVERRIDES := \ 
        net.dns1=8.8.8.8 \ 
        net.dns2=8.8.4.4

Une deuxième partie décrit l’héritage de configuration à partir d’autres fichiers. En particulier, le fichier build/target/product/full_base.mk définit la configuration pour la construction d’une image AOSP générique contenant les composants open source. Le fichier device.mk contient d’autres définitions qui pourraient être partagées avec une autre cible si le fichier AndroidProducts.mk en contenait plusieurs.

# Inherit from those products. Most specific first. 
$(call inherit-product, $(SRC_TARGET_DIR)/product/full_base.mk) 
$(call inherit-product, device/ti/beagleboneblack/device.mk)

Les dernières lignes renseignent les variables d’identification de la cible (nom du produit, modèle, nom du fabricant, etc.). Le détail est disponible à l’adresse http://www.kandroid.org/online-pdk/guide/build_new_device.html ou bien au chapitre 4 de l’ouvrage Embedded Android cité en bibliographie.

PRODUCT_NAME := beagleboneblack 
PRODUCT_DEVICE := beagleboneblack 
PRODUCT_BRAND := Android 
PRODUCT_MODEL := BEAGLEBONEBLACK 
PRODUCT_MANUFACTURER := Texas_Instruments_Inc

Le fichier device.mk permet de décrire d’autres fonctionnalités comme la copie de fichier ou l’overlay. La copie utilise la variable PRODUCT_COPY_FILES. La syntaxe est très simple, la source étant séparée de la destination par le caractère « deux points ». Dans l’exemple suivant, le fichier device/ti/beagleboneblack/init.am335xevm.rc est copié lors de la compilation dans le répertoire root qui correspond au ramdisk initial correspondant au fichier ramdisk.img d’AOSP.

PRODUCT_COPY_FILES := \ 
        device/ti/beagleboneblack/init.am335xevm.rc:root/init.am335xevm.rc \ 
...

Dans le cas d’un overlay, l’arborescence décrite dans le répertoire overlay remplace lors de la compilation celle définie par défaut.

DEVICE_PACKAGE_OVERLAYS := \ 
    device/ti/beagleboneblack/overlay

L’arborescence du répertoire overlay est présentée ci-après :

overlay 
├── frameworks 
│   └── base 
│       ├── core 
│       │   └── res 
│       │       └── res 
│       │           ├── values 
│       │           │   └── config.xml 
│       │           └── xml 
│       │               └── storage_list.xml 
│       └── packages 
│           └── SettingsProvider 
│               └── res 
│                   └── values 
│                       └── defaults.xml 
└── packages 
    └── apps 
        └── Browser 
            └── res 
                └── values 
                    └── strings.xml

Le fichier BoardConfig.mk décrit la configuration matérielle de la cible. En voici un extrait :

# Use beaglebone camera cape as default 
BOARD_HAVE_CAMERA_CAPE := true 
TARGET_CPU_ABI := armeabi-v7a 
TARGET_CPU_ABI2 := armeabi 
TARGET_ARCH := arm 
TARGET_ARCH_VARIANT := armv7-a-neon 
ARCH_ARM_HAVE_TLS_REGISTER := true 

TARGET_NO_KERNEL := true 

BOARD_HAVE_BLUETOOTH := false 
TARGET_NO_BOOTLOADER := true 
TARGET_NO_RECOVERY := true 
BOARD_KERNEL_BASE := 0x80000000 
...

Dans certains cas ce fichier utilise une configuration conditionnelle afin – par exemple – de déterminer le pilote noyau à utiliser. Nous reproduisons ci-dessous un fichier de configuration pour un chipset i.MX6. Dans le cas d’une carte de type Wandboard, le pilote Wi-Fi à utiliser correspond à brcmfmac.ko.

ifeq ($(BOARD_WLAN_VENDOR),WANDBOARD) 
BOARD_WLAN_DEVICE                        := bcmdhd 
WPA_SUPPLICANT_VERSION                   := VER_0_8_ATHEROS 
WIFI_DRIVER_MODULE_PATH                  := "/system/bin/wifi/brcmfmac.ko" 
WIFI_DRIVER_MODULE_NAME                  := "brcmfmac" 
endif

Nous terminons la description par l’ajout du nom d’une nouvelle cible à AOSP. Comme nous l’avons vu dans le premier article d’introduction à AOSP, la procédure standard utilise la commande lunch. Dans le cas de la Pandaboard, le fichier vendorsetup.sh est présent dans le répertoire device/ti/panda. Ce fichier contient simplement une ligne permettant d’ajouter l’entrée à la liste affichée par lunch.

add_lunch_combo full_panda-userdebug

Ce principe n’est cependant pas systématiquement utilisé. En effet, le BSP Android de la BB Black utilise une variable TARGET_PRODUCT ajoutée à la ligne de compilation :

$ make TARGETPRODUCT=beagleboneblack

Cette variable est utilisée dans les fichiers Makefile et Android.mk de la distribution Android comme le montrent les exemples qui suivent :

ifeq ($(TARGET_PRODUCT), beagleboneblack) 
$(MAKE) -C kernel ARCH=arm am335x_evm_android_defconfig 
endif 

# This is for beagleboneblack camera cape 
ifeq ($(TARGET_PRODUCT), beagleboneblack) 
ifeq ($(BOARD_HAVE_CAMERA_CAPE),true) 
LOCAL_CFLAGS += -DCONFIG_CAMERA_CAPE 
endif 
endif

Ajout de service

Il est relativement simple d’ajouter un service lancé au démarrage d’Android. Prenons l’exemple du simple script boucle.sh effectuant toutes les secondes une trace visible par logcat.

#!/system/bin/sh 

echo $$ > /data/boucle.pid 

while [ 1 ]; do 

log -t MY_SERVICE boucle 
        sleep 1 
done

Après transfert du script sur la cible Android par ADB, on peut tester son fonctionnement par :

# /data/boucle.sh & 
# logcat

On doit alors obtenir les traces indiquant le fonctionnement de la boucle :

I/MY_SERVICE(  849): boucle 
I/MY_SERVICE(  850): boucle 
I/MY_SERVICE(  851): boucle 
I/MY_SERVICE(  853): boucle 
I/MY_SERVICE(  854): boucle 
I/MY_SERVICE(  855): boucle 
...

Afin que boucle.sh soit lancé au démarrage du système, il suffit de modifier le script /init.rc (ou bien /init.<nom_cible>.rc) et d’y ajouter les lignes suivantes :

service my_service /data/boucle.sh 
        class main 
        oneshot

Ce fichier init.rc modifié peut bien entendu faire partie de la configuration spécifique de la cible dans device.

Cas particulier de l’émulateur

L’émulateur est très pratique dans le cas de premiers tests puisqu’il ne nécessite pas de matériel. La configuration est très proche de celle décrite précédemment mise à part la localisation des fichiers dans build/target/board/generic.

$ ls -l build/target/board/generic 
total 20 
-rw-r--r-- 1 pierre pierre   29 Oct 16 10:46 AndroidBoard.mk 
-rw-r--r-- 1 pierre pierre 1754 Oct 16 10:46 BoardConfig.mk 
-rw-r--r-- 1 pierre pierre  338 Oct 16 10:46 README.txt 
-rw-r--r-- 1 pierre pierre 1429 Feb 13 15:57 device.mk 
-rw-r--r-- 1 pierre pierre  108 Oct 16 10:46 system.prop

Le fichier README.txt indique qu’il n’est pas possible de dériver la configuration de l’émulateur mais cela n’empêche pas de réaliser quelques tests !

It is not a product "base class"; no other products inherit 
from it or use it in any way.

Un test simple consiste à modifier le fichier device.mk afin d’ajouter une image de fond d’écran au démarrage ( initlogo.rle), une animation adaptée ( bootanimation.zip) et enfin un paquet Hello qui sera compilé avec l’image AOSP. Nous remarquons qu’il existe bien un répertoire device/generic/goldfish.

PRODUCT_COPY_FILES += \ 

device/generic/goldfish/bootanimation.zip:system/media/bootanimation.zip \ 
device/generic/goldfish/initlogo.rle:root/initlogo.rle 

PRODUCT_PACKAGES += \ 
    Hello

Le répertoire Hello contenant les sources de l’application (créée avec ADT) doit être ajouté au répertoire device/generic/goldfish. Après compilation de l’image AOSP, on pourra tester la nouvelle version par la commande suivante et constater la présence de l’application dans le répertoire /data/app et bien entendu sur le bureau Android.

$ emulator -data out/target/product/generic/userdata.img &

Conclusion

Cet article nous a permis de présenter la configuration/customisation d’AOSP pour une cible matérielle. Il existe assez peu de documentation officielle sur ce sujet et il est parfois nécessaire de partir à la recherche des informations directement dans les sources du BSP Android.

Bibliographie

 

Un commentaire sur “ Customisation d’AOSP ”

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *