bpfloader-rs: implement rust native logging am: cbb87b6c97 am: 22020c5f2f

Original change: https://android-review.googlesource.com/c/platform/system/bpf/+/3294153

Change-Id: Ifbea6a19d7e0b40254dc7fa85434abda2f7c4d35
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/loader/Android.bp b/loader/Android.bp
index 1e68f92..c9ea5d0 100644
--- a/loader/Android.bp
+++ b/loader/Android.bp
@@ -113,6 +113,8 @@
     ],
     rustlibs: [
         "libbpf_android_bindgen",
+        "libandroid_logger",
+        "liblog_rust",
     ],
     required: [
         "timeInState.o",
diff --git a/loader/bpfloader.rs b/loader/bpfloader.rs
index ede1a29..a117f14 100644
--- a/loader/bpfloader.rs
+++ b/loader/bpfloader.rs
@@ -15,19 +15,131 @@
  */
 
 //! BPF loader for system and vendor applications
+use android_logger::AndroidLogger;
+use log::{error, info, Level, LevelFilter, Log, Metadata, Record, SetLoggerError};
+use std::{
+    cmp::max,
+    env,
+    fs::File,
+    io::{LineWriter, Write},
+    os::fd::FromRawFd,
+    panic,
+    sync::{Arc, Mutex},
+};
+
+enum KernelLevel {
+    // Commented out unused due to rust complaining...
+    // EMERG = 0,
+    // ALERT = 1,
+    // CRIT = 2,
+    ERR = 3,
+    WARNING = 4,
+    // NOTICE = 5,
+    INFO = 6,
+    DEBUG = 7,
+}
+
+fn level_to_kern_level(level: &Level) -> u8 {
+    let result = match level {
+        Level::Error => KernelLevel::ERR,
+        Level::Warn => KernelLevel::WARNING,
+        Level::Info => KernelLevel::INFO,
+        Level::Debug => KernelLevel::DEBUG,
+        Level::Trace => KernelLevel::DEBUG,
+    };
+    result as u8
+}
+
+/// A logger implementation to enable bpfloader to write to kmsg on error as
+/// bpfloader runs at early init prior to the availability of standard Android
+/// logging. If a crash were to occur, we can disrupt boot, and therefore we
+/// need the ability to access the logs on the serial port.
+pub struct BpfKmsgLogger {
+    log_level: LevelFilter,
+    tag: String,
+    kmsg_writer: Arc<Mutex<Box<dyn Write + Send>>>,
+    a_logger: AndroidLogger,
+}
+
+impl Log for BpfKmsgLogger {
+    fn enabled(&self, metadata: &Metadata) -> bool {
+        metadata.level() <= self.log_level || self.a_logger.enabled(metadata)
+    }
+
+    fn log(&self, record: &Record) {
+        if !self.enabled(record.metadata()) {
+            return;
+        }
+
+        if record.metadata().level() <= self.log_level {
+            let mut writer = self.kmsg_writer.lock().unwrap();
+            write!(
+                writer,
+                "<{}>{}: {}",
+                level_to_kern_level(&record.level()),
+                self.tag,
+                record.args()
+            )
+            .unwrap();
+            let _ = writer.flush();
+        }
+        self.a_logger.log(record);
+    }
+
+    fn flush(&self) {}
+}
+
+impl BpfKmsgLogger {
+    /// Initialize the logger
+    pub fn init(kmsg_file: File) -> Result<(), SetLoggerError> {
+        let alog_level = LevelFilter::Info;
+        let kmsg_level = LevelFilter::Error;
+
+        let log_config = android_logger::Config::default()
+            .with_tag("BpfLoader-rs")
+            .with_max_level(alog_level)
+            .with_log_buffer(android_logger::LogId::Main)
+            .format(|buf, record| writeln!(buf, "{}", record.args()));
+
+        let writer = Box::new(LineWriter::new(kmsg_file)) as Box<dyn Write + Send>;
+        log::set_max_level(max(alog_level, kmsg_level));
+        log::set_boxed_logger(Box::new(BpfKmsgLogger {
+            log_level: kmsg_level,
+            tag: "BpfLoader-rs".to_string(),
+            kmsg_writer: Arc::new(Mutex::new(writer)),
+            a_logger: AndroidLogger::new(log_config),
+        }))
+    }
+}
 
 #[cfg(enable_libbpf)]
 fn load_libbpf_progs() {
     // Libbpf loader functionality here.
+    info!("Loading libbpf programs");
 }
 
 #[cfg(not(enable_libbpf))]
 fn load_libbpf_progs() {
     // Empty stub for feature flag disabled case
+    info!("Loading of libbpf programs DISABLED");
 }
 
 fn main() {
+    let kmsg_fd = env::var("ANDROID_FILE__dev_kmsg").unwrap().parse::<i32>().unwrap();
+    // SAFETY: The init script opens this file for us
+    let kmsg_file = unsafe { File::from_raw_fd(kmsg_fd) };
+
+    if let Err(logger) = BpfKmsgLogger::init(kmsg_file) {
+        error!("BpfLoader-rs: log::setlogger failed: {}", logger);
+    }
+
+    // Redirect panic messages to both logcat and serial port
+    panic::set_hook(Box::new(|panic_info| {
+        error!("{}", panic_info);
+    }));
+
     load_libbpf_progs();
+    info!("Done, loading legacy BPF progs");
 
     // SAFETY: Linking in the existing legacy bpfloader functionality.
     // Any of the four following bindgen functions can abort() or exit()