rusty-gd: Add btsnoop config

Bug: 171749953
Tag: #gd-refactor
Test: gd/cert/run --rhost SimpleHalTest
Change-Id: Ibbce98d9e12355e0bef63ef62cfbac8098884775
diff --git a/system/gd/rust/common/src/sys_prop.rs b/system/gd/rust/common/src/sys_prop.rs
index 20b01f1..db0779f 100644
--- a/system/gd/rust/common/src/sys_prop.rs
+++ b/system/gd/rust/common/src/sys_prop.rs
@@ -27,3 +27,30 @@
 pub fn get(_name: &str) -> Option<String> {
     None
 }
+
+/// Gets the specified property as a u32
+pub fn get_u32(name: &str) -> Option<u32> {
+    if let Some(value) = get(name) {
+        value.parse().ok()
+    } else {
+        None
+    }
+}
+
+/// Gets the specified property as a bool (logic follows libcutils/properties.cpp)
+pub fn get_bool(name: &str) -> Option<bool> {
+    if let Some(value) = get(name) {
+        match value.as_str() {
+            "0" | "n" | "no" | "false" | "off" => Some(false),
+            "1" | "y" | "yes" | "true" | "on" => Some(true),
+            _ => None
+        }
+    } else {
+        None
+    }
+}
+
+/// Gets whether the current build is debuggable
+pub fn get_debuggable() -> bool {
+    get_bool("ro.debuggable").unwrap_or(false)
+}
diff --git a/system/gd/rust/facade/src/lib.rs b/system/gd/rust/facade/src/lib.rs
index f15cb3d..ac6bc4d 100644
--- a/system/gd/rust/facade/src/lib.rs
+++ b/system/gd/rust/facade/src/lib.rs
@@ -35,10 +35,11 @@
         rt: Arc<Runtime>,
         grpc_port: u16,
         rootcanal_port: Option<u16>,
+        snoop_path: Option<String>,
     ) -> grpcio::Service {
         create_root_facade(Self {
             rt: rt.clone(),
-            manager: FacadeServiceManager::create(rt, grpc_port, rootcanal_port),
+            manager: FacadeServiceManager::create(rt, grpc_port, rootcanal_port, snoop_path),
         })
     }
 }
@@ -121,7 +122,7 @@
 type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
 
 impl FacadeServiceManager {
-    fn create(rt: Arc<Runtime>, grpc_port: u16, rootcanal_port: Option<u16>) -> Self {
+    fn create(rt: Arc<Runtime>, grpc_port: u16, rootcanal_port: Option<u16>, snoop_path: Option<String>) -> Self {
         let (tx, mut rx) = channel::<LifecycleCommand>(1);
         let local_rt = rt.clone();
         rt.spawn(async move {
@@ -131,6 +132,7 @@
                     LifecycleCommand::Start { req, done } => {
                         let stack = Stack::new(local_rt.clone()).await;
                         stack.set_rootcanal_port(rootcanal_port).await;
+                        stack.configure_snoop(snoop_path.clone()).await;
                         server = Some(FacadeServer::start(stack, req, grpc_port).await);
                         done.send(()).unwrap();
                     }
diff --git a/system/gd/rust/facade/src/main.rs b/system/gd/rust/facade/src/main.rs
index ad2c3f7..a7227d4 100644
--- a/system/gd/rust/facade/src/main.rs
+++ b/system/gd/rust/facade/src/main.rs
@@ -12,12 +12,12 @@
 use futures::executor::block_on;
 use futures::stream::StreamExt;
 use grpcio::*;
+use log::debug;
 use nix::sys::signal;
 use std::net::{IpAddr, Ipv4Addr, Shutdown, SocketAddr};
 use std::sync::{Arc, Mutex};
 use tokio::net::TcpStream;
 use tokio::runtime::Runtime;
-use log::debug;
 
 fn main() {
     let sigint = install_sigint();
@@ -64,10 +64,14 @@
     let grpc_port = value_t!(matches, "grpc-port", u16).unwrap();
     let signal_port = value_t!(matches, "signal-port", u16).unwrap();
     let rootcanal_port = value_t!(matches, "rootcanal-port", u16).ok();
-
     let env = Arc::new(Environment::new(2));
     let mut server = ServerBuilder::new(env)
-        .register_service(RootFacadeService::create(rt, grpc_port, rootcanal_port))
+        .register_service(RootFacadeService::create(
+            rt,
+            grpc_port,
+            rootcanal_port,
+            matches.value_of("btsnoop").map(String::from),
+        ))
         .bind("0.0.0.0", root_server_port)
         .build()
         .unwrap();
diff --git a/system/gd/rust/hal/src/lib.rs b/system/gd/rust/hal/src/lib.rs
index 75791e1..99f11d1 100644
--- a/system/gd/rust/hal/src/lib.rs
+++ b/system/gd/rust/hal/src/lib.rs
@@ -7,6 +7,7 @@
 
 pub mod facade;
 pub mod rootcanal_hal;
+pub mod snoop;
 
 #[cfg(target_os = "android")]
 mod hidl_hal;
diff --git a/system/gd/rust/hal/src/snoop.rs b/system/gd/rust/hal/src/snoop.rs
new file mode 100644
index 0000000..f5b7620
--- /dev/null
+++ b/system/gd/rust/hal/src/snoop.rs
@@ -0,0 +1,77 @@
+//! BT snoop logger
+
+use bt_common::sys_prop;
+use gddi::Stoppable;
+
+/// The different modes snoop logging can be in
+#[derive(Clone)]
+pub enum SnoopMode {
+    /// All logs disabled
+    Disabled,
+    /// Only sanitized logs
+    Filtered,
+    /// Log everything
+    Full,
+}
+
+/// There was an error parsing the mode from a string
+pub struct SnoopModeParseError;
+
+impl std::str::FromStr for SnoopMode {
+    type Err = SnoopModeParseError;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "disabled" => Ok(SnoopMode::Disabled),
+            "filtered" => Ok(SnoopMode::Filtered),
+            "full" => Ok(SnoopMode::Full),
+            _ => Err(SnoopModeParseError),
+        }
+    }
+}
+
+/// All snoop logging config
+#[derive(Clone, Stoppable)]
+pub struct SnoopConfig {
+    path: String,
+    max_packets_per_file: u32,
+    mode: SnoopMode,
+}
+
+impl SnoopConfig {
+    /// Constructs a new snoop config
+    pub fn new() -> Self {
+        Self {
+            path: "/data/misc/bluetooth/logs/btsnoop_hci.log".to_string(),
+            max_packets_per_file: sys_prop::get_u32("persist.bluetooth.btsnoopsize")
+                .unwrap_or(0xFFFF),
+            mode: get_configured_snoop_mode()
+                .parse()
+                .unwrap_or(SnoopMode::Disabled),
+        }
+    }
+
+    /// Overwrites the laoded log path with the provided one
+    pub fn set_path(&mut self, value: String) {
+        self.path = value;
+    }
+
+    /// Overwrites the loaded mode with the provided one
+    pub fn set_mode(&mut self, value: SnoopMode) {
+        self.mode = value;
+    }
+}
+
+impl Default for SnoopConfig {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+fn get_configured_snoop_mode() -> String {
+    sys_prop::get("persist.bluetooth.btsnooplogmode").unwrap_or(if sys_prop::get_debuggable() {
+        sys_prop::get("persist.bluetooth.btsnoopdefaultmode").unwrap_or_default()
+    } else {
+        String::default()
+    })
+}
diff --git a/system/gd/rust/main/src/lib.rs b/system/gd/rust/main/src/lib.rs
index e294f86..5013a03 100644
--- a/system/gd/rust/main/src/lib.rs
+++ b/system/gd/rust/main/src/lib.rs
@@ -2,6 +2,7 @@
 
 use gddi::{module, Registry, RegistryBuilder, Stoppable};
 use bt_hal::rootcanal_hal::RootcanalConfig;
+use bt_hal::snoop::{SnoopConfig, SnoopMode};
 use std::sync::Arc;
 use tokio::runtime::Runtime;
 use bt_common::GrpcFacade;
@@ -37,6 +38,16 @@
         }
     }
 
+    /// Configures snoop. If the path is provided, full logging is turned on
+    pub async fn configure_snoop(&self, path: Option<String>) {
+        let mut config = SnoopConfig::default();
+        if let Some(path) = path {
+            config.set_path(path);
+            config.set_mode(SnoopMode::Full);
+        }
+        self.registry.inject(config).await;
+    }
+
     /// Helper forwarding to underlying registry
     pub async fn get<T: 'static + Clone + Send + Sync + Stoppable>(&self) -> T {
         self.registry.get::<T>().await