Fix error logging on the C++ side

This commit is contained in:
topjohnwu 2023-10-13 16:59:54 -07:00
parent 51e37880c6
commit 36de62873a
7 changed files with 48 additions and 26 deletions

1
native/src/Cargo.lock generated
View File

@ -75,6 +75,7 @@ dependencies = [
"cxx", "cxx",
"cxx-gen", "cxx-gen",
"libc", "libc",
"num-derive",
"num-traits", "num-traits",
"thiserror", "thiserror",
] ]

View File

@ -17,3 +17,4 @@ thiserror = { workspace = true }
argh = { workspace = true } argh = { workspace = true }
bytemuck = { workspace = true } bytemuck = { workspace = true }
num-traits = { workspace = true } num-traits = { workspace = true }
num-derive = { workspace = true }

View File

@ -4,6 +4,7 @@
#![feature(utf8_chunks)] #![feature(utf8_chunks)]
pub use libc; pub use libc;
use num_traits::FromPrimitive;
pub use cstr::*; pub use cstr::*;
use cxx_extern::*; use cxx_extern::*;
@ -21,7 +22,9 @@ mod xwrap;
#[cxx::bridge] #[cxx::bridge]
pub mod ffi { pub mod ffi {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum LogLevel { #[repr(i32)]
#[cxx_name = "LogLevel"]
pub(crate) enum LogLevelCxx {
ErrorCxx, ErrorCxx,
Error, Error,
Warn, Warn,
@ -36,9 +39,10 @@ pub mod ffi {
extern "Rust" { extern "Rust" {
#[cxx_name = "log_with_rs"] #[cxx_name = "log_with_rs"]
fn log_from_cxx(level: LogLevel, msg: &[u8]); fn log_from_cxx(level: LogLevelCxx, msg: &[u8]);
#[cxx_name = "set_log_level_state"]
fn set_log_level_state_cxx(level: LogLevelCxx, enabled: bool);
fn exit_on_error(b: bool); fn exit_on_error(b: bool);
fn set_log_level_state(level: LogLevel, enabled: bool);
fn cmdline_logging(); fn cmdline_logging();
} }
@ -54,3 +58,9 @@ pub mod ffi {
fn enable_selinux(); fn enable_selinux();
} }
} }
fn set_log_level_state_cxx(level: ffi::LogLevelCxx, enabled: bool) {
if let Some(level) = LogLevel::from_i32(level.repr) {
set_log_level_state(level, enabled)
}
}

View File

@ -1,10 +1,12 @@
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::FromPrimitive;
use std::fmt; use std::fmt;
use std::fmt::{Arguments, Display}; use std::fmt::{Arguments, Display};
use std::io::{stderr, stdout, Write}; use std::io::{stderr, stdout, Write};
use std::panic::Location; use std::panic::Location;
use std::process::exit; use std::process::exit;
use crate::ffi::LogLevel; use crate::ffi::LogLevelCxx;
use crate::{Utf8CStr, Utf8CStrBufArr}; use crate::{Utf8CStr, Utf8CStrBufArr};
// Error handling and logging throughout the Rust codebase in Magisk: // Error handling and logging throughout the Rust codebase in Magisk:
@ -30,6 +32,16 @@ mod LogFlag {
pub const ExitOnError: u32 = 1 << 4; pub const ExitOnError: u32 = 1 << 4;
} }
#[derive(Copy, Clone, FromPrimitive, ToPrimitive)]
#[repr(i32)]
pub enum LogLevel {
ErrorCxx = LogLevelCxx::ErrorCxx.repr,
Error = LogLevelCxx::Error.repr,
Warn = LogLevelCxx::Warn.repr,
Info = LogLevelCxx::Info.repr,
Debug = LogLevelCxx::Debug.repr,
}
// We don't need to care about thread safety, because all // We don't need to care about thread safety, because all
// logger changes will only happen on the main thread. // logger changes will only happen on the main thread.
pub static mut LOGGER: Logger = Logger { pub static mut LOGGER: Logger = Logger {
@ -63,7 +75,6 @@ impl LogLevel {
LogLevel::Warn => LogFlag::DisableWarn, LogLevel::Warn => LogFlag::DisableWarn,
LogLevel::Info => LogFlag::DisableInfo, LogLevel::Info => LogFlag::DisableInfo,
LogLevel::Debug => LogFlag::DisableDebug, LogLevel::Debug => LogFlag::DisableDebug,
_ => 0,
} }
} }
} }
@ -85,16 +96,18 @@ fn log_with_writer<F: FnOnce(LogWriter)>(level: LogLevel, f: F) {
return; return;
} }
f(logger.write); f(logger.write);
if level == LogLevel::ErrorCxx && (logger.flags & LogFlag::ExitOnError) != 0 { if matches!(level, LogLevel::ErrorCxx) && (logger.flags & LogFlag::ExitOnError) != 0 {
exit(1); exit(1);
} }
} }
pub fn log_from_cxx(level: LogLevel, msg: &[u8]) { pub fn log_from_cxx(level: LogLevelCxx, msg: &[u8]) {
if let Some(level) = LogLevel::from_i32(level.repr) {
// SAFETY: The null termination is handled on the C++ side // SAFETY: The null termination is handled on the C++ side
let msg = unsafe { Utf8CStr::from_bytes_unchecked(msg) }; let msg = unsafe { Utf8CStr::from_bytes_unchecked(msg) };
log_with_writer(level, |write| write(level, msg)); log_with_writer(level, |write| write(level, msg));
} }
}
pub fn log_with_formatter<F: FnOnce(Formatter) -> fmt::Result>(level: LogLevel, f: F) { pub fn log_with_formatter<F: FnOnce(Formatter) -> fmt::Result>(level: LogLevel, f: F) {
log_with_writer(level, |write| { log_with_writer(level, |write| {
@ -110,7 +123,7 @@ pub fn log_with_args(level: LogLevel, args: Arguments) {
pub fn cmdline_logging() { pub fn cmdline_logging() {
fn cmdline_write(level: LogLevel, msg: &Utf8CStr) { fn cmdline_write(level: LogLevel, msg: &Utf8CStr) {
if level == LogLevel::Info { if matches!(level, LogLevel::Info) {
stdout().write_all(msg.as_bytes()).ok(); stdout().write_all(msg.as_bytes()).ok();
} else { } else {
stderr().write_all(msg.as_bytes()).ok(); stderr().write_all(msg.as_bytes()).ok();
@ -129,21 +142,21 @@ pub fn cmdline_logging() {
#[macro_export] #[macro_export]
macro_rules! error { macro_rules! error {
($($args:tt)+) => { ($($args:tt)+) => {
$crate::log_with_args($crate::ffi::LogLevel::Error, format_args_nl!($($args)+)) $crate::log_with_args($crate::LogLevel::Error, format_args_nl!($($args)+))
} }
} }
#[macro_export] #[macro_export]
macro_rules! warn { macro_rules! warn {
($($args:tt)+) => { ($($args:tt)+) => {
$crate::log_with_args($crate::ffi::LogLevel::Warn, format_args_nl!($($args)+)) $crate::log_with_args($crate::LogLevel::Warn, format_args_nl!($($args)+))
} }
} }
#[macro_export] #[macro_export]
macro_rules! info { macro_rules! info {
($($args:tt)+) => { ($($args:tt)+) => {
$crate::log_with_args($crate::ffi::LogLevel::Info, format_args_nl!($($args)+)) $crate::log_with_args($crate::LogLevel::Info, format_args_nl!($($args)+))
} }
} }
@ -151,7 +164,7 @@ macro_rules! info {
#[macro_export] #[macro_export]
macro_rules! debug { macro_rules! debug {
($($args:tt)+) => { ($($args:tt)+) => {
$crate::log_with_args($crate::ffi::LogLevel::Debug, format_args_nl!($($args)+)) $crate::log_with_args($crate::LogLevel::Debug, format_args_nl!($($args)+))
} }
} }
@ -189,15 +202,15 @@ pub type LoggedResult<T> = Result<T, LoggedError>;
#[macro_export] #[macro_export]
macro_rules! log_err { macro_rules! log_err {
($msg:literal $(,)?) => {{ ($msg:literal $(,)?) => {{
$crate::log_with_args($crate::ffi::LogLevel::Error, format_args_nl!($msg)); $crate::log_with_args($crate::LogLevel::Error, format_args_nl!($msg));
$crate::LoggedError::default() $crate::LoggedError::default()
}}; }};
($err:expr $(,)?) => {{ ($err:expr $(,)?) => {{
$crate::log_with_args($crate::ffi::LogLevel::Error, format_args_nl!("{}", $err)); $crate::log_with_args($crate::LogLevel::Error, format_args_nl!("{}", $err));
$crate::LoggedError::default() $crate::LoggedError::default()
}}; }};
($($args:tt)+) => {{ ($($args:tt)+) => {{
$crate::log_with_args($crate::ffi::LogLevel::Error, format_args_nl!($($args)+)); $crate::log_with_args($crate::LogLevel::Error, format_args_nl!($($args)+));
$crate::LoggedError::default() $crate::LoggedError::default()
}}; }};
} }

View File

@ -26,19 +26,19 @@ fn error_str() -> &'static str {
macro_rules! error_cxx { macro_rules! error_cxx {
($($args:tt)+) => { ($($args:tt)+) => {
($crate::log_with_args($crate::ffi::LogLevel::ErrorCxx, format_args_nl!($($args)+))) ($crate::log_with_args($crate::LogLevel::ErrorCxx, format_args_nl!($($args)+)))
} }
} }
macro_rules! perror { macro_rules! perror {
($fmt:expr) => { ($fmt:expr) => {
$crate::log_with_formatter($crate::ffi::LogLevel::ErrorCxx, |w| { $crate::log_with_formatter($crate::LogLevel::ErrorCxx, |w| {
w.write_str($fmt)?; w.write_str($fmt)?;
w.write_fmt(format_args_nl!(" failed with {}: {}", $crate::errno(), error_str())) w.write_fmt(format_args_nl!(" failed with {}: {}", $crate::errno(), error_str()))
}) })
}; };
($fmt:expr, $($args:tt)*) => { ($fmt:expr, $($args:tt)*) => {
$crate::log_with_formatter($crate::ffi::LogLevel::ErrorCxx, |w| { $crate::log_with_formatter($crate::LogLevel::ErrorCxx, |w| {
w.write_fmt(format_args!($fmt, $($args)*))?; w.write_fmt(format_args!($fmt, $($args)*))?;
w.write_fmt(format_args_nl!(" failed with {}: {}", $crate::errno(), error_str())) w.write_fmt(format_args_nl!(" failed with {}: {}", $crate::errno(), error_str()))
}) })

View File

@ -11,7 +11,6 @@ use bytemuck::{bytes_of, bytes_of_mut, write_zeroes, Pod, Zeroable};
use num_derive::{FromPrimitive, ToPrimitive}; use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use base::ffi::LogLevel;
use base::libc::{ use base::libc::{
clock_gettime, getpid, gettid, localtime_r, pipe2, pthread_sigmask, sigaddset, sigset_t, clock_gettime, getpid, gettid, localtime_r, pipe2, pthread_sigmask, sigaddset, sigset_t,
sigtimedwait, timespec, tm, CLOCK_REALTIME, O_CLOEXEC, PIPE_BUF, SIGPIPE, SIG_BLOCK, sigtimedwait, timespec, tm, CLOCK_REALTIME, O_CLOEXEC, PIPE_BUF, SIGPIPE, SIG_BLOCK,
@ -50,11 +49,10 @@ extern "C" {
fn level_to_prio(level: LogLevel) -> i32 { fn level_to_prio(level: LogLevel) -> i32 {
match level { match level {
LogLevel::Error => ALogPriority::ANDROID_LOG_ERROR as i32, LogLevel::Error | LogLevel::ErrorCxx => ALogPriority::ANDROID_LOG_ERROR as i32,
LogLevel::Warn => ALogPriority::ANDROID_LOG_WARN as i32, LogLevel::Warn => ALogPriority::ANDROID_LOG_WARN as i32,
LogLevel::Info => ALogPriority::ANDROID_LOG_INFO as i32, LogLevel::Info => ALogPriority::ANDROID_LOG_INFO as i32,
LogLevel::Debug => ALogPriority::ANDROID_LOG_DEBUG as i32, LogLevel::Debug => ALogPriority::ANDROID_LOG_DEBUG as i32,
_ => 0,
} }
} }

View File

@ -3,12 +3,11 @@ use std::fs::File;
use std::io::{IoSlice, Write}; use std::io::{IoSlice, Write};
use std::sync::OnceLock; use std::sync::OnceLock;
use base::ffi::LogLevel;
use base::libc::{ use base::libc::{
close, makedev, mknod, open, syscall, unlink, SYS_dup3, O_CLOEXEC, O_RDWR, STDERR_FILENO, close, makedev, mknod, open, syscall, unlink, SYS_dup3, O_CLOEXEC, O_RDWR, STDERR_FILENO,
STDIN_FILENO, STDOUT_FILENO, S_IFCHR, STDIN_FILENO, STDOUT_FILENO, S_IFCHR,
}; };
use base::{cstr, exit_on_error, raw_cstr, Logger, Utf8CStr, LOGGER}; use base::{cstr, exit_on_error, raw_cstr, LogLevel, Logger, Utf8CStr, LOGGER};
static KMSG: OnceLock<File> = OnceLock::new(); static KMSG: OnceLock<File> = OnceLock::new();