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//! task
16#![allow(missing_docs)]
17
18use crate::daemon_lib::{auth, daemon_unity};
19
20use crate::daemon_lib::shell::*;
21
22use crate::daemon_lib::daemon_app::{self, AppTaskMap, DaemonAppTask};
23use crate::daemon_lib::sys_para::*;
24use crate::utils::hdc_log::*;
25use crate::common::forward::{self, ForwardTaskMap, HdcForward};
26use crate::common::hdcfile::{self, FileTaskMap, HdcFile};
27use crate::common::jdwp;
28use crate::config::*;
29use crate::transfer;
30
31use std::io::{self, Error, ErrorKind};
32
33async fn daemon_shell_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
34    match task_message.command {
35        HdcCommand::ShellInit => {
36            let pty_task = PtyTask::new(
37                session_id,
38                task_message.channel_id,
39                None,
40                HdcCommand::KernelEchoRaw,
41            );
42            PtyMap::put(session_id, task_message.channel_id, pty_task).await;
43        }
44        HdcCommand::UnityExecute => {
45            match String::from_utf8(task_message.payload) {
46                Ok(cmd_str) => {
47                    let shell_execute_task: ShellExecuteTask = ShellExecuteTask::new(
48                        session_id,
49                        task_message.channel_id,
50                        cmd_str,
51                        HdcCommand::KernelEchoRaw,
52                    );
53
54                    ShellExecuteMap::put(session_id, task_message.channel_id, shell_execute_task).await;
55                },
56                Err(_) => {
57                    crate::common::hdctransfer::echo_client(
58                        session_id,
59                        task_message.channel_id,
60                        "only support utf-8 chars",
61                        MessageLevel::Fail,
62                    )
63                    .await;
64                    let message = TaskMessage {
65                        channel_id: task_message.channel_id,
66                        command: HdcCommand::KernelChannelClose,
67                        payload: [1].to_vec(),
68                    };
69                    let _ = daemon_channel_close(message, session_id).await;
70                    return Err(Error::new(ErrorKind::Other, "Get an FromUtf8Error"));
71                }
72            }
73        }
74        _ => {
75            let channel_id = task_message.channel_id;
76            if let Some(pty_task) = PtyMap::get(session_id, channel_id).await {
77                let _ = &pty_task.tx.send(task_message.payload.clone()).await;
78                if task_message.payload[..].contains(&0x4_u8) {
79                    PtyMap::del(session_id, channel_id).await;
80                }
81                return Ok(());
82            } else {
83                return Err(Error::new(ErrorKind::Other, "invalid channel id"));
84            }
85        }
86    }
87    Ok(())
88}
89
90async fn remove_task(session_id: u32, channel_id: u32) {
91    jdwp::stop_task(session_id, channel_id).await;
92    AppTaskMap::remove(session_id, channel_id).await;
93    FileTaskMap::remove(session_id, channel_id).await;
94    forward::free_channel_task(session_id, channel_id).await;
95    // shell & hilog task
96    if let Some(pty_task) = PtyMap::get(session_id, channel_id).await {
97        let _ = &pty_task.tx.send(vec![0x04_u8]).await;
98        PtyMap::del(session_id, channel_id).await;
99    }
100    ShellExecuteMap::del(session_id, channel_id).await;
101}
102
103async fn daemon_channel_close(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
104    // task stop:
105    crate::debug!(
106        "daemon_channel_close session_id {session_id}, channel_id {}",
107        task_message.channel_id
108    );
109
110    remove_task(session_id, task_message.channel_id).await;
111
112    if task_message.payload[0] > 0 {
113        let message = TaskMessage {
114            channel_id: task_message.channel_id,
115            command: HdcCommand::KernelChannelClose,
116            payload: vec![task_message.payload[0] - 1],
117        };
118        transfer::put(session_id, message).await;
119    }
120    Ok(())
121}
122
123async fn daemon_file_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
124    match task_message.command {
125        HdcCommand::AppCheck | HdcCommand::AppUninstall => {
126            if !AppTaskMap::exsit(session_id, task_message.channel_id).await {
127                let task = DaemonAppTask::new(session_id, task_message.channel_id);
128                AppTaskMap::put(session_id, task_message.channel_id, task).await;
129            }
130            daemon_app::command_dispatch(
131                session_id,
132                task_message.channel_id,
133                task_message.command,
134                &task_message.payload,
135                task_message.payload.len() as u16,
136            )
137            .await;
138            return Ok(());
139        }
140        HdcCommand::AppBegin | HdcCommand::AppData => {
141            daemon_app::command_dispatch(
142                session_id,
143                task_message.channel_id,
144                task_message.command,
145                &task_message.payload,
146                task_message.payload.len() as u16,
147            )
148            .await;
149            return Ok(());
150        }
151        HdcCommand::FileMode | HdcCommand::FileCheck | HdcCommand::FileInit => {
152            if !FileTaskMap::exsit(session_id, task_message.channel_id).await {
153                let mut task = HdcFile::new(session_id, task_message.channel_id);
154                task.transfer.server_or_daemon = false;
155                FileTaskMap::put(session_id, task_message.channel_id, task).await;
156            }
157
158            hdcfile::command_dispatch(
159                session_id,
160                task_message.channel_id,
161                task_message.command,
162                &task_message.payload,
163                task_message.payload.len() as u16,
164            )
165            .await;
166            return Ok(());
167        }
168        HdcCommand::ForwardInit | HdcCommand::ForwardCheck => {
169            let mut task = HdcForward::new(session_id, task_message.channel_id, false);
170            task.transfer.server_or_daemon = false;
171            ForwardTaskMap::update(session_id, task_message.channel_id, task).await;
172            forward::command_dispatch(
173                session_id,
174                task_message.channel_id,
175                task_message.command,
176                &task_message.payload,
177                task_message.payload.len() as u16,
178            )
179            .await;
180            return Ok(());
181        }
182        HdcCommand::ForwardCheckResult
183        | HdcCommand::ForwardActiveSlave
184        | HdcCommand::ForwardActiveMaster
185        | HdcCommand::ForwardData
186        | HdcCommand::ForwardFreeContext => {
187            forward::command_dispatch(
188                session_id,
189                task_message.channel_id,
190                task_message.command,
191                &task_message.payload,
192                task_message.payload.len() as u16,
193            )
194            .await;
195            return Ok(());
196        }
197        HdcCommand::FileBegin
198        | HdcCommand::FileData
199        | HdcCommand::FileFinish
200        | HdcCommand::DirMode => {
201            hdcfile::command_dispatch(
202                session_id,
203                task_message.channel_id,
204                task_message.command,
205                &task_message.payload,
206                task_message.payload.len() as u16,
207            )
208            .await;
209            return Ok(());
210        }
211        HdcCommand::UnityRunmode
212        | HdcCommand::UnityReboot
213        | HdcCommand::UnityRemount
214        | HdcCommand::UnityRootrun
215        | HdcCommand::JdwpList
216        | HdcCommand::JdwpTrack => {
217            daemon_unity::command_dispatch(
218                session_id,
219                task_message.channel_id,
220                task_message.command,
221                &task_message.payload,
222                task_message.payload.len() as u16,
223            )
224            .await;
225            return Ok(());
226        }
227        _ => {
228            crate::error!(
229                "other tasks, cmd {:?}. session_id {session_id}, channel_id {}",
230                task_message.command,
231                task_message.channel_id
232            );
233        }
234    }
235
236    Ok(())
237}
238
239async fn daemon_hilog_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
240    let cmd = if task_message.payload.len() == 1 && task_message.payload[0] == 104 {
241        // payload is 'h'
242        "hilog -h"
243    } else {
244        // blank or unknown payload, ignore
245        "hilog"
246    }
247    .to_string();
248    let pty_task = PtyTask::new(
249        session_id,
250        task_message.channel_id,
251        Some(cmd),
252        HdcCommand::KernelEchoRaw,
253    );
254    PtyMap::put(session_id, task_message.channel_id, pty_task).await;
255    Ok(())
256}
257
258async fn daemon_bug_report_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
259    let pty_task = PtyTask::new(
260        session_id,
261        task_message.channel_id,
262        Some("hidumper".to_string()),
263        HdcCommand::UnityBugreportData,
264    );
265    PtyMap::put(session_id, task_message.channel_id, pty_task).await;
266    Ok(())
267}
268
269fn get_control_permission(param: &str) -> bool {
270    let (_, control_value) = get_dev_item(param, "_");
271    if control_value.trim().to_lowercase() == "false" {
272        return false;
273    }
274    true
275}
276
277fn check_control(command: HdcCommand) -> bool {
278    let mut control_param = "";
279    match command {
280        HdcCommand::UnityRunmode
281        | HdcCommand::UnityReboot
282        | HdcCommand::UnityRemount
283        | HdcCommand::UnityRootrun
284        | HdcCommand::ShellInit
285        | HdcCommand::ShellData
286        | HdcCommand::UnityExecute
287        | HdcCommand::UnityHilog
288        | HdcCommand::UnityBugreportInit
289        | HdcCommand::JdwpList
290        | HdcCommand::JdwpTrack => {
291            control_param = ENV_SHELL_CONTROL;
292        }
293        HdcCommand::FileInit
294        | HdcCommand::FileCheck
295        | HdcCommand::FileData
296        | HdcCommand::FileBegin
297        | HdcCommand::FileFinish
298        | HdcCommand::AppCheck
299        | HdcCommand::AppData
300        | HdcCommand::AppUninstall => {
301            control_param = ENV_FILE_CONTROL;
302        }
303        HdcCommand::ForwardInit
304        | HdcCommand::ForwardCheck
305        | HdcCommand::ForwardCheckResult
306        | HdcCommand::ForwardActiveSlave
307        | HdcCommand::ForwardActiveMaster
308        | HdcCommand::ForwardData
309        | HdcCommand::ForwardFreeContext => {
310            control_param = ENV_FPORT_CONTROL;
311        }
312        _ => {}
313    }
314    // (_, run_debug) = crate::utils::get_dev_item(param);
315    if !control_param.is_empty() && !get_control_permission(control_param) {
316        return false;
317    }
318    true
319}
320
321pub async fn dispatch_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
322    let cmd = task_message.command;
323    let special_cmd =
324        (cmd == HdcCommand::KernelHandshake) || (cmd == HdcCommand::KernelChannelClose);
325    let auth_ok = auth::AuthStatusMap::get(session_id).await == auth::AuthStatus::Ok;
326
327    if !auth_ok && !special_cmd {
328        crate::error!("auth status is nok, cannt accept cmd: {}", cmd as u32);
329        crate::common::hdctransfer::echo_client(
330            session_id,
331            task_message.channel_id,
332            auth::get_auth_msg(session_id).await.as_str(),
333            MessageLevel::Fail,
334        )
335        .await;
336        transfer::put(
337            session_id,
338            auth::make_channel_close_message(task_message.channel_id).await,
339        )
340        .await;
341        return Err(Error::new(
342            ErrorKind::Other,
343            format!("auth status is nok, cannt accept cmd: {}", cmd as u32),
344        ));
345    }
346    if !check_control(task_message.command) {
347        crate::common::hdctransfer::echo_client(
348            session_id,
349            task_message.channel_id,
350            "debugging is not allowed",
351            MessageLevel::Fail,
352        )
353        .await;
354        crate::common::hdctransfer::transfer_task_finish(task_message.channel_id, session_id).await;
355        crate::debug!(
356            "check_permission param false: {}",
357            task_message.command as u32
358        );
359
360        return Ok(());
361    }
362    match task_message.command {
363        HdcCommand::KernelHandshake => auth::handshake_task(task_message, session_id).await,
364        HdcCommand::UnityHilog => daemon_hilog_task(task_message, session_id).await,
365        HdcCommand::UnityBugreportInit => daemon_bug_report_task(task_message, session_id).await,
366        HdcCommand::ShellInit | HdcCommand::ShellData | HdcCommand::UnityExecute => {
367            daemon_shell_task(task_message, session_id).await
368        }
369        HdcCommand::KernelChannelClose => daemon_channel_close(task_message, session_id).await,
370        HdcCommand::FileInit
371        | HdcCommand::FileCheck
372        | HdcCommand::FileData
373        | HdcCommand::FileBegin
374        | HdcCommand::FileFinish
375        | HdcCommand::FileMode
376        | HdcCommand::DirMode
377        | HdcCommand::AppCheck
378        | HdcCommand::AppData
379        | HdcCommand::AppUninstall
380        | HdcCommand::ForwardInit
381        | HdcCommand::ForwardCheck
382        | HdcCommand::ForwardCheckResult
383        | HdcCommand::ForwardActiveSlave
384        | HdcCommand::ForwardActiveMaster
385        | HdcCommand::ForwardData
386        | HdcCommand::ForwardFreeContext
387        | HdcCommand::UnityRunmode
388        | HdcCommand::UnityReboot
389        | HdcCommand::UnityRemount
390        | HdcCommand::UnityRootrun
391        | HdcCommand::JdwpList
392        | HdcCommand::JdwpTrack => daemon_file_task(task_message, session_id).await,
393        HdcCommand::KernelWakeupSlavetask => Ok(()),
394        _ => Err(Error::new(
395            ErrorKind::Other,
396            format!("unknown command: {}", task_message.command as u32),
397        )),
398    }
399}