Merge "Moving set_requesting_sid to new_binder method."
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index af177be..dfc1db0 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -54,6 +54,8 @@
         "librand",
         "librusqlite",
         "libstatslog_rust",
+        "libstatslog_rust_header",
+        "libstatspull_rust",
         "libthiserror",
     ],
     shared_libs: [
diff --git a/keystore2/aaid/Android.bp b/keystore2/aaid/Android.bp
index d27fdf6..c04ce51 100644
--- a/keystore2/aaid/Android.bp
+++ b/keystore2/aaid/Android.bp
@@ -39,8 +39,8 @@
 
     bindgen_flags: [
         "--size_t-is-usize",
-        "--whitelist-function=aaid_keystore_attestation_id",
-        "--whitelist-var=KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE",
+        "--allowlist-function=aaid_keystore_attestation_id",
+        "--allowlist-var=KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE",
     ],
 }
 
diff --git a/keystore2/apc_compat/Android.bp b/keystore2/apc_compat/Android.bp
index 9519c8e..bf21675 100644
--- a/keystore2/apc_compat/Android.bp
+++ b/keystore2/apc_compat/Android.bp
@@ -41,12 +41,12 @@
     source_stem: "bindings",
 
     bindgen_flags: [
-        "--whitelist-function=tryGetUserConfirmationService",
-        "--whitelist-function=promptUserConfirmation",
-        "--whitelist-function=abortUserConfirmation",
-        "--whitelist-function=closeUserConfirmationService",
-        "--whitelist-var=INVALID_SERVICE_HANDLE",
-        "--whitelist-var=APC_COMPAT_.*",
+        "--allowlist-function=tryGetUserConfirmationService",
+        "--allowlist-function=promptUserConfirmation",
+        "--allowlist-function=abortUserConfirmation",
+        "--allowlist-function=closeUserConfirmationService",
+        "--allowlist-var=INVALID_SERVICE_HANDLE",
+        "--allowlist-var=APC_COMPAT_.*",
     ],
 }
 
diff --git a/keystore2/src/authorization.rs b/keystore2/src/authorization.rs
index 0a8fe25..ec1edff 100644
--- a/keystore2/src/authorization.rs
+++ b/keystore2/src/authorization.rs
@@ -118,7 +118,7 @@
     }
 
     fn add_auth_token(&self, auth_token: &HardwareAuthToken) -> Result<()> {
-        //check keystore permission
+        // Check keystore permission.
         check_keystore_permission(KeystorePerm::add_auth()).context("In add_auth_token.")?;
 
         ENFORCEMENTS.add_auth_token(auth_token.clone())?;
@@ -133,8 +133,8 @@
     ) -> Result<()> {
         match (lock_screen_event, password) {
             (LockScreenEvent::UNLOCK, Some(password)) => {
-                //This corresponds to the unlock() method in legacy keystore API.
-                //check permission
+                // This corresponds to the unlock() method in legacy keystore API.
+                // check permission
                 check_keystore_permission(KeystorePerm::unlock())
                     .context("In on_lock_screen_event: Unlock with password.")?;
                 ENFORCEMENTS.set_device_locked(user_id, false);
@@ -201,7 +201,7 @@
         check_keystore_permission(KeystorePerm::get_auth_token())
             .context("In get_auth_tokens_for_credstore.")?;
 
-        // if the challenge is zero, return error
+        // If the challenge is zero, return error
         if challenge == 0 {
             return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT))
                 .context("In get_auth_tokens_for_credstore. Challenge can not be zero.");
diff --git a/keystore2/src/boot_level_keys.rs b/keystore2/src/boot_level_keys.rs
index 3d33a26..dd69ed7 100644
--- a/keystore2/src/boot_level_keys.rs
+++ b/keystore2/src/boot_level_keys.rs
@@ -224,6 +224,7 @@
         KeyParameterValue::KeySize(256).into(),
         KeyParameterValue::MinMacLength(256).into(),
         KeyParameterValue::KeyPurpose(KeyPurpose::SIGN).into(),
+        KeyParameterValue::NoAuthRequired.into(),
         KeyParameterValue::MaxUsesPerBoot(1).into(),
     ];
     // We use TRUSTED_ENVIRONMENT here because it is the authority on when
diff --git a/keystore2/src/crypto/Android.bp b/keystore2/src/crypto/Android.bp
index 21c9b74..3ba47cd 100644
--- a/keystore2/src/crypto/Android.bp
+++ b/keystore2/src/crypto/Android.bp
@@ -59,27 +59,27 @@
     shared_libs: ["libcrypto"],
     bindgen_flags: [
         "--size_t-is-usize",
-        "--whitelist-function", "randomBytes",
-        "--whitelist-function", "AES_gcm_encrypt",
-        "--whitelist-function", "AES_gcm_decrypt",
-        "--whitelist-function", "CreateKeyId",
-        "--whitelist-function", "generateKeyFromPassword",
-        "--whitelist-function", "HKDFExtract",
-        "--whitelist-function", "HKDFExpand",
-        "--whitelist-function", "ECDHComputeKey",
-        "--whitelist-function", "ECKEYGenerateKey",
-        "--whitelist-function", "ECKEYMarshalPrivateKey",
-        "--whitelist-function", "ECKEYParsePrivateKey",
-        "--whitelist-function", "EC_KEY_get0_public_key",
-        "--whitelist-function", "ECPOINTPoint2Oct",
-        "--whitelist-function", "ECPOINTOct2Point",
-        "--whitelist-function", "EC_KEY_free",
-        "--whitelist-function", "EC_POINT_free",
-        "--whitelist-function", "extractSubjectFromCertificate",
-        "--whitelist-type", "EC_KEY",
-        "--whitelist-type", "EC_POINT",
-        "--whitelist-var", "EC_MAX_BYTES",
-        "--whitelist-var", "EVP_MAX_MD_SIZE",
+        "--allowlist-function", "randomBytes",
+        "--allowlist-function", "AES_gcm_encrypt",
+        "--allowlist-function", "AES_gcm_decrypt",
+        "--allowlist-function", "CreateKeyId",
+        "--allowlist-function", "generateKeyFromPassword",
+        "--allowlist-function", "HKDFExtract",
+        "--allowlist-function", "HKDFExpand",
+        "--allowlist-function", "ECDHComputeKey",
+        "--allowlist-function", "ECKEYGenerateKey",
+        "--allowlist-function", "ECKEYMarshalPrivateKey",
+        "--allowlist-function", "ECKEYParsePrivateKey",
+        "--allowlist-function", "EC_KEY_get0_public_key",
+        "--allowlist-function", "ECPOINTPoint2Oct",
+        "--allowlist-function", "ECPOINTOct2Point",
+        "--allowlist-function", "EC_KEY_free",
+        "--allowlist-function", "EC_POINT_free",
+        "--allowlist-function", "extractSubjectFromCertificate",
+        "--allowlist-type", "EC_KEY",
+        "--allowlist-type", "EC_POINT",
+        "--allowlist-var", "EC_MAX_BYTES",
+        "--allowlist-var", "EVP_MAX_MD_SIZE",
     ],
     cflags: ["-DBORINGSSL_NO_CXX"],
 }
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index c35956f..32e2c98 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -72,6 +72,9 @@
 use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
     AttestationPoolStatus::AttestationPoolStatus,
 };
+use statslog_rust::keystore2_storage_stats::{
+	Keystore2StorageStats, StorageType as StatsdStorageType,
+};
 
 use keystore2_crypto::ZVec;
 use lazy_static::lazy_static;
@@ -829,6 +832,9 @@
     const UNASSIGNED_KEY_ID: i64 = -1i64;
     const PERBOOT_DB_FILE_NAME: &'static str = &"file:perboot.sqlite?mode=memory&cache=shared";
 
+    /// Name of the file that holds the cross-boot persistent database.
+    pub const PERSISTENT_DB_FILENAME: &'static str = &"persistent.sqlite";
+
     /// This creates a PerBootDbKeepAlive object to keep the per boot database alive.
     pub fn keep_perboot_db_alive() -> Result<PerBootDbKeepAlive> {
         let conn = Connection::open_in_memory()
@@ -847,7 +853,7 @@
     pub fn new(db_root: &Path, gc: Option<Gc>) -> Result<Self> {
         // Build the path to the sqlite file.
         let mut persistent_path = db_root.to_path_buf();
-        persistent_path.push("persistent.sqlite");
+        persistent_path.push(Self::PERSISTENT_DB_FILENAME);
 
         // Now convert them to strings prefixed with "file:"
         let mut persistent_path_str = "file:".to_owned();
@@ -1042,6 +1048,100 @@
         Ok(conn)
     }
 
+    fn do_table_size_query(
+        &mut self,
+        storage_type: StatsdStorageType,
+        query: &str,
+        params: &[&str],
+    ) -> Result<Keystore2StorageStats> {
+        let (total, unused) = self.with_transaction(TransactionBehavior::Deferred, |tx| {
+            tx.query_row(query, params, |row| Ok((row.get(0)?, row.get(1)?)))
+                .with_context(|| {
+                    format!("get_storage_stat: Error size of storage type {}", storage_type as i32)
+                })
+                .no_gc()
+        })?;
+        Ok(Keystore2StorageStats { storage_type, size: total, unused_size: unused })
+    }
+
+    fn get_total_size(&mut self) -> Result<Keystore2StorageStats> {
+        self.do_table_size_query(
+            StatsdStorageType::Database,
+            "SELECT page_count * page_size, freelist_count * page_size
+             FROM pragma_page_count('persistent'),
+                  pragma_page_size('persistent'),
+                  persistent.pragma_freelist_count();",
+            &[],
+        )
+    }
+
+    fn get_table_size(
+        &mut self,
+        storage_type: StatsdStorageType,
+        schema: &str,
+        table: &str,
+    ) -> Result<Keystore2StorageStats> {
+        self.do_table_size_query(
+            storage_type,
+            "SELECT pgsize,unused FROM dbstat(?1)
+             WHERE name=?2 AND aggregate=TRUE;",
+            &[schema, table],
+        )
+    }
+
+    /// Fetches a storage statisitics atom for a given storage type. For storage
+    /// types that map to a table, information about the table's storage is
+    /// returned. Requests for storage types that are not DB tables return None.
+    pub fn get_storage_stat(
+        &mut self,
+        storage_type: StatsdStorageType,
+    ) -> Result<Keystore2StorageStats> {
+        match storage_type {
+            StatsdStorageType::Database => self.get_total_size(),
+            StatsdStorageType::KeyEntry => {
+                self.get_table_size(storage_type, "persistent", "keyentry")
+            }
+            StatsdStorageType::KeyEntryIdIndex => {
+                self.get_table_size(storage_type, "persistent", "keyentry_id_index")
+            }
+            StatsdStorageType::KeyEntryDomainNamespaceIndex => {
+                self.get_table_size(storage_type, "persistent", "keyentry_domain_namespace_index")
+            }
+            StatsdStorageType::BlobEntry => {
+                self.get_table_size(storage_type, "persistent", "blobentry")
+            }
+            StatsdStorageType::BlobEntryKeyEntryIdIndex => {
+                self.get_table_size(storage_type, "persistent", "blobentry_keyentryid_index")
+            }
+            StatsdStorageType::KeyParameter => {
+                self.get_table_size(storage_type, "persistent", "keyparameter")
+            }
+            StatsdStorageType::KeyParameterKeyEntryIdIndex => {
+                self.get_table_size(storage_type, "persistent", "keyparameter_keyentryid_index")
+            }
+            StatsdStorageType::KeyMetadata => {
+                self.get_table_size(storage_type, "persistent", "keymetadata")
+            }
+            StatsdStorageType::KeyMetadataKeyEntryIdIndex => {
+                self.get_table_size(storage_type, "persistent", "keymetadata_keyentryid_index")
+            }
+            StatsdStorageType::Grant => self.get_table_size(storage_type, "persistent", "grant"),
+            StatsdStorageType::AuthToken => {
+                self.get_table_size(storage_type, "perboot", "authtoken")
+            }
+            StatsdStorageType::BlobMetadata => {
+                self.get_table_size(storage_type, "persistent", "blobmetadata")
+            }
+            StatsdStorageType::BlobMetadataBlobEntryIdIndex => {
+                self.get_table_size(storage_type, "persistent", "blobmetadata_blobentryid_index")
+            }
+            _ => Err(anyhow::Error::msg(format!(
+                "Unsupported storage type: {}",
+                storage_type as i32
+            ))),
+        }
+    }
+
     /// This function is intended to be used by the garbage collector.
     /// It deletes the blob given by `blob_id_to_delete`. It then tries to find a superseded
     /// key blob that might need special handling by the garbage collector.
@@ -3072,6 +3172,8 @@
     use rusqlite::NO_PARAMS;
     use rusqlite::{Error, TransactionBehavior};
     use std::cell::RefCell;
+    use std::collections::BTreeMap;
+    use std::fmt::Write;
     use std::sync::atomic::{AtomicU8, Ordering};
     use std::sync::Arc;
     use std::thread;
@@ -5172,4 +5274,192 @@
         assert_eq!(secret_bytes, &*decrypted_secret_bytes);
         Ok(())
     }
+
+    fn get_valid_statsd_storage_types() -> Vec<StatsdStorageType> {
+        vec![
+            StatsdStorageType::KeyEntry,
+            StatsdStorageType::KeyEntryIdIndex,
+            StatsdStorageType::KeyEntryDomainNamespaceIndex,
+            StatsdStorageType::BlobEntry,
+            StatsdStorageType::BlobEntryKeyEntryIdIndex,
+            StatsdStorageType::KeyParameter,
+            StatsdStorageType::KeyParameterKeyEntryIdIndex,
+            StatsdStorageType::KeyMetadata,
+            StatsdStorageType::KeyMetadataKeyEntryIdIndex,
+            StatsdStorageType::Grant,
+            StatsdStorageType::AuthToken,
+            StatsdStorageType::BlobMetadata,
+            StatsdStorageType::BlobMetadataBlobEntryIdIndex,
+        ]
+    }
+
+    /// Perform a simple check to ensure that we can query all the storage types
+    /// that are supported by the DB. Check for reasonable values.
+    #[test]
+    fn test_query_all_valid_table_sizes() -> Result<()> {
+        const PAGE_SIZE: i64 = 4096;
+
+        let mut db = new_test_db()?;
+
+        for t in get_valid_statsd_storage_types() {
+            let stat = db.get_storage_stat(t)?;
+            assert!(stat.size >= PAGE_SIZE);
+            assert!(stat.size >= stat.unused_size);
+        }
+
+        Ok(())
+    }
+
+    fn get_storage_stats_map(db: &mut KeystoreDB) -> BTreeMap<i32, Keystore2StorageStats> {
+        get_valid_statsd_storage_types()
+            .into_iter()
+            .map(|t| (t as i32, db.get_storage_stat(t).unwrap()))
+            .collect()
+    }
+
+    fn assert_storage_increased(
+        db: &mut KeystoreDB,
+        increased_storage_types: Vec<StatsdStorageType>,
+        baseline: &mut BTreeMap<i32, Keystore2StorageStats>,
+    ) {
+        for storage in increased_storage_types {
+            // Verify the expected storage increased.
+            let new = db.get_storage_stat(storage).unwrap();
+            let storage = storage as i32;
+            let old = &baseline[&storage];
+            assert!(new.size >= old.size, "{}: {} >= {}", storage, new.size, old.size);
+            assert!(
+                new.unused_size <= old.unused_size,
+                "{}: {} <= {}",
+                storage,
+                new.unused_size,
+                old.unused_size
+            );
+
+            // Update the baseline with the new value so that it succeeds in the
+            // later comparison.
+            baseline.insert(storage, new);
+        }
+
+        // Get an updated map of the storage and verify there were no unexpected changes.
+        let updated_stats = get_storage_stats_map(db);
+        assert_eq!(updated_stats.len(), baseline.len());
+
+        for &k in baseline.keys() {
+            let stringify = |map: &BTreeMap<i32, Keystore2StorageStats>| -> String {
+                let mut s = String::new();
+                for &k in map.keys() {
+                    writeln!(&mut s, "  {}: {}, {}", &k, map[&k].size, map[&k].unused_size)
+                        .expect("string concat failed");
+                }
+                s
+            };
+
+            assert!(
+                updated_stats[&k].size == baseline[&k].size
+                    && updated_stats[&k].unused_size == baseline[&k].unused_size,
+                "updated_stats:\n{}\nbaseline:\n{}",
+                stringify(&updated_stats),
+                stringify(&baseline)
+            );
+        }
+    }
+
+    #[test]
+    fn test_verify_key_table_size_reporting() -> Result<()> {
+        let mut db = new_test_db()?;
+        let mut working_stats = get_storage_stats_map(&mut db);
+
+        let key_id = db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
+        assert_storage_increased(
+            &mut db,
+            vec![
+                StatsdStorageType::KeyEntry,
+                StatsdStorageType::KeyEntryIdIndex,
+                StatsdStorageType::KeyEntryDomainNamespaceIndex,
+            ],
+            &mut working_stats,
+        );
+
+        let mut blob_metadata = BlobMetaData::new();
+        blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
+        db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), None)?;
+        assert_storage_increased(
+            &mut db,
+            vec![
+                StatsdStorageType::BlobEntry,
+                StatsdStorageType::BlobEntryKeyEntryIdIndex,
+                StatsdStorageType::BlobMetadata,
+                StatsdStorageType::BlobMetadataBlobEntryIdIndex,
+            ],
+            &mut working_stats,
+        );
+
+        let params = make_test_params(None);
+        db.insert_keyparameter(&key_id, &params)?;
+        assert_storage_increased(
+            &mut db,
+            vec![StatsdStorageType::KeyParameter, StatsdStorageType::KeyParameterKeyEntryIdIndex],
+            &mut working_stats,
+        );
+
+        let mut metadata = KeyMetaData::new();
+        metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
+        db.insert_key_metadata(&key_id, &metadata)?;
+        assert_storage_increased(
+            &mut db,
+            vec![StatsdStorageType::KeyMetadata, StatsdStorageType::KeyMetadataKeyEntryIdIndex],
+            &mut working_stats,
+        );
+
+        let mut sum = 0;
+        for stat in working_stats.values() {
+            sum += stat.size;
+        }
+        let total = db.get_storage_stat(StatsdStorageType::Database)?.size;
+        assert!(sum <= total, "Expected sum <= total. sum: {}, total: {}", sum, total);
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_verify_auth_table_size_reporting() -> Result<()> {
+        let mut db = new_test_db()?;
+        let mut working_stats = get_storage_stats_map(&mut db);
+        db.insert_auth_token(&HardwareAuthToken {
+            challenge: 123,
+            userId: 456,
+            authenticatorId: 789,
+            authenticatorType: kmhw_authenticator_type::ANY,
+            timestamp: Timestamp { milliSeconds: 10 },
+            mac: b"mac".to_vec(),
+        })?;
+        assert_storage_increased(&mut db, vec![StatsdStorageType::AuthToken], &mut working_stats);
+        Ok(())
+    }
+
+    #[test]
+    fn test_verify_grant_table_size_reporting() -> Result<()> {
+        const OWNER: i64 = 1;
+        let mut db = new_test_db()?;
+        make_test_key_entry(&mut db, Domain::APP, OWNER, TEST_ALIAS, None)?;
+
+        let mut working_stats = get_storage_stats_map(&mut db);
+        db.grant(
+            &KeyDescriptor {
+                domain: Domain::APP,
+                nspace: 0,
+                alias: Some(TEST_ALIAS.to_string()),
+                blob: None,
+            },
+            OWNER as u32,
+            123,
+            key_perm_set![KeyPerm::use_()],
+            |_, _| Ok(()),
+        )?;
+
+        assert_storage_increased(&mut db, vec![StatsdStorageType::Grant], &mut working_stats);
+
+        Ok(())
+    }
 }
diff --git a/keystore2/src/enforcements.rs b/keystore2/src/enforcements.rs
index 7993c88..378b72f 100644
--- a/keystore2/src/enforcements.rs
+++ b/keystore2/src/enforcements.rs
@@ -61,47 +61,54 @@
     state: AuthRequestState,
     /// This need to be set to Some to fulfill a AuthRequestState::OpAuth or
     /// AuthRequestState::TimeStampedOpAuth.
-    hat: Option<HardwareAuthToken>,
+    hat: Mutex<Option<HardwareAuthToken>>,
 }
 
+unsafe impl Sync for AuthRequest {}
+
 impl AuthRequest {
-    fn op_auth() -> Arc<Mutex<Self>> {
-        Arc::new(Mutex::new(Self { state: AuthRequestState::OpAuth, hat: None }))
+    fn op_auth() -> Arc<Self> {
+        Arc::new(Self { state: AuthRequestState::OpAuth, hat: Mutex::new(None) })
     }
 
-    fn timestamped_op_auth(receiver: Receiver<Result<TimeStampToken, Error>>) -> Arc<Mutex<Self>> {
-        Arc::new(Mutex::new(Self {
+    fn timestamped_op_auth(receiver: Receiver<Result<TimeStampToken, Error>>) -> Arc<Self> {
+        Arc::new(Self {
             state: AuthRequestState::TimeStampedOpAuth(receiver),
-            hat: None,
-        }))
+            hat: Mutex::new(None),
+        })
     }
 
     fn timestamp(
         hat: HardwareAuthToken,
         receiver: Receiver<Result<TimeStampToken, Error>>,
-    ) -> Arc<Mutex<Self>> {
-        Arc::new(Mutex::new(Self { state: AuthRequestState::TimeStamp(receiver), hat: Some(hat) }))
+    ) -> Arc<Self> {
+        Arc::new(Self { state: AuthRequestState::TimeStamp(receiver), hat: Mutex::new(Some(hat)) })
     }
 
-    fn add_auth_token(&mut self, hat: HardwareAuthToken) {
-        self.hat = Some(hat)
+    fn add_auth_token(&self, hat: HardwareAuthToken) {
+        *self.hat.lock().unwrap() = Some(hat)
     }
 
-    fn get_auth_tokens(&mut self) -> Result<(HardwareAuthToken, Option<TimeStampToken>)> {
-        match (&self.state, self.hat.is_some()) {
-            (AuthRequestState::OpAuth, true) => Ok((self.hat.take().unwrap(), None)),
-            (AuthRequestState::TimeStampedOpAuth(recv), true)
-            | (AuthRequestState::TimeStamp(recv), true) => {
+    fn get_auth_tokens(&self) -> Result<(HardwareAuthToken, Option<TimeStampToken>)> {
+        let hat = self
+            .hat
+            .lock()
+            .unwrap()
+            .take()
+            .ok_or(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED))
+            .context("In get_auth_tokens: No operation auth token received.")?;
+
+        let tst = match &self.state {
+            AuthRequestState::TimeStampedOpAuth(recv) | AuthRequestState::TimeStamp(recv) => {
                 let result = recv.recv().context("In get_auth_tokens: Sender disconnected.")?;
-                let tst = result.context(concat!(
+                Some(result.context(concat!(
                     "In get_auth_tokens: Worker responded with error ",
                     "from generating timestamp token."
-                ))?;
-                Ok((self.hat.take().unwrap(), Some(tst)))
+                ))?)
             }
-            (_, false) => Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED))
-                .context("In get_auth_tokens: No operation auth token received."),
-        }
+            AuthRequestState::OpAuth => None,
+        };
+        Ok((hat, tst))
     }
 }
 
@@ -127,7 +134,7 @@
     /// We block on timestamp tokens, because we can always make progress on these requests.
     /// The per-op auth tokens might never come, which means we fail if the client calls
     /// update or finish before we got a per-op auth token.
-    Waiting(Arc<Mutex<AuthRequest>>),
+    Waiting(Arc<AuthRequest>),
     /// In this state we have gotten all of the required tokens, we just cache them to
     /// be used when the operation progresses.
     Token(HardwareAuthToken, Option<TimeStampToken>),
@@ -169,9 +176,15 @@
     const CLEANUP_PERIOD: u8 = 25;
 
     pub fn add_auth_token(&self, hat: HardwareAuthToken) {
-        let mut map = self.map_and_cleanup_counter.lock().unwrap();
-        let (ref mut map, _) = *map;
-        if let Some((_, recv)) = map.remove_entry(&hat.challenge) {
+        let recv = {
+            // Limit the scope of the mutex guard, so that it is not held while the auth token is
+            // added.
+            let mut map = self.map_and_cleanup_counter.lock().unwrap();
+            let (ref mut map, _) = *map;
+            map.remove_entry(&hat.challenge)
+        };
+
+        if let Some((_, recv)) = recv {
             recv.add_auth_token(hat);
         }
     }
@@ -191,7 +204,7 @@
 }
 
 #[derive(Debug)]
-struct TokenReceiver(Weak<Mutex<AuthRequest>>);
+struct TokenReceiver(Weak<AuthRequest>);
 
 impl TokenReceiver {
     fn is_obsolete(&self) -> bool {
@@ -200,8 +213,7 @@
 
     fn add_auth_token(&self, hat: HardwareAuthToken) {
         if let Some(state_arc) = self.0.upgrade() {
-            let mut state = state_arc.lock().unwrap();
-            state.add_auth_token(hat);
+            state_arc.add_auth_token(hat);
         }
     }
 }
@@ -326,8 +338,7 @@
     /// tokens into the DeferredAuthState::Token state for future use.
     fn get_auth_tokens(&mut self) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
         let deferred_tokens = if let DeferredAuthState::Waiting(ref auth_request) = self.state {
-            let mut state = auth_request.lock().unwrap();
-            Some(state.get_auth_tokens().context("In AuthInfo::get_auth_tokens.")?)
+            Some(auth_request.get_auth_tokens().context("In AuthInfo::get_auth_tokens.")?)
         } else {
             None
         };
diff --git a/keystore2/src/error.rs b/keystore2/src/error.rs
index 465dcfa..d1b2ffb 100644
--- a/keystore2/src/error.rs
+++ b/keystore2/src/error.rs
@@ -140,7 +140,7 @@
 /// This function should be used by Keystore service calls to translate error conditions
 /// into service specific exceptions.
 ///
-/// All error conditions get logged by this function.
+/// All error conditions get logged by this function, except for KEY_NOT_FOUND error.
 ///
 /// All `Error::Rc(x)` and `Error::Km(x)` variants get mapped onto a service specific error
 /// code of x. This is possible because KeyMint `ErrorCode` errors are always negative and
@@ -174,7 +174,13 @@
     map_err_with(
         result,
         |e| {
-            log::error!("{:?}", e);
+            // Make the key not found errors silent.
+            if !matches!(
+                e.root_cause().downcast_ref::<Error>(),
+                Some(Error::Rc(ResponseCode::KEY_NOT_FOUND))
+            ) {
+                log::error!("{:?}", e);
+            }
             e
         },
         handle_ok,
diff --git a/keystore2/src/keystore2_main.rs b/keystore2/src/keystore2_main.rs
index b95add2..4d4a718 100644
--- a/keystore2/src/keystore2_main.rs
+++ b/keystore2/src/keystore2_main.rs
@@ -17,6 +17,7 @@
 use keystore2::entropy;
 use keystore2::globals::ENFORCEMENTS;
 use keystore2::maintenance::Maintenance;
+use keystore2::metrics;
 use keystore2::remote_provisioning::RemoteProvisioningService;
 use keystore2::service::KeystoreService;
 use keystore2::{apc::ApcManager, shared_secret_negotiation};
@@ -135,6 +136,13 @@
         },
     );
 
+    std::thread::spawn(|| {
+        match metrics::register_pull_metrics_callbacks() {
+            Err(e) => error!("register_pull_metrics_callbacks failed: {:?}.", e),
+            _ => info!("Pull metrics callbacks successfully registered."),
+        };
+    });
+
     info!("Successfully registered Keystore 2.0 service.");
 
     info!("Joining thread pool now.");
diff --git a/keystore2/src/legacy_blob.rs b/keystore2/src/legacy_blob.rs
index a3e440b..e631356 100644
--- a/keystore2/src/legacy_blob.rs
+++ b/keystore2/src/legacy_blob.rs
@@ -686,10 +686,18 @@
         let user_id = uid_to_android_user(uid);
         path.push(format!("user_{}", user_id));
         let uid_str = uid.to_string();
-        let dir =
-            Self::with_retry_interrupted(|| fs::read_dir(path.as_path())).with_context(|| {
-                format!("In list_vpn_profiles: Failed to open legacy blob database. {:?}", path)
-            })?;
+        let dir = match Self::with_retry_interrupted(|| fs::read_dir(path.as_path())) {
+            Ok(dir) => dir,
+            Err(e) => match e.kind() {
+                ErrorKind::NotFound => return Ok(Default::default()),
+                _ => {
+                    return Err(e).context(format!(
+                        "In list_vpn_profiles: Failed to open legacy blob database. {:?}",
+                        path
+                    ))
+                }
+            },
+        };
         let mut result: Vec<String> = Vec::new();
         for entry in dir {
             let file_name =
@@ -1370,4 +1378,14 @@
 
         Ok(())
     }
+
+    #[test]
+    fn list_vpn_profiles_on_non_existing_user() -> Result<()> {
+        let temp_dir = TempDir::new("list_vpn_profiles_on_non_existing_user")?;
+        let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
+
+        assert!(legacy_blob_loader.list_vpn_profiles(20)?.is_empty());
+
+        Ok(())
+    }
 }
diff --git a/keystore2/src/legacy_migrator.rs b/keystore2/src/legacy_migrator.rs
index e5bcae4..5e0d573 100644
--- a/keystore2/src/legacy_migrator.rs
+++ b/keystore2/src/legacy_migrator.rs
@@ -420,7 +420,7 @@
             .context("In list_uid: Trying to list legacy entries.")
     }
 
-    /// This is a key migration request that can run in the migrator thread. This should
+    /// This is a key migration request that must run in the migrator thread. This must
     /// be passed to do_serialized.
     fn check_and_migrate(&mut self, uid: u32, mut key: KeyDescriptor) -> Result<()> {
         let alias = key.alias.clone().ok_or_else(|| {
diff --git a/keystore2/src/metrics.rs b/keystore2/src/metrics.rs
index c5dd582..5b66307 100644
--- a/keystore2/src/metrics.rs
+++ b/keystore2/src/metrics.rs
@@ -13,7 +13,9 @@
 // limitations under the License.
 
 //! This module provides convenience functions for keystore2 logging.
+use crate::async_task::AsyncTask;
 use crate::error::get_error_code;
+use crate::globals::DB;
 use crate::key_parameter::KeyParameterValue as KsKeyParamValue;
 use crate::operation::Outcome;
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
@@ -22,15 +24,28 @@
     KeyParameter::KeyParameter, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
     SecurityLevel::SecurityLevel,
 };
-use statslog_rust::keystore2_key_creation_event_reported::{
-    Algorithm as StatsdAlgorithm, EcCurve as StatsdEcCurve, KeyOrigin as StatsdKeyOrigin,
-    Keystore2KeyCreationEventReported, SecurityLevel as StatsdKeyCreationSecurityLevel,
-    UserAuthType as StatsdUserAuthType,
+use anyhow::Result;
+use keystore2_system_property::PropertyWatcher;
+use lazy_static::lazy_static;
+use statslog_rust::{
+    keystore2_key_creation_event_reported::{
+        Algorithm as StatsdAlgorithm, EcCurve as StatsdEcCurve, KeyOrigin as StatsdKeyOrigin,
+        Keystore2KeyCreationEventReported, SecurityLevel as StatsdKeyCreationSecurityLevel,
+        UserAuthType as StatsdUserAuthType,
+    },
+    keystore2_key_operation_event_reported::{
+        Keystore2KeyOperationEventReported, Outcome as StatsdOutcome, Purpose as StatsdKeyPurpose,
+        SecurityLevel as StatsdKeyOperationSecurityLevel,
+    },
+    keystore2_storage_stats::StorageType as StatsdStorageType,
 };
-use statslog_rust::keystore2_key_operation_event_reported::{
-    Keystore2KeyOperationEventReported, Outcome as StatsdOutcome, Purpose as StatsdKeyPurpose,
-    SecurityLevel as StatsdKeyOperationSecurityLevel,
-};
+use statslog_rust_header::Atoms;
+use statspull_rust::{set_pull_atom_callback, StatsPullResult};
+
+lazy_static! {
+    /// Background thread which handles logging via statsd
+    static ref STATSD_LOGS_HANDLER: AsyncTask = Default::default();
+}
 
 fn create_default_key_creation_atom() -> Keystore2KeyCreationEventReported {
     // If a value is not present, fields represented by bitmaps and i32 fields
@@ -75,19 +90,18 @@
 pub fn log_key_creation_event_stats<U>(
     sec_level: SecurityLevel,
     key_params: &[KeyParameter],
-    result: &anyhow::Result<U>,
+    result: &Result<U>,
 ) {
     let key_creation_event_stats =
         construct_key_creation_event_stats(sec_level, key_params, result);
 
-    let logging_result = key_creation_event_stats.stats_write();
+    STATSD_LOGS_HANDLER.queue_lo(move |_| {
+        let logging_result = key_creation_event_stats.stats_write();
 
-    if let Err(e) = logging_result {
-        log::error!(
-            "In log_key_creation_event_stats. Error in logging key creation event. {:?}",
-            e
-        );
-    }
+        if let Err(e) = logging_result {
+            log::error!("Error in logging key creation event in the async task. {:?}", e);
+        }
+    });
 }
 
 /// Log key operation events via statsd API.
@@ -106,20 +120,19 @@
         key_upgraded,
     );
 
-    let logging_result = key_operation_event_stats.stats_write();
+    STATSD_LOGS_HANDLER.queue_lo(move |_| {
+        let logging_result = key_operation_event_stats.stats_write();
 
-    if let Err(e) = logging_result {
-        log::error!(
-            "In log_key_operation_event_stats. Error in logging key operation event. {:?}",
-            e
-        );
-    }
+        if let Err(e) = logging_result {
+            log::error!("Error in logging key operation event in the async task. {:?}", e);
+        }
+    });
 }
 
 fn construct_key_creation_event_stats<U>(
     sec_level: SecurityLevel,
     key_params: &[KeyParameter],
-    result: &anyhow::Result<U>,
+    result: &Result<U>,
 ) -> Keystore2KeyCreationEventReported {
     let mut key_creation_event_atom = create_default_key_creation_atom();
 
@@ -375,6 +388,55 @@
     }
     bitmap
 }
+
+/// Registers pull metrics callbacks
+pub fn register_pull_metrics_callbacks() -> Result<()> {
+    // Before registering the callbacks with statsd, we have to wait for the system to finish
+    // booting up. This avoids possible races that may occur at startup. For example, statsd
+    // depends on a companion service, and if registration happens too soon it will fail since
+    // the companion service isn't up yet.
+    let mut watcher = PropertyWatcher::new("sys.boot_completed")?;
+    loop {
+        watcher.wait()?;
+        let value = watcher.read(|_name, value| Ok(value.trim().to_string()));
+        if value? == "1" {
+            set_pull_atom_callback(Atoms::Keystore2StorageStats, None, pull_metrics_callback);
+            break;
+        }
+    }
+    Ok(())
+}
+
+fn pull_metrics_callback() -> StatsPullResult {
+    let mut result = StatsPullResult::new();
+    let mut append = |stat| {
+        match stat {
+            Ok(s) => result.push(Box::new(s)),
+            Err(error) => {
+                log::error!("pull_metrics_callback: Error getting storage stat: {}", error)
+            }
+        };
+    };
+    DB.with(|db| {
+        let mut db = db.borrow_mut();
+        append(db.get_storage_stat(StatsdStorageType::Database));
+        append(db.get_storage_stat(StatsdStorageType::KeyEntry));
+        append(db.get_storage_stat(StatsdStorageType::KeyEntryIdIndex));
+        append(db.get_storage_stat(StatsdStorageType::KeyEntryDomainNamespaceIndex));
+        append(db.get_storage_stat(StatsdStorageType::BlobEntry));
+        append(db.get_storage_stat(StatsdStorageType::BlobEntryKeyEntryIdIndex));
+        append(db.get_storage_stat(StatsdStorageType::KeyParameter));
+        append(db.get_storage_stat(StatsdStorageType::KeyParameterKeyEntryIdIndex));
+        append(db.get_storage_stat(StatsdStorageType::KeyMetadata));
+        append(db.get_storage_stat(StatsdStorageType::KeyMetadataKeyEntryIdIndex));
+        append(db.get_storage_stat(StatsdStorageType::Grant));
+        append(db.get_storage_stat(StatsdStorageType::AuthToken));
+        append(db.get_storage_stat(StatsdStorageType::BlobMetadata));
+        append(db.get_storage_stat(StatsdStorageType::BlobMetadataBlobEntryIdIndex));
+    });
+    result
+}
+
 /// 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)]
diff --git a/keystore2/src/vintf/Android.bp b/keystore2/src/vintf/Android.bp
index feec8ae..3ab0ec5 100644
--- a/keystore2/src/vintf/Android.bp
+++ b/keystore2/src/vintf/Android.bp
@@ -53,11 +53,11 @@
     shared_libs: ["libvintf"],
     bindgen_flags: [
         "--size_t-is-usize",
-        "--whitelist-function", "getHalNames",
-        "--whitelist-function", "getHalNamesAndVersions",
-        "--whitelist-function", "getHidlInstances",
-        "--whitelist-function", "getAidlInstances",
-        "--whitelist-function", "freeNames",
+        "--allowlist-function", "getHalNames",
+        "--allowlist-function", "getHalNamesAndVersions",
+        "--allowlist-function", "getHidlInstances",
+        "--allowlist-function", "getAidlInstances",
+        "--allowlist-function", "freeNames",
     ],
 }
 
diff --git a/keystore2/system_property/Android.bp b/keystore2/system_property/Android.bp
index 5a13c90..9e7b056 100644
--- a/keystore2/system_property/Android.bp
+++ b/keystore2/system_property/Android.bp
@@ -29,9 +29,9 @@
 
     bindgen_flags: [
         "--size_t-is-usize",
-        "--whitelist-function=__system_property_find",
-        "--whitelist-function=__system_property_read_callback",
-        "--whitelist-function=__system_property_wait",
+        "--allowlist-function=__system_property_find",
+        "--allowlist-function=__system_property_read_callback",
+        "--allowlist-function=__system_property_wait",
     ],
 }
 
diff --git a/keystore2/system_property/lib.rs b/keystore2/system_property/lib.rs
index f14cf0e..be13c88 100644
--- a/keystore2/system_property/lib.rs
+++ b/keystore2/system_property/lib.rs
@@ -15,8 +15,9 @@
 //! This crate provides the PropertyWatcher type, which watches for changes
 //! in Android system properties.
 
+use keystore2_system_property_bindgen::prop_info as PropInfo;
 use std::os::raw::c_char;
-use std::ptr::null_mut;
+use std::ptr::null;
 use std::{
     ffi::{c_void, CStr, CString},
     str::Utf8Error,
@@ -56,27 +57,34 @@
 /// as `keystore.boot_level`; it can report the current value of this
 /// property, or wait for it to change.
 pub struct PropertyWatcher {
-    prop_info: *const keystore2_system_property_bindgen::prop_info,
+    prop_name: CString,
+    prop_info: *const PropInfo,
     serial: keystore2_system_property_bindgen::__uint32_t,
 }
 
 impl PropertyWatcher {
     /// Create a PropertyWatcher for the named system property.
     pub fn new(name: &str) -> Result<Self> {
-        let cstr = CString::new(name)?;
-        // Unsafe FFI call. We generate the CStr in this function
-        // and so ensure it is valid during call.
-        // Returned pointer is valid for the lifetime of the program.
-        let prop_info =
-            unsafe { keystore2_system_property_bindgen::__system_property_find(cstr.as_ptr()) };
-        if prop_info.is_null() {
-            Err(PropertyWatcherError::SystemPropertyAbsent)
+        Ok(Self { prop_name: CString::new(name)?, prop_info: null(), serial: 0 })
+    }
+
+    // Lazy-initializing accessor for self.prop_info.
+    fn get_prop_info(&mut self) -> Option<*const PropInfo> {
+        if self.prop_info.is_null() {
+            // Unsafe required for FFI call. Input and output are both const.
+            // The returned pointer is valid for the lifetime of the program.
+            self.prop_info = unsafe {
+                keystore2_system_property_bindgen::__system_property_find(self.prop_name.as_ptr())
+            };
+        }
+        if self.prop_info.is_null() {
+            None
         } else {
-            Ok(Self { prop_info, serial: 0 })
+            Some(self.prop_info)
         }
     }
 
-    fn read_raw(&self, mut f: impl FnOnce(Option<&CStr>, Option<&CStr>)) {
+    fn read_raw(prop_info: *const PropInfo, mut f: impl FnOnce(Option<&CStr>, Option<&CStr>)) {
         // Unsafe function converts values passed to us by
         // __system_property_read_callback to Rust form
         // and pass them to inner callback.
@@ -98,7 +106,7 @@
         // to a void pointer, and unwrap it in our callback.
         unsafe {
             keystore2_system_property_bindgen::__system_property_read_callback(
-                self.prop_info,
+                prop_info,
                 Some(callback),
                 &mut f as *mut _ as *mut c_void,
             )
@@ -108,12 +116,14 @@
     /// Call the passed function, passing it the name and current value
     /// of this system property. See documentation for
     /// `__system_property_read_callback` for details.
-    pub fn read<T, F>(&self, f: F) -> Result<T>
+    /// Returns an error if the property is empty or doesn't exist.
+    pub fn read<T, F>(&mut self, f: F) -> Result<T>
     where
         F: FnOnce(&str, &str) -> anyhow::Result<T>,
     {
+        let prop_info = self.get_prop_info().ok_or(PropertyWatcherError::SystemPropertyAbsent)?;
         let mut result = Err(PropertyWatcherError::ReadCallbackNotCalled);
-        self.read_raw(|name, value| {
+        Self::read_raw(prop_info, |name, value| {
             // use a wrapping closure as an erzatz try block.
             result = (|| {
                 let name = name.ok_or(PropertyWatcherError::MissingCString)?.to_str()?;
@@ -124,10 +134,43 @@
         result
     }
 
+    // Waits for the property that self is watching to be created. Returns immediately if the
+    // property already exists.
+    fn wait_for_property_creation(&mut self) -> Result<()> {
+        let mut global_serial = 0;
+        loop {
+            match self.get_prop_info() {
+                Some(_) => return Ok(()),
+                None => {
+                    // Unsafe call for FFI. The function modifies only global_serial, and has
+                    // no side-effects.
+                    if !unsafe {
+                        // Wait for a global serial number change, then try again. On success,
+                        // the function will update global_serial with the last version seen.
+                        keystore2_system_property_bindgen::__system_property_wait(
+                            null(),
+                            global_serial,
+                            &mut global_serial,
+                            null(),
+                        )
+                    } {
+                        return Err(PropertyWatcherError::WaitFailed);
+                    }
+                }
+            }
+        }
+    }
+
     /// Wait for the system property to change. This
     /// records the serial number of the last change, so
     /// race conditions are avoided.
     pub fn wait(&mut self) -> Result<()> {
+        // If the property is null, then wait for it to be created. Subsequent waits will
+        // skip this step and wait for our specific property to change.
+        if self.prop_info.is_null() {
+            return self.wait_for_property_creation();
+        }
+
         let mut new_serial = self.serial;
         // Unsafe block to call __system_property_wait.
         // All arguments are private to PropertyWatcher so we
@@ -137,7 +180,7 @@
                 self.prop_info,
                 self.serial,
                 &mut new_serial,
-                null_mut(),
+                null(),
             )
         } {
             return Err(PropertyWatcherError::WaitFailed);
diff --git a/keystore2/vpnprofilestore/lib.rs b/keystore2/vpnprofilestore/lib.rs
index e7340a0..d92e045 100644
--- a/keystore2/vpnprofilestore/lib.rs
+++ b/keystore2/vpnprofilestore/lib.rs
@@ -175,7 +175,7 @@
 /// This function should be used by vpnprofilestore service calls to translate error conditions
 /// into service specific exceptions.
 ///
-/// All error conditions get logged by this function.
+/// All error conditions get logged by this function, except for ERROR_PROFILE_NOT_FOUND error.
 ///
 /// `Error::Error(x)` variants get mapped onto a service specific error code of `x`.
 ///
@@ -190,12 +190,16 @@
 {
     result.map_or_else(
         |e| {
-            log::error!("{:#?}", e);
             let root_cause = e.root_cause();
-            let rc = match root_cause.downcast_ref::<Error>() {
-                Some(Error::Error(e)) => *e,
-                Some(Error::Binder(_, _)) | None => ERROR_SYSTEM_ERROR,
+            let (rc, log_error) = match root_cause.downcast_ref::<Error>() {
+                // Make the profile not found errors silent.
+                Some(Error::Error(ERROR_PROFILE_NOT_FOUND)) => (ERROR_PROFILE_NOT_FOUND, false),
+                Some(Error::Error(e)) => (*e, true),
+                Some(Error::Binder(_, _)) | None => (ERROR_SYSTEM_ERROR, true),
             };
+            if log_error {
+                log::error!("{:?}", e);
+            }
             Err(BinderStatus::new_service_specific_error(rc, None))
         },
         handle_ok,
diff --git a/ondevice-signing/KeystoreKey.cpp b/ondevice-signing/KeystoreKey.cpp
index 9b5e505..96e369a 100644
--- a/ondevice-signing/KeystoreKey.cpp
+++ b/ondevice-signing/KeystoreKey.cpp
@@ -151,8 +151,25 @@
     KeyEntryResponse keyEntryResponse;
     LOG(INFO) << "Trying to retrieve existing keystore key...";
     status = mService->getKeyEntry(descriptor, &keyEntryResponse);
-    if (!status.isOk()) {
-        LOG(INFO) << "Existing keystore key not found, creating new key";
+    bool keyValid = false;
+
+    if (status.isOk()) {
+        // Make sure this is an early boot key
+        for (const auto& auth : keyEntryResponse.metadata.authorizations) {
+            if (auth.keyParameter.tag == Tag::MAX_BOOT_LEVEL) {
+                if (auth.keyParameter.value.get<KeyParameterValue::integer>() == kOdsignBootLevel) {
+                    keyValid = true;
+                    break;
+                }
+            }
+        }
+        if (!keyValid) {
+            LOG(WARNING) << "Found invalid keystore key without MAX_BOOT_LEVEL tag";
+        }
+    }
+
+    if (!keyValid) {
+        LOG(INFO) << "Existing keystore key not found or invalid, creating new key";
         auto newKeyStatus = createNewKey(descriptor);
         if (!newKeyStatus.ok()) {
             LOG(ERROR) << "Failed to create new key";
diff --git a/provisioner/Android.bp b/provisioner/Android.bp
index d3f06fe..12a21d1 100644
--- a/provisioner/Android.bp
+++ b/provisioner/Android.bp
@@ -51,3 +51,19 @@
         "android.security.provisioner-java",
     ],
 }
+
+cc_binary {
+    name: "rkp_factory_extraction_tool",
+    srcs: ["rkp_factory_extraction_tool.cpp"],
+    shared_libs: [
+        "android.hardware.security.keymint-V1-ndk_platform",
+        "libbinder",
+        "libbinder_ndk",
+        "libcppbor_external",
+        "libcppcose_rkp",
+        "libcrypto",
+        "liblog",
+        "libvintf",
+    ],
+    //export_include_dirs: ["include"],
+}
diff --git a/provisioner/rkp_factory_extraction_tool.cpp b/provisioner/rkp_factory_extraction_tool.cpp
new file mode 100644
index 0000000..d4842b1
--- /dev/null
+++ b/provisioner/rkp_factory_extraction_tool.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <vector>
+
+#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
+#include <android/binder_manager.h>
+#include <cppbor.h>
+#include <keymaster/cppcose/cppcose.h>
+#include <log/log.h>
+#include <vintf/VintfObject.h>
+
+using std::set;
+using std::string;
+using std::vector;
+
+using aidl::android::hardware::security::keymint::DeviceInfo;
+using aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent;
+using aidl::android::hardware::security::keymint::MacedPublicKey;
+using aidl::android::hardware::security::keymint::ProtectedData;
+
+using android::vintf::HalManifest;
+using android::vintf::VintfObject;
+
+using namespace cppbor;
+using namespace cppcose;
+
+namespace {
+
+const string kPackage = "android.hardware.security.keymint";
+const string kInterface = "IRemotelyProvisionedComponent";
+const string kFormattedName = kPackage + "." + kInterface + "/";
+
+ErrMsgOr<vector<uint8_t>> generateEekChain(size_t length, const vector<uint8_t>& eekId) {
+    auto eekChain = cppbor::Array();
+
+    vector<uint8_t> prevPrivKey;
+    for (size_t i = 0; i < length - 1; ++i) {
+        vector<uint8_t> pubKey(ED25519_PUBLIC_KEY_LEN);
+        vector<uint8_t> privKey(ED25519_PRIVATE_KEY_LEN);
+
+        ED25519_keypair(pubKey.data(), privKey.data());
+
+        // The first signing key is self-signed.
+        if (prevPrivKey.empty()) prevPrivKey = privKey;
+
+        auto coseSign1 = constructCoseSign1(prevPrivKey,
+                                            cppbor::Map() /* payload CoseKey */
+                                                .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
+                                                .add(CoseKey::ALGORITHM, EDDSA)
+                                                .add(CoseKey::CURVE, ED25519)
+                                                .add(CoseKey::PUBKEY_X, pubKey)
+                                                .canonicalize()
+                                                .encode(),
+                                            {} /* AAD */);
+        if (!coseSign1) return coseSign1.moveMessage();
+        eekChain.add(coseSign1.moveValue());
+
+        prevPrivKey = privKey;
+    }
+
+    vector<uint8_t> pubKey(X25519_PUBLIC_VALUE_LEN);
+    vector<uint8_t> privKey(X25519_PRIVATE_KEY_LEN);
+    X25519_keypair(pubKey.data(), privKey.data());
+
+    auto coseSign1 = constructCoseSign1(prevPrivKey,
+                                        cppbor::Map() /* payload CoseKey */
+                                            .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
+                                            .add(CoseKey::KEY_ID, eekId)
+                                            .add(CoseKey::ALGORITHM, ECDH_ES_HKDF_256)
+                                            .add(CoseKey::CURVE, cppcose::X25519)
+                                            .add(CoseKey::PUBKEY_X, pubKey)
+                                            .canonicalize()
+                                            .encode(),
+                                        {} /* AAD */);
+    if (!coseSign1) return coseSign1.moveMessage();
+    eekChain.add(coseSign1.moveValue());
+
+    return eekChain.encode();
+}
+
+std::vector<uint8_t> getChallenge() {
+    return std::vector<uint8_t>(0);
+}
+
+std::vector<uint8_t> composeCertificateRequest(ProtectedData&& protectedData,
+                                               DeviceInfo&& deviceInfo) {
+    Array emptyMacedKeysToSign;
+    emptyMacedKeysToSign
+        .add(std::vector<uint8_t>(0))   // empty protected headers as bstr
+        .add(Map())                     // empty unprotected headers
+        .add(Null())                    // nil for the payload
+        .add(std::vector<uint8_t>(0));  // empty tag as bstr
+    Array certificateRequest;
+    certificateRequest.add(EncodedItem(std::move(deviceInfo.deviceInfo)))
+        .add(getChallenge())  // fake challenge
+        .add(EncodedItem(std::move(protectedData.protectedData)))
+        .add(std::move(emptyMacedKeysToSign));
+    return certificateRequest.encode();
+}
+
+int32_t errorMsg(string name) {
+    std::cerr << "Failed for rkp instance: " << name;
+    return -1;
+}
+
+}  // namespace
+
+int main() {
+    std::shared_ptr<const HalManifest> manifest = VintfObject::GetDeviceHalManifest();
+    set<string> rkpNames = manifest->getAidlInstances(kPackage, kInterface);
+    for (auto name : rkpNames) {
+        string fullName = kFormattedName + name;
+        if (!AServiceManager_isDeclared(fullName.c_str())) {
+            ALOGE("Could not find the following instance declared in the manifest: %s\n",
+                  fullName.c_str());
+            return errorMsg(name);
+        }
+        AIBinder* rkpAiBinder = AServiceManager_getService(fullName.c_str());
+        ::ndk::SpAIBinder rkp_binder(rkpAiBinder);
+        auto rkp_service = IRemotelyProvisionedComponent::fromBinder(rkp_binder);
+        std::vector<uint8_t> keysToSignMac;
+        std::vector<MacedPublicKey> emptyKeys;
+
+        // Replace this eek chain generation with the actual production GEEK
+        std::vector<uint8_t> eekId(10);  // replace with real KID later (EEK fingerprint)
+        auto eekOrErr = generateEekChain(3 /* chainlength */, eekId);
+        if (!eekOrErr) {
+            ALOGE("Failed to generate test EEK somehow: %s", eekOrErr.message().c_str());
+            return errorMsg(name);
+        }
+
+        std::vector<uint8_t> eek = eekOrErr.moveValue();
+        DeviceInfo deviceInfo;
+        ProtectedData protectedData;
+        if (rkp_service) {
+            ALOGE("extracting bundle");
+            ::ndk::ScopedAStatus status = rkp_service->generateCertificateRequest(
+                true /* testMode */, emptyKeys, eek, getChallenge(), &deviceInfo, &protectedData,
+                &keysToSignMac);
+            if (!status.isOk()) {
+                ALOGE("Bundle extraction failed. Error code: %d", status.getServiceSpecificError());
+                return errorMsg(name);
+            }
+            std::cout << "\n";
+            std::vector<uint8_t> certificateRequest =
+                composeCertificateRequest(std::move(protectedData), std::move(deviceInfo));
+            std::copy(certificateRequest.begin(), certificateRequest.end(),
+                      std::ostream_iterator<char>(std::cout));
+        }
+    }
+}