Architecture

Android runtime

Status. rustdroid runs Android apps with ltk rendering today. The permissions module, the asynchronous permission API and the per-app sandbox are designed, not built. Android apps currently receive a fixed grant list inherited from the upstream translation layer.

Eydos runs Android packages natively, without a virtual machine or a container running an Android image. The runtime is rustdroid, a fork of android_translation_layer that keeps the Android Java API surface and the embedded Android runtime, ART, but replaces the native side: the UI is drawn with ltk instead of GTK, and the JNI layer is reimplemented in Rust. Running each APK as its own Flatpak was considered and rejected; rustdroid is the single centre for Android apps.

How an app is drawn

The Android view hierarchy is the retained model. Every frame, rustdroid projects it into a fresh ltk element tree; it does not keep a parallel widget tree. Android performs its own measure and layout in Java, and the native side reads back absolute rectangles and places each view at its exact position. Standard widgets map to real ltk widgets. Views that draw themselves, and surface or GL based apps, render into a canvas exposed as a texture. WebView uses ltk-webkit. The Android looper is driven by ltk’s event loop.

Below the runtime, bionic-translation provides the shims that let Android’s C library expectations run on glibc, and art-standalone packages the runtime itself for Debian.

Permissions

Android apps go through the same permission system as everything else, with Android’s semantics preserved so the app behaves as its developers expect:

  • A catalogue maps each Android permission to its protection level, its group and the Eydos resource it corresponds to.
  • The app’s declared permissions are read from its manifest at install.
  • Undeclared permissions are denied without asking. Normal ones are granted at install. Dangerous ones are asked per group with allow, only this time and deny; two denials stop the prompts until the user changes the setting.
  • The prompt is the system consent dialog, drawn by the compositor; rustdroid draws nothing itself.
  • A single gate in the native layer is consulted by location, media, content providers, notifications and networking before they answer.
  • On the Java side, checkPermission asks the native layer, and requestPermissions becomes asynchronous and delivers its result on the looper, as on Android. shouldShowRequestPermissionRationale returns a real answer.

Decisions are stored in the shared permission store under the package name, so Settings shows Android apps next to everything else.

Files and printing

The Android intents for opening and creating documents map to the file chooser portal. The result comes back as a content URI served by a documents provider over the files the user chose, with persistable URI permissions recorded in the shared store. Printing goes through Android’s print manager, which renders to PDF and hands the document to the print portal.

Sandbox

ART and the APK’s code share rustdroid’s process. Until that process is wrapped in its own bwrap sandbox, the permission gate binds the Java API paths but not native libraries an APK may carry; well-known apps ship native code. For a well-behaved app this is consent; against a hostile one it is not a barrier. Wrapping the process is the second phase of the permissions work, and the point at which Android apps become a fully confined application class.