Log keystore2 crash events.

Ignore-AOSP-First: Merge conflict resolution of a CL in the topic.
Bug: 188590587
Test: statsd TestDrive script.
Merged-In: I0ad7c94187060dca28469ba262e1e4d93fe3df83

Change-Id: I0ad7c94187060dca28469ba262e1e4d93fe3df83
diff --git a/keystore2/src/keystore2_main.rs b/keystore2/src/keystore2_main.rs
index 2c7d4a0..cf2ba04 100644
--- a/keystore2/src/keystore2_main.rs
+++ b/keystore2/src/keystore2_main.rs
@@ -18,6 +18,7 @@
 use keystore2::globals::ENFORCEMENTS;
 use keystore2::maintenance::Maintenance;
 use keystore2::metrics::Metrics;
+use keystore2::metrics_store;
 use keystore2::remote_provisioning::RemoteProvisioningService;
 use keystore2::service::KeystoreService;
 use keystore2::{apc::ApcManager, shared_secret_negotiation};
@@ -51,6 +52,9 @@
     let mut args = std::env::args();
     args.next().expect("That's odd. How is there not even a first argument?");
 
+    // Write/update keystore.crash_count system property.
+    metrics_store::update_keystore_crash_sysprop();
+
     // Keystore 2.0 cannot change to the database directory (typically /data/misc/keystore) on
     // startup as Keystore 1.0 did because Keystore 2.0 is intended to run much earlier than
     // Keystore 1.0. Instead we set a global variable to the database path.
diff --git a/keystore2/src/metrics_store.rs b/keystore2/src/metrics_store.rs
index 32fe353..32067b9 100644
--- a/keystore2/src/metrics_store.rs
+++ b/keystore2/src/metrics_store.rs
@@ -29,7 +29,8 @@
     SecurityLevel::SecurityLevel,
 };
 use android_security_metrics::aidl::android::security::metrics::{
-    Algorithm::Algorithm as MetricsAlgorithm, AtomID::AtomID, EcCurve::EcCurve as MetricsEcCurve,
+    Algorithm::Algorithm as MetricsAlgorithm, AtomID::AtomID, CrashStats::CrashStats,
+    EcCurve::EcCurve as MetricsEcCurve,
     HardwareAuthenticatorType::HardwareAuthenticatorType as MetricsHardwareAuthenticatorType,
     KeyCreationWithAuthInfo::KeyCreationWithAuthInfo,
     KeyCreationWithGeneralInfo::KeyCreationWithGeneralInfo,
@@ -43,12 +44,17 @@
     RkpPoolStats::RkpPoolStats, SecurityLevel::SecurityLevel as MetricsSecurityLevel,
     Storage::Storage as MetricsStorage,
 };
-use anyhow::Result;
+use anyhow::{Context, Result};
+use keystore2_system_property::{write, PropertyWatcher, PropertyWatcherError};
 use lazy_static::lazy_static;
 use std::collections::HashMap;
 use std::sync::Mutex;
 use std::time::{Duration, SystemTime, UNIX_EPOCH};
 
+// Note: Crash events are recorded at keystore restarts, based on the assumption that keystore only
+// gets restarted after a crash, during a boot cycle.
+const KEYSTORE_CRASH_COUNT_PROPERTY: &str = "keystore.crash_count";
+
 lazy_static! {
     /// Singleton for MetricsStore.
     pub static ref METRICS_STORE: MetricsStore = Default::default();
@@ -92,6 +98,16 @@
             return pull_attestation_pool_stats();
         }
 
+        // Process keystore crash stats.
+        if AtomID::CRASH_STATS == atom_id {
+            return Ok(vec![KeystoreAtom {
+                payload: KeystoreAtomPayload::CrashStats(CrashStats {
+                    count_of_crash_events: read_keystore_crash_count()?,
+                }),
+                ..Default::default()
+            }]);
+        }
+
         // It is safe to call unwrap here since the lock can not be poisoned based on its usage
         // in this module and the lock is not acquired in the same thread before.
         let metrics_store_guard = self.metrics_store.lock().unwrap();
@@ -582,6 +598,55 @@
     METRICS_STORE.insert_atom(AtomID::RKP_ERROR_STATS, rkp_error_stats);
 }
 
+/// This function tries to read and update the system property: keystore.crash_count.
+/// If the property is absent, it sets the property with value 0. If the property is present, it
+/// increments the value. This helps tracking keystore crashes internally.
+pub fn update_keystore_crash_sysprop() {
+    let crash_count = read_keystore_crash_count();
+    let new_count = match crash_count {
+        Ok(count) => count + 1,
+        Err(error) => {
+            // If the property is absent, this is the first start up during the boot.
+            // Proceed to write the system property with value 0. Otherwise, log and return.
+            if !matches!(
+                error.root_cause().downcast_ref::<PropertyWatcherError>(),
+                Some(PropertyWatcherError::SystemPropertyAbsent)
+            ) {
+                log::warn!(
+                    concat!(
+                        "In update_keystore_crash_sysprop: ",
+                        "Failed to read the existing system property due to: {:?}.",
+                        "Therefore, keystore crashes will not be logged."
+                    ),
+                    error
+                );
+                return;
+            }
+            0
+        }
+    };
+
+    if let Err(e) = write(KEYSTORE_CRASH_COUNT_PROPERTY, &new_count.to_string()) {
+        log::error!(
+            concat!(
+                "In update_keystore_crash_sysprop:: ",
+                "Failed to write the system property due to error: {:?}"
+            ),
+            e
+        );
+    }
+}
+
+/// Read the system property: keystore.crash_count.
+pub fn read_keystore_crash_count() -> Result<i32> {
+    let mut prop_reader = PropertyWatcher::new("keystore.crash_count").context(concat!(
+        "In read_keystore_crash_count: Failed to create reader a PropertyWatcher."
+    ))?;
+    prop_reader
+        .read(|_n, v| v.parse::<i32>().map_err(std::convert::Into::into))
+        .context("In read_keystore_crash_count: Failed to read the existing system property.")
+}
+
 /// Enum defining the bit position for each padding mode. Since padding mode can be repeatable, it
 /// is represented using a bitmap.
 #[allow(non_camel_case_types)]