shutdown_shim/
reboot_reasons.rs1use fidl::marker::SourceBreaking;
6use fidl_fuchsia_hardware_power_statecontrol as fpower;
7
8#[derive(Debug, PartialEq, PartialOrd, Clone)]
13pub struct RebootReasons(pub Vec<fpower::RebootReason2>);
14
15impl RebootReasons {
16 pub fn new(reason: fpower::RebootReason2) -> Self {
18 Self(vec![reason])
19 }
20
21 pub(crate) fn from_deprecated(reason: &fpower::RebootReason) -> Self {
26 let reason = match reason {
27 fpower::RebootReason::UserRequest => fpower::RebootReason2::UserRequest,
28 fpower::RebootReason::SystemUpdate => fpower::RebootReason2::SystemUpdate,
29 fpower::RebootReason::RetrySystemUpdate => fpower::RebootReason2::RetrySystemUpdate,
30 fpower::RebootReason::HighTemperature => fpower::RebootReason2::HighTemperature,
31 fpower::RebootReason::FactoryDataReset => fpower::RebootReason2::FactoryDataReset,
32 fpower::RebootReason::SessionFailure => fpower::RebootReason2::SessionFailure,
33 fpower::RebootReason::SysmgrFailure => fpower::RebootReason2::SysmgrFailure,
34 fpower::RebootReason::CriticalComponentFailure => {
35 fpower::RebootReason2::CriticalComponentFailure
36 }
37 fpower::RebootReason::ZbiSwap => fpower::RebootReason2::ZbiSwap,
38 fpower::RebootReason::OutOfMemory => fpower::RebootReason2::OutOfMemory,
39 };
40 Self::new(reason)
41 }
42
43 pub(crate) fn to_deprecated(&self) -> fpower::RebootReason {
53 enum FoldState {
54 Direct(fpower::RebootReason),
55 Indirect(fpower::RebootReason),
56 None,
57 }
58 let state = self.0.iter().fold(FoldState::None, |state, reason| {
59 match (&state, &reason) {
60 (FoldState::Direct(_), _) => state,
62 (_, fpower::RebootReason2::UserRequest) => {
64 FoldState::Direct(fpower::RebootReason::UserRequest)
65 }
66 (_, fpower::RebootReason2::SystemUpdate) => {
67 FoldState::Direct(fpower::RebootReason::SystemUpdate)
68 }
69 (_, fpower::RebootReason2::RetrySystemUpdate) => {
70 FoldState::Direct(fpower::RebootReason::RetrySystemUpdate)
71 }
72 (_, fpower::RebootReason2::HighTemperature) => {
73 FoldState::Direct(fpower::RebootReason::HighTemperature)
74 }
75 (_, fpower::RebootReason2::FactoryDataReset) => {
76 FoldState::Direct(fpower::RebootReason::FactoryDataReset)
77 }
78 (_, fpower::RebootReason2::SessionFailure) => {
79 FoldState::Direct(fpower::RebootReason::SessionFailure)
80 }
81 (_, fpower::RebootReason2::SysmgrFailure) => {
82 FoldState::Direct(fpower::RebootReason::SysmgrFailure)
83 }
84 (_, fpower::RebootReason2::CriticalComponentFailure) => {
85 FoldState::Direct(fpower::RebootReason::CriticalComponentFailure)
86 }
87 (_, fpower::RebootReason2::ZbiSwap) => {
88 FoldState::Direct(fpower::RebootReason::ZbiSwap)
89 }
90 (_, fpower::RebootReason2::OutOfMemory) => {
91 FoldState::Direct(fpower::RebootReason::OutOfMemory)
92 }
93 (_, fpower::RebootReason2::AndroidUnexpectedReason) => {
94 FoldState::Direct(fpower::RebootReason::UserRequest)
95 }
96 (FoldState::Indirect(_), fpower::RebootReason2::NetstackMigration) => state,
99 (FoldState::None, fpower::RebootReason2::NetstackMigration) => {
101 FoldState::Indirect(fpower::RebootReason::SystemUpdate)
102 }
103 (_, fpower::RebootReason2::__SourceBreaking { unknown_ordinal: _ }) => {
104 unreachable!()
105 }
106 }
107 });
108 match state {
109 FoldState::Direct(reason) | FoldState::Indirect(reason) => reason,
110 FoldState::None => {
111 unreachable!("RebootReasons is guaranteed to have at least 1 reason.")
112 }
113 }
114 }
115}
116
117impl AsRef<Vec<fpower::RebootReason2>> for RebootReasons {
118 fn as_ref(&self) -> &Vec<fpower::RebootReason2> {
119 &self.0
120 }
121}
122
123impl From<RebootReasons> for fpower::RebootOptions {
124 fn from(RebootReasons(reasons): RebootReasons) -> Self {
125 fpower::RebootOptions { reasons: Some(reasons), __source_breaking: SourceBreaking }
126 }
127}
128
129#[derive(Debug, PartialEq)]
131pub enum InvalidRebootOptions {
132 NoReasons,
134}
135
136impl TryFrom<fpower::RebootOptions> for RebootReasons {
137 type Error = InvalidRebootOptions;
138 fn try_from(options: fpower::RebootOptions) -> Result<Self, Self::Error> {
139 let fpower::RebootOptions { reasons, __source_breaking } = options;
140 if let Some(reasons) = reasons {
141 if !reasons.is_empty() {
142 return Ok(RebootReasons(reasons));
143 }
144 }
145
146 Err(InvalidRebootOptions::NoReasons)
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153 use test_case::test_case;
154
155 #[test_case(None => Err(InvalidRebootOptions::NoReasons); "no_reasons")]
156 #[test_case(Some(vec![]) => Err(InvalidRebootOptions::NoReasons); "empty_reasons")]
157 #[test_case(Some(vec![fpower::RebootReason2::UserRequest]) => Ok(()); "success")]
158 fn reboot_reasons(
159 reasons: Option<Vec<fpower::RebootReason2>>,
160 ) -> Result<(), InvalidRebootOptions> {
161 let options = fpower::RebootOptions { reasons, __source_breaking: SourceBreaking };
162 RebootReasons::try_from(options).map(|_reasons| {})
163 }
164
165 #[test_case(
166 vec![fpower::RebootReason2::UserRequest, fpower::RebootReason2::SystemUpdate] =>
167 fpower::RebootReason::UserRequest;
168 "prefer_first_a")]
169 #[test_case(
170 vec![fpower::RebootReason2::SystemUpdate, fpower::RebootReason2::UserRequest] =>
171 fpower::RebootReason::SystemUpdate;
172 "prefer_first_b")]
173 #[test_case(
174 vec![fpower::RebootReason2::NetstackMigration, fpower::RebootReason2::UserRequest] =>
175 fpower::RebootReason::UserRequest;
176 "prefer_direct")]
177 #[test_case(
178 vec![fpower::RebootReason2::NetstackMigration] =>
179 fpower::RebootReason::SystemUpdate;
180 "netstack_migration")]
181 fn reasons_to_deprecated(reasons: Vec<fpower::RebootReason2>) -> fpower::RebootReason {
182 let options =
183 fpower::RebootOptions { reasons: Some(reasons), __source_breaking: SourceBreaking };
184 RebootReasons::try_from(options).unwrap().to_deprecated()
185 }
186}