diff --git a/libs/vsutil/Android.bp b/libs/vsutil/Android.bp deleted file mode 100644 index ccb36a07..00000000 --- a/libs/vsutil/Android.bp +++ /dev/null @@ -1,26 +0,0 @@ -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -rust_library { - name: "libvsutil", - crate_name: "vsutil", - srcs: ["src/lib.rs"], - // Only build on targets which crosvm builds on. - enabled: false, - target: { - android64: { - compile_multilib: "64", - enabled: true, - }, - linux_bionic_arm64: { - enabled: true, - }, - }, - rustlibs: [ - "android.system.virtualizationservice-rust", - "libbinder_rs", - "libdisk", - ], - apex_available: ["com.android.virt"], -} diff --git a/libs/vsutil/src/file.rs b/libs/vsutil/src/file.rs deleted file mode 100644 index 4adaae16..00000000 --- a/libs/vsutil/src/file.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2023, 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. - -//! Functions to process files. - -use binder::{self, ExceptionCode, ParcelFileDescriptor, Status}; -use std::fs::File; - -/// Converts a `&ParcelFileDescriptor` to a `File` by cloning the file. -pub fn clone_file(fd: &ParcelFileDescriptor) -> binder::Result { - fd.as_ref().try_clone().map_err(|e| { - Status::new_exception_str( - ExceptionCode::BAD_PARCELABLE, - Some(format!("Failed to clone File from ParcelFileDescriptor: {:?}", e)), - ) - }) -} diff --git a/libs/vsutil/src/lib.rs b/libs/vsutil/src/lib.rs deleted file mode 100644 index cac888a0..00000000 --- a/libs/vsutil/src/lib.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2023, 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. - -//! This library provides utility functions used by both various -//! Virtualization services. - -mod file; -mod partition; - -pub use file::clone_file; -pub use partition::init_writable_partition; diff --git a/libs/vsutil/src/partition.rs b/libs/vsutil/src/partition.rs deleted file mode 100644 index a4e72dee..00000000 --- a/libs/vsutil/src/partition.rs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2023, 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. - -//! Functions to process partitions. - -use crate::file::clone_file; -use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{ - PartitionType::PartitionType, -}; -use binder::{self, ExceptionCode, ParcelFileDescriptor, Status}; -use disk::QcowFile; -use std::io::{Error, ErrorKind, Write}; - -/// crosvm requires all partitions to be a multiple of 4KiB. -const PARTITION_GRANULE_BYTES: u64 = 4096; - -/// Initialize an empty partition image of the given size to be used as a writable partition. -pub fn init_writable_partition( - image_fd: &ParcelFileDescriptor, - size_bytes: i64, - partition_type: PartitionType, -) -> binder::Result<()> { - let size_bytes = size_bytes.try_into().map_err(|e| { - Status::new_exception_str( - ExceptionCode::ILLEGAL_ARGUMENT, - Some(format!("Invalid size {}: {:?}", size_bytes, e)), - ) - })?; - let size_bytes = round_up(size_bytes, PARTITION_GRANULE_BYTES); - let image = clone_file(image_fd)?; - // initialize the file. Any data in the file will be erased. - image.set_len(0).map_err(|e| { - Status::new_service_specific_error_str(-1, Some(format!("Failed to reset a file: {:?}", e))) - })?; - let mut part = QcowFile::new(image, size_bytes).map_err(|e| { - Status::new_service_specific_error_str( - -1, - Some(format!("Failed to create QCOW2 image: {:?}", e)), - ) - })?; - - match partition_type { - PartitionType::RAW => Ok(()), - PartitionType::ANDROID_VM_INSTANCE => format_as_android_vm_instance(&mut part), - PartitionType::ENCRYPTEDSTORE => format_as_encryptedstore(&mut part), - _ => Err(Error::new( - ErrorKind::Unsupported, - format!("Unsupported partition type {:?}", partition_type), - )), - } - .map_err(|e| { - Status::new_service_specific_error_str( - -1, - Some(format!("Failed to initialize partition as {:?}: {:?}", partition_type, e)), - ) - }) -} - -fn round_up(input: u64, granule: u64) -> u64 { - if granule == 0 { - return input; - } - // If the input is absurdly large we round down instead of up; it's going to fail anyway. - let result = input.checked_add(granule - 1).unwrap_or(input); - (result / granule) * granule -} - -fn format_as_android_vm_instance(part: &mut dyn Write) -> std::io::Result<()> { - const ANDROID_VM_INSTANCE_MAGIC: &str = "Android-VM-instance"; - const ANDROID_VM_INSTANCE_VERSION: u16 = 1; - - part.write_all(ANDROID_VM_INSTANCE_MAGIC.as_bytes())?; - part.write_all(&ANDROID_VM_INSTANCE_VERSION.to_le_bytes())?; - part.flush() -} - -fn format_as_encryptedstore(part: &mut dyn Write) -> std::io::Result<()> { - const UNFORMATTED_STORAGE_MAGIC: &str = "UNFORMATTED-STORAGE"; - - part.write_all(UNFORMATTED_STORAGE_MAGIC.as_bytes())?; - part.flush() -} diff --git a/virtualizationmanager/Android.bp b/virtualizationmanager/Android.bp index fedfd76b..59e507f8 100644 --- a/virtualizationmanager/Android.bp +++ b/virtualizationmanager/Android.bp @@ -54,7 +54,6 @@ rust_defaults { "libtombstoned_client_rust", "libvm_control", "libvmconfig", - "libvsutil", "libzip", "libvsock", "liblibfdt", diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs index 4bc25dac..468ee19a 100644 --- a/virtualizationmanager/src/aidl.rs +++ b/virtualizationmanager/src/aidl.rs @@ -53,6 +53,7 @@ use binder::{ self, wait_for_interface, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, Status, StatusCode, Strong, }; +use disk::QcowFile; use lazy_static::lazy_static; use log::{debug, error, info, warn}; use microdroid_payload_config::{OsConfig, Task, TaskType, VmPayloadConfig}; @@ -63,7 +64,7 @@ use semver::VersionReq; use std::convert::TryInto; use std::ffi::CStr; use std::fs::{read_dir, remove_file, File, OpenOptions}; -use std::io::{BufRead, BufReader, Write}; +use std::io::{BufRead, BufReader, Error, ErrorKind, Write}; use std::num::{NonZeroU16, NonZeroU32}; use std::os::unix::io::{FromRawFd, IntoRawFd}; use std::os::unix::raw::pid_t; @@ -71,7 +72,6 @@ use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex, Weak}; use vmconfig::VmConfig; use vsock::VsockStream; -use vsutil::{clone_file, init_writable_partition}; use zip::ZipArchive; /// The unique ID of a VM used (together with a port number) for vsock communication. @@ -83,8 +83,19 @@ pub const BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtualizationservic /// Gaps in composite disk images are filled with a shared zero.img. const ZERO_FILLER_SIZE: u64 = 4096; +/// Magic string for the instance image +const ANDROID_VM_INSTANCE_MAGIC: &str = "Android-VM-instance"; + +/// Version of the instance image format +const ANDROID_VM_INSTANCE_VERSION: u16 = 1; + const MICRODROID_OS_NAME: &str = "microdroid"; +const UNFORMATTED_STORAGE_MAGIC: &str = "UNFORMATTED-STORAGE"; + +/// crosvm requires all partitions to be a multiple of 4KiB. +const PARTITION_GRANULARITY_BYTES: u64 = 4096; + lazy_static! { pub static ref GLOBAL_SERVICE: Strong = wait_for_interface(BINDER_SERVICE_IDENTIFIER) @@ -178,7 +189,45 @@ impl IVirtualizationService for VirtualizationService { partition_type: PartitionType, ) -> binder::Result<()> { check_manage_access()?; - init_writable_partition(image_fd, size_bytes, partition_type) + let size_bytes = size_bytes.try_into().map_err(|e| { + Status::new_exception_str( + ExceptionCode::ILLEGAL_ARGUMENT, + Some(format!("Invalid size {}: {:?}", size_bytes, e)), + ) + })?; + let size_bytes = round_up(size_bytes, PARTITION_GRANULARITY_BYTES); + let image = clone_file(image_fd)?; + // initialize the file. Any data in the file will be erased. + image.set_len(0).map_err(|e| { + Status::new_service_specific_error_str( + -1, + Some(format!("Failed to reset a file: {:?}", e)), + ) + })?; + let mut part = QcowFile::new(image, size_bytes).map_err(|e| { + Status::new_service_specific_error_str( + -1, + Some(format!("Failed to create QCOW2 image: {:?}", e)), + ) + })?; + + match partition_type { + PartitionType::RAW => Ok(()), + PartitionType::ANDROID_VM_INSTANCE => format_as_android_vm_instance(&mut part), + PartitionType::ENCRYPTEDSTORE => format_as_encryptedstore(&mut part), + _ => Err(Error::new( + ErrorKind::Unsupported, + format!("Unsupported partition type {:?}", partition_type), + )), + } + .map_err(|e| { + Status::new_service_specific_error_str( + -1, + Some(format!("Failed to initialize partition as {:?}: {:?}", partition_type, e)), + ) + })?; + + Ok(()) } /// Creates or update the idsig file by digesting the input APK file. @@ -435,6 +484,26 @@ fn write_zero_filler(zero_filler_path: &Path) -> Result<()> { Ok(()) } +fn format_as_android_vm_instance(part: &mut dyn Write) -> std::io::Result<()> { + part.write_all(ANDROID_VM_INSTANCE_MAGIC.as_bytes())?; + part.write_all(&ANDROID_VM_INSTANCE_VERSION.to_le_bytes())?; + part.flush() +} + +fn format_as_encryptedstore(part: &mut dyn Write) -> std::io::Result<()> { + part.write_all(UNFORMATTED_STORAGE_MAGIC.as_bytes())?; + part.flush() +} + +fn round_up(input: u64, granularity: u64) -> u64 { + if granularity == 0 { + return input; + } + // If the input is absurdly large we round down instead of up; it's going to fail anyway. + let result = input.checked_add(granularity - 1).unwrap_or(input); + (result / granularity) * granularity +} + /// Given the configuration for a disk image, assembles the `DiskFile` to pass to crosvm. /// /// This may involve assembling a composite disk from a set of partition images. @@ -886,6 +955,16 @@ fn get_state(instance: &VmInstance) -> VirtualMachineState { } } +/// Converts a `&ParcelFileDescriptor` to a `File` by cloning the file. +pub fn clone_file(file: &ParcelFileDescriptor) -> Result { + file.as_ref().try_clone().map_err(|e| { + Status::new_exception_str( + ExceptionCode::BAD_PARCELABLE, + Some(format!("Failed to clone File from ParcelFileDescriptor: {:?}", e)), + ) + }) +} + /// Converts an `&Option` to an `Option` by cloning the file. fn maybe_clone_file(file: &Option) -> Result, Status> { file.as_ref().map(clone_file).transpose() diff --git a/virtualizationmanager/src/atom.rs b/virtualizationmanager/src/atom.rs index 5118a8d0..d6eb1417 100644 --- a/virtualizationmanager/src/atom.rs +++ b/virtualizationmanager/src/atom.rs @@ -14,7 +14,7 @@ //! Functions for creating and collecting atoms. -use crate::aidl::GLOBAL_SERVICE; +use crate::aidl::{clone_file, GLOBAL_SERVICE}; use crate::crosvm::VmMetric; use crate::get_calling_uid; use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::DeathReason::DeathReason; @@ -37,7 +37,6 @@ use microdroid_payload_config::VmPayloadConfig; use statslog_virtualization_rust::vm_creation_requested; use std::thread; use std::time::{Duration, SystemTime}; -use vsutil::clone_file; use zip::ZipArchive; const INVALID_NUM_CPUS: i32 = -1;