1cc290419Sopenharmony_ci/*
2cc290419Sopenharmony_ci * Copyright (C) 2023 Huawei Device Co., Ltd.
3cc290419Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4cc290419Sopenharmony_ci * you may not use this file except in compliance with the License.
5cc290419Sopenharmony_ci * You may obtain a copy of the License at
6cc290419Sopenharmony_ci *
7cc290419Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8cc290419Sopenharmony_ci *
9cc290419Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10cc290419Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11cc290419Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cc290419Sopenharmony_ci * See the License for the specific language governing permissions and
13cc290419Sopenharmony_ci * limitations under the License.
14cc290419Sopenharmony_ci */
15cc290419Sopenharmony_ciuse crate::daemon_lib::mount;
16cc290419Sopenharmony_ciuse crate::daemon_lib::task_manager;
17cc290419Sopenharmony_ciuse crate::common::jdwp::DisplayType;
18cc290419Sopenharmony_ciuse crate::common::jdwp::Jdwp;
19cc290419Sopenharmony_ciuse crate::daemon_lib::sys_para::*;
20cc290419Sopenharmony_ciuse crate::utils::hdc_log::*;
21cc290419Sopenharmony_ciuse crate::common::hdctransfer;
22cc290419Sopenharmony_ciuse crate::config::{self, HdcCommand, MessageLevel};
23cc290419Sopenharmony_ciuse libc::sync;
24cc290419Sopenharmony_ci
25cc290419Sopenharmony_ciextern "C" {
26cc290419Sopenharmony_ci    fn Restart();
27cc290419Sopenharmony_ci}
28cc290419Sopenharmony_ci
29cc290419Sopenharmony_ciasync fn hdc_restart() {
30cc290419Sopenharmony_ci    crate::info!("Mode changed, hdc daemon restart!");
31cc290419Sopenharmony_ci    unsafe {
32cc290419Sopenharmony_ci        Restart();
33cc290419Sopenharmony_ci    }
34cc290419Sopenharmony_ci}
35cc290419Sopenharmony_ci
36cc290419Sopenharmony_ciasync fn echo_client(session_id: u32, channel_id: u32, message: &str, level: MessageLevel) {
37cc290419Sopenharmony_ci    hdctransfer::echo_client(session_id, channel_id, message, level).await;
38cc290419Sopenharmony_ci}
39cc290419Sopenharmony_ci
40cc290419Sopenharmony_ciasync fn echo_device_mode_result(session_id: u32, channel_id: u32, result: bool, message: &str) {
41cc290419Sopenharmony_ci    if result {
42cc290419Sopenharmony_ci        echo_client(
43cc290419Sopenharmony_ci            session_id,
44cc290419Sopenharmony_ci            channel_id,
45cc290419Sopenharmony_ci            "Set device run mode successful.",
46cc290419Sopenharmony_ci            MessageLevel::Ok,
47cc290419Sopenharmony_ci        )
48cc290419Sopenharmony_ci        .await;
49cc290419Sopenharmony_ci    } else {
50cc290419Sopenharmony_ci        let msg = format!("Set device run mode failed: {}", message);
51cc290419Sopenharmony_ci        echo_client(session_id, channel_id, msg.as_str(), MessageLevel::Fail).await;
52cc290419Sopenharmony_ci    }
53cc290419Sopenharmony_ci    task_finish(session_id, channel_id).await;
54cc290419Sopenharmony_ci}
55cc290419Sopenharmony_ci
56cc290419Sopenharmony_ciasync fn echo_reboot_result(session_id: u32, channel_id: u32, result: bool, message: &str) {
57cc290419Sopenharmony_ci    if result {
58cc290419Sopenharmony_ci        echo_client(
59cc290419Sopenharmony_ci            session_id,
60cc290419Sopenharmony_ci            channel_id,
61cc290419Sopenharmony_ci            "Reboot successful.",
62cc290419Sopenharmony_ci            MessageLevel::Ok,
63cc290419Sopenharmony_ci        )
64cc290419Sopenharmony_ci        .await;
65cc290419Sopenharmony_ci    } else {
66cc290419Sopenharmony_ci        let msg = format!("Reboot failed: {}", message);
67cc290419Sopenharmony_ci        echo_client(session_id, channel_id, msg.as_str(), MessageLevel::Fail).await;
68cc290419Sopenharmony_ci    }
69cc290419Sopenharmony_ci    task_finish(session_id, channel_id).await;
70cc290419Sopenharmony_ci}
71cc290419Sopenharmony_ci
72cc290419Sopenharmony_ciasync fn echo_root_run_mode_result(session_id: u32, channel_id: u32, result: bool, message: &str) {
73cc290419Sopenharmony_ci    if result {
74cc290419Sopenharmony_ci        let msg = format!("Set {} run mode successful.", message);
75cc290419Sopenharmony_ci        echo_client(session_id, channel_id, msg.as_str(), MessageLevel::Ok).await;
76cc290419Sopenharmony_ci    } else {
77cc290419Sopenharmony_ci        let msg = format!("Set {} run mode failed.", message);
78cc290419Sopenharmony_ci        echo_client(session_id, channel_id, msg.as_str(), MessageLevel::Fail).await;
79cc290419Sopenharmony_ci    }
80cc290419Sopenharmony_ci    task_finish(session_id, channel_id).await;
81cc290419Sopenharmony_ci}
82cc290419Sopenharmony_ci
83cc290419Sopenharmony_ciasync fn set_root_run_enable(session_id: u32, channel_id: u32, root: bool) {
84cc290419Sopenharmony_ci    let root_flag = if root { "0" } else { "1" };
85cc290419Sopenharmony_ci    let mode_msg = if root { "sh" } else { "root" };
86cc290419Sopenharmony_ci    let result = set_dev_item(config::ENV_ROOT_RUN_MODE, root_flag);
87cc290419Sopenharmony_ci    echo_root_run_mode_result(session_id, channel_id, result, mode_msg).await;
88cc290419Sopenharmony_ci    crate::info!(
89cc290419Sopenharmony_ci        "set_root_run_enable: session_id: {}, channel_id: {}, root: {}, result: {}",
90cc290419Sopenharmony_ci        session_id,
91cc290419Sopenharmony_ci        channel_id,
92cc290419Sopenharmony_ci        root,
93cc290419Sopenharmony_ci        result
94cc290419Sopenharmony_ci    );
95cc290419Sopenharmony_ci    if result {
96cc290419Sopenharmony_ci        crate::info!("set_root_run root:{root} free_all_session");
97cc290419Sopenharmony_ci        task_manager::free_all_sessiones().await;
98cc290419Sopenharmony_ci        std::process::exit(0);
99cc290419Sopenharmony_ci    }
100cc290419Sopenharmony_ci}
101cc290419Sopenharmony_ci
102cc290419Sopenharmony_ciasync fn set_root_run(session_id: u32, channel_id: u32, _payload: &[u8]) {
103cc290419Sopenharmony_ci    let (ret, debug_able) = get_dev_item(config::ENV_DEBUGGABLE, "_");
104cc290419Sopenharmony_ci    if !ret || debug_able.trim() != "1" {
105cc290419Sopenharmony_ci        crate::info!("get debuggable failed");
106cc290419Sopenharmony_ci        echo_client(
107cc290419Sopenharmony_ci            session_id,
108cc290419Sopenharmony_ci            channel_id,
109cc290419Sopenharmony_ci            "Cannot set root run mode in undebuggable version.",
110cc290419Sopenharmony_ci            MessageLevel::Fail,
111cc290419Sopenharmony_ci        )
112cc290419Sopenharmony_ci        .await;
113cc290419Sopenharmony_ci        task_finish(session_id, channel_id).await;
114cc290419Sopenharmony_ci        return;
115cc290419Sopenharmony_ci    }
116cc290419Sopenharmony_ci
117cc290419Sopenharmony_ci    if _payload.is_empty() {
118cc290419Sopenharmony_ci        set_root_run_enable(session_id, channel_id, false).await;
119cc290419Sopenharmony_ci    } else if _payload == [b'r'] {
120cc290419Sopenharmony_ci        set_root_run_enable(session_id, channel_id, true).await;
121cc290419Sopenharmony_ci    } else {
122cc290419Sopenharmony_ci        echo_root_run_mode_result(session_id, channel_id, false, "Unknown command").await;
123cc290419Sopenharmony_ci    }
124cc290419Sopenharmony_ci}
125cc290419Sopenharmony_ci
126cc290419Sopenharmony_ciasync fn reboot_device(session_id: u32, channel_id: u32, _payload: &[u8]) {
127cc290419Sopenharmony_ci    unsafe {
128cc290419Sopenharmony_ci        sync();
129cc290419Sopenharmony_ci    };
130cc290419Sopenharmony_ci
131cc290419Sopenharmony_ci    let param = match String::from_utf8(_payload.to_vec()) {
132cc290419Sopenharmony_ci        Ok(param) => param,
133cc290419Sopenharmony_ci        Err(_) => String::from("Unknown"),
134cc290419Sopenharmony_ci    };
135cc290419Sopenharmony_ci
136cc290419Sopenharmony_ci    let mut cmd = String::from("reboot");
137cc290419Sopenharmony_ci    if !param.is_empty() {
138cc290419Sopenharmony_ci        cmd.push(',');
139cc290419Sopenharmony_ci        cmd.push_str(param.as_str());
140cc290419Sopenharmony_ci    }
141cc290419Sopenharmony_ci    let cmd = cmd.trim();
142cc290419Sopenharmony_ci    let result = set_dev_item(config::ENV_STARTUP, cmd);
143cc290419Sopenharmony_ci    echo_reboot_result(session_id, channel_id, result, cmd).await;
144cc290419Sopenharmony_ci}
145cc290419Sopenharmony_ci
146cc290419Sopenharmony_ciasync fn remount_device(session_id: u32, channel_id: u32) {
147cc290419Sopenharmony_ci    unsafe {
148cc290419Sopenharmony_ci        if libc::getuid() != 0 {
149cc290419Sopenharmony_ci            echo_client(
150cc290419Sopenharmony_ci                session_id,
151cc290419Sopenharmony_ci                channel_id,
152cc290419Sopenharmony_ci                "Operate need running as root",
153cc290419Sopenharmony_ci                MessageLevel::Fail,
154cc290419Sopenharmony_ci            )
155cc290419Sopenharmony_ci            .await;
156cc290419Sopenharmony_ci            task_finish(session_id, channel_id).await;
157cc290419Sopenharmony_ci            return;
158cc290419Sopenharmony_ci        }
159cc290419Sopenharmony_ci    }
160cc290419Sopenharmony_ci    let ret = mount::remount_device();
161cc290419Sopenharmony_ci    if ret {
162cc290419Sopenharmony_ci        echo_client(session_id, channel_id, "Mount finish", MessageLevel::Ok).await;
163cc290419Sopenharmony_ci    } else {
164cc290419Sopenharmony_ci        echo_client(session_id, channel_id, "Mount failed", MessageLevel::Fail).await;
165cc290419Sopenharmony_ci    }
166cc290419Sopenharmony_ci    task_finish(session_id, channel_id).await;
167cc290419Sopenharmony_ci}
168cc290419Sopenharmony_ci
169cc290419Sopenharmony_ciasync fn set_device_mode(session_id: u32, channel_id: u32, _payload: &[u8]) {
170cc290419Sopenharmony_ci    let param = match String::from_utf8(_payload.to_vec()) {
171cc290419Sopenharmony_ci        Ok(param) => param,
172cc290419Sopenharmony_ci        Err(_) => String::from("Unknown"),
173cc290419Sopenharmony_ci    };
174cc290419Sopenharmony_ci    match param.as_str() {
175cc290419Sopenharmony_ci        config::MODE_USB => {
176cc290419Sopenharmony_ci            let result = set_dev_item(config::ENV_HDC_MODE, config::MODE_USB);
177cc290419Sopenharmony_ci            echo_device_mode_result(session_id, channel_id, result, config::MODE_USB).await;
178cc290419Sopenharmony_ci            if result {
179cc290419Sopenharmony_ci                crate::info!("tmode usb free_all_session");
180cc290419Sopenharmony_ci                task_manager::free_all_sessiones().await;
181cc290419Sopenharmony_ci                hdc_restart().await
182cc290419Sopenharmony_ci            }
183cc290419Sopenharmony_ci        }
184cc290419Sopenharmony_ci        str if str.starts_with(config::PREFIX_PORT) => {
185cc290419Sopenharmony_ci            let result = set_dev_item(config::ENV_HDC_MODE, config::MODE_TCP);
186cc290419Sopenharmony_ci            if !result {
187cc290419Sopenharmony_ci                echo_device_mode_result(session_id, channel_id, result, config::MODE_TCP).await;
188cc290419Sopenharmony_ci                return;
189cc290419Sopenharmony_ci            }
190cc290419Sopenharmony_ci
191cc290419Sopenharmony_ci            let port = &str[config::PREFIX_PORT.len()..];
192cc290419Sopenharmony_ci            let port =
193cc290419Sopenharmony_ci                port.trim_end_matches(|c: char| c.is_ascii_control() || c.is_ascii_whitespace());
194cc290419Sopenharmony_ci            let result = set_dev_item(config::ENV_HOST_PORT, port);
195cc290419Sopenharmony_ci            echo_device_mode_result(session_id, channel_id, result, config::ENV_HOST_PORT).await;
196cc290419Sopenharmony_ci            if result {
197cc290419Sopenharmony_ci                crate::info!("tmode port:{port} free_all_session");
198cc290419Sopenharmony_ci                task_manager::free_all_sessiones().await;
199cc290419Sopenharmony_ci                hdc_restart().await
200cc290419Sopenharmony_ci            }
201cc290419Sopenharmony_ci        }
202cc290419Sopenharmony_ci        _ => {
203cc290419Sopenharmony_ci            echo_device_mode_result(session_id, channel_id, false, "Unknown command").await;
204cc290419Sopenharmony_ci        }
205cc290419Sopenharmony_ci    }
206cc290419Sopenharmony_ci}
207cc290419Sopenharmony_ci
208cc290419Sopenharmony_ciasync fn do_jdwp_list(session_id: u32, channel_id: u32) {
209cc290419Sopenharmony_ci    crate::debug!("do_jdwp_list, session_id {session_id}, channel_id {channel_id}");
210cc290419Sopenharmony_ci    let jdwp = Jdwp::get_instance().clone();
211cc290419Sopenharmony_ci    let process_list = jdwp.get_process_list().await;
212cc290419Sopenharmony_ci    if process_list.is_empty() {
213cc290419Sopenharmony_ci        echo_client(session_id, channel_id, "[Empty]", MessageLevel::Ok).await;
214cc290419Sopenharmony_ci    } else {
215cc290419Sopenharmony_ci        echo_client(
216cc290419Sopenharmony_ci            session_id,
217cc290419Sopenharmony_ci            channel_id,
218cc290419Sopenharmony_ci            process_list.as_str(),
219cc290419Sopenharmony_ci            MessageLevel::Ok,
220cc290419Sopenharmony_ci        )
221cc290419Sopenharmony_ci        .await;
222cc290419Sopenharmony_ci    }
223cc290419Sopenharmony_ci    task_finish(session_id, channel_id).await;
224cc290419Sopenharmony_ci}
225cc290419Sopenharmony_ci
226cc290419Sopenharmony_ciasync fn do_jdwp_track(session_id: u32, channel_id: u32, payload: &[u8]) {
227cc290419Sopenharmony_ci    // 0:AllApp 1:DebugApp 2:ReleaseApp 3:AllAppWithType
228cc290419Sopenharmony_ci    let mut display = DisplayType::DebugApp;
229cc290419Sopenharmony_ci    if !payload.is_empty() && payload[0] == b'p' {
230cc290419Sopenharmony_ci        display = DisplayType::AllApp;
231cc290419Sopenharmony_ci    } else if !payload.is_empty() && payload[0] == b'a' {
232cc290419Sopenharmony_ci        display = DisplayType::AllAppWithType;
233cc290419Sopenharmony_ci    }
234cc290419Sopenharmony_ci    let jdwp = Jdwp::get_instance().clone();
235cc290419Sopenharmony_ci    jdwp.add_tracker(channel_id, session_id, display)
236cc290419Sopenharmony_ci        .await;
237cc290419Sopenharmony_ci}
238cc290419Sopenharmony_ci
239cc290419Sopenharmony_cipub async fn command_dispatch(
240cc290419Sopenharmony_ci    session_id: u32,
241cc290419Sopenharmony_ci    channel_id: u32,
242cc290419Sopenharmony_ci    _command: HdcCommand,
243cc290419Sopenharmony_ci    _payload: &[u8],
244cc290419Sopenharmony_ci    _payload_size: u16,
245cc290419Sopenharmony_ci) -> bool {
246cc290419Sopenharmony_ci    crate::info!("DaemonUnityTask: command:{:?}", _command);
247cc290419Sopenharmony_ci    match _command {
248cc290419Sopenharmony_ci        HdcCommand::UnityReboot => reboot_device(session_id, channel_id, _payload).await,
249cc290419Sopenharmony_ci        HdcCommand::UnityRunmode => set_device_mode(session_id, channel_id, _payload).await,
250cc290419Sopenharmony_ci        HdcCommand::UnityRootrun => set_root_run(session_id, channel_id, _payload).await,
251cc290419Sopenharmony_ci        HdcCommand::JdwpList => do_jdwp_list(session_id, channel_id).await,
252cc290419Sopenharmony_ci        HdcCommand::JdwpTrack => do_jdwp_track(session_id, channel_id, _payload).await,
253cc290419Sopenharmony_ci        HdcCommand::UnityRemount => remount_device(session_id, channel_id).await,
254cc290419Sopenharmony_ci        _ => {
255cc290419Sopenharmony_ci            crate::error!("other command, {:?}", _command);
256cc290419Sopenharmony_ci        }
257cc290419Sopenharmony_ci    }
258cc290419Sopenharmony_ci    true
259cc290419Sopenharmony_ci}
260cc290419Sopenharmony_ci
261cc290419Sopenharmony_ciasync fn task_finish(session_id: u32, channel_id: u32) {
262cc290419Sopenharmony_ci    hdctransfer::transfer_task_finish(channel_id, session_id).await;
263cc290419Sopenharmony_ci}
264