1 /* 2 * Copyright (C) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 use std::ffi::{CString, c_char, c_int, c_uint, c_longlong, c_ulonglong, c_void}; 17 18 use crate::{EventType, WatchRule, QueryArg, QueryRule}; 19 20 /// Length limit for event domain definition. 21 const MAX_LENGTH_OF_EVENT_DOMAIN: usize = 17; 22 23 /// Length limit for event name definition. 24 const MAX_LENGTH_OF_EVENT_NAME: usize = 33; 25 26 /// Length limit for event tag definition. 27 const MAX_LENGTH_OF_EVENT_TAG: usize = 85; 28 29 /// Length limit for timezone definition. 30 const MAX_LENGTH_OF_TIME_ZONE: usize = 6; 31 32 /// Length limit for event list. 33 const MAX_NUMBER_OF_EVENT_LIST: usize = 10; 34 35 /// Length limit for event list definition. 36 const MAX_EVENT_LIST_LEN: usize = 339; 37 38 /// This type represent to HiSysEventWatchRule defined in C. 39 #[repr(C)] 40 #[derive(Copy, Clone)] 41 struct HiSysEventWatchRule { 42 /// The domain of the event. 43 pub domain: [u8; MAX_LENGTH_OF_EVENT_DOMAIN], 44 45 /// The name of the event. 46 pub name: [u8; MAX_LENGTH_OF_EVENT_NAME], 47 48 /// The tag of the event. 49 pub tag: [u8; MAX_LENGTH_OF_EVENT_TAG], 50 51 /// The rule of match system event. 52 pub rule_type: c_int, 53 54 /// The type of match system event. 55 pub event_type: c_int, 56 } 57 58 /// This type represent to HiSysEventQueryArg defined in C. 59 #[repr(C)] 60 #[derive(Copy, Clone)] 61 struct HiSysEventQueryArg { 62 /// Begin time. 63 pub begin_time: c_longlong, 64 65 /// End time. 66 pub end_time: c_longlong, 67 68 /// Max number of receive system event. 69 pub max_events: c_int, 70 } 71 72 /// This type represent to HiSysEventQueryRuleWrapper defined in C. 73 #[repr(C)] 74 #[derive(Copy, Clone)] 75 struct HiSysEventQueryRuleWrapper { 76 // The domain of the event. 77 pub domain: [u8; MAX_LENGTH_OF_EVENT_DOMAIN], 78 79 /// List of event name. 80 pub event_list: [u8; MAX_EVENT_LIST_LEN], 81 82 /// Size of event name list. 83 pub event_list_size: c_uint, 84 85 /// extra condition for event query. 86 pub condition: *const c_char, 87 } 88 89 /// This type represent to HiSysEventRecord defined in C. 90 #[repr(C)] 91 #[derive(Copy, Clone)] 92 pub struct HiSysEventRecord { 93 /// Domain. 94 domain: [u8; MAX_LENGTH_OF_EVENT_DOMAIN], 95 96 /// Event name. 97 event_name: [u8; MAX_LENGTH_OF_EVENT_NAME], 98 99 /// Event type. 100 event_type: c_int, 101 102 /// Timestamp. 103 time: c_ulonglong, 104 105 /// Timezone. 106 tz: [u8; MAX_LENGTH_OF_TIME_ZONE], 107 108 /// Process id. 109 pid: c_longlong, 110 111 /// Thread id. 112 tid: c_longlong, 113 114 /// User id. 115 uid: c_longlong, 116 117 /// Trace id. 118 trace_id: c_ulonglong, 119 120 /// Span id. 121 spand_id: c_ulonglong, 122 123 /// Parent span id. 124 pspan_id: c_ulonglong, 125 126 /// Trace flag. 127 trace_flag: c_int, 128 129 /// Level. 130 level: *const c_char, 131 132 /// Tag. 133 tag: *const c_char, 134 135 /// Event content. 136 json_str: *const c_char, 137 } 138 139 impl HiSysEventRecord { 140 141 /// Get domain name get_domainnull142 pub fn get_domain(&self) -> String { 143 std::str::from_utf8(&self.domain).expect("need valid domain array") 144 .trim_end_matches(char::from(0)).to_string() 145 } 146 147 /// Get event name get_event_namenull148 pub fn get_event_name(&self) -> String { 149 std::str::from_utf8(&self.event_name).expect("need valid event name array") 150 .trim_end_matches(char::from(0)).to_string() 151 } 152 153 /// Get event name get_event_typenull154 pub fn get_event_type(&self) -> EventType { 155 match self.event_type { 156 1 => EventType::Fault, 157 2 => EventType::Statistic, 158 3 => EventType::Security, 159 4 => EventType::Behavior, 160 _ => EventType::Fault, 161 } 162 } 163 164 /// Get time get_timenull165 pub fn get_time(&self) -> u64 { 166 self.time 167 } 168 169 /// Get time zone get_time_zonenull170 pub fn get_time_zone(&self) -> String { 171 std::str::from_utf8(&self.tz).expect("need valid time zone array") 172 .trim_end_matches(char::from(0)).to_string() 173 } 174 175 /// Get process id get_pidnull176 pub fn get_pid(&self) -> i64 { 177 self.pid 178 } 179 180 /// Get thread id get_tidnull181 pub fn get_tid(&self) -> i64 { 182 self.tid 183 } 184 185 /// Get user id get_uidnull186 pub fn get_uid(&self) -> i64 { 187 self.uid 188 } 189 190 /// Get trace id get_trace_idnull191 pub fn get_trace_id(&self) -> u64 { 192 self.trace_id 193 } 194 195 /// Get span id get_span_idnull196 pub fn get_span_id(&self) -> u64 { 197 self.spand_id 198 } 199 200 /// Get parent span id get_parent_span_idnull201 pub fn get_parent_span_id(&self) -> u64 { 202 self.pspan_id 203 } 204 205 /// Get trace flag get_trace_flagnull206 pub fn get_trace_flag(&self) -> i32 { 207 self.trace_flag 208 } 209 210 /// Get level get_levelnull211 pub fn get_level(&self) -> String { 212 let level_arr = unsafe { 213 std::ffi::CString::from_raw(self.level as *mut std::ffi::c_char) 214 }; 215 std::str::from_utf8(level_arr.to_bytes()).expect("need valid level pointer") 216 .trim_end_matches(char::from(0)).to_owned() 217 } 218 219 /// Get tag get_tagnull220 pub fn get_tag(&self) -> String { 221 let tag_arr = unsafe { 222 std::ffi::CString::from_raw(self.tag as *mut std::ffi::c_char) 223 }; 224 let tag = std::str::from_utf8(tag_arr.to_bytes()).expect("need valid tag pointer") 225 .trim_end_matches(char::from(0)); 226 String::from(tag) 227 } 228 229 /// Get json string get_json_strnull230 pub fn get_json_str(&self) -> String { 231 let json_str_arr = unsafe { 232 std::ffi::CString::from_raw(self.json_str as *mut std::ffi::c_char) 233 }; 234 let json_str = std::str::from_utf8(json_str_arr.to_bytes()).expect("need valid json str pointer") 235 .trim_end_matches(char::from(0)); 236 String::from(json_str) 237 } 238 } 239 240 /// Callback for handling query result, the query result will be send in several times. 241 pub type OnQuery = unsafe extern "C" fn ( 242 callback: *mut c_void, 243 records: *const HiSysEventRecord, 244 size: c_uint 245 ); 246 247 /// Callback when event quering finish. 248 pub type OnComplete = unsafe extern "C" fn ( 249 callback: *mut c_void, 250 reason: c_int, 251 total: c_int 252 ); 253 254 /// This type represent a rust HiSysEventRustQuerierC which like C++ HiSysEventRustQuerierC. 255 #[repr(C)] 256 struct HiSysEventRustQuerierC { 257 pub on_query_cb: *mut c_void, 258 pub on_query_wrapper_cb: OnQuery, 259 pub on_complete_cb: *mut c_void, 260 pub on_complete_wrapper_cb: OnComplete, 261 } 262 263 /// This type represent a rust interfaces. 264 #[allow(dead_code)] 265 pub struct Querier { 266 /// Native event querier. 267 native: *mut HiSysEventRustQuerierC, 268 269 /// Customized rust callback on query. 270 on_query_callback: *mut c_void, 271 272 /// Customized rust callback on complete. 273 on_complete_callback: *mut c_void, 274 } 275 276 impl Querier { 277 /// Create a rust HiSysEventRustQuerierC object with callbacks in a querier. newnull278 pub fn new<F1, F2>(on_query_callback: F1, on_complete_callback: F2) -> Option<Self> 279 where 280 F1: Fn(&[HiSysEventRecord]) + Send + Sync + 'static, 281 F2: Fn(i32, i32) + Send + Sync + 'static, 282 { 283 let on_query_callback = Box::into_raw(Box::new(on_query_callback)); 284 let on_complete_callback = Box::into_raw(Box::new(on_complete_callback)); 285 let native = unsafe { 286 CreateRustEventQuerier(on_query_callback as *mut c_void, Self::on_query_callback::<F1>, 287 on_complete_callback as *mut c_void, Self::on_complete_callback::<F2>) 288 }; 289 if native.is_null() { 290 None 291 } else { 292 Some(Self { 293 native, 294 on_query_callback: on_query_callback as *mut c_void, 295 on_complete_callback: on_complete_callback as *mut c_void, 296 }) 297 } 298 } 299 300 /// Callback for handling query result, the query result will be send in several times. 301 /// 302 /// # Safety 303 /// 304 /// The callback parameter will be kept valid during native 305 /// HiSysEventRustQuerierC object lifetime. 306 /// 307 unsafe extern "C" fn on_query_callback<F>(callback: *mut c_void, records: *const HiSysEventRecord, 308 size: c_uint) 309 where 310 F: Fn(&[HiSysEventRecord]) + Send + Sync + 'static, 311 { 312 let mut transalted_records: Vec<HiSysEventRecord> = vec![]; 313 for i in 0..size { 314 let record_item = unsafe { 315 GetHiSysEventRecordByIndexWrapper(records, size, i as c_uint) 316 }; 317 transalted_records.push(record_item); 318 } 319 let callback = (callback as *const F).as_ref().unwrap(); 320 callback(transalted_records.as_slice()); 321 } 322 323 /// Callback when event quering finish. 324 /// 325 /// # Safety 326 /// 327 /// The callback parameter will be kept valid during native 328 /// HiSysEventRustQuerierC object lifetime. 329 /// 330 unsafe extern "C" fn on_complete_callback<F>(callback: *mut c_void, reason: c_int, 331 total: c_int) 332 where 333 F: Fn(i32, i32) + Send + Sync + 'static, 334 { 335 let callback = (callback as *const F).as_ref().unwrap(); 336 callback(reason, total); 337 } 338 339 /// free memories allocated for Querier try_to_recyclenull340 pub fn try_to_recycle(&self) { 341 unsafe { 342 RecycleRustEventQuerier(self.as_raw()) 343 } 344 } 345 } 346 347 /// Implement trait AsRawPtr for Querier 348 /// 349 /// # Safety 350 /// 351 /// A `Querier` is always constructed with a valid raw pointer 352 /// to a `HiSysEventRustQuerierC`. 353 /// 354 unsafe impl AsRawPtr<HiSysEventRustQuerierC> for Querier { as_rawnull355 fn as_raw(&self) -> *const HiSysEventRustQuerierC { 356 self.native 357 } 358 as_mut_rawnull359 fn as_mut_raw(&mut self) -> *mut HiSysEventRustQuerierC { 360 self.native 361 } 362 } 363 364 /// Query system event. 365 pub(crate) fn query(query_arg: &QueryArg, query_rules: &[QueryRule], querier: &Querier) -> i32 { 366 let query_arg_wrapper = HiSysEventQueryArg { 367 begin_time: query_arg.begin_time as c_longlong, 368 end_time: query_arg.end_time as c_longlong, 369 max_events: query_arg.max_events as c_int, 370 }; 371 let mut query_rules_wrapper: Vec<HiSysEventQueryRuleWrapper> = vec![]; 372 for i in 0..query_rules.len() { 373 let condition_wrapper = CString::new(query_rules[i].condition).expect("Need a condition for query."); 374 query_rules_wrapper.push(HiSysEventQueryRuleWrapper { 375 domain: [0; MAX_LENGTH_OF_EVENT_DOMAIN], 376 event_list: [0; MAX_EVENT_LIST_LEN], 377 event_list_size: MAX_NUMBER_OF_EVENT_LIST as c_uint, 378 condition: condition_wrapper.as_ptr() as *const c_char, 379 }); 380 crate::utils::trans_slice_to_array(query_rules[i].domain, &mut query_rules_wrapper[i].domain); 381 let src_len = query_rules[i].event_list.len(); 382 let dest_len = query_rules_wrapper[i].event_list.len(); 383 let total_cnt = if src_len <= dest_len { 384 src_len 385 } else { 386 dest_len 387 }; 388 query_rules_wrapper[i].event_list_size = total_cnt as c_uint; 389 let src_str = query_rules[i].event_list.join("|"); 390 let src_str = &src_str[..]; 391 crate::utils::trans_slice_to_array(src_str, &mut query_rules_wrapper[i].event_list); 392 } 393 // Safty: call C ffi border function, all risks are under control. 394 unsafe { 395 HiSysEventQueryWrapper(&query_arg_wrapper as *const HiSysEventQueryArg, 396 query_rules_wrapper.as_mut_ptr(), 397 query_rules.len() as c_uint, 398 querier.as_raw(), 399 ) 400 } 401 } 402 403 /// Callback when receive system event. 404 pub type OnEvent = unsafe extern "C" fn ( 405 callback: *mut c_void, 406 record: HiSysEventRecord 407 ); 408 409 /// Callback when hisysevent service shutdown. 410 pub type OnServiceDied = unsafe extern "C" fn ( 411 callback: *mut c_void, 412 ); 413 414 /// This type represent a rust HiSysEventWatcher which like C++ HiSysEventWatcher. 415 #[repr(C)] 416 struct HiSysEventRustWatcherC { 417 pub on_event_cb: *mut c_void, 418 pub on_event_wrapper_cb: OnEvent, 419 pub on_service_died_cb: *mut c_void, 420 pub on_service_died_wrapper_cb: OnServiceDied, 421 } 422 423 /// This type represent a rust interfaces. 424 #[allow(dead_code)] 425 pub struct Watcher { 426 /// Native event listener instance 427 native: *mut HiSysEventRustWatcherC, 428 429 /// Customized rust callback on event 430 on_event_callback: *mut c_void, 431 432 /// Customized rust callback on service died 433 on_service_died_callback: *mut c_void, 434 } 435 436 impl Watcher { 437 /// Create a rust HiSysEventRustWatcherC object with callbacks in a watcher. newnull438 pub fn new<F1, F2>(on_event_callback: F1, on_service_died_callback: F2) -> Option<Self> 439 where 440 F1: Fn(HiSysEventRecord) + Send + Sync + 'static, 441 F2: Fn() + Send + Sync + 'static, 442 { 443 let on_event_callback = Box::into_raw(Box::new(on_event_callback)); 444 let on_service_died_callback = Box::into_raw(Box::new(on_service_died_callback)); 445 let native = unsafe { 446 CreateRustEventWatcher(on_event_callback as *mut c_void, Self::on_event::<F1>, 447 on_service_died_callback as *mut c_void, Self::on_service_died::<F2>) 448 }; 449 if native.is_null() { 450 None 451 } else { 452 Some(Self { 453 native, 454 on_event_callback: on_event_callback as *mut c_void, 455 on_service_died_callback: on_service_died_callback as *mut c_void, 456 }) 457 } 458 } 459 460 /// Callback when receive system event. 461 /// 462 /// # Safety 463 /// 464 /// The callback parameter will be kept valid during native 465 /// HiSysEventRustWatcherC object lifetime. 466 /// 467 unsafe extern "C" fn on_event<F>(callback: *mut c_void, record: HiSysEventRecord) 468 where 469 F: Fn(HiSysEventRecord) + Send + Sync + 'static, 470 { 471 let callback = (callback as *const F).as_ref().unwrap(); 472 callback(record); 473 } 474 475 /// Callback when hisysevent service shutdown. 476 /// 477 /// # Safety 478 /// 479 /// The callback parameter will be kept valid during native 480 /// HiSysEventRustWatcherC object lifetime. 481 /// 482 unsafe extern "C" fn on_service_died<F>(callback: *mut c_void) 483 where 484 F: Fn() + Send + Sync + 'static, 485 { 486 let callback = (callback as *const F).as_ref().unwrap(); 487 callback(); 488 } 489 490 /// free memories allocated for Watcher try_to_recyclenull491 pub fn try_to_recycle(&self) { 492 unsafe { 493 RecycleRustEventWatcher(self.as_raw()) 494 } 495 } 496 } 497 498 /// Implement trait AsRawPtr for Watcher 499 /// 500 /// # Safety 501 /// 502 /// A `Watcher` is always constructed with a valid raw pointer 503 /// to a `HiSysEventRustWatcherC`. 504 /// 505 unsafe impl AsRawPtr<HiSysEventRustWatcherC> for Watcher { as_rawnull506 fn as_raw(&self) -> *const HiSysEventRustWatcherC { 507 self.native 508 } 509 as_mut_rawnull510 fn as_mut_raw(&mut self) -> *mut HiSysEventRustWatcherC { 511 self.native 512 } 513 } 514 515 /// Add watcher to watch system event. 516 pub(crate) fn add_watcher(watcher: &Watcher, watch_rules: &[WatchRule]) -> i32 { 517 let mut watch_rules_wrapper: Vec<HiSysEventWatchRule> = vec![]; 518 for i in 0..watch_rules.len() { 519 watch_rules_wrapper.push(HiSysEventWatchRule { 520 domain: [0; MAX_LENGTH_OF_EVENT_DOMAIN], 521 name: [0; MAX_LENGTH_OF_EVENT_NAME], 522 tag: [0; MAX_LENGTH_OF_EVENT_TAG], 523 rule_type: 0, 524 event_type: 0, 525 }); 526 crate::utils::trans_slice_to_array(watch_rules[i].domain, &mut watch_rules_wrapper[i].domain); 527 crate::utils::trans_slice_to_array(watch_rules[i].name, &mut watch_rules_wrapper[i].name); 528 crate::utils::trans_slice_to_array(watch_rules[i].tag, &mut watch_rules_wrapper[i].tag); 529 watch_rules_wrapper[i].rule_type = watch_rules[i].rule_type as i32 as c_int; 530 watch_rules_wrapper[i].event_type = watch_rules[i].event_type as i32 as c_int; 531 } 532 // Safty: call C ffi border function, all risks are under control. 533 unsafe { 534 HiSysEventAddWatcherWrapper(watcher.as_raw(), 535 watch_rules_wrapper.as_mut_ptr(), 536 watch_rules.len() as c_uint) 537 } 538 } 539 540 /// Remove watcher. 541 pub(crate) fn remove_watcher(watcher: &Watcher) -> i32 { 542 // Safty: call C ffi border function, all risks are under control. 543 unsafe { 544 HiSysEventRemoveWatcherWrapper(watcher.as_raw()) 545 } 546 } 547 548 /// Trait for transparent Rust wrappers around native raw pointer types. 549 /// 550 /// # Safety 551 /// 552 /// The pointer return by this trait's methods should be immediately passed to 553 /// native and not stored by Rust. The pointer is valid only as long as the 554 /// underlying native object is alive, so users must be careful to take this into 555 /// account, as Rust cannot enforce this. 556 /// 557 /// For this trait to be a correct implementation, `T` must be a valid native 558 /// type. Since we cannot constrain this via the type system, this trait is 559 /// marked as unsafe. 560 /// 561 unsafe trait AsRawPtr<T> { 562 /// Return a pointer to the native version of `self` as_rawnull563 fn as_raw(&self) -> *const T; 564 565 /// Return a mutable pointer to the native version of `self` as_mut_rawnull566 fn as_mut_raw(&mut self) -> *mut T; 567 } 568 569 extern "C" { 570 /// ffi border function. HiSysEventAddWatcherWrappernull571 fn HiSysEventAddWatcherWrapper(watcher: *const HiSysEventRustWatcherC, rules: *const HiSysEventWatchRule, 572 rule_size: c_uint) -> c_int; 573 574 /// ffi border function. HiSysEventRemoveWatcherWrappernull575 fn HiSysEventRemoveWatcherWrapper(watcher: *const HiSysEventRustWatcherC) -> c_int; 576 577 /// ffi border function. HiSysEventQueryWrappernull578 fn HiSysEventQueryWrapper(query_arg: *const HiSysEventQueryArg, rules: *const HiSysEventQueryRuleWrapper, 579 rule_size: c_uint, querier: *const HiSysEventRustQuerierC) -> c_int; 580 581 /// ffi border function. GetHiSysEventRecordByIndexWrappernull582 fn GetHiSysEventRecordByIndexWrapper(records: *const HiSysEventRecord, total: c_uint, 583 index: c_uint) -> HiSysEventRecord; 584 585 /// ffi border function. CreateRustEventWatchernull586 fn CreateRustEventWatcher(on_event_callback: *const c_void, 587 on_event_wrapper_callback: OnEvent, 588 on_service_died_callback: *const c_void, 589 on_service_died_wrapper_callback: OnServiceDied) -> *mut HiSysEventRustWatcherC; 590 591 /// ffi border function. RecycleRustEventWatchernull592 fn RecycleRustEventWatcher(watcher: *const HiSysEventRustWatcherC); 593 594 /// ffi border function. CreateRustEventQueriernull595 fn CreateRustEventQuerier(on_query_callback: *const c_void, 596 on_query_wrapper_callback: OnQuery, 597 on_complete_callback: *const c_void, 598 on_complete_wrapper_callback: OnComplete) -> *mut HiSysEventRustQuerierC; 599 600 /// ffi border function. RecycleRustEventQueriernull601 fn RecycleRustEventQuerier(querier: *const HiSysEventRustQuerierC); 602 } 603