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.