Add API to determine VM capabilities

Clients can't call HypervisorProperties directly, so expose the same
functionality via an API. This is expressed fairly broadly to allow
for future expansion.

Modify the tests to use the new API.

Also update our @IntDef declarations to specify the intended prefix
(although I'm not sure anything checks them).

Bug: 243642678
Test: atest MicrodroidTests
Change-Id: I52595938514d056ce697969eacffc1526c44faeb
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 {