Menjalankan Android Virtual Device dengan RTX 3060 dan Cuttlefish di Ubuntu 24.04


Membangun Android virtual yang bisa diakses langsung dari browser sebenarnya tidak harus menggunakan emulator desktop seperti Android Studio, VNC, atau solusi cloud Android pihak ketiga.

Dalam percobaan ini, sebuah server Ubuntu 24.04 dengan NVIDIA GeForce RTX 3060 digunakan sebagai host untuk menjalankan Android 17 melalui Cuttlefish. Rendering Android diteruskan ke GPU NVIDIA menggunakan Gfxstream, kemudian tampilan dan kontrol Android dikirim ke browser menggunakan WebRTC.

Hasil akhirnya adalah sebuah Cloud Android pribadi yang dapat dikendalikan langsung dari browser, dengan resolusi 1080×1920 dan akselerasi GPU hardware.

Artikel ini mendokumentasikan proses dari persiapan GPU sampai Android berhasil tampil dan dikontrol melalui browser.


Hasil akhir

Arsitektur yang digunakan:

                         Browser
                            │
                       HTTPS / WebRTC
                            │
                            ▼
                    Cuttlefish WebRTC
                            │
                            ▼
                    Android 17 x86_64
                            │
                         Gfxstream
                            │
                            ▼
                       crosvm / KVM
                            │
                            ▼
                    NVIDIA RTX 3060

Host yang digunakan:

  • Ubuntu 24.04 LTS
  • CPU Intel dengan VT-x
  • NVIDIA GeForce RTX 3060 12 GB
  • NVIDIA Driver 610.43.02
  • Cuttlefish 1.57.0
  • Android 17
  • Display 1080×1920
  • RAM VM 8 GB
  • CPU VM 6 core
  • GPU mode gfxstream
  • WebRTC melalui port 8443

Pada tahap akhir, Android berhasil boot dan nvidia-smi menunjukkan proses crosvm menggunakan RTX 3060 dengan sekitar 163 MiB VRAM.


1. Mengapa menggunakan Cuttlefish?

Awalnya ada beberapa pendekatan yang bisa digunakan untuk membuat Android virtual di server:

  • Android Emulator
  • Redroid
  • Waydroid
  • Docker Android
  • Cuttlefish

Untuk kebutuhan seperti cloud phone yang bisa dikontrol melalui browser, Cuttlefish lebih menarik karena memang dirancang sebagai virtual device Android dan memiliki integrasi WebRTC.

AOSP menjelaskan bahwa Cuttlefish dapat diakses dari browser melalui WebRTC tanpa software tambahan di komputer client. WebRTC juga mendukung kontrol perangkat dan bahkan menyediakan ADB di dalam browser.

Arsitekturnya juga lebih cocok untuk kebutuhan GPU virtual dibanding memaksakan Android container menggunakan stack GPU host secara langsung.


2. Persiapan NVIDIA RTX 3060

Langkah pertama adalah memastikan GPU NVIDIA berjalan normal di Ubuntu.

Periksa GPU:

nvidia-smi

Pada sistem yang digunakan, hasil akhirnya menunjukkan:

NVIDIA GeForce RTX 3060
Driver Version: 610.43.02
CUDA Version: 13.3
Memory: 12288 MiB

Yang lebih penting bukan hanya nvidia-smi berhasil.

Cuttlefish membutuhkan driver host yang mendukung:

  • EGL
  • GL_KHR_surfaceless_context
  • OpenGL ES
  • Vulkan

Persyaratan tersebut memang disebutkan secara resmi oleh AOSP untuk accelerated graphics Cuttlefish.

Periksa Vulkan:

vulkaninfo --summary

Kemudian periksa EGL:

eglinfo -B

Untuk memastikan NVIDIA digunakan:

eglinfo -B 2>&1 | grep -Ei 'surfaceless|KHR_surfaceless|NVIDIA'

Yang dicari adalah renderer NVIDIA dan platform Surfaceless yang berhasil.

Dalam setup ini renderer yang terdeteksi adalah:

NVIDIA GeForce RTX 3060

dengan driver:

610.43.02

Ini merupakan bagian penting karena Cuttlefish Gfxstream akan meneruskan API grafis OpenGL dan Vulkan ke host. AOSP secara eksplisit mendokumentasikan --gpu_mode=gfxstream untuk mode accelerated graphics tersebut.


3. Memastikan virtualisasi CPU tersedia

Cuttlefish menggunakan virtualisasi hardware.

Pada CPU Intel, periksa VT-x:

grep -c -w "vmx\|svm" /proc/cpuinfo

Nilai yang bukan nol menunjukkan bahwa CPU memiliki extension virtualisasi yang diperlukan.

Kemudian periksa KVM:

ls -l /dev/kvm

Hasil yang digunakan:

crw-rw---- 1 root kvm ... /dev/kvm

AOSP juga menggunakan pemeriksaan vmx|svm sebagai salah satu langkah validasi awal Cuttlefish.


4. Instalasi Cuttlefish

Cuttlefish kemudian dipasang menggunakan paket resmi.

Repository Android Cuttlefish ditambahkan:

echo "deb https://us-apt.pkg.dev/projects/android-cuttlefish-artifacts android-cuttlefish main" \
  | sudo tee /etc/apt/sources.list.d/cuttlefish.list

Kemudian:

sudo apt update

Install:

sudo apt install -y cuttlefish-base cuttlefish-user

Tambahkan user ke group yang diperlukan:

sudo usermod -aG kvm,cvdnetwork,render $USER

Kemudian reboot:

sudo reboot

Setelah login kembali:

groups

Pastikan group berikut tersedia:

kvm
cvdnetwork
render

AOSP juga mendokumentasikan kebutuhan group kvm, cvdnetwork, dan render untuk instalasi Cuttlefish.


5. Memeriksa versi Cuttlefish

Setelah instalasi:

cvd version

Dalam setup ini:

version: 1.57.0
VCS: 9bb9c72329cedcb436bb75afc05c24d73fbcdf5d

Versi ini penting karena workflow Cuttlefish modern sudah menggunakan cvd, bukan hanya workflow lama berbasis launch_cvd.

Dokumentasi AOSP terbaru juga menggunakan cvd create untuk workflow Cuttlefish modern.


6. Mengambil Android build

Daripada melakukan build Android dari source yang membutuhkan waktu dan storage sangat besar, kita menggunakan prebuilt Android Cuttlefish image.

Buat direktori:

mkdir -p ~/cuttlefish
cd ~/cuttlefish

Kemudian gunakan:

cvd fetch \
  --target_directory="$HOME/cuttlefish" \
  --default_build="aosp-android-latest-release/aosp_cf_x86_64_only_phone-userdebug"

Cuttlefish kemudian mengambil host package dan Android image dari Android build server.

Pada setup ini build yang didapat adalah:

16102939/aosp_cf_x86_64_only_phone-userdebug

AOSP sendiri menyediakan target aosp_cf_x86_64_only_phone untuk x86_64 Cuttlefish dan menjelaskan penggunaan build host package serta device image yang sesuai.


7. Masalah penting pada host package

Pada tahap ini ditemukan masalah yang cukup spesifik.

Direktori:

/usr/lib/cuttlefish-common/bin

digunakan oleh paket Debian Cuttlefish dan berisi mekanisme substitution.

Jika direktori tersebut langsung digunakan sebagai host artifacts, proses Cuttlefish mencoba membuat temporary symlink di lokasi yang tidak dapat ditulis oleh user biasa.

Akibatnya muncul error permission:

PERMISSION_DENIED

Solusinya bukan menjalankan seluruh Cuttlefish sebagai root.

Sebaliknya, host binary disalin ke direktori kerja milik user:

cd ~/cuttlefish

cp -a bin bin.symlink-backup

rm -rf bin
mkdir bin

cp -a /usr/lib/cuttlefish-common/bin/. bin/

rm -rf ~/cuttlefish/bin.symlink-backup

Setelah itu binary menjadi milik user:

-rwxr-xr-x ... adit adit ... bin/cvd_internal_start
-rwxr-xr-x ... adit adit ... bin/cvdalloc

Dalam artikel ini nama user asli disamarkan menjadi rocky, sehingga contoh berikut menggunakan:

/home/rocky/cuttlefish

8. Membuat Android virtual machine

Setelah image dan host package tersedia, instance Cuttlefish dibuat.

Konfigurasi yang digunakan:

cd ~/cuttlefish

cvd create \
  --product_path="$HOME/cuttlefish" \
  --host_path="$HOME/cuttlefish" \
  --num_instances=1 \
  --group_name=phone01 \
  --cpus=6 \
  --memory_mb=8192 \
  --gpu_mode=gfxstream \
  --display0=width=1920,height=1200,dpi=320,refresh_rate_hz=60

Ada beberapa parameter penting di sini.

CPU

--cpus=6

Android VM mendapatkan 6 virtual CPU.

RAM

--memory_mb=8192

Android VM mendapatkan 8 GB RAM.

Resolusi

--display=width=1080,height=1920,dpi=320,refresh_rate_hz=60

Ini menghasilkan konfigurasi smartphone portrait:

1080 × 1920
60 Hz
320 DPI

GPU

Bagian paling penting:

--gpu_mode=gfxstream

AOSP menjelaskan bahwa Gfxstream meneruskan OpenGL dan Vulkan API dari guest ke host.


9. Memastikan crosvm benar-benar menggunakan Gfxstream

Setelah instance dibuat:

cvd status

Kemudian:

ps aux | grep -E 'crosvm|cvd_internal_start|qemu' | grep -v grep

Command crosvm yang dihasilkan mengandung:

--gpu=displays=[[mode=windowed[1080,1920],
dpi=[320,320],
refresh-rate=60]],
context-types=gfxstream-gles:gfxstream-vulkan:gfxstream-composer,
egl=true,
surfaceless=true,
glx=false,
gles=true

Artinya Cuttlefish memang menjalankan Gfxstream, bukan mode software rendering biasa.

Konfigurasi lengkap proses crosvm juga menunjukkan:

--mem=8192
--cpus=6

serta device display 1080×1920.


10. Memastikan Android berhasil boot

Setelah beberapa saat:

adb devices

Hasilnya:

List of devices attached
127.0.0.1:6520    device

Kemudian:

adb shell getprop sys.boot_completed

Hasil:

1

Artinya Android sudah selesai boot.

Untuk memeriksa versi Android:

adb shell getprop ro.build.version.release

Hasil:

17

Jadi instance yang berjalan adalah Android 17.


11. Memastikan RTX 3060 benar-benar digunakan

Ini merupakan salah satu pengujian terpenting.

Jalankan:

nvidia-smi

Pada hasil yang berhasil, terdapat proses:

crosvm

di daftar proses GPU:

PID     Type    Process
3758    C+G     .../host_tools/bin/crosvm

dengan penggunaan:

163 MiB

VRAM RTX 3060.

Ini jauh lebih meyakinkan daripada sekadar melihat Android berhasil boot.

Artinya jalurnya benar-benar berjalan:

Android
   ↓
Gfxstream
   ↓
crosvm
   ↓
NVIDIA driver
   ↓
RTX 3060

12. Error Gfxstream yang terlihat di log

Saat melakukan pengecekan log, terdapat beberapa pesan seperti:

HWUI: Failed to initialize 101010-2 format, error = EGL_SUCCESS

dan:

GFXSTREAM: Could not open '/dev/goldfish_pipe_dprctd'

serta:

GFXSTREAM: Both vsock and goldfish_pipe paths failed

Pesan tersebut memang terlihat sebagai E atau W di log, tetapi dalam pengujian ini Android tetap berhasil boot dan dapat ditampilkan melalui WebRTC.

Karena itu, jangan menjadikan setiap baris ERROR di log sebagai indikasi bahwa Cuttlefish gagal.

Indikator yang lebih penting adalah:

adb shell getprop sys.boot_completed

yang menghasilkan:

1

dan apakah display Android benar-benar dapat ditampilkan serta dikontrol.


13. Mengaktifkan WebRTC

Salah satu alasan Cuttlefish cocok untuk kebutuhan cloud Android adalah WebRTC.

AOSP menyediakan antarmuka browser:

https://localhost:8443

WebRTC memungkinkan virtual Android dikendalikan langsung dari browser tanpa aplikasi client tambahan.

Pada versi Cuttlefish yang digunakan, setelah cvd create, WebRTC sudah aktif dan memberikan endpoint:

https://localhost:8443

Periksa port:

ss -lntp | grep 8443

Hasil:

LISTEN 0 4 0.0.0.0:8443 0.0.0.0:* users:(("operator_proxy",pid=3681,fd=4))

Kemudian:

curl -k -I https://127.0.0.1:8443

Hasil:

HTTP/2 200
content-type: text/html; charset=utf-8

Ini memastikan operator_proxy aktif dan Web UI Cuttlefish dapat diakses.


14. Mengakses Cloud Android dari komputer lain

Karena server tidak menggunakan desktop environment untuk kebutuhan ini, cara aman untuk pengujian awal adalah SSH tunnel.

Dari komputer client:

ssh -L 8443:127.0.0.1:8443 rocky@HOST_MOONLIGHT

Kemudian buka browser:

https://localhost:8443

Jika browser menampilkan peringatan sertifikat, lanjutkan ke halaman tersebut.

Cuttlefish WebRTC akan menampilkan daftar device.

Dalam kasus ini device muncul sebagai:

phone01
└── phone01-1-1

15. Menampilkan Android di browser

Pada Web UI Cuttlefish, pilih:

phone01

kemudian:

Show All

Setelah device dipilih, panel Android akan muncul.

Hasil akhirnya menunjukkan:

phone01-1-1

Display 0
1080 × 1920

Layar Android 17 kemudian tampil langsung di browser.

Interface Cuttlefish menyediakan kontrol seperti:

  • Power
  • Back
  • Home
  • Rotation
  • Volume
  • Keyboard
  • Lock/unlock
  • Bluetooth
  • dan kontrol virtual device lainnya

Dengan demikian browser bukan hanya menerima video, tetapi juga dapat mengirim input ke Android.


16. WebRTC bukan hanya port 8443

Ada satu hal penting jika nantinya server ingin dibuka untuk akses dari jaringan lain atau internet.

Port:

8443

hanya merupakan bagian dari koneksi WebRTC.

Menurut dokumentasi resmi AOSP, WebRTC Cuttlefish juga membutuhkan:

TCP 15550–15599
UDP 15550–15599

jika client berada di mesin berbeda.

Jadi jangan berasumsi bahwa cukup melakukan reverse proxy:

https://cloud.example.com
        ↓
      :8443

lalu semua trafik WebRTC otomatis bekerja.

Untuk deployment publik, port ICE/WebRTC juga harus diperhitungkan.


17. Kenapa bukan Redroid?

Dalam eksperimen sebelumnya, Redroid memang sempat dicoba.

Masalahnya adalah integrasi GPU host NVIDIA proprietary dengan stack GBM/Mesa di dalam container.

Pada mode host GPU, Android gagal melewati tahap graphics initialization dan muncul error seperti:

failed to create gbm device

dan:

failed to open gralloc0 device

Pendekatan ini akhirnya ditinggalkan.

Cuttlefish menggunakan pendekatan yang berbeda:

Android Guest
      ↓
   Gfxstream
      ↓
   crosvm
      ↓
Host EGL/Vulkan
      ↓
NVIDIA RTX 3060

Pendekatan tersebut lebih cocok untuk host dengan GPU NVIDIA proprietary karena rendering guest diteruskan melalui mekanisme virtualisasi grafis Cuttlefish, bukan mencoba memasukkan stack NVIDIA host secara langsung ke Android container.

Hasil akhirnya membuktikan pendekatan ini berhasil karena crosvm benar-benar muncul sebagai proses GPU pada RTX 3060.


18. Struktur akhir sistem

Setelah semua tahap selesai, struktur deployment kurang lebih seperti berikut:

Moonlight
│
├── Ubuntu 24.04
│
├── NVIDIA Driver 610.43.02
│   └── RTX 3060 12 GB
│
├── KVM
│
├── Cuttlefish 1.57.0
│
└── ~/cuttlefish
    │
    ├── Android 17 x86_64
    │
    ├── crosvm
    │
    ├── Gfxstream
    │
    └── WebRTC
         │
         └── :8443

Instance:

phone01

dengan:

CPU       : 6 core
RAM       : 8 GB
Display   : 1080 × 1920
DPI       : 320
Refresh   : 60 Hz
Android   : 17
GPU       : NVIDIA RTX 3060
Renderer  : Gfxstream
Streaming : WebRTC

19. Verifikasi akhir

Untuk memastikan seluruh stack masih sehat, beberapa pemeriksaan sederhana dapat dilakukan.

Cuttlefish

cvd status

Harus menunjukkan instance aktif.

Android

adb devices

Contoh:

127.0.0.1:6520    device

Android boot

adb shell getprop sys.boot_completed

Harus:

1

Android version

adb shell getprop ro.build.version.release

Harus:

17

GPU

nvidia-smi

Cari proses:

crosvm

WebRTC

ss -lntp | grep 8443

Harus ada:

operator_proxy

HTTP

curl -k -I https://127.0.0.1:8443

Harus memberikan respons HTTP.

Browser

Buka:

https://localhost:8443

Kemudian pilih:

phone01

dan tampilkan device.

Jika layar Android muncul dan dapat dikontrol, seluruh pipeline telah berhasil.


Kesimpulan

Setup ini berhasil membuat Android 17 virtual berbasis Cuttlefish dengan GPU acceleration NVIDIA RTX 3060 dan kontrol melalui browser.

Bagian terpenting dari konfigurasi bukan sekadar berhasil menjalankan Android. Ada tiga lapisan yang harus bekerja bersamaan:

1. KVM
      ↓
2. Cuttlefish + crosvm
      ↓
3. Gfxstream → NVIDIA RTX 3060
      ↓
4. WebRTC → Browser

Pada hasil akhir, Android 17 berhasil boot, ADB mendeteksi device, display berjalan pada 1080×1920, crosvm terdeteksi menggunakan RTX 3060, dan layar Android berhasil ditampilkan serta dikontrol langsung melalui browser.

Dengan fondasi ini, sistem sudah mendekati konsep private cloud Android seperti LDCloud, tetapi infrastrukturnya berjalan sendiri di server Moonlight.

Tahap berikutnya dapat dikembangkan menjadi deployment yang lebih serius: autostart Cuttlefish setelah reboot, persistent storage, domain HTTPS, authentication, firewall, akses melalui VPN, serta multi-instance Android. AOSP juga menyediakan mekanisme multi-tenancy Cuttlefish untuk menjalankan beberapa instance dalam satu host.

Referensi resmi

Leave a Reply

Your email address will not be published. Required fields are marked *