1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 use crate::daemon_lib::mount;
16 use crate::daemon_lib::task_manager;
17 use crate::common::jdwp::DisplayType;
18 use crate::common::jdwp::Jdwp;
19 use crate::daemon_lib::sys_para::*;
20 use crate::utils::hdc_log::*;
21 use crate::common::hdctransfer;
22 use crate::config::{self, HdcCommand, MessageLevel};
23 use libc::sync;
24 
25 extern "C" {
Restartnull26     fn Restart();
27 }
28 
29 async fn hdc_restart() {
30     crate::info!("Mode changed, hdc daemon restart!");
31     unsafe {
32         Restart();
33     }
34 }
35 
36 async fn echo_client(session_id: u32, channel_id: u32, message: &str, level: MessageLevel) {
37     hdctransfer::echo_client(session_id, channel_id, message, level).await;
38 }
39 
40 async fn echo_device_mode_result(session_id: u32, channel_id: u32, result: bool, message: &str) {
41     if result {
42         echo_client(
43             session_id,
44             channel_id,
45             "Set device run mode successful.",
46             MessageLevel::Ok,
47         )
48         .await;
49     } else {
50         let msg = format!("Set device run mode failed: {}", message);
51         echo_client(session_id, channel_id, msg.as_str(), MessageLevel::Fail).await;
52     }
53     task_finish(session_id, channel_id).await;
54 }
55 
56 async fn echo_reboot_result(session_id: u32, channel_id: u32, result: bool, message: &str) {
57     if result {
58         echo_client(
59             session_id,
60             channel_id,
61             "Reboot successful.",
62             MessageLevel::Ok,
63         )
64         .await;
65     } else {
66         let msg = format!("Reboot failed: {}", message);
67         echo_client(session_id, channel_id, msg.as_str(), MessageLevel::Fail).await;
68     }
69     task_finish(session_id, channel_id).await;
70 }
71 
72 async fn echo_root_run_mode_result(session_id: u32, channel_id: u32, result: bool, message: &str) {
73     if result {
74         let msg = format!("Set {} run mode successful.", message);
75         echo_client(session_id, channel_id, msg.as_str(), MessageLevel::Ok).await;
76     } else {
77         let msg = format!("Set {} run mode failed.", message);
78         echo_client(session_id, channel_id, msg.as_str(), MessageLevel::Fail).await;
79     }
80     task_finish(session_id, channel_id).await;
81 }
82 
83 async fn set_root_run_enable(session_id: u32, channel_id: u32, root: bool) {
84     let root_flag = if root { "0" } else { "1" };
85     let mode_msg = if root { "sh" } else { "root" };
86     let result = set_dev_item(config::ENV_ROOT_RUN_MODE, root_flag);
87     echo_root_run_mode_result(session_id, channel_id, result, mode_msg).await;
88     crate::info!(
89         "set_root_run_enable: session_id: {}, channel_id: {}, root: {}, result: {}",
90         session_id,
91         channel_id,
92         root,
93         result
94     );
95     if result {
96         crate::info!("set_root_run root:{root} free_all_session");
97         task_manager::free_all_sessiones().await;
98         std::process::exit(0);
99     }
100 }
101 
102 async fn set_root_run(session_id: u32, channel_id: u32, _payload: &[u8]) {
103     let (ret, debug_able) = get_dev_item(config::ENV_DEBUGGABLE, "_");
104     if !ret || debug_able.trim() != "1" {
105         crate::info!("get debuggable failed");
106         echo_client(
107             session_id,
108             channel_id,
109             "Cannot set root run mode in undebuggable version.",
110             MessageLevel::Fail,
111         )
112         .await;
113         task_finish(session_id, channel_id).await;
114         return;
115     }
116 
117     if _payload.is_empty() {
118         set_root_run_enable(session_id, channel_id, false).await;
119     } else if _payload == [b'r'] {
120         set_root_run_enable(session_id, channel_id, true).await;
121     } else {
122         echo_root_run_mode_result(session_id, channel_id, false, "Unknown command").await;
123     }
124 }
125 
126 async fn reboot_device(session_id: u32, channel_id: u32, _payload: &[u8]) {
127     unsafe {
128         sync();
129     };
130 
131     let param = match String::from_utf8(_payload.to_vec()) {
132         Ok(param) => param,
133         Err(_) => String::from("Unknown"),
134     };
135 
136     let mut cmd = String::from("reboot");
137     if !param.is_empty() {
138         cmd.push(',');
139         cmd.push_str(param.as_str());
140     }
141     let cmd = cmd.trim();
142     let result = set_dev_item(config::ENV_STARTUP, cmd);
143     echo_reboot_result(session_id, channel_id, result, cmd).await;
144 }
145 
146 async fn remount_device(session_id: u32, channel_id: u32) {
147     unsafe {
148         if libc::getuid() != 0 {
149             echo_client(
150                 session_id,
151                 channel_id,
152                 "Operate need running as root",
153                 MessageLevel::Fail,
154             )
155             .await;
156             task_finish(session_id, channel_id).await;
157             return;
158         }
159     }
160     let ret = mount::remount_device();
161     if ret {
162         echo_client(session_id, channel_id, "Mount finish", MessageLevel::Ok).await;
163     } else {
164         echo_client(session_id, channel_id, "Mount failed", MessageLevel::Fail).await;
165     }
166     task_finish(session_id, channel_id).await;
167 }
168 
169 async fn set_device_mode(session_id: u32, channel_id: u32, _payload: &[u8]) {
170     let param = match String::from_utf8(_payload.to_vec()) {
171         Ok(param) => param,
172         Err(_) => String::from("Unknown"),
173     };
174     match param.as_str() {
175         config::MODE_USB => {
176             let result = set_dev_item(config::ENV_HDC_MODE, config::MODE_USB);
177             echo_device_mode_result(session_id, channel_id, result, config::MODE_USB).await;
178             if result {
179                 crate::info!("tmode usb free_all_session");
180                 task_manager::free_all_sessiones().await;
181                 hdc_restart().await
182             }
183         }
184         str if str.starts_with(config::PREFIX_PORT) => {
185             let result = set_dev_item(config::ENV_HDC_MODE, config::MODE_TCP);
186             if !result {
187                 echo_device_mode_result(session_id, channel_id, result, config::MODE_TCP).await;
188                 return;
189             }
190 
191             let port = &str[config::PREFIX_PORT.len()..];
192             let port =
193                 port.trim_end_matches(|c: char| c.is_ascii_control() || c.is_ascii_whitespace());
194             let result = set_dev_item(config::ENV_HOST_PORT, port);
195             echo_device_mode_result(session_id, channel_id, result, config::ENV_HOST_PORT).await;
196             if result {
197                 crate::info!("tmode port:{port} free_all_session");
198                 task_manager::free_all_sessiones().await;
199                 hdc_restart().await
200             }
201         }
202         _ => {
203             echo_device_mode_result(session_id, channel_id, false, "Unknown command").await;
204         }
205     }
206 }
207 
208 async fn do_jdwp_list(session_id: u32, channel_id: u32) {
209     crate::debug!("do_jdwp_list, session_id {session_id}, channel_id {channel_id}");
210     let jdwp = Jdwp::get_instance().clone();
211     let process_list = jdwp.get_process_list().await;
212     if process_list.is_empty() {
213         echo_client(session_id, channel_id, "[Empty]", MessageLevel::Ok).await;
214     } else {
215         echo_client(
216             session_id,
217             channel_id,
218             process_list.as_str(),
219             MessageLevel::Ok,
220         )
221         .await;
222     }
223     task_finish(session_id, channel_id).await;
224 }
225 
226 async fn do_jdwp_track(session_id: u32, channel_id: u32, payload: &[u8]) {
227     // 0:AllApp 1:DebugApp 2:ReleaseApp 3:AllAppWithType
228     let mut display = DisplayType::DebugApp;
229     if !payload.is_empty() && payload[0] == b'p' {
230         display = DisplayType::AllApp;
231     } else if !payload.is_empty() && payload[0] == b'a' {
232         display = DisplayType::AllAppWithType;
233     }
234     let jdwp = Jdwp::get_instance().clone();
235     jdwp.add_tracker(channel_id, session_id, display)
236         .await;
237 }
238 
239 pub async fn command_dispatch(
240     session_id: u32,
241     channel_id: u32,
242     _command: HdcCommand,
243     _payload: &[u8],
244     _payload_size: u16,
245 ) -> bool {
246     crate::info!("DaemonUnityTask: command:{:?}", _command);
247     match _command {
248         HdcCommand::UnityReboot => reboot_device(session_id, channel_id, _payload).await,
249         HdcCommand::UnityRunmode => set_device_mode(session_id, channel_id, _payload).await,
250         HdcCommand::UnityRootrun => set_root_run(session_id, channel_id, _payload).await,
251         HdcCommand::JdwpList => do_jdwp_list(session_id, channel_id).await,
252         HdcCommand::JdwpTrack => do_jdwp_track(session_id, channel_id, _payload).await,
253         HdcCommand::UnityRemount => remount_device(session_id, channel_id).await,
254         _ => {
255             crate::error!("other command, {:?}", _command);
256         }
257     }
258     true
259 }
260 
261 async fn task_finish(session_id: u32, channel_id: u32) {
262     hdctransfer::transfer_task_finish(channel_id, session_id).await;
263 }
264