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::auth;
16 use crate::config::*;
17 use crate::host_app::HostAppTask;
18
19 use hdc::common::hdcfile::HdcFile;
20 use hdc::config::{self, HdcCommand};
21 use hdc::transfer;
22 use hdc::utils;
23
24 use std::collections::HashMap;
25 use std::io::{self, Error, ErrorKind};
26 use std::sync::Arc;
27
28 use ylong_runtime::net::SplitReadHalf;
29 use ylong_runtime::net::TcpStream;
30 use ylong_runtime::sync::{Mutex, RwLock};
31
32 #[derive(Debug, Clone)]
33 pub struct TaskInfo {
34 pub command: HdcCommand,
35 pub connect_key: String,
36 pub channel_id: u32,
37 pub params: Vec<String>,
38 }
39
channel_task_dispatch(task_info: TaskInfo) -> io::Result<()>40 pub async fn channel_task_dispatch(task_info: TaskInfo) -> io::Result<()> {
41 hdc::debug!(
42 "in channel_task_dispatch, task_info={:#?}",
43 task_info.clone()
44 );
45
46 match task_info.command {
47 HdcCommand::UnityRunmode | HdcCommand::UnityRootrun => {
48 hdc::trace!("dispatch to runmode task");
49 channel_unity_task(task_info).await?
50 }
51 HdcCommand::UnityExecute | HdcCommand::ShellInit | HdcCommand::ShellData => {
52 hdc::trace!("dispatch to shell task");
53 channel_shell_task(task_info).await?
54 }
55 HdcCommand::KernelTargetConnect => {
56 hdc::trace!("dispatch to tconn task");
57 channel_connect_task(task_info).await?;
58 }
59 HdcCommand::KernelTargetList => {
60 hdc::trace!("dispatch to list task");
61 channel_list_targets_task(task_info).await?;
62 }
63 HdcCommand::KernelChannelClose => {
64 hdc::trace!("dispatch to close task");
65 transfer::TcpMap::end(task_info.channel_id).await;
66 }
67 HdcCommand::FileInit
68 | HdcCommand::FileBegin
69 | HdcCommand::FileData
70 | HdcCommand::FileCheck
71 | HdcCommand::FileFinish
72 | HdcCommand::AppInit
73 | HdcCommand::AppBegin
74 | HdcCommand::AppData
75 | HdcCommand::AppFinish
76 | HdcCommand::AppUninstall => {
77 channel_file_task(task_info).await?;
78 }
79 HdcCommand::UnityHilog => {
80 channel_hilog_task(task_info).await?;
81 }
82 HdcCommand::UnityBugreportInit => {
83 channel_bug_report_task(task_info).await?;
84 }
85 _ => {
86 hdc::info!("get unknown command {:#?}", task_info.command);
87 return Err(Error::new(ErrorKind::Other, "command not found"));
88 }
89 }
90 Ok(())
91 }
92
channel_hilog_task(task_info: TaskInfo) -> io::Result<()>93 async fn channel_hilog_task(task_info: TaskInfo) -> io::Result<()> {
94 let session_id =
95 get_valid_session_id(task_info.connect_key.clone(), task_info.channel_id).await?;
96 let payload = if task_info.params.len() > 1 && task_info.params[1] == "-h" {
97 vec![104]
98 } else {
99 vec![0]
100 };
101 transfer::put(
102 session_id,
103 TaskMessage {
104 channel_id: task_info.channel_id,
105 command: HdcCommand::UnityHilog,
106 payload: payload,
107 },
108 )
109 .await;
110 Ok(())
111 }
112
channel_bug_report_task(task_info: TaskInfo) -> io::Result<()>113 async fn channel_bug_report_task(task_info: TaskInfo) -> io::Result<()> {
114 let session_id =
115 get_valid_session_id(task_info.connect_key.clone(), task_info.channel_id).await?;
116 transfer::put(
117 session_id,
118 TaskMessage {
119 channel_id: task_info.channel_id,
120 command: HdcCommand::UnityBugreportInit,
121 payload: vec![],
122 },
123 )
124 .await;
125 Ok(())
126 }
127
channel_file_task(task_info: TaskInfo) -> io::Result<()>128 async fn channel_file_task(task_info: TaskInfo) -> io::Result<()> {
129 let session_id =
130 get_valid_session_id(task_info.connect_key.clone(), task_info.channel_id).await?;
131 let opt = admin_session(ActionType::Query(session_id)).await;
132 if opt.is_none() {
133 admin_session(ActionType::Add(HdcSession::new(
134 session_id,
135 String::from(""),
136 NodeType::Daemon,
137 ConnectType::Tcp,
138 )))
139 .await;
140 }
141 let opt = admin_session(ActionType::Query(session_id)).await;
142
143 let arc = opt.unwrap();
144 let mut session = arc.lock().await;
145 if let std::collections::hash_map::Entry::Vacant(e) =
146 session.map_tasks.entry(task_info.channel_id)
147 {
148 match task_info.command {
149 HdcCommand::AppInit | HdcCommand::AppUninstall => {
150 let mut task = HostAppTask::new(session_id, task_info.channel_id);
151 task.transfer.server_or_daemon = true;
152 e.insert(Arc::new(Mutex::new(task)));
153 }
154 HdcCommand::FileInit => {
155 let mut task = HdcFile::new(session_id, task_info.channel_id);
156 task.transfer.server_or_daemon = true;
157 e.insert(Arc::new(Mutex::new(task)));
158 }
159 _ => {
160 println!("other tasks");
161 }
162 }
163 }
164 let task = session.map_tasks.get(&task_info.channel_id).unwrap();
165 let task_ = &mut task.lock().await;
166 let cmd_idx = match task_info.command {
167 HdcCommand::AppInit
168 | HdcCommand::AppBegin
169 | HdcCommand::AppData
170 | HdcCommand::AppFinish
171 | HdcCommand::AppUninstall => 1,
172 _ => 2,
173 };
174 let cmd = task_info.params[cmd_idx..]
175 .iter()
176 .map(|s| s.trim_end_matches('\0'))
177 .collect::<Vec<_>>()
178 .join(" ")
179 .into_bytes();
180 let _ = task_.command_dispatch(task_info.command, &cmd[..], cmd.len() as u16);
181
182 Ok(())
183 }
184
channel_unity_task(task_info: TaskInfo) -> io::Result<()>185 async fn channel_unity_task(task_info: TaskInfo) -> io::Result<()> {
186 let session_id = match ConnectMap::get_session_id(task_info.connect_key.clone()).await {
187 Some(seid) => seid,
188 None => return Err(Error::new(ErrorKind::Other, "session not found")),
189 };
190 let cmd = task_info.params[1..]
191 .iter()
192 .map(|s| s.trim_end_matches('\0'))
193 .collect::<Vec<_>>()
194 .join(" ")
195 .into_bytes();
196 transfer::put(
197 session_id,
198 TaskMessage {
199 channel_id: task_info.channel_id,
200 command: task_info.command,
201 payload: cmd,
202 },
203 )
204 .await;
205 Ok(())
206 }
207
channel_shell_task(task_info: TaskInfo) -> io::Result<()>208 async fn channel_shell_task(task_info: TaskInfo) -> io::Result<()> {
209 let session_id =
210 get_valid_session_id(task_info.connect_key.clone(), task_info.channel_id).await?;
211 match task_info.command {
212 HdcCommand::UnityExecute => {
213 let cmd = task_info.params[1..]
214 .iter()
215 .map(|s| s.trim_end_matches('\0'))
216 .collect::<Vec<_>>()
217 .join(" ")
218 .into_bytes();
219 transfer::put(
220 session_id,
221 TaskMessage {
222 channel_id: task_info.channel_id,
223 command: task_info.command,
224 payload: cmd,
225 },
226 )
227 .await;
228 }
229 HdcCommand::ShellInit => {
230 transfer::put(
231 session_id,
232 TaskMessage {
233 channel_id: task_info.channel_id,
234 command: task_info.command,
235 payload: vec![0],
236 },
237 )
238 .await;
239 }
240 HdcCommand::ShellData => {
241 let payload = task_info.params.join("").into_bytes();
242 transfer::put(
243 session_id,
244 TaskMessage {
245 channel_id: task_info.channel_id,
246 command: task_info.command,
247 payload,
248 },
249 )
250 .await;
251 }
252 _ => {}
253 }
254
255 Ok(())
256 }
257
channel_connect_task(task_info: TaskInfo) -> io::Result<()>258 async fn channel_connect_task(task_info: TaskInfo) -> io::Result<()> {
259 if task_info.params.len() < 2 || task_info.params[1].len() <= 1 {}
260 let connect_key = task_info.params[1].trim_end_matches('\0').to_string();
261 if ConnectMap::get(connect_key.clone()).await.is_some() {
262 let ret = transfer::send_channel_msg(
263 task_info.channel_id,
264 transfer::EchoLevel::INFO,
265 "Target is connected, repeat operation".to_string(),
266 )
267 .await;
268 transfer::TcpMap::end(task_info.channel_id).await;
269 return ret;
270 }
271 match TcpStream::connect(connect_key.clone()).await {
272 Err(_) => {
273 let ret = transfer::send_channel_msg(
274 task_info.channel_id,
275 transfer::EchoLevel::FAIL,
276 "Connect to daemon failed".to_string(),
277 )
278 .await;
279 transfer::TcpMap::end(task_info.channel_id).await;
280 return ret;
281 }
282 Ok(stream) => {
283 let session_id = utils::get_pseudo_random_u32();
284 let (mut rd, wr) = stream.into_split();
285 transfer::TcpMap::start(session_id, wr).await;
286
287 match auth::handshake_with_daemon(
288 connect_key.clone(),
289 session_id,
290 task_info.channel_id,
291 &mut rd,
292 )
293 .await
294 {
295 Ok((dev_name, version)) => {
296 ConnectMap::put(
297 connect_key.clone(),
298 DaemonInfo {
299 session_id,
300 conn_type: config::ConnectType::Tcp,
301 conn_status: ConnectStatus::Connected,
302 dev_name,
303 version,
304 },
305 )
306 .await;
307 }
308 Err(e) => {
309 let _ = transfer::send_channel_msg(
310 task_info.channel_id,
311 transfer::EchoLevel::FAIL,
312 e.to_string(),
313 )
314 .await;
315 transfer::TcpMap::end(task_info.channel_id).await;
316 return Ok(());
317 }
318 };
319
320 ylong_runtime::spawn(tcp_handle_deamon(rd, session_id, connect_key));
321 return transfer::send_channel_msg(
322 task_info.channel_id,
323 transfer::EchoLevel::INFO,
324 "Connect OK".to_string(),
325 )
326 .await;
327 }
328 }
329 }
330
channel_list_targets_task(task_info: TaskInfo) -> io::Result<()>331 async fn channel_list_targets_task(task_info: TaskInfo) -> io::Result<()> {
332 let is_full = task_info.params.contains(&"-v".to_string());
333 let target_list = ConnectMap::get_list(is_full).await;
334 let msg = if target_list.is_empty() {
335 "[Empty]".to_string()
336 } else {
337 target_list.join("\n")
338 };
339 let _ = transfer::send_channel_msg(task_info.channel_id, transfer::EchoLevel::RAW, msg).await?;
340 transfer::TcpMap::end(task_info.channel_id).await;
341 Ok(())
342 }
343
tcp_handle_deamon( mut rd: SplitReadHalf, session_id: u32, connect_key: String, ) -> io::Result<()>344 async fn tcp_handle_deamon(
345 mut rd: SplitReadHalf,
346 session_id: u32,
347 connect_key: String,
348 ) -> io::Result<()> {
349 loop {
350 match transfer::tcp::unpack_task_message(&mut rd).await {
351 Ok(task_message) => {
352 hdc::info!(
353 "in tcp_handle_deamon, recv cmd: {:#?}, payload len: {}",
354 task_message.command,
355 task_message.payload.len(),
356 );
357 if let Err(e) = session_task_dispatch(task_message, session_id).await {
358 hdc::error!("dispatch task failed: {}", e.to_string());
359 }
360 }
361 Err(e) => {
362 hdc::warn!("unpack task failed: {}", e.to_string());
363 ConnectMap::remove(connect_key).await;
364 return Err(e);
365 }
366 };
367 }
368 }
369
session_task_dispatch(task_message: TaskMessage, session_id: u32) -> io::Result<()>370 async fn session_task_dispatch(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
371 match task_message.command {
372 HdcCommand::KernelEchoRaw | HdcCommand::UnityBugreportData => {
373 transfer::send_channel_data(task_message.channel_id, task_message.payload).await;
374 }
375 HdcCommand::KernelChannelClose => {
376 session_channel_close(task_message, session_id).await?;
377 }
378 HdcCommand::AppBegin
379 | HdcCommand::AppData
380 | HdcCommand::AppFinish
381 | HdcCommand::FileInit
382 | HdcCommand::FileBegin
383 | HdcCommand::FileData
384 | HdcCommand::FileCheck
385 | HdcCommand::FileFinish => {
386 session_file_task(task_message, session_id).await?;
387 }
388 _ => {}
389 }
390 Ok(())
391 }
392
session_file_task(task_message: TaskMessage, session_id: u32) -> io::Result<()>393 async fn session_file_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
394 let channel_id = task_message.channel_id;
395 let command = task_message.command;
396 let opt = admin_session(ActionType::Query(session_id)).await;
397 if opt.is_none() {
398 admin_session(ActionType::Add(HdcSession::new(
399 session_id,
400 String::from(""),
401 NodeType::Server,
402 ConnectType::Tcp,
403 )))
404 .await;
405 }
406 let opt = admin_session(ActionType::Query(session_id)).await;
407
408 let arc = opt.unwrap();
409 let mut session = arc.lock().await;
410 if let std::collections::hash_map::Entry::Vacant(e) = session.map_tasks.entry(channel_id) {
411 match command {
412 HdcCommand::AppBegin => {
413 let mut task = HostAppTask::new(session_id, channel_id);
414 task.transfer.server_or_daemon = true;
415 e.insert(Arc::new(Mutex::new(task)));
416 }
417 HdcCommand::FileInit => {
418 let mut task = HdcFile::new(session_id, channel_id);
419 task.transfer.server_or_daemon = true;
420 e.insert(Arc::new(Mutex::new(task)));
421 }
422 _ => {
423 println!("other tasks");
424 }
425 }
426 }
427 let task = session.map_tasks.get(&channel_id).unwrap();
428 let task_ = &mut task.lock().await;
429 let cmd = task_message.payload;
430 let _ = task_.command_dispatch(command, &cmd[..], cmd.len() as u16);
431
432 Ok(())
433 }
434
session_channel_close(task_message: TaskMessage, session_id: u32) -> io::Result<()>435 async fn session_channel_close(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
436 if task_message.payload[0] > 0 {
437 let message = TaskMessage {
438 channel_id: task_message.channel_id,
439 command: HdcCommand::KernelChannelClose,
440 payload: vec![task_message.payload[0] - 1],
441 };
442 transfer::put(session_id, message).await;
443 }
444 hdc::info!("recv channel close");
445 transfer::TcpMap::end(task_message.channel_id).await;
446 Ok(())
447 }
448
449 #[allow(unused)]
450 #[derive(Default)]
451 enum ConnectStatus {
452 #[default]
453 Unknown = 0,
454 Ready,
455 Connected,
456 Offline,
457 }
458
459 #[allow(unused)]
460 #[derive(Default)]
461 struct DaemonInfo {
462 pub session_id: u32,
463 pub conn_type: config::ConnectType,
464 pub conn_status: ConnectStatus,
465 pub dev_name: String,
466 pub version: String,
467 }
468
469 type DaemonInfo_ = Arc<Mutex<DaemonInfo>>;
470 type ConnectMap_ = Arc<RwLock<HashMap<String, DaemonInfo_>>>;
471
472 pub struct ConnectMap {}
473 impl ConnectMap {
get_instance() -> ConnectMap_474 fn get_instance() -> ConnectMap_ {
475 static mut CONNECT_TYPE_MAP: Option<ConnectMap_> = None;
476 unsafe {
477 CONNECT_TYPE_MAP
478 .get_or_insert_with(|| Arc::new(RwLock::new(HashMap::new())))
479 .clone()
480 }
481 }
482
remove(connect_key: String)483 async fn remove(connect_key: String) {
484 let instance = Self::get_instance();
485 let mut map = instance.write().await;
486 map.remove(&connect_key);
487 }
488
put(connect_key: String, daemon_info: DaemonInfo)489 async fn put(connect_key: String, daemon_info: DaemonInfo) {
490 let instance = Self::get_instance();
491 let mut map = instance.write().await;
492 map.insert(connect_key, Arc::new(Mutex::new(daemon_info)));
493 }
494
get(connect_key: String) -> Option<DaemonInfo_>495 async fn get(connect_key: String) -> Option<DaemonInfo_> {
496 let instance = Self::get_instance();
497 let map = instance.read().await;
498 let key = if connect_key.as_str() == "any" && map.keys().len() == 1 {
499 map.keys().last().unwrap()
500 } else {
501 &connect_key
502 };
503 match map.get(key) {
504 Some(daemon_info) => Some(daemon_info.clone()),
505 None => None,
506 }
507 }
508
get_list(is_full: bool) -> Vec<String>509 async fn get_list(is_full: bool) -> Vec<String> {
510 let instance = Self::get_instance();
511 let map = instance.read().await;
512 let mut list = vec![];
513 for (key, info) in map.iter() {
514 if is_full {
515 let mut output = vec![key.as_str()];
516 let guard = info.lock().await;
517 output.push(match guard.conn_type {
518 ConnectType::Tcp => "TCP",
519 ConnectType::Usb(_) => "USB",
520 ConnectType::Uart => "UART",
521 ConnectType::Bt => "BT",
522 });
523 output.push(match guard.conn_status {
524 ConnectStatus::Connected => "Connected",
525 ConnectStatus::Ready => "Ready",
526 ConnectStatus::Offline => "Offline",
527 ConnectStatus::Unknown => "Unknown",
528 });
529 if guard.dev_name.is_empty() {
530 output.push("unknown...");
531 } else {
532 let dev_name = guard.dev_name.as_str();
533 output.push(dev_name);
534 };
535 output.push("hdc");
536 list.push(output.join("\t"));
537 } else {
538 list.push(key.to_owned());
539 }
540 }
541 list
542 }
543
get_session_id(connect_key: String) -> Option<u32>544 pub async fn get_session_id(connect_key: String) -> Option<u32> {
545 let daemon_info = Self::get(connect_key).await?;
546 let guard = daemon_info.lock().await;
547 Some(guard.session_id)
548 }
549 }
550
get_valid_session_id(connect_key: String, channel_id: u32) -> io::Result<u32>551 async fn get_valid_session_id(connect_key: String, channel_id: u32) -> io::Result<u32> {
552 match ConnectMap::get_session_id(connect_key).await {
553 Some(session_id) => Ok(session_id),
554 None => {
555 transfer::send_channel_msg(
556 channel_id,
557 transfer::EchoLevel::FAIL,
558 "Not match target founded, check connect-key please".to_string(),
559 )
560 .await?;
561 transfer::TcpMap::end(channel_id).await;
562 return Err(Error::new(ErrorKind::Other, "session not found"));
563 }
564 }
565 }
566