blob: d1eec9df5125f3396c8cff8441358bfc8d273d75 [file] [log] [blame]
// Copyright 2021, The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Provides interface for logging events to binary log buffers.
// WARNING: this is not part of the crate's public API and is subject to change at any time
#[doc(hidden)]
pub mod __private_api {
use log_event_list_bindgen as log_bindgen;
use std::os::raw::c_char;
pub use log_bindgen::log_id_LOG_ID_SECURITY as LogIdSecurity;
/// Whether security logging is enabled.
#[cfg(not(android_vndk))]
fn security_log_enabled() -> bool {
// SAFETY: The call doesn't require any preconditions and only returns an int, so must be safe.
unsafe { log_bindgen::__android_log_security() != 0 }
}
#[cfg(android_vndk)]
fn security_log_enabled() -> bool {
false
}
/// A struct representing that liblog call returned an error. No details are provided.
#[derive(Clone, Copy)]
pub struct LogContextError;
/// Convert liblog status code into a Result.
fn check_liblog_result(status: i32) -> Result<(), LogContextError> {
if status < 0 {
Err(LogContextError)
} else {
Ok(())
}
}
/// Event log context.
pub struct LogContext {
ctx: log_bindgen::android_log_context,
log_type: log_bindgen::log_id,
}
/// SAFETY: Log context is essentially a buffer with some associated state. All data that is
/// appended to the context is copied into the buffers, no references are ever stored.
unsafe impl Send for LogContext {}
impl LogContext {
/// Creates a context for a given event tag.
pub fn new(log_type: log_bindgen::log_id, tag: u32) -> Option<LogContext> {
if log_type == log_bindgen::log_id_LOG_ID_SECURITY && !security_log_enabled() {
return None;
}
// SAFETY: The method returns a pointer that is stored and always freed exactly once via
// Drop below.
let ctx = unsafe { log_bindgen::create_android_logger(tag) };
if !ctx.is_null() {
Some(LogContext { ctx, log_type })
} else {
None
}
}
/// Appends an i32 to the context.
pub fn append_i32(self, data: i32) -> Result<Self, LogContextError> {
// SAFETY: This will only be called on a non-null pointer returned from
// create_android_logger previously, so should be safe.
check_liblog_result(unsafe { log_bindgen::android_log_write_int32(self.ctx, data) })?;
Ok(self)
}
/// Appends an i64 to the context.
pub fn append_i64(self, data: i64) -> Result<Self, LogContextError> {
// SAFETY: This will only be called on a non-null pointer returned from
// create_android_logger previously, so should be safe.
check_liblog_result(unsafe { log_bindgen::android_log_write_int64(self.ctx, data) })?;
Ok(self)
}
/// Appends an f32 to the context.
pub fn append_f32(self, data: f32) -> Result<Self, LogContextError> {
// SAFETY: This will only be called on a non-null pointer returned from
// create_android_logger previously, so should be safe.
check_liblog_result(unsafe { log_bindgen::android_log_write_float32(self.ctx, data) })?;
Ok(self)
}
/// Append a string to the context.
pub fn append_str(self, data: &str) -> Result<Self, LogContextError> {
// SAFETY: This will only be called on a non-null pointer returned from
// create_android_logger previously, and the function will only read data.len() characters
// from the str, the pointer itself won't be stored, so should be safe.
check_liblog_result(unsafe {
log_bindgen::android_log_write_string8_len(
self.ctx,
data.as_ptr() as *const c_char,
data.len(),
)
})?;
Ok(self)
}
/// Begin a sublist of values.
pub fn begin_list(self) -> Result<Self, LogContextError> {
// SAFETY: This will only be called on a non-null pointer returned from
// create_android_logger previously, so should be safe.
check_liblog_result(unsafe { log_bindgen::android_log_write_list_begin(self.ctx) })?;
Ok(self)
}
/// End a sublist of values.
pub fn end_list(self) -> Result<Self, LogContextError> {
// SAFETY: This will only be called on a non-null pointer returned from
// create_android_logger previously, so should be safe.
check_liblog_result(unsafe { log_bindgen::android_log_write_list_end(self.ctx) })?;
Ok(self)
}
/// Writes the context to a given buffer type and consumes the context.
pub fn write(self) -> Result<(), LogContextError> {
// SAFETY: This will only be called on a non-null pointer returned from
// create_android_logger previously, so should be safe.
check_liblog_result(unsafe {
log_bindgen::android_log_write_list(self.ctx, self.log_type)
})
}
}
impl Drop for LogContext {
fn drop(&mut self) {
// SAFETY: This will only be called on a non-null pointer returned from
// create_android_logger previously, so should be safe.
unsafe { log_bindgen::android_log_destroy(&mut self.ctx) };
}
}
}