Erstellen und Portieren NDK-basierter Android*-Apps für die Intel® Architektur

Ziel

Dieser Artikel bietet Einsteigern eine Einführung in das Erstellen nativer (NDK-basierter) Android*-Anwendungen für Geräte, die auf der Intel® Architektur (IA) basieren. Darüber informiert er über das Portieren von NDK-Android-Apps – die ursprünglich für Geräte auf Basis anderer Architekturen entwickelt wurden – auf IA-basierte Geräte. Wir beleuchten zwei Szenarien: Das erste Beispiel umfasst alle Schritte, die für das Erstellen einer einfachen NDK-basierten Android*-App – von Anfang bis Ende – erforderlich sind. Ein weiteres Beispiel zeigt, wie sich eine bestehende NDK-basierte Android-App, die auf IA-basierten Geräten eingesetzt werden soll, einfach portieren lässt.

Inhaltsverzeichnis

1. Einleitung

2. Erstellen einer NDK-basierten Android*-App für IA-basierte Geräte (schrittweise Entwicklung einer einfachen App)

a. Erstellen eines Android*-Standardprojekts
b. Aufruf von nativem Code aus Java-Quellen
c. Generieren von JNI-Header-Stubs für nativen Code mit „javah“
d. Erstellen von nativem Code für die IA mit dem NDK
e. Neuerstellung, Installation und Ausführung der für die IA konzipierten Android-NDK-App

3. Portieren bestehender NDK-Apps auf IA-basierte Geräte mit dem x86-NDK-Toolset

4. Zusammenfassung

Einleitung

Die Tools des Native Development Kit (NDK) ermöglichen die Verwendung von nativem Code in Android*-Anwendungen. So können Sie als Entwickler Legacycode wiederverwenden, für Low-Level-Hardware Code schreiben oder Apps entwickeln, die sich von anderen abheben, da Sie andernfalls nicht optimale oder verwendbare Funktionen einsetzen können.

Dieser Artikel bietet eine grundlegende Einführung, die das Erstellen von NDK-basierten Apps für die IA von Anfang bis Ende erläutert. Er präsentiert zudem einfache Anwendungsszenarien für das Portieren bestehender NDK-basierter Apps auf IA-basierte Geräte. Anhand eines Beispiels veranschaulichen wir die schrittweise Entwicklung einer App.

Dabei gehen wir davon aus, dass Sie die Android-Entwicklungsumgebung – einschließlich Android-SDK und Android-NDK – bereits installiert und emulator-x86 zum Testen der Apps konfiguriert haben. Weitere Informationen finden Sie auf der Intel-Website in der Android-Community. Um unsere Entwicklungsumgebung einfach zu halten, verwenden wir hauptsächlich die Linux*-Befehlszeilentools.

Erstellen einer NDK-basierten Android*-App für IA-basierte Geräte (schrittweise Entwicklung einer einfachen App)

Nehmen wir an, wir hätten Legacycode, der C und Assembly-Sprache für das Parsen der CPUID verwendet (weitere Informationen zur CPUID siehe http://de.wikipedia.org/wiki/CPUID*). Unten sehen Sie den Quellcode für den im Beispiel verwendeten C-„Legacy“-Code cpuid.c (nur zu Demonstrationszwecken).

Wir möchten cpuid_parse aus unserer Android-App aufrufen (nur zu Demonstrationszwecken – die Funktion cpuid_parse erwartet einen im Vorfeld zugewiesenen Puffer) und den Rückgabewert innerhalb der App anzeigen.

Das Erstellen einer Android-App und Verwenden des oben erwähnten nativen Legacycodes wird unten schrittweise von Anfang bis Ende beschrieben.

1. Erstellen eines Android*-Standardprojekts

Das Android-SDK enthält Befehlszeilentools, mit denen sich eine Standardprojektstruktur für eine typische „Hello World“-App anlegen lässt. Zuerst erstellen wir ein Standardprojekt. Anschließend ändern wir die Java-Quellen, um JNI-Aufrufe und nativen Code hinzuzufügen.

Im Screenshot oben haben wir zunächst das Verzeichnis labs/lab2 erstellt und dann mit dem Befehlszeilentool „android“ das Standardprojekt erzeugt. Wir haben android-15 als API-Ebene definiert und unserer App den Namen „CPUIdApp“ gegeben (mit Paket com.example.cpuid).

Anschließend haben wir mit dem Befehlszeilentool „ant“ das Projekt im Debug-Modus erstellt und mit „adb“ installiert (bzw. neu installiert, falls es bereits auf dem Emulator oder Ziel vorhanden war). Wir gehen davon aus, dass Sie bereits einen Emulator oder ein Gerät angeschlossen haben und es sich dabei um das einzige in der Befehlsausgabe „adb devices“ aufgeführte Gerät handelt.

Unten sehen Sie einen Screenshot des Android-x86-Emulators mit ICS nach der Durchführung der oben beschriebenen Schritte.

Wenn Sie die App anklicken, wird die Standardausgabe der App – „Hello World“ – angezeigt. Ändern wir nun die App, sodass sie nativen Code verwendet.

2. Aufruf von nativem Code aus Java-Quellen

Das Android-Standardprojekt erzeugt die Java-Quellen für ein typisches „Hello World“-Projekt, indem dem Paket ein Namespace zugewiesen wird (z. B. com.example.cpuid). Der Screenshot unten zeigt den für die Java-Hauptquelldatei erzeugten Quellcode.

Um nativen C/C++-Code in unserer Java-Quelldatei verwenden zu können, müssen wir zunächst den JNI-Aufruf deklarieren und die native Bibliothek laden (siehe gelb umrahmter Bereich im Screenshot unten).

Wie in der Deklaration zu sehen, gibt der native Aufruf einen Java-String zurück, den wir an einer beliebigen Stelle in unserer Java-Quelle verwenden können. Wie im Screenshot oben zu sehen, haben wir TextView so angepasst, dass der String des nativen Aufrufs angezeigt wird (siehe rot umrahmter Bereich).

Dies ist ein sehr einfaches Beispiel für die Deklaration und Verwendung nativer JNI-Aufrufe in Android-App-Java-Quellen. Nun werden wir mit dem „javah“-Tool die JNI-Header-Stubs für nativen Code erzeugen und nativen Code so hinzufügen oder ändern, dass er mit nativen JNI-Headern kompatibel ist.

3. Generieren von JNI-Header-Stubs für nativen Code mit „javah“

Jetzt müssen wir unseren nativen Code so ändern, dass er mit der JNI-Aufrufspezifikation kompatibel ist. Das „javah“-Tool hilft uns, die geeigneten JNI-Header-Stubs auf Basis der Java-Quelldateien automatisch zu generieren. Das „javah“-Tool benötigt die kompilierte Java-Klassendatei für die Generierung der Header. Daher erzeugen wir mit dem „ant“-Tool schnell Java-Klassendateien, wie im Screenshot unten gezeigt („ant debug“).

Erzeugen Sie mit „javah“ den JNI-Header wie im Screenshot gezeigt (zweiter gelb umrahmter Bereich). Damit werden das Verzeichnis „jni“ und der Header-Stub auf Basis der Java-Klasse erstellt. Der Screenshot unten zeigt den generierten nativen JNI-Header-Stub.

Erstellen Sie die entsprechende C-Quelldatei („com_example_cpuid_CPUIdApp.c“) für den oben generierten Header. Unten sehen Sie den Quellcode:

Wir rufen den nativen Code cpuid_parse auf und geben den geparsten Puffer als JNI-String zurück. Jetzt können wir den nativen Code mit dem x86-NDK-Toolset kompilieren.

4. Erstellen von nativem Code für x86 mit dem NDK

Weitere Informationen zur Installation und Verwendung des NDK für die IA finden Sie auf der Intel-Website in der Android-Community (http://software.intel.com/de-de/android/articles/android-ndk-for-intel-architecture).

Das Android-NDK-Toolset verwendet ein Build-System, für das im Projektordner „jni“ das angepasste Android-spezifische Makefile „Android.mk“ abgelegt sein muss, um nativen Code zu kompilieren. Android.mk spezifiziert alle nativen C/C++-Quelldateien, die kompiliert werden sollen, sowie die Header und den Build-Typ (z. B. shared_library).

Unten sehen Sie das für den nativen Code benötigte Android-Makefile unseres Projekts („jni/Android.mk“).

Hierbei handelt es sich um ein einfaches Szenario mit zwei C-Quelldateien, das die Erstellung einer freigegebenen Bibliothek spezifiziert.

Wir können nun mit „ndk-build APP_ABI=x86“ unseren nativen Code erstellen und die freigegebene Bibliothek generieren. Das Android-Build-System umfasst ein weiteres Makefile („Application.mk“), in dem sich zusätzliche Konfigurationsoptionen angeben lassen. So können wir beispielsweise alle unterstützten ABIs in der Datei Application.mk angeben. Mit ndk-build werden dann native freigegebene Bibliotheken für alle Zielarchitekturen erzeugt.

Der Screenshot oben zeigt, dass der native Code für x86 erfolgreich kompiliert wurde und gibt die generierte und installierte freigegebene Bibliothek an. Jetzt können wir unsere Android-App neu erstellen und auf dem x86-Emulator bzw. Zielgerät installieren bzw. ausführen.

5. Neuerstellung, Installation und Ausführung der für die IA konzipierten Android-NDK-App

Mit „ant debug clean“ können wir unsere alten Build-Dateien leeren und mit einem erneuten „ant debug“ einen kompletten Rebuild des Android-Projekts starten. Mit „adb“ können Sie die App auf dem Zielgerät bzw. x86-Emulator neu installieren (siehe Screenshot unten).

Der Screenshot unten zeigt das App-Symbol innerhalb des x86-Emulators und das Ergebnis der Ausführung der App innerhalb des x86-Emulators.

Wir haben erfolgreich eine NDK-basierte Android-App von Anfang bis Ende erstellt.

Portieren bestehender NDK-Apps auf IA-basierte Geräte mit dem x86-NDK-Toolset

Android-Apps mit nativem Code haben in der Regel eine Standardprojektstruktur, wobei der Ordner „jni“ die nativen Quellen und die zugehörigen Android.mk/Application.mk-Build-Dateien enthält. Im vorherigen Abschnitt haben wir ein einfaches Beispiel mit nativem Quellcode und der zugehörigen Datei Android.mk gesehen.

Mit dem Android-NDK-Toolset können wir alle Ziel-ABIs in Application.mk auf einmal angeben und die nativen freigegebenen Bibliotheken für alle Ziele automatisch generieren. Das Android-Build-System paketiert automatisch alle nativen Zielbibliotheken innerhalb des Android-Package-Managers. Während der Installation wird der APK nur die der Zielarchitektur entsprechende native Bibliothek installieren.

Wir können „ndk-build“ aufrufen oder in Application.mk Folgendes angeben:

APP_ABI := all

ODER

APP_ABI := armeabi armeabi-v7a x86

Weitere Informationen siehe http://developer.android.com/sdk/ndk/index.html.

Die Änderungen, die erforderlich sind, um eine bestehende Android-App mit nativem Code, die derzeit nicht für x86 konzipiert ist, für die IA zu portieren, sind – wie oben beschrieben – in den meisten Fällen unkompliziert; es sei denn, die App verwendet architekturspezifische Assembly-Sprache oder Konstrukte. Darüber hinaus können weitere Probleme mit der Speicherausrichtung oder der Verwendung plattformspezifischer Befehle auftreten. Weitere Informationen siehe /de-de/android/articles/ndk-android-application-porting-methodologies.

Zusammenfassung

Dieser Artikel beschäftigte sich mit dem Erstellen und Portieren NDK-basierter Android-Apps für IA-Zielgeräte. Das Erstellen einer NDK-basierten App, die auf die IA ausgelegt ist, wurde von Anfang bis Ende schrittweise erläutert. Darüber hinaus wurden auch einfache Vorgehensweisen zur Portierung bestehender NDK-basierter Android-Apps auf IA-Zielgeräte mit dem NDK-Toolset angesprochen.

Hinweise

Intel ist eine Marke der Intel Corporation in den USA und anderen Ländern.

DIE INFORMATIONEN IN DIESEM DOKUMENT WERDEN IN ZUSAMMENHANG MIT INTEL® PRODUKTEN BEREITGESTELLT. DURCH DIESES DOKUMENT WERDEN WEDER AUSDRÜCKLICH NOCH KONKLUDENT ODER AUF ANDERE WEISE IRGENDWELCHE RECHTE AN GEISTIGEM EIGENTUM GEWÄHRT. MIT AUSNAHME DER FÜR DEN VERKAUF DIESER PRODUKTE IN DEN GESCHÄFTSBEDINGUNGEN VON INTEL DARGELEGTEN ANGABEN ÜBERNIMMT INTEL KEINE HAFTUNG. INTEL SCHLIESST IM ZUSAMMENHANG MIT DEM VERKAUF UND/ODER DER VERWENDUNG VON INTEL® PRODUKTEN JEDE AUSDRÜCKLICHE ODER STILLSCHWEIGENDE HAFTUNG ODER GARANTIE AUS, EINSCHLIESSLICH DER HAFTUNG BZW. GARANTIE IN BEZUG AUF DIE EIGNUNG FÜR EINEN BESTIMMTEN ZWECK, DIE HANDELSÜBLICHKEIT ODER DIE VERLETZUNG VON PATENTEN, URHEBERRECHTEN ODER ANDEREN RECHTEN AUF GEISTIGES EIGENTUM.

„Unternehmenskritische Anwendungen“ sind in diesem Kontext Anwendungen, bei denen die Fehlfunktion des Intel® Produkts in direkter oder indirekter Weise zu Personenschäden oder dem Tod führen könnte. SOLLTEN SIE INTEL® PRODUKTE FÜR UNTERNEHMENSKRITISCHE ANWENDUNGEN KAUFEN ODER VERWENDEN, VERPFLICHTEN SIE SICH, DASS SIE INTEL UND SEINE TOCHTERUNTERNEHMEN, SUBUNTERNEHMEN UND ANGESCHLOSSENEN UNTERNEHMEN BEZÜGLICH ALLER SCHÄDEN, AUFWENDUNGEN UND ANGEMESSENEN ANWALTSKOSTEN, DIE SICH DIREKT ODER INDIREKT AUS EINEM ANSPRUCH AUF PRODUKTHAFTUNG, PERSONENSCHÄDEN ODER TOD ERGEBEN UND IN VERBINDUNG MIT DER UNTERNEHMENSKRITISCHEN ANWENDUNG STEHEN, ENTLASTEN UND SCHADLOS HALTEN, SELBST WENN INTEL ODER SEINE SUBUNTERNEHMEN BEIM DESIGN, DER HERSTELLUNG ODER DEN WARNHINWEISEN DIESES INTEL® PRODUKTS FAHRLÄSSIG GEHANDELT HABEN.

Intel behält sich das Recht vor, Spezifikationen und Produktbeschreibungen jederzeit ohne vorherige Ankündigung zu ändern. Entwickler dürfen nicht vom Vorhandensein oder Nichtvorhandensein bestimmter Funktionsmerkmale oder Produkteigenschaften, die als „reserved“ oder als „undefined“ gekennzeichnet sind, ausgehen. Intel behält sich eine künftige Definition derselben vor und lehnt jegliche Haftung hinsichtlich Inkompatibilität bzw. anderer Konflikte, die sich aus künftigen Änderungen dieser Merkmale ergeben, ab. Die hier angegebene Information kann sich jederzeit ohne besondere Mitteilung ändern. Nutzen Sie diese Angaben nicht für die Fertigstellung von Designs.

Die in diesem Dokument beschriebenen Produkte können konstruktionsbedingte Defekte oder Fehler (Errata) enthalten, die zu Abweichungen der Produkteigenschaften von den angegebenen Spezifikationen führen. Eine Liste derzeit bekannter Errata ist auf Anfrage erhältlich.

Wenden Sie sich an Ihr zuständiges Vertriebsbüro von Intel oder an Ihren Distributor, um die neuesten Spezifikationen zu erhalten, bevor Sie Produkte bestellen.

Dokumente, die eine Bestellnummer haben und auf die in diesem Dokument Bezug genommen wird bzw. weitere Literatur von Intel erhalten Sie im Internet unter http://www.intel.com/design/literature.htm. *Andere Marken oder Produktnamen sind Eigentum der jeweiligen Inhaber.

Copyright © 2012 Intel Corporation. Alle Rechte vorbehalten.

Einzelheiten zur Compiler-Optimierung finden Sie in unserem Optimierungshinweis.