Merge "Skip 25Q1 (ab/BP1A.250305.020) in aosp-main-future" into aosp-main-future
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index d47afc4..1c078ce 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -19,6 +19,3 @@
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
rustfmt = --config-path=rustfmt.toml
ktfmt = --kotlinlang-style
-
-[Hook Scripts]
-aosp_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "."
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
index 4aac37a..a9b4abe 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
@@ -38,6 +38,7 @@
import android.system.virtualmachine.VirtualMachineException
import android.util.Log
import android.widget.Toast
+import com.android.internal.annotations.GuardedBy
import com.android.system.virtualmachine.flags.Flags.terminalGuiSupport
import com.android.virtualization.terminal.MainActivity.Companion.TAG
import com.android.virtualization.terminal.Runner.Companion.create
@@ -55,6 +56,7 @@
import java.io.FileOutputStream
import java.io.IOException
import java.lang.RuntimeException
+import java.lang.Math.min
import java.net.InetSocketAddress
import java.net.SocketAddress
import java.nio.file.Files
@@ -75,6 +77,40 @@
private var server: Server? = null
private var debianService: DebianServiceImpl? = null
private var portNotifier: PortNotifier? = null
+ private var mLock = Object()
+ @GuardedBy("mLock")
+ private var currentMemBalloonPercent = 0;
+
+ @GuardedBy("mLock")
+ private val inflateMemBalloonHandler = Handler(Looper.getMainLooper())
+ private val inflateMemBalloonTask: Runnable = object : Runnable {
+ override fun run() {
+ synchronized(mLock) {
+ if (currentMemBalloonPercent < INITIAL_MEM_BALLOON_PERCENT
+ || currentMemBalloonPercent > MAX_MEM_BALLOON_PERCENT
+ ) {
+ Log.e(
+ TAG, "currentBalloonPercent=$currentMemBalloonPercent is invalid," +
+ " should be in range: " +
+ "$INITIAL_MEM_BALLOON_PERCENT~$MAX_MEM_BALLOON_PERCENT"
+ )
+ return
+ }
+ // Increases the balloon size by MEM_BALLOON_PERCENT_STEP% every time
+ if (currentMemBalloonPercent < MAX_MEM_BALLOON_PERCENT) {
+ currentMemBalloonPercent =
+ min(
+ MAX_MEM_BALLOON_PERCENT,
+ currentMemBalloonPercent + MEM_BALLOON_PERCENT_STEP
+ )
+ virtualMachine?.setMemoryBalloonByPercent(currentMemBalloonPercent)
+ inflateMemBalloonHandler.postDelayed(this,
+ MEM_BALLOON_INFLATE_INTERVAL_MILLIS)
+ }
+ }
+ }
+ }
+
interface VmLauncherServiceCallback {
fun onVmStart()
@@ -99,13 +135,26 @@
// When the app starts, reset the memory balloon to 0%.
// This gives the app maximum available memory.
ApplicationLifeCycleEvent.APP_ON_START -> {
- virtualMachine?.setMemoryBalloonByPercent(0)
+ synchronized(mLock) {
+ inflateMemBalloonHandler.removeCallbacks(inflateMemBalloonTask);
+ currentMemBalloonPercent = 0;
+ virtualMachine?.setMemoryBalloonByPercent(currentMemBalloonPercent)
+ }
}
ApplicationLifeCycleEvent.APP_ON_STOP -> {
- // When the app stops, inflate the memory balloon to 10%.
- // This allows the system to reclaim memory while the app is in the background.
- // TODO(b/400590341) Inflate the balloon while the application remains Stop status.
- virtualMachine?.setMemoryBalloonByPercent(10)
+ // When the app stops, inflate the memory balloon to INITIAL_MEM_BALLOON_PERCENT.
+ // Inflate the balloon by MEM_BALLOON_PERCENT_STEP every
+ // MEM_BALLOON_INFLATE_INTERVAL_MILLIS milliseconds until reaching
+ // MAX_MEM_BALLOON_PERCENT of total memory. This allows the system to reclaim
+ // memory while the app is in the background.
+ synchronized(mLock) {
+ currentMemBalloonPercent = INITIAL_MEM_BALLOON_PERCENT;
+ virtualMachine?.setMemoryBalloonByPercent(currentMemBalloonPercent)
+ inflateMemBalloonHandler.postDelayed(
+ inflateMemBalloonTask,
+ MEM_BALLOON_INFLATE_INTERVAL_MILLIS
+ );
+ }
}
else -> {
Log.e(TAG, "unrecognized lifecycle event: $event")
@@ -388,6 +437,11 @@
private const val RESULT_STOP = 1
private const val RESULT_ERROR = 2
+ private const val INITIAL_MEM_BALLOON_PERCENT = 10
+ private const val MAX_MEM_BALLOON_PERCENT = 50
+ private const val MEM_BALLOON_INFLATE_INTERVAL_MILLIS = 60000L
+ private const val MEM_BALLOON_PERCENT_STEP = 5;
+
private fun getMyIntent(context: Context): Intent {
return Intent(context.getApplicationContext(), VmLauncherService::class.java)
}
diff --git a/android/vm/vm_shell.sh b/android/vm/vm_shell.sh
index 60d9329..cac5781 100755
--- a/android/vm/vm_shell.sh
+++ b/android/vm/vm_shell.sh
@@ -50,15 +50,13 @@
}
function list_cids() {
- local selected_cid=$1
- local available_cids=$(adb shell /apex/com.android.virt/bin/vm list | awk 'BEGIN { FS="[:,]" } /cid/ { print $2; }')
- echo "${available_cids}"
+ adb shell /apex/com.android.virt/bin/vm list | awk 'BEGIN { FS="[:,]" } /cid/ { print $2; }'
}
function handle_connect_cmd() {
selected_cid=$1
- available_cids=$(list_cids)
+ available_cids=($(list_cids))
if [ -z "${available_cids}" ]; then
echo No VM is available
@@ -66,11 +64,11 @@
fi
if [ ! -n "${selected_cid}" ]; then
- if [ ${#selected_cid[@]} -eq 1 ]; then
+ if [ ${#available_cids[@]} -eq 1 ]; then
selected_cid=${available_cids[0]}
else
PS3="Select CID of VM to adb-shell into: "
- select cid in ${available_cids}
+ select cid in ${available_cids[@]}
do
selected_cid=${cid}
break
diff --git a/tests/backcompat_test/Android.bp b/tests/backcompat_test/Android.bp
index aa1e089..d47487a 100644
--- a/tests/backcompat_test/Android.bp
+++ b/tests/backcompat_test/Android.bp
@@ -14,6 +14,7 @@
"libanyhow",
"liblibc",
"libnix",
+ "librustutils",
"libvmclient",
"liblog_rust",
],
diff --git a/tests/backcompat_test/src/main.rs b/tests/backcompat_test/src/main.rs
index b92049d..eaf3365 100644
--- a/tests/backcompat_test/src/main.rs
+++ b/tests/backcompat_test/src/main.rs
@@ -25,6 +25,7 @@
use anyhow::anyhow;
use anyhow::Context;
use anyhow::Error;
+use anyhow::Result;
use log::info;
use std::fs::read_to_string;
use std::fs::File;
@@ -46,11 +47,11 @@
/// Runs a protected VM and validates it against a golden device tree.
#[test]
-fn test_device_tree_protected_compat() -> Result<(), Error> {
+fn test_device_tree_protected_compat() -> Result<()> {
run_test(true, GOLDEN_DEVICE_TREE_PROTECTED)
}
-fn run_test(protected: bool, golden_dt: &str) -> Result<(), Error> {
+fn run_test(protected: bool, golden_dt: &str) -> Result<()> {
let kernel = Some(open_payload(VMBASE_EXAMPLE_KERNEL_PATH)?);
android_logger::init_once(
android_logger::Config::default()
@@ -142,7 +143,8 @@
{
return Err(anyhow!("failed to execute dtc"));
}
- let dtcompare_res = Command::new("./dtcompare")
+ let mut dtcompare_cmd = Command::new("./dtcompare");
+ dtcompare_cmd
.arg("--dt1")
.arg("dump_dt_golden.dtb")
.arg("--dt2")
@@ -162,12 +164,23 @@
.arg("/chosen/linux,initrd-start")
.arg("--ignore-path-value")
.arg("/chosen/linux,initrd-end")
- .arg("--ignore-path-value")
- .arg("/avf/secretkeeper_public_key")
.arg("--ignore-path")
- .arg("/avf/name")
- .output()
- .context("failed to execute dtcompare")?;
+ .arg("/avf/name");
+ // Check if Secretkeeper is advertised. If not, check the vendor API level. Secretkeeper is
+ // required as of 202504, and if missing, the test should fail.
+ // Otherwise, ignore the fields, as they are not required.
+ if service.isUpdatableVmSupported()? {
+ dtcompare_cmd.arg("--ignore-path-value").arg("/avf/secretkeeper_public_key");
+ } else if vsr_api_level()? >= 202504 {
+ return Err(anyhow!("Secretkeeper support missing on vendor API >= 202504. Secretkeeper needs to be implemented."));
+ } else {
+ dtcompare_cmd
+ .arg("--ignore-path")
+ .arg("/avf/secretkeeper_public_key")
+ .arg("--ignore-path")
+ .arg("/avf/untrusted/defer-rollback-protection");
+ }
+ let dtcompare_res = dtcompare_cmd.output().context("failed to execute dtcompare")?;
if !dtcompare_res.status.success() {
if !Command::new("./dtc_static")
.arg("-I")
@@ -202,7 +215,17 @@
Ok(())
}
-fn open_payload(path: &str) -> Result<ParcelFileDescriptor, Error> {
+fn open_payload(path: &str) -> Result<ParcelFileDescriptor> {
let file = File::open(path).with_context(|| format!("Failed to open VM image {path}"))?;
Ok(ParcelFileDescriptor::new(file))
}
+
+fn vsr_api_level() -> Result<i32> {
+ get_sysprop_i32("ro.vendor.api_level")
+}
+
+fn get_sysprop_i32(prop: &str) -> Result<i32> {
+ let res = rustutils::system_properties::read(prop)?;
+ res.map(|val| val.parse::<i32>().with_context(|| format!("Failed to read {prop}")))
+ .unwrap_or(Ok(-1))
+}
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
index 59a57f1..5513af6 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
@@ -1463,7 +1463,7 @@
}
private void ensureUpdatableVmSupported() throws DeviceNotAvailableException {
- if (PropertyUtil.isVendorApiLevelAtLeast(getAndroidDevice(), 202504)) {
+ if (PropertyUtil.getVsrApiLevel(getAndroidDevice()) >= 202504) {
assertTrue(
"Missing Updatable VM support, have you declared Secretkeeper interface?",
isUpdatableVmSupported());