Merge "Add API to determine VM capabilities"
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachine.java b/javalib/src/android/system/virtualmachine/VirtualMachine.java
index bdec164..61c41a7 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachine.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachine.java
@@ -129,7 +129,7 @@
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
+    @IntDef(prefix = "STATUS_", value = {
             STATUS_STOPPED,
             STATUS_RUNNING,
             STATUS_DELETED
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachineCallback.java b/javalib/src/android/system/virtualmachine/VirtualMachineCallback.java
index c89b8bb..bb6b2b8 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachineCallback.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachineCallback.java
@@ -35,7 +35,7 @@
 public interface VirtualMachineCallback {
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
+    @IntDef(prefix = "ERROR_", value = {
         ERROR_UNKNOWN,
         ERROR_PAYLOAD_VERIFICATION_FAILED,
         ERROR_PAYLOAD_CHANGED,
@@ -57,7 +57,7 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
+    @IntDef(prefix = "STOP_REASON_", value = {
         STOP_REASON_VIRTUALIZATION_SERVICE_DIED,
         STOP_REASON_INFRASTRUCTURE_ERROR,
         STOP_REASON_KILLED,
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java b/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
index 08f1bb8..9f62579 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -61,7 +61,7 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
+    @IntDef(prefix = "DEBUG_LEVEL_", value = {
             DEBUG_LEVEL_NONE,
             DEBUG_LEVEL_APP_ONLY,
             DEBUG_LEVEL_FULL
@@ -409,6 +409,7 @@
          * Sets whether to protect the VM memory from the host. No default is provided, this
          * must be set explicitly.
          *
+         * @see VirtualMachineManager#getCapabilities
          * @hide
          */
         @NonNull
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachineManager.java b/javalib/src/android/system/virtualmachine/VirtualMachineManager.java
index ad5864e..86fd91f 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachineManager.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachineManager.java
@@ -18,12 +18,16 @@
 
 import static java.util.Objects.requireNonNull;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.content.Context;
+import android.sysprop.HypervisorProperties;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.Map;
 import java.util.WeakHashMap;
@@ -44,6 +48,28 @@
             new WeakHashMap<>();
 
     /**
+     * Capabilities of the virtual machine implementation.
+     *
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "CAPABILITY_", flag = true, value = {
+            CAPABILITY_PROTECTED_VM,
+            CAPABILITY_NON_PROTECTED_VM
+    })
+    public @interface Capability {}
+
+    /* The implementation supports creating protected VMs, whose memory is inaccessible to the
+     * host OS.
+     */
+    public static final int CAPABILITY_PROTECTED_VM = 1;
+
+    /* The implementation supports creating non-protected VMs, whose memory is accessible to the
+     * host OS.
+     */
+    public static final int CAPABILITY_NON_PROTECTED_VM = 2;
+
+    /**
      * Returns the per-context instance.
      *
      * @hide
@@ -67,6 +93,25 @@
     private static final Object sCreateLock = new Object();
 
     /**
+     * Returns a set of flags indicating what this implementation of virtualization is capable of.
+     *
+     * @see #CAPABILITY_PROTECTED_VM
+     * @see #CAPABILITY_NON_PROTECTED_VM
+     * @hide
+     */
+    @Capability
+    public int getCapabilities() {
+        @Capability int result = 0;
+        if (HypervisorProperties.hypervisor_protected_vm_supported().orElse(false)) {
+            result |= CAPABILITY_PROTECTED_VM;
+        }
+        if (HypervisorProperties.hypervisor_vm_supported().orElse(false)) {
+            result |= CAPABILITY_NON_PROTECTED_VM;
+        }
+        return result;
+    }
+
+    /**
      * Creates a new {@link VirtualMachine} with the given name and config. Creating a virtual
      * machine with the same name as an existing virtual machine is an error. The existing virtual
      * machine has to be deleted before its name can be reused.
diff --git a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
index 3052c85..07705ba 100644
--- a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
@@ -116,28 +116,19 @@
             assumeNoException(e);
             return;
         }
-        if (protectedVm) {
-            assume().withMessage("Skip where protected VMs aren't supported")
-                    .that(hypervisor_protected_vm_supported())
-                    .isTrue();
-        } else {
-            assume().withMessage("Skip where VMs aren't supported")
-                    .that(hypervisor_vm_supported())
-                    .isTrue();
-        }
         Context context = ApplicationProvider.getApplicationContext();
         mInner = new Inner(context, protectedVm, VirtualMachineManager.getInstance(context));
-    }
 
-    // These are inlined from android.sysprop.HypervisorProperties which isn't @SystemApi.
-    // TODO(b/243642678): Move to using a proper Java API for this.
-
-    private boolean hypervisor_vm_supported() {
-        return SystemProperties.getBoolean("ro.boot.hypervisor.vm.supported", false);
-    }
-
-    private boolean hypervisor_protected_vm_supported() {
-        return SystemProperties.getBoolean("ro.boot.hypervisor.protected_vm.supported", false);
+        int capabilities = mInner.getVirtualMachineManager().getCapabilities();
+        if (protectedVm) {
+            assume().withMessage("Skip where protected VMs aren't supported")
+                    .that(capabilities & VirtualMachineManager.CAPABILITY_PROTECTED_VM)
+                    .isNotEqualTo(0);
+        } else {
+            assume().withMessage("Skip where VMs aren't supported")
+                    .that(capabilities & VirtualMachineManager.CAPABILITY_NON_PROTECTED_VM)
+                    .isNotEqualTo(0);
+        }
     }
 
     public abstract static class VmEventListener implements VirtualMachineCallback {