c't 9/2018
S. 162
Praxis
Android-Development
Aufmacherbild

Backe, backe, … Kernelmodul

Linux-Kernelmodul für Android kompilieren

Warum sollte man ein Linux-Kernelmodul für Android kompilieren? Weil: Alte Smartphones lernen so ganz neue Kunststücke. Und alte Autos werden mit solchen alten Smartphones selbst ein bisschen smart. Wir habens ausprobiert und stellen fest: Mit dem richtigen Rezept ist das kaum schwerer als Brezelbacken und versüßt einen verregneten Nachmittag.

Das Android-Betriebssystem ist ab Werk reichhaltig bestückt. Dabei profitiert es von seiner Verwandtschaft zum Linux-Betriebssystem. Das geht so weit, dass man Linux-Quellcode mit wenig Mühe für Android kompilieren kann. Für Entwickler, die Projekte fingerschonend voranbringen wollen, ist das ein ergiebiger Steinbruch.

Doch gelegentlich kann dieser Fundus auch den Bedarf von Android-Usern decken: Der Autor dieses Beitrags wollte sein Auto smarter machen, als es war: Dessen eingebaute Freisprecheinrichtung sollte ihre Internet-Verbindung als Router weitergeben, denn mittels der externen Antenne baut sie stabilere Verbindungen auf als ein Smartphone hinter Glas und Blech.

Mit dem Bluetooth Profiles Scanner lässt sich per Android-Gerät checken, ob eine Freisprecheinrichtung die erforderlichen Bluetooth-Profile mitbringt.

Der Hersteller der Freisprechanlage hat die Routing-Funktion zwar nicht vorgesehen, aber ein billiges Android-Smartphone sollte die Lücke schließen können. Dazu muss es per Bluetooth an die Anlage ankoppeln und den Internet-Zugang als Router per WLAN weiterreichen. Die Umsetzung klappte letztlich sehr gut und macht bei jeder Fahrt Freude.

Doch dazwischen stand ein Problem: Für die Bluetooth-Kopplung zwischen Handy und Anlage braucht man das Profil Dial-Up Networking (DUN). Auf Android funktioniert es aber mangels Point-to-Point Protocol nicht. Zwar lässt sich DUN nachrüsten, aber die Verbindung kann man nicht per WLAN weiterreichen.

Der VW-Konzern hat die Freisprecheinrichtung RNS-510 in diversen Audi-, Skoda-, Seat- und VW-Modellen eingesetzt. Sie kann per Bluetooth sogar die SIM eines Smartphones nutzen. Die Router-Funktion fehlt jedoch.

Zum Kasten: Android-Brüder im Auto: Das Konzept

An dieser Stelle kommt Linux ins Spiel: Man nimmt einfach fertig programmierte, quelloffene PPP-Erweiterungen, übersetzt sie für Android und rüstet ein Smartphone im Rahmen eines größeren Projekts zum WLAN-Router auf. Das ist das Thema dieser Serie von Android-Artikeln – eine Übersicht finden Sie im Kasten „Android-Brüder im Auto: Das Konzept“.

Es gibt diverse fertige PPP-Module, jedoch passen nicht alle zum Kernel des jeweiligen Android-Handys. Deshalb empfiehlt es sich, ein Modul aus dem Quelltext zu erzeugen, also selbst zu kompilieren.

Wir beschreiben diesen Vorgang anhand des Kernelmoduls ppp_async.ko. Im Großen und Ganzen sollte er auf jedem gerooteten Android-Handy funktionieren. Wir haben das Samsung Galaxy S GT-I9000 eingesetzt. Es ist gebraucht schon für unter 20 Euro erhältlich und sehr gut als WLAN-Router geeignet, denn man kann es zum automatischen Booten bei Einschalten der Zündung einrichten. Das geht mit einigen Samsung-Smartphones ohne Modifikationen der Hardware.

Richten Sie auf dem GT-I9000 das Betriebssystem Cyanogenmod 9.1 ein und rooten Sie es – zum Beispiel so wie kürzlich in c’t gezeigt [1]. Wir empfehlen Cyanogenmod 9.1, weil das die letzte Version ist, mit der man das Galaxy S ohne HW-Modifikationen einschalten kann, indem man Strom an den USB-Anschluss anlegt. Cyanogenmod wird zwar nicht weiterentwickelt, aber das gesamte Projekt ist archiviert und nach wie vor erhältlich. Sie finden das Archiv für das GT-I9000 via ct.de/yh2m.

Um ein Modul zu kompilieren, benötigen Sie ein Linux-System mit Entwicklungsumgebung, eine USB-Verbindung, über die Sie das erstellte Modul auf das Smartphone oder Tablet spielen, und den Quellcode des Android-Kernels, den Sie erweitern wollen.

Vorheizen

Nicht jeder Smartphone-Hersteller veröffentlicht die Quellen seiner Kernel, sodass man sich mit dem Original-Kernel von Google oder einem von Cyanogenmod behelfen muss. Wir dokumentieren das Vorgehen mit Cyanogenmod. Sie finden die Quellen auf der zugehörigen Projektseite via ct.de/yh2m.

Kompilieren erfordert ein sauberes Linux. So vermeiden Sie Störungen von beispielsweise fremden Bibliotheken. Falls Sie bereits eine Ubuntu-VM so angelegt haben, wie in [1] beschrieben, fahren Sie fort beim Abschnitt „Zutaten“.

Andernfalls installieren Sie zunächst die aktuelle Version von Oracles VirtualBox samt der Extensions auf Ihrem PC (Windows, Linux oder Mac). Richten Sie dann Ubuntu 14.04 in der 64-Bit-Fassung mitsamt den aktuellen Gasterweiterungen als virtuelle Maschine ein (1 GByte RAM, 12 MByte Grafik-RAM, 35 GByte Plattenkapazität).

Achtung: Jüngere Ubuntu-Versionen, zum Beispiel 16.04, eignen sich nicht, weil dafür nicht alle benötigten Pakete erhältlich sind. Lassen Sie beim Booten der Ubuntu-VM die Option „Aktualisierungen während der Installation herunterladen“ abgeschaltet; andernfalls bekommen Sie am Ende dennoch ein System mit Ubuntu 16.04 oder jünger.

Zutaten

Für das Kompilieren sind einige Vorarbeiten erforderlich. Bringen Sie Ubuntu 14.04 auf den aktuellen Stand. Öffnen Sie dazu das Terminal und melden Sie sich mit sudo -s als Root an und geben Sie auf Nachfrage das zuvor festgelegte Administratorpasswort ein.

Starten Sie die Aktualisierung über die Befehle

apt-get update && apt-get dist-upgrade

Erlauben Sie apt-get, den Datenträger zu verwenden. Entfernen Sie am Ende unbenötigte Pakete mittels

apt-get autoremove

Installieren Sie die Android Debug Bridge (ADB) für die USB-Kommunikation zwischen Ubuntu und dem Smartphone:

apt-get install android-tools-adb

ADB ist Teil der Android-Entwicklungsumgebung. Beispielsweise öffnet der Befehl adb shell eine Terminal-Sitzung auf dem Handy.

Android-Debugging

Stellen Sie sicher, dass auf dem Smartphone das USB-Debugging eingeschaltet ist (auf Cyanogenmod 9.1 ist das normalerweise der Fall): Öffnen Sie dazu die Einstellungen und dort den allerletzten Punkt „Über das Telefon“. Tippen Sie sieben Mal auf die Build-Nummer, wechseln eine Menüebene hoch und öffnen Sie die „Entwickleroptionen“ – bei der Option „USB-Debugging“ sollte das Häkchen gesetzt sein.

Früher mal ein billiges Smartphone, jetzt Musik-Zentrale und einzigartiger WLAN-Router: das Samsung Galaxy S GT-I9000

Schließen Sie das Telefon per USB an. Auf einer VirtualBox-VM reichen Sie die Verbindung durch, indem Sie im Menü „Geräte/USB“ den Eintrag „Samsung GTI-9000“ auswählen. Falls das Handy fragt, ob es sich mit Ihrer Ubuntu-VM verbinden darf, genehmigen Sie das.

Deaktivieren Sie die USB-Speicherfreigabe des Telefons, falls sie aktiviert ist. Auf dem GT-I9000 finden Sie diese Einstellung, indem Sie mit dem Finger von der oberen Kante zum Zentrum des Bildschirms wischen und die Option „USB-Speicher“ antippen.

Für den Vollzugriff auf ein CyanogenMod-Gerät müssen Sie definieren, wer mit Root-Rechten auf das System zugreifen darf. Diese liegen im Menü „Einstellungen/Entwickleroptionen/Root-Zugriff“. Tippen Sie die Option „Apps und ADB“ an; so bekommt man auch in der Shell Vollzugriff.

Smartphone als WLAN-Router

Prüfen Sie in der Linux-VM in einem Terminal-Fenster, ob die Verbindung zum Samsung-Smartphone funktioniert:

adb devices

Der Befehl sollte „List of devices attached“ melden und darunter die Seriennummer Ihres Gerätes ausgeben. Ein Beispiel sieht so aus:

* daemon not running. starting it:

. now on port 5037 *

* daemon started successfully *

List of devices attached

1235673A6FF54321 device

Scheitert die Verbindung, liegt es vermutlich an fehlenden Rechten auf der Ubuntu-VM. Diese lassen sich mit dem Texteditor Nano nachtragen. Dafür braucht man die Hersteller-ID respektive Google-ID des Smartphones. Sie lautet normalerweise 18d1 und lässt sich mit dem Kommando lsusb auslesen. Die Ausgabe sieht zum Beispiel so aus:

Bus 001 Device 002: ID 18d1:4e22:

. Google Inc. Nexus S (debug)

Falls die ID Ihres Smartphones abweicht, notieren Sie sie. Legen Sie auf der Ubuntu-VM eine neue Datei an und tragen Sie darin die ID und die Zugriffsrechte ein:

nano /etc/udev/rules.d/51-android:

..rules

Geben Sie darin die folgende Zeile ein und anstelle von 18d1 die für Ihr Gerät zutreffende ID:

SUBSYSTEM=="usb", ATTR{idVendor:

.}=="18d1", MODE="0666"

Die Option MODE legt die Zugriffsrechte fest; mit 0666 gewähren Sie Lese- und Schreibzugriff. Speichern Sie die Änderungen mit der Tastenkombination Strg+O und beenden Sie den Editor mit Strg+X. Nun sollte der Befehl adb devices die Seriennummer Ihres Geräts ausgeben.

Entwicklungsumgebung einrichten

Installieren Sie die Entwicklungsumgebung und die erforderlichen Pakete:

apt-get install bison build-essential:

. curl flex git gnupg gperf libesd0-:

.dev liblz4-tool libncurses5-dev:

. libsdl1.2-dev libwxgtk2.8-dev libx:

.ml2 libxml2-utils lzop pngcrush:

. schedtool squashfs-tools xsltproc:

. zip zlib1g-dev

Außerdem sind für die Android-Projekte noch diese Pakete erforderlich:

apt-get install g++-multilib gcc-:

.multilib lib32ncurses5-dev lib32:

.readline-gplv2-dev lib32z1-dev

Für Android-Fassungen von Version 2.3 bis zu 4.4 brauchen Sie Java 6. Neuere Androiden brauchen Java 7. Die im Beispiel verwendete Cyanogenmod-Version 9.1 gründet auf Ice Cream Sandwich 4.04. Richten Sie dafür Java 6 ein. Google empfiehlt für Ubuntu Open-Java anstelle der Fassung von Oracle:

apt-get install openjdk-6-jdk:

. openjdk-6-jre

Beenden Sie den Super-User-Modus mit exit und arbeiten Sie als regulärer Benutzer weiter.

Android-Repository laden

Als Nächstes gilt es, die CyanogenMod-Quellen per repo herunterzuladen. Das erledigt im Hintergrund ein lokaler Git-Client. Damit das klappt, muss man im Git-Client eine Identität konfigurieren (andernfalls bricht er den Vorgang mit dem Fehler „Please tell me who you are“ ab). Das kann Ihr regulärer Git-Account sein, wenn Sie bereits einen haben. Er akzeptiert aber auch eine Fantasie-Identität:

git config --global user.email "you:

.@example.com"

git config --global user.name "Your:

. Name"

Erstellen Sie in Ihrem Ordner die Verzeichnisse android, android/system und bin:

mkdir -p ~/bin ~/android/system

Installieren Sie das Skript Repo in den Ordner ~/bin:

curl https://storage.googleapis.:

.com/git-repo-downloads/repo >:

. ~/bin/repo

Schalten Sie das Executable-Bit ein, damit es ausgeführt werden kann:

chmod a+x ~/bin/repo

Damit es die Shell automatisch findet, fügen Sie den Ordner ~/bin zur Pfad-Variable der Shell hinzu:

export PATH=~/bin:$PATH

Wechseln Sie in das Verzeichnis android/system und laden und initialisieren Sie das Repository:

cd ~/android/system

repo init -u git://github.com/Cyano:

.genMod/android.git -b cm-9.1.0

In Cyanogenmod 9 verweist die Datei ~/android/system/.repo/default.xml auf eine externe Quelle, welche die Autoren wegen fehlender Rechte sperren mussten. Deshalb bricht der Download des entsprechenden Quelltexts ab. Kommentieren Sie die gesperrte Quelle aus, für das Projekt ist sie nicht erforderlich. Wechseln Sie dazu in das Verzeichnis ~/android/system/.repo/manifests und öffnen die Datei mit nano default.xml. Kommentieren Sie die Zeile <project path="external/svox" name="CyanogenMod/android_external_svox" /> aus, indem Sie „<!–“ an den Anfang und „–>“ ans Ende setzen. Speichern Sie mit Strg+X und Y.

Kehren Sie ins Verzeichnis ~/android/system zurück und laden Sie die noch fehlenden Quelltexte. Weil die Ladeversuche zum Beispiel wegen überlasteten oder abgeschalteten Servern gelegentlich scheitern, behilft man sich damit, das Repo-Kommando mehrfach zu wiederholen. So sucht es bei fehlenden Elementen auf anderen Servern:

until repo sync -j 4 -c; do echo Noch:

.ch ein Versuch...; sleep 5; done

Mit der Option -j 4 gibt man die Zahl der parallel laufenden Downloads an. Auf schnellen Computern mit schneller Internetanbindung kann man den Wert höher setzen, etwa auf -j 12. Spätestens jetzt können Sie getrost eine Pause einlegen, da dieser Vorgang lange dauert.

Paket-Ladung

Laden Sie die für das Kompilieren erforderlichen Pakete:

~/android/system/vendor/cm/./get-:

.prebuilts

Dabei tritt unter Umständen eine Fehlermeldung auf, die Sie ignorieren können. Lassen Sie die erforderlichen Umgebungsvariablen per Skript einrichten und laden Sie mit dem Befehl breakfast den geräteabhängigen Code herunter:

source build/envsetup.sh

breakfast galaxysmtd

Der zweite Schritt kann scheitern, wenn das Repository nicht vollständig ist. In diesem Fall stößt der Befehl breakfast das Nachladen von fehlenden Elementen selbst an. Falls das auch nicht klappt, initialisieren Sie repo erneut (ab dem Schritt repo sync ...). Falls auch das nicht hilft, löschen Sie das Verzeichnis .repo und starten Sie neu ab dem Befehl repo init -u ...

Stellen Sie sicher, dass das Smartphone per USB an Ihrem PC angeschlossen ist und dass VirtualBox die USB-Verbindung zur Ubuntu-VM durchreicht. Laden Sie nun weitere Dateien aus dem aktuellen ROM Ihres Smartphones:

cd ~/android/system/device/samsung/:

.galaxysmtd/

./extract-files.sh

Nun werden die erforderlichen Config-Skripte geholt und weitere Environment-Variablen für das Kompilieren gesetzt:

cd ~/android/system

brunch galaxysmtd

Umgebungsvariablen für das Kompilieren

Damit das Smartphone das später kompilierte Modul laden kann, muss das Modul eine zum Kernel passende Release-Nnummer tragen. Die ermittelt man mit den Befehlen adb shell und uname -r.

Auf dem Testmuster lautet sie <3.0.8-g2311908>. Verlassen Sie die ADB-Shell mit exit. Öffnen Sie im Verzeichnis ~/android/system/kernel/samsung/aries die Datei Makefile mit einem Texteditor und kommentieren Sie die mit KERNELRELEASE beginnende Zeile aus. Legen Sie darunter eine neue Zeile mit der korrekten Kernelfassung an. Im Beispiel lautet sie KERNELRELEASE = 3.0.8-g2311908. Speichern Sie die Änderungen.

Erzeugen Sie die Konfigurationsdatei zum Kompilieren:

cd ~/android/system/kernel/samsung:

./aries

make cyanogenmod_galaxysmtd_defcon:

.fig

Prüfen Sie, ob die richtige Kernel-Release-Version konfiguriert wurde:

make kernelrelease

Falls die Release-Version mit -dirty endet, ändern Sie die Datei setlocalversion unter ~/android/system/kernel/samsung/aries/scripts/. Entfernen Sie in den beiden Zeilen printf '%s' -dirty> und <*+|*+\ *) printf '%s' -dirty ;; jeweils den Ausdruck -dirty. Speichern Sie die Änderungen. Spätestens jetzt sollte make kernelrelease die korrekte Kernelversion anzeigen.

Erweitern Sie die Kernelkonfigurationsoptionen so, dass das Modul ppp_async kompiliert wird. Wechseln Sie in das Verzeichnis ~/android/system/kernel/samsung/aries/arch/arm/configs. Öffnen Sie die Datei cyanogenmod_galaxysmtd_defconfig mit einem Editor. Fügen Sie nach der Zeile CONFIG_PPP=y diese neue Zeile ein:

CONFIG_PPP_ASYNC=m

Aktualisieren Sie die Konfigurationsdatei:

cd ~/android/system/kernel/samsung:

./aries

make cyanogenmod_galaxysmtd_defconfig

Kompilieren

Nun können Sie den Kompiliervorgang starten:

make V=1 ARCH=arm CROSS_COMPILE=:

.arm-eabi- modules

Die Variable CROSS_COMPILE=arm-eabi- stellt den richtigen gcc-Compiler ein. Der Vorgang sollte nach wenigen Minuten fertig sein.

Mit Android-Tools wie KoControl lässt sich direkt auf dem Gerät anzeigen, welche Kernelmodule vorhanden und geladen sind.

Sollten stattdessen beim Kompilieren Fehler über nicht bekannte Compiler-Optionen ausgegeben werden, dann verwendet Ihr System vermutlich den Standard-Compiler gcc anstelle des im Sourcecode mitgelieferten Cross-Compilers. Welcher Compiler zum Einsatz kam, zeigt ein Blick auf die Environment-Variable CROSS_COMPILE mit dem Befehl env. Wenn der Befehl env eine leere oder eine falsche Ausgabe liefert, wiederholen Sie den Aufruf wie oben angegeben.

Servieren

Das fertige Modul finden Sie im Verzeichnis ~/android/system/kernel/samsung/aries/drivers/net. Um es auf das Smartphone zu kopieren, gibt es verschiedene Wege (z. B. E-Mail, SMB, FTP). Am einfachsten ist, die Datei per USB auf das Handy zu schieben. Wechseln Sie in das eben genannte Verzeichnis. Kopieren Sie das Modul per

adb push ppp_async.ko /sdcard/

auf die Datenpartition des Geräts. Falls das nicht funktioniert, muss man auf dem Smartphone den USB-Modus deaktivieren und den Vorgang wiederholen. Verfrachten Sie das Modul aus dem Ordner /sdcard in das Android-System:

adb shell

su

mount -o remount,rw /system

cp /sdcard/ppp_async.ko /system:

./lib/modules

Wechseln Sie per

cd /system/lib/modules

ins Module-Verzeichnis und prüfen Sie per modinfo ppp_async.ko, ob ein Modul für die ARM-Plattform mit der richtigen Release-Nummer gebacken worden ist. Laden Sie das Modul mittels

insmod ppp_async.ko

und prüfen Sie per lsmod, ob das geklappt hat. Funktioniert alles, geben Sie dem Modul die nötigen Rechte über

chmod 644 ppp_async.ko

Auf Android lässt sich die Modul-Liste zum Beispiel mit dem Tool KoControl anzeigen, das Root-Rechte voraussetzt.

Damit ist das Galaxy S GT-I9000 für die Funktion als WLAN-Router vorbereitet. Hinzu kommen noch weitere Komponenten, beispielsweise fertige Tasker-Skripte. Diese Einrichtungsschritte erklären wir im nächsten Teil dieses Android-Projekts in einer der kommenden c’t-Ausgaben. (dz@ct.de)