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