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