Merge changes from topic "avb_testkey_rsa4096_pub_bin"
* changes:
pvmfw: Use pvmfw_embedded_key from Rust
pvmfw: Introduce pvmfw_embedded_key
diff --git a/authfs/tests/benchmarks/src/java/com/android/fs/benchmarks/AuthFsBenchmarks.java b/authfs/tests/benchmarks/src/java/com/android/fs/benchmarks/AuthFsBenchmarks.java
index 5e9073a..641b566 100644
--- a/authfs/tests/benchmarks/src/java/com/android/fs/benchmarks/AuthFsBenchmarks.java
+++ b/authfs/tests/benchmarks/src/java/com/android/fs/benchmarks/AuthFsBenchmarks.java
@@ -20,6 +20,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assume.assumeTrue;
+
import android.platform.test.annotations.RootPermissionTest;
import com.android.fs.common.AuthFsTestRule;
@@ -71,11 +73,13 @@
@Before
public void setUp() throws Exception {
+ assumeTrue(AuthFsTestRule.getDevice().supportsMicrodroid(/*protectedVm=*/ true));
String metricsPrefix =
MetricsProcessor.getMetricPrefix(
getDevice().getProperty("debug.hypervisor.metrics_tag"));
mMetricsProcessor = new MetricsProcessor(metricsPrefix + "authfs/");
- AuthFsTestRule.startMicrodroid();
+ // TODO(b/236123069): Run benchmark tests in both protected and unprotected VMs.
+ AuthFsTestRule.startMicrodroid(/*protectedVm=*/ true);
}
@After
diff --git a/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java b/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java
index 994f23b..2220169 100644
--- a/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java
+++ b/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java
@@ -24,7 +24,6 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.util.PollingCheck;
@@ -131,7 +130,7 @@
return sMicrodroidDevice;
}
- public static void startMicrodroid() throws DeviceNotAvailableException {
+ public static void startMicrodroid(boolean protectedVm) throws DeviceNotAvailableException {
CLog.i("Starting the shared VM");
assertThat(sMicrodroidDevice).isNull();
sMicrodroidDevice =
@@ -139,6 +138,7 @@
findTestFile(sTestInfo.getBuildInfo(), TEST_APK_NAME),
VM_CONFIG_PATH_IN_APK)
.debugLevel("full")
+ .protectedVm(protectedVm)
.build(getDevice());
// From this point on, we need to tear down the Microdroid instance
@@ -152,10 +152,11 @@
}
public static void shutdownMicrodroid() throws DeviceNotAvailableException {
- assertNotNull(sMicrodroidDevice);
- getDevice().shutdownMicrodroid(sMicrodroidDevice);
- sMicrodroidDevice = null;
- sMicrodroid = null;
+ if (sMicrodroidDevice != null) {
+ getDevice().shutdownMicrodroid(sMicrodroidDevice);
+ sMicrodroidDevice = null;
+ sMicrodroid = null;
+ }
}
@Override
@@ -224,7 +225,7 @@
}
}
- private static TestDevice getDevice() {
+ public static TestDevice getDevice() {
return (TestDevice) sTestInfo.getDevice();
}
@@ -245,7 +246,6 @@
}
private void setUpTest() throws Exception {
- assumeTrue(getDevice().supportsMicrodroid());
sAndroid.run("mkdir -p " + TEST_OUTPUT_DIR);
}
diff --git a/authfs/tests/hosttests/java/src/com/android/fs/AuthFsHostTest.java b/authfs/tests/hosttests/java/src/com/android/fs/AuthFsHostTest.java
index 3157dfd..967d104 100644
--- a/authfs/tests/hosttests/java/src/com/android/fs/AuthFsHostTest.java
+++ b/authfs/tests/hosttests/java/src/com/android/fs/AuthFsHostTest.java
@@ -21,6 +21,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.RootPermissionTest;
@@ -74,7 +75,8 @@
@BeforeClassWithInfo
public static void beforeClassWithDevice(TestInformation testInfo) throws Exception {
AuthFsTestRule.setUpAndroid(testInfo);
- AuthFsTestRule.startMicrodroid();
+ assumeTrue(AuthFsTestRule.getDevice().supportsMicrodroid(/*protectedVm=*/ true));
+ AuthFsTestRule.startMicrodroid(/*protectedVm=*/ true);
sAndroid = AuthFsTestRule.getAndroid();
sMicrodroid = AuthFsTestRule.getMicrodroid();
}
diff --git a/microdroid/vm_payload/Android.bp b/microdroid/vm_payload/Android.bp
index 925928e..eeca1c1 100644
--- a/microdroid/vm_payload/Android.bp
+++ b/microdroid/vm_payload/Android.bp
@@ -13,7 +13,9 @@
"libandroid_logger",
"libanyhow",
"libbinder_rs",
+ "liblazy_static",
"liblog_rust",
+ "librpcbinder_rs",
],
apex_available: [
"com.android.compos",
diff --git a/microdroid/vm_payload/include/vm_payload.h b/microdroid/vm_payload/include/vm_payload.h
index 6e065a5..2aeb44e 100644
--- a/microdroid/vm_payload/include/vm_payload.h
+++ b/microdroid/vm_payload/include/vm_payload.h
@@ -25,6 +25,9 @@
extern "C" {
#endif
+struct AIBinder;
+typedef struct AIBinder AIBinder;
+
/**
* Notifies the host that the payload is ready.
*
@@ -33,6 +36,27 @@
bool AVmPayload_notifyPayloadReady(void);
/**
+ * Runs a binder RPC server, serving the supplied binder service implementation on the given vsock
+ * port.
+ *
+ * If and when the server is ready for connections (it is listening on the port), `on_ready` is
+ * called to allow appropriate action to be taken - e.g. to notify clients that they may now
+ * attempt to connect with `AVmPayload_notifyPayloadReady`.
+ *
+ * The current thread is joined to the binder thread pool to handle incoming messages.
+ *
+ * \param service the service to bind to the given port.
+ * \param port vsock port.
+ * \param on_ready the callback to execute once the server is ready for connections. The callback
+ * will be called at most once.
+ * \param param param for the `on_ready` callback.
+ *
+ * \return true if the server has shutdown normally, false if it failed in some way.
+ */
+bool AVmPayload_runVsockRpcServer(AIBinder *service, unsigned int port,
+ void (*on_ready)(void *param), void *param);
+
+/**
* Get a secret that is uniquely bound to this VM instance. The secrets are 32-byte values and the
* value associated with an identifier will not change over the lifetime of the VM instance.
*
@@ -72,6 +96,17 @@
*/
bool AVmPayload_getDiceAttestationCdi(void *data, size_t size, size_t *total);
+/**
+ * Gets the path to the APK contents. It is a directory, under which are
+ * the unzipped contents of the APK containing the payload, all read-only
+ * but accessible to the payload.
+ *
+ * \return the path to the APK contents. The returned string should not be
+ * deleted or freed by the application. The string remains valid for the
+ * lifetime of the VM.
+ */
+const char *AVmPayload_getApkContentsPath(void);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/microdroid/vm_payload/src/vm_payload_service.rs b/microdroid/vm_payload/src/vm_payload_service.rs
index 44013c9..b0dd891 100644
--- a/microdroid/vm_payload/src/vm_payload_service.rs
+++ b/microdroid/vm_payload/src/vm_payload_service.rs
@@ -15,10 +15,19 @@
//! This module handles the interaction with virtual machine payload service.
use android_system_virtualization_payload::aidl::android::system::virtualization::payload::IVmPayloadService::{
- IVmPayloadService, VM_PAYLOAD_SERVICE_NAME};
+ IVmPayloadService, VM_PAYLOAD_SERVICE_NAME, VM_APK_CONTENTS_PATH};
use anyhow::{Context, Result};
-use binder::{wait_for_interface, Strong};
+use binder::{wait_for_interface, Strong, unstable_api::{AIBinder, new_spibinder}};
+use lazy_static::lazy_static;
use log::{error, info, Level};
+use rpcbinder::run_vsock_rpc_server;
+use std::ffi::CString;
+use std::os::raw::{c_char, c_void};
+
+lazy_static! {
+ static ref VM_APK_CONTENTS_PATH_C: CString =
+ CString::new(VM_APK_CONTENTS_PATH).expect("CString::new failed");
+}
/// Notifies the host that the payload is ready.
/// Returns true if the notification succeeds else false.
@@ -42,6 +51,44 @@
get_vm_payload_service()?.notifyPayloadReady().context("Cannot notify payload ready")
}
+/// Runs a binder RPC server, serving the supplied binder service implementation on the given vsock
+/// port.
+///
+/// If and when the server is ready for connections (it is listening on the port), `on_ready` is
+/// called to allow appropriate action to be taken - e.g. to notify clients that they may now
+/// attempt to connect.
+///
+/// The current thread is joined to the binder thread pool to handle incoming messages.
+///
+/// Returns true if the server has shutdown normally, false if it failed in some way.
+///
+/// # Safety
+///
+/// The `on_ready` callback is only called inside `run_vsock_rpc_server`, within the lifetime of
+/// `ReadyNotifier` (the last parameter of `run_vsock_rpc_server`). If `on_ready` is called with
+/// wrong param, the callback execution could go wrong.
+#[no_mangle]
+pub unsafe extern "C" fn AVmPayload_runVsockRpcServer(
+ service: *mut AIBinder,
+ port: u32,
+ on_ready: Option<unsafe extern "C" fn(param: *mut c_void)>,
+ param: *mut c_void,
+) -> bool {
+ // SAFETY: AIBinder returned has correct reference count, and the ownership can
+ // safely be taken by new_spibinder.
+ let service = new_spibinder(service);
+ if let Some(service) = service {
+ run_vsock_rpc_server(service, port, || {
+ if let Some(on_ready) = on_ready {
+ on_ready(param);
+ }
+ })
+ } else {
+ error!("Failed to convert the given service from AIBinder to SpIBinder.");
+ false
+ }
+}
+
/// Get a secret that is uniquely bound to this VM instance.
///
/// # Safety
@@ -145,6 +192,12 @@
}
}
+/// Gets the path to the APK contents.
+#[no_mangle]
+pub extern "C" fn AVmPayload_getApkContentsPath() -> *const c_char {
+ (*VM_APK_CONTENTS_PATH_C).as_ptr()
+}
+
fn try_get_dice_attestation_cdi() -> Result<Vec<u8>> {
get_vm_payload_service()?.getDiceAttestationCdi().context("Cannot get attestation CDI")
}
diff --git a/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl b/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
index 4dd3db6..4823bb8 100644
--- a/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
+++ b/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
@@ -24,6 +24,9 @@
/** Name of the service IVmPayloadService. */
const String VM_PAYLOAD_SERVICE_NAME = "virtual_machine_payload_service";
+ /** Path to the APK contents path. */
+ const String VM_APK_CONTENTS_PATH = "/mnt/apk";
+
/** Notifies that the payload is ready to serve. */
void notifyPayloadReady();
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 00c3dce..b8e85e7 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -33,12 +33,14 @@
VirtualMachineCpuStatus::VirtualMachineCpuStatus,
VirtualMachineMemStatus::VirtualMachineMemStatus,
};
+use android_system_virtualization_payload::aidl::android::system::virtualization::payload::IVmPayloadService::VM_APK_CONTENTS_PATH;
use anyhow::{anyhow, bail, ensure, Context, Error, Result};
use apkverify::{get_public_key_der, verify, V4Signature};
use binder::{ProcessState, Strong};
use diced_utils::cbor::{encode_header, encode_number};
use glob::glob;
use itertools::sorted;
+use libc::VMADDR_CID_HOST;
use log::{error, info};
use microdroid_metadata::{write_metadata, Metadata, PayloadMetadata};
use microdroid_payload_config::{OsConfig, Task, TaskType, VmPayloadConfig};
@@ -62,6 +64,7 @@
use vsock::VsockStream;
const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
+const SENDING_VM_STATUS_CYCLE_PERIOD: Duration = Duration::from_secs(60);
const MAIN_APK_PATH: &str = "/dev/block/by-name/microdroid-apk";
const MAIN_APK_IDSIG_PATH: &str = "/dev/block/by-name/microdroid-apk-idsig";
const MAIN_APK_DEVICE_NAME: &str = "microdroid-apk";
@@ -75,9 +78,6 @@
const DEBUG_MICRODROID_NO_VERIFIED_BOOT: &str =
"/sys/firmware/devicetree/base/virtualization/guest/debug-microdroid,no-verified-boot";
-/// The CID representing the host VM
-const VMADDR_CID_HOST: u32 = 2;
-
const APEX_CONFIG_DONE_PROP: &str = "apex_config.done";
const APP_DEBUGGABLE_PROP: &str = "ro.boot.microdroid.app_debuggable";
const APK_MOUNT_DONE_PROP: &str = "microdroid_manager.apk.mounted";
@@ -97,39 +97,39 @@
InvalidConfig(String),
}
-fn send_vm_status() -> Result<()> {
+fn send_vm_status(service: &Strong<dyn IVirtualMachineService>) -> Result<()> {
+ // Collect VM CPU time information and creating VmCpuStatus atom for metrics.
+ let cpu_time = get_cpu_time()?;
+ let vm_cpu_status = VirtualMachineCpuStatus {
+ cpu_time_user: cpu_time.user,
+ cpu_time_nice: cpu_time.nice,
+ cpu_time_sys: cpu_time.sys,
+ cpu_time_idle: cpu_time.idle,
+ };
+ service.notifyCpuStatus(&vm_cpu_status).expect("Can't send information about VM CPU status");
+
+ // Collect VM memory information and creating VmMemStatus atom for metrics.
+ let mem_info = get_mem_info()?;
+ let vm_mem_status = VirtualMachineMemStatus {
+ mem_total: mem_info.total,
+ mem_free: mem_info.free,
+ mem_available: mem_info.available,
+ mem_buffer: mem_info.buffer,
+ mem_cached: mem_info.cached,
+ };
+ service.notifyMemStatus(&vm_mem_status).expect("Can't send information about VM memory status");
+
+ Ok(())
+}
+
+fn send_vm_status_periodically() -> Result<()> {
let service = get_vms_rpc_binder()
.context("cannot connect to VirtualMachineService")
.map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
- let one_second = Duration::from_millis(1000);
loop {
- // Collect VM CPU time information and creating VmCpuStatus atom for metrics.
- let cpu_time = get_cpu_time()?;
- let vm_cpu_status = VirtualMachineCpuStatus {
- cpu_time_user: cpu_time.user,
- cpu_time_nice: cpu_time.nice,
- cpu_time_sys: cpu_time.sys,
- cpu_time_idle: cpu_time.idle,
- };
- service
- .notifyCpuStatus(&vm_cpu_status)
- .expect("Can't send information about VM CPU status");
-
- // Collect VM memory information and creating VmMemStatus atom for metrics.
- let mem_info = get_mem_info()?;
- let vm_mem_status = VirtualMachineMemStatus {
- mem_total: mem_info.total,
- mem_free: mem_info.free,
- mem_available: mem_info.available,
- mem_buffer: mem_info.buffer,
- mem_cached: mem_info.cached,
- };
- service
- .notifyMemStatus(&vm_mem_status)
- .expect("Can't send information about VM memory status");
-
- thread::sleep(one_second);
+ send_vm_status(&service)?;
+ thread::sleep(SENDING_VM_STATUS_CYCLE_PERIOD);
}
}
@@ -226,7 +226,7 @@
.map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
thread::spawn(move || {
- if let Err(e) = send_vm_status() {
+ if let Err(e) = send_vm_status_periodically() {
error!("failed to get virtual machine status: {:?}", e);
}
});
@@ -399,7 +399,7 @@
MountForExec::Allowed,
"fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0",
Path::new("/dev/block/mapper/microdroid-apk"),
- Path::new("/mnt/apk"),
+ Path::new(VM_APK_CONTENTS_PATH),
Some(APK_MOUNT_DONE_PROP),
)
.context("Failed to run zipfuse")?;
@@ -450,6 +450,7 @@
ProcessState::start_thread_pool();
system_properties::write("dev.bootcomplete", "1").context("set dev.bootcomplete")?;
+ send_vm_status(service)?;
exec_task(task, service).context("Failed to run payload")
}
@@ -782,12 +783,11 @@
service.notifyPayloadStarted()?;
let exit_status = command.spawn()?.wait()?;
+ send_vm_status(service)?;
exit_status.code().ok_or_else(|| anyhow!("Failed to get exit_code from the paylaod."))
}
fn build_command(task: &Task) -> Result<Command> {
- const VMADDR_CID_HOST: u32 = 2;
-
let mut command = match task.type_ {
TaskType::Executable => Command::new(&task.command),
TaskType::MicrodroidLauncher => {
@@ -825,7 +825,7 @@
let mut watcher = PropertyWatcher::new("ro.product.cpu.abilist")?;
let value = watcher.read(|_name, value| Ok(value.trim().to_string()))?;
let abi = value.split(',').next().ok_or_else(|| anyhow!("no abilist"))?;
- let path = format!("/mnt/apk/lib/{}/{}", abi, name);
+ let path = format!("{}/lib/{}/{}", VM_APK_CONTENTS_PATH, abi, name);
let metadata = fs::metadata(&path).with_context(|| format!("Unable to access {}", path))?;
if !metadata.is_file() {
diff --git a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
index ebb2bcf..e8c435f 100644
--- a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
+++ b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
@@ -33,4 +33,7 @@
/* get the VM's boot certificate chain (BCC). */
byte[] getBcc();
+
+ /* get the APK contents path. */
+ String getApkContentsPath();
}
diff --git a/tests/benchmark/Android.bp b/tests/benchmark/Android.bp
index 88e4d41..2ba3881 100644
--- a/tests/benchmark/Android.bp
+++ b/tests/benchmark/Android.bp
@@ -45,7 +45,6 @@
"com.android.microdroid.testservice-ndk",
"libbase",
"libbinder_ndk",
- "libbinder_rpc_unstable",
"liblog",
"libvm_payload",
],
diff --git a/tests/benchmark/src/native/benchmarkbinary.cpp b/tests/benchmark/src/native/benchmarkbinary.cpp
index c394756..24712b1 100644
--- a/tests/benchmark/src/native/benchmarkbinary.cpp
+++ b/tests/benchmark/src/native/benchmarkbinary.cpp
@@ -29,7 +29,6 @@
#include <vm_main.h>
#include <vm_payload.h>
-#include <binder_rpc_unstable.hpp>
#include <fstream>
#include <random>
#include <string>
@@ -164,9 +163,8 @@
abort();
}
};
-
- if (!RunVsockRpcServerCallback(test_service->asBinder().get(), test_service->SERVICE_PORT,
- callback, nullptr)) {
+ if (!AVmPayload_runVsockRpcServer(test_service->asBinder().get(), test_service->SERVICE_PORT,
+ callback, nullptr)) {
return Error() << "RPC Server failed to run";
}
return {};
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
index c9df624..33788ed 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
@@ -485,7 +485,7 @@
}
@Test
- public void testTelemetryPushedAtoms() throws Exception {
+ public void testTelemetryPushedAtomsOfEventMetrics() throws Exception {
// Reset statsd config and report before the test
ConfigUtils.removeConfig(getDevice());
ReportUtils.clearReports(getDevice());
@@ -566,6 +566,49 @@
}
@Test
+ public void testTelemetryPushedAtomsOfValueMetrics() throws Exception {
+ // Reset statsd config and report before the test
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+
+ // Setup statsd config
+ int[] atomIds = {
+ AtomsProto.Atom.VM_CPU_STATUS_REPORTED_FIELD_NUMBER,
+ AtomsProto.Atom.VM_MEM_STATUS_REPORTED_FIELD_NUMBER,
+ };
+ ConfigUtils.uploadConfigForPushedAtoms(getDevice(), PACKAGE_NAME, atomIds);
+
+ // Create VM with microdroid
+ final String configPath = "assets/vm_config_apex.json"; // path inside the APK
+ final String cid =
+ startMicrodroid(
+ getDevice(),
+ getBuild(),
+ APK_NAME,
+ PACKAGE_NAME,
+ configPath,
+ /* debug */ true,
+ minMemorySize(),
+ Optional.of(NUM_VCPUS));
+
+ // Boot VM with microdroid
+ adbConnectToMicrodroid(getDevice(), cid);
+ waitForBootComplete();
+
+ // Check VmCpuStatusReported and VmMemStatusReported atoms and clear the statsd report
+ List<StatsLog.EventMetricData> data;
+ data = ReportUtils.getEventMetricDataList(getDevice());
+ assertThat(data.size() >= 2).isTrue();
+ assertThat(data.get(0).getAtom().getPushedCase().getNumber())
+ .isEqualTo(AtomsProto.Atom.VM_CPU_STATUS_REPORTED_FIELD_NUMBER);
+ assertThat(data.get(1).getAtom().getPushedCase().getNumber())
+ .isEqualTo(AtomsProto.Atom.VM_MEM_STATUS_REPORTED_FIELD_NUMBER);
+
+ // Shutdown VM with microdroid
+ shutdownMicrodroid(getDevice(), cid);
+ }
+
+ @Test
@CddTest(requirements = {"9.17/C-1-1", "9.17/C-1-2", "9.17/C/1-3"})
public void testMicrodroidBoots() throws Exception {
final String configPath = "assets/vm_config.json"; // path inside the APK
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index bb17058..da2c626 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -38,7 +38,6 @@
"com.android.microdroid.testservice-ndk",
"libbase",
"libbinder_ndk",
- "libbinder_rpc_unstable",
"MicrodroidTestNativeLibSub",
"libvm_payload",
],
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index 5c9cf42..c4296df 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -111,6 +111,7 @@
assertThat(testResults.mAddInteger).isEqualTo(123 + 456);
assertThat(testResults.mAppRunProp).isEqualTo("true");
assertThat(testResults.mSublibRunProp).isEqualTo("true");
+ assertThat(testResults.mApkContentsPath).isEqualTo("/mnt/apk");
}
@Test
@@ -538,6 +539,7 @@
String mAppRunProp;
String mSublibRunProp;
String mExtraApkTestProp;
+ String mApkContentsPath;
}
private TestResults runVmTestService(VirtualMachine vm) throws Exception {
@@ -557,6 +559,7 @@
testService.readProperty("debug.microdroid.app.sublib.run");
testResults.mExtraApkTestProp =
testService.readProperty("debug.microdroid.test.extra_apk");
+ testResults.mApkContentsPath = testService.getApkContentsPath();
} catch (Exception e) {
testResults.mException = e;
}
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index 5d6ca8b..1a3e940 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -30,7 +30,6 @@
#include <vm_main.h>
#include <vm_payload.h>
-#include <binder_rpc_unstable.hpp>
#include <string>
using android::base::ErrnoError;
@@ -113,6 +112,17 @@
}
return ndk::ScopedAStatus::ok();
}
+
+ ndk::ScopedAStatus getApkContentsPath(std::string* out) override {
+ const char* path_c = AVmPayload_getApkContentsPath();
+ if (path_c == nullptr) {
+ return ndk::ScopedAStatus::
+ fromServiceSpecificErrorWithMessage(0, "Failed to get APK contents path");
+ }
+ std::string path(path_c);
+ *out = path;
+ return ndk::ScopedAStatus::ok();
+ }
};
auto testService = ndk::SharedRefBase::make<TestService>();
@@ -122,8 +132,8 @@
abort();
}
};
- if (!RunVsockRpcServerCallback(testService->asBinder().get(), testService->SERVICE_PORT,
- callback, nullptr)) {
+ if (!AVmPayload_runVsockRpcServer(testService->asBinder().get(), testService->SERVICE_PORT,
+ callback, nullptr)) {
return Error() << "RPC Server failed to run";
}
diff --git a/virtualizationservice/Android.bp b/virtualizationservice/Android.bp
index 0551229..26d41c9 100644
--- a/virtualizationservice/Android.bp
+++ b/virtualizationservice/Android.bp
@@ -32,6 +32,7 @@
"libcommand_fds",
"libdisk",
"liblazy_static",
+ "liblibc",
"liblog_rust",
"libmicrodroid_metadata",
"libmicrodroid_payload_config",
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 827dcb0..b4ce9d2 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -22,7 +22,6 @@
use crate::crosvm::{CrosvmConfig, DiskFile, PayloadState, VmInstance, VmState};
use crate::payload::{add_microdroid_payload_images, add_microdroid_system_images};
use crate::selinux::{getfilecon, SeContext};
-use crate::{Cid, FIRST_GUEST_CID, SYSPROP_LAST_CID};
use android_os_permissions_aidl::aidl::android::os::IPermissionController;
use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::ErrorCode::ErrorCode;
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
@@ -55,6 +54,7 @@
SpIBinder, Status, StatusCode, Strong, ThreadState,
};
use disk::QcowFile;
+use libc::VMADDR_CID_HOST;
use log::{debug, error, info, warn};
use microdroid_payload_config::{OsConfig, Task, TaskType, VmPayloadConfig};
use rpcbinder::run_vsock_rpc_server_with_factory;
@@ -73,13 +73,19 @@
use vsock::{VsockListener, VsockStream};
use zip::ZipArchive;
+/// The unique ID of a VM used (together with a port number) for vsock communication.
+pub type Cid = u32;
+
pub const BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtualizationservice";
/// Directory in which to write disk image files used while running VMs.
pub const TEMPORARY_DIRECTORY: &str = "/data/misc/virtualizationservice";
-/// The CID representing the host VM
-const VMADDR_CID_HOST: u32 = 2;
+/// The first CID to assign to a guest VM managed by the VirtualizationService. CIDs lower than this
+/// are reserved for the host or other usage.
+const FIRST_GUEST_CID: Cid = 10;
+
+const SYSPROP_LAST_CID: &str = "virtualizationservice.state.last_cid";
/// The size of zero.img.
/// Gaps in composite disk images are filled with a shared zero.img.
@@ -358,7 +364,7 @@
let log_fd = log_fd.map(clone_file).transpose()?;
let requester_uid = ThreadState::get_calling_uid();
let requester_debug_pid = ThreadState::get_calling_pid();
- let cid = next_cid().or(Err(ExceptionCode::ILLEGAL_STATE))?;
+ let cid = state.next_cid().or(Err(ExceptionCode::ILLEGAL_STATE))?;
// Counter to generate unique IDs for temporary image files.
let mut next_temporary_image_id = 0;
@@ -969,27 +975,27 @@
let vm = self.debug_held_vms.swap_remove(pos);
Some(vm)
}
-}
-/// Get the next available CID, or an error if we have run out. The last CID used is stored in
-/// a system property so that restart of virtualizationservice doesn't reuse CID while the host
-/// Android is up.
-fn next_cid() -> Result<Cid> {
- let next = if let Some(val) = system_properties::read(SYSPROP_LAST_CID)? {
- if let Ok(num) = val.parse::<u32>() {
- num.checked_add(1).ok_or_else(|| anyhow!("run out of CID"))?
+ /// Get the next available CID, or an error if we have run out. The last CID used is stored in
+ /// a system property so that restart of virtualizationservice doesn't reuse CID while the host
+ /// Android is up.
+ fn next_cid(&mut self) -> Result<Cid> {
+ let next = if let Some(val) = system_properties::read(SYSPROP_LAST_CID)? {
+ if let Ok(num) = val.parse::<u32>() {
+ num.checked_add(1).ok_or_else(|| anyhow!("run out of CID"))?
+ } else {
+ error!("Invalid last CID {}. Using {}", &val, FIRST_GUEST_CID);
+ FIRST_GUEST_CID
+ }
} else {
- error!("Invalid last CID {}. Using {}", &val, FIRST_GUEST_CID);
+ // First VM since the boot
FIRST_GUEST_CID
- }
- } else {
- // First VM since the boot
- FIRST_GUEST_CID
- };
- // Persist the last value for next use
- let str_val = format!("{}", next);
- system_properties::write(SYSPROP_LAST_CID, &str_val)?;
- Ok(next)
+ };
+ // Persist the last value for next use
+ let str_val = format!("{}", next);
+ system_properties::write(SYSPROP_LAST_CID, &str_val)?;
+ Ok(next)
+ }
}
/// Gets the `VirtualMachineState` of the given `VmInstance`.
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index f5c894a..6f646b7 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -14,9 +14,8 @@
//! Functions for running instances of `crosvm`.
-use crate::aidl::VirtualMachineCallbacks;
+use crate::aidl::{Cid, VirtualMachineCallbacks};
use crate::atom::write_vm_exited_stats;
-use crate::Cid;
use anyhow::{anyhow, bail, Context, Error};
use command_fds::CommandFdExt;
use lazy_static::lazy_static;
diff --git a/virtualizationservice/src/main.rs b/virtualizationservice/src/main.rs
index 828d3a2..cea2747 100644
--- a/virtualizationservice/src/main.rs
+++ b/virtualizationservice/src/main.rs
@@ -29,17 +29,8 @@
use log::{info, Level};
use std::fs::{remove_dir_all, remove_file, read_dir};
-/// The first CID to assign to a guest VM managed by the VirtualizationService. CIDs lower than this
-/// are reserved for the host or other usage.
-const FIRST_GUEST_CID: Cid = 10;
-
-const SYSPROP_LAST_CID: &str = "virtualizationservice.state.last_cid";
-
const LOG_TAG: &str = "VirtualizationService";
-/// The unique ID of a VM used (together with a port number) for vsock communication.
-type Cid = u32;
-
fn main() {
android_logger::init_once(
Config::default()
diff --git a/vm/src/run.rs b/vm/src/run.rs
index 967314b..de8f1c0 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -55,6 +55,8 @@
task_profiles: Vec<String>,
extra_idsigs: &[PathBuf],
) -> Result<(), Error> {
+ let apk_file = File::open(apk).context("Failed to open APK file")?;
+
let extra_apks = parse_extra_apk_list(apk, config_path)?;
if extra_apks.len() != extra_idsigs.len() {
bail!(
@@ -70,7 +72,6 @@
service.createOrUpdateIdsigFile(&extra_apk_fd, &extra_idsig_fd)?;
}
- let apk_file = File::open(apk).context("Failed to open APK file")?;
let idsig_file = File::create(idsig).context("Failed to create idsig file")?;
let apk_fd = ParcelFileDescriptor::new(apk_file);
diff --git a/vmbase/common.h b/vmbase/common.h
new file mode 100644
index 0000000..788dcf0
--- /dev/null
+++ b/vmbase/common.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 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
+ *
+ * https://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.
+ */
+
+#pragma once
+
+#define PSCI_SYSTEM_RESET (0x84000009)
+
+.macro adr_l, reg:req, sym:req
+ adrp \reg, \sym
+ add \reg, \reg, :lo12:\sym
+.endm
+
+.macro mov_i, reg:req, imm:req
+ movz \reg, :abs_g3:\imm
+ movk \reg, :abs_g2_nc:\imm
+ movk \reg, :abs_g1_nc:\imm
+ movk \reg, :abs_g0_nc:\imm
+.endm
+
+.macro reset_or_hang
+ mov_i x0, PSCI_SYSTEM_RESET
+ hvc 0
+999: wfi
+ b 999b
+.endm
diff --git a/vmbase/entry.S b/vmbase/entry.S
index 75ab90b..5f0a2ce 100644
--- a/vmbase/entry.S
+++ b/vmbase/entry.S
@@ -14,17 +14,7 @@
* limitations under the License.
*/
-.macro adr_l, reg:req, sym:req
- adrp \reg, \sym
- add \reg, \reg, :lo12:\sym
-.endm
-
-.macro mov_i, reg:req, imm:req
- movz \reg, :abs_g3:\imm
- movk \reg, :abs_g2_nc:\imm
- movk \reg, :abs_g1_nc:\imm
- movk \reg, :abs_g0_nc:\imm
-.endm
+#include <common.h>
.set .L_MAIR_DEV_nGnRE, 0x04
.set .L_MAIR_MEM_WBWA, 0xff
@@ -95,6 +85,16 @@
adr x30, vector_table_panic
msr vbar_el1, x30
+ /*
+ * Our load address is set by the host so validate it before proceeding.
+ */
+ adr x30, entry
+ mov_i x29, entry
+ cmp x29, x30
+ b.eq 1f
+ reset_or_hang
+1:
+
adrp x30, idmap
msr ttbr0_el1, x30
diff --git a/vmbase/exceptions_panic.S b/vmbase/exceptions_panic.S
index 4a3f2db..54735b2 100644
--- a/vmbase/exceptions_panic.S
+++ b/vmbase/exceptions_panic.S
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <common.h>
+
/**
* The following table is intended to trap any fault resulting from the very
* first memory accesses. They assume that PSCI v0.2 is available and provides
@@ -21,80 +23,69 @@
* results in the core busy-looping.
*/
-.macro exception_panic
- mov x0, 0x84000000
- movk x0, 9
- mov x1, 0
- mov x2, 0
- mov x3, 0
- hvc 0
-0: wfi
- b 0b
-.endm
-
.section .text.vector_table_panic, "ax"
.global vector_table_panic
.balign 0x800
vector_table_panic:
sync_cur_sp0_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
irq_cur_sp0_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
fiq_cur_sp0_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
serr_cur_sp0_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
sync_cur_spx_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
irq_cur_spx_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
fiq_cur_spx_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
serr_cur_spx_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
sync_lower_64_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
irq_lower_64_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
fiq_lower_64_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
serr_lower_64_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
sync_lower_32_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
irq_lower_32_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
fiq_lower_32_panic:
- exception_panic
+ reset_or_hang
.balign 0x80
serr_lower_32_panic:
- exception_panic
+ reset_or_hang