XenDroid - RetroBIOS¶
Technical notes
Xbox 360 emulator for Android, package xendroid.compose, arm64-v8a only. Xenia Edge is vendored whole under emulator-core/src/main/cpp/xenia and a Kotlin and Compose frontend replaces the desktop front end: its own windowed app, AAudio and OpenSLES audio systems, an Android input driver, and Android providers for the guest keyboard, the message box and disc swap. The library recognises ISO, ZAR, GOD, extracted XEX folders and STFS containers, and the boot path reads the file signature before mounting. ref: emulator-core/src/main/cpp/CMakeLists.txt:30-56, 112-152, emulator-core/src/main/cpp/xendroid_emu.cpp:333-346, 671-676, app/src/main/java/xendroid/compose/data/GameFormat.kt:6, 26-32
Releases are tagged XenDroid-
No Xbox 360 system file is read. xboxkrnl, xam and xbdm are HLE modules registered at startup, the XEX1 retail, XEX2 retail and XEX2 devkit keys are constant arrays tried in turn when an image is read, and every XConfig setting is answered from cvars and constants rather than from a flash image. When the launched title is itself a system title the kernel resolves xam.xex, then $flash_xam.xex, through the guest filesystem under the \SystemRoot symlink pointing at that title's own directory. ref: emulator-core/src/main/cpp/xenia/src/xenia/emulator.cc:421-428, 757-772, emulator-core/src/main/cpp/xenia/src/xenia/cpu/xex_module.cc:55-63, 925-935, emulator-core/src/main/cpp/xenia/src/xenia/kernel/xconfig.cc:89-159
The storage root is the compose external files directory of the package and is
passed as a launch argument beside the config path and the log path. content,
cache, cache0, cache1, patches and plugins hang off it, the global
configuration is xenia-canary.config.toml and per title overrides live in
config/
479 game patches ship inside the APK, synced at build time from the xenia-canary game-patches submodule pinned at 3553a5ae. The patch database reads the patches directory only, so a bundled patch reaches the emulator once the user toggles it, which writes the asset out under the same name. ref: app/build.gradle:12-19, app/src/main/java/xendroid/compose/patches/PatchAssets.kt:17-23, app/src/main/java/xendroid/compose/patches/PatchStore.kt:23-33, emulator-core/src/main/cpp/xenia/src/xenia/patcher/patch_db.cc:34-60
ES-DE finds the emulator by the xendroid.compose/.EmulatorHostActivity package rule and hands the game over as the intent data URI. ref: app/src/main/AndroidManifest.xml:54-73, docs/frontend-integration.md
7 files | 0 required, 7 optional | 1 in repo, 6 missing
<driver>.zip optional missing
Replacement Vulkan driver package
- Source:
app/src/main/java/xendroid/compose/ui/settings/SettingRows.kt:175-200,app/src/main/java/xendroid/compose/settings/SettingsRepository.kt:34-35,app/src/main/java/xendroid/compose/settings/SettingsRepository.kt:140,emulator-core/src/main/java/xendroid/compose/Utils.java:164-236,emulator-core/src/main/java/xendroid/compose/Application.java:21-24,emulator-core/src/main/cpp/xenia/src/xenia/ui/vulkan/vulkan_instance.cc:49,emulator-core/src/main/cpp/xenia/src/xenia/ui/vulkan/vulkan_instance.cc:168-192,emulator-core/src/main/cpp/xenia/src/xenia/ui/vulkan/vulkan_instance.cc:203 - Config key:
Vulkan|vulkan_lib_path - Imported through a picker restricted to application/zip. The archive is read whole, meta.json names the library to keep, and a single .so is taken instead when no meta.json is present; the .so files and meta.json are unpacked into a directory named after the archive, in internal storage. The configured path is read before the instance is created and opened through adrenotools when the file exists, otherwise the system libvulkan.so is used. The row is hidden on devices without /dev/kgsl-3d0.
<font>.ttf optional missing
Replacement face for the overlay text
- Source:
emulator-core/src/main/cpp/xenia/src/xenia/ui/imgui_drawer.cc:39-44,emulator-core/src/main/cpp/xenia/src/xenia/ui/imgui_drawer.cc:353-366,emulator-core/src/main/cpp/xenia/src/xenia/ui/imgui_drawer.cc:367-376 - Config key:
UI|custom_font_path - Loaded when the configured path exists, over the glyph ranges the atlas is built with. A path that does not resolve, or a face that fails to build, leaves the embedded Inter face in place, so the absence is covered.
<sound>.wav optional missing
Sound played when an achievement unlocks
- Source:
emulator-core/src/main/cpp/xenia/src/xenia/ui/audio_helper.cc:21-24,emulator-core/src/main/cpp/xenia/src/xenia/ui/audio_helper.cc:38-80,emulator-core/src/main/cpp/xenia/src/xenia/ui/audio_helper.cc:97-101,emulator-core/src/main/cpp/xenia/src/xenia/kernel/xam/achievement_manager.cc:163-166,emulator-core/src/main/cpp/xenia/src/xenia/config.cc:174-190,emulator-core/src/main/cpp/xenia/src/xenia/ui/config_helpers.h:47 - Config key:
UI|achievement_sound_path - Read through miniaudio, which accepts WAV, MP3, OGG and FLAC. The engine is built the first time an achievement fires, and an empty or missing path leaves the notification silent. Config written under the older key General|notification_sound_path is carried to this cvar when the file is read, and that is the key the shipped template still carries.
<title_id> - <title>.patch.toml optional missing bundled
Memory patch set for one title
- Source:
emulator-core/src/main/cpp/xenia/src/xenia/patcher/patch_db.h:124-125,emulator-core/src/main/cpp/xenia/src/xenia/patcher/patch_db.cc:34-60,emulator-core/src/main/cpp/xenia/src/xenia/patcher/patch_db.cc:63-105,emulator-core/src/main/cpp/xenia/src/xenia/patcher/patcher.cc:22-37,emulator-core/src/main/cpp/xenia/src/xenia/emulator.cc:415 - Config key:
General|apply_patches - Read from the patches directory under the storage root, keeping names that open with eight hexadecimal digits and close with .patch.toml. The title id and title name fields and a hash node are mandatory, the file is dropped without them, and each entry of the patch array is applied only when its is_enabled flag is set and the module hash matches. Patching is on by default.
plugins.toml optional missing
Plugin manifest for one title
- Source:
emulator-core/src/main/cpp/xenia/src/xenia/patcher/plugin_loader.cc:16-21,emulator-core/src/main/cpp/xenia/src/xenia/patcher/plugin_loader.cc:27-37,emulator-core/src/main/cpp/xenia/src/xenia/patcher/plugin_loader.cc:40-56,emulator-core/src/main/cpp/xenia/src/xenia/patcher/plugin_loader.cc:58-125,emulator-core/src/main/cpp/xenia/src/xenia/emulator.cc:431-432 - Config key:
General|allow_plugins - Read from plugins/
/ under the storage root, where the directory name is eight hexadecimal digits. Each entry of the plugin array needs a hash node, and an entry without one is skipped. Plugin loading is off by default, so nothing under plugins is scanned until it is turned on.
<plugin>.xex optional missing
Plugin module named by a plugin manifest
- Source:
emulator-core/src/main/cpp/xenia/src/xenia/patcher/plugin_loader.cc:175-233,emulator-core/src/main/cpp/xenia/src/xenia/patcher/plugin_loader.cc:235-252,emulator-core/src/main/cpp/xenia/src/xenia/emulator.cc:2625-2630 - The title directory is mounted as the plugins device and each enabled entry whose hash matches the running module is loaded as a user module on its own thread.
Account optional in repo
Encrypted profile account blob
- Path:
content/<XUID>/FFFE07D1/00010000/<XUID>/Account - Source:
emulator-core/src/main/cpp/xenia/src/xenia/kernel/xam/profile_standalone.cc:24-52,emulator-core/src/main/cpp/xenia/src/xenia/kernel/xam/profile_standalone.cc:72-99,emulator-core/src/main/cpp/xenia/src/xenia/kernel/xam/profile_standalone.cc:129-141,emulator-core/src/main/cpp/xenia/src/xenia/kernel/xam/profile_manager.cc:256-296,app/src/main/java/xendroid/compose/core/ProfileBootstrap.kt:13-28,app/src/main/java/xendroid/compose/core/ProfilePaths.kt:6-13 - A 0x10 hash, an 8 byte confounder and an encrypted X_XAMACCOUNTINFO. Read from the profile directory when the content tree is enumerated and from the mounted profile when a XUID is logged in, decrypted with the retail key first and the devkit key second, against the HMAC the first sixteen bytes carry. The frontend creates one for the gamertag XenDroid on first run when the tree holds none, and writes its XUID to the slot 0 setting.
Generated on 2026-08-23T16:12:06Z