Merge "Fix threading bugs"
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index b8e85e7..73c36aa 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -18,7 +18,6 @@
mod instance;
mod ioutil;
mod payload;
-mod procutil;
mod swap;
mod vm_payload_service;
@@ -26,12 +25,8 @@
use crate::instance::{ApexData, ApkData, InstanceDisk, MicrodroidData, RootHash};
use crate::vm_payload_service::register_vm_payload_service;
use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::ErrorCode::ErrorCode;
-use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::{
- IVirtualMachineService::{
+use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::{
IVirtualMachineService, VM_BINDER_SERVICE_PORT, VM_STREAM_SERVICE_PORT,
- },
- 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};
@@ -46,7 +41,6 @@
use microdroid_payload_config::{OsConfig, Task, TaskType, VmPayloadConfig};
use openssl::sha::Sha512;
use payload::{get_apex_data_from_payload, load_metadata, to_metadata};
-use procutil::{get_cpu_time, get_mem_info};
use rand::Fill;
use rpcbinder::get_vsock_rpc_interface;
use rustutils::system_properties;
@@ -59,12 +53,10 @@
use std::path::Path;
use std::process::{Child, Command, Stdio};
use std::str;
-use std::thread;
use std::time::{Duration, SystemTime};
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";
@@ -97,42 +89,6 @@
InvalidConfig(String),
}
-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()))?;
-
- loop {
- send_vm_status(&service)?;
- thread::sleep(SENDING_VM_STATUS_CYCLE_PERIOD);
- }
-}
-
fn translate_error(err: &Error) -> (ErrorCode, String) {
if let Some(e) = err.downcast_ref::<MicrodroidError>() {
match e {
@@ -225,12 +181,6 @@
.context("cannot connect to VirtualMachineService")
.map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
- thread::spawn(move || {
- if let Err(e) = send_vm_status_periodically() {
- error!("failed to get virtual machine status: {:?}", e);
- }
- });
-
match try_run_payload(&service) {
Ok(code) => {
info!("notifying payload finished");
@@ -450,8 +400,6 @@
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")
}
@@ -783,7 +731,6 @@
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."))
}
diff --git a/microdroid_manager/src/procutil.rs b/microdroid_manager/src/procutil.rs
deleted file mode 100644
index f9479c4..0000000
--- a/microdroid_manager/src/procutil.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-// 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.
-
-use anyhow::{bail, Result};
-use libc::{sysconf, _SC_CLK_TCK};
-use std::fs::File;
-use std::io::{BufRead, BufReader};
-
-const MILLIS_PER_SEC: i64 = 1000;
-
-pub struct CpuTime {
- pub user: i64,
- pub nice: i64,
- pub sys: i64,
- pub idle: i64,
-}
-
-pub struct MemInfo {
- pub total: i64,
- pub free: i64,
- pub available: i64,
- pub buffer: i64,
- pub cached: i64,
-}
-
-// Get CPU time information from /proc/stat
-//
-// /proc/stat example(omitted):
-// cpu 24790952 21104390 10771070 10480973587 1700955 0 410931 0 316532 0
-// cpu0 169636 141307 61153 81785791 9605 0 183524 0 1345 0
-// cpu1 182431 198327 68273 81431817 10445 0 32392 0 2616 0
-// cpu2 183209 174917 68591 81933935 12239 0 10042 0 2415 0
-// cpu3 183413 177758 69908 81927474 13354 0 5853 0 2491 0
-// intr 7913477443 39 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-// ctxt 10326710014
-// btime 1664123605
-// processes 9225712
-// procs_running 1
-// procs_blocked 0
-// softirq 2683914305 14595298 304837101 1581 327291100 16397051 0 208857783 1024640365 787932 786506094
-//
-// expected output:
-// user: 24790952
-// nice: 21104390
-// sys: 10771070
-// idle: 10480973587
-pub fn get_cpu_time() -> Result<CpuTime> {
- let mut proc_stat = BufReader::new(File::open("/proc/stat")?);
- let mut line = String::new();
- proc_stat.read_line(&mut line)?;
- let data_list: Vec<_> = line.split_whitespace().filter_map(|s| s.parse::<i64>().ok()).collect();
- if data_list.len() < 4 {
- bail!("Failed to extract numeric values in /proc/stat :\n{}", line);
- }
-
- let ticks_per_sec = unsafe { sysconf(_SC_CLK_TCK) } as i64;
- let cpu_time = CpuTime {
- user: data_list[0] * MILLIS_PER_SEC / ticks_per_sec,
- nice: data_list[1] * MILLIS_PER_SEC / ticks_per_sec,
- sys: data_list[2] * MILLIS_PER_SEC / ticks_per_sec,
- idle: data_list[3] * MILLIS_PER_SEC / ticks_per_sec,
- };
- Ok(cpu_time)
-}
-
-// Get memory information from /proc/meminfo
-//
-// /proc/meminfo example(omitted):
-// MemTotal: 263742736 kB
-// MemFree: 37144204 kB
-// MemAvailable: 249168700 kB
-// Buffers: 10231296 kB
-// Cached: 189502836 kB
-// SwapCached: 113848 kB
-// Active: 132266424 kB
-// Inactive: 73587504 kB
-// Active(anon): 1455240 kB
-// Inactive(anon): 6993584 kB
-// Active(file): 130811184 kB
-// Inactive(file): 66593920 kB
-// Unevictable: 56436 kB
-// Mlocked: 56436 kB
-// SwapTotal: 255123452 kB
-// SwapFree: 254499068 kB
-// Dirty: 596 kB
-// Writeback: 0 kB
-// AnonPages: 5295864 kB
-// Mapped: 3512608 kB
-//
-// expected output:
-// total: 263742736
-// free: 37144204
-// available: 249168700
-// buffer: 10231296
-// cached: 189502836
-pub fn get_mem_info() -> Result<MemInfo> {
- let mut proc_stat = BufReader::new(File::open("/proc/meminfo")?);
- let mut lines = String::new();
- for _ in 0..5 {
- proc_stat.read_line(&mut lines)?;
- }
- let data_list: Vec<_> =
- lines.split_whitespace().filter_map(|s| s.parse::<i64>().ok()).collect();
- if data_list.len() != 5 {
- bail!("Failed to extract numeric values in /proc/meminfo :\n{}", lines);
- }
-
- let mem_info = MemInfo {
- total: data_list[0],
- free: data_list[1],
- available: data_list[2],
- buffer: data_list[3],
- cached: data_list[4],
- };
- Ok(mem_info)
-}
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
index 33788ed..c9df624 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 testTelemetryPushedAtomsOfEventMetrics() throws Exception {
+ public void testTelemetryPushedAtoms() throws Exception {
// Reset statsd config and report before the test
ConfigUtils.removeConfig(getDevice());
ReportUtils.clearReports(getDevice());
@@ -566,49 +566,6 @@
}
@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/virtualizationservice/Android.bp b/virtualizationservice/Android.bp
index 26d41c9..d6f4607 100644
--- a/virtualizationservice/Android.bp
+++ b/virtualizationservice/Android.bp
@@ -71,5 +71,8 @@
rust_test {
name: "virtualizationservice_device_test",
defaults: ["virtualizationservice_defaults"],
+ rustlibs: [
+ "libtempfile",
+ ],
test_suites: ["general-tests"],
}
diff --git a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
index 4fa5fa0..e8c1724 100644
--- a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
+++ b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
@@ -16,8 +16,6 @@
package android.system.virtualmachineservice;
import android.system.virtualizationcommon.ErrorCode;
-import android.system.virtualmachineservice.VirtualMachineCpuStatus;
-import android.system.virtualmachineservice.VirtualMachineMemStatus;
/** {@hide} */
interface IVirtualMachineService {
@@ -58,14 +56,4 @@
* Notifies that an error has occurred inside the VM..
*/
void notifyError(ErrorCode errorCode, in String message);
-
- /**
- * Notifies the current CPU status of the VM.
- */
- void notifyCpuStatus(in VirtualMachineCpuStatus cpuStatus);
-
- /**
- * Notifies the current memory status of the VM.
- */
- void notifyMemStatus(in VirtualMachineMemStatus memStatus);
}
diff --git a/virtualizationservice/aidl/android/system/virtualmachineservice/VirtualMachineCpuStatus.aidl b/virtualizationservice/aidl/android/system/virtualmachineservice/VirtualMachineCpuStatus.aidl
deleted file mode 100644
index 307c3f9..0000000
--- a/virtualizationservice/aidl/android/system/virtualmachineservice/VirtualMachineCpuStatus.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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 android.system.virtualmachineservice;
-
-parcelable VirtualMachineCpuStatus {
- long cpu_time_user;
- long cpu_time_nice;
- long cpu_time_sys;
- long cpu_time_idle;
-}
diff --git a/virtualizationservice/aidl/android/system/virtualmachineservice/VirtualMachineMemStatus.aidl b/virtualizationservice/aidl/android/system/virtualmachineservice/VirtualMachineMemStatus.aidl
deleted file mode 100644
index 3de57c6..0000000
--- a/virtualizationservice/aidl/android/system/virtualmachineservice/VirtualMachineMemStatus.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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 android.system.virtualmachineservice;
-
-parcelable VirtualMachineMemStatus {
- long mem_total;
- long mem_free;
- long mem_available;
- long mem_buffer;
- long mem_cached;
-}
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index b4ce9d2..bc697e3 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -14,10 +14,7 @@
//! Implementation of the AIDL interface of the VirtualizationService.
-use crate::atom::{
- write_vm_booted_stats, write_vm_cpu_status_stats, write_vm_creation_stats,
- write_vm_mem_status_stats,
-};
+use crate::atom::{write_vm_booted_stats, write_vm_creation_stats};
use crate::composite::make_composite_image;
use crate::crosvm::{CrosvmConfig, DiskFile, PayloadState, VmInstance, VmState};
use crate::payload::{add_microdroid_payload_images, add_microdroid_system_images};
@@ -39,13 +36,9 @@
VirtualMachineRawConfig::VirtualMachineRawConfig,
VirtualMachineState::VirtualMachineState,
};
-use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::{
- IVirtualMachineService::{
+use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::{
BnVirtualMachineService, IVirtualMachineService, VM_BINDER_SERVICE_PORT,
VM_STREAM_SERVICE_PORT, VM_TOMBSTONES_SERVICE_PORT,
- },
- VirtualMachineCpuStatus::VirtualMachineCpuStatus,
- VirtualMachineMemStatus::VirtualMachineMemStatus,
};
use anyhow::{anyhow, bail, Context, Result};
use apkverify::{HashAlgorithm, V4Signature};
@@ -1147,36 +1140,6 @@
))
}
}
-
- fn notifyCpuStatus(&self, status: &VirtualMachineCpuStatus) -> binder::Result<()> {
- let cid = self.cid;
- if let Some(vm) = self.state.lock().unwrap().get_vm(cid) {
- info!("VM with CID {} reported its CPU status", cid);
- write_vm_cpu_status_stats(vm.requester_uid as i32, &vm.name, status);
- Ok(())
- } else {
- error!("notifyCurrentStatus is called from an unknown CID {}", cid);
- Err(Status::new_service_specific_error_str(
- -1,
- Some(format!("cannot find a VM with CID {}", cid)),
- ))
- }
- }
-
- fn notifyMemStatus(&self, status: &VirtualMachineMemStatus) -> binder::Result<()> {
- let cid = self.cid;
- if let Some(vm) = self.state.lock().unwrap().get_vm(cid) {
- info!("VM with CID {} reported its memory status", cid);
- write_vm_mem_status_stats(vm.requester_uid as i32, &vm.name, status);
- Ok(())
- } else {
- error!("notifyCurrentStatus is called from an unknown CID {}", cid);
- Err(Status::new_service_specific_error_str(
- -1,
- Some(format!("cannot find a VM with CID {}", cid)),
- ))
- }
- }
}
impl VirtualMachineService {
diff --git a/virtualizationservice/src/atom.rs b/virtualizationservice/src/atom.rs
index 8c46ac5..eabb4cc 100644
--- a/virtualizationservice/src/atom.rs
+++ b/virtualizationservice/src/atom.rs
@@ -22,17 +22,11 @@
VirtualMachineConfig::VirtualMachineConfig,
};
use android_system_virtualizationservice::binder::{Status, Strong};
-use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::{
- VirtualMachineCpuStatus::VirtualMachineCpuStatus,
- VirtualMachineMemStatus::VirtualMachineMemStatus,
-};
use anyhow::{anyhow, Result};
use binder::{ParcelFileDescriptor, ThreadState};
use log::{trace, warn};
use microdroid_payload_config::VmPayloadConfig;
-use statslog_virtualization_rust::{
- vm_booted, vm_cpu_status_reported, vm_creation_requested, vm_exited, vm_mem_status_reported,
-};
+use statslog_virtualization_rust::{vm_booted, vm_creation_requested, vm_exited};
use std::time::{Duration, SystemTime};
use zip::ZipArchive;
@@ -212,48 +206,3 @@
Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
}
}
-
-/// Write the stats of VM cpu status to statsd
-pub fn write_vm_cpu_status_stats(
- uid: i32,
- vm_identifier: &String,
- cpu_status: &VirtualMachineCpuStatus,
-) {
- let vm_cpu_status_reported = vm_cpu_status_reported::VmCpuStatusReported {
- uid,
- vm_identifier,
- cpu_time_user_millis: cpu_status.cpu_time_user,
- cpu_time_nice_millis: cpu_status.cpu_time_nice,
- cpu_time_sys_millis: cpu_status.cpu_time_sys,
- cpu_time_idle_millis: cpu_status.cpu_time_idle,
- };
- match vm_cpu_status_reported.stats_write() {
- Err(e) => {
- warn!("statslog_rust failed with error: {}", e);
- }
- Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
- }
-}
-
-/// Write the stats of VM memory status to statsd
-pub fn write_vm_mem_status_stats(
- uid: i32,
- vm_identifier: &String,
- mem_status: &VirtualMachineMemStatus,
-) {
- let vm_mem_status_reported = vm_mem_status_reported::VmMemStatusReported {
- uid,
- vm_identifier,
- mem_total_kb: mem_status.mem_total,
- mem_free_kb: mem_status.mem_free,
- mem_available_kb: mem_status.mem_available,
- mem_buffer_kb: mem_status.mem_buffer,
- mem_cached_kb: mem_status.mem_cached,
- };
- match vm_mem_status_reported.stats_write() {
- Err(e) => {
- warn!("statslog_rust failed with error: {}", e);
- }
- Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
- }
-}
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index 4190fbb..233e74b 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -27,7 +27,9 @@
use microdroid_metadata::{ApexPayload, ApkPayload, Metadata, PayloadConfig, PayloadMetadata};
use microdroid_payload_config::{ApexConfig, VmPayloadConfig};
use once_cell::sync::OnceCell;
-use packagemanager_aidl::aidl::android::content::pm::IPackageManagerNative::IPackageManagerNative;
+use packagemanager_aidl::aidl::android::content::pm::{
+ IPackageManagerNative::IPackageManagerNative, StagedApexInfo::StagedApexInfo,
+};
use regex::Regex;
use serde::Deserialize;
use serde_xml_rs::from_reader;
@@ -48,7 +50,7 @@
const PACKAGE_MANAGER_NATIVE_SERVICE: &str = "package_native";
/// Represents the list of APEXes
-#[derive(Clone, Debug, Deserialize)]
+#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
struct ApexInfoList {
#[serde(rename = "apex-info")]
list: Vec<ApexInfo>,
@@ -58,6 +60,8 @@
struct ApexInfo {
#[serde(rename = "moduleName")]
name: String,
+ #[serde(rename = "versionCode")]
+ version: u64,
#[serde(rename = "modulePath")]
path: PathBuf,
@@ -101,6 +105,40 @@
Ok(apex_info_list)
})
}
+
+ // Override apex info with the staged one
+ fn override_staged_apex(&mut self, staged_apex_info: &StagedApexInfo) -> Result<()> {
+ let mut need_to_add: Option<ApexInfo> = None;
+ for apex_info in self.list.iter_mut() {
+ if staged_apex_info.moduleName == apex_info.name {
+ if apex_info.is_active && apex_info.is_factory {
+ // Copy the entry to the end as factory/non-active after the loop
+ // to keep the factory version. Typically this step is unncessary,
+ // but some apexes (like sharedlibs) need to be kept even if it's inactive.
+ need_to_add.replace(ApexInfo { is_active: false, ..apex_info.clone() });
+ // And make this one as non-factory. Note that this one is still active
+ // and overridden right below.
+ apex_info.is_factory = false;
+ }
+ // Active one is overridden with the staged one.
+ if apex_info.is_active {
+ apex_info.version = staged_apex_info.versionCode as u64;
+ apex_info.path = PathBuf::from(&staged_apex_info.diskImagePath);
+ apex_info.has_classpath_jar = staged_apex_info.hasClassPathJars;
+ apex_info.last_update_seconds = last_updated(&apex_info.path)?;
+ }
+ }
+ }
+ if let Some(info) = need_to_add {
+ self.list.push(info);
+ }
+ Ok(())
+ }
+}
+
+fn last_updated<P: AsRef<Path>>(path: P) -> Result<u64> {
+ let metadata = metadata(path)?;
+ Ok(metadata.modified()?.duration_since(SystemTime::UNIX_EPOCH)?.as_secs())
}
impl ApexInfo {
@@ -137,19 +175,11 @@
.context("Failed to get service when prefer_staged is set.")?;
let staged =
pm.getStagedApexModuleNames().context("getStagedApexModuleNames failed")?;
- for apex_info in list.list.iter_mut() {
- if staged.contains(&apex_info.name) {
- if let Some(staged_apex_info) =
- pm.getStagedApexInfo(&apex_info.name).context("getStagedApexInfo failed")?
- {
- apex_info.path = PathBuf::from(staged_apex_info.diskImagePath);
- apex_info.has_classpath_jar = staged_apex_info.hasClassPathJars;
- let metadata = metadata(&apex_info.path)?;
- apex_info.last_update_seconds =
- metadata.modified()?.duration_since(SystemTime::UNIX_EPOCH)?.as_secs();
- // by definition, staged apex can't be a factory apex.
- apex_info.is_factory = false;
- }
+ for name in staged {
+ if let Some(staged_apex_info) =
+ pm.getStagedApexInfo(&name).context("getStagedApexInfo failed")?
+ {
+ list.override_staged_apex(&staged_apex_info)?;
}
}
}
@@ -243,8 +273,13 @@
let apex_list = pm.get_apex_list(vm_payload_config.prefer_staged)?;
// collect APEXes from config
- let apex_infos =
+ let mut apex_infos =
collect_apex_infos(&apex_list, &vm_payload_config.apexes, app_config.debugLevel);
+
+ // Pass sorted list of apexes. Sorting key shouldn't use `path` because it will change after
+ // reboot with prefer_staged. `last_update_seconds` is added to distinguish "samegrade"
+ // update.
+ apex_infos.sort_by_key(|info| (&info.name, &info.version, &info.last_update_seconds));
info!("Microdroid payload APEXes: {:?}", apex_infos.iter().map(|ai| &ai.name));
let metadata_file = make_metadata_file(app_config, &apex_infos, temporary_directory)?;
@@ -422,6 +457,7 @@
#[cfg(test)]
mod tests {
use super::*;
+ use tempfile::NamedTempFile;
#[test]
fn test_find_apex_names_in_classpath() {
@@ -560,4 +596,90 @@
]
);
}
+
+ #[test]
+ fn test_prefer_staged_apex_with_factory_active_apex() {
+ let single_apex = ApexInfo {
+ name: "foo".to_string(),
+ version: 1,
+ path: PathBuf::from("foo.apex"),
+ is_factory: true,
+ is_active: true,
+ ..Default::default()
+ };
+ let mut apex_info_list = ApexInfoList { list: vec![single_apex.clone()] };
+
+ let staged = NamedTempFile::new().unwrap();
+ apex_info_list
+ .override_staged_apex(&StagedApexInfo {
+ moduleName: "foo".to_string(),
+ versionCode: 2,
+ diskImagePath: staged.path().to_string_lossy().to_string(),
+ ..Default::default()
+ })
+ .expect("should be ok");
+
+ assert_eq!(
+ apex_info_list,
+ ApexInfoList {
+ list: vec![
+ ApexInfo {
+ version: 2,
+ is_factory: false,
+ path: staged.path().to_owned(),
+ last_update_seconds: last_updated(staged.path()).unwrap(),
+ ..single_apex.clone()
+ },
+ ApexInfo { is_active: false, ..single_apex },
+ ],
+ }
+ );
+ }
+
+ #[test]
+ fn test_prefer_staged_apex_with_factory_and_inactive_apex() {
+ let factory_apex = ApexInfo {
+ name: "foo".to_string(),
+ version: 1,
+ path: PathBuf::from("foo.apex"),
+ is_factory: true,
+ ..Default::default()
+ };
+ let active_apex = ApexInfo {
+ name: "foo".to_string(),
+ version: 2,
+ path: PathBuf::from("foo.downloaded.apex"),
+ is_active: true,
+ ..Default::default()
+ };
+ let mut apex_info_list =
+ ApexInfoList { list: vec![factory_apex.clone(), active_apex.clone()] };
+
+ let staged = NamedTempFile::new().unwrap();
+ apex_info_list
+ .override_staged_apex(&StagedApexInfo {
+ moduleName: "foo".to_string(),
+ versionCode: 3,
+ diskImagePath: staged.path().to_string_lossy().to_string(),
+ ..Default::default()
+ })
+ .expect("should be ok");
+
+ assert_eq!(
+ apex_info_list,
+ ApexInfoList {
+ list: vec![
+ // factory apex isn't touched
+ factory_apex,
+ // update active one
+ ApexInfo {
+ version: 3,
+ path: staged.path().to_owned(),
+ last_update_seconds: last_updated(staged.path()).unwrap(),
+ ..active_apex
+ },
+ ],
+ }
+ );
+ }
}