1 // Copyright (C) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::collections::HashMap;
15 use std::fs::File;
16 use std::os::fd::{IntoRawFd, RawFd};
17 
18 use ipc::parcel::MsgParcel;
19 use ipc::{IpcResult, IpcStatusCode};
20 
21 use crate::error::ErrorCode;
22 use crate::manage::account::GetOhosAccountUid;
23 use crate::manage::events::TaskManagerEvent;
24 use crate::service::permission::PermissionChecker;
25 use crate::service::RequestServiceStub;
26 use crate::task::config::{Action, CommonTaskConfig, Mode, NetworkConfig, TaskConfig, Version};
27 use crate::task::ATOMIC_SERVICE;
28 use crate::utils::form_item::{FileSpec, FormItem};
29 use crate::utils::query_calling_bundle;
30 
31 impl RequestServiceStub {
construct(&self, data: &mut MsgParcel, reply: &mut MsgParcel) -> IpcResult<()>32     pub(crate) fn construct(&self, data: &mut MsgParcel, reply: &mut MsgParcel) -> IpcResult<()> {
33         info!("Service construct");
34 
35         if !PermissionChecker::check_internet() {
36             error!("End Service construct, failed: no INTERNET permission");
37             reply.write(&(ErrorCode::Permission as i32))?;
38             return Err(IpcStatusCode::Failed);
39         }
40 
41         let action: u32 = data.read()?;
42         let action: Action = Action::from(action as u8);
43 
44         let version: u32 = data.read()?;
45         let version: Version = Version::from(version as u8);
46 
47         let mode: u32 = data.read()?;
48         let mode: Mode = Mode::from(mode as u8);
49 
50         let bundle_type: u32 = data.read()?;
51 
52         let cover: bool = data.read()?;
53 
54         let network: u32 = data.read()?;
55         let network_config = NetworkConfig::from(network as u8);
56 
57         let metered: bool = data.read()?;
58 
59         let roaming: bool = data.read()?;
60 
61         let retry: bool = data.read()?;
62 
63         let redirect: bool = data.read()?;
64 
65         let background: bool = data.read()?;
66 
67         let index: u32 = data.read()?;
68 
69         let begins: i64 = data.read()?;
70 
71         let ends: i64 = data.read()?;
72 
73         let gauge: bool = data.read()?;
74 
75         let precise: bool = data.read()?;
76 
77         let priority: u32 = data.read()?;
78 
79         let url: String = data.read()?;
80 
81         let title: String = data.read()?;
82 
83         let method: String = data.read()?;
84 
85         let token: String = data.read()?;
86 
87         let description: String = data.read()?;
88 
89         let data_base: String = data.read()?;
90 
91         let proxy: String = data.read()?;
92 
93         let certificate_pins: String = data.read()?;
94 
95         let bundle = query_calling_bundle();
96 
97         let uid = ipc::Skeleton::calling_uid();
98         let token_id = ipc::Skeleton::calling_full_token_id();
99         let pid = ipc::Skeleton::calling_pid();
100 
101         let certs_path_size: u32 = data.read()?;
102         if certs_path_size > data.readable() as u32 {
103             error!("End Service construct, failed: certs_path_size too large");
104             reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
105             return Err(IpcStatusCode::Failed);
106         }
107         let mut certs_path = Vec::new();
108         for _ in 0..certs_path_size {
109             let cert_path: String = data.read()?;
110             certs_path.push(cert_path);
111         }
112 
113         let form_size: u32 = data.read()?;
114         if form_size > data.readable() as u32 {
115             error!("End Service construct, failed: form_size too large");
116             reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
117             return Err(IpcStatusCode::Failed);
118         }
119         let mut form_items = Vec::new();
120         for _ in 0..form_size {
121             let name: String = data.read()?;
122             let value: String = data.read()?;
123             form_items.push(FormItem { name, value });
124         }
125 
126         let file_size: u32 = data.read()?;
127         if file_size > data.readable() as u32 {
128             error!("End Service construct, failed: file_specs size too large");
129             reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
130             return Err(IpcStatusCode::Failed);
131         }
132         let mut file_specs: Vec<FileSpec> = Vec::new();
133         for _ in 0..file_size {
134             let name: String = data.read()?;
135             let path: String = data.read()?;
136             let file_name: String = data.read()?;
137             let mime_type: String = data.read()?;
138             let is_user_file: bool = data.read()?;
139             let mut fd: Option<RawFd> = None;
140             if is_user_file {
141                 let ipc_fd: File = data.read_file()?;
142                 fd = Some(ipc_fd.into_raw_fd());
143             }
144             file_specs.push(FileSpec {
145                 name,
146                 path,
147                 file_name,
148                 mime_type,
149                 is_user_file,
150                 fd,
151             });
152         }
153 
154         // Response bodies fd.
155         let body_file_size: u32 = data.read()?;
156         if body_file_size > data.readable() as u32 {
157             error!("End Service construct, failed: body_file size too large");
158             reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
159             return Err(IpcStatusCode::Failed);
160         }
161 
162         let mut body_file_paths: Vec<String> = Vec::new();
163         for _ in 0..body_file_size {
164             let file_name: String = data.read()?;
165             body_file_paths.push(file_name);
166         }
167 
168         let header_size: u32 = data.read()?;
169         if header_size > data.readable() as u32 {
170             error!("End Service construct, failed: header size too large");
171             reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
172             return Err(IpcStatusCode::Failed);
173         }
174         let mut headers: HashMap<String, String> = HashMap::new();
175         for _ in 0..header_size {
176             let key: String = data.read()?;
177             let value: String = data.read()?;
178             headers.insert(key, value);
179         }
180 
181         let extras_size: u32 = data.read()?;
182         if extras_size > data.readable() as u32 {
183             error!("End Service construct, failed: extras size too large");
184             reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
185             return Err(IpcStatusCode::Failed);
186         }
187         let mut extras: HashMap<String, String> = HashMap::new();
188         for _ in 0..extras_size {
189             let key: String = data.read()?;
190             let value: String = data.read()?;
191             extras.insert(key, value);
192         }
193 
194         let atomic_account = if bundle_type == ATOMIC_SERVICE {
195             GetOhosAccountUid()
196         } else {
197             "".to_string()
198         };
199 
200         let task_config = TaskConfig {
201             bundle,
202             bundle_type,
203             atomic_account,
204             url,
205             title,
206             description,
207             method,
208             headers,
209             data: data_base,
210             token,
211             proxy,
212             certificate_pins,
213             extras,
214             version,
215             form_items,
216             file_specs,
217             body_file_paths,
218             certs_path,
219             common_data: CommonTaskConfig {
220                 task_id: 0,
221                 uid,
222                 token_id,
223                 action,
224                 mode,
225                 cover,
226                 network_config,
227                 metered,
228                 roaming,
229                 retry,
230                 redirect,
231                 index,
232                 begins: begins as u64,
233                 ends,
234                 gauge,
235                 precise,
236                 priority,
237                 background,
238             },
239         };
240 
241         debug!("Service construct: task_config constructed");
242 
243         let (event, rx) = TaskManagerEvent::construct(task_config);
244         if !self.task_manager.lock().unwrap().send_event(event) {
245             return Err(IpcStatusCode::Failed);
246         }
247         let ret = match rx.get() {
248             Some(ret) => ret,
249             None => {
250                 error!("End Service construct, failed: receives ret failed");
251                 return Err(IpcStatusCode::Failed);
252             }
253         };
254 
255         let task_id = match ret {
256             Ok(id) => id,
257             Err(err_code) => {
258                 error!("End Service construct, failed: {:?}", err_code);
259                 reply.write(&(err_code as i32))?;
260                 return Err(IpcStatusCode::Failed);
261             }
262         };
263 
264         debug!("Service construct: construct event sent to manager");
265 
266         let ret = self.client_manager.subscribe(task_id, pid, uid, token_id);
267         if ret != ErrorCode::ErrOk {
268             error!("End Service subscribe, tid: {}, failed: {:?}", task_id, ret);
269             reply.write(&(ret as i32))?;
270             reply.write(&(task_id as i32))?;
271             return Ok(());
272         }
273 
274         reply.write(&(ErrorCode::ErrOk as i32))?;
275         debug!("End Service construct, succeed with tid: {}", task_id);
276         reply.write(&(task_id as i32))?;
277         Ok(())
278     }
279 }
280