1 // Copyright 2021, The Android Open Source Project 2 // 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 //! Provides interface for logging events to binary log buffers. 16 17 // WARNING: this is not part of the crate's public API and is subject to change at any time 18 #[doc(hidden)] 19 pub mod __private_api { 20 use log_event_list_bindgen as log_bindgen; 21 use std::os::raw::c_char; 22 23 pub use log_bindgen::log_id_LOG_ID_SECURITY as LogIdSecurity; 24 25 /// Whether security logging is enabled. 26 #[cfg(not(android_vndk))] security_log_enabled() -> bool27 fn security_log_enabled() -> bool { 28 // SAFETY: The call doesn't require any preconditions and only returns an int, so must be safe. 29 unsafe { log_bindgen::__android_log_security() != 0 } 30 } 31 32 #[cfg(android_vndk)] security_log_enabled() -> bool33 fn security_log_enabled() -> bool { 34 false 35 } 36 37 /// A struct representing that liblog call returned an error. No details are provided. 38 #[derive(Clone, Copy)] 39 pub struct LogContextError; 40 41 /// Convert liblog status code into a Result. check_liblog_result(status: i32) -> Result<(), LogContextError>42 fn check_liblog_result(status: i32) -> Result<(), LogContextError> { 43 if status < 0 { 44 Err(LogContextError) 45 } else { 46 Ok(()) 47 } 48 } 49 50 /// Event log context. 51 pub struct LogContext { 52 ctx: log_bindgen::android_log_context, 53 log_type: log_bindgen::log_id, 54 } 55 56 /// SAFETY: Log context is essentially a buffer with some associated state. All data that is 57 /// appended to the context is copied into the buffers, no references are ever stored. 58 unsafe impl Send for LogContext {} 59 60 impl LogContext { 61 /// Creates a context for a given event tag. new(log_type: log_bindgen::log_id, tag: u32) -> Option<LogContext>62 pub fn new(log_type: log_bindgen::log_id, tag: u32) -> Option<LogContext> { 63 if log_type == log_bindgen::log_id_LOG_ID_SECURITY && !security_log_enabled() { 64 return None; 65 } 66 67 // SAFETY: The method returns a pointer that is stored and always freed exactly once via 68 // Drop below. 69 let ctx = unsafe { log_bindgen::create_android_logger(tag) }; 70 if !ctx.is_null() { 71 Some(LogContext { ctx, log_type }) 72 } else { 73 None 74 } 75 } 76 77 /// Appends an i32 to the context. append_i32(self, data: i32) -> Result<Self, LogContextError>78 pub fn append_i32(self, data: i32) -> Result<Self, LogContextError> { 79 // SAFETY: This will only be called on a non-null pointer returned from 80 // create_android_logger previously, so should be safe. 81 check_liblog_result(unsafe { log_bindgen::android_log_write_int32(self.ctx, data) })?; 82 Ok(self) 83 } 84 85 /// Appends an i64 to the context. append_i64(self, data: i64) -> Result<Self, LogContextError>86 pub fn append_i64(self, data: i64) -> Result<Self, LogContextError> { 87 // SAFETY: This will only be called on a non-null pointer returned from 88 // create_android_logger previously, so should be safe. 89 check_liblog_result(unsafe { log_bindgen::android_log_write_int64(self.ctx, data) })?; 90 Ok(self) 91 } 92 93 /// Appends an f32 to the context. append_f32(self, data: f32) -> Result<Self, LogContextError>94 pub fn append_f32(self, data: f32) -> Result<Self, LogContextError> { 95 // SAFETY: This will only be called on a non-null pointer returned from 96 // create_android_logger previously, so should be safe. 97 check_liblog_result(unsafe { log_bindgen::android_log_write_float32(self.ctx, data) })?; 98 Ok(self) 99 } 100 101 /// Append a string to the context. append_str(self, data: &str) -> Result<Self, LogContextError>102 pub fn append_str(self, data: &str) -> Result<Self, LogContextError> { 103 // SAFETY: This will only be called on a non-null pointer returned from 104 // create_android_logger previously, and the function will only read data.len() characters 105 // from the str, the pointer itself won't be stored, so should be safe. 106 check_liblog_result(unsafe { 107 log_bindgen::android_log_write_string8_len( 108 self.ctx, 109 data.as_ptr() as *const c_char, 110 data.len(), 111 ) 112 })?; 113 Ok(self) 114 } 115 116 /// Begin a sublist of values. begin_list(self) -> Result<Self, LogContextError>117 pub fn begin_list(self) -> Result<Self, LogContextError> { 118 // SAFETY: This will only be called on a non-null pointer returned from 119 // create_android_logger previously, so should be safe. 120 check_liblog_result(unsafe { log_bindgen::android_log_write_list_begin(self.ctx) })?; 121 Ok(self) 122 } 123 124 /// End a sublist of values. end_list(self) -> Result<Self, LogContextError>125 pub fn end_list(self) -> Result<Self, LogContextError> { 126 // SAFETY: This will only be called on a non-null pointer returned from 127 // create_android_logger previously, so should be safe. 128 check_liblog_result(unsafe { log_bindgen::android_log_write_list_end(self.ctx) })?; 129 Ok(self) 130 } 131 132 /// Writes the context to a given buffer type and consumes the context. write(self) -> Result<(), LogContextError>133 pub fn write(self) -> Result<(), LogContextError> { 134 // SAFETY: This will only be called on a non-null pointer returned from 135 // create_android_logger previously, so should be safe. 136 check_liblog_result(unsafe { 137 log_bindgen::android_log_write_list(self.ctx, self.log_type) 138 }) 139 } 140 } 141 142 impl Drop for LogContext { drop(&mut self)143 fn drop(&mut self) { 144 // SAFETY: This will only be called on a non-null pointer returned from 145 // create_android_logger previously, so should be safe. 146 unsafe { log_bindgen::android_log_destroy(&mut self.ctx) }; 147 } 148 } 149 } 150