Effiziente Applikations-Aktualisierung mit Android Things 05.10.2017, 10:40 Uhr

Android der Dinge

War Android Things anfangs eine reine Hardware-Zugriffsbibliothek für Googles Betriebssystem, so baut der Suchmaschinenanbieter das Product Schritt für Schritt zu einer vollwertigen Auslieferungsplattform für Prozessrechner aus. Dieser Artikel zeigt einige Komfortfeatures im Detail.
Auch wenn man es als alter Microcontroller-Programmierer nicht gerne hört: Industrie 4.0 und die immer kleiner werdenden Ordermengen sorgen dafür, dass die Entwicklungskosten bei Embedded-Produkten permanent an Gewicht gewinnen. Wer hier mit Assembler oder C programmiert, erlebt spätestens beim Ausliefern der Produkte Schiffbruch.
Ein gutes Beispiel dafür sind Multimeter: Vor einigen Jahren war der p.t. User zufrieden, wenn das Gerät neben dem gemittelten Messwert noch die Einheit anzeigen konnte. Heute gehören Verlaufsdiagramme, komplexe Statistiken und diverse andere Features schon in der Mittelklasse zum absoluten Must Have.
Das nächste Problem ist die Aktualisierung derartiger Geräte: Hat man eine Internetverbindung, so ist es nur eine Frage der Zeit, bis ein Hacker eine Schwachstelle findet. Wer in so einem Fall einen physikalischen Rückruf startet, lebt in einem Zustand der Sünde. Andererseits ist das manuelle Programmieren einer vollständigen Updatelogik alles andere als einfach.
Kurzum: als Entwickler von Embeddedgeräten wünscht man sich Hilfe. Google tritt an, um diese zu gewähren. Android ist für die Aufgaben des mobilen Bereichs gut geeignet: In Zeiten von preiswerten Einplatinenrechnern mit hochleistungsfähigen Prozessoren spricht nur wenig dagegen, dem Gerät ausreichend Leistung und die Ausführung eines vernünftigen Betriebssystems zu geben. Was dabei zu beachten ist, klärt dieser Artikel.

Ein Multimeter ist kein Smartphone

Hinter dieser auf den ersten Blick banal klingenden Feststellung verbirgt sich eine wichtige Erkenntnis: Es ist in den meisten Fällen nicht empfehlenswert, den Durchschnitts-User den Zugriff auf das unterliegende Betriebssystem zu gewähren.
Dass dies auch in der Praxis auftritt, hat sich in der Consulting Tätigkeit des Autors dieser Zeilen schon mehrfach bewiesen. So gab es in einem ostasiatischen Land einen Versuch, in dem ein Messgerät mit einem vollwertigen lokalisierten Android ausgestattet war. Der Gutteil - dies ist kein Scherz - der von den Betatestern angemeldeten Kritikpunkte bezog sich sodann nicht auf das Gerät selbst, sondern auch auf Probleme bei der Ausführung von Spielen, Mail-Clients und ähnlichen Besskram, der auf einem Messgerät an sich nichts zu suchen hat.
Der vernünftigere Ansatz zur Nutzung von Android im Embeddedbereich ist, das Betriebssystem als eine Quelle von Werkzeugen anzusehen: So stellt Android beispielsweise einen umfangreichen GUI-Stack, der zudem mit diversen Bibliotheken - Stichwort beispielsweise Diagrammgenerierung - erweitert werden kann. Die Resultate lassen sich bei Bedarf sogar swizzeln und auf SPI-Displays ausgeben: Wer einmal von Hand einen komplexen Chart auf Achtbittern realisiert hat, weiss, dass diese Vorgehensweise nur wenig zukunftsträchtig ist.

Nichts wie los!

Wer heute ein Embedded-Betriebssystem auswählt, ohne sich Gedanken darüber zu machen, wie Updates zum Endkunden kommen, lebt in einem Zustand der Sünde. Google hat dies insofern erkannt, als der Suchmaschinenanbieter keine Stand-Alone-Betriebssystem-Images mehr anbietet: Wer heute Android Things einsetzen möchte, muss zwangsweise die unter https://partner.android.com/things/console/ bereitstehende Android Things-Konsole öffnen. Sie funktioniert laut Eigenbeschreibung am besten mit Chrome: Der Autor hat mit anderen Browsern ausser wenig lästigen Fehlermeldungen nur beim Uploaden von Bundes Probleme gehabt.
Nach dem Start und dem Abnicken der Lizenzbedingungen klicken Sie auf den grünen Plus-Knopf, um den Assistenten zur Generierung eines neuen Projekts auf den Bildschirm zu holen. Die Eingabe des Produktnamens ist hierbei wenig kritisch - es handelt sich dabei um einen String, der nur innerhalb des Unternehmens relevant ist. Wir wollen in den folgenden Schritten NMGThing1 annehmen. Im Feld SOM Type dürfen Sie auswählen, welche Art von Prozessrechner von Ihrem System unterstützt werden soll. Google unterstützt zum Zeitpunkt der Drucklegung eine Gruppe von Entwicklerboards aus dem Hause Freescale und den Raspberry Pi 3: Insbesondere in kleineren Serien kann es vernünftig sein, den Raspberry Pi wie in Bild 1 gezeigt einfach im umgekehrten Zustand mittels einiger Schrauben auf der Entwicklerplatine zu befestigen.
Das Montieren von Prozessrechnern auf eigener Hardware - hier mit einem Shenzhen Xunlong OrangePi - funktioniert wirklich (Bild 1)
Wir wollen in diesem Artikel mit einem Raspberry Pi 3 arbeiten, weshalb dieser im Feld SOM Type markiert wird. Aktivieren Sie die Checkbox zum Inkludieren der Google Play-Services. Im Feld OEM Partition Size dürfen Sie auswählen, wieviel Speicherplatz auf dem generierten Image maximal zur Verfügung stehen soll: Wählen Sie hier 32 MB aus. Beachten Sie allerdings, dass sich diese Einstellungen nach dem Bestätigen nicht mehr rückgängigmachen lassen.
Klicken Sie sodann auf Create, um die Generierung des Projekts zu befehligen. Die Konsole lässt sich an dieser Stelle rund eine Minute Zeit- Google's Server sind mitunterüberlastet. Im nächsten Schritt finden Sie sich in der Settings-Seite wieder. Klicken Sie dort auf den Link Create Starter Build, um den Prozess der Erzeugung eines neuen Android Things-Images zu starten. Die Konsole reagiert darauf mit dem Einblenden des in Bild 2  gezeigten Konfigurationsfenster, in dem Sie die diversen Parameter des Images festlegen sollen. Wir wollen uns in der folgenden Schritten allerdings mit den von Google festgelegten Voreinstellungen zufrieden geben, weshalb wir im nächsten Schritt auf den Knopf Build Configuration klicken.
Der Image-Generator der Android Things-Konsole ist sehr flexibel  (Bild 2)
Nach der erfolgreichen Erzeugung einer Build-Konfiguration finden Sie weiter unten die Option Build Configuration List. Klicken Sie dort auf den Link Download Build, um den Kompilationsprozess zu starten. Der hinter der Android Things-Konsole stehende Server beginnt sodann mit der Erzeugung eines eigenen SD-Karten-Images für ihre Applikation: Die Bereitstellung kann, je nach Serververfassung, schon einmal die eine oder andere Minute in Anspruch nehmen.
Extrahieren Sie das Archiv sodann wie gewohnt, um das Image auf den Prozessrechner zu laden. Verbinden Sie diesen sodann per Ethernet mit ihrer Workstation, stecken Sie einen Monitor an und verbinden Sie das Gerät erst danach mit seiner Energieversorgung - wie bei fast allen Einplatinencomputern dauert der erste Start etwas länger, weil auch hier der Raspberry Pi im ersten Schritt die Speicherkarte und ihre Partitionstabelle an die neue Situation anpasst.
Die dritte Version von Android Studio bringt diverse Erweiterungen mit, die die Arbeit mit Android Things erleichtern. Der Autor nutzt in seiner täglichen Arbeit seit einiger Zeit die Beta 5, und kann bei Berücksichtigung des Locale-Bugs nicht von Stabilitätsproblemen berichten – in den folgenden Schritten gehen wir also davon aus, dass sie mit der aktuellsten Version der IDE arbeiten. Das einst in GitHub zum Download bereitgestellte Projektskelett wird von Google seit längerer Zeit nicht mehr gewartet und funktioniert dementsprechend mit aktuellen Versionen von Android Things eher schlecht als recht - ein Problem, mit dem Sie sich nach Möglichkeit nicht aufhalten sollten.
Klicken Sie nach dem Start der IDE auf Start a new Android Studio Project, und beginnen Sie mit der Erzeugung einer neuen Applikation nach dem hinreichend bekannten Schema. In den folgenden Schritten geht der Autor davon aus, dass Sie als Name NMGThings auswählen.
Bild 3 zeigt den Schritt, der für Sie relevant ist. Die neue Version der IDE unterstützt nämlich die Entwicklung von Android Things-Varianten direkt, weshalb sie im Projektassistenten die zu ihrem Image passende Version der API auswählen. Wer sich an Standardeinstellungen von Google orientiert, bekommt ein Gerät, das auf Android 7.0 basiert - passen Sie Einstellungen also an.
Die Voreinstellungen von Android Things und von der Android Things-Konsole passen derzeit nicht zusammen (Bild 3)
Legen Sie sodann eine neue leere MainActivity an, und klicken Sie sich durch den Assistenten, um die Erstellung des Projektskeletts abzuschliessen. Gradle lässt sich wie immer beim Herunterladen etwas Zeit - diesmal ist es noch langsamer, weil zusätzlich einige für Android Things dedizierte Bibliotheken samt der dazugehörenden Dokumentation von einem Google-Server heruntergeladen werden müssen.
Der erste erfreuliche Unterschied zum in GitHub befindliche Projektskelett ist, dass das von Android Studio 3.0 erstellte Basisprojekt eine Activity mitbringt - wir müssen uns also nicht mehr mit dem Ressourcensystem herumärgern, sondern können gleich mit der Programmierung beginnen.
In zum Modul der Applikation gehörenden gradle.build findet sich folgende Passage, die die Android Things-Unterstützung ins Projekt einbindet:
 
dependencies {
    . . .
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
    compileOnly 'com.google.android.things:androidthings:+'
}
 
Die Bibliothek findet sich auch in der Manifestdatei wieder, wo sie mittels uses-library importiert wird:
 
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tamoggemon.nmgthing">
    <application>
        <uses-library android:name="com.google.android.things" />
 
Das in der Einleitung genannte Problem des Single-Use-Betriebssystems wird in Android Things insofern umgesetzt, als das von Google bereitgestellte Image ohne Programmstarter auskommt.
Der Entwickler des Geräts deklariert stattdessen eine Activity, die beim Betriebssystem als Startpunkt angemeldet wird und fortan im Rahmen des Hochfahrens des Geräts zum Einsatz kommt. Dies wird durch das Einschreiben eines zusätzlichen Intent-Filters im Manifest bewerkstelligt:
 
<activity android:name=".MainActivity">. . .
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.IOT_LAUNCHER" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
 
Das Vorhandensein des Intentfilters android.intent.category.IOT_LAUNCHER deklariert MainActivity hierbei als jenes Formular, das nach dem Start aktiviert wird. Beachten Sie, dass dies keine Einschränkung für die Anzahl der Activities darstellt: Sie können so viele Activities anlegen, wie sie wollen - wichtig ist nur, dass immer nur eine als Einsprungpunkt dient.
Da wir in den folgenden Schritten die Nutzung der Android Things-Konsole zur Aktualisierung eines „im Feld“ befindlichen Geräts demonstrieren wollen, müssen wir im ersten Schritt etwas generieren, was eine leicht verständliche Ausgabe erzeugt.

Lass es blinken

Zum Zeitpunkt der Drucklegung unterstützt Android Things fünf verschiedene Schnittstellen für Drittanbieterhardware: hinter der GPIO-API verbirgt sich die Möglichkeit, auf digitale Ein- und Ausgabepins zurückzugreifen. Analoge Ausgabe wird nur über Pulsbreitenmodulation unterstützt – für die in manchen SoCs enthaltenen Analog-Digital bzw Digital-Analog-Wandler hat Google bisher keine API spendiert.
Ob der Java-inhärenten Probleme mit der Latenz ist Android Things für Bit Banging eher schlecht als recht geeignet: zur Kommunikation mit komplexerer Hardware unterstützt Google deshalb I2C, SPI und UART.
Von besonderem Interesse ist in diesem Zusammenhang die unter https://github.com/androidthings/contrib-drivers bereitstehende Sammlung von User Drivers: es handelt sich dabei um von Google oder von Drittentwicklern angebotene Treiber, die bestimmte Hardwarekomponenten direkt aus Java heraus ansprechbar machen. Momentan finden sich dort rund zwei Dutzend Treiber, die verschiedene Aspekte der Programmierung für Android Things beleuchten.
Google geht bei der Ansprache von Hardwaregeräten unter Android Things von Strings aus: Jedes adressierbare Gerät wird auf Seiten des Entwicklers über einen String angesprochen.
Die genauen Strings können Sie entweder zur Laufzeit unter Nutzung von Methoden des Frameworks ermitteln, oder aber auf die in Bild 4 gezeigte Liste zurückgreifen.
Die graue Tabelle verrät uns mehr über die zur Verfügung stehenden Funktionseinheiten (Bild 4)
Wer im Bereich Hardware tätig ist, sollte immer eine Gruppe von Leuchtdioden im Haus haben – haben Sie dies nicht, so schafft AliExpress gerne Abhilfe. Das Realisieren eines Lauflichts spricht das innere Kind im Entwickler an, und ist zudem nicht allzu kompliziert. Wir wollen uns deshalb mit der in Bild 5 gezeigten Schaltung begnügen, die vier verschiedenfarbige LEDs an den Prozessrechner anschliesst.
Aus elektrotechnischer Sicht primitiv: das Lauflicht (Bild 5)

Die Auswahl des Widerstandswerts ist hierbei relativ unkritisch: Richten Sie sich nach der Strommenge, die ihre LEDs benötigen. Die einzelnen Pins des Raspberry Pi können pro Pin bis zu 15 Milliampere liefern, der gesamte Port liefert maximal 50mA. Da das SoC allerdings nicht für klassische Embeddedaufgaben vorgesehen ist, empfiehlt sich an dieser Stelle Zurückhaltung.
Im nächsten Schritt müssen wir dafür sorgen, dass die Pins ansprechbar werden. Als erstes ist hierbei ein Feld von Gpio-Instanzen erforderlich, das als Member der MainActivity entsteht:
 
public class MainActivity extends Activity {
    Gpio myPins[]=new Gpio[4];
 
Das Einrichten eines Arrays von GPIO-Instanzen lohnt sich an dieser Stelle insofern, als es in Android Things ob der Strings nur schwierig möglich ist, Operationen auf eine Gruppe von Geräten auszuführen. Sind die einzelnen Wrapper in einem Feld, so können Sie den Index zum numerisch gesteuerten Ansprechen einzelner Pins benutzen.
Im nächsten Schritt müssen wir die Gpio-Instanzen initialisieren. Hierzu dient folgender Code, den Sie im Idealfall in onCreate platzieren:
 
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    PeripheralManagerService service = new PeripheralManagerService();
    try {
        myPins[0] = service.openGpio("BCM6");
        myPins[0].setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH);
        myPins[1] = service.openGpio("BCM13");
myPins[1].setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
        myPins[2] = service.openGpio("BCM19");
myPins[2].setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH);
        myPins[3] = service.openGpio("BCM26");
myPins[3].setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH);
    }
    catch (Exception e){}
}
 
Aufmerksamen Lesern fällt auf, dass Google bei der Realisierung des Gpio-Moduls von Android Things mitgedacht hat. Die Initialisierung beginnt - wie sollte es unter Android anders sein - mit dem Beschaffen einer Instanz eines als PeripheralManagerService bezeichneten Betriebssystemservices, der als Schnittstelle zwischen ihrer Applikation und der unterliegenden Hardware dient. Im nächsten Schritt wird die Methode openGpio aufgerufen, um die jeweiligen Objekte zu erzeugen.
GPIO-Pins können als Eingang oder als Ausgang agieren. Google erlaubt in setDirection das Festlegen des Betriebsmodus. Im Fall eines Ausgangs fragt das Betriebssystem an dieser Stelle  ab, welchen Logikpegel die jeweiligen Pins initial einnehmen sollen. Dadurch entfällt der in anderen Betriebssystemen bzw. HALs erforderliche Tanz mit Direction und SetValue ersatzlos.
Während man in einem klassischen Echtzeit-Betriebssystem tun und lassen kann, was man möchte, muss man sich unter Android Things mit strengeren Regeln abgeben: Das zugrunde liegende Betriebssystem ist nach wie vor Android, weshalb Nettigkeiten wie der ANR-Dialog mit von der Partie sind.
Zum Realisieren eines regelmässigen Ein- und Ausschaltens wollen wir hier auf einen Handler zurückgreifen, der samt der zu ihm gehörenden Runnable-Klasse in MainActivity entsteht. Diese Vorgehensweise hat den Vorteil, dass das Runnable als innere Klasse der Activity betrachtet wird und auf das Feld myPins direkt zugreifen kann.:
 
public class MainActivity extends Activity {
    Gpio myPins[]=new Gpio[4];
    android.os.Handler myHandler;
    private Runnable myRunnable = new Runnable() {
 
Die eigentliche run-Methode ist dann primitiv. Sie iteriert über alle in myPins enthaltenen Gpio-Objekte, invertiert den Wert und schreibt diesen zurück:
 
@Override
        public void run() {
            try {
                for(int i=0;i<4;i++){
                    myPins[i].setValue(!myPins[i].getValue());  
                }
 
Nach getaner Arbeit rufen wir abermals postDelayed auf. Der numerische Parameter legt dabei fest, wie viele Millisekunden das Betriebssystem warten soll. Damit ist sichergestellt, dass sich der Handler nach einmaliger Aktivierung immer wieder aktiviert:
 
                myHandler.postDelayed(myRunnable, 500);
            } catch (Exception e) {
                Log.e("NMG", e.getMessage());
            }
        }
    };
 
Leider müssen wir den ersten Durchlauf von Hand anstossen, weshalb wir im Try-Catch-Block nach der Initialisierung der GPIO-Wrapperobjekte folgenden Code platzieren:
 
try {
    . . .
    myHandler=new Handler();
    myHandler.post(myRunnable);
}
 
Google hielt sich bei der Implementierung der Android-Things-API streng an die Vorgaben aus dem Hause Oracle: wundern sie sich nicht darüber, dass so gut wie alle Funktionen eine Vielzahl von Exceptions werfen.

Raspberry Pi ansprechbarmachen

Im Prinzip sind wir an dieser Stelle fertig - das Programm könnte auf den Prozessrechner gejagt werden. Nun stellt sich die Frage, wie dies in der Praxis erfolgt: Das zum Ansprechen von gewöhnlichen Handys verwendete USB-Kabel taugt beim Raspberry Pi insofern nicht, als sein MicroUSB-Port nur zur Stromversorgung vorgesehen ist und keinen Kontakt zur Workstation aufnehmen würde.
Die Lösung für dieses Problem ist die Nutzung des Internets - das vorher erwähnte Ethernet-Kabel ist WLAN insofern überlegen, als die merkbar höhere Latenz einer drahtlose Verbindung beim Debugging zu einer massiven Verlangsamung des Workflows führt.
Android Things blendet ihnen am Startbildschirm die IP-Adresse ein, unter der die Netzwerkport des Raspberry Pi auf Eingaben wartet. Wechseln Sie im nächsten Schritt in den Installationsordner ihres Android-SDK, und geben Sie folgendes Kommando ein, um eine Verbindung aufzubauen:
 
tamhan@TAMHAN14:~/Android/Sdk/platform-tools$ ./adb connect 10.42.0.44:5555
connected to 10.42.0.44:5555
 
Android Debugger Bridge ist zustandslos: Fährt der Prozessrechner herunter, geht die Workstation schlafen, oder tritt ein sonstiges Störereignis auf, so werden die Verbindungen nicht automatisch wiederhergestellt. Denken Sie also daran, dass Sie den Connect-Befehl nochmals eingeben müssen, wenn sie aus der Mittagspause zurückkehren.
Nach dem erfolgreichen Aufbau einer Verbindung zwischen Prozessrechner und Workstation können Sie das System wie gewohnt per ADB ansprechen: Der Raspberry Pi scheint, wie in Bild 6 gezeigt, in der Liste der Zielplattformen auf.
Android Studio macht keinen Unterschied, ob ein Zielgerät per USB oder per Netzwerk ansprechbar ist (Bild 6)
Im Prinzip sollten Sie sich an dieser Stelle an einer blinkenden Gruppe von Leuchtdioden erfreuen können. Ist dies nicht der Fall, so ist die wahrscheinlich häufigste Ursache, dass Sie eine SD-Karte zum Testen von mehreren Applikationen verwendet haben.
Diese Vorgehensweise für Ärger, weil das Deployen eines zweiten Programms seinen Vorgänger nicht deinstalliert. Es kommt dann zu diversen Kappeleien zwischen den Applikationen, die um die geteilten Hardwareressourcen kämpfen. Im Interesse ihrer Vernunft ist es empfehlenswert, für jedes Android Things-Produkt eine eigene SD-Karte anzulegen.
Als dienstalter Knochen konnte der Autor an dieser Stelle einen kleinen Versuch nicht verkneifen – zur Ermittlung der Frequenzstabilität wurde ein LeCroy-Digitalspeicheroszillograph mit dem Ausgang verbunden. Bei einer Schaltfrequenz von einer Sekunde war die Ausgabe stabil – wer das Runnable stattdessen alle zehn Millisekunden triggert, bekommt Probleme.

Updates aus der Wolke

Das Aktualisieren der Firmware eines Embedded-Geräts ist eine haarige Angelegenheit: Geht dabei etwas schief, so muss das betroffene Unternehmene Hardware bewegen - dies ist erstens teuer, und der Kundenzufriedenheit zweitens nur wenig zuträglich.
Im Interesse der Vermeidung von Ausfällen setzen Hersteller seit einiger Zeit auf das Prinzip des A-B-Update: Prozessrechner das Telefon sind mit zwei identischen Speicherpartitionen ausgestattet. Im Bootloader findet sich Logik, die wahlweise die Inhalte der Partition A oder Partition B aktiviert. Wer ein Update einspielen möchte, schreibt es in die veraltete Partition - auf diese Art und Weise ist sichergestellt, dass der Benutzer nach einem fehlgeschlagenen Updateversuch zum gerade aktuellen und mehr oder weniger gut funktionierenden Betriebssystem zurückkehren kann.
Im Fall unseres Prozessrechners lässt sich diese Vorgehensweise dadurch bestätigen, dass wir die Partitionstabelle wie in Bild 7 gezeigt auf den Bildschirm holen - Sie sehen, dass einige Partitionen, darunter auch die 32 MByte grosse OEM-Partition, zweimal angelegt wurden.
sudo lsblk -o NAME,FSTYPE,SIZE,MOUNTPOINT,LABEL liefert Informationen über das Dateisystem (Bild 7)
Google nutzt dieses Verfahren übrigens seit einiger Zeit zur Aktualisierung von Smartphones und Tablets - die unter https://source.android.com/devices/tech/ota/ab_updates
bereitstehende Webseite bietet eine Vielzahl von Hintergrundinformationen zur Thematik, die für Embedded-Entwickler schon aus Gründen der Fortbildung eine hochinteressante Lektüre darstellt.
Unsere nächste Aufgabe ist das Aktualisieren des Blinkprogramms ohne Nutzung der ADB. Dies erfolgt über die Android Things-Konsole, in der sie - mehr oder weniger nach Belieben - neue Bundles anlegen können, die Google sodann nach bestem Wissen auf die Endgeräte überträgt.
An dieser Stelle muss ich Sie darauf aufmerksam machen, dass die kommerzielle Nutzung der Android Things-Konsole derzeit vertraglich untersagt ist. In den nach der ersten Anmeldung angezeigten AGBs findet sich folgende Passage, die Hervorhebungen sind vom Autor:
 
1.1. Android Things Console and Software. Subject to the Terms, Google grants you a limited, revocable, non-transferable, non-exclusive, right to (i) access and use the Android Things Console and (ii) install and use the Software on up to 500 devices owned or controlled by you for the sole purpose of internal development and testing of devices that have integrated the Software. These Terms do not provide you with a right to sell, exploit or otherwise distribute any device that has integrated the Software. Commercial rights to use the Software for these purposes must be granted expressly via a separate written agreement with Google ("Commercial Agreement"). The Commercial Agreement will control in the event of a conflict with these Terms.
 
Ärgerlicherweise nennt Google bisher keine Informationen über die Preise der Update-Dienstleistungen: die unter https://stackoverflow.com/questions/46125585/android-things-can-sdk-be-used-for-commercial-projects befindliche Diskussion zeigt, dass einige Entwickler mehr als frustriert sind.
Zudem zeigen die Erfahrungen mit Google Maps, dass der Suchmaschinenanbieter bei gebotener Gelegenheit durchaus heftig zulangt: es wäre also durchaus vorstellbar, dass Google eine nicht unerhebliche Menge an Lizenzgebühren verlangt.
Entwickler-eigene Software wird in der Konsole über ein als Bundle bezeichnetes .zip-Archiv bereitgestellt: ein Android Things-Bundle hat mit seinem für normale Android-Applikationen vorgesehenen Namensvetter indes nichts gemein. Es handelt sich dabei stattdessen um ein vergleichsweise einfach aufgebauhtes Archiv, das die für den Prozessrechner relevanten Dateien bereitstellt.
Spezifischerweise dürfen Sie ein .zip-Archiv anliefern, das die während dem Hochfahren des Geräts anzuzeigende Animation beschreibt. Zudem muss das Archiv ein oder mehrere .apk-Dateien enthalten, eine davon implementiert den Intent-Filter für das weiter oben besprochene Startereignis android.intent.category.IOT_LAUNCHER.
Wir wollen in den folgenden Schritten eine Veränderung des Blink-Patterns vornehmen. Kehren Sie in Android Studio zurück, und passen Sie den Code der OnCreate-Methode an:
 
PeripheralManagerService service = new PeripheralManagerService();
try {
    myPins[0] = service.openGpio("BCM6");
myPins[0].setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
    myPins[1] = service.openGpio("BCM13");
    myPins[1].setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
    myPins[2] = service.openGpio("BCM19");
myPins[2].setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH);
    myPins[3] = service.openGpio("BCM26");
myPins[3].setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH);
 
Von besonderem Interesse ist an dieser Stelle, dass wir nun statt drei High und einem Low zwei High- und zwei Low-Werte einschreiben. Der Prozessrechner blinkt sodann eine andere Lichtfolge, was auch mit freiem Auge ohne grosse Probleme feststellbar ist. Alternativ dazu können Sie natürlich auch die Aufrufgeschwindigkeit des Runnables beschleunigen oder verlangsamen – achten Sie nur darauf, eine Methode zu wählen, deren Ergebnisse auch ohne Oszillograph beobachtet werden können.
Da wir dieses Projekt über die Android Things Console ausliefern, dürfen Sie keinen Debuggingprozess anstoossen. Klicken Sie stattdessen auf Build Make Project, um Android Studio zur Rekompilation des Gesamtprojekts zu animieren. Alternativ dazu können Sie an dieser Stelle die SD-Karte klonen und einen zweiten Raspberry Pi anwerfen, der ausschliesslich auf das Herunterladen von Updates wartet.
Klicken Sie im nächsten Schritt auf Build Build APK, um das Werkzeug zur Erzeugung der APK-Datei zu animieren. Klicken Sie daraufhin in die Statuszeile am unteren Bildschirmrand, um den in Bild 8 gezeigten Dialog auf den Bildschirm zu holen. Dort können Sie auf den Link Locate klicken, um das APK im Dateisystem-Browser ihrer Workstation zu öffnen.
Android Studio führt Sie direkt zur APK ihrer Applikation (Bild 8)
Packen Sie die. APK-Datei im nächsten Schritt unter Nutzung eines beliebigen Werkzeugs in ein .zip-Archiv, und kehren sie in die Android Things-Konsole zurück. Klicken Sie auf die Rubrik Factory Images, um die Liste der diversen, zu ihrem Projekt gehörenden Module auf den Bildschirm zu holen. Klicken Sie in der Rubrik Bundles sodann auf den Link Upload Bundle, und navigieren Sie zu ihrer soeben erzeugten Zipdatei. Diese darf danach durch Anklicken von Upload hochgeladen werden.
Im Test des Autors war dies – witzigerweise - die einzige Stelle, in der Firefox Probleme hatte: Das Backend akzeptiert die Auswahl der Datei nur unter Chrome. Wie dem auch sei, wird das Hochladen einige Zeit in Anspruch nehmen – ein Fortschrittsbalken informiert Sie darüber, wie weit das Backend mit der Verarbeitung ihrer Spende vorangekommen ist.
Wählen Sie im nächsten Schritt das aktuellste Bundle und die vorher verwendete Android Things-Version aus, und wechseln Sie in die Rubrik OTA Updates. Klicken Sie dort auf den Button „Start a new Update“, und wählen Sie das aktuelle Bundle und die Android Things-Version. Klicken Sie danach auf den Knopf Push Update, um eine Messagebox auf den Bildschirm zu holen, in der Sie die Aktualisierungsoperation nochmals bestätigen müssen. Nach dem Anklicken von Push beginnt das Backend mit der Generierung der Aktualisierung, die sodann wie in Bild 9 gezeigt angezeigt wird.
Die Updates beginnen mit der Selbst-Auslieferung (Bild 9)
An dieser Stelle ist Geduld erforderlich: Der auf jedem Raspberry Pi vorinstallierte automatische Upgrade-Assistent sucht nämlich nur einmal alle 5 bis 6 Stunden nach einem Update, und lässt sich nicht von Hand zu häufigeren Suchen animieren. Als wäre dieser Blödsinn nicht genug, hat Google im Moment auch kein Verfahren implementiert, um den Prozessrechner automatisch neu zu starten: Sie sollten also nach fünf oder sechs Stunden den Prozessrechner herunterfahren und neu starten, um eine Aktualisierung des Betriebssystems und der dazugehörigen Applikationen anzuweisen.
Dieses auf den ersten Blick wie eine Schikane wirkende Vorgehen ist übrigens sinnvoll: Stellen Sie sich die Freude eines Rüstungselektronikers vor, wenn ein Transferstandard während eines langlaufenden Experiments beschliesst, dass jetzt ein Update erforderlich ist, das die Farbe einer Leuchtdiode verändert.
Der effizienteste Weg zum Rebooten des Prozessrechners ist, über ADB Verbindung zum unterliegenden Linux-Betriebssystem aufzunehmen. Hierzu muss der ADB-Dienst im ersten Schritt in den Root-Modus versetzt werden – ob des Neustart des Daemons müssen Sie die Verbindung zum RPi danach neu aufbauen:
 
tamhan@TAMHAN14:~/Android/Sdk/platform-tools$ ./adb root
restarting adbd as root
tamhan@TAMHAN14:~/Android/Sdk/platform-tools$ ./adb connect 10.42.0.44
connected to 10.42.0.44:5555
 
Im nächsten Schritt folgt die eigentliche Aufforderung zum Neustart. Dazu beschaffen Sie eine Shell, und nutzen danach den Befehl reboot:
 
tamhan@TAMHAN14:~/Android/Sdk/platform-tools$ ./adb shell
rpi3:/ # reboot
 
Ärgerlicherweise erwies sich dies in Tests des Autors als nur wenig produktiv: Reboots beeinflussen die Update-Suchrate des Prozessrechners offensichtlich nicht.Interessant ist, dass das Nutzen der Shell auch den Zugriff auf das von gewöhnlichen Unix-Workstations bekannte ls-Kommando erlaubt. Dort findet sich zeitweise der in Bild 10 gezeigte Prozess, der manchmal sogar einige Prozent Rechenleistung in Anspruch nimmt.
Der Name Update-Engine klingt verdächtig nach Chrome OS (Bild 10)
Die Update-Engine lässt sich sogar aus der Kommandozeile heraus ausführen: Ärgerlicherweise ist es auch hier nicht möglich, sofort eine Aktualisierung zu befehlen.
An dieser Stelle sorgt das weiter oben gesehene Phänomen abermals für Ärger - Android Things ist nicht, oder nur leidlich, dafür ausgerüstet, mit Situationen umzugehen, in denen mehrere Peripheriegeräte und den Zugriff auf ein Hardwaremodul streiten. Versuchen Sie deshalb im ersten Schritt, dass von Android Studio platzierte Paket durch den PM zu beseitigen:
 
tamhan@TAMHAN14:~/Android/Sdk/platform-tools$ ./adb shell
rpi3:/ # pm uninstall com.tamoggemon.nmgthing
Success
 
Aus technischer Sicht bietet diese Sequenz von Konsolenbefehlen übrigens nichts überraschendes: Da Android Things keine Settings-Applikationen mitbringt, müssen wir das Programm stattdessen unter Nutzung des auf der Konsole verfügbaren Paketmanager beseitigen. Achten Sie lediglich darauf, den hier verwendeten Paketnamen com.tamoggemon.nmgthing durch einen anderen, zu ihrem Paket passenden String, zu ersetzen. Nach dem erfolgreichen Zurücksetzen des Android Things-Geräts erscheint der bekannte Homescreen am Bildschirm.
Führt auch dies nicht zum Ziel, so können wir überprüfen, ob die Kombination aus Bundle und Betriebssystem lebensfähig ist. Hierzu zählen wir in den Tab Factory Images zurück, und erstellen eine neue Build-Konfiguration aus dem aktuellsten Bundle und der aktuellsten Android Things-Version. Klicken Sie danach wie gewohnt auf Create Build Configuration und auf Download Build, um das Backend von Android Things - wie am Anfang des Artikels - dazu anzuweisen, ein neues Image zu kompilieren. Laden Sie dieses danach herunter, und  deployen Sie es auf die gewohnte Art und Weise in Richtung des Prozessrechners.
Funktioniert ihr Bundle zumindest in der Theorie, so wird die im Bundle enthaltene Applikation nach der erfolgreichen Initialisierung des neugebrannten Images am Bildschirm erscheinen. Erfolgt dies nicht, so ist die Struktur des Bundles fehlerhaft.

Bootscreen nach Mass

Sie dürfen im Bundle durch das Mit-Ausliefern einer Datei namens bootanimation.zip eine Animation festlegen, die im Rahmen der Initialisierung des Betriebssystems angezeigt wird: insbesondere im Bereich der hochpreisigen Messtechnik ist es wünschenswert, die Nutzung von Android so gut wie möglich zu verschweigen.
Für erste Gehversuche wollen wir uns eine der unter https://forum.xda-developers.com/android/themes/bootanimations-50-flashable-t3059659 zum Download bereitstehenden Beispielanimationen von fremden Autoren ansehen – wer Disintegrating Hexagon extrahiert und das Resultat durch den Tree-Befehl jagt, sieht das in der Bild 13 gezeigte Resultat. Wichtig ist, dass die in den einzelnen Ordnern liegenden .png-Dateien stets durchnummeriert sein müssen, da sie der Bootloader sonst nicht findet.
desc.txt – der Name darf auf keinen Fall mit einem grossen D geschrieben werden – ist hierbei eine Textdatei, die die Anzeige der in den verschiedenen Ordnern liegenden .png-Dateien steuert. Im Fall des Beispielfiles sieht die Struktur folgendermassen aus:
 
720 1280 30
p 0 0 DisintegratingHexagon
 
Die erste Zeile des Files legt die Breite, die Höhe und die Anzahl der Frames pro Sekunde fest: unsere Animation ist für ein Telefon mit einer Auflösung von 1280x720 vorgesehen, und wird mit 60 Frames pro Sekunde abgespielt.
Die darunter folgenden Zeilen beschreiben die Stufen der Animation, und sind nach folgendem Schema aufgebaut:
 
TYPE COUNT PAUSE PATH [#RGBHEX CLOCK]
 
Type ist entweder p oder c: ein c-Teil wird vom Betriebssystem auf jeden Fall abgespielt, während der P-Teil vom erfolgreich durchgelaufenen Systemstart unterbrochen werden darf. Count bestimmt, wie oft die Animation abzuspielen ist – wer hier 0 übergibt, erzeugt eine Endlosschleife, die nur vom erfolgreichen Bootprozess unterbrochen wird. Mit Pause bestimmen Sie die in Frames gehaltene Wartezeit nach dem erfolgreichen Abspielen der Sequenz, während Path den – case sensitive gehaltenen – Namen des Unterordners enthält, in dem die jeweiligen Sequenzdateien warten.
Die beiden optionalen Attribute erlauben das Festlegen einer Hintergrundfarbe und eines Platzes zum Einblenden einer Uhrzeit – eine vollständige Dokumentation findet sich unter https://android.googlesource.com/platform/frameworks/base/+/master/cmds/bootanimation/FORMAT.md. Zu guter Letzt dürfen wir in jedem Verzeichnis eine Datei namens audio.wav ablegen, die im Rahmen des Abarbeitens der jeweiligen Sequenz aus den Lautsprechern des Geräts erklingt.

Meine eigene Animation

Nach diesen vorbereitenden Überlegungen ist es an der Zeit, eine eigene Bootanimation zusammenzustellen. Im Interesse besserer User Experience sollten Sie darauf achten, dass die Animation nie stehenbleibt – wenn die Balken nicht mehr laufen, ist der User versucht, das Gerät abzuwürgen. Dies löst in vielen Fällen eine zwangsweise Überprüfung des Dateisystems aus, die noch mehr Zeit in Anspruch nimmt: am Ende dieses Teufelskreises steht allzu oft eine Reklamation.
Als erste Aufgabe wollen wir – im Interesse von reduziertem Speicherverbrauch – dafür sorgen, dass die Animation nur mit zehn Frames pro Sekunde abgearbeitet wird. Hierzu müssen wir die erste Zeile von desc.txt folgendermassen anpassen:


1920 1080 10

Im nächsten Schritt müssen wir die beiden abzuspielenden Sequenzen realisieren. Der Autor möchte nach dem Start erstens eine über den Bildschirm laufende Schrift realisieren, um den Bildschirm daraufhin langsam von weiss zu schwarz umzufärben. Dazu sind zwei Animationsfolgen erforderlich, weshalb desc.txt als Ganzes folgendermassen aussieht:
 
1920 1080 10
c 1 0 laufschrift
p 0 0 farbenwirbel
 
Der mit c markierte Teil wird hierbei zwei Mal durchlaufen, während der darauffolgende Farbenwirbel so lange abgearbeitet wird, bis Android Things einsatzbereit ist. Erzeugen Sie im nächsten Schritt die beiden Unterordner, und platzieren Sie die Elemente wie in Bild 11 gezeigt.
Die Grafiken sind am Platz – dass beide Animationen je zehn Frames umfassen, ist Zufall (Bild 11)
Danach verpacken wir die .apk-Datei und das Archiv bootanimation.zip in ein neues .zip-Archiv, das im nächsten Schritt wie gewohnt in Google‘s Backend wandert. Im Interesse schnellerer Abarbeitung laden sie ein neues Image herunter, und erfreuen sich danach an der Animation.
Beim Debugging von bootanimation.zip ist es hilfreich, das File direkt auszutauschen. Die Lösung für dieses Problem besteht darin, die Karte aus dem Prozessrechner zu entnehmen und mit einem Cardreader in einer Unix-Workstation zu mounten: bootanimation.zip liegt im Ordner /oem/media.
Angemerkt sei, dass die häufigste Ursache für Probleme beim Abspielen der Animation in der falschen Komprimierungseinstellung liegt.

Fazit

Android Things ist mit Sicherheit noch nicht ausgereift - das Deployment von Updates weist noch die eine oder andere Kinderkrankheit aus, zudem ist noch nicht klar, wie fürstlich sich Google die Nutzung der Android Things-Console am Ende bezahlen lassen wird.
Schon jetzt ist indes klar, dass die Arbeit mit Android Things nicht unvernünftig ist: Die Möglichkeit, den gesamten GUI-Stack von Android Things zu nutzen, spart insbesondere bei Kleinserien wertvolle Mannstunden…
Autor
Tam Hanna
Der in der Slowakei lebende Tam Hanna leitet die ebenda ansässige Tamoggemon Holding k.s. Dieses Unternehmen beschäftigt sich mit Consulting, Anwendungsentwicklung und dem Verfassen von Fachtexten für die IT-Industrie. Seit 2004 liegt der Schwerpunkt von Tams Tätigkeit im Bereich der Mobilcomputer. Er verfolgt die Industrie seit dem Palm IIIc, ist als Blogger bei Heise tätig und in diversen Magazinen und auf einigen Kongressen zu sehen. Auf der JVM-Con , die vom 28. – 29. November 2017 in Köln stattfindet, hält der Autor einen Vortrag zum Thema dieses Artikels.




Das könnte Sie auch interessieren