Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 738 – Hinzufügen von Android als unterstützte Plattform

Autor:
Malcolm Smith <smith at chaquo.com>
Sponsor:
Petr Viktorin <encukou at gmail.com>
Discussions-To:
Discourse thread
Status:
Final
Typ:
Standards Track
Erstellt:
12. Dez. 2023
Python-Version:
3.13
Resolution:
Discourse-Nachricht

Inhaltsverzeichnis

Wichtig

Diese PEP ist ein historisches Dokument. Die aktuellste, kanonische Dokumentation finden Sie jetzt unter Python unter Android verwenden.

×

Siehe PEP 1, um Änderungen vorzuschlagen.

Zusammenfassung

Diese PEP schlägt vor, Android als unterstützte Plattform in CPython aufzunehmen. Das anfängliche Ziel ist, dass Android in Python 3.13 den Tier-3-Support erreicht.

Diese PEP basiert auf PEP 730 – „Hinzufügen von iOS als unterstützte Plattform“ von Russell Keith-Magee und deckt viele der gleichen Themen ab. Bemerkenswerte Unterschiede zwischen den beiden Plattformen finden Sie, wenn Sie nach dem Wort „iOS“ suchen.

Motivation

In den letzten 15 Jahren sind mobile Plattformen zu immer wichtigeren Teilen der Computerlandschaft geworden. Android ist das Betriebssystem, das auf etwa 70 % dieser Geräte läuft. Es gibt jedoch keine offizielle Unterstützung für Android in CPython.

Die Projekte Chaquopy, BeeWare und Kivy unterstützen Android seit vielen Jahren, und alle wurden verwendet, um Anwendungen zu generieren, die für die Veröffentlichung im Google Play Store akzeptiert wurden. Dies demonstriert die technische Machbarkeit der Android-Unterstützung.

Für die Zukunft von Python als Sprache ist es wichtig, dass es auf jeder Plattform eingesetzt werden kann, die weit verbreitet ist. Andernfalls werden potenzielle Benutzer andere Sprachen wählen, die eine Unterstützung für diese Plattformen *anbieten*. Dies gilt insbesondere im Bildungsbereich, wo die nächste Entwicklergeneration in vielen Fällen bereits mehr Zeit auf mobilen Plattformen als auf Desktops verbringt.

Begründung

Allgemein

Android ist im Grunde eine POSIX-Plattform, die auf einem Linux-Kernel und dem ELF-Binärformat basiert. Es verwendet nicht glibc, sondern stellt seine eigene C-Bibliotheksimplementierung namens Bionic bereit. Infolgedessen ist es im Allgemeinen nicht binärkompatibel mit einer anderen Linux-Distribution, auch wenn die Architektur übereinstimmt. Es hat auch ein eigenes Dateisystemlayout, das keinem anderen Unix ähnelt.

Die Quellcode-Kompatibilität von Android mit Linux ist jedoch recht gut. In seinen frühen Jahren war die C-Bibliothek sehr unvollständig, aber die meisten Lücken wurden um 2014 geschlossen. Seitdem kann jeder C-Code, der für Linux kompiliert wird, normalerweise auch für Android kompiliert werden, es sei denn, er beinhaltet direkten Zugriff auf Hardwaregeräte oder Betriebssystemdienste.

Dies gilt auch für CPython. Obwohl es Android noch nie offiziell unterstützt hat, können neuere Versionen (seit 3.6) bereits mit minimalen Patches für Android kompiliert werden.

Betriebssystemversionen

Jede Android-Version kann auf drei Arten identifiziert werden

  • Eine herkömmliche Punkt-Versionsnummer (obwohl neuere Versionen durchgängig ganze Zahlen verwenden)
  • Eine sequenzielle Ganzzahl „API-Level“ (die häufigste Form in Entwicklerdokumentationen)
  • Ein alphabethischer Codename mit Süßwaren-Thema (wird nicht mehr für Marketingzwecke verwendet, erscheint aber immer noch in Entwicklerdokumentationen)

Es gibt kein konsistentes Muster, um eine dieser Angaben mit einer anderen zu verknüpfen; sie müssen in einer Tabelle nachgeschlagen werden.

Jedes Jahr wird eine neue Hauptversion von Android veröffentlicht, aber die Updates, die für jedes Gerät verfügbar sind, liegen vollständig in der Kontrolle seines Herstellers. Leider hören viele Hersteller lange auf, Updates an Geräte zu senden, bevor ihre Benutzer bereit sind, sie zu entsorgen. Zum Beispiel war im Oktober 2023 die älteste Android-Version, die noch Sicherheitsupdates erhielt, API-Level 30, aber laut Googles eigenen Statistiken waren nur 60 % der Geräte auf dieser Version oder neuer.

Für Python 3.13 schlagen wir daher vor, die Mindestversion von Android auf 5.0 (API-Level 21) festzulegen, die 2014 veröffentlicht wurde. Laut den obigen Statistiken würde dies 99 % der aktiven Geräte abdecken.

Entwicklungswerkzeuge

Die Android-Entwicklungswerkzeuge werden gleichermaßen auf Linux (x86_64), Windows (x86_64) und macOS (x86_64 und ARM64) unterstützt. Für CPython sind die wichtigsten Werkzeuge

  • Das NDK (Native Development Kit) enthält einen C- und C++-Compiler (clang), einen Linker (lld) und Header für alle Systembibliotheken.

    Die Binärkompatibilität zwischen Bibliotheken, die mit verschiedenen NDK-Versionen kompiliert wurden, ist im Allgemeinen sehr gut, aber für Reproduzierbarkeit wäre es am besten, wenn jede Python-Version während ihrer gesamten Lebensdauer bei einer NDK-Version bleibt. Für Python 3.13 wäre dies die aktuelle Langzeitunterstützungsversion des NDK, r26.

    Jede NDK-Version kann so konfiguriert werden, dass sie eine breite Palette von Android-Versionen unterstützt. Zum Beispiel unterstützt NDK r26 API-Level 21 bis 34. Binärdateien, die für eine ältere Android-Version kompiliert wurden, funktionieren jedoch normalerweise auf unbestimmte Zeit auf neueren Versionen weiter; Ausnahmen von dieser Regel werden nur aus Sicherheitsgründen gemacht.

  • Gradle ist das Werkzeug, das zum Erstellen vollständiger, bereitstellbarer Apps verwendet wird.
  • Der Emulator, basierend auf QEMU, ist ein simuliertes Android-Gerät, das auf einem Entwicklungsrechner läuft. Im Gegensatz zu iOS verwendet ein Emulator die gleiche ABI wie ein echtes Gerät derselben Architektur und kann dieselben Binärdateien ausführen.

Diese Werkzeuge können alle entweder über die Befehlszeile oder über die Android Studio IDE, die auf IntelliJ IDEA basiert, verwendet werden.

Architekturen

Android unterstützt derzeit 4 Architekturen. Ihre Namen, wie sie von den Android-Tools verwendet werden, sind

  • armeabi-v7a
  • arm64-v8a
  • x86
  • x86_64

Praktisch alle aktuellen physischen Geräte verwenden eine der ARM-Architekturen. x86 und x86_64 werden für die Verwendung im Emulator unterstützt.

Für Python 3.13 schlagen wir vor, dass der Tier-3-Support nur die 64-Bit-Plattformen (arm64-v8a und x86_64) abdeckt.

  • x86 wird seit 2020 nicht mehr als Entwicklungsplattform unterstützt, und seitdem wurden keine neuen Emulator-Images mehr veröffentlicht.
  • Der Anteil von armeabi-v7a an aktiven Geräten liegt jetzt bei weniger als 10 % und nimmt stetig ab.

    Es wäre auch schwieriger, dies mit einem zuverlässigen Buildbot abzudecken, da keine nativen Hosts für den Emulator verfügbar sind (ARM64-Macs verfügen nicht über Hardwareunterstützung für ARM32-Code). Obwohl die plattformübergreifende Emulation möglich ist, ist sie wesentlich langsamer und instabiler, weshalb die Emulator-Images für armeabi-v7a seit 2016 nicht mehr aktualisiert wurden.

    Es wird jedoch weiterhin für Uhren und sehr günstige Handys verwendet. Wenn dies anhält, müssen wir möglicherweise in Betracht ziehen, es in einer zukünftigen Python-Version hinzuzufügen.

Auch wenn 32-Bit-Architekturen nicht offiziell unterstützt werden, sollten keine Änderungen vorgenommen werden, die nachgelagerte Projekte behindern, die sie weiterhin erstellen möchten.

App-Lebenszyklus

Die primäre Programmiersprache in Android-Apps ist Java oder sein moderner Nachkomme Kotlin. Als solche stellt eine App keine eigene ausführbare Datei bereit. Stattdessen starten alle Apps als Java-virtuelle Maschine, die eine vom Betriebssystem bereitgestellte ausführbare Datei ausführt. Der Java-Code der App kann dann nativen Code zum Prozess hinzufügen, indem er dynamische Bibliotheken lädt und sie über JNI aufruft.

Im Gegensatz zu iOS ist das Erstellen von Unterprozessen unter Android *unterstützt*. Apps dürfen jedoch nur ausführbare Dateien an bestimmten Stellen ausführen, von denen keine zur Laufzeit beschreibbar ist. Lang laufende Unterprozesse werden offiziell nicht empfohlen und es wird nicht garantiert, dass sie in zukünftigen Android-Versionen unterstützt werden.

Android bietet zwar eine Kommandozeilen-Shell, diese ist jedoch nur für Entwickler gedacht und für den typischen Endbenutzer nicht verfügbar.

Aus diesen Gründen wird der empfohlene Weg, Python unter Android auszuführen, darin bestehen, libpython3.x.so in den Haupt-App-Prozess zu laden. Eine ausführbare Datei python3.x wird auf dieser Plattform nicht offiziell unterstützt.

Spezifikation

Arbeitsumfang

Der Schwerpunkt dieser Arbeit wird darauf liegen, ein Android-Äquivalent zum vorhandenen Windows-Embeddable-Paket zu erstellen, d. h. einen Satz kompilierter Bibliotheken, die Entwickler zu ihren Apps hinzufügen können. Kein Installer wird erforderlich sein.

Das Hinzufügen von Android als Tier-3-Plattform erfordert lediglich die Unterstützung für das Kompilieren eines Android-kompatiblen Builds aus dem ungepatchten CPython-Quellcode. Es ist nicht unbedingt erforderlich, dass offizielle Android-Artefakte auf python.org verteilt werden, obwohl diese zukünftig hinzugefügt werden könnten.

Android wird mit demselben Konfigurations- und Makefile-System wie andere POSIX-Plattformen erstellt und muss daher *auf* einer POSIX-Plattform erstellt werden. Sowohl Linux als auch macOS werden unterstützt.

Ein Gradle-Projekt wird für die Ausführung der CPython-Testsuite bereitgestellt. Es wird eine Tooling bereitgestellt, um den Prozess des Erstellens der Testsuite-App, des Startens des Emulators, des Installierens der Testsuite und der Ausführung zu automatisieren.

Verknüpfung

Aus den in App-Lebenszyklus erläuterten Gründen wird Python als dynamische Bibliothek libpython3.x.so in die App aufgenommen, die mit dlopen in eine App geladen werden kann.

Im Gegensatz zu Linux verwendet Android eine dlloaded-Bibliothek nicht implizit, um Relokationen in nachfolgend geladenen Bibliotheken aufzulösen, auch wenn RTLD_GLOBAL verwendet wird. Alle Python-Erweiterungsmodule müssen daher beim Erstellen für Android explizit gegen libpython3.x.so gelinkt werden.

Ein Erweiterungsmodul, das gegen libpython3.x.so gelinkt ist, kann nicht von einer ausführbaren Datei geladen werden, die statisch gegen libpython3.x.a gelinkt ist. Daher wird eine statische Bibliothek libpython3.x.a unter Android nicht unterstützt. Dies ist das gleiche Muster, das von CPython unter Windows verwendet wird.

Dieser Ansatz ermöglicht auch die Verwendung der Option -Wl,--no-undefined, um fehlende Symbole zur Build-Zeit zu erkennen, was eine erhebliche Zeitersparnis bedeuten kann.

Im Gegensatz zu iOS erlaubt Android das Laden von dynamischen Bibliotheken von jedem Ort, sodass ein Verzeichnisbaum, der ko-lokalisierte .py-, .pyc- und .so-Dateien enthält, von Pythons Standard-Importer verarbeitet werden kann.

Standardbibliothek

Nicht unterstützte Module

Eine Reihe von Standardbibliotheksmodulen werden unter Android nicht unterstützt, da die zugrunde liegenden C-APIs nicht verfügbar sind

  • curses und readline
  • dbm.gnu und dbm.ndbm
  • grp
  • multiprocessing – obwohl Unterprozesse im Allgemeinen erlaubt sind (siehe App-Lebenszyklus), unterstützt Android keinen Teil der System V IPC API.
  • tkinter und turtle – diese würden eine Android-Version von Tk selbst erfordern, die nicht offiziell unterstützt wird.

sys

sys.platform gibt "android" zurück. Obwohl Android auf Linux basiert, unterscheidet es sich in genügend wichtigen Punkten, dass ein separater Name gerechtfertigt ist.

Wenn die C-Level-Stdio-Streams in eine Android-App eingebettet sind, sind sie mit nichts verbunden. In diesem Modus werden sys.stdout und sys.stderr zum System- Logcat umgeleitet, das mit den Android-Entwicklungswerkzeugen angezeigt werden kann. sys.stdin gibt immer EOF zurück.

platform

Die meisten Werte, die vom Modul platform zurückgegeben werden, entsprechen denen, die von os.uname() zurückgegeben werden, mit Ausnahme von

  • platform.system() - "Android", anstelle des Standardwerts "Linux"
  • platform.release() - Android-Versionsnummer als String (z. B. "14"), anstelle der Linux-Kernel-Version

Zusätzlich wird eine Methode platform.android_ver() hinzugefügt, die ein NamedTuple mit den folgenden Elementen zurückgibt

  • release - Android-Version des Geräts als String (z. B. "14")
  • api_level - API-Level des Geräts als Integer (z. B. 34)
  • manufacturer - Hersteller des Geräts als String (z. B. "Google")
  • model - Modellname des Geräts als String (z. B. "Pixel 7")
  • device - Gerätename des Geräts als String (z. B. "panther")
  • is_emulator - True, wenn das Gerät ein Emulator ist; False, wenn es sich um ein physisches Gerät handelt.

Welcher der Felder model und device eindeutiger ist und welcher dem Marketingnamen ähnlicher ist, variiert je nach Hersteller.

os

os.uname() gibt das rohe Ergebnis eines POSIX uname()-Aufrufs zurück. Dies führt zu folgenden Werten

  • sysname - "Linux"
  • release - Die Linux-Kernel-Version (z. B. "5.10.157-android13-4-00003-gdfb1120f912b-ab10994928")

Dieser Ansatz behandelt das Modul os als „rohe“ Schnittstelle zu System-APIs und platform als höherwertige API, die allgemein nützlichere Werte liefert.

CI-Ressourcen

Da Android-Emulatoren und physische Geräte dieselbe ABI verwenden und mit identischen oder sehr ähnlichen Betriebssystem-Binärdateien geliefert werden, ist das Testen auf Emulatoren ausreichend. x86_64-Emulatoren können unter Linux, macOS oder Windows ausgeführt werden, ARM64-Emulatoren werden jedoch nur auf ARM64-Macs unterstützt.

Anaconda hat angeboten, physische Hardware für den Betrieb von Android-Buildbots bereitzustellen. Diese werden sowohl Linux x86_64- als auch macOS ARM64-Maschinen umfassen, die sowohl unterstützte Laufzeitarchitekturen als auch beide unterstützten Build-Plattformen abdecken würden.

CPython testet Tier-3-Plattformen derzeit nicht auf GitHub Actions, aber falls sich dies jemals ändert, können ihre Linux- und macOS-Runner auch Android-Emulatoren hosten. macOS ARM64-Runner sind seit Januar 2024 für alle öffentlichen Repositories kostenlos verfügbar.

Packaging

Android-Wheels verwenden Tags im Format android_<api-level>_<abi>. Zum Beispiel

  • android_21_arm64_v8a
  • android_21_x86_64

Für die Bedeutung von <api-level> siehe Betriebssystemversionen. Im Kontext des Wheel-Tags gibt es die minimale Android-Version an, die beim Kompilieren des Wheels ausgewählt wurde. Installationstools wie pip sollten dies ähnlich wie die vorhandenen macOS-Tags interpretieren, d. h. eine App mit einem Mindest-API-Level von N kann Wheels mit dem Tag API-Level N oder älter einbeziehen.

Dieses Format stammt aus dem Chaquopy-Projekt, das derzeit ein Wheel-Repository mit Tags zwischen API-Level 16 und 21 unterhält.

Sich jedoch auf eine kleine Gruppe von Android-Enthusiasten zu verlassen, um das gesamte Python-Ökosystem zu erstellen, ist keine skalierbare Lösung. Solange prominente Bibliotheken nicht routinemäßig ihre eigenen Android-Wheels veröffentlichen, wird die Fähigkeit der Community, Python unter Android zu nutzen, eingeschränkt sein.

Daher wird es notwendig sein, klar zu dokumentieren, wie Projekte Android-Builds zu ihrer CI- und Release-Tooling hinzufügen können. Das Hinzufügen von Android-Unterstützung zu Tools wie crossenv und cibuildwheel könnte eine Möglichkeit sein, dies zu erreichen.

Das Android-Wheel-Tag-Format sollte auch der Liste der von PyPI akzeptierten Tags hinzugefügt werden.

PEP 11 Update

PEP 11 wird aktualisiert, um die beiden unterstützten Android-ABIs aufzunehmen. Autoconf identifiziert sie bereits mit folgenden Triplets

  • aarch64-linux-android
  • x86_64-linux-android

Petr Viktorin wird der erste Kernteam-Ansprechpartner für diese ABIs sein.

Abwärtskompatibilität

Das Hinzufügen einer neuen Plattform führt keine Abwärtskompatibilitätsprobleme für CPython selbst mit sich. Es kann jedoch einige Abwärtskompatibilitätsprobleme für Projekte geben, die historisch CPython-Unterstützung geleistet haben (z. B. BeeWare und Kivy), wenn die endgültige Form der CPython-Patches nicht mit den historisch verwendeten Patches übereinstimmt.

Sicherheitsimplikationen

Das Hinzufügen einer neuen Plattform führt keine neuen Sicherheitsprobleme ein.

Wie man das lehrt

Die Bildungsbedürfnisse im Zusammenhang mit dieser PEP beziehen sich auf zwei Gruppen von Entwicklern.

Erstens müssen Entwickler von *Apps* wissen, wie sie Python zusammen mit ihrem eigenen Python-Code und unterstützenden Paketen in eine Android-App einbinden und wie sie diese zur Laufzeit verwenden. Die Dokumentation wird dies in ähnlicher Form wie das vorhandene Windows-Embeddable-Paket abdecken. Sie wird jedoch den meisten Entwicklern die Verwendung von höherwertigen Tools wie Briefcase, Chaquopy und Buildozer empfehlen, die alle bereits umfassende Dokumentation besitzen.

Zweitens müssen Entwickler von *Paketen* mit Binärkomponenten wissen, wie sie diese für Android erstellen und veröffentlichen (siehe Verpackung).

Referenzimplementierung

Das Chaquopy-Repository enthält einen Referenz-Patch und Build-Skripte. Diese müssen von den anderen Komponenten von Chaquopy entkoppelt werden, bevor sie in den Hauptzweig aufgenommen werden können.

Briefcase stellt eine Referenzimplementierung für Code zur Ausführung von Testsuiten auf Android-Geräten und -Emulatoren bereit. Das Toga Testbed ist ein Beispiel für eine Testsuite, die mithilfe von GitHub Actions auf dem Android-Emulator ausgeführt wird.

Abgelehnte Ideen

Die folgenden Änderungen wurden an der ursprünglichen Spezifikation von platform.android_ver() vorgenommen

  • Das Feld min_api_level wurde entfernt, da es im Gegensatz zu allen anderen Feldern keine Eigenschaft des aktuellen Geräts ist. Diese Information ist weiterhin über die vorab vorhandene Funktion sys.getandroidapilevel() verfügbar.
  • Das Feld is_emulator wurde hinzugefügt, da sich während des Testens herausstellte, dass einige Probleme emulator-spezifisch waren.

Quelle: https://github.com/python/peps/blob/main/peps/pep-0738.rst

Zuletzt geändert: 2024-10-07 17:43:06 GMT