Googles Android/ Eine Übersicht zu Android

Aus Wikibooks

Zurück zu Googles Android


Faszination Smartphone[Bearbeiten]

Smartphones begeistern auch wenig technikaffine Menschen seit einigen Jahren. Die Kombination aus Telefonie, GPS, Internet und Multimedia-Inhalten bietet Entwicklern mit Phantasie ein breites Spektrum an Anwendungsmöglichkeiten. Kaum ein Tag vergeht, an dem nicht eine neue originelle App auf einem der virtuellen Marktplätze angeboten wird.

Derzeit ist Android, gefolgt von Apples iOS, das meistverwendete Betriebssystem auf Smartphones und Tablet-Computern. Da Android anders als vergleichbare Betriebsysteme offen ist, kann es auch auf andere Geräte portiert werden. In diesem Buch lernen Sie vieles zum Betriebssystem Android und Möglichkeiten zur Anwendungsentwicklung.

Linux Inside[Bearbeiten]

Obwohl Android auf Linux 2.6 basiert, gibt es doch einige ganz erhebliche Unterschiede zu den klassischen Linux-Systemen. Für Systemaufrufe wird nicht wie sonst die Bibliothek glibc, sondern die androideigene Entwicklung bionic verwendet. Für diesen – auf den ersten Blick ungewöhnlichen Schritt – gibt es gute Gründe:

  • Lizenz: glibc nutzt die GPL (GNU General Public License), bionic dagegen die BSD-Lizenz.

GPL erfordert das so genannte Copyleft und somit, dass jede Software, die glibc nutzt, selbst unter die GPL zu stellen ist. Diese Anforderung schränkt die kommerziellen Anpassungen von Android stark ein. Selbst wenn kommerzielle Interessen keine primäre Rolle spielen, kann man aus dem Quellcode unter Umständen auf interne Details des Gerätes schließen, die nicht öffentlich gemacht werden sollen.

  • Größe: Die glibc benötigt etwa 400 kByte je Prozess, bionic dagegen gerade mal die Hälfte.

Ein Vorteil, der natürlich besonders auf mobilen Endgeräten mit ihren begrenzten Ressourcen zum Tragen kommt.

Darüber hinaus gilt bionic und insbesondere ihre Thread-Bibliothek als sehr schnell.

Java[Bearbeiten]

Apps für Android werden in Java entwickelt. Das hat den großen Vorteil, dass so eine große Gruppe von Entwicklern nach einer Einarbeitung in das javabasierte Android-SDK schnell in der Lage ist, für die Plattform zu entwickeln. Mit Hilfe des Android NDK (Native Development Kit) kann aber auch nativer Code, also Code der mit etwa mit Hilfe eines C- oder C++-Compilers übersetzt wurde, integriert werden. Die Entwicklungsumgebung für Android Apps findet man auch in der folgenden Abbildung:

Wir sehen, dass die Java-Quellen in der Entwicklungsumgebung geschrieben und wie gewohnt in das class-Format als Java-Bytecode übersetzt werden. Anders als bei der Arbeit mit dem Java-SDK werden die class-Dateien dann in das so genannte dex-Format (Dalvik Executable) übersetzt. Eine dex-Datei kann dabei mehrere class-Dateien umfassen. Es handelt sich aber nicht nur um die Zusammenfassung mehrerer Dateien zu einer einzigen, sondern wirklich um die Übersetzung in neuen Programm-Code. Doch dazu gleich mehr. Die dex-Datei wird mit weiteren Dateien, wie etwa dem Manifest, zur eigentlichen App zusammengefasst, deren Datei die Endung apk erhält. Diese apk-Datei wird dann auf dem Gerät installiert.

Der dex-Code aus der App wird dort von der Dalvik Virtual Machine (DVM) ausgeführt. Die DVM wurde von Dan Bornstein bei Google entwickelt und eignet sich besonders als Laufzeitumgebung für Low-End-Geräte. Sie basiert auf einer frei verfügbaren Java-Umgebung namens Apache Harmony und zeichnet sich durch einen geringen Bedarf an Arbeitsspeicher und Strom aus. Da die DVM keinen Java-Byte-Code ausführt, ist sie keine JVM und fällt somit nicht unter Lizenzbestimmungen von Oracle.

Neben dem lizenzrechtlichen Vorteil ergibt sich aber auch ein erheblicher Performance-Unterschied: Die JVM basiert auf dem Maschinenmodell der Kellermaschine. Konkrete Computer sind aber Registermaschinen. Die Bytecode-Anweisungen, die für eine Kellermaschine entwickelt wurden, müssen also zur Laufzeit in Anweisungen für Registermaschinen umgesetzt werden. In der Mitte der 1990-er Jahre interpretierten die frühen JVM-Implementierungen den Bytecode und benötigten dazu viel Zeit, da die Anweisungen ja auf eine komplett andere Architektur umgesetzt werden mussten. Heute wird Bytecode mit Hilfe eines Just-In-Time-Compilers (JIT-Compiler) zur Laufzeit direkt in den Maschinencode der Zielplattform übersetzt. Das ist zwar schneller als die Interpretation und benötigt – anders als bei leistungsstarken Servern – doch einige der auf mobilen Endgeräten knappen Ressourcen. Bei der Entwicklung unter Android wird der class-Code bereits auf der Entwicklungsmaschine in dex-Code übersetzt. Dieser dex-Code basiert auf Registermaschinen und kann von der DVM auf dem Endgerät zügig interpretiert werden. Unter anderem versprach man sich von diesem Ansatz auch, keinen JIT-Compiler mehr zu benötigen, doch enthält die DVM seit Android 2.2 einen JIT-Compiler, was insbesondere bei dürftig ausgestatteten Geräten zu spürbaren Leistungssteigerungen geführt hat.

Die Sandbox[Bearbeiten]

Zunächst erscheint es wieder merkwürdig, dass Android verschwenderisch mit System-Ressourcen umgeht. Jede App hat nämlich

  • einen eigenen Prozess
  • eine eigene DVM
  • einen eigenen Heap
  • ein eigenes Verzeichnis im Dateisystem
  • einen eigenen Betriebssystem-User

Dadurch, dass wir jeder App diese eigene Umgebung zugestehen, erhalten wir mehr Sicherheit. Die strikte Trennung der Prozesse bewirkt, dass verschiedene Apps nicht auf den Arbeitsspeicher anderer Apps zugreifen können. Das Verzeichnis der Anwendung ist ebenfalls gegen fremde Zugriffe geschützt. Apps dürfen nur Ressourcen anderer Apps nutzen, wenn sie dazu berechtigt sind. Berechtigungen werden explizit in einer eigenen Datei, dem Manifest der App, angefordert und bereitgestellt.

Tatsächlich können eigene DVMs sogar ohne großen Aufwand bereitgestellt werden. Es wird auf den expliziten Neustart einer DVM verzichtet. Stattdessen gibt es einen Systemprozess namens zygote, der mit Hilfe der Unix-Anweisung fork dafür sorgt, dass jede App einen eigenen DVM-Prozess hat. Außerdem sorgt zygote dafür, dass möglichst viele Ressourcen geteilt werden. Dies sorgt für einen raschen Start und eine ressourcenschonenden Betrieb der DVM. Wer mehr über die Interna von Android wissen will sei auf einen Übersichtsartikel verwiesen.

TODO Referenz auf Fokusreport


Da Android mehrere Apps gleichzeitig betreiben kann, sind Engpässe im Hauptspeicher möglich, wenn zu viele Apps gestartet werden. Die Apps werden in einem Stapel verwaltet.

Das oberste Programm ist dabei sichtbar und aktiv. Mit dem Back-Button des Android-Gerätes wird eine Anwendung vom Stack aktiviert und die vormals aktive Anwendung auf den Stack gelegt. Sollte es zu Speicherengpässen kommen, kann Android Apps, die weiter unter auf dem Stapel liegen, beenden.

Das Manifest[Bearbeiten]

Wir haben bereits gesehen, dass Android-Apps eine Manifest-Datei enthalten. Das Manifest ist ein XML-Dokument, in dem verschiedene Eigenschaften der App publiziert sind. Unter anderem sind dort auch die Rechte verzeichnet und somit die Ressourcen, die die App nutzen will. Bei der Installation wird der Anwender gefragt, ob er bereit ist, der App diese Rechte einzuräumen. Im folgenden Beispiel wird deklariert, dass die App GPS-Zugriff braucht:

  <uses-permission   
    android:name="android.permission.ACCESS_FINE_LOCATION">
  </uses-permission>

Komponenten[Bearbeiten]

Wegen des Sandbox-Prinzips kann keine App die öffentlichen Klassen einer anderen App nutzen. Auf den ersten Blick schränkt dies die Wiederverwendbarkeit unseres Codes stark ein. Tatsächlich bedient sich Android einer wesentlich robusteren Software-Architektur als der einfachen Verwendung von Java-Klassen. Die Klassenstruktur einer App ist vollständig gekapselt und somit für andere Apps eine Blackbox. Jede App kann aber Komponenten publizieren, die dann von anderen Apps nutzbar sind. Wir lösen uns so von den Implementierungsdetails unserer Java-Klassen und haben insgesamt weniger Abhängigkeiten. Der Entwurf und die Implementierung einer App können sich jetzt komplett ändern, solange nur die Schnittstelle der Komponenten erhalten bleibt.

Ein erheblicher Teil dieses Buches widmet sich der Entwicklung von Komponenten. Damit sind insbesondere gemeint

  • Activities
  • Services
  • Broadcast-Receiver
  • Content-Provider

Jeder dieser Komponentenarten ist jeweils mindestens ein Kapitel gewidmet. Wir geben daher an dieser Stelle nur einen kurzen Überblick

Activities[Bearbeiten]

Activity ist die Java-Klasse die zu jeder Form von GUI gehört. Die Activity enthält die Logik, die zu einer GUI gehört. Ein bekanntes Beispiel ist die Dialer-Activity aus der folgenden Abbildung.

Services[Bearbeiten]

Komplexe Aufgaben werden nicht im Hauptthread einer View ausgeführt. Bei Zeitüberschreitung einer Anwenderaktion kann Android die ganze App mit einer „Application Not Responding“-Meldung wegen Zeitüberschreitung abbrechen. Potenziell zeitaufwändige Operationen wie etwa Netzwerkzugriffe werden daher von Services in Threads oder eigenen DVMs bearbeitet. Nebenläufigkeit spielt bei Android eine bedeutende Rolle.

Broadcast-Receiver[Bearbeiten]

Auf dem Gerät treten Ereignisse ein, die über einen so genannten Broadcast gemeldet werden. Beispiele für Broadcasts sind

  • das Telefon klingelt
  • eine SMS trifft ein
  • die Akkuleistung lässt nach

Ausserdem können Apps auch eigene Broadcasts versenden. Mit Hilfe eines Broadcast-Receivers kann eine App Broadcasts mit Ereignissen „abonnieren“, die für die App wichtig sind.

Content-Provider[Bearbeiten]

Content-Provider bieten ihren Nutzern eine SQL-ähnliche Syntax als Schnittstelle für Daten. Wie der Provider diese Schnittstelle implementiert und ob überhaupt eine Datenbank zum Einsatz kommt, ist dem Nutzer des Providers dabei nicht bekannt. Im folgenden Beispiel verschaffen wir uns Zugriff auf alle Lieder, die auf unserem Telefon gespeichert sind und die das Wort ‚Yesterday‘ in ihrem Titel tragen.

  Uri from = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  String artist = MediaStore.Audio.AudioColumns.ARTIST;
  String stream = MediaStore.Audio.Media.DATA;
  String title = MediaStore.Audio.Media.TITLE;
  String where = title + " like '%Yesterday%'";
  Cursor songs = getContentResolver().query(from,
    new String[] { artist, stream, title },
    where, null, null);

Einen ersten Eindruck über den Aufbau eines Content-Providers liefert die folgende Abbildung


Wir sehen, dass die Komponenten einer App voneinander unabhängig sind. Wie sie ihre Schnittstellen publizieren, lernen wir noch in einem späteren Kapitel. Wir bezeichnen Komponenten auch als lose gekoppelt (loosely coupled). Obwohl sich alles lokal auf einem kleinen mobilen Gerät abspielt, hat die Architektur einer App in Android Ähnlichkeit mit einem verteilten System.

Einzelnachweis[Bearbeiten]