Pass sorted list of apexes to VM

The order of apex list does matter within microdroid. To keep the
stability, sort the list of apexes before passing to a VM.

Sorting key is a composite of (apex name, apex version, apex mod
timestamp). Paths are not suitable for sorting key because
"prefer_staged" will result in different paths before/after reboot.

We could use "unordered list", especially when checking the VM identity
within a VM. But "ordered list" is assumed in many places and is more
efficient.

Bug: 257377686
Test: virtualizationservice_device_test
Merged-In: I1c269afc059da0df4c6f318d5a591f7a03d4600f
Change-Id: I1c269afc059da0df4c6f318d5a591f7a03d4600f
(cherry picked from commit a44227570f032d166b7636daf47a369670925d89)
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index f85a839..cd80efd 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -59,6 +59,8 @@
 struct ApexInfo {
     #[serde(rename = "moduleName")]
     name: String,
+    #[serde(rename = "versionCode")]
+    version: u64,
     #[serde(rename = "modulePath")]
     path: PathBuf,
 
@@ -119,6 +121,7 @@
                 }
                 // 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)?;
@@ -259,8 +262,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 =
@@ -565,6 +573,7 @@
     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,
@@ -576,6 +585,7 @@
         apex_info_list
             .override_staged_apex(&StagedApexInfo {
                 moduleName: "foo".to_string(),
+                versionCode: 2,
                 diskImagePath: staged.path().to_string_lossy().to_string(),
                 ..Default::default()
             })
@@ -586,6 +596,7 @@
             ApexInfoList {
                 list: vec![
                     ApexInfo {
+                        version: 2,
                         is_factory: false,
                         path: staged.path().to_owned(),
                         last_update_seconds: last_updated(staged.path()).unwrap(),
@@ -601,12 +612,14 @@
     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()
@@ -618,6 +631,7 @@
         apex_info_list
             .override_staged_apex(&StagedApexInfo {
                 moduleName: "foo".to_string(),
+                versionCode: 3,
                 diskImagePath: staged.path().to_string_lossy().to_string(),
                 ..Default::default()
             })
@@ -631,6 +645,7 @@
                     factory_apex,
                     // update active one
                     ApexInfo {
+                        version: 3,
                         path: staged.path().to_owned(),
                         last_update_seconds: last_updated(staged.path()).unwrap(),
                         ..active_apex