Merge "Add libdebugstore for Future Use by ART and Frameworks" into main
diff --git a/libs/debugstore/OWNERS b/libs/debugstore/OWNERS
new file mode 100644
index 0000000..428a1a2
--- /dev/null
+++ b/libs/debugstore/OWNERS
@@ -0,0 +1,3 @@
+benmiles@google.com
+gaillard@google.com
+mohamadmahmoud@google.com
diff --git a/libs/debugstore/rust/Android.bp b/libs/debugstore/rust/Android.bp
new file mode 100644
index 0000000..55ba3c3
--- /dev/null
+++ b/libs/debugstore/rust/Android.bp
@@ -0,0 +1,71 @@
+// Copyright (C) 2024 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.
+
+package {
+    default_team: "trendy_team_android_telemetry_infra",
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+rust_defaults {
+    name: "libdebugstore_defaults",
+    srcs: ["src/lib.rs"],
+    rustlibs: [
+        "libcrossbeam_queue",
+        "libparking_lot",
+        "libonce_cell",
+        "libcxx",
+    ],
+    shared_libs: ["libutils"],
+    edition: "2021",
+}
+
+rust_ffi_static {
+    name: "libdebugstore_rust_ffi",
+    crate_name: "debugstore",
+    defaults: ["libdebugstore_defaults"],
+}
+
+cc_library {
+    name: "libdebugstore_cxx",
+    generated_headers: ["libdebugstore_cxx_bridge_header"],
+    generated_sources: ["libdebugstore_cxx_bridge_code"],
+    export_generated_headers: ["libdebugstore_cxx_bridge_header"],
+    shared_libs: ["libutils"],
+    whole_static_libs: ["libdebugstore_rust_ffi"],
+}
+
+rust_test {
+    name: "libdebugstore_tests",
+    defaults: ["libdebugstore_defaults"],
+    test_options: {
+        unit_test: true,
+    },
+    shared_libs: ["libdebugstore_cxx"],
+}
+
+genrule {
+    name: "libdebugstore_cxx_bridge_header",
+    tools: ["cxxbridge"],
+    cmd: "$(location cxxbridge) $(in) --header >> $(out)",
+    srcs: ["src/lib.rs"],
+    out: ["debugstore/debugstore_cxx_bridge.rs.h"],
+}
+
+genrule {
+    name: "libdebugstore_cxx_bridge_code",
+    tools: ["cxxbridge"],
+    cmd: "$(location cxxbridge) $(in) >> $(out)",
+    srcs: ["src/lib.rs"],
+    out: ["debugstore/debugstore_cxx_bridge.rs.cpp"],
+}
diff --git a/libs/debugstore/rust/Cargo.toml b/libs/debugstore/rust/Cargo.toml
new file mode 100644
index 0000000..23a8d24
--- /dev/null
+++ b/libs/debugstore/rust/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "debugstore"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib", "rlib"]
+
+[dependencies]
\ No newline at end of file
diff --git a/libs/debugstore/rust/src/core.rs b/libs/debugstore/rust/src/core.rs
new file mode 100644
index 0000000..1dfa512
--- /dev/null
+++ b/libs/debugstore/rust/src/core.rs
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+use super::event::Event;
+use super::event_type::EventType;
+use super::storage::Storage;
+use crate::cxxffi::uptimeMillis;
+use once_cell::sync::Lazy;
+use std::fmt;
+use std::sync::atomic::{AtomicU64, Ordering};
+
+//  Lazily initialized static instance of DebugStore.
+static INSTANCE: Lazy<DebugStore> = Lazy::new(DebugStore::new);
+
+/// The `DebugStore` struct is responsible for managing debug events and data.
+pub struct DebugStore {
+    /// Atomic counter for generating unique event IDs.
+    id_generator: AtomicU64,
+    /// Non-blocking storage for debug events.
+    event_store: Storage<Event, { DebugStore::DEFAULT_EVENT_LIMIT }>,
+}
+
+impl DebugStore {
+    /// The default limit for the number of events that can be stored.
+    ///
+    /// This limit is used to initialize the storage for debug events.
+    const DEFAULT_EVENT_LIMIT: usize = 16;
+    /// A designated identifier used for events that cannot be closed.
+    ///
+    /// This ID is used for point/instantaneous events, or events do not have
+    ///  a distinct end.
+    const NON_CLOSABLE_ID: u64 = 0;
+    /// The version number for the encoding of debug store data.
+    ///
+    /// This constant is used as a part of the debug store's data format,
+    /// allowing for version tracking and compatibility checks.
+    const ENCODE_VERSION: u32 = 1;
+
+    /// Creates a new instance of `DebugStore` with specified event limit and maximum delay.
+    fn new() -> Self {
+        Self { id_generator: AtomicU64::new(1), event_store: Storage::new() }
+    }
+
+    /// Returns a shared instance of `DebugStore`.
+    ///
+    /// This method provides a singleton pattern access to `DebugStore`.
+    pub fn get_instance() -> &'static DebugStore {
+        &INSTANCE
+    }
+
+    /// Begins a new debug event with the given name and data.
+    ///
+    /// This method logs the start of a debug event, assigning it a unique ID and marking its start time.
+    /// - `name`: The name of the debug event.
+    /// - `data`: Associated data as key-value pairs.
+    /// - Returns: A unique ID for the debug event.
+    pub fn begin(&self, name: String, data: Vec<(String, String)>) -> u64 {
+        let id = self.generate_id();
+        self.event_store.insert(Event::new(
+            id,
+            Some(name),
+            uptimeMillis(),
+            EventType::DurationStart,
+            data,
+        ));
+        id
+    }
+
+    /// Records a debug event without a specific duration, with the given name and data.
+    ///
+    /// This method logs an instantaneous debug event, useful for events that don't have a duration but are significant.
+    /// - `name`: The name of the debug event.
+    /// - `data`: Associated data as key-value pairs.
+    pub fn record(&self, name: String, data: Vec<(String, String)>) {
+        self.event_store.insert(Event::new(
+            Self::NON_CLOSABLE_ID,
+            Some(name),
+            uptimeMillis(),
+            EventType::Point,
+            data,
+        ));
+    }
+
+    /// Ends a debug event that was previously started with the given ID.
+    ///
+    /// This method marks the end of a debug event, completing its lifecycle.
+    /// - `id`: The unique ID of the debug event to end.
+    /// - `data`: Additional data to log at the end of the event.
+    pub fn end(&self, id: u64, data: Vec<(String, String)>) {
+        if id != Self::NON_CLOSABLE_ID {
+            self.event_store.insert(Event::new(
+                id,
+                None,
+                uptimeMillis(),
+                EventType::DurationEnd,
+                data,
+            ));
+        }
+    }
+
+    fn generate_id(&self) -> u64 {
+        let mut id = self.id_generator.fetch_add(1, Ordering::Relaxed);
+        while id == Self::NON_CLOSABLE_ID {
+            id = self.id_generator.fetch_add(1, Ordering::Relaxed);
+        }
+        id
+    }
+}
+
+impl fmt::Display for DebugStore {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let uptime_now = uptimeMillis();
+        write!(f, "{},{},{}::", Self::ENCODE_VERSION, self.event_store.len(), uptime_now)?;
+
+        write!(
+            f,
+            "{}",
+            self.event_store.fold(String::new(), |mut acc, event| {
+                if !acc.is_empty() {
+                    acc.push_str("||");
+                }
+                acc.push_str(&event.to_string());
+                acc
+            })
+        )
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_begin_event() {
+        let debug_store = DebugStore::new();
+        let _event_id = debug_store.begin("test_event".to_string(), vec![]);
+        let output = debug_store.to_string();
+        assert!(
+            output.contains("test_event"),
+            "The output should contain the event name 'test_event'"
+        );
+    }
+
+    #[test]
+    fn test_unique_event_ids() {
+        let debug_store = DebugStore::new();
+        let event_id1 = debug_store.begin("event1".to_string(), vec![]);
+        let event_id2 = debug_store.begin("event2".to_string(), vec![]);
+        assert_ne!(event_id1, event_id2, "Event IDs should be unique");
+    }
+
+    #[test]
+    fn test_end_event() {
+        let debug_store = DebugStore::new();
+        let event_id = debug_store.begin("test_event".to_string(), vec![]);
+        debug_store.end(event_id, vec![]);
+        let output = debug_store.to_string();
+
+        let id_pattern = format!("ID:{},", event_id);
+        assert!(
+            output.contains("test_event"),
+            "The output should contain the event name 'test_event'"
+        );
+        assert_eq!(
+            output.matches(&id_pattern).count(),
+            2,
+            "The output should contain two events (start and end) associated with the given ID"
+        );
+    }
+
+    #[test]
+    fn test_event_data_handling() {
+        let debug_store = DebugStore::new();
+        debug_store
+            .record("data_event".to_string(), vec![("key".to_string(), "value".to_string())]);
+        let output = debug_store.to_string();
+        assert!(
+            output.contains("data_event"),
+            "The output should contain the event name 'data_event'"
+        );
+        assert!(
+            output.contains("key=value"),
+            "The output should contain the event data 'key=value'"
+        );
+    }
+}
diff --git a/libs/debugstore/rust/src/event.rs b/libs/debugstore/rust/src/event.rs
new file mode 100644
index 0000000..0c16665
--- /dev/null
+++ b/libs/debugstore/rust/src/event.rs
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+use super::event_type::EventType;
+use std::fmt;
+
+/// Represents a single debug event within the Debug Store system.
+///
+/// It contains all the necessary information for a debug event.
+#[derive(Clone)]
+pub struct Event {
+    /// The unique identifier for this event.
+    pub id: u64,
+    /// The optional name of the event.
+    pub name: Option<String>,
+    /// The system uptime when the event occurred.
+    pub timestamp: i64,
+    /// The type of the event.
+    pub event_type: EventType,
+    /// Additional data associated with the event, stored in the given order as key-value pairs.
+    data: Vec<(String, String)>,
+}
+
+impl Event {
+    /// Constructs a new `Event`.
+    ///
+    /// - `id`: The unique identifier for the event.
+    /// - `name`: An optional name for the event.
+    /// - `timestamp`: The system uptime when the event occurred.
+    /// - `event_type`: The type of the event.
+    /// - `data`: Additional data for the event, represented as ordered key-value pairs.
+    pub fn new(
+        id: u64,
+        name: Option<String>,
+        timestamp: i64,
+        event_type: EventType,
+        data: Vec<(String, String)>,
+    ) -> Self {
+        Self { id, name, timestamp, event_type, data }
+    }
+}
+
+impl fmt::Display for Event {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "ID:{},C:{},T:{}", self.id, self.event_type, self.timestamp)?;
+
+        if let Some(ref name) = self.name {
+            write!(f, ",N:{}", name)?;
+        }
+
+        if !self.data.is_empty() {
+            let data_str =
+                self.data.iter().map(|(k, v)| format!("{}={}", k, v)).collect::<Vec<_>>().join(";");
+            write!(f, ",D:{}", data_str)?;
+        }
+
+        Ok(())
+    }
+}
diff --git a/libs/debugstore/rust/src/event_type.rs b/libs/debugstore/rust/src/event_type.rs
new file mode 100644
index 0000000..6f4bafb
--- /dev/null
+++ b/libs/debugstore/rust/src/event_type.rs
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+use std::fmt;
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum EventType {
+    /// Marks the an unknown or invalid event, for convenient mapping to a protobuf enum.
+    Invalid,
+    /// Marks the beginning of a duration-based event, indicating the start of a timed operation.
+    DurationStart,
+    /// Marks the end of a duration-based event, indicating the end of a timed operation.
+    DurationEnd,
+    /// Represents a single, instantaneous event with no duration.
+    Point,
+}
+
+impl fmt::Display for EventType {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "{}",
+            match self {
+                EventType::Invalid => "I",
+                EventType::DurationStart => "S",
+                EventType::DurationEnd => "E",
+                EventType::Point => "P",
+            }
+        )
+    }
+}
diff --git a/libs/debugstore/rust/src/lib.rs b/libs/debugstore/rust/src/lib.rs
new file mode 100644
index 0000000..f2195c0
--- /dev/null
+++ b/libs/debugstore/rust/src/lib.rs
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+//! # Debug Store Crate
+/// The Debug Store Crate provides functionalities for storing debug events.
+/// It allows logging and retrieval of debug events, and associated data.
+mod core;
+mod event;
+mod event_type;
+mod storage;
+
+pub use core::*;
+pub use event::*;
+
+use cxx::{CxxString, CxxVector};
+
+#[cxx::bridge(namespace = "android::debugstore")]
+#[allow(unsafe_op_in_unsafe_fn)]
+mod cxxffi {
+    extern "Rust" {
+        fn debug_store_to_string() -> String;
+        fn debug_store_record(name: &CxxString, data: &CxxVector<CxxString>);
+        fn debug_store_begin(name: &CxxString, data: &CxxVector<CxxString>) -> u64;
+        fn debug_store_end(id: u64, data: &CxxVector<CxxString>);
+    }
+
+    #[namespace = "android"]
+    unsafe extern "C++" {
+        include!("utils/SystemClock.h");
+        fn uptimeMillis() -> i64;
+    }
+}
+
+fn debug_store_to_string() -> String {
+    DebugStore::get_instance().to_string()
+}
+
+fn debug_store_record(name: &CxxString, data: &CxxVector<CxxString>) {
+    DebugStore::get_instance().record(name.to_string_lossy().into_owned(), cxx_vec_to_pairs(data));
+}
+
+fn debug_store_begin(name: &CxxString, data: &CxxVector<CxxString>) -> u64 {
+    DebugStore::get_instance().begin(name.to_string_lossy().into_owned(), cxx_vec_to_pairs(data))
+}
+
+fn debug_store_end(id: u64, data: &CxxVector<CxxString>) {
+    DebugStore::get_instance().end(id, cxx_vec_to_pairs(data));
+}
+
+fn cxx_vec_to_pairs(vec: &CxxVector<CxxString>) -> Vec<(String, String)> {
+    vec.iter()
+        .map(|s| s.to_string_lossy().into_owned())
+        .collect::<Vec<_>>()
+        .chunks(2)
+        .filter_map(|chunk| match chunk {
+            [k, v] => Some((k.clone(), v.clone())),
+            _ => None,
+        })
+        .collect()
+}
diff --git a/libs/debugstore/rust/src/storage.rs b/libs/debugstore/rust/src/storage.rs
new file mode 100644
index 0000000..2ad7f4e
--- /dev/null
+++ b/libs/debugstore/rust/src/storage.rs
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+use crossbeam_queue::ArrayQueue;
+
+/// A thread-safe storage that allows non-blocking attempts to store and visit elements.
+pub struct Storage<T, const N: usize> {
+    insertion_buffer: ArrayQueue<T>,
+}
+
+impl<T, const N: usize> Storage<T, N> {
+    /// Creates a new Storage with the specified size.
+    pub fn new() -> Self {
+        Self { insertion_buffer: ArrayQueue::new(N) }
+    }
+
+    /// Inserts a value into the storage, returning an error if the lock cannot be acquired.
+    pub fn insert(&self, value: T) {
+        self.insertion_buffer.force_push(value);
+    }
+
+    /// Folds over the elements in the storage using the provided function.
+    pub fn fold<U, F>(&self, init: U, mut func: F) -> U
+    where
+        F: FnMut(U, &T) -> U,
+    {
+        let mut acc = init;
+        while let Some(value) = self.insertion_buffer.pop() {
+            acc = func(acc, &value);
+        }
+        acc
+    }
+
+    /// Returns the number of elements that have been inserted into the storage.
+    pub fn len(&self) -> usize {
+        self.insertion_buffer.len()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_insert_and_retrieve() {
+        let storage = Storage::<i32, 10>::new();
+        storage.insert(7);
+
+        let sum = storage.fold(0, |acc, &x| acc + x);
+        assert_eq!(sum, 7, "The sum of the elements should be equal to the inserted value.");
+    }
+
+    #[test]
+    fn test_fold_functionality() {
+        let storage = Storage::<i32, 5>::new();
+        storage.insert(1);
+        storage.insert(2);
+        storage.insert(3);
+
+        let sum = storage.fold(0, |acc, &x| acc + x);
+        assert_eq!(
+            sum, 6,
+            "The sum of the elements should be equal to the sum of inserted values."
+        );
+    }
+
+    #[test]
+    fn test_insert_and_retrieve_multiple_values() {
+        let storage = Storage::<i32, 10>::new();
+        storage.insert(1);
+        storage.insert(2);
+        storage.insert(5);
+
+        let first_sum = storage.fold(0, |acc, &x| acc + x);
+        assert_eq!(first_sum, 8, "The sum of the elements should be equal to the inserted values.");
+
+        storage.insert(30);
+        storage.insert(22);
+
+        let second_sum = storage.fold(0, |acc, &x| acc + x);
+        assert_eq!(
+            second_sum, 52,
+            "The sum of the elements should be equal to the inserted values."
+        );
+    }
+
+    #[test]
+    fn test_storage_limit() {
+        let storage = Storage::<i32, 1>::new();
+        storage.insert(1);
+        // This value should overwrite the previously inserted value (1).
+        storage.insert(4);
+        let sum = storage.fold(0, |acc, &x| acc + x);
+        assert_eq!(sum, 4, "The sum of the elements should be equal to the inserted values.");
+    }
+
+    #[test]
+    fn test_concurrent_insertions() {
+        use std::sync::Arc;
+        use std::thread;
+
+        let storage = Arc::new(Storage::<i32, 100>::new());
+        let threads: Vec<_> = (0..10)
+            .map(|_| {
+                let storage_clone = Arc::clone(&storage);
+                thread::spawn(move || {
+                    for i in 0..10 {
+                        storage_clone.insert(i);
+                    }
+                })
+            })
+            .collect();
+
+        for thread in threads {
+            thread.join().expect("Thread should finish without panicking");
+        }
+
+        let count = storage.fold(0, |acc, _| acc + 1);
+        assert_eq!(count, 100, "Storage should be filled to its limit with concurrent insertions.");
+    }
+}