xref: /aosp_15_r20/tools/asuite/adevice/src/restart_chooser.rs (revision c2e18aaa1096c836b086f94603d04f4eb9cf37f5)
1 //! Crate to provide the AppClass for an installed file.
2 /// The current implementation parses module info and creates
3 /// a map from installed file to its highest ranking "class".
4 /// Later the AppClass will be mapped to a restart level.
5 use serde::{Deserialize, Serialize};
6 use std::ffi::OsStr;
7 use std::path::Path;
8 
9 use crate::cli::RestartChoice;
10 
11 pub struct RestartChooser {
12     // Users override for restarting.
13     restart_choice: RestartChoice,
14 }
15 
16 impl RestartChooser {
new(restart_choice: &RestartChoice) -> Self17     pub fn new(restart_choice: &RestartChoice) -> Self {
18         RestartChooser { restart_choice: restart_choice.clone() }
19     }
20 
21     // Given a file in ANDROID_PRODUCT_OUT tree, return the restart type for it.
restart_type(&self, installed_file: &str) -> RestartType22     pub fn restart_type(&self, installed_file: &str) -> RestartType {
23         match self.restart_choice {
24             RestartChoice::Auto => {
25                 if can_soft_restart_based_on_filename(installed_file) {
26                     RestartType::SoftRestart
27                 } else {
28                     RestartType::Reboot
29                 }
30             }
31             RestartChoice::None => RestartType::None,
32             RestartChoice::Reboot => RestartType::Reboot,
33             RestartChoice::Restart => RestartType::SoftRestart,
34         }
35     }
36 }
37 
38 // Some file extensions only need a SoftRestart due to being
39 // reloaded when zygote restarts on `adb shell start`
40 // Extensions like xml, prof, bprof come up with .jar files (i.e. framework-minus-apex),
41 // so we list them here too.
42 const SOFT_RESTART_FILE_EXTS: &[&str] =
43     &["art", "oat", "vdex", "odex", "fsv_meta", "apk", "jar", "xml", "prof", "bprof", "idsig"];
can_soft_restart_based_on_filename(filename: &str) -> bool44 fn can_soft_restart_based_on_filename(filename: &str) -> bool {
45     let ext = Path::new(filename).extension().and_then(OsStr::to_str).unwrap_or("");
46     SOFT_RESTART_FILE_EXTS.contains(&ext)
47 }
48 
49 #[derive(Debug, Clone, Serialize, Deserialize)]
50 pub struct Module {
51     pub class: Vec<String>,
52     pub installed: Vec<String>,
53 }
54 
55 #[derive(Clone, Debug, PartialEq)]
56 pub enum RestartType {
57     /// The device needs to be rebooted
58     Reboot,
59     /// Adb shell restart will suffice
60     SoftRestart,
61     /// No restarts needed.
62     None,
63     // A force kill command will be enough.
64     // RestartBinary,
65 }
66 
67 #[cfg(test)]
68 mod tests {
69 
70     use super::*;
auto_restart() -> RestartChooser71     fn auto_restart() -> RestartChooser {
72         RestartChooser::new(&RestartChoice::Auto)
73     }
74 
75     #[test]
reboot_for_module_with_shared_and_static_lib()76     fn reboot_for_module_with_shared_and_static_lib() {
77         assert_eq!(
78             RestartType::Reboot,
79             auto_restart().restart_type("vendor/lib64/DefaultVehicleHal.so")
80         );
81     }
82 
83     #[test]
test_so_rebooots()84     fn test_so_rebooots() {
85         assert_eq!(RestartType::Reboot, auto_restart().restart_type("vendor/lib64/Weird.so"));
86     }
87     #[test]
test_bogus_file_rebooots()88     fn test_bogus_file_rebooots() {
89         // It doesn't matter if the file exists or not, if the extension doesn't match, it is a reboot.
90         assert_eq!(RestartType::Reboot, auto_restart().restart_type("bad/file/path"));
91     }
92 
93     #[test]
soft_restart_for_certain_file_extensions()94     fn soft_restart_for_certain_file_extensions() {
95         // Have extensions in SOFT_RESET_FILE_EXTS
96         for installed_file in &[
97             "vendor/good/file/path.art",
98             "vendor/good/file/path.oat",
99             "vendor/good/file/path.vdex",
100             "vendor/good/file/path.fsv_meta",
101         ] {
102             assert_eq!(
103                 RestartType::SoftRestart,
104                 auto_restart().restart_type(installed_file),
105                 "Wrong class for {}",
106                 installed_file
107             );
108         }
109 
110         // Do NOT have extensions in SOFT_RESET_FILE_EXTS (REBOOT due to module class)
111         for installed_file in &[
112             "vendor/good/file/path.extraart",
113             "vendor/good/file/path.artextra",
114             "vendor/good/file/path",
115         ] {
116             assert_eq!(
117                 RestartType::Reboot,
118                 auto_restart().restart_type(installed_file),
119                 "Wrong class for {}",
120                 installed_file
121             );
122         }
123     }
124 
125     #[test]
binary_with_rc_file_reboots_for_rc()126     fn binary_with_rc_file_reboots_for_rc() {
127         assert_eq!(
128             RestartType::Reboot,
129             auto_restart().restart_type("system/bin/surfaceflinger.rc")
130         );
131         // This fails after our choice to reboot based on extension.
132         // assert_eq!(
133         //     RestartType::SoftRestart,
134         //     auto_restart().restart_type("system/bin/surfaceflinger")
135         // );
136     }
137 
138     #[test]
restart_choice_is_used()139     fn restart_choice_is_used() {
140         let restart_chooser = RestartChooser::new(&RestartChoice::None);
141         assert_eq!(RestartType::None, restart_chooser.restart_type("system/bin/surfaceflinger.rc"));
142     }
143 }
144