Merge "microdroid_manager: Fix duplicate error log"
diff --git a/.gitignore b/.gitignore
index 96ef6c0..5917dfb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
-/target
+apkdmverity/target/
+zipfuse/target/
+policy
+zipfuse/target/
Cargo.lock
diff --git a/OWNERS b/OWNERS
index 7e479c4..5bd97f3 100644
--- a/OWNERS
+++ b/OWNERS
@@ -12,6 +12,7 @@
ardb@google.com
ascull@google.com
inseob@google.com
+jeffv@google.com
jooyung@google.com
mzyngier@google.com
ptosi@google.com
diff --git a/apkdmverity/src/main.rs b/apkdmverity/src/main.rs
index 16dd480..de7f5bb 100644
--- a/apkdmverity/src/main.rs
+++ b/apkdmverity/src/main.rs
@@ -45,7 +45,7 @@
block device is created at \"/dev/mapper/<name>\".' root_hash is \
optional; idsig file's root hash will be used if specified as \"none\"."
))
- .arg(Arg::with_name("verbose").short("v").long("verbose").help("Shows verbose output"))
+ .arg(Arg::with_name("verbose").short('v').long("verbose").help("Shows verbose output"))
.get_matches();
let apks = matches.values_of("apk").unwrap();
diff --git a/authfs/Android.bp b/authfs/Android.bp
index 40643b8..cb7f119 100644
--- a/authfs/Android.bp
+++ b/authfs/Android.bp
@@ -14,7 +14,7 @@
"libandroid_logger",
"libanyhow",
"libauthfs_fsverity_metadata",
- "libbinder_rpc_unstable_bindgen",
+ "libbinder_common",
"libbinder_rs",
"libcfg_if",
"libfsverity_digests_proto_rust",
diff --git a/authfs/fd_server/Android.bp b/authfs/fd_server/Android.bp
index 9499cd2..943eec1 100644
--- a/authfs/fd_server/Android.bp
+++ b/authfs/fd_server/Android.bp
@@ -11,7 +11,6 @@
"libanyhow",
"libauthfs_fsverity_metadata",
"libbinder_common",
- "libbinder_rpc_unstable_bindgen",
"libbinder_rs",
"libclap",
"liblibc",
diff --git a/authfs/src/file.rs b/authfs/src/file.rs
index 44e60d8..d9f8964 100644
--- a/authfs/src/file.rs
+++ b/authfs/src/file.rs
@@ -6,15 +6,14 @@
pub use dir::{InMemoryDir, RemoteDirEditor};
pub use remote_file::{RemoteFileEditor, RemoteFileReader, RemoteMerkleTreeReader};
-use binder::unstable_api::{new_spibinder, AIBinder};
-use binder::FromIBinder;
-use std::convert::TryFrom;
-use std::io;
-use std::path::{Path, MAIN_SEPARATOR};
-
use crate::common::{divide_roundup, CHUNK_SIZE};
use authfs_aidl_interface::aidl::com::android::virt::fs::IVirtFdService::IVirtFdService;
use authfs_aidl_interface::binder::{Status, Strong};
+use binder::StatusCode;
+use binder_common::rpc_client::connect_rpc_binder;
+use std::convert::TryFrom;
+use std::io;
+use std::path::{Path, MAIN_SEPARATOR};
pub type VirtFdService = Strong<dyn IVirtFdService>;
pub type VirtFdServiceStatus = Status;
@@ -24,21 +23,15 @@
pub const RPC_SERVICE_PORT: u32 = 3264;
pub fn get_rpc_binder_service(cid: u32) -> io::Result<VirtFdService> {
- // SAFETY: AIBinder returned by RpcClient has correct reference count, and the ownership can be
- // safely taken by new_spibinder.
- let ibinder = unsafe {
- new_spibinder(binder_rpc_unstable_bindgen::RpcClient(cid, RPC_SERVICE_PORT) as *mut AIBinder)
- };
- if let Some(ibinder) = ibinder {
- Ok(<dyn IVirtFdService>::try_from(ibinder).map_err(|e| {
- io::Error::new(
- io::ErrorKind::AddrNotAvailable,
- format!("Cannot connect to RPC service: {}", e),
- )
- })?)
- } else {
- Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid raw AIBinder"))
- }
+ connect_rpc_binder(cid, RPC_SERVICE_PORT).map_err(|e| match e {
+ StatusCode::BAD_VALUE => {
+ io::Error::new(io::ErrorKind::InvalidInput, "Invalid raw AIBinder")
+ }
+ _ => io::Error::new(
+ io::ErrorKind::AddrNotAvailable,
+ format!("Cannot connect to RPC service: {}", e),
+ ),
+ })
}
/// A trait for reading data by chunks. Chunks can be read by specifying the chunk index. Only the
diff --git a/avmd/src/avmd.rs b/avmd/src/avmd.rs
index e3bc7a7..50cdfdf 100644
--- a/avmd/src/avmd.rs
+++ b/avmd/src/avmd.rs
@@ -12,9 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+extern crate alloc;
+
+use alloc::{
+ string::{String, ToString},
+ vec::Vec,
+};
use apexutil::to_hex_string;
+use core::fmt;
use serde::{Deserialize, Serialize};
-use std::fmt;
/// An Avmd struct contains
/// - A header with version information that allows rollback when needed.
diff --git a/avmd/src/lib.rs b/avmd/src/lib.rs
index 9722518..7a06e6a 100644
--- a/avmd/src/lib.rs
+++ b/avmd/src/lib.rs
@@ -14,6 +14,8 @@
//! Library for handling AVMD blobs.
+#![no_std]
+
mod avmd;
pub use avmd::{ApkDescriptor, Avmd, Descriptor, ResourceIdentifier, VbMetaDescriptor};
diff --git a/avmd/src/main.rs b/avmd/src/main.rs
index b156a66..ca28f42 100644
--- a/avmd/src/main.rs
+++ b/avmd/src/main.rs
@@ -149,8 +149,8 @@
let args = app.get_matches();
match args.subcommand() {
- ("create", Some(sub_args)) => create(sub_args)?,
- ("dump", Some(sub_args)) => dump(sub_args)?,
+ Some(("create", sub_args)) => create(sub_args)?,
+ Some(("dump", sub_args)) => dump(sub_args)?,
_ => bail!("Invalid arguments"),
}
Ok(())
diff --git a/compos/Android.bp b/compos/Android.bp
index 69b22d6..0f1675b 100644
--- a/compos/Android.bp
+++ b/compos/Android.bp
@@ -12,7 +12,6 @@
"libandroid_logger",
"libanyhow",
"libbinder_common",
- "libbinder_rpc_unstable_bindgen",
"libbinder_rs",
"libclap",
"libcompos_common",
diff --git a/compos/common/Android.bp b/compos/common/Android.bp
index 1a69b1a..3c3397d 100644
--- a/compos/common/Android.bp
+++ b/compos/common/Android.bp
@@ -12,7 +12,6 @@
"compos_aidl_interface-rust",
"libanyhow",
"libbinder_common",
- "libbinder_rpc_unstable_bindgen",
"liblazy_static",
"liblog_rust",
"libnested_virt",
diff --git a/compos/composd_cmd/composd_cmd.rs b/compos/composd_cmd/composd_cmd.rs
index c6a5479..d5feed8 100644
--- a/compos/composd_cmd/composd_cmd.rs
+++ b/compos/composd_cmd/composd_cmd.rs
@@ -49,8 +49,8 @@
ProcessState::start_thread_pool();
match args.subcommand() {
- ("staged-apex-compile", _) => run_staged_apex_compile()?,
- ("test-compile", Some(sub_matches)) => {
+ Some(("staged-apex-compile", _)) => run_staged_apex_compile()?,
+ Some(("test-compile", sub_matches)) => {
let prefer_staged = sub_matches.is_present("prefer-staged");
run_test_compile(prefer_staged)?;
}
diff --git a/compos/src/compsvc_main.rs b/compos/src/compsvc_main.rs
index 4ecbfe9..186977e 100644
--- a/compos/src/compsvc_main.rs
+++ b/compos/src/compsvc_main.rs
@@ -28,12 +28,8 @@
},
binder::Strong,
};
-use anyhow::{anyhow, bail, Context, Result};
-use binder::{
- unstable_api::{new_spibinder, AIBinder},
- FromIBinder,
-};
-use binder_common::rpc_server::run_rpc_server;
+use anyhow::{bail, Context, Result};
+use binder_common::{rpc_client::connect_rpc_binder, rpc_server::run_rpc_server};
use compos_common::COMPOS_VSOCK_PORT;
use log::{debug, error};
use std::panic;
@@ -76,15 +72,6 @@
}
fn get_vm_service() -> Result<Strong<dyn IVirtualMachineService>> {
- // SAFETY: AIBinder returned by RpcClient has correct reference count, and the ownership
- // can be safely taken by new_spibinder.
- let ibinder = unsafe {
- new_spibinder(binder_rpc_unstable_bindgen::RpcClient(
- VMADDR_CID_HOST,
- VM_BINDER_SERVICE_PORT as u32,
- ) as *mut AIBinder)
- }
- .ok_or_else(|| anyhow!("Failed to connect to IVirtualMachineService"))?;
-
- FromIBinder::try_from(ibinder).context("Connecting to IVirtualMachineService")
+ connect_rpc_binder(VMADDR_CID_HOST, VM_BINDER_SERVICE_PORT as u32)
+ .context("Connecting to IVirtualMachineService")
}
diff --git a/microdroid_manager/Android.bp b/microdroid_manager/Android.bp
index d1afc14..3ba2700 100644
--- a/microdroid_manager/Android.bp
+++ b/microdroid_manager/Android.bp
@@ -16,7 +16,7 @@
"libanyhow",
"libapexutil_rust",
"libapkverify",
- "libbinder_rpc_unstable_bindgen",
+ "libbinder_common",
"libbinder_rs",
"libbyteorder",
"libdiced_utils",
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 557a379..fa064a7 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -25,8 +25,8 @@
use android_security_dice::aidl::android::security::dice::IDiceMaintenance::IDiceMaintenance;
use anyhow::{anyhow, bail, ensure, Context, Error, Result};
use apkverify::{get_public_key_der, verify};
-use binder::unstable_api::{new_spibinder, AIBinder};
-use binder::{wait_for_interface, FromIBinder, Strong};
+use binder::{wait_for_interface, Strong};
+use binder_common::rpc_client::connect_rpc_binder;
use diced_utils::cbor::encode_header;
use glob::glob;
use idsig::V4Signature;
@@ -139,19 +139,8 @@
}
fn get_vms_rpc_binder() -> Result<Strong<dyn IVirtualMachineService>> {
- // SAFETY: AIBinder returned by RpcClient has correct reference count, and the ownership can be
- // safely taken by new_spibinder.
- let ibinder = unsafe {
- new_spibinder(binder_rpc_unstable_bindgen::RpcClient(
- VMADDR_CID_HOST,
- VM_BINDER_SERVICE_PORT as u32,
- ) as *mut AIBinder)
- };
- if let Some(ibinder) = ibinder {
- <dyn IVirtualMachineService>::try_from(ibinder).context("Cannot connect to RPC service")
- } else {
- bail!("Invalid raw AIBinder")
- }
+ connect_rpc_binder(VMADDR_CID_HOST, VM_BINDER_SERVICE_PORT as u32)
+ .context("Cannot connect to RPC service")
}
fn main() -> Result<()> {
diff --git a/tests/aidl/com/android/microdroid/testservice/IBenchmarkService.aidl b/tests/aidl/com/android/microdroid/testservice/IBenchmarkService.aidl
new file mode 100644
index 0000000..afcf989
--- /dev/null
+++ b/tests/aidl/com/android/microdroid/testservice/IBenchmarkService.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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
+ *
+ * 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 com.android.microdroid.testservice;
+
+/** {@hide} */
+interface IBenchmarkService {
+ const int SERVICE_PORT = 5677;
+
+ /** Reads a file and returns the elapsed seconds for the reading. */
+ double readFile(String filename, long fileSizeBytes, boolean isRand);
+}
diff --git a/tests/benchmark/Android.bp b/tests/benchmark/Android.bp
index e6d5b83..2111620 100644
--- a/tests/benchmark/Android.bp
+++ b/tests/benchmark/Android.bp
@@ -12,6 +12,7 @@
"MicroroidDeviceTestHelper",
"androidx.test.runner",
"androidx.test.ext.junit",
+ "com.android.microdroid.testservice-java",
"truth-prebuilt",
],
libs: ["android.system.virtualmachine"],
@@ -24,4 +25,12 @@
cc_library_shared {
name: "MicrodroidBenchmarkNativeLib",
srcs: ["src/native/benchmarkbinary.cpp"],
+ shared_libs: [
+ "android.system.virtualmachineservice-ndk",
+ "com.android.microdroid.testservice-ndk",
+ "libbase",
+ "libbinder_ndk",
+ "libbinder_rpc_unstable",
+ "liblog",
+ ],
}
diff --git a/tests/benchmark/assets/vm_config.json b/tests/benchmark/assets/vm_config.json
index 67e3d21..e8f43e0 100644
--- a/tests/benchmark/assets/vm_config.json
+++ b/tests/benchmark/assets/vm_config.json
@@ -4,7 +4,10 @@
},
"task": {
"type": "microdroid_launcher",
- "command": "MicrodroidBenchmarkNativeLib.so"
+ "command": "MicrodroidBenchmarkNativeLib.so",
+ "args": [
+ "no_io"
+ ]
},
"export_tombstones": true
}
diff --git a/tests/benchmark/assets/vm_config_io.json b/tests/benchmark/assets/vm_config_io.json
new file mode 100644
index 0000000..1a5a9e5
--- /dev/null
+++ b/tests/benchmark/assets/vm_config_io.json
@@ -0,0 +1,18 @@
+{
+ "os": {
+ "name": "microdroid"
+ },
+ "task": {
+ "type": "microdroid_launcher",
+ "command": "MicrodroidBenchmarkNativeLib.so",
+ "args": [
+ "io"
+ ]
+ },
+ "apexes": [
+ {
+ "name": "com.android.virt"
+ }
+ ],
+ "export_tombstones": true
+}
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 3731e13..7ee2d39 100644
--- a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
+++ b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.microdroid.benchmark;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -22,11 +23,13 @@
import android.app.Instrumentation;
import android.os.Bundle;
+import android.system.virtualmachine.VirtualMachine;
import android.system.virtualmachine.VirtualMachineConfig;
import android.system.virtualmachine.VirtualMachineConfig.DebugLevel;
import android.system.virtualmachine.VirtualMachineException;
import com.android.microdroid.test.MicrodroidDeviceTestBase;
+import com.android.microdroid.testservice.IBenchmarkService;
import org.junit.Before;
import org.junit.Rule;
@@ -38,10 +41,13 @@
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
@RunWith(Parameterized.class)
public class MicrodroidBenchmarks extends MicrodroidDeviceTestBase {
private static final String TAG = "MicrodroidBenchmarks";
+ private static final int VIRTIO_BLK_TRIAL_COUNT = 5;
@Rule public Timeout globalTimeout = Timeout.seconds(300);
@@ -159,12 +165,100 @@
continue;
}
- String base = name.substring(MICRODROID_IMG_PREFIX.length(),
- name.length() - MICRODROID_IMG_SUFFIX.length());
- String metric = "avf_perf/microdroid/img_size_" + base + "_MB";
+ String base =
+ name.substring(
+ MICRODROID_IMG_PREFIX.length(),
+ name.length() - MICRODROID_IMG_SUFFIX.length());
+ String metric = "avf_perf/microdroid/img_size_" + base + "_MB" + "+" + name;
double size = Files.size(file.toPath()) / SIZE_MB;
bundle.putDouble(metric, size);
}
mInstrumentation.sendStatus(0, bundle);
}
+
+ @Test
+ public void testVirtioBlkSeqReadRate() throws Exception {
+ testVirtioBlkReadRate(/*isRand=*/ false);
+ }
+
+ @Test
+ public void testVirtioBlkRandReadRate() throws Exception {
+ testVirtioBlkReadRate(/*isRand=*/ true);
+ }
+
+ private void testVirtioBlkReadRate(boolean isRand) throws Exception {
+ VirtualMachineConfig.Builder builder =
+ mInner.newVmConfigBuilder("assets/vm_config_io.json");
+ VirtualMachineConfig config = builder.debugLevel(DebugLevel.FULL).build();
+ List<Double> readRates = new ArrayList<>();
+
+ for (int i = 0; i < VIRTIO_BLK_TRIAL_COUNT; ++i) {
+ String vmName = "test_vm_io_" + i;
+ mInner.forceCreateNewVirtualMachine(vmName, config);
+ VirtualMachine vm = mInner.getVirtualMachineManager().get(vmName);
+ VirtioBlkVmEventListener listener = new VirtioBlkVmEventListener(readRates, isRand);
+ listener.runToFinish(TAG, vm);
+ }
+ reportMetrics(readRates, isRand);
+ }
+
+ private void reportMetrics(List<Double> readRates, boolean isRand) {
+ double sum = 0;
+ for (double rate : readRates) {
+ sum += rate;
+ }
+ double mean = sum / readRates.size();
+ double sqSum = 0;
+ for (double rate : readRates) {
+ sqSum += (rate - mean) * (rate - mean);
+ }
+ double stdDev = Math.sqrt(sqSum / (readRates.size() - 1));
+
+ Bundle bundle = new Bundle();
+ String metricNamePrefix =
+ "avf_perf/virtio-blk/"
+ + (mProtectedVm ? "protected-vm/" : "unprotected-vm/")
+ + (isRand ? "rand_read_" : "seq_read_");
+ String unit = "_mb_per_sec";
+
+ bundle.putDouble(metricNamePrefix + "mean" + unit, mean);
+ bundle.putDouble(metricNamePrefix + "std" + unit, stdDev);
+ mInstrumentation.sendStatus(0, bundle);
+ }
+
+ private static class VirtioBlkVmEventListener extends VmEventListener {
+ private static final String FILENAME = APEX_ETC_FS + "microdroid_super.img";
+
+ private final long mFileSizeBytes;
+ private final List<Double> mReadRates;
+ private final boolean mIsRand;
+
+ VirtioBlkVmEventListener(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;
+ }
+
+ @Override
+ public void onPayloadReady(VirtualMachine vm) {
+ try {
+ IBenchmarkService benchmarkService =
+ IBenchmarkService.Stub.asInterface(
+ vm.connectToVsockServer(IBenchmarkService.SERVICE_PORT).get());
+ double elapsedSeconds =
+ benchmarkService.readFile(FILENAME, mFileSizeBytes, mIsRand);
+ double fileSizeMb = mFileSizeBytes / SIZE_MB;
+ mReadRates.add(fileSizeMb / elapsedSeconds);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ forceStop(vm);
+ }
+ }
}
diff --git a/tests/benchmark/src/native/benchmarkbinary.cpp b/tests/benchmark/src/native/benchmarkbinary.cpp
index b5ec49c..5523579 100644
--- a/tests/benchmark/src/native/benchmarkbinary.cpp
+++ b/tests/benchmark/src/native/benchmarkbinary.cpp
@@ -13,11 +13,123 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+#include <aidl/android/system/virtualmachineservice/IVirtualMachineService.h>
+#include <aidl/com/android/microdroid/testservice/BnBenchmarkService.h>
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+#include <fcntl.h>
+#include <linux/vm_sockets.h>
+#include <stdio.h>
#include <unistd.h>
-extern "C" int android_native_main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) {
- // do nothing for now; just leave it alive. good night.
- for (;;) {
- sleep(1000);
+#include <binder_rpc_unstable.hpp>
+#include <chrono>
+#include <random>
+#include <string>
+
+#include "android-base/logging.h"
+
+using aidl::android::system::virtualmachineservice::IVirtualMachineService;
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+using android::base::unique_fd;
+
+namespace {
+constexpr uint64_t kBlockSizeBytes = 4096;
+
+class IOBenchmarkService : public aidl::com::android::microdroid::testservice::BnBenchmarkService {
+public:
+ ndk::ScopedAStatus readFile(const std::string& filename, int64_t fileSizeBytes, bool isRand,
+ double* out) override {
+ if (auto res = read_file(filename, fileSizeBytes, isRand); res.ok()) {
+ *out = res.value();
+ } else {
+ std::stringstream error;
+ error << "Failed reading file: " << res.error();
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ error.str().c_str());
+ }
+ return ndk::ScopedAStatus::ok();
}
+
+private:
+ /** Returns the elapsed seconds for reading the file. */
+ Result<double> read_file(const std::string& filename, int64_t fileSizeBytes, bool is_rand) {
+ const int64_t block_count = fileSizeBytes / kBlockSizeBytes;
+ std::vector<uint64_t> offsets;
+ if (is_rand) {
+ std::mt19937 rd{std::random_device{}()};
+ offsets.reserve(block_count);
+ for (auto i = 0; i < block_count; ++i) offsets.push_back(i * kBlockSizeBytes);
+ std::shuffle(offsets.begin(), offsets.end(), rd);
+ }
+ char buf[kBlockSizeBytes];
+
+ clock_t start = clock();
+ unique_fd fd(open(filename.c_str(), O_RDONLY | O_CLOEXEC));
+ if (fd.get() == -1) {
+ return ErrnoError() << "Read: opening " << filename << " failed";
+ }
+ for (auto i = 0; i < block_count; ++i) {
+ if (is_rand) {
+ if (lseek(fd.get(), offsets[i], SEEK_SET) == -1) {
+ return ErrnoError() << "failed to lseek";
+ }
+ }
+ auto bytes = read(fd.get(), buf, kBlockSizeBytes);
+ if (bytes == 0) {
+ return Error() << "unexpected end of file";
+ } else if (bytes == -1) {
+ return ErrnoError() << "failed to read";
+ }
+ }
+ return {((double)clock() - start) / CLOCKS_PER_SEC};
+ }
+};
+
+Result<void> run_io_benchmark_tests() {
+ auto test_service = ndk::SharedRefBase::make<IOBenchmarkService>();
+ auto callback = []([[maybe_unused]] void* param) {
+ // Tell microdroid_manager that we're ready.
+ // If we can't, abort in order to fail fast - the host won't proceed without
+ // receiving the onReady signal.
+ ndk::SpAIBinder binder(
+ RpcClient(VMADDR_CID_HOST, IVirtualMachineService::VM_BINDER_SERVICE_PORT));
+ auto vm_service = IVirtualMachineService::fromBinder(binder);
+ if (vm_service == nullptr) {
+ LOG(ERROR) << "failed to connect VirtualMachineService\n";
+ abort();
+ }
+ if (auto status = vm_service->notifyPayloadReady(); !status.isOk()) {
+ LOG(ERROR) << "failed to notify payload ready to virtualizationservice: "
+ << status.getDescription();
+ abort();
+ }
+ };
+
+ if (!RunRpcServerCallback(test_service->asBinder().get(), test_service->SERVICE_PORT, callback,
+ nullptr)) {
+ return Error() << "RPC Server failed to run";
+ }
+ return {};
+}
+} // Anonymous namespace
+
+extern "C" int android_native_main([[maybe_unused]] int argc, char* argv[]) {
+ if (strcmp(argv[1], "no_io") == 0) {
+ // do nothing for now; just leave it alive. good night.
+ for (;;) {
+ sleep(1000);
+ }
+ } else if (strcmp(argv[1], "io") == 0) {
+ if (auto res = run_io_benchmark_tests(); res.ok()) {
+ return 0;
+ } else {
+ LOG(ERROR) << "IO benchmark test failed: " << res.error() << "\n";
+ return 1;
+ }
+ }
+ return 0;
}
diff --git a/tests/helper/src/java/com/android/microdroid/test/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/MicrodroidDeviceTestBase.java
index a2c43d7..1f57634 100644
--- a/tests/helper/src/java/com/android/microdroid/test/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/MicrodroidDeviceTestBase.java
@@ -139,7 +139,7 @@
protected abstract static class VmEventListener implements VirtualMachineCallback {
private ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
- void runToFinish(String logTag, VirtualMachine vm)
+ public void runToFinish(String logTag, VirtualMachine vm)
throws VirtualMachineException, InterruptedException {
vm.setCallback(mExecutorService, this);
vm.run();
@@ -148,7 +148,7 @@
mExecutorService.awaitTermination(300, TimeUnit.SECONDS);
}
- void forceStop(VirtualMachine vm) {
+ protected void forceStop(VirtualMachine vm) {
try {
vm.clearCallback();
vm.stop();
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 1141106..b429e4d 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -157,6 +157,26 @@
}
@Test
+ public void bootFailsWhenLowMem() throws VirtualMachineException, InterruptedException {
+ VirtualMachineConfig lowMemConfig = mInner.newVmConfigBuilder("assets/vm_config.json")
+ .memoryMib(20)
+ .debugLevel(DebugLevel.NONE)
+ .build();
+ VirtualMachine vm = mInner.forceCreateNewVirtualMachine("low_mem", lowMemConfig);
+ final CompletableFuture<Integer> exception = new CompletableFuture<>();
+ VmEventListener listener =
+ new VmEventListener() {
+ @Override
+ public void onDied(VirtualMachine vm, @DeathReason int reason) {
+ exception.complete(reason);
+ super.onDied(vm, reason);
+ }
+ };
+ listener.runToFinish(TAG, vm);
+ assertThat(exception.getNow(0)).isAnyOf(DeathReason.REBOOT, DeathReason.HANGUP);
+ }
+
+ @Test
public void changingDebugLevelInvalidatesVmIdentity()
throws VirtualMachineException, InterruptedException, IOException {
assume()
diff --git a/zipfuse/src/main.rs b/zipfuse/src/main.rs
index 874056a..8400a72 100644
--- a/zipfuse/src/main.rs
+++ b/zipfuse/src/main.rs
@@ -41,7 +41,7 @@
let matches = App::new("zipfuse")
.arg(
Arg::with_name("options")
- .short("o")
+ .short('o')
.takes_value(true)
.required(false)
.help("Comma separated list of mount options"),