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 //! app
16 #![allow(missing_docs)]
17
18 use crate::utils::hdc_log::*;
19 use crate::common::filemanager::FileManager;
20 use crate::common::hdctransfer::{self, HdcTransferBase};
21 use crate::config;
22 use crate::config::HdcCommand;
23 use crate::config::TaskMessage;
24 use crate::serializer::native_struct::TransferConfig;
25 use crate::serializer::serialize::Serialization;
26 use crate::tar::decompress::Decompress;
27 use crate::transfer;
28 use std::collections::HashMap;
29 use std::path::PathBuf;
30 use std::sync::Arc;
31 use ylong_runtime::sync::Mutex;
32
33 use std::fs::{create_dir_all, File, *};
34 use std::io::{self, Error, ErrorKind};
35 use std::process::Command;
36
37 #[derive(Debug, Default, Clone, PartialEq, Eq)]
38 pub struct DaemonAppTask {
39 pub result_msg: Vec<u8>,
40 pub transfer: HdcTransferBase,
41 }
42
43 impl DaemonAppTask {
newnull44 pub fn new(_session_id: u32, _channel_id: u32) -> Self {
45 Self {
46 result_msg: vec![],
47 transfer: HdcTransferBase::new(_session_id, _channel_id),
48 }
49 }
50 }
51
52 type DaemonAppTask_ = Arc<Mutex<DaemonAppTask>>;
53 type AppTaskMap_ = Arc<Mutex<HashMap<(u32, u32), DaemonAppTask_>>>;
54 pub struct AppTaskMap {}
55 impl AppTaskMap {
get_instancenull56 fn get_instance() -> AppTaskMap_ {
57 static mut MAP: Option<AppTaskMap_> = None;
58 unsafe {
59 MAP.get_or_insert_with(|| Arc::new(Mutex::new(HashMap::new())))
60 .clone()
61 }
62 }
63
64 pub async fn put(session_id: u32, channel_id: u32, value: DaemonAppTask) {
65 let map = Self::get_instance();
66 let mut map = map.lock().await;
67 map.insert((session_id, channel_id), Arc::new(Mutex::new(value)));
68 }
69
70 pub async fn exsit(session_id: u32, channel_id: u32) -> bool {
71 let arc = Self::get_instance();
72 let map = arc.lock().await;
73 let task = map.get(&(session_id, channel_id));
74 task.is_some()
75 }
76
77 pub async fn remove(session_id: u32, channel_id: u32) -> Option<DaemonAppTask_> {
78 let arc = Self::get_instance();
79 let mut map = arc.lock().await;
80 map.remove(&(session_id, channel_id))
81 }
82
83 pub async fn get(session_id: u32, channel_id: u32) -> Option<DaemonAppTask_> {
84 let arc = Self::get_instance();
85 let map = arc.lock().await;
86 let Some(task) = map.get(&(session_id, channel_id)) else {
87 crate::error!(
88 "session_id:{} channel_id:{} not found",
89 session_id,
90 channel_id
91 );
92 return None;
93 };
94 Some(task.clone())
95 }
96
97 async fn stop_task(session_id: u32) {
98 let arc = Self::get_instance();
99 let map = arc.lock().await;
100 crate::info!("app stop_task, session_id:{}, task_size: {}", session_id, map.len());
101 for _iter in map.iter() {
102 if _iter.0 .0 != session_id {
103 continue;
104 }
105 let mut task = _iter.1.lock().await;
106 task.transfer.stop_run = true;
107 }
108 }
109
110 async fn dump_task() -> String {
111 let arc = Self::get_instance();
112 let map = arc.lock().await;
113 let mut result = String::new();
114 for _iter in map.iter() {
115 let task = _iter.1.lock().await;
116 let command = task.transfer.command_str.clone();
117 let line = format!(
118 "session_id:{},\tchannel_id:{},\tcommand:{}",
119 _iter.0 .0, _iter.0 .1, command
120 );
121 result.push_str(line.as_str());
122 }
123 result
124 }
125 }
126
tar_to_dirnull127 fn tar_to_dir(tar_path: PathBuf) -> Result<String, String> {
128 if !tar_path.exists() {
129 return Err(format!("{} is not exist!", tar_path.display()));
130 }
131
132 match Decompress::file(tar_path.display().to_string().as_str()) {
133 Ok(decompress) => {
134 let tar_string = tar_path.display().to_string();
135 let dir = tar_string.trim_end_matches(".tar");
136 if let Err(err) = decompress.decompress(dir) {
137 return Err(format!("Decompress failed, {err}"));
138 }
139 Ok(dir.to_string())
140 }
141 Err(err) => Err(format!("Decompress failed, {err}")),
142 }
143 }
144
145 async fn do_app_check(session_id: u32, channel_id: u32, _payload: &[u8]) -> bool {
146 let Some(arc) = AppTaskMap::get(session_id, channel_id).await else {
147 crate::error!(
148 "session_id:{} channel_id:{} not found",
149 session_id,
150 channel_id
151 );
152 return false;
153 };
154 let mut task = arc.lock().await;
155 let mut transconfig = TransferConfig {
156 ..Default::default()
157 };
158 let _ = transconfig.parse(_payload.to_owned());
159 task.transfer.transfer_config.options = transconfig.options.clone();
160 task.transfer.transfer_config.function_name = transconfig.function_name.clone();
161 let tmp_dir = String::from(config::INSTALL_TMP_DIR);
162 let local_path = tmp_dir.clone() + transconfig.optional_name.as_str();
163 task.transfer.command_str = format!(
164 "[{}],\tlocal_path:{}\n",
165 transconfig.function_name, local_path
166 );
167 task.transfer.is_master = false;
168 task.transfer.local_path = local_path;
169 task.transfer.file_size = transconfig.file_size;
170 task.transfer.index = 0;
171 let state = metadata(tmp_dir.clone());
172 if let Ok(metadata_obj) = state {
173 if metadata_obj.is_dir() {
174 return File::create(task.transfer.local_path.clone()).is_ok();
175 }
176 } else {
177 crate::debug!("{tmp_dir} is not exist.");
178 let _ = create_dir_all(tmp_dir);
179 return File::create(task.transfer.local_path.clone()).is_ok();
180 }
181 false
182 }
183
184 async fn put_file_begin(session_id: u32, channel_id: u32) {
185 let file_begin_message = TaskMessage {
186 channel_id,
187 command: HdcCommand::AppBegin,
188 payload: Vec::<u8>::new(),
189 };
190 transfer::put(session_id, file_begin_message).await;
191 }
192
193 async fn put_app_finish(
194 session_id: u32,
195 channel_id: u32,
196 mode: u8,
197 exit_status: u8,
198 result: &mut [u8],
199 ) {
200 let mut msg = Vec::<u8>::new();
201 msg.push(mode);
202 msg.push(exit_status);
203 let Some(arc) = AppTaskMap::get(session_id, channel_id).await else {
204 crate::error!(
205 "session_id:{} channel_id:{} not found",
206 session_id,
207 channel_id
208 );
209 return;
210 };
211 let mut task = arc.lock().await;
212 task.result_msg.append(&mut result.to_vec());
213 msg.append(&mut task.result_msg.clone());
214
215 let app_finish_message = TaskMessage {
216 channel_id,
217 command: HdcCommand::AppFinish,
218 payload: msg.clone(),
219 };
220 transfer::put(session_id, app_finish_message).await;
221 }
222
223 async fn app_uninstall(session_id: u32, channel_id: u32, _payload: &[u8]) {
224 let mut str = match String::from_utf8(_payload.to_vec()) {
225 Ok(v) => v,
226 Err(e) => {
227 crate::error!(
228 "session_id:{} channel_id:{} uninstall error:{}",
229 session_id,
230 channel_id,
231 e
232 );
233 put_app_finish(
234 session_id,
235 channel_id,
236 0,
237 0,
238 &mut e.to_string().into_bytes()[..],
239 )
240 .await;
241 return;
242 }
243 };
244 str = str.trim_end_matches('\0').to_string();
245
246 let (opt, package): (Vec<String>, Vec<String>) = str
247 .split(' ')
248 .map(String::from)
249 .partition(|word| word.starts_with('-'));
250 do_app_uninstall(session_id, channel_id, opt.join(" "), package.join(" ")).await;
251 }
252
253 async fn handle_execute_result(
254 session_id: u32,
255 channel_id: u32,
256 result: Result<Vec<u8>, Error>,
257 mode: u8,
258 ) {
259 match &result {
260 Ok(message) => {
261 let mut m: Vec<u8> = message.clone();
262 put_app_finish(session_id, channel_id, mode, 1, &mut m[..]).await;
263 }
264 Err(err) => {
265 crate::error!(
266 "session_id:{} channel_id:{} error:{}",
267 session_id,
268 channel_id,
269 err
270 );
271 put_app_finish(
272 session_id,
273 channel_id,
274 mode,
275 0,
276 &mut err.to_string().into_bytes()[..],
277 )
278 .await;
279 }
280 }
281 }
282
283 async fn do_app_uninstall(session_id: u32, channel_id: u32, options: String, package: String) {
284 let mode = config::AppModeType::UnInstall as u8;
285 // let cmd = String::new();
286 let cmd = if !options.contains('n') {
287 format!("bm uninstall {} -n {}", options, package)
288 } else {
289 format!("bm uninstall {} {}", options, package)
290 };
291 crate::debug!("channel_id {channel_id}, cmd {cmd}");
292 let result = execute_cmd(&cmd);
293 handle_execute_result(session_id, channel_id, result, mode).await;
294 }
295
296 async fn do_app_install(session_id: u32, channel_id: u32) {
297 let Some(arc) = AppTaskMap::get(session_id, channel_id).await else {
298 crate::error!(
299 "session_id:{} channel_id:{} not found",
300 session_id,
301 channel_id
302 );
303 return;
304 };
305 let task = arc.lock().await;
306 let options = task.transfer.transfer_config.options.clone();
307 let mut local_path = task.transfer.local_path.clone();
308 drop(task);
309 if local_path.ends_with(".tar") {
310 match tar_to_dir(PathBuf::from(local_path.clone())) {
311 Ok(dir) => {
312 let _ = remove_file(local_path.clone());
313 local_path = dir
314 }
315 Err(err) => {
316 crate::error!("{err}");
317 }
318 }
319 }
320 let mode = config::AppModeType::Install as u8;
321 let cmd = if !options.contains('p') && !options.contains('s') {
322 format!("bm install {} -p {}", options, local_path)
323 } else {
324 format!("bm install {} {}", options, local_path)
325 };
326 crate::debug!("channel_id {channel_id}, cmd {cmd}");
327 let result = execute_cmd(&cmd);
328 handle_execute_result(session_id, channel_id, result, mode).await;
329 let _ = FileManager::remove_file(local_path.as_str());
330 }
331
execute_cmdnull332 fn execute_cmd(cmd: &String) -> io::Result<Vec<u8>> {
333 let result = Command::new(config::SHELL_PROG).args(["-c", cmd]).output();
334 match result {
335 Ok(output) => {
336 let msg = [output.stdout, output.stderr].concat();
337 let mut str = match String::from_utf8(msg) {
338 Ok(s) => s,
339 Err(e) => {
340 let error_msg = format!("cmd execute error: {}", e);
341 crate::error!("{error_msg}");
342 return Err(Error::new(ErrorKind::Other, error_msg));
343 }
344 };
345 str = str.replace('\n', " ");
346 Ok(str.into_bytes())
347 }
348 Err(e) => Err(Error::new(ErrorKind::Other, e.to_string())),
349 }
350 }
351
352 async fn on_transfer_finish(session_id: u32, channel_id: u32) {
353 let Some(arc) = AppTaskMap::get(session_id, channel_id).await else {
354 crate::error!(
355 "session_id:{} channel_id:{} not found",
356 session_id,
357 channel_id
358 );
359 return;
360 };
361 let task = arc.lock().await;
362 let function_name = task.transfer.transfer_config.function_name.clone();
363 drop(task);
364 if function_name == config::TRANSFER_FUNC_NAME {
365 do_app_install(session_id, channel_id).await;
366 }
367 }
368
369 async fn transfer_fail(session_id: u32, channel_id: u32, error: &str) {
370 let mode = config::AppModeType::Install as u8;
371 put_app_finish(
372 session_id,
373 channel_id,
374 mode,
375 0,
376 &mut error.to_string().into_bytes()[..],
377 )
378 .await;
379 }
380
381 pub async fn command_dispatch(
382 session_id: u32,
383 channel_id: u32,
384 _command: HdcCommand,
385 _payload: &[u8],
386 _payload_size: u16,
387 ) -> bool {
388 match _command {
389 HdcCommand::AppCheck => {
390 if do_app_check(session_id, channel_id, _payload).await {
391 put_file_begin(session_id, channel_id).await;
392 } else {
393 transfer_fail(session_id, channel_id, "check file fail.").await;
394 }
395 }
396 HdcCommand::AppUninstall => {
397 app_uninstall(session_id, channel_id, _payload).await;
398 }
399 HdcCommand::AppData => {
400 let Some(arc) = AppTaskMap::get(session_id, channel_id).await else {
401 crate::error!(
402 "session_id:{} channel_id:{} not found",
403 session_id,
404 channel_id
405 );
406 return false;
407 };
408 let mut task = arc.lock().await;
409 if task.transfer.stop_run {
410 crate::error!("stop_run {}", task.transfer.stop_run);
411 return false;
412 }
413 if hdctransfer::transfer_data(&mut task.transfer, _payload) {
414 drop(task);
415 on_transfer_finish(session_id, channel_id).await;
416 }
417 }
418 _ => {
419 crate::error!(
420 "session_id:{} channel_id:{}, command:{:?} not support",
421 session_id,
422 channel_id,
423 _command
424 );
425 }
426 }
427 true
428 }
429
430 pub async fn stop_task(session_id: u32) {
431 AppTaskMap::stop_task(session_id).await;
432 }
433
434 pub async fn dump_task() -> String {
435 AppTaskMap::dump_task().await
436 }
437