• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::notification_bar::NotificationDispatcher;
25 use crate::service::permission::PermissionChecker;
26 use crate::service::RequestServiceStub;
27 use crate::task::config::{Action, CommonTaskConfig, Mode, NetworkConfig, TaskConfig, Version};
28 use crate::task::ATOMIC_SERVICE;
29 use crate::utils::form_item::{FileSpec, FormItem};
30 use crate::utils::query_calling_bundle;
31 
32 impl RequestServiceStub {
construct(&self, data: &mut MsgParcel, reply: &mut MsgParcel) -> IpcResult<()>33     pub(crate) fn construct(&self, data: &mut MsgParcel, reply: &mut MsgParcel) -> IpcResult<()> {
34         info!("Service construct");
35 
36         if !PermissionChecker::check_internet() {
37             error!("End Service construct, failed: no INTERNET permission");
38             reply.write(&(ErrorCode::Permission as i32))?;
39             return Err(IpcStatusCode::Failed);
40         }
41 
42         let action: u32 = data.read()?;
43         let action: Action = Action::from(action as u8);
44 
45         let version: u32 = data.read()?;
46         let version: Version = Version::from(version as u8);
47 
48         let mode: u32 = data.read()?;
49         let mode: Mode = Mode::from(mode as u8);
50 
51         let bundle_type: u32 = data.read()?;
52 
53         let cover: bool = data.read()?;
54 
55         let network: u32 = data.read()?;
56         let network_config = NetworkConfig::from(network as u8);
57 
58         let metered: bool = data.read()?;
59 
60         let roaming: bool = data.read()?;
61 
62         let retry: bool = data.read()?;
63 
64         let redirect: bool = data.read()?;
65 
66         let background: bool = data.read()?;
67 
68         let multipart: bool = data.read()?;
69 
70         let index: u32 = data.read()?;
71 
72         let begins: i64 = data.read()?;
73 
74         let ends: i64 = data.read()?;
75 
76         let gauge: bool = data.read()?;
77 
78         let precise: bool = data.read()?;
79 
80         let priority: u32 = data.read()?;
81 
82         let url: String = data.read()?;
83 
84         let title: String = data.read()?;
85 
86         let method: String = data.read()?;
87 
88         let token: String = data.read()?;
89 
90         let description: String = data.read()?;
91 
92         let data_base: String = data.read()?;
93 
94         let proxy: String = data.read()?;
95 
96         let certificate_pins: String = data.read()?;
97 
98         let bundle = query_calling_bundle();
99 
100         let uid = ipc::Skeleton::calling_uid();
101         let token_id = ipc::Skeleton::calling_full_token_id();
102         let pid = ipc::Skeleton::calling_pid();
103 
104         let certs_path_size: u32 = data.read()?;
105         if certs_path_size > data.readable() as u32 {
106             error!("End Service construct, failed: certs_path_size too large");
107             reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
108             return Err(IpcStatusCode::Failed);
109         }
110         let mut certs_path = Vec::new();
111         for _ in 0..certs_path_size {
112             let cert_path: String = data.read()?;
113             certs_path.push(cert_path);
114         }
115 
116         let form_size: u32 = data.read()?;
117         if form_size > data.readable() as u32 {
118             error!("End Service construct, failed: form_size too large");
119             reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
120             return Err(IpcStatusCode::Failed);
121         }
122         let mut form_items = Vec::new();
123         for _ in 0..form_size {
124             let name: String = data.read()?;
125             let value: String = data.read()?;
126             form_items.push(FormItem { name, value });
127         }
128 
129         let file_size: u32 = data.read()?;
130         if file_size > data.readable() as u32 {
131             error!("End Service construct, failed: file_specs size too large");
132             reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
133             return Err(IpcStatusCode::Failed);
134         }
135         let mut file_specs: Vec<FileSpec> = Vec::new();
136         for _ in 0..file_size {
137             let name: String = data.read()?;
138             let path: String = data.read()?;
139             let file_name: String = data.read()?;
140             let mime_type: String = data.read()?;
141             let is_user_file: bool = data.read()?;
142             let mut fd: Option<RawFd> = None;
143             if is_user_file {
144                 let ipc_fd: File = data.read_file()?;
145                 fd = Some(ipc_fd.into_raw_fd());
146             }
147             file_specs.push(FileSpec {
148                 name,
149                 path,
150                 file_name,
151                 mime_type,
152                 is_user_file,
153                 fd,
154             });
155         }
156 
157         // Response bodies fd.
158         let body_file_size: u32 = data.read()?;
159         if body_file_size > data.readable() as u32 {
160             error!("End Service construct, failed: body_file size too large");
161             reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
162             return Err(IpcStatusCode::Failed);
163         }
164 
165         let mut body_file_paths: Vec<String> = Vec::new();
166         for _ in 0..body_file_size {
167             let file_name: String = data.read()?;
168             body_file_paths.push(file_name);
169         }
170 
171         let header_size: u32 = data.read()?;
172         if header_size > data.readable() as u32 {
173             error!("End Service construct, failed: header size too large");
174             reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
175             return Err(IpcStatusCode::Failed);
176         }
177         let mut headers: HashMap<String, String> = HashMap::new();
178         for _ in 0..header_size {
179             let key: String = data.read()?;
180             let value: String = data.read()?;
181             headers.insert(key, value);
182         }
183 
184         let extras_size: u32 = data.read()?;
185         if extras_size > data.readable() as u32 {
186             error!("End Service construct, failed: extras size too large");
187             reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
188             return Err(IpcStatusCode::Failed);
189         }
190         let mut extras: HashMap<String, String> = HashMap::new();
191         for _ in 0..extras_size {
192             let key: String = data.read()?;
193             let value: String = data.read()?;
194             extras.insert(key, value);
195         }
196 
197         let atomic_account = if bundle_type == ATOMIC_SERVICE {
198             GetOhosAccountUid()
199         } else {
200             "".to_string()
201         };
202 
203         let task_config = TaskConfig {
204             bundle,
205             bundle_type,
206             atomic_account,
207             url,
208             title,
209             description,
210             method,
211             headers,
212             data: data_base,
213             token,
214             proxy,
215             certificate_pins,
216             extras,
217             version,
218             form_items,
219             file_specs,
220             body_file_paths,
221             certs_path,
222             common_data: CommonTaskConfig {
223                 task_id: 0,
224                 uid,
225                 token_id,
226                 action,
227                 mode,
228                 cover,
229                 network_config,
230                 metered,
231                 roaming,
232                 retry,
233                 redirect,
234                 index,
235                 begins: begins as u64,
236                 ends,
237                 gauge,
238                 precise,
239                 priority,
240                 background,
241                 multipart,
242             },
243         };
244 
245         debug!("Service construct: task_config constructed");
246 
247         let (event, rx) = TaskManagerEvent::construct(task_config);
248         if !self.task_manager.lock().unwrap().send_event(event) {
249             return Err(IpcStatusCode::Failed);
250         }
251         let ret = match rx.get() {
252             Some(ret) => ret,
253             None => {
254                 error!("End Service construct, failed: receives ret failed");
255                 return Err(IpcStatusCode::Failed);
256             }
257         };
258 
259         let task_id = match ret {
260             Ok(id) => id,
261             Err(err_code) => {
262                 error!("End Service construct, failed: {:?}", err_code);
263                 reply.write(&(err_code as i32))?;
264                 return Err(IpcStatusCode::Failed);
265             }
266         };
267 
268         let title = if data.read::<bool>()? {
269             Some(data.read::<String>()?)
270         } else {
271             None
272         };
273 
274         let text = if data.read::<bool>()? {
275             Some(data.read::<String>()?)
276         } else {
277             None
278         };
279         if title.is_some() || text.is_some() {
280             NotificationDispatcher::get_instance()
281                 .update_task_customized_notification(task_id, title, text);
282         }
283 
284         debug!("Service construct: construct event sent to manager");
285 
286         let ret = self.client_manager.subscribe(task_id, pid, uid, token_id);
287         if ret != ErrorCode::ErrOk {
288             error!("End Service subscribe, tid: {}, failed: {:?}", task_id, ret);
289             reply.write(&(ret as i32))?;
290             reply.write(&(task_id as i32))?;
291             return Ok(());
292         }
293 
294         reply.write(&(ErrorCode::ErrOk as i32))?;
295         debug!("End Service construct, succeed with tid: {}", task_id);
296         reply.write(&(task_id as i32))?;
297         Ok(())
298     }
299 }
300