
Diese Geschichte handelt von einem nicht standardmäßigen Ansatz für die Entwicklung von Android-Anwendungen. Es ist eine Sache, Android Studio zu installieren und "Hello, World" in Java oder Kotlin zu schreiben. Aber ich werde zeigen, wie dieselbe Aufgabe unterschiedlich ausgeführt werden kann.
Wir erinnern Sie daran: Für alle Leser von „Habr“ - ein Rabatt von 10.000 Rubel bei der Anmeldung für einen Skillbox-Kurs mit dem Promo-Code „Habr“.
Skillbox empfiehlt: Der Online-Schulungskurs "Profession Java-Entwickler" .
Wie funktioniert mein Smartphone mit Android OS?
Zunächst ein kleiner Hintergrund. Eines Abends rief mich eine Freundin namens Ariella an. Sie fragte mich: „Hören Sie, wie funktioniert mein Smartphone? Was ist drin? Wie funktioniert alles mit elektrischer Energie und gewöhnlichen Einheiten und Nullen? “
Meine Bekanntschaft ist kein Neuling in der Entwicklung, sie hat mehrere Projekte auf Arduino erstellt, die sowohl aus Software als auch aus Hardware bestanden. Vielleicht wollte sie deshalb mehr wissen. Ich habe es geschafft, mit Hilfe von Kenntnissen zu antworten, die ich in einem der Informatikkurse an der Universität erworben habe.
Dann haben wir ein paar Wochen zusammengearbeitet, als Ariella herausfinden wollte, wie die Bausteine der elektronischen Technologie funktionieren, dh Halbleiterelemente, einschließlich Transistoren. Als nächstes gingen wir zu einer höheren Ebene: Ich zeigte ihr, wie man Logikgatter erstellt, zum Beispiel NAND (logisches UND) plus NOR (logisches ODER) unter Verwendung einer bestimmten Kombination von Transistoren.
Wir haben logische Elemente verschiedener Typen untersucht und sie kombiniert, um Berechnungen (z. B. Hinzufügen von zwei Binärzahlen) und Speicherzellen (Trigger) durchzuführen. Als alles klar wurde, begannen sie, einen einfachen Prozessor (imaginär) zu entwickeln, in dem es zwei Allzweckregister und zwei einfache Anweisungen gab (Hinzufügen dieser Register). Wir haben sogar ein einfaches Programm geschrieben, das diese beiden Zahlen multipliziert.
Wenn Sie sich für dieses Thema interessieren, lesen Sie übrigens die Anweisungen zum Erstellen eines 8-Bit-Computers von Grund auf neu. Es erklärt fast alles von den Grundlagen. Ich wünschte, ich hätte es früher gelesen!
Hallo Android!
Nachdem ich alle Phasen der Studie abgeschlossen hatte, schien es mir, dass Ariella genug Wissen hatte, um zu verstehen, wie der Smartphone-Prozessor funktioniert. Ihr Smartphone ist das Galaxy S6 Edge, dessen Basis die ARM-Architektur ist (wie bei den meisten Smartphones auch). Wir haben beschlossen, eine "Hello, World" -Anwendung für Android zu schreiben, jedoch in Assemblersprache.
.text .globl _start _start: mov %r0, $1 // file descriptor number 1 (stdout) ldr %r1, =message mov %r2, $message_len mov %r7, $4 // syscall 4 (write) swi $0 mov %r0, $0 // exit status 0 (ok) mov %r7, $1 // syscall 1 (exit) swi $0 .data message: .ascii "Hello, World\n" message_len = . - message
Wenn Sie noch nie zuvor auf Assembler-Code gestoßen sind, kann dieser Block Sie erschrecken. Aber es ist okay, lassen Sie uns den Code zusammen analysieren.
Unser Programm besteht also aus zwei Teilen. Der erste ist Text mit Maschinencode-Anweisungen und der zweite sind Variablen, Zeilen und andere Informationen (beginnend mit Zeile 15). Der Textabschnitt ist normalerweise schreibgeschützt und die Daten sind auch beschreibbar.
In Zeile 2 definieren wir eine globale Funktion namens _start. Es ist der Einstiegspunkt in die Anwendung. Das Betriebssystem beginnt ab diesem Punkt mit der Ausführung des Codes. Die Funktionsdefinition wird in Zeile 4 deklariert.
Darüber hinaus führt die Funktion zwei weitere Aufgaben aus. In den Zeilen 5–9 wird die Meldung auf dem Bildschirm angezeigt, in den Zeilen 11–13 endet das Programm. Selbst wenn Sie die Zeilen 11–13 löschen, gibt das Programm unsere Zeile „Hallo Welt“ aus und beendet das Programm. Die Ausgabe ist jedoch nicht korrekt, da das Programm mit einem Fehler endet. Ohne die Zeilen 11–13 versucht die Anwendung, eine ungültige Anweisung auszuführen.
Das Drucken wird mit der Systemfunktion "Systemaufruf" des Betriebssystems angezeigt. In der Anwendung rufen wir die Funktion write () auf. Wir geben es an, wenn wir den Wert 4 mit dem Namen r7 (Zeile 8) in das Prozessorregister laden. Als nächstes wird der Befehl swi $ = 0 (Zeile 9) ausgeführt, wobei ein Übergang direkt zum Linux-Kernel erfolgt, der die Basis von Android bildet.
Die Parameter für den Systemaufruf werden über andere Register übertragen. Zum Beispiel zeigt r0 die Nummer des Dateideskriptors, den wir drucken müssen. Wir setzen dort den Wert 1 (Zeile 5) und geben die Standardausgabe (stdout) an, dh die Ausgabe auf dem Bildschirm.
r1 gibt die Speicheradresse der Daten an, die wir schreiben möchten, also laden wir einfach die Adresse der Zeichenfolge „Hello, World“ (Zeile 6) in diesen Bereich, und das Register r2 zeigt an, wie viele Bytes wir schreiben möchten. In unserem Programm wird es auf message_len (Zeile 7) gesetzt, berechnet in Zeile 18 unter Verwendung einer speziellen Syntax: Das Punktsymbol gibt die aktuelle Speicheradresse an. Aus diesem Grund. - Nachricht gibt die aktuelle Speicheradresse abzüglich der Nachrichtenadresse an. Nun, da wir message_len unmittelbar nach der Nachricht deklarieren, wird dies alles als Länge der Nachricht berechnet.
Wenn Sie den Code für die Zeilen 5–9 mit C schreiben, erhalten Sie Folgendes:
#define message "Hello, World\n" write(1, message, strlen(message));
Das Herunterfahren des Programms ist etwas einfacher. Dazu registrieren wir einfach den Exit-Code im Register r0 (Zeile 11). Danach addieren wir den Wert 1, der die Nummer des Systemfunktionsaufrufs exit () ist, zu r7 (Zeile 12) und rufen dann den Kernel erneut auf (Zeile 13).
Eine vollständige Liste der Android-Systemaufrufe und ihrer Nummern finden Sie im
Quellcode des Betriebssystems . Es gibt auch eine Implementierung von
write () und
exit () , die die entsprechenden Systemfunktionen aufrufen.
Programm zusammenstellen
Um unser Projekt zu kompilieren, benötigen Sie Android NDK (Native Development Kit). Es enthält eine Reihe von Compilern und Build-Tools für die ARM-Plattform. Sie können es von der offiziellen Website herunterladen und beispielsweise über Android Studio installieren.

Nach der Installation des NDK benötigen wir die Datei arm-linux-androideabi-as. Dies ist der Assembler für ARM. Wenn Sie über Android Studio heruntergeladen haben, suchen Sie im Android SDK-Ordner danach. Normalerweise ist sein Standort
ndk-bundle \ toolchains \ arm-linux-androideabi-4.9 \ prebuilt \ windows-x86_64 \ bin.Nachdem der Assembler gefunden wurde, speichern Sie das, was in einer Datei namens hello.s geschrieben ist, und führen Sie den folgenden Befehl aus, um es in Maschinencode zu konvertieren:
arm-linux-androideabi-as -o hallo.o hallo.sDiese Operation erstellt eine ELF-Objektdatei mit dem Namen hello.o. Rufen Sie den Linker auf, um es in eine Binärdatei zu konvertieren, die auf Ihrem Gerät funktionieren kann:
arm-linux-androideabi-ld -o hallo hallo.oJetzt haben wir eine Hallo-Datei, die ein gebrauchsfertiges Programm enthält.
Starten Sie die Anwendung auf Ihrem Gerät
Android-Anwendungen werden normalerweise im APK-Format verteilt. Dies ist eine spezielle Art von komprimierter Datei, die Java-Klassen enthält (ja, Sie können mit C / C ++ schreiben, aber Java muss der Einstiegspunkt sein).
Um Probleme beim Starten der Anwendung zu vermeiden, wurde im Beispiel adb verwendet, mit dem wir es in den temporären Ordner unseres Android-Geräts kopieren konnten. Danach starten wir die ADB-Shell, um die Anwendung zu starten und das Ergebnis auszuwerten:
adb push hallo / data / local / tmp / hallo
adb shell chmod + x / data / local / tmp / halloFühren Sie abschließend die Anwendung aus:
adb shell / data / local / tmp / halloWas schreibst du?
Jetzt haben Sie eine ähnliche Arbeitsumgebung wie Ariella. Sie verbrachte mehrere Tage damit, den ARM-Assembler zu studieren, und entwickelte dann ein einfaches Projekt - dies ist das Spiel Sven Boom (eine Variation von Fizz Buzz, ursprünglich aus Israel). Die Spieler zählen nacheinander und jedes Mal, wenn die Zahl durch 7 geteilt wird oder die Zahl 7 enthält, müssen sie „Boom“ sagen (daher der Name des Spiels).
Es ist erwähnenswert, dass das Spielprogramm keine so einfache Aufgabe ist. Ariella hat eine ganze Methode geschrieben, bei der Zahlen ziffernweise angezeigt werden. Da sie alles in Assembler geschrieben hat, ohne die Standardfunktionen der C-Bibliothek aufzurufen, dauerte die Lösung mehrere Tage.
Das erste Ariella-Programm für Adnroid finden Sie
hier . Übrigens sind einige Code-IDs in der Anwendung tatsächlich hebräische Wörter (zum Beispiel _sifra_ahrona).
Das Schreiben einer Android-Anwendung in Assembler ist eine gute Möglichkeit, die ARM-Architektur besser kennenzulernen und die innere Küche des Gadgets, das Sie täglich verwenden, besser zu verstehen. Ich schlage vor, dass Sie dies genau tun und versuchen, eine kleine Assembler-Anwendung für Ihr Gerät zu erstellen. Es könnte ein einfaches Spiel oder etwas anderes sein.
Skillbox empfiehlt: