Ika /ee-kah/, the Japanese word for squid or cuttlefish, began as an effort to run the Cuttlefish Android emulator on Fedora Asahi Remix. It later grew into a desktop-centric Android build for Apple Silicon and x86-64 hosts, but the name stuck.
- LineageOS 23.2 (Android 16) reimagined as a desktop-first operating system.
- Native builds for Apple Silicon and x86-64 hosts on Fedora, Debian/Ubuntu and Arch Linux. Ika runs on machines with as little as 4 GB of RAM; building it from source needs 16 GB.
- X11 and Wayland desktop sessions are both supported.
- Dynamic display window resizing that preserves DPI settings.
- GPU acceleration with support for OpenGL ES and Vulkan.
- App windows: run single Android apps in their own desktop windows, listed in your desktop's app menu; games start fullscreen with gamepad passthrough (see App windows).
- Camera: use a webcam or a Mac's FaceTime camera as Android's front camera (see Camera).
- Built-in root utility:
ika rootroots the VM with Magisk (see Rooting with Magisk). - Flexible build options for MindTheGapps, microG, or a fully de-Googled ROM without an app store.
Changes since the last published binaries are listed in CHANGELOG.md.
The Apple Silicon Vulkan memory-sharing path, including its 16 KiB-page and udmabuf handling, and the known graphics limitations are documented in GFXSTREAM-VULKAN.md. The source patches are listed in lineageos/patches/README.md.
Ika consists of two packages: an Android disk image (informally, the device ROM)
and a matching Cuttlefish virtual machine application. Prebuilt Fedora 44
(.rpm), Debian 13/Ubuntu 26.04 (.deb) and Arch Linux x86_64 (.pkg.tar.zst)
packages are available below. Select your distribution and CPU architecture, then
download the corresponding application and disk image.
Note
Debian and Ubuntu require Mesa 26.1 or newer. Get updated binaries from Debian trixie-backports or the Kisak Mesa PPA before installing the Ika packages.
| Distribution • Architecture | Application | Disk Image |
|---|---|---|
| Fedora 44 • x86_64 | ika-base (160 MB) | ika-lineageos (1.37 GB) |
| Fedora 44 • ARM64 | ika-base (155 MB) | ika-lineageos (1.36 GB) |
| Debian 13 / Ubuntu 26.04 • x86_64 | ika-base (122 MB) | ika-lineageos (1.32 GB) |
| Debian 13 / Ubuntu 26.04 • ARM64 | ika-base (107 MB) | ika-lineageos (1.29 GB) |
| Arch Linux • x86_64 | ika-base (220 MB) | ika-lineageos (1.56 GB) |
| Arch Linux • ARM64 | ./ika-build |
./ika-build |
Building requires at least 16 GB of RAM and 300 GB of storage. The first build
takes 3–6 hours or more, depending on your hardware and internet bandwidth, so
it's best left to run overnight. The ika-build script handles the prerequisite
steps and produces installable .rpm, .deb or Arch Linux packages for your
distribution. Prebuilt binaries are published for Fedora, Debian/Ubuntu and
Arch Linux x86_64; on Arch Linux ARM64, build from source.
# 1. Download and extract:
curl -L https://github.com/DesktopECHO/ika/archive/refs/heads/main.zip -o ika-main.zip
unzip ika-main.zip && rm ika-main.zip && cd ika-main
# 2. Build:
# Prepares signing certificates, installs build dependencies, downloads the
# LineageOS 23.2 source, applies the overlay and source patches, builds the
# Cuttlefish target for the host architecture, creates RPM, Debian or Arch packages,
# and prints the package installation command when the build is complete.
./ika-build
# 3. Install packages and reboot.
# Run the package installation command printed by ika-build, then reboot.
# Rebooting applies the new group memberships, limits, udev rules, and device
# permissions. Logging out is not sufficient.
sudo reboot
# 4. Launch
ika startIka requires Mesa 26.1 or newer on Debian/Ubuntu hosts (Fedora and Arch Linux
already include Mesa 26.1).
On Debian 13 (trixie), ika-build automatically enables trixie-backports
when Mesa 26.1 or newer is not already installed and installs the required Mesa
packages with explicit package/trixie-backports selectors, following the
Debian Backports instructions.
On Ubuntu-family hosts, ika-build offers to enable ppa:kisak/kisak-mesa
with add-apt-repository, then installs the Mesa packages from Kisak. Set
UBUNTU_ENABLE_KISAK_MESA=true for an unattended build. See the
Kisak Mesa PPA instructions.
Debian trixie also requires Vulkan loader 1.4.341. On trixie only, ika-build
builds that loader from the pinned Debian Salsa packaging source.
After the initial build, use the narrowest command that matches your changes:
- Full build — re-run
./ika-build, then run the installation command it prints. By default it builds the host's native ROM; passall,arm64orx86_64to choose the targets, and--microgor--mtgto choose the Google integration, for example./ika-build all --mtg. With no arguments,ika-buildasks whether to use microG, MindTheGapps, or a de-Googled image without an app store. - ROM only — re-run
./lineageos/scripts/build_lineageos_desktop.sh(or passarm64/x86_64to limit it to one target). Use this after editing patches or overlays underlineageos/. PassRESET_PATCHED_PROJECTS=1if you want patched source projects in the workspace reset before re-applying. - Host packages only — re-run
./tools/buildutils/build_packages.sh. Use this after editing host sources underbase/orfrontend/, after editing the package metadata underbase/rpm/,base/debian/,frontend/rpm/, orfrontend/debian/, or whenever you've finished a fresh ROM rebuild and want to repackageika-lineageoswith the new contents. Install the outputs directly with your distribution's package manager.
See lineageos/README.md for ROM build options: provider selection, target subsets, microG release pinning, native-bridge sources and workspace overrides.
The clock at the top left of the console window is also a hot corner. Click and hold it to move the console window. If the window is maximized or fullscreen, click it once to return to windowed mode.
Drag the window to the left or right edge of the screen to fill half of the desktop, or drag it to the top edge to maximize the window.
Super (Command) + F switches fullscreen mode on and off.
Super (Command) + T switches the title bar on and off.
Without a title bar, resize the console by dragging just outside its edges: the window keeps an invisible 4-pixel margin for that, so the edge of the Android desktop stays clickable. While a window is resized, its last complete picture is stretched and blurred until Android has drawn the new size.
After the packages are installed, ika is available on your PATH. Use it to
start, stop, and restart the packaged Cuttlefish environment. Right-click the
Ika icon in the dock or app menu for Stop Ika, Restart Ika and
Start with Camera.
# Start a windowed VM
ika start
# Check whether the VM is running
ika status
# Stop the VM
ika stop
# Factory reset the VM and clear instance state
ika reset
# Restart with new launch arguments
ika restart --gpu_mode=gfxstream --cpus=8 --memory_mb=8192
# Explicitly force the GLES+Vulkan context set in direct gfxstream mode
ika restart --gpu_mode=gfxstream --gfxstream_vulkan=on
# Factory reset and use a 128 GB userdata image on the next start
ika reset --data_gb=128
# Root the VM with Magisk; the first time, this factory-resets the VM and
# unlocks its bootloader, after asking to confirm
ika root
# Print the GSF ID, copy it and open Google's uncertified device page
ika gsf
# Game mode: start Ika fullscreen, passing the gamepad, keyboard and mouse
# through as HID devices
ika start --game
# Use the host's camera as Android's camera (auto-detected, or a given node)
ika restart --camera
ika restart --camera=video2
# List launchable apps (open app windows in bold), open one in its own
# window by label or package name, close it
ika app
ika app Asphalt 8 --game
ika app com.android.settings
ika app --info Chromium
ika app close Asphalt 8
# Sync the Android apps into the desktop's app menu now (ika start keeps
# it in sync automatically), or remove them and turn that off
ika app sync
ika app sync --remove
# Show the built-in usage text
ika help--camera passes a host camera to Android as its front camera (crosvm
virtio-media, served by Android's external camera HAL):
ika start --camera(orika restart --camera) uses the first video capture device that offers MJPEG, NV12 or YUYV: USB webcams, the FaceTime camera of Apple Silicon Macs on an Asahi kernel (apple-isp), and that of Intel Macs (UVC on 2011-2012 and T2 models,facetimehdon 2013-2017 models). Metadata nodes, such as the second node of a UVC webcam, are skipped, and virtual cameras (v4l2loopback, vivid) are used only when there is no other.--camera=video2or--camera=/dev/video2picks a device;v4l2-ctl --list-deviceslists them.- The camera is attached when Android starts:
ika start --camerarefuses while it runs, so useika restart --camerathen. It is used until the nextika startorika restartwithout--camera. It needs thevideogroup, and while Android streams from it, other programs on the host can't.
ika root roots the VM with Magisk.
It works on user and userdebug builds and needs nothing else installed. If
the VM is not running, it is started first.
- The first time,
ika rootfactory-resets the VM and unlocks its bootloader, after asking to confirm. Unlocking changes the keys that encrypt Android's data, so the data cannot be kept, just as when a phone's bootloader is unlocked. - It downloads the latest Magisk release from GitHub into
~/ika(again only when a newer one is out), patches Android'sinit_bootimage with Magisk's own patcher, flashes it from the bootloader and finishes Magisk's setup. The VM reboots a few times along the way. - Afterwards
adb shell suworks without a prompt, the Magisk app is installed and Android's developer options are enabled. - Running
ika rootagain on a rooted VM keeps its data and updates Magisk to the latest release. ika resetundoes it: it relocks the bootloader and returns the VM to stock Android.
Ika is not Play Protect certified, so Google may block signing in to Google Play, showing a "Device is not Play Protect certified" notification. Many devices never see this. If yours does, register its Google Services Framework (GSF) ID with your Google account:
- Run
ika gsf. It copies the ID to the clipboard (withwl-copy,xcliporxsel), prints it and opens google.com/android/uncertified in the default browser. If the VM is not running, it is started first. - Paste the ID on that page and register it.
- Wait a few minutes, then run
ika restart.
Registering lifts the sign-in block only. The device stays uncertified, so
apps that check Play Integrity still fail. A factory reset (ika reset, or
rooting for the first time) gives the device a new ID, which has to be
registered again. ika gsf needs Google Play Services, so it works on
MindTheGapps builds only.
With the VM running, ika app PACKAGE opens a single app in its own
resizable window with a normal title bar, separate from the desktop console.
Each window is backed by its own Android virtual display that follows the
window size, so resizing the window gives the app more room rather than
stretching it. Super + T and Super + F work as they do in the console.
- The app is restarted on the new display if it was already running on the desktop, and closing the window closes the app.
- Apps can be named by package or by the label shown by
ika app. Labels match case-insensitively, exactly or by a unique part (ika app settiopens Settings), and need no quotes when they contain spaces. An ambiguous name lists the matching apps instead of guessing. - Some apps are hidden from
ika app, name matching and the menu: Android Switch, the Google search app, Calculator, Calendar, Clock, Contacts, Recorder and AudioFX. SeeIKA_HIDDEN_APPSintools/ika. They still open when given by full package name. - The window title is the app's label; override it with
--title=TEXT. Window size is remembered per app under~/ika/apps/PACKAGE/;--size=WxHsets it explicitly. --gameenables UHID gamepad, keyboard and mouse input without forcing fullscreen; add-ffor fullscreen.- Games (apps that declare
android:appCategory="game", or are listed inIKA_GAME_APPSintools/ika) start in a game session instead of an app window: the console switches to fullscreen game mode (gamepad, keyboard and mouse passthrough, raw frames rather than encoded video) and the game runs fullscreen on Android's primary display. Leaving fullscreen or closing that window ends the session: the window closes, and the game is sent to the background (Home, where it saves its state), so the Android desktop is in front the next time you open Ika; starting the game again resumes it where you left it. The desktop console comes back if it was open before. As on a phone, Android may still reclaim a backgrounded game, which then starts fresh. Starting another game replaces the current one.ika app NAME --windowopens a game in its own window instead. Only games started withika app(or from the menu) behave this way;ika start --gameand games opened inside the Android desktop are unaffected. - Touch input (
ika app NAME --touch) is for games that ignore the mouse. Left-button clicks and drags are sent to Android as a real finger on a touchscreen instead of as mouse input, so a drag is a swipe. The right and middle buttons and the wheel stay mouse input, Ctrl or Shift with the left button still simulates a pinch, and no hover is sent. In a game session the mouse leaves UHID (the gamepad and keyboard still pass through as HID devices), and a session already running in the other input mode is restarted when you start a game in the new one.--touchworks with app windows too, andIKA_TOUCH=1 ika start --gamedoes the same for the console. Most desktop apps should not use it: some route mouse clicks differently from touch, for example Chromium's tab strip. - App windows stream encoded H.264 video from the guest rather than the
console's raw frames, which costs guest CPU time. Set
IKA_APP_BIT_RATE(default80M) to trade quality for bandwidth.IKA_APP_CODEC_OPTIONS(defaultvideo-qp-max:int=18) caps the encoder's quantizer to keep text sharp; set it empty to remove the cap. Where the host's VA-API driver decodes H.264 (Intel GPUs, for example), the video is decoded on the GPU; otherwise in software. ika app syncadds every launchable app to the desktop's app menu, as "🎮 ∙ LABEL" for games (apps declaringandroid:appCategory="game", or listed inIKA_GAME_APPSintools/ika) and "ᗩ ∙ LABEL" for other apps, in an "Android Apps (Ika)" group: a folder in the GNOME app grid, or a submenu on KDE Plasma, XFCE, Cinnamon and MATE. Launchers are~/.local/share/applications/ika-PACKAGE.desktopand are named after the app window's ID, so the dock and task switcher show an open app window under its launcher. Each launcher gets the app's own icon, rendered by Android so adaptive icons look as they do in the Ika launcher, and stored in~/ika/apps/icons/. Edits you make to a launcher are kept unless the app's label or icon changes.- Menu entries work while Ika is stopped:
ika appthen starts the VM without the desktop console (ika start --no-console) and opens the app once Android has booted. Launched from a menu,ika appreports progress and errors as desktop notifications. - Right-click a menu entry for App Settings, which opens the app's
Android App info page (permissions, storage, force stop, uninstall) in the
Settings window. From a terminal:
ika app --info NAME. The entries of games also offer Play with Touch Input, which runsika app --touch PACKAGE. - The menu is kept up to date automatically: once the guest has booted,
ika startruns a background watcher that syncs the menu and then checks every few seconds (IKA_APP_MENU_POLL_SEC, default 5) for installed, updated, removed, enabled or disabled apps. It logs to~/ika/app-menu.logand stops with the VM.ika app syncforces a sync.ika app sync --removedeletes the launchers and the group and turns the automatic sync off untilika app syncis run again.ika resetremoves the entries too, since a factory reset removes the apps; the nextika startrebuilds the menu. ika startleaves app windows open;ika stop,resetandrestartclose them.
ika start and ika restart pass extra arguments directly to
cvd_internal_start, so you can override launch settings on the command line.
ika stop calls the matching low-level stop helper and then cleans up local
Cuttlefish processes. ika reset is the destructive variant: it passes
--clear_instance_dirs, removes the local Chromium-install stamp, relocks the
bootloader and removes root.
Default ika settings and configuration:
- host tools from
/usr/lib/cuttlefish-common - the packaged LineageOS tree from
/usr/share/cuttlefish-common/lineageos - instance state under
~/ika - ~64 GB thin-provisioned ext4 userdata image
- Chromium installed as the default browser on new devices
- guest vCPUs set to the available/performance-core count minus two, capped at 12
- guest RAM set to one quarter of host RAM, capped at 32 GB
- Ethernet-only guest networking by default; Wi-Fi, Bluetooth, NFC, UWB, GNSS, and the modem simulator remain off unless explicitly enabled
gfxstream_guest_angle is the default GPU mode. It runs guest OpenGL ES through
Android ANGLE over gfxstream Vulkan. If the host only has llvmpipe, ika uses
gfxstream instead, which is much lighter on the CPU. Passing --gpu_mode
overrides this. See GFXSTREAM.md for a comparison. Use
gfxstream_guest_angle for games and Vulkan/CTS; mixed gfxstream mode does
not support data-buffer AHardwareBuffers. Program-binary caching stays disabled
because it corrupts rendering in some games. On RADV hosts, ika adds
syncshaders to RADV_DEBUG for gfxstream modes. This prevents asynchronous
host shader compilation from intermittently executing incomplete
transform-feedback pipelines; existing caller-provided RADV_DEBUG options are
retained. Other Vulkan drivers are unchanged.
Pass --data_gb=128 to ika reset to choose the size, in decimal gigabytes,
of newly created userdata. The selected size is stored under ~/ika and takes
effect on the next ika start. It remains the configured size for later factory
resets until changed by another ika reset --data_gb=....
The --gfxstream_vulkan switch controls the optional Vulkan context only when
--gpu_mode=gfxstream is selected. It has no effect with the default
gfxstream_guest_angle mode because that path requires Vulkan.
ika start --gpu_mode=gfxstream --gfxstream_vulkan=auto
ika restart --gpu_mode=gfxstream --gfxstream_vulkan=off
ika restart --gpu_mode=gfxstream --gfxstream_vulkan=onauto is the default. When the primary host Vulkan device is llvmpipe, auto
requests GLES-only gfxstream (gfxstream-gles:gfxstream-composer). On Apple
Silicon hosts with 16 KiB pages, auto leaves Cuttlefish's normal GLES+Vulkan
selection in place and routes host-visible guest Vulkan memory through the
udmabuf-backed path the Apple GPU supports. On other hosts, auto leaves the
normal Cuttlefish gfxstream defaults alone, so systems with hardware Vulkan keep
Vulkan enabled.
Use --gfxstream_vulkan=on to re-enable gfxstream Vulkan for testing, or
--gfxstream_vulkan=off to force GLES-only gfxstream. The same policy can be
set with GFXSTREAM_VULKAN=auto|off|on; an explicit
--gpu_context_types=... argument takes precedence.
In direct gfxstream mode, the guest advertises OpenGL ES 3.2, including
ANDROID_EMU_gles_max_version_3_2, with fallback to ES 3.1, 3.0, and 2.0 when
the host translator cannot provide 3.2. Vulkan remains the preferred accelerated
API for applications that support it.
The repository builds the host package names listed below. On RPM distributions,
outputs land under rpmbuild/RPMS/; on Debian-family distributions, outputs
land under deb/. Non-primary packages are moved into an extras/
subdirectory by tools/buildutils/build_packages.sh.
ika-base— Core host binaries, networking helpers, system services, and scrcpy-based virtual console used by theikalauncherika-lineageos— Bundledlineageos/tree installed under/usr/share/cuttlefish-common/lineageosika-user— Browser-facing operator serviceika-orchestration— Host Orchestrator service and nginx configurationika-integration— Cloud-integration utilitiesika-defaults— Optional defaults-override service and configurationika-metrics— Metrics transmitter binaryika-common— Compatibility metapackage for the primary host packages
Most users need only ika-base and ika-lineageos.
On ARM64 Asahi Linux, this fork uses gfxstream-backed acceleration. The default
gfxstream_guest_angle mode uses guest ANGLE over gfxstream Vulkan, while the
auto policy for direct gfxstream mode keeps Cuttlefish's GLES and Vulkan
contexts enabled on Apple Silicon hosts with 16 KiB pages and applies the
required udmabuf-backed external-memory path. guest_swiftshader remains a
fallback for isolating host GPU issues.
ika expects your login session to be in kvm, cvdnetwork, render, and
video. The ika-base package adds the installing user to these groups during
package configuration, but the active session, its PAM resource limits, and the
live /dev/kvm udev permissions don't pick up the new state without a
reboot—see step 3 under Build Ika from Source for the
full list of deferred changes.
Bazel is installed automatically through Bazelisk by ./ika-build, which runs
tools/buildutils/installbazel.sh during
the dependency step. That step,
tools/buildutils/lib/dependencies.sh,
installs the main build dependencies near the start of a build. The signing-key
bootstrap may first install its smaller certificate toolset if needed. The
standalone build scripts
(build_lineageos_desktop.sh, build_packages.sh) assume dependencies are
already installed and fail fast when one is missing.
The networking helper uses nftables exclusively—both the host-side
bridge/NAT setup in cuttlefish-host-resources.sh and the per-user
cvdalloc daemon manage their rules via native nft commands against a
shared ip cuttlefish table. iptables (and iptables-nft) and ebtables
are no longer runtime dependencies.