Snap for 7956453 from 970ba98ee22d24d42c5f1ee05aa8ec25fe90ea36 to sc-v2-release

Change-Id: Iaeac564004cf4f68864f0ab19868f89cb5d53a2f
diff --git a/profcollectd/libprofcollectd/config.rs b/profcollectd/libprofcollectd/config.rs
index e8afb37..902b5b5 100644
--- a/profcollectd/libprofcollectd/config.rs
+++ b/profcollectd/libprofcollectd/config.rs
@@ -22,6 +22,7 @@
 use rand::Rng;
 use serde::{Deserialize, Serialize};
 use std::error::Error;
+use std::fs::{read_dir, remove_file};
 use std::path::Path;
 use std::str::FromStr;
 use std::time::Duration;
@@ -31,6 +32,7 @@
 
 pub const REPORT_RETENTION_SECS: u64 = 14 * 24 * 60 * 60; // 14 days.
 
+// Static configs that cannot be changed.
 lazy_static! {
     pub static ref TRACE_OUTPUT_DIR: &'static Path = Path::new("/data/misc/profcollectd/trace/");
     pub static ref PROFILE_OUTPUT_DIR: &'static Path = Path::new("/data/misc/profcollectd/output/");
@@ -42,6 +44,7 @@
         Path::new("/data/misc/profcollectd/output/config.json");
 }
 
+/// Dynamic configs, stored in config.json.
 #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
 pub struct Config {
     /// Version of config file scheme, always equals to 1.
@@ -56,6 +59,8 @@
     pub sampling_period: Duration,
     /// An optional filter to limit which binaries to or not to profile.
     pub binary_filter: String,
+    /// Maximum size of the trace directory.
+    pub max_trace_limit: u64,
 }
 
 impl Config {
@@ -70,6 +75,10 @@
             )?),
             sampling_period: Duration::from_millis(get_device_config("sampling_period", 500)?),
             binary_filter: get_device_config("binary_filter", "".to_string())?,
+            max_trace_limit: get_device_config(
+                "max_trace_limit",
+                /* 512MB */ 512 * 1024 * 1024,
+            )?,
         })
     }
 }
@@ -138,3 +147,19 @@
     node_id[0] |= 0x1;
     MacAddr6::from(node_id)
 }
+
+pub fn clear_data() -> Result<()> {
+    fn remove_files(path: &Path) -> Result<()> {
+        read_dir(path)?
+            .filter_map(|e| e.ok())
+            .map(|e| e.path())
+            .filter(|e| e.is_file())
+            .try_for_each(remove_file)?;
+        Ok(())
+    }
+
+    remove_files(&TRACE_OUTPUT_DIR)?;
+    remove_files(&PROFILE_OUTPUT_DIR)?;
+    remove_files(&REPORT_OUTPUT_DIR)?;
+    Ok(())
+}
diff --git a/profcollectd/libprofcollectd/lib.rs b/profcollectd/libprofcollectd/lib.rs
index f417bd8..5892e25 100644
--- a/profcollectd/libprofcollectd/lib.rs
+++ b/profcollectd/libprofcollectd/lib.rs
@@ -91,6 +91,12 @@
     Ok(get_profcollectd_service()?.report()?)
 }
 
+/// Clear all local data.
+pub fn reset() -> Result<()> {
+    config::clear_data()?;
+    Ok(())
+}
+
 /// Inits logging for Android
 pub fn init_logging() {
     let min_log_level = if cfg!(feature = "test") { log::Level::Info } else { log::Level::Error };
diff --git a/profcollectd/libprofcollectd/scheduler.rs b/profcollectd/libprofcollectd/scheduler.rs
index cfd0381..b83bc45 100644
--- a/profcollectd/libprofcollectd/scheduler.rs
+++ b/profcollectd/libprofcollectd/scheduler.rs
@@ -16,6 +16,8 @@
 
 //! ProfCollect tracing scheduler.
 
+use std::fs;
+use std::path::Path;
 use std::sync::mpsc::{sync_channel, SyncSender};
 use std::sync::Arc;
 use std::sync::Mutex;
@@ -59,11 +61,13 @@
                     Ok(_) => break,
                     Err(_) => {
                         // Did not receive a termination signal, initiate trace event.
-                        trace_provider.lock().unwrap().trace(
-                            &TRACE_OUTPUT_DIR,
-                            "periodic",
-                            &config.sampling_period,
-                        );
+                        if check_space_limit(*TRACE_OUTPUT_DIR, &config).unwrap() {
+                            trace_provider.lock().unwrap().trace(
+                                &TRACE_OUTPUT_DIR,
+                                "periodic",
+                                &config.sampling_period,
+                            );
+                        }
                     }
                 }
             }
@@ -83,7 +87,9 @@
 
     pub fn one_shot(&self, config: &Config, tag: &str) -> Result<()> {
         let trace_provider = self.trace_provider.clone();
-        trace_provider.lock().unwrap().trace(&TRACE_OUTPUT_DIR, tag, &config.sampling_period);
+        if check_space_limit(*TRACE_OUTPUT_DIR, config)? {
+            trace_provider.lock().unwrap().trace(&TRACE_OUTPUT_DIR, tag, &config.sampling_period);
+        }
         Ok(())
     }
 
@@ -106,3 +112,21 @@
         self.trace_provider.lock().unwrap().get_name()
     }
 }
+
+/// Run if space usage is under limit.
+fn check_space_limit(path: &Path, config: &Config) -> Result<bool> {
+    let ret = dir_size(path)? <= config.max_trace_limit;
+    if !ret {
+        log::error!("trace storage exhausted.");
+    }
+    Ok(ret)
+}
+
+/// Returns the size of a directory, non-recursive.
+fn dir_size(path: &Path) -> Result<u64> {
+    fs::read_dir(path)?.try_fold(0, |acc, file| {
+        let metadata = file?.metadata()?;
+        let size = if metadata.is_file() { metadata.len() } else { 0 };
+        Ok(acc + size)
+    })
+}
diff --git a/profcollectd/libprofcollectd/service.rs b/profcollectd/libprofcollectd/service.rs
index 04f30f8..a7fdce7 100644
--- a/profcollectd/libprofcollectd/service.rs
+++ b/profcollectd/libprofcollectd/service.rs
@@ -21,15 +21,15 @@
 use binder::Status;
 use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProfCollectd::IProfCollectd;
 use std::ffi::CString;
-use std::fs::{copy, create_dir, read_dir, read_to_string, remove_dir_all, remove_file, write};
+use std::fs::{copy, read_dir, read_to_string, remove_file, write};
 use std::path::PathBuf;
 use std::str::FromStr;
 use std::sync::{Mutex, MutexGuard};
 use std::time::Duration;
 
 use crate::config::{
-    Config, BETTERBUG_CACHE_DIR_PREFIX, BETTERBUG_CACHE_DIR_SUFFIX, CONFIG_FILE,
-    PROFILE_OUTPUT_DIR, REPORT_OUTPUT_DIR, REPORT_RETENTION_SECS, TRACE_OUTPUT_DIR,
+    clear_data, Config, BETTERBUG_CACHE_DIR_PREFIX, BETTERBUG_CACHE_DIR_SUFFIX, CONFIG_FILE,
+    PROFILE_OUTPUT_DIR, REPORT_OUTPUT_DIR, REPORT_RETENTION_SECS,
 };
 use crate::report::{get_report_ts, pack_report};
 use crate::scheduler::Scheduler;
@@ -147,11 +147,8 @@
             .is_none();
 
         if config_changed {
-            log::info!("Config change detected, clearing traces.");
-            remove_dir_all(*PROFILE_OUTPUT_DIR)?;
-            remove_dir_all(*TRACE_OUTPUT_DIR)?;
-            create_dir(*PROFILE_OUTPUT_DIR)?;
-            create_dir(*TRACE_OUTPUT_DIR)?;
+            log::info!("Config change detected, resetting profcollect.");
+            clear_data()?;
 
             write(*CONFIG_FILE, &new_config.to_string())?;
         }
diff --git a/profcollectd/profcollectctl.rs b/profcollectd/profcollectctl.rs
index c825f55..6778465 100644
--- a/profcollectd/profcollectctl.rs
+++ b/profcollectd/profcollectctl.rs
@@ -29,8 +29,9 @@
     stop        Terminate periodic collection.
     once        Request an one-off trace.
     process     Convert traces to perf profiles.
-    report      Create a report containing all profiles.
     reconfig    Refresh configuration.
+    report      Create a report containing all profiles.
+    reset       Clear all local data.
     help        Print this message.
 "#;
 
@@ -65,6 +66,10 @@
             let path = libprofcollectd::report().context("Failed to create profile report.")?;
             println!("Report created at: {}", &path);
         }
+        "reset" => {
+            libprofcollectd::reset().context("Failed to reset.")?;
+            println!("Reset done.");
+        }
         "help" => println!("{}", &HELP_MSG),
         arg => bail!("Unknown argument: {}\n{}", &arg, &HELP_MSG),
     }
diff --git a/profcollectd/profcollectd.rc b/profcollectd/profcollectd.rc
index 1100bd2..b92fccb 100644
--- a/profcollectd/profcollectd.rc
+++ b/profcollectd/profcollectd.rc
@@ -6,15 +6,15 @@
     group root wakelock
     writepid /dev/cpuset/system-background/tasks
 
-on property:persist.device_config.profcollect_native_boot.enabled=true
-    start profcollectd
-
-on property:persist.profcollectd.enabled_override=true
-    start profcollectd
-
 on post-fs-data
     # Create directory for profcollectd.
     mkdir /data/misc/profcollectd 0770 shell shell
     mkdir /data/misc/profcollectd/trace 0770 shell shell
     mkdir /data/misc/profcollectd/output 0770 shell shell
     mkdir /data/misc/profcollectd/report 0770 shell shell
+
+on boot && property:persist.device_config.profcollect_native_boot.enabled=true
+    start profcollectd
+
+on boot && property:persist.device_config.profcollect_native_boot.enabled=
+    exec_background - root shell -- /system/bin/profcollectctl reset