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 16use std::ffi::{CString, c_char, c_int, c_uint, c_longlong, c_ulonglong, c_void}; 17 18use crate::{EventType, WatchRule, QueryArg, QueryRule}; 19 20/// Length limit for event domain definition. 21const MAX_LENGTH_OF_EVENT_DOMAIN: usize = 17; 22 23/// Length limit for event name definition. 24const MAX_LENGTH_OF_EVENT_NAME: usize = 33; 25 26/// Length limit for event tag definition. 27const MAX_LENGTH_OF_EVENT_TAG: usize = 85; 28 29/// Length limit for timezone definition. 30const MAX_LENGTH_OF_TIME_ZONE: usize = 6; 31 32/// Length limit for event list. 33const MAX_NUMBER_OF_EVENT_LIST: usize = 10; 34 35/// Length limit for event list definition. 36const MAX_EVENT_LIST_LEN: usize = 339; 37 38/// This type represent to HiSysEventWatchRule defined in C. 39#[repr(C)] 40#[derive(Copy, Clone)] 41struct 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)] 61struct 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)] 75struct 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)] 92pub 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 139impl HiSysEventRecord { 140 141 /// Get domain name 142 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 148 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 154 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 165 pub fn get_time(&self) -> u64 { 166 self.time 167 } 168 169 /// Get time zone 170 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 176 pub fn get_pid(&self) -> i64 { 177 self.pid 178 } 179 180 /// Get thread id 181 pub fn get_tid(&self) -> i64 { 182 self.tid 183 } 184 185 /// Get user id 186 pub fn get_uid(&self) -> i64 { 187 self.uid 188 } 189 190 /// Get trace id 191 pub fn get_trace_id(&self) -> u64 { 192 self.trace_id 193 } 194 195 /// Get span id 196 pub fn get_span_id(&self) -> u64 { 197 self.spand_id 198 } 199 200 /// Get parent span id 201 pub fn get_parent_span_id(&self) -> u64 { 202 self.pspan_id 203 } 204 205 /// Get trace flag 206 pub fn get_trace_flag(&self) -> i32 { 207 self.trace_flag 208 } 209 210 /// Get level 211 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 220 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 230 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. 241pub 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. 248pub 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)] 256struct 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)] 265pub 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 276impl Querier { 277 /// Create a rust HiSysEventRustQuerierC object with callbacks in a querier. 278 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 340 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/// 354unsafe impl AsRawPtr<HiSysEventRustQuerierC> for Querier { 355 fn as_raw(&self) -> *const HiSysEventRustQuerierC { 356 self.native 357 } 358 359 fn as_mut_raw(&mut self) -> *mut HiSysEventRustQuerierC { 360 self.native 361 } 362} 363 364/// Query system event. 365pub(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. 404pub type OnEvent = unsafe extern "C" fn ( 405 callback: *mut c_void, 406 record: HiSysEventRecord 407); 408 409/// Callback when hisysevent service shutdown. 410pub 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)] 416struct 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)] 425pub 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 436impl Watcher { 437 /// Create a rust HiSysEventRustWatcherC object with callbacks in a watcher. 438 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 491 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/// 505unsafe impl AsRawPtr<HiSysEventRustWatcherC> for Watcher { 506 fn as_raw(&self) -> *const HiSysEventRustWatcherC { 507 self.native 508 } 509 510 fn as_mut_raw(&mut self) -> *mut HiSysEventRustWatcherC { 511 self.native 512 } 513} 514 515/// Add watcher to watch system event. 516pub(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. 541pub(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/// 561unsafe trait AsRawPtr<T> { 562 /// Return a pointer to the native version of `self` 563 fn as_raw(&self) -> *const T; 564 565 /// Return a mutable pointer to the native version of `self` 566 fn as_mut_raw(&mut self) -> *mut T; 567} 568 569extern "C" { 570 /// ffi border function. 571 fn HiSysEventAddWatcherWrapper(watcher: *const HiSysEventRustWatcherC, rules: *const HiSysEventWatchRule, 572 rule_size: c_uint) -> c_int; 573 574 /// ffi border function. 575 fn HiSysEventRemoveWatcherWrapper(watcher: *const HiSysEventRustWatcherC) -> c_int; 576 577 /// ffi border function. 578 fn HiSysEventQueryWrapper(query_arg: *const HiSysEventQueryArg, rules: *const HiSysEventQueryRuleWrapper, 579 rule_size: c_uint, querier: *const HiSysEventRustQuerierC) -> c_int; 580 581 /// ffi border function. 582 fn GetHiSysEventRecordByIndexWrapper(records: *const HiSysEventRecord, total: c_uint, 583 index: c_uint) -> HiSysEventRecord; 584 585 /// ffi border function. 586 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. 592 fn RecycleRustEventWatcher(watcher: *const HiSysEventRustWatcherC); 593 594 /// ffi border function. 595 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. 601 fn RecycleRustEventQuerier(querier: *const HiSysEventRustQuerierC); 602} 603