* Copyright (C) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#![allow(missing_docs)]
use crate::daemon_lib::{auth, daemon_unity};
use crate::daemon_lib::shell::*;
use crate::daemon_lib::daemon_app::{self, AppTaskMap, DaemonAppTask};
use crate::daemon_lib::sys_para::*;
use crate::utils::hdc_log::*;
use crate::common::forward::{self, ForwardTaskMap, HdcForward};
use crate::common::hdcfile::{self, FileTaskMap, HdcFile};
use crate::common::jdwp;
use crate::config::*;
use crate::transfer;
use std::io::{self, Error, ErrorKind};
async fn daemon_shell_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
match task_message.command {
HdcCommand::ShellInit => {
let pty_task = PtyTask::new(
session_id,
task_message.channel_id,
None,
HdcCommand::KernelEchoRaw,
);
PtyMap::put(session_id, task_message.channel_id, pty_task).await;
}
HdcCommand::UnityExecute => {
match String::from_utf8(task_message.payload) {
Ok(cmd_str) => {
let shell_execute_task: ShellExecuteTask = ShellExecuteTask::new(
session_id,
task_message.channel_id,
cmd_str,
HdcCommand::KernelEchoRaw,
);
ShellExecuteMap::put(session_id, task_message.channel_id, shell_execute_task).await;
},
Err(_) => {
crate::common::hdctransfer::echo_client(
session_id,
task_message.channel_id,
"only support utf-8 chars",
MessageLevel::Fail,
)
.await;
let message = TaskMessage {
channel_id: task_message.channel_id,
command: HdcCommand::KernelChannelClose,
payload: [1].to_vec(),
};
let _ = daemon_channel_close(message, session_id).await;
return Err(Error::new(ErrorKind::Other, "Get an FromUtf8Error"));
}
}
}
_ => {
let channel_id = task_message.channel_id;
if let Some(pty_task) = PtyMap::get(session_id, channel_id).await {
let _ = &pty_task.tx.send(task_message.payload.clone()).await;
if task_message.payload[..].contains(&0x4_u8) {
PtyMap::del(session_id, channel_id).await;
}
return Ok(());
} else {
return Err(Error::new(ErrorKind::Other, "invalid channel id"));
}
}
}
Ok(())
}
async fn remove_task(session_id: u32, channel_id: u32) {
jdwp::stop_task(session_id, channel_id).await;
AppTaskMap::remove(session_id, channel_id).await;
FileTaskMap::remove(session_id, channel_id).await;
forward::free_channel_task(session_id, channel_id).await;
if let Some(pty_task) = PtyMap::get(session_id, channel_id).await {
let _ = &pty_task.tx.send(vec![0x04_u8]).await;
PtyMap::del(session_id, channel_id).await;
}
ShellExecuteMap::del(session_id, channel_id).await;
}
async fn daemon_channel_close(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
crate::debug!(
"daemon_channel_close session_id {session_id}, channel_id {}",
task_message.channel_id
);
remove_task(session_id, task_message.channel_id).await;
if task_message.payload[0] > 0 {
let message = TaskMessage {
channel_id: task_message.channel_id,
command: HdcCommand::KernelChannelClose,
payload: vec![task_message.payload[0] - 1],
};
transfer::put(session_id, message).await;
}
Ok(())
}
async fn daemon_file_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
match task_message.command {
HdcCommand::AppCheck | HdcCommand::AppUninstall => {
if !AppTaskMap::exsit(session_id, task_message.channel_id).await {
let task = DaemonAppTask::new(session_id, task_message.channel_id);
AppTaskMap::put(session_id, task_message.channel_id, task).await;
}
daemon_app::command_dispatch(
session_id,
task_message.channel_id,
task_message.command,
&task_message.payload,
task_message.payload.len() as u16,
)
.await;
return Ok(());
}
HdcCommand::AppBegin | HdcCommand::AppData => {
daemon_app::command_dispatch(
session_id,
task_message.channel_id,
task_message.command,
&task_message.payload,
task_message.payload.len() as u16,
)
.await;
return Ok(());
}
HdcCommand::FileMode | HdcCommand::FileCheck | HdcCommand::FileInit => {
if !FileTaskMap::exsit(session_id, task_message.channel_id).await {
let mut task = HdcFile::new(session_id, task_message.channel_id);
task.transfer.server_or_daemon = false;
FileTaskMap::put(session_id, task_message.channel_id, task).await;
}
hdcfile::command_dispatch(
session_id,
task_message.channel_id,
task_message.command,
&task_message.payload,
task_message.payload.len() as u16,
)
.await;
return Ok(());
}
HdcCommand::ForwardInit | HdcCommand::ForwardCheck => {
let mut task = HdcForward::new(session_id, task_message.channel_id, false);
task.transfer.server_or_daemon = false;
ForwardTaskMap::update(session_id, task_message.channel_id, task).await;
forward::command_dispatch(
session_id,
task_message.channel_id,
task_message.command,
&task_message.payload,
task_message.payload.len() as u16,
)
.await;
return Ok(());
}
HdcCommand::ForwardCheckResult
| HdcCommand::ForwardActiveSlave
| HdcCommand::ForwardActiveMaster
| HdcCommand::ForwardData
| HdcCommand::ForwardFreeContext => {
forward::command_dispatch(
session_id,
task_message.channel_id,
task_message.command,
&task_message.payload,
task_message.payload.len() as u16,
)
.await;
return Ok(());
}
HdcCommand::FileBegin
| HdcCommand::FileData
| HdcCommand::FileFinish
| HdcCommand::DirMode => {
hdcfile::command_dispatch(
session_id,
task_message.channel_id,
task_message.command,
&task_message.payload,
task_message.payload.len() as u16,
)
.await;
return Ok(());
}
HdcCommand::UnityRunmode
| HdcCommand::UnityReboot
| HdcCommand::UnityRemount
| HdcCommand::UnityRootrun
| HdcCommand::JdwpList
| HdcCommand::JdwpTrack => {
daemon_unity::command_dispatch(
session_id,
task_message.channel_id,
task_message.command,
&task_message.payload,
task_message.payload.len() as u16,
)
.await;
return Ok(());
}
_ => {
crate::error!(
"other tasks, cmd {:?}. session_id {session_id}, channel_id {}",
task_message.command,
task_message.channel_id
);
}
}
Ok(())
}
async fn daemon_hilog_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
let cmd = if task_message.payload.len() == 1 && task_message.payload[0] == 104 {
"hilog -h"
} else {
"hilog"
}
.to_string();
let pty_task = PtyTask::new(
session_id,
task_message.channel_id,
Some(cmd),
HdcCommand::KernelEchoRaw,
);
PtyMap::put(session_id, task_message.channel_id, pty_task).await;
Ok(())
}
async fn daemon_bug_report_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
let pty_task = PtyTask::new(
session_id,
task_message.channel_id,
Some("hidumper".to_string()),
HdcCommand::UnityBugreportData,
);
PtyMap::put(session_id, task_message.channel_id, pty_task).await;
Ok(())
}
fn get_control_permission(param: &str) -> bool {
let (_, control_value) = get_dev_item(param, "_");
if control_value.trim().to_lowercase() == "false" {
return false;
}
true
}
fn check_control(command: HdcCommand) -> bool {
let mut control_param = "";
match command {
HdcCommand::UnityRunmode
| HdcCommand::UnityReboot
| HdcCommand::UnityRemount
| HdcCommand::UnityRootrun
| HdcCommand::ShellInit
| HdcCommand::ShellData
| HdcCommand::UnityExecute
| HdcCommand::UnityHilog
| HdcCommand::UnityBugreportInit
| HdcCommand::JdwpList
| HdcCommand::JdwpTrack => {
control_param = ENV_SHELL_CONTROL;
}
HdcCommand::FileInit
| HdcCommand::FileCheck
| HdcCommand::FileData
| HdcCommand::FileBegin
| HdcCommand::FileFinish
| HdcCommand::AppCheck
| HdcCommand::AppData
| HdcCommand::AppUninstall => {
control_param = ENV_FILE_CONTROL;
}
HdcCommand::ForwardInit
| HdcCommand::ForwardCheck
| HdcCommand::ForwardCheckResult
| HdcCommand::ForwardActiveSlave
| HdcCommand::ForwardActiveMaster
| HdcCommand::ForwardData
| HdcCommand::ForwardFreeContext => {
control_param = ENV_FPORT_CONTROL;
}
_ => {}
}
if !control_param.is_empty() && !get_control_permission(control_param) {
return false;
}
true
}
pub async fn dispatch_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
let cmd = task_message.command;
let special_cmd =
(cmd == HdcCommand::KernelHandshake) || (cmd == HdcCommand::KernelChannelClose);
let auth_ok = auth::AuthStatusMap::get(session_id).await == auth::AuthStatus::Ok;
if !auth_ok && !special_cmd {
crate::error!("auth status is nok, cannt accept cmd: {}", cmd as u32);
crate::common::hdctransfer::echo_client(
session_id,
task_message.channel_id,
auth::get_auth_msg(session_id).await.as_str(),
MessageLevel::Fail,
)
.await;
transfer::put(
session_id,
auth::make_channel_close_message(task_message.channel_id).await,
)
.await;
return Err(Error::new(
ErrorKind::Other,
format!("auth status is nok, cannt accept cmd: {}", cmd as u32),
));
}
if !check_control(task_message.command) {
crate::common::hdctransfer::echo_client(
session_id,
task_message.channel_id,
"debugging is not allowed",
MessageLevel::Fail,
)
.await;
crate::common::hdctransfer::transfer_task_finish(task_message.channel_id, session_id).await;
crate::debug!(
"check_permission param false: {}",
task_message.command as u32
);
return Ok(());
}
match task_message.command {
HdcCommand::KernelHandshake => auth::handshake_task(task_message, session_id).await,
HdcCommand::UnityHilog => daemon_hilog_task(task_message, session_id).await,
HdcCommand::UnityBugreportInit => daemon_bug_report_task(task_message, session_id).await,
HdcCommand::ShellInit | HdcCommand::ShellData | HdcCommand::UnityExecute => {
daemon_shell_task(task_message, session_id).await
}
HdcCommand::KernelChannelClose => daemon_channel_close(task_message, session_id).await,
HdcCommand::FileInit
| HdcCommand::FileCheck
| HdcCommand::FileData
| HdcCommand::FileBegin
| HdcCommand::FileFinish
| HdcCommand::FileMode
| HdcCommand::DirMode
| HdcCommand::AppCheck
| HdcCommand::AppData
| HdcCommand::AppUninstall
| HdcCommand::ForwardInit
| HdcCommand::ForwardCheck
| HdcCommand::ForwardCheckResult
| HdcCommand::ForwardActiveSlave
| HdcCommand::ForwardActiveMaster
| HdcCommand::ForwardData
| HdcCommand::ForwardFreeContext
| HdcCommand::UnityRunmode
| HdcCommand::UnityReboot
| HdcCommand::UnityRemount
| HdcCommand::UnityRootrun
| HdcCommand::JdwpList
| HdcCommand::JdwpTrack => daemon_file_task(task_message, session_id).await,
HdcCommand::KernelWakeupSlavetask => Ok(()),
_ => Err(Error::new(
ErrorKind::Other,
format!("unknown command: {}", task_message.command as u32),
)),
}
}