Merge "[VM] Build virtual machine from a descriptor"
diff --git a/apex/Android.bp b/apex/Android.bp
index e0ca9bf..2d6c757 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -15,20 +15,55 @@
     "microdroid_vendor_boot",
 ]
 
-apex {
-    name: "com.android.virt",
+soong_config_module_type {
+    name: "virt_apex",
+    module_type: "apex",
+    config_namespace: "ANDROID",
+    bool_variables: ["avf_enabled"],
+    properties: ["defaults"],
+}
 
+virt_apex {
+    name: "com.android.virt",
+    soong_config_variables: {
+        avf_enabled: {
+            defaults: ["com.android.virt_avf_enabled"],
+            conditions_default: {
+                defaults: ["com.android.virt_avf_disabled"],
+            },
+        },
+    },
+}
+
+apex_defaults {
+    name: "com.android.virt_common",
     // TODO(jiyong): make it updatable
     updatable: false,
     future_updatable: true,
     platform_apis: true,
 
-    system_ext_specific: true,
-
     manifest: "manifest.json",
 
     key: "com.android.virt.key",
     certificate: ":com.android.virt.certificate",
+
+    apps: [
+        "android.system.virtualmachine.res",
+    ],
+
+    file_contexts: ":com.android.virt-file_contexts",
+    canned_fs_config: "canned_fs_config",
+
+    bootclasspath_fragments: [
+        "com.android.virt-bootclasspath-fragment",
+    ],
+}
+
+apex_defaults {
+    name: "com.android.virt_avf_enabled",
+
+    defaults: ["com.android.virt_common"],
+
     custom_sign_tool: "sign_virt_apex",
 
     // crosvm and virtualizationservice are only enabled for 64-bit targets on device
@@ -52,17 +87,12 @@
         "fd_server",
         "vm",
     ],
-    java_libs: [
-        "android.system.virtualmachine",
-    ],
     jni_libs: [
         "libvirtualmachine_jni",
     ],
-    apps: [
-        "android.system.virtualmachine.res",
-    ],
     prebuilts: [
         "com.android.virt.init.rc",
+        "features_com.android.virt.xml",
         "microdroid_initrd_app_debuggable",
         "microdroid_initrd_full_debuggable",
         "microdroid_initrd_normal",
@@ -71,13 +101,17 @@
         "microdroid_bootloader.avbpubkey",
         "microdroid_kernel",
     ],
-    file_contexts: ":com.android.virt-file_contexts",
-    canned_fs_config: "canned_fs_config",
     host_required: [
         "vm_shell",
     ],
 }
 
+apex_defaults {
+    name: "com.android.virt_avf_disabled",
+
+    defaults: ["com.android.virt_common"],
+}
+
 apex_key {
     name: "com.android.virt.key",
     public_key: "com.android.virt.avbpubkey",
@@ -174,3 +208,43 @@
         },
     },
 }
+
+// Encapsulate the contributions made by the com.android.virt to the bootclasspath.
+bootclasspath_fragment {
+    name: "com.android.virt-bootclasspath-fragment",
+    contents: ["framework-virtualization"],
+    apex_available: ["com.android.virt"],
+
+    // The bootclasspath_fragments that provide APIs on which this depends.
+    fragments: [
+        {
+            apex: "com.android.art",
+            module: "art-bootclasspath-fragment",
+        },
+    ],
+
+    // Additional stubs libraries that this fragment's contents use which are
+    // not provided by another bootclasspath_fragment.
+    additional_stubs: [
+        "android-non-updatable",
+    ],
+
+    hidden_api: {
+
+        // This module does not contain any split packages.
+        split_packages: [],
+
+        // The following packages and all their subpackages currently only
+        // contain classes from this bootclasspath_fragment. Listing a package
+        // here won't prevent other bootclasspath modules from adding classes in
+        // any of those packages but it will prevent them from adding those
+        // classes into an API surface, e.g. public, system, etc.. Doing so will
+        // result in a build failure due to inconsistent flags.
+        package_prefixes: [
+            "android.system.virtualmachine",
+            "android.system.virtualizationservice",
+            // android.sysprop.*, renamed by jarjar
+            "com.android.system.virtualmachine.sysprop",
+        ],
+    },
+}
diff --git a/apex/permissions/Android.bp b/apex/permissions/Android.bp
new file mode 100644
index 0000000..0c925ce
--- /dev/null
+++ b/apex/permissions/Android.bp
@@ -0,0 +1,24 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+prebuilt_etc {
+    name: "features_com.android.virt.xml",
+    sub_dir: "permissions",
+    src: "features_com.android.virt.xml",
+}
diff --git a/apex/permissions/features_com.android.virt.xml b/apex/permissions/features_com.android.virt.xml
new file mode 100644
index 0000000..d2b32e6
--- /dev/null
+++ b/apex/permissions/features_com.android.virt.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<permissions>
+    <feature name="android.software.virtualization_framework" />
+</permissions>
diff --git a/apex/product_packages.mk b/apex/product_packages.mk
index 5bc0044..4293c80 100644
--- a/apex/product_packages.mk
+++ b/apex/product_packages.mk
@@ -21,7 +21,6 @@
 
 PRODUCT_PACKAGES += \
     com.android.compos \
-    com.android.virt \
 
 # TODO(b/207336449): Figure out how to get these off /system
 PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST := \
@@ -33,3 +32,5 @@
 PRODUCT_SYSTEM_EXT_PROPERTIES := ro.config.isolated_compilation_enabled=true
 
 PRODUCT_FSVERITY_GENERATE_METADATA := true
+
+PRODUCT_AVF_ENABLED := true
diff --git a/demo/Android.bp b/demo/Android.bp
index 8613166..5241e25 100644
--- a/demo/Android.bp
+++ b/demo/Android.bp
@@ -13,7 +13,7 @@
         "com.google.android.material_material",
     ],
     libs: [
-        "android.system.virtualmachine",
+        "framework-virtualization",
     ],
     jni_libs: ["MicrodroidTestNativeLib"],
     platform_apis: true,
diff --git a/demo/AndroidManifest.xml b/demo/AndroidManifest.xml
index 6669adb..17a7680 100644
--- a/demo/AndroidManifest.xml
+++ b/demo/AndroidManifest.xml
@@ -4,11 +4,11 @@
 
     <uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
     <uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33"/>
+    <uses-feature android:name="android.software.virtualization_framework" android:required="true" />
     <application
         android:label="MicrodroidDemo"
         android:theme="@style/Theme.MicrodroidDemo"
         android:testOnly="true">
-        <uses-library android:name="android.system.virtualmachine" android:required="true" />
         <activity android:name=".MainActivity" android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/javalib/Android.bp b/javalib/Android.bp
index cb03fa1..1d89059 100644
--- a/javalib/Android.bp
+++ b/javalib/Android.bp
@@ -11,10 +11,16 @@
 }
 
 java_sdk_library {
-    name: "android.system.virtualmachine",
-    installable: true,
+    name: "framework-virtualization",
+    installable: false,
     compile_dex: true,
 
+    shared_library: false,
+
+    // TODO(b/243512044): use framework-module-defaults
+
+    dist_group: "android",
+
     jarjar_rules: "jarjar-rules.txt",
 
     srcs: ["src/**/*.java"],
@@ -25,6 +31,7 @@
     ],
 
     apex_available: ["com.android.virt"],
+
     permitted_packages: [
         "android.system.virtualmachine",
         "android.system.virtualizationservice",
@@ -38,6 +45,9 @@
             "-Xep:GuardedBy:ERROR",
         ],
     },
+
+    // Temporary workaround, will be removed in a follow-up child cl.
+    unsafe_ignore_missing_latest_api: true,
 }
 
 prebuilt_apis {
diff --git a/tests/aidl/com/android/microdroid/testservice/IBenchmarkService.aidl b/tests/aidl/com/android/microdroid/testservice/IBenchmarkService.aidl
index 260f804..16e4893 100644
--- a/tests/aidl/com/android/microdroid/testservice/IBenchmarkService.aidl
+++ b/tests/aidl/com/android/microdroid/testservice/IBenchmarkService.aidl
@@ -25,7 +25,7 @@
      *
      * @return The read rate in MB/s.
      */
-    double measureReadRate(String filename, long fileSizeBytes, boolean isRand);
+    double measureReadRate(String filename, boolean isRand);
 
     /** Returns an entry from /proc/meminfo. */
     long getMemInfoEntry(String name);
diff --git a/tests/benchmark/Android.bp b/tests/benchmark/Android.bp
index e6f39f8..bccea6b 100644
--- a/tests/benchmark/Android.bp
+++ b/tests/benchmark/Android.bp
@@ -16,7 +16,7 @@
         "com.android.microdroid.testservice-java",
         "truth-prebuilt",
     ],
-    libs: ["android.system.virtualmachine"],
+    libs: ["framework-virtualization"],
     jni_libs: [
         "MicrodroidBenchmarkNativeLib",
         "MicrodroidIdleNativeLib",
@@ -28,20 +28,11 @@
 }
 
 cc_library_shared {
-    name: "MicrodroidIdleNativeLib",
-    srcs: ["src/native/idlebinary.cpp"],
-    header_libs: ["vm_payload_headers"],
-    shared_libs: [
-        "libbase",
-    ],
-}
-
-cc_library_shared {
     name: "MicrodroidBenchmarkNativeLib",
-    srcs: ["src/native/benchmarkbinary.cpp"],
+    srcs: ["src/native/*.cpp"],
+    local_include_dirs: ["src/native/include"],
     static_libs: [
         "com.android.microdroid.testservice-ndk",
-        "libiobenchmark",
     ],
     shared_libs: [
         "libbase",
@@ -50,12 +41,3 @@
         "libvm_payload",
     ],
 }
-
-cc_library {
-    name: "libiobenchmark",
-    srcs: ["src/native/io_vsock.cpp"],
-    export_include_dirs: ["src/native/include"],
-    shared_libs: [
-        "libbase",
-    ],
-}
diff --git a/tests/benchmark/AndroidManifest.xml b/tests/benchmark/AndroidManifest.xml
index c39b91c..8a7366a 100644
--- a/tests/benchmark/AndroidManifest.xml
+++ b/tests/benchmark/AndroidManifest.xml
@@ -18,7 +18,6 @@
     <uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
     <uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" />
     <application>
-        <uses-library android:name="android.system.virtualmachine" android:required="false" />
     </application>
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.microdroid.benchmark"
diff --git a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
index db74358..28852e8 100644
--- a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
+++ b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
@@ -257,18 +257,10 @@
     private static class VirtioBlkListener implements BenchmarkVmListener.InnerListener {
         private static final String FILENAME = APEX_ETC_FS + "microdroid_super.img";
 
-        private final long mFileSizeBytes;
         private final List<Double> mReadRates;
         private final boolean mIsRand;
 
         VirtioBlkListener(List<Double> readRates, boolean isRand) {
-            File file = new File(FILENAME);
-            try {
-                mFileSizeBytes = Files.size(file.toPath());
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-            assertThat(mFileSizeBytes).isGreaterThan((long) SIZE_MB);
             mReadRates = readRates;
             mIsRand = isRand;
         }
@@ -276,7 +268,7 @@
         @Override
         public void onPayloadReady(VirtualMachine vm, IBenchmarkService benchmarkService)
                 throws RemoteException {
-            double readRate = benchmarkService.measureReadRate(FILENAME, mFileSizeBytes, mIsRand);
+            double readRate = benchmarkService.measureReadRate(FILENAME, mIsRand);
             mReadRates.add(readRate);
         }
     }
diff --git a/tests/benchmark/src/native/benchmarkbinary.cpp b/tests/benchmark/src/native/benchmarkbinary.cpp
index 70c6884..e43025c 100644
--- a/tests/benchmark/src/native/benchmarkbinary.cpp
+++ b/tests/benchmark/src/native/benchmarkbinary.cpp
@@ -23,6 +23,8 @@
 #include <fcntl.h>
 #include <linux/vm_sockets.h>
 #include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <time.h>
 #include <unistd.h>
 #include <vm_main.h>
@@ -56,9 +58,9 @@
 
 class IOBenchmarkService : public aidl::com::android::microdroid::testservice::BnBenchmarkService {
 public:
-    ndk::ScopedAStatus measureReadRate(const std::string& filename, int64_t fileSizeBytes,
-                                       bool isRand, double* out) override {
-        auto res = measure_read_rate(filename, fileSizeBytes, isRand);
+    ndk::ScopedAStatus measureReadRate(const std::string& filename, bool isRand,
+                                       double* out) override {
+        auto res = measure_read_rate(filename, isRand);
         if (res.ok()) {
             *out = res.value();
         }
@@ -90,10 +92,17 @@
     }
 
 private:
-    /** Measures the read rate for reading the given file. */
-    Result<double> measure_read_rate(const std::string& filename, int64_t fileSizeBytes,
-                                     bool is_rand) {
-        const int64_t block_count = fileSizeBytes / kBlockSizeBytes;
+    /**
+     * Measures the read rate for reading the given file.
+     * @return The read rate in MB/s.
+     */
+    Result<double> measure_read_rate(const std::string& filename, bool is_rand) {
+        struct stat file_stats;
+        if (stat(filename.c_str(), &file_stats) == -1) {
+            return Error() << "failed to get file stats";
+        }
+        const int64_t file_size_bytes = file_stats.st_size;
+        const int64_t block_count = file_size_bytes / kBlockSizeBytes;
         std::vector<uint64_t> offsets(block_count);
         for (auto i = 0; i < block_count; ++i) {
             offsets[i] = i * kBlockSizeBytes;
@@ -118,8 +127,8 @@
             }
         }
         double elapsed_seconds = ((double)clock() - start) / CLOCKS_PER_SEC;
-        double read_rate = (double)fileSizeBytes / kNumBytesPerMB / elapsed_seconds;
-        return {read_rate};
+        double file_size_mb = (double)file_size_bytes / kNumBytesPerMB;
+        return {file_size_mb / elapsed_seconds};
     }
 
     Result<size_t> read_meminfo_entry(const std::string& stat) {
diff --git a/tests/helper/Android.bp b/tests/helper/Android.bp
index 60d4be1..bd92020 100644
--- a/tests/helper/Android.bp
+++ b/tests/helper/Android.bp
@@ -24,5 +24,5 @@
         "VirtualizationTestHelper",
         "truth-prebuilt",
     ],
-    libs: ["android.system.virtualmachine"],
+    libs: ["framework-virtualization"],
 }
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 1e57ff8..d1e1f6c 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
@@ -15,9 +15,9 @@
  */
 package com.android.microdroid.test.device;
 
-import static com.google.common.truth.TruthJUnit.assume;
+import static android.content.pm.PackageManager.FEATURE_VIRTUALIZATION_FRAMEWORK;
 
-import static org.junit.Assume.assumeNoException;
+import static com.google.common.truth.TruthJUnit.assume;
 
 import android.app.Instrumentation;
 import android.app.UiAutomation;
@@ -119,17 +119,12 @@
     }
 
     public void prepareTestSetup(boolean protectedVm) {
-        // In case when the virt APEX doesn't exist on the device, classes in the
-        // android.system.virtualmachine package can't be loaded. Therefore, before using the
-        // classes, check the existence of a class in the package and skip this test if not exist.
-        try {
-            Class.forName("android.system.virtualmachine.VirtualMachineManager");
-        } catch (ClassNotFoundException e) {
-            assumeNoException(e);
-            return;
-        }
-        Context context = ApplicationProvider.getApplicationContext();
-        mInner = new Inner(context, protectedVm, VirtualMachineManager.getInstance(context));
+        Context ctx = ApplicationProvider.getApplicationContext();
+        assume().withMessage("Device doesn't support AVF")
+                .that(ctx.getPackageManager().hasSystemFeature(FEATURE_VIRTUALIZATION_FRAMEWORK))
+                .isTrue();
+
+        mInner = new Inner(ctx, protectedVm, VirtualMachineManager.getInstance(ctx));
 
         int capabilities = mInner.getVirtualMachineManager().getCapabilities();
         if (protectedVm) {
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index 8972046..8d49721 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -19,7 +19,7 @@
         "truth-prebuilt",
         "compatibility-common-util-devicesidelib",
     ],
-    libs: ["android.system.virtualmachine"],
+    libs: ["framework-virtualization"],
     jni_libs: [
         "MicrodroidTestNativeLib",
         "MicrodroidIdleNativeLib",
@@ -55,3 +55,10 @@
     srcs: ["src/native/testlib.cpp"],
     stl: "libc++_static",
 }
+
+cc_library_shared {
+    name: "MicrodroidIdleNativeLib",
+    srcs: ["src/native/idlebinary.cpp"],
+    header_libs: ["vm_payload_headers"],
+    stl: "libc++_static",
+}
diff --git a/tests/testapk/AndroidManifest.xml b/tests/testapk/AndroidManifest.xml
index ab22546..fefd20a 100644
--- a/tests/testapk/AndroidManifest.xml
+++ b/tests/testapk/AndroidManifest.xml
@@ -18,8 +18,8 @@
     <uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
     <uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" />
     <uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" />
+    <uses-feature android:name="android.software.virtualization_framework" android:required="false" />
     <application>
-        <uses-library android:name="android.system.virtualmachine" android:required="false" />
     </application>
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.microdroid.test"
diff --git a/tests/benchmark/src/native/idlebinary.cpp b/tests/testapk/src/native/idlebinary.cpp
similarity index 100%
rename from tests/benchmark/src/native/idlebinary.cpp
rename to tests/testapk/src/native/idlebinary.cpp