Merge "Stop existing CursorHandler when a new one is created" into main
diff --git a/java/framework/src/android/system/virtualmachine/VirtualMachine.java b/java/framework/src/android/system/virtualmachine/VirtualMachine.java
index d54bd44..72a2429 100644
--- a/java/framework/src/android/system/virtualmachine/VirtualMachine.java
+++ b/java/framework/src/android/system/virtualmachine/VirtualMachine.java
@@ -71,7 +71,6 @@
 import android.system.virtualizationservice.IVirtualMachineCallback;
 import android.system.virtualizationservice.IVirtualizationService;
 import android.system.virtualizationservice.InputDevice;
-import android.system.virtualizationservice.MemoryTrimLevel;
 import android.system.virtualizationservice.PartitionType;
 import android.system.virtualizationservice.VirtualMachineAppConfig;
 import android.system.virtualizationservice.VirtualMachineRawConfig;
@@ -270,34 +269,35 @@
 
         @Override
         public void onTrimMemory(int level) {
-            @MemoryTrimLevel int vmTrimLevel;
+            int percent;
 
             switch (level) {
                 case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
-                    vmTrimLevel = MemoryTrimLevel.TRIM_MEMORY_RUNNING_CRITICAL;
+                    percent = 50;
                     break;
                 case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
-                    vmTrimLevel = MemoryTrimLevel.TRIM_MEMORY_RUNNING_LOW;
+                    percent = 30;
                     break;
                 case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
-                    vmTrimLevel = MemoryTrimLevel.TRIM_MEMORY_RUNNING_MODERATE;
+                    percent = 10;
                     break;
                 case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
                 case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
                 case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
                     /* Release as much memory as we can. The app is on the LMKD LRU kill list. */
-                    vmTrimLevel = MemoryTrimLevel.TRIM_MEMORY_RUNNING_CRITICAL;
+                    percent = 50;
                     break;
                 default:
                     /* Treat unrecognised messages as generic low-memory warnings. */
-                    vmTrimLevel = MemoryTrimLevel.TRIM_MEMORY_RUNNING_LOW;
+                    percent = 30;
                     break;
             }
 
             synchronized (mLock) {
                 try {
                     if (mVirtualMachine != null) {
-                        mVirtualMachine.onTrimMemory(vmTrimLevel);
+                        long bytes = mConfig.getMemoryBytes();
+                        mVirtualMachine.setMemoryBalloon(bytes * percent / 100);
                     }
                 } catch (Exception e) {
                     /* Caller doesn't want our exceptions. Log them instead. */
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index 425beed..2d83963 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -36,7 +36,6 @@
     IVirtualMachine::{BnVirtualMachine, IVirtualMachine},
     IVirtualMachineCallback::IVirtualMachineCallback,
     IVirtualizationService::IVirtualizationService,
-    MemoryTrimLevel::MemoryTrimLevel,
     Partition::Partition,
     PartitionType::PartitionType,
     VirtualMachineAppConfig::{DebugLevel::DebugLevel, Payload::Payload, VirtualMachineAppConfig},
@@ -1234,10 +1233,20 @@
             .or_service_specific_exception(-1)
     }
 
-    fn onTrimMemory(&self, level: MemoryTrimLevel) -> binder::Result<()> {
+    fn getMemoryBalloon(&self) -> binder::Result<i64> {
+        let balloon = self
+            .instance
+            .get_memory_balloon()
+            .with_context(|| format!("Error getting balloon for VM with CID {}", self.instance.cid))
+            .with_log()
+            .or_service_specific_exception(-1)?;
+        Ok(balloon.try_into().unwrap())
+    }
+
+    fn setMemoryBalloon(&self, num_bytes: i64) -> binder::Result<()> {
         self.instance
-            .trim_memory(level)
-            .with_context(|| format!("Error trimming VM with CID {}", self.instance.cid))
+            .set_memory_balloon(num_bytes.try_into().unwrap())
+            .with_context(|| format!("Error setting balloon for VM with CID {}", self.instance.cid))
             .with_log()
             .or_service_specific_exception(-1)
     }
diff --git a/virtualizationmanager/src/crosvm.rs b/virtualizationmanager/src/crosvm.rs
index 379a498..4787abc 100644
--- a/virtualizationmanager/src/crosvm.rs
+++ b/virtualizationmanager/src/crosvm.rs
@@ -44,7 +44,6 @@
 use std::thread::{self, JoinHandle};
 use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::DeathReason::DeathReason;
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
-    MemoryTrimLevel::MemoryTrimLevel,
     VirtualMachineAppConfig::DebugLevel::DebugLevel,
     AudioConfig::AudioConfig as AudioConfigParcelable,
     DisplayConfig::DisplayConfig as DisplayConfigParcelable,
@@ -627,42 +626,35 @@
 
     /// Responds to memory-trimming notifications by inflating the virtio
     /// balloon to reclaim guest memory.
-    pub fn trim_memory(&self, level: MemoryTrimLevel) -> Result<(), Error> {
+    pub fn get_memory_balloon(&self) -> Result<u64, Error> {
         let request = VmRequest::BalloonCommand(BalloonControlCommand::Stats {});
-        match vm_control::client::handle_request(&request, &self.crosvm_control_socket_path) {
-            Ok(VmResponse::BalloonStats { stats, balloon_actual: _ }) => {
-                if let Some(total_memory) = stats.total_memory {
-                    // Reclaim up to 50% of total memory assuming worst case
-                    // most memory is anonymous and must be swapped to zram
-                    // with an approximate 2:1 compression ratio.
-                    let pct = match level {
-                        MemoryTrimLevel::TRIM_MEMORY_RUNNING_CRITICAL => 50,
-                        MemoryTrimLevel::TRIM_MEMORY_RUNNING_LOW => 30,
-                        MemoryTrimLevel::TRIM_MEMORY_RUNNING_MODERATE => 10,
-                        _ => bail!("Invalid memory trim level {:?}", level),
-                    };
-                    let command = BalloonControlCommand::Adjust {
-                        num_bytes: total_memory * pct / 100,
-                        wait_for_success: false,
-                    };
-                    if let Err(e) = vm_control::client::handle_request(
-                        &VmRequest::BalloonCommand(command),
-                        &self.crosvm_control_socket_path,
-                    ) {
-                        bail!("Error sending balloon adjustment: {:?}", e);
+        let result =
+            match vm_control::client::handle_request(&request, &self.crosvm_control_socket_path) {
+                Ok(VmResponse::BalloonStats { stats: _, balloon_actual }) => balloon_actual,
+                Ok(VmResponse::Err(e)) => {
+                    // ENOTSUP is returned when the balloon protocol is not initialized. This
+                    // can occur for numerous reasons: Guest is still booting, guest doesn't
+                    // support ballooning, host doesn't support ballooning. We don't log or
+                    // raise an error in this case: trim is just a hint and we can ignore it.
+                    if e.errno() != libc::ENOTSUP {
+                        bail!("Errno return when requesting balloon stats: {}", e.errno())
                     }
+                    0
                 }
-            }
-            Ok(VmResponse::Err(e)) => {
-                // ENOTSUP is returned when the balloon protocol is not initialized. This
-                // can occur for numerous reasons: Guest is still booting, guest doesn't
-                // support ballooning, host doesn't support ballooning. We don't log or
-                // raise an error in this case: trim is just a hint and we can ignore it.
-                if e.errno() != libc::ENOTSUP {
-                    bail!("Errno return when requesting balloon stats: {}", e.errno())
-                }
-            }
-            e => bail!("Error requesting balloon stats: {:?}", e),
+                e => bail!("Error requesting balloon stats: {:?}", e),
+            };
+        Ok(result)
+    }
+
+    /// Responds to memory-trimming notifications by inflating the virtio
+    /// balloon to reclaim guest memory.
+    pub fn set_memory_balloon(&self, num_bytes: u64) -> Result<(), Error> {
+        let command = BalloonControlCommand::Adjust { num_bytes, wait_for_success: false };
+        if let Err(e) = vm_control::client::handle_request(
+            &VmRequest::BalloonCommand(command),
+            &self.crosvm_control_socket_path,
+        ) {
+            bail!("Error sending balloon adjustment: {:?}", e);
         }
         Ok(())
     }
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl
index 9d1d5d5..afa25e2 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl
@@ -16,7 +16,6 @@
 package android.system.virtualizationservice;
 
 import android.system.virtualizationservice.IVirtualMachineCallback;
-import android.system.virtualizationservice.MemoryTrimLevel;
 import android.system.virtualizationservice.VirtualMachineState;
 
 interface IVirtualMachine {
@@ -42,8 +41,9 @@
      */
     void stop();
 
-    /** Communicate app low-memory notifications to the VM. */
-    void onTrimMemory(MemoryTrimLevel level);
+    /** Access to the VM's memory balloon. */
+    long getMemoryBalloon();
+    void setMemoryBalloon(long num_bytes);
 
     /** Open a vsock connection to the CID of the VM on the given port. */
     ParcelFileDescriptor connectVsock(int port);
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/MemoryTrimLevel.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/MemoryTrimLevel.aidl
deleted file mode 100644
index 9ed9e99..0000000
--- a/virtualizationservice/aidl/android/system/virtualizationservice/MemoryTrimLevel.aidl
+++ /dev/null
@@ -1,27 +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.virtualizationservice;
-
-/**
- * Memory trim levels propagated from the app to the VM.
- */
-@Backing(type="int")
-enum MemoryTrimLevel {
-    /* Same meaning as in ComponentCallbacks2 */
-    TRIM_MEMORY_RUNNING_CRITICAL = 0,
-    TRIM_MEMORY_RUNNING_LOW = 1,
-    TRIM_MEMORY_RUNNING_MODERATE = 2,
-}