/* * 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::common::sendmsg::send_msg; use crate::common::uds::{PollNode, UdsAddr, UdsServer}; use crate::config::ErrCode; use crate::config::HdcCommand; use crate::config::TaskMessage; use crate::daemon_lib::sys_para::set_dev_item; use crate::{transfer, utils}; use crate::utils::hdc_log::*; use libc::{POLLERR, POLLHUP, POLLIN, POLLNVAL, POLLRDHUP, SOCK_STREAM}; use std::collections::HashMap; use std::sync::{Arc, Once}; #[cfg(feature = "host")] extern crate ylong_runtime_static as ylong_runtime; use ylong_runtime::sync::waiter::Waiter; use ylong_runtime::sync::Mutex; const JPID_SOCKET_PATH: &str = "ohjpid-control"; const PATH_LEN: usize = JPID_SOCKET_PATH.as_bytes().len() + 1; #[allow(unused)] #[derive(Clone, Debug, PartialEq)] pub enum DisplayType { AllApp = 0, DebugApp = 1, ReleaseApp = 2, AllAppWithType = 3, } type NodeMap = Arc>>; type SocketPairVec = Arc>>; type SocketpairMap = Arc>>; type Trackers = Arc>>; pub trait JdwpBase: Send + Sync + 'static {} pub struct Jdwp { poll_node_map: NodeMap, socketpair_map: SocketpairMap, new_process_waiter: Arc, trackers: Trackers, await_fd: i32, } impl JdwpBase for Jdwp {} type JdWpShare = Arc; impl Default for Jdwp { fn default() -> Self { Self::new() } } impl Jdwp { pub fn get_instance() -> JdWpShare { static mut INSTANCE: Option = None; unsafe { INSTANCE .get_or_insert_with(|| Arc::new(Jdwp::new())) .clone() } } pub fn new() -> Self { Self { poll_node_map: Arc::new(Mutex::new(HashMap::default())), socketpair_map: Arc::new(Mutex::new(HashMap::default())), new_process_waiter: Arc::new(Waiter::new()), trackers: Arc::new(Mutex::new(Vec::new())), await_fd: UdsServer::wrap_event_fd(), } } } impl Jdwp { async fn put_socketpair(&self, target_pid: u32, fd: i32, fd2: i32) { let socketpair_map = self.socketpair_map.clone(); let mut socketpair_map_lock = socketpair_map.lock().await; if let Some(vec) = socketpair_map_lock.get(&target_pid) { let mut lock = vec.lock().await; lock.push((fd, fd2)); } else { let vec = vec![(fd, fd2)]; socketpair_map_lock.insert(target_pid, Arc::new(Mutex::new(vec))); } } pub async fn send_fd_to_target(&self, target_pid: u32, fd: i32, fd2: i32, parameter: &str) -> bool { let map = self.poll_node_map.clone(); let map = map.lock().await; let keys = map.keys(); for k in keys { let v = map.get(k); if let Some(node) = v { if node.ppid == target_pid { crate::info!("send_fd_to_target pid:{target_pid}, fd:({fd}, {fd2})"); self.put_socketpair(target_pid, fd, fd2).await; let bytes = fd.to_be_bytes(); let fd_bytes = bytes.as_slice(); let param_bytes = parameter.as_bytes(); let param_bytes = [fd_bytes, param_bytes].concat(); let param_bytes = param_bytes.as_slice(); let ret = send_msg(node.fd, fd, param_bytes); crate::info!("send_fd_to_target ret:{}", ret); return ret > 0; } } } false } async fn send_process_list(trackers: Trackers, node_map: NodeMap) { let trackers = trackers.lock().await; for (channel_id2, session_id2, display) in trackers.iter() { let message = Self::get_process_list_with_pkg_name(node_map.clone(), display.clone()).await; let len = message.as_bytes().len(); let len_str = format!("{:04x}\n", len); let mut header = len_str.as_bytes().to_vec(); let mut buffer = Vec::::new(); buffer.append(&mut header); buffer.append(&mut message.as_str().as_bytes().to_vec()); let data = TaskMessage { channel_id: *channel_id2, command: HdcCommand::KernelEchoRaw, payload: buffer.to_vec(), }; transfer::put(*session_id2, data).await; } } pub async fn add_tracker(&self, channel_id: u32, session_id: u32, display: DisplayType) { let mut trackers_lock = self.trackers.lock().await; trackers_lock.push((channel_id, session_id, display)); drop(trackers_lock); let node_map = self.poll_node_map.clone(); Self::send_process_list(self.trackers.clone(), node_map).await; } pub async fn get_process_list(&self) -> String { let mut result = String::from(""); let map = self.poll_node_map.clone(); let map = map.lock().await; let keys = map.keys(); for key in keys { let value = map.get(key); if let Some(v) = value { result.push_str((v.ppid.to_string() + "\n").as_str()); } } result } pub async fn get_process_list_with_pkg_name(map: NodeMap, display: DisplayType) -> String { let mut result = String::from(""); let map = map.lock().await; let keys = map.keys(); for key in keys { let value = map.get(key); if let Some(v) = value { if display == DisplayType::AllApp { result.push_str((v.ppid.to_string() + " " + v.pkg_name.as_str() + "\n").as_str()); } else if display == DisplayType::DebugApp { if v.is_debug { result.push_str((v.ppid.to_string() + " " + v.pkg_name.as_str() + "\n").as_str()); } } else if display == DisplayType::AllAppWithType { let mut apptype = String::from("release"); if v.is_debug { apptype = String::from("debug"); } result.push_str(( v.ppid.to_string() + " " + v.pkg_name.as_str() + " " + apptype.as_str() + "\n").as_str()); } } } result } fn chang_item_once() { static ONCE: Once = Once::new(); ONCE.call_once(|| { let result = set_dev_item("persist.hdc.jdwp", "0"); crate::info!("set persist.hdc.jdwp to 0 result: {}", result); } ); } pub async fn handle_client(fd: i32, waiter: Arc, node_map: NodeMap) { crate::info!("handle_client start..."); let mut buffer: [u8; 1024] = [0; 1024]; let size = UdsServer::wrap_recv(fd, &mut buffer); let u32_size = std::mem::size_of::(); if size > u32_size as isize { let len = u32::from_le_bytes(buffer[0..u32_size].try_into().unwrap_or_default()); let pid = u32::from_le_bytes(buffer[u32_size..2 * u32_size].try_into().unwrap_or_default()); if pid == 0 || len == 0 { crate::warn!("Data parsing exception. pid {pid}, len {len}"); return; } crate::info!("pid:{}", pid); let is_debug = u32::from_le_bytes(buffer[u32_size * 2..3 * u32_size].try_into().unwrap_or_default()) == 1; crate::info!("debug:{}", is_debug); let pkg_name = String::from_utf8(buffer[u32_size * 3..len as usize].to_vec()).unwrap_or_default(); crate::info!("pkg name:{}", pkg_name); Self::chang_item_once(); let node_map = node_map.clone(); let mut map = node_map.lock().await; let node = PollNode::new(fd, pid, pkg_name.clone(), is_debug); let mut key_ = -1; for (key, value) in map.iter() { if value.pkg_name == pkg_name { key_ = *key; UdsServer::wrap_close(value.fd); break; } } if key_ != -1 { map.remove(&key_); } map.insert(fd, node); drop(map); waiter.wake_one(); } else if size <= u32_size as isize { crate::info!("The data length is too short, size = {size}"); } } pub fn jdwp_listen(&self) -> bool { let fd = UdsServer::wrap_socket(SOCK_STREAM); let name = JPID_SOCKET_PATH.as_bytes(); let socket_name = &mut [0u8; PATH_LEN]; socket_name[0] = b'\0'; socket_name[1..].copy_from_slice(name); let addr = UdsAddr::parse_abstract(&socket_name[1..]); if let Ok(addr_obj) = &addr { if let Err(ret) = UdsServer::wrap_bind(fd, addr_obj) { crate::error!("bind fail. {ret:?}"); return false; } let ret = UdsServer::wrap_listen(fd); if ret < 0 { crate::error!("listen fail, ret = {ret}"); return false; } let node_map = self.poll_node_map.clone(); let waiter = self.new_process_waiter.clone(); ylong_runtime::spawn(async move { loop { let client_fd = UdsServer::wrap_accept(fd); if client_fd == -1 { crate::error!("wrap_accept failed"); break; } let map = node_map.clone(); let w = waiter.clone(); utils::spawn(Self::handle_client(client_fd, w, map)); } }); true } else { crate::info!("parse addr fail "); false } } pub fn start_data_looper(&self) { let node_map = self.poll_node_map.clone(); let socketpair_map = self.socketpair_map.clone(); let trackers = self.trackers.clone(); let await_fd = self.await_fd; utils::spawn(async move { loop { let mut poll_nodes = Vec::::new(); let mut fd_node = PollNode::new(await_fd, 0, "".to_string(), false); fd_node.revents = 0; fd_node.events = POLLIN; poll_nodes.push(fd_node); let node_map_value = node_map.lock().await; let keys = node_map_value.keys(); for k in keys { if let Some(n) = node_map_value.get(k) { poll_nodes.push(n.clone()); } } let size = poll_nodes.len(); drop(node_map_value); UdsServer::wrap_poll(poll_nodes.as_mut_slice(), size.try_into().unwrap_or_default(), -1); let mut node_map_value = node_map.lock().await; for pnode in &poll_nodes { if pnode.revents & (POLLNVAL | POLLRDHUP | POLLHUP | POLLERR) != 0 { crate::info!("start_data_looper remove node:{}", pnode.pkg_name); node_map_value.remove(&pnode.fd); UdsServer::wrap_close(pnode.fd); let pid = pnode.ppid; let mut socketpair_map_lock = socketpair_map.lock().await; if let Some(vec) = socketpair_map_lock.remove(&pid) { let lock = vec.lock().await; for (fd0, fd1) in lock.iter() { //此处close socketpair,会导致hdcd和aa之间的pipe异常,hdcd读取不到aa force-stop的返回结果 crate::info!("start_data_looper close pid:{}, socketpair_fd:({},{})", pid, fd0, fd1); } } } else if pnode.fd == await_fd && pnode.revents & POLLIN != 0 { UdsServer::wrap_read_fd(await_fd); } } drop(node_map_value); let trackers = trackers.clone(); let node_map = node_map.clone(); Self::send_process_list(trackers, node_map).await; } }); } pub async fn create_fd_event_poll(&self) { loop { let waiter = self.new_process_waiter.clone(); waiter.wait().await; UdsServer::wrap_write_fd(self.await_fd); } } pub async fn init(&self) -> ErrCode { if !self.jdwp_listen() { crate::info!("jdwp_listen failed"); return ErrCode::ModuleJdwpFailed; } self.start_data_looper(); set_dev_item("persist.hdc.jdwp", "0"); let result = set_dev_item("persist.hdc.jdwp", "1"); crate::info!("init set persist.hdc.jdwp to 1 result: {}", result); self.create_fd_event_poll().await; ErrCode::Success } } pub async fn stop_session_task(session_id: u32) { let jdwp = Jdwp::get_instance(); let mut trackers = jdwp.trackers.lock().await; trackers.retain(|x| x.1 != session_id); } pub async fn stop_task(session_id: u32, channel_id: u32) { let jdwp = Jdwp::get_instance(); let mut trackers = jdwp.trackers.lock().await; trackers.retain(|x| x.1 != session_id || x.0 != channel_id); }