Getting started with Protected Virtual Machines

Prepare a device

First you will need a device that is capable of running virtual machines. On arm64, this means a device which boots the kernel in EL2 and the kernel was built with KVM enabled. Unfortunately at the moment, we don't have an arm64 device in AOSP which does that. Instead, use cuttlefish which provides the same functionalities except that the virtual machines are not protected from the host (i.e. Android). This however should be enough for functional testing.

We support the following device:

  • aosp_cf_x86_64_phone (Cuttlefish a.k.a. Cloud Android)
  • oriole (Pixel 6)
  • raven (Pixel 6 Pro)


Building Cuttlefish

source build/
lunch aosp_cf_x86_64_phone-userdebug

Run Cuttlefish locally by

acloud create --local-instance --local-image

Pixel 6 and 6 Pro

If the device is running Android 12, join the Android Beta Program to uprade to Android 13 Beta.

Once upgraded to Android 13, execute the following command to enable pKVM.

adb reboot bootloader
fastboot flashing unlock
fastboot oem pkvm enable
fastboot reboot

Due to a bug in Android 13 for these devices, pKVM may stop working after an OTA update. To prevent this, it is necessary to manually replicate the pvmfw partition to the other slot:

git -C <android_root>/packages/modules/Virtualization
show de6b0b2ecf6225a0a7b43241de27e74fc3e6ceb2:pvmfw/pvmfw.img > /tmp/pvmfw.img
adb reboot bootloader
fastboot --slot other flash pvmfw /tmp/pvmfw.img
fastboot reboot

Otherwise, if an OTA has already made pKVM unusable, the working partition should be copied to the “current” slot:

adb reboot bootloader
fastboot flash pvmfw /tmp/pvmfw.img
fastboot reboot

Finally, if the pvmfw partition has been corrupted, both slots may be flashed using the pvmfw.img pre-built as long as the bootloader remains unlocked. Otherwise, a fresh install of Android 13 followed by the manual steps above for flashing the other slot should be used as a last resort.

Running demo app

The instruction is here.

Running tests

There are various tests that spawn guest VMs and check different aspects of the architecture. They all can run via atest.

atest VirtualizationTestCases.64
atest MicrodroidHostTestCases
atest MicrodroidTestApp

If you run into problems, inspect the logs produced by atest. Their location is printed at the end. The host_log_*.zip file should contain the output of individual commands as well as VM logs.

Spawning your own VMs with custom kernel

You can spawn your own VMs by passing a JSON config file to the VirtualizationService via the vm tool on a rooted KVM-enabled device. If your device is attached over ADB, you can run:

cat > vm_config.json
  "kernel": "/data/local/tmp/kernel",
  "initrd": "/data/local/tmp/ramdisk",
  "params": "rdinit=/bin/init"
adb root
adb push <kernel> /data/local/tmp/kernel
adb push <ramdisk> /data/local/tmp/ramdisk
adb push vm_config.json /data/local/tmp/vm_config.json
adb shell "start virtualizationservice"
adb shell "/apex/ run /data/local/tmp/vm_config.json"

The vm command also has other subcommands for debugging; run /apex/ help for details.

Spawning your own VMs with Microdroid

Microdroid is a lightweight version of Android that is intended to run on pVM. You can manually run the demo app on top of Microdroid as follows:

TARGET_BUILD_APPS=MicrodroidDemoApp m apps_only dist
adb shell mkdir -p /data/local/tmp/virt
adb push out/dist/MicrodroidDemoApp.apk /data/local/tmp/virt/
adb shell /apex/ run-app \
  --debug full \
  /data/local/tmp/virt/MicrodroidDemoApp.apk \
  /data/local/tmp/virt/MicrodroidDemoApp.apk.idsig \
  /data/local/tmp/virt/instance.img assets/vm_config.json

Building and updating CrosVM and VirtualizationService

You can update CrosVM and the VirtualizationService by updating the APEX instead of rebuilding the entire image.

banchan aosp_arm64   // or aosp_x86_64 if the device is cuttlefish
adb install out/dist/
adb reboot

Building and updating kernel inside Microdroid

Checkout the Android common kernel and build it following the official guideline.

mkdir android-kernel && cd android-kernel
repo init -u -b common-android14-5.15
repo sync
FAST_BUILD=1 DIST_DIR=out/dist BUILD_CONFIG=common/build.config.microdroid.aarch64 build/ -j80

Replace build.config.microdroid.aarch64 with build.config.microdroid.x86_64 if building for x86.

Then copy the built kernel to the Android source tree.

cp out/dist/Image <android_root>/packages/modules/Virtualization/microdroid/kernel/arm64/kernel-5.15

Finally rebuild the APEX and install it by following the steps shown in Building and updating Crosvm and Virtualization.