Provide rust binding for binary event logging.

Bug: 183201685
Test: atest MixedDeviceOwnerTest#testSecurityLoggingWithSingleUser
Change-Id: I82fb3b7d3e68ba638937b3fa17655f2614b89919
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 5a8158a..e4d8a58 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -178,3 +178,21 @@
     first_version: "9",
     unversioned_until: "current",
 }
+
+rust_bindgen {
+    name: "liblog_event_list_bindgen",
+    wrapper_src: "rust/liblog_wrapper.h",
+    crate_name: "log_event_list_bindgen",
+    source_stem: "bindings",
+
+    bindgen_flags: [
+        "--size_t-is-usize",
+        "--allowlist-function=create_android_logger",
+        "--allowlist-function=android_log_destroy",
+        "--allowlist-function=android_log_write_int32",
+        "--allowlist-function=android_log_write_string8_len",
+        "--allowlist-function=android_log_write_list",
+        "--allowlist-function=__android_log_security",
+        "--allowlist-type=log_id",
+    ],
+}
diff --git a/liblog/rust/liblog_wrapper.h b/liblog/rust/liblog_wrapper.h
new file mode 100644
index 0000000..e6680fe
--- /dev/null
+++ b/liblog/rust/liblog_wrapper.h
@@ -0,0 +1,4 @@
+#pragma once
+
+#include <log/log_event_list.h>
+#include <private/android_logger.h>
diff --git a/rust/Android.bp b/rust/Android.bp
index e9802f7..0292da1 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -20,6 +20,14 @@
     },
 }
 
+rust_library {
+    name: "liblog_event_list",
+    crate_name: "log_event_list",
+    srcs: ["liblog_event_list.rs"],
+    rustlibs: ["liblog_event_list_bindgen"],
+    shared_libs: ["liblog"],
+}
+
 rust_defaults {
     name: "liblogger_test_defaults",
     crate_name: "logger",
diff --git a/rust/liblog_event_list.rs b/rust/liblog_event_list.rs
new file mode 100644
index 0000000..ed36e20
--- /dev/null
+++ b/rust/liblog_event_list.rs
@@ -0,0 +1,90 @@
+// 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.
+
+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.
+fn security_log_enabled() -> bool {
+    // The call doesn't require any preconditions and only returns an int, so must be safe.
+    unsafe {
+        log_bindgen::__android_log_security() != 0
+    }
+}
+
+/// Event log context.
+pub struct LogContext {
+    ctx: log_bindgen::android_log_context,
+    log_type: log_bindgen::log_id
+}
+
+/// 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;
+        }
+
+        // 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) -> Self {
+        // 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_write_int32(self.ctx, data) };
+        self
+    }
+
+    /// Append a string to the context.
+    pub fn append_str(self, data: &str) -> Self {
+        // 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.
+        unsafe {
+            log_bindgen::android_log_write_string8_len(
+                self.ctx, data.as_ptr() as *const c_char, data.len())
+        };
+        self
+    }
+
+    /// Writes the context to a given buffer type and consumes the context.
+    pub fn write(self) {
+        // 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_write_list(self.ctx, self.log_type) };
+    }
+}
+
+impl Drop for LogContext {
+    fn drop(&mut self) {
+        // 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) };
+    }
+}