Keystore 2.0: Implement legacy blob support.

This CL implements on-demand migration of legacy key blobs into
the Keystore 2.0.

This CL has joined authorship by
hasinigt@google.com and jdanis@google.com

Test: keystore2_test
      CTS Test.
      And manual test with key upgrade app.
Change-Id: I0a1f266c12f06cc2e196692d759dedf48b4d347a
diff --git a/keystore2/src/authorization.rs b/keystore2/src/authorization.rs
index 3190541..02b19c4 100644
--- a/keystore2/src/authorization.rs
+++ b/keystore2/src/authorization.rs
@@ -16,7 +16,7 @@
 
 use crate::error::Error as KeystoreError;
 use crate::error::map_or_log_err;
-use crate::globals::{ENFORCEMENTS, SUPER_KEY, DB};
+use crate::globals::{ENFORCEMENTS, SUPER_KEY, DB, LEGACY_MIGRATOR};
 use crate::permission::KeystorePerm;
 use crate::super_key::UserState;
 use crate::utils::check_keystore_permission;
@@ -70,6 +70,7 @@
                     .with(|db| {
                         UserState::get_with_password_unlock(
                             &mut db.borrow_mut(),
+                            &LEGACY_MIGRATOR,
                             &SUPER_KEY,
                             user_id as u32,
                             user_password,
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index 9767d32..3217857 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -1128,7 +1128,7 @@
     /// Stores a super key in the database.
     pub fn store_super_key(
         &mut self,
-        user_id: i64,
+        user_id: u32,
         blob_info: &(&[u8], &BlobMetaData),
     ) -> Result<KeyEntry> {
         self.with_transaction(TransactionBehavior::Immediate, |tx| {
@@ -1141,7 +1141,7 @@
                         id,
                         KeyType::Super,
                         Domain::APP.0,
-                        user_id,
+                        user_id as i64,
                         Self::USER_SUPER_KEY_ALIAS,
                         KeyLifeCycle::Live,
                         &KEYSTORE_UUID,
@@ -1172,7 +1172,7 @@
         self.with_transaction(TransactionBehavior::Immediate, |tx| {
             let key_descriptor = KeyDescriptor {
                 domain: Domain::APP,
-                nspace: user_id as u64 as i64,
+                nspace: user_id as i64,
                 alias: Some(String::from("USER_SUPER_KEY")),
                 blob: None,
             };
@@ -2559,7 +2559,7 @@
                         }
                     }
                 }
-                notify_gc = Self::mark_unreferenced(&tx, key_id as u64 as i64)
+                notify_gc = Self::mark_unreferenced(&tx, key_id)
                     .context("In unbind_keys_for_user.")?
                     || notify_gc;
             }
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index 83d381d..8cc0106 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -18,6 +18,7 @@
 
 use crate::gc::Gc;
 use crate::legacy_blob::LegacyBlobLoader;
+use crate::legacy_migrator::LegacyMigrator;
 use crate::super_key::SuperKeyManager;
 use crate::utils::Asp;
 use crate::{async_task::AsyncTask, database::MonotonicRawTime};
@@ -49,7 +50,7 @@
 /// a gc. Although one GC is created for each thread local database connection, this closure
 /// is run only once, as long as the ASYNC_TASK instance is the same. So only one additional
 /// database connection is created for the garbage collector worker.
-fn create_thread_local_db() -> KeystoreDB {
+pub fn create_thread_local_db() -> KeystoreDB {
     let gc = Gc::new_init_with(ASYNC_TASK.clone(), || {
         (
             Box::new(|uuid, blob| {
@@ -144,8 +145,11 @@
     pub static ref ENFORCEMENTS: Enforcements = Enforcements::new();
     /// LegacyBlobLoader is initialized and exists globally.
     /// The same directory used by the database is used by the LegacyBlobLoader as well.
-    pub static ref LEGACY_BLOB_LOADER: LegacyBlobLoader = LegacyBlobLoader::new(
-        &DB_PATH.lock().expect("Could not get the database path for legacy blob loader."));
+    pub static ref LEGACY_BLOB_LOADER: Arc<LegacyBlobLoader> = Arc::new(LegacyBlobLoader::new(
+        &DB_PATH.lock().expect("Could not get the database path for legacy blob loader.")));
+    /// Legacy migrator. Atomically migrates legacy blobs to the database.
+    pub static ref LEGACY_MIGRATOR: Arc<LegacyMigrator> =
+        Arc::new(LegacyMigrator::new(ASYNC_TASK.clone()));
 }
 
 static KEYMINT_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
diff --git a/keystore2/src/legacy_blob.rs b/keystore2/src/legacy_blob.rs
index d4688ac..1981022 100644
--- a/keystore2/src/legacy_blob.rs
+++ b/keystore2/src/legacy_blob.rs
@@ -17,7 +17,6 @@
 //! This module implements methods to load legacy keystore key blob files.
 
 use crate::{
-    database::KeyMetaData,
     error::{Error as KsError, ResponseCode},
     key_parameter::{KeyParameter, KeyParameterValue},
     super_key::SuperKeyManager,
@@ -28,8 +27,11 @@
 };
 use anyhow::{Context, Result};
 use keystore2_crypto::{aes_gcm_decrypt, derive_key_from_password, ZVec};
-use std::io::{ErrorKind, Read};
 use std::{convert::TryInto, fs::File, path::Path, path::PathBuf};
+use std::{
+    fs,
+    io::{ErrorKind, Read, Result as IoResult},
+};
 
 const SUPPORTED_LEGACY_BLOB_VERSION: u8 = 3;
 
@@ -231,6 +233,7 @@
     pub fn new(path: &Path) -> Self {
         Self { path: path.to_owned() }
     }
+
     /// Encodes an alias string as ascii character sequence in the range
     /// ['+' .. '.'] and ['0' .. '~'].
     /// Bytes with values in the range ['0' .. '~'] are represented as they are.
@@ -587,7 +590,7 @@
         let sw_list = Self::read_key_parameters(&mut stream)
             .context("In read_characteristics_file.")?
             .into_iter()
-            .map(|value| KeyParameter::new(value, SecurityLevel::SOFTWARE));
+            .map(|value| KeyParameter::new(value, SecurityLevel::KEYSTORE));
 
         Ok(hw_list.into_iter().flatten().chain(sw_list).collect())
     }
@@ -600,7 +603,7 @@
     //            used this for user installed certificates without private key material.
 
     fn read_km_blob_file(&self, uid: u32, alias: &str) -> Result<Option<(Blob, String)>> {
-        let mut iter = ["USRPKEY", "USERSKEY"].iter();
+        let mut iter = ["USRPKEY", "USRSKEY"].iter();
 
         let (blob, prefix) = loop {
             if let Some(prefix) = iter.next() {
@@ -619,7 +622,7 @@
     }
 
     fn read_generic_blob(path: &Path) -> Result<Option<Blob>> {
-        let mut file = match File::open(path) {
+        let mut file = match Self::with_retry_interrupted(|| File::open(path)) {
             Ok(file) => file,
             Err(e) => match e.kind() {
                 ErrorKind::NotFound => return Ok(None),
@@ -633,47 +636,214 @@
     /// This function constructs the blob file name which has the form:
     /// user_<android user id>/<uid>_<alias>.
     fn make_blob_filename(&self, uid: u32, alias: &str, prefix: &str) -> PathBuf {
-        let mut path = self.path.clone();
         let user_id = uid_to_android_user(uid);
         let encoded_alias = Self::encode_alias(&format!("{}_{}", prefix, alias));
-        path.push(format!("user_{}", user_id));
+        let mut path = self.make_user_path_name(user_id);
         path.push(format!("{}_{}", uid, encoded_alias));
         path
     }
 
     /// This function constructs the characteristics file name which has the form:
-    /// user_<android user id>/.<uid>_chr_<alias>.
+    /// user_<android user id>/.<uid>_chr_<prefix>_<alias>.
     fn make_chr_filename(&self, uid: u32, alias: &str, prefix: &str) -> PathBuf {
-        let mut path = self.path.clone();
         let user_id = uid_to_android_user(uid);
         let encoded_alias = Self::encode_alias(&format!("{}_{}", prefix, alias));
-        path.push(format!("user_{}", user_id));
+        let mut path = self.make_user_path_name(user_id);
         path.push(format!(".{}_chr_{}", uid, encoded_alias));
         path
     }
 
-    fn load_by_uid_alias(
+    fn make_super_key_filename(&self, user_id: u32) -> PathBuf {
+        let mut path = self.make_user_path_name(user_id);
+        path.push(".masterkey");
+        path
+    }
+
+    fn make_user_path_name(&self, user_id: u32) -> PathBuf {
+        let mut path = self.path.clone();
+        path.push(&format!("user_{}", user_id));
+        path
+    }
+
+    /// Returns if the legacy blob database is empty, i.e., there are no entries matching "user_*"
+    /// in the database dir.
+    pub fn is_empty(&self) -> Result<bool> {
+        let dir = Self::with_retry_interrupted(|| fs::read_dir(self.path.as_path()))
+            .context("In is_empty: Failed to open legacy blob database.")?;
+        for entry in dir {
+            if (*entry.context("In is_empty: Trying to access dir entry")?.file_name())
+                .to_str()
+                .map_or(false, |f| f.starts_with("user_"))
+            {
+                return Ok(false);
+            }
+        }
+        Ok(true)
+    }
+
+    /// Returns if the legacy blob database is empty for a given user, i.e., there are no entries
+    /// matching "user_*" in the database dir.
+    pub fn is_empty_user(&self, user_id: u32) -> Result<bool> {
+        let mut user_path = self.path.clone();
+        user_path.push(format!("user_{}", user_id));
+        if !user_path.as_path().is_dir() {
+            return Ok(true);
+        }
+        Ok(Self::with_retry_interrupted(|| user_path.read_dir())
+            .context("In is_empty_user: Failed to open legacy user dir.")?
+            .next()
+            .is_none())
+    }
+
+    fn extract_alias(encoded_alias: &str) -> Option<String> {
+        // We can check the encoded alias because the prefixes we are interested
+        // in are all in the printable range that don't get mangled.
+        for prefix in &["USRPKEY_", "USRSKEY_", "USRCERT_", "CACERT_"] {
+            if let Some(alias) = encoded_alias.strip_prefix(prefix) {
+                return Self::decode_alias(&alias).ok();
+            }
+        }
+        None
+    }
+
+    /// List all entries for a given user. The strings are unchanged file names, i.e.,
+    /// encoded with UID prefix.
+    fn list_user(&self, user_id: u32) -> Result<Vec<String>> {
+        let path = self.make_user_path_name(user_id);
+        let dir =
+            Self::with_retry_interrupted(|| fs::read_dir(path.as_path())).with_context(|| {
+                format!("In list_user: Failed to open legacy blob database. {:?}", path)
+            })?;
+        let mut result: Vec<String> = Vec::new();
+        for entry in dir {
+            let file_name = entry.context("In list_user: Trying to access dir entry")?.file_name();
+            if let Some(f) = file_name.to_str() {
+                result.push(f.to_string())
+            }
+        }
+        Ok(result)
+    }
+
+    /// List all keystore entries belonging to the given uid.
+    pub fn list_keystore_entries_for_uid(&self, uid: u32) -> Result<Vec<String>> {
+        let user_id = uid_to_android_user(uid);
+
+        let user_entries = self
+            .list_user(user_id)
+            .context("In list_keystore_entries_for_uid: Trying to list user.")?;
+
+        let uid_str = format!("{}_", uid);
+
+        let mut result: Vec<String> = user_entries
+            .into_iter()
+            .filter_map(|v| {
+                if !v.starts_with(&uid_str) {
+                    return None;
+                }
+                let encoded_alias = &v[uid_str.len()..];
+                Self::extract_alias(encoded_alias)
+            })
+            .collect();
+
+        result.sort_unstable();
+        result.dedup();
+        Ok(result)
+    }
+
+    fn with_retry_interrupted<F, T>(f: F) -> IoResult<T>
+    where
+        F: Fn() -> IoResult<T>,
+    {
+        loop {
+            match f() {
+                Ok(v) => return Ok(v),
+                Err(e) => match e.kind() {
+                    ErrorKind::Interrupted => continue,
+                    _ => return Err(e),
+                },
+            }
+        }
+    }
+
+    /// Deletes a keystore entry. Also removes the user_<uid> directory on the
+    /// last migration.
+    pub fn remove_keystore_entry(&self, uid: u32, alias: &str) -> Result<bool> {
+        let mut something_was_deleted = false;
+        let prefixes = ["USRPKEY", "USRSKEY"];
+        for prefix in &prefixes {
+            let path = self.make_blob_filename(uid, alias, prefix);
+            if let Err(e) = Self::with_retry_interrupted(|| fs::remove_file(path.as_path())) {
+                match e.kind() {
+                    // Only a subset of keys are expected.
+                    ErrorKind::NotFound => continue,
+                    // Log error but ignore.
+                    _ => log::error!("Error while deleting key blob entries. {:?}", e),
+                }
+            }
+            let path = self.make_chr_filename(uid, alias, prefix);
+            if let Err(e) = Self::with_retry_interrupted(|| fs::remove_file(path.as_path())) {
+                match e.kind() {
+                    ErrorKind::NotFound => {
+                        log::info!("No characteristics file found for legacy key blob.")
+                    }
+                    // Log error but ignore.
+                    _ => log::error!("Error while deleting key blob entries. {:?}", e),
+                }
+            }
+            something_was_deleted = true;
+            // Only one of USRPKEY and USRSKEY can be present. So we can end the loop
+            // if we reach this point.
+            break;
+        }
+
+        let prefixes = ["USRCERT", "CACERT"];
+        for prefix in &prefixes {
+            let path = self.make_blob_filename(uid, alias, prefix);
+            if let Err(e) = Self::with_retry_interrupted(|| fs::remove_file(path.as_path())) {
+                match e.kind() {
+                    // USRCERT and CACERT are optional either or both may or may not be present.
+                    ErrorKind::NotFound => continue,
+                    // Log error but ignore.
+                    _ => log::error!("Error while deleting key blob entries. {:?}", e),
+                }
+                something_was_deleted = true;
+            }
+        }
+
+        if something_was_deleted {
+            let user_id = uid_to_android_user(uid);
+            if self
+                .is_empty_user(user_id)
+                .context("In remove_keystore_entry: Trying to check for empty user dir.")?
+            {
+                let user_path = self.make_user_path_name(user_id);
+                Self::with_retry_interrupted(|| fs::remove_dir(user_path.as_path())).ok();
+            }
+        }
+
+        Ok(something_was_deleted)
+    }
+
+    /// Load a legacy key blob entry by uid and alias.
+    pub fn load_by_uid_alias(
         &self,
         uid: u32,
         alias: &str,
-        key_manager: &SuperKeyManager,
-    ) -> Result<(Option<(Blob, Vec<KeyParameter>)>, Option<Vec<u8>>, Option<Vec<u8>>, KeyMetaData)>
-    {
-        let metadata = KeyMetaData::new();
-
+        key_manager: Option<&SuperKeyManager>,
+    ) -> Result<(Option<(Blob, Vec<KeyParameter>)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
         let km_blob = self.read_km_blob_file(uid, alias).context("In load_by_uid_alias.")?;
 
         let km_blob = match km_blob {
             Some((km_blob, prefix)) => {
-                let km_blob =
-                    match km_blob {
-                        Blob { flags: _, value: BlobValue::Decrypted(_) } => km_blob,
-                        // Unwrap the key blob if required.
-                        Blob { flags, value: BlobValue::Encrypted { iv, tag, data } } => {
+                let km_blob = match km_blob {
+                    Blob { flags: _, value: BlobValue::Decrypted(_) } => km_blob,
+                    // Unwrap the key blob if required and if we have key_manager.
+                    Blob { flags, value: BlobValue::Encrypted { ref iv, ref tag, ref data } } => {
+                        if let Some(key_manager) = key_manager {
                             let decrypted = match key_manager
                                 .get_per_boot_key_by_user_id(uid_to_android_user(uid))
                             {
-                                Some(key) => aes_gcm_decrypt(&data, &iv, &tag, &(key.get_key()))
+                                Some(key) => aes_gcm_decrypt(data, iv, tag, &(key.get_key()))
                                     .context(
                                     "In load_by_uid_alias: while trying to decrypt legacy blob.",
                                 )?,
@@ -688,11 +858,16 @@
                                 }
                             };
                             Blob { flags, value: BlobValue::Decrypted(decrypted) }
+                        } else {
+                            km_blob
                         }
-                        _ => return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED)).context(
+                    }
+                    _ => {
+                        return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED)).context(
                             "In load_by_uid_alias: Found wrong blob type in legacy key blob file.",
-                        ),
-                    };
+                        )
+                    }
+                };
 
                 let hw_sec_level = match km_blob.is_strongbox() {
                     true => SecurityLevel::STRONGBOX,
@@ -730,14 +905,17 @@
             }
         };
 
-        Ok((km_blob, user_cert, ca_cert, metadata))
+        Ok((km_blob, user_cert, ca_cert))
+    }
+
+    /// Returns true if the given user has a super key.
+    pub fn has_super_key(&self, user_id: u32) -> bool {
+        self.make_super_key_filename(user_id).is_file()
     }
 
     /// Load and decrypt legacy super key blob.
     pub fn load_super_key(&self, user_id: u32, pw: &[u8]) -> Result<Option<ZVec>> {
-        let mut path = self.path.clone();
-        path.push(&format!("user_{}", user_id));
-        path.push(".masterkey");
+        let path = self.make_super_key_filename(user_id);
         let blob = Self::read_generic_blob(&path)
             .context("In load_super_key: While loading super key.")?;
 
@@ -764,6 +942,18 @@
 
         Ok(blob)
     }
+
+    /// Removes the super key for the given user from the legacy database.
+    /// If this was the last entry in the user's database, this function removes
+    /// the user_<uid> directory as well.
+    pub fn remove_super_key(&self, user_id: u32) {
+        let path = self.make_super_key_filename(user_id);
+        Self::with_retry_interrupted(|| fs::remove_file(path.as_path())).ok();
+        if self.is_empty_user(user_id).ok().unwrap_or(false) {
+            let path = self.make_user_path_name(user_id);
+            Self::with_retry_interrupted(|| fs::remove_dir(path.as_path())).ok();
+        }
+    }
 }
 
 #[cfg(test)]
@@ -898,6 +1088,37 @@
     }
 
     #[test]
+    fn test_is_empty() {
+        let temp_dir = TempDir::new("test_is_empty").expect("Failed to create temp dir.");
+        let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
+
+        assert!(legacy_blob_loader.is_empty().expect("Should succeed and be empty."));
+
+        let _db = crate::database::KeystoreDB::new(temp_dir.path(), None)
+            .expect("Failed to open database.");
+
+        assert!(legacy_blob_loader.is_empty().expect("Should succeed and still be empty."));
+
+        std::fs::create_dir(&*temp_dir.build().push("user_0")).expect("Failed to create user_0.");
+
+        assert!(!legacy_blob_loader.is_empty().expect("Should succeed but not be empty."));
+
+        std::fs::create_dir(&*temp_dir.build().push("user_10")).expect("Failed to create user_10.");
+
+        assert!(!legacy_blob_loader.is_empty().expect("Should succeed but still not be empty."));
+
+        std::fs::remove_dir_all(&*temp_dir.build().push("user_0"))
+            .expect("Failed to remove user_0.");
+
+        assert!(!legacy_blob_loader.is_empty().expect("Should succeed but still not be empty."));
+
+        std::fs::remove_dir_all(&*temp_dir.build().push("user_10"))
+            .expect("Failed to remove user_10.");
+
+        assert!(legacy_blob_loader.is_empty().expect("Should succeed and be empty again."));
+    }
+
+    #[test]
     fn test_legacy_blobs() -> anyhow::Result<()> {
         let temp_dir = TempDir::new("legacy_blob_test")?;
         std::fs::create_dir(&*temp_dir.build().push("user_0"))?;
@@ -944,7 +1165,7 @@
 
         assert_eq!(
             legacy_blob_loader
-                .load_by_uid_alias(10223, "authbound", &key_manager)
+                .load_by_uid_alias(10223, "authbound", Some(&key_manager))
                 .unwrap_err()
                 .root_cause()
                 .downcast_ref::<error::Error>(),
@@ -953,18 +1174,18 @@
 
         key_manager.unlock_user_key(&mut db, 0, PASSWORD, &legacy_blob_loader)?;
 
-        if let (Some((Blob { flags, value }, _params)), Some(cert), Some(chain), _kp) =
-            legacy_blob_loader.load_by_uid_alias(10223, "authbound", &key_manager)?
+        if let (Some((Blob { flags, value: _ }, _params)), Some(cert), Some(chain)) =
+            legacy_blob_loader.load_by_uid_alias(10223, "authbound", Some(&key_manager))?
         {
             assert_eq!(flags, 4);
-            assert_eq!(value, BlobValue::Decrypted(DECRYPTED_USRPKEY_AUTHBOUND.try_into()?));
+            //assert_eq!(value, BlobValue::Encrypted(..));
             assert_eq!(&cert[..], LOADED_CERT_AUTHBOUND);
             assert_eq!(&chain[..], LOADED_CACERT_AUTHBOUND);
         } else {
             panic!("");
         }
-        if let (Some((Blob { flags, value }, _params)), Some(cert), Some(chain), _kp) =
-            legacy_blob_loader.load_by_uid_alias(10223, "non_authbound", &key_manager)?
+        if let (Some((Blob { flags, value }, _params)), Some(cert), Some(chain)) =
+            legacy_blob_loader.load_by_uid_alias(10223, "non_authbound", Some(&key_manager))?
         {
             assert_eq!(flags, 0);
             assert_eq!(value, BlobValue::Decrypted(LOADED_USRPKEY_NON_AUTHBOUND.try_into()?));
@@ -974,6 +1195,33 @@
             panic!("");
         }
 
+        legacy_blob_loader.remove_keystore_entry(10223, "authbound").expect("This should succeed.");
+        legacy_blob_loader
+            .remove_keystore_entry(10223, "non_authbound")
+            .expect("This should succeed.");
+
+        assert_eq!(
+            (None, None, None),
+            legacy_blob_loader.load_by_uid_alias(10223, "authbound", Some(&key_manager))?
+        );
+        assert_eq!(
+            (None, None, None),
+            legacy_blob_loader.load_by_uid_alias(10223, "non_authbound", Some(&key_manager))?
+        );
+
+        // The database should not be empty due to the super key.
+        assert!(!legacy_blob_loader.is_empty()?);
+        assert!(!legacy_blob_loader.is_empty_user(0)?);
+
+        // The database should be considered empty for user 1.
+        assert!(legacy_blob_loader.is_empty_user(1)?);
+
+        legacy_blob_loader.remove_super_key(0);
+
+        // Now it should be empty.
+        assert!(legacy_blob_loader.is_empty_user(0)?);
+        assert!(legacy_blob_loader.is_empty()?);
+
         Ok(())
     }
 }
diff --git a/keystore2/src/legacy_migrator.rs b/keystore2/src/legacy_migrator.rs
new file mode 100644
index 0000000..60c6bca
--- /dev/null
+++ b/keystore2/src/legacy_migrator.rs
@@ -0,0 +1,570 @@
+// 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.
+
+//! This module acts as a bridge between the legacy key database and the keystore2 database.
+
+use crate::database::{
+    BlobMetaData, BlobMetaEntry, CertificateInfo, DateTime, EncryptedBy, KeyMetaData, KeyMetaEntry,
+    KeystoreDB, Uuid, KEYSTORE_UUID,
+};
+use crate::error::Error;
+use crate::legacy_blob::BlobValue;
+use crate::utils::uid_to_android_user;
+use crate::{async_task::AsyncTask, legacy_blob::LegacyBlobLoader};
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
+use android_system_keystore2::aidl::android::system::keystore2::{
+    Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
+};
+use anyhow::{Context, Result};
+use core::ops::Deref;
+use keystore2_crypto::ZVec;
+use std::collections::{HashMap, HashSet};
+use std::convert::TryInto;
+use std::sync::atomic::{AtomicU8, Ordering};
+use std::sync::mpsc::channel;
+use std::sync::{Arc, Mutex};
+
+/// Represents LegacyMigrator.
+pub struct LegacyMigrator {
+    async_task: Arc<AsyncTask>,
+    initializer: Mutex<
+        Option<
+            Box<
+                dyn FnOnce() -> (KeystoreDB, HashMap<SecurityLevel, Uuid>, Arc<LegacyBlobLoader>)
+                    + Send
+                    + 'static,
+            >,
+        >,
+    >,
+    /// This atomic is used for cheap interior mutability. It is intended to prevent
+    /// expensive calls into the legacy migrator when the legacy database is empty.
+    /// When transitioning from READY to EMPTY, spurious calls may occur for a brief period
+    /// of time. This is tolerable in favor of the common case.
+    state: AtomicU8,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+struct RecentMigration {
+    uid: u32,
+    alias: String,
+}
+
+impl RecentMigration {
+    fn new(uid: u32, alias: String) -> Self {
+        Self { uid, alias }
+    }
+}
+
+struct LegacyMigratorState {
+    recently_migrated: HashSet<RecentMigration>,
+    recently_migrated_super_key: HashSet<u32>,
+    legacy_loader: Arc<LegacyBlobLoader>,
+    sec_level_to_km_uuid: HashMap<SecurityLevel, Uuid>,
+    db: KeystoreDB,
+}
+
+impl LegacyMigrator {
+    const WIFI_NAMESPACE: i64 = 102;
+    const AID_WIFI: u32 = 1010;
+
+    const STATE_UNINITIALIZED: u8 = 0;
+    const STATE_READY: u8 = 1;
+    const STATE_EMPTY: u8 = 2;
+
+    /// Constructs a new LegacyMigrator using the given AsyncTask object as migration
+    /// worker.
+    pub fn new(async_task: Arc<AsyncTask>) -> Self {
+        Self {
+            async_task,
+            initializer: Default::default(),
+            state: AtomicU8::new(Self::STATE_UNINITIALIZED),
+        }
+    }
+
+    /// The legacy migrator must be initialized deferred, because keystore starts very early.
+    /// At this time the data partition may not be mounted. So we cannot open database connections
+    /// until we get actual key load requests. This sets the function that the legacy loader
+    /// uses to connect to the database.
+    pub fn set_init<F>(&self, f_init: F) -> Result<()>
+    where
+        F: FnOnce() -> (KeystoreDB, HashMap<SecurityLevel, Uuid>, Arc<LegacyBlobLoader>)
+            + Send
+            + 'static,
+    {
+        let mut initializer = self.initializer.lock().expect("Failed to lock initializer.");
+
+        // If we are not uninitialized we have no business setting the initializer.
+        if self.state.load(Ordering::Relaxed) != Self::STATE_UNINITIALIZED {
+            return Ok(());
+        }
+
+        // Only set the initializer if it hasn't been set before.
+        if initializer.is_none() {
+            *initializer = Some(Box::new(f_init))
+        }
+
+        Ok(())
+    }
+
+    /// This function is called by the migration requestor to check if it is worth
+    /// making a migration request. It also transitions the state from UNINITIALIZED
+    /// to READY or EMPTY on first use. The deferred initialization is necessary, because
+    /// Keystore 2.0 runs early during boot, where data may not yet be mounted.
+    /// Returns Ok(STATE_READY) if a migration request is worth undertaking and
+    /// Ok(STATE_EMPTY) if the database is empty. An error is returned if the loader
+    /// was not initialized and cannot be initialized.
+    fn check_state(&self) -> Result<u8> {
+        let mut first_try = true;
+        loop {
+            match (self.state.load(Ordering::Relaxed), first_try) {
+                (Self::STATE_EMPTY, _) => {
+                    return Ok(Self::STATE_EMPTY);
+                }
+                (Self::STATE_UNINITIALIZED, true) => {
+                    // If we find the legacy loader uninitialized, we grab the initializer lock,
+                    // check if the legacy database is empty, and if not, schedule an initialization
+                    // request. Coming out of the initializer lock, the state is either EMPTY or
+                    // READY.
+                    let mut initializer = self.initializer.lock().unwrap();
+
+                    if let Some(initializer) = initializer.take() {
+                        let (db, sec_level_to_km_uuid, legacy_loader) = (initializer)();
+
+                        if legacy_loader.is_empty().context(
+                            "In check_state: Trying to check if the legacy database is empty.",
+                        )? {
+                            self.state.store(Self::STATE_EMPTY, Ordering::Relaxed);
+                            return Ok(Self::STATE_EMPTY);
+                        }
+
+                        self.async_task.queue_hi(move |shelf| {
+                            shelf.get_or_put_with(|| LegacyMigratorState {
+                                recently_migrated: Default::default(),
+                                recently_migrated_super_key: Default::default(),
+                                legacy_loader,
+                                sec_level_to_km_uuid,
+                                db,
+                            });
+                        });
+
+                        // It is safe to set this here even though the async task may not yet have
+                        // run because any thread observing this will not be able to schedule a
+                        // task that can run before the initialization.
+                        // Also we can only transition out of this state while having the
+                        // initializer lock and having found an initializer.
+                        self.state.store(Self::STATE_READY, Ordering::Relaxed);
+                        return Ok(Self::STATE_READY);
+                    } else {
+                        // There is a chance that we just lost the race from state.load() to
+                        // grabbing the initializer mutex. If that is the case the state must
+                        // be EMPTY or READY after coming out of the lock. So we can give it
+                        // one more try.
+                        first_try = false;
+                        continue;
+                    }
+                }
+                (Self::STATE_UNINITIALIZED, false) => {
+                    // Okay, tough luck. The legacy loader was really completely uninitialized.
+                    return Err(Error::sys()).context(
+                        "In check_state: Legacy loader should not be called uninitialized.",
+                    );
+                }
+                (Self::STATE_READY, _) => return Ok(Self::STATE_READY),
+                (s, _) => panic!("Unknown legacy migrator state. {} ", s),
+            }
+        }
+    }
+
+    /// List all aliases for uid in the legacy database.
+    pub fn list_uid(&self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
+        let uid = match (domain, namespace) {
+            (Domain::APP, namespace) => namespace as u32,
+            (Domain::SELINUX, Self::WIFI_NAMESPACE) => Self::AID_WIFI,
+            _ => return Ok(Vec::new()),
+        };
+        self.do_serialized(move |state| state.list_uid(uid)).unwrap_or_else(|| Ok(Vec::new())).map(
+            |v| {
+                v.into_iter()
+                    .map(|alias| KeyDescriptor {
+                        domain,
+                        nspace: namespace,
+                        alias: Some(alias),
+                        blob: None,
+                    })
+                    .collect()
+            },
+        )
+    }
+
+    /// Sends the given closure to the migrator thread for execution after calling check_state.
+    /// Returns None if the database was empty and the request was not executed.
+    /// Otherwise returns Some with the result produced by the migration request.
+    /// The loader state may transition to STATE_EMPTY during the execution of this function.
+    fn do_serialized<F, T: Send + 'static>(&self, f: F) -> Option<Result<T>>
+    where
+        F: FnOnce(&mut LegacyMigratorState) -> Result<T> + Send + 'static,
+    {
+        // Short circuit if the database is empty or not initialized (error case).
+        match self.check_state().context("In do_serialized: Checking state.") {
+            Ok(LegacyMigrator::STATE_EMPTY) => return None,
+            Ok(LegacyMigrator::STATE_READY) => {}
+            Err(e) => return Some(Err(e)),
+            Ok(s) => panic!("Unknown legacy migrator state. {} ", s),
+        }
+
+        // We have established that there may be a key in the legacy database.
+        // Now we schedule a migration request.
+        let (sender, receiver) = channel();
+        self.async_task.queue_hi(move |shelf| {
+            // Get the migrator state from the shelf.
+            // There may not be a state. This can happen if this migration request was scheduled
+            // before a previous request established that the legacy database was empty
+            // and removed the state from the shelf. Since we know now that the database
+            // is empty, we can return None here.
+            let (new_state, result) = if let Some(legacy_migrator_state) =
+                shelf.get_downcast_mut::<LegacyMigratorState>()
+            {
+                let result = f(legacy_migrator_state);
+                (legacy_migrator_state.check_empty(), Some(result))
+            } else {
+                (Self::STATE_EMPTY, None)
+            };
+
+            // If the migration request determined that the database is now empty, we discard
+            // the state from the shelf to free up the resources we won't need any longer.
+            if result.is_some() && new_state == Self::STATE_EMPTY {
+                shelf.remove_downcast_ref::<LegacyMigratorState>();
+            }
+
+            // Send the result to the requester.
+            if let Err(e) = sender.send((new_state, result)) {
+                log::error!("In do_serialized. Error in sending the result. {:?}", e);
+            }
+        });
+
+        let (new_state, result) = match receiver.recv() {
+            Err(e) => {
+                return Some(Err(e).context("In do_serialized. Failed to receive from the sender."))
+            }
+            Ok(r) => r,
+        };
+
+        // We can only transition to EMPTY but never back.
+        // The migrator never creates any legacy blobs.
+        if new_state == Self::STATE_EMPTY {
+            self.state.store(Self::STATE_EMPTY, Ordering::Relaxed)
+        }
+
+        result
+    }
+
+    /// Runs the key_accessor function and returns its result. If it returns an error and the
+    /// root cause was KEY_NOT_FOUND, tries to migrate a key with the given parameters from
+    /// the legacy database to the new database and runs the key_accessor function again if
+    /// the migration request was successful.
+    pub fn with_try_migrate<F, T>(
+        &self,
+        key: &KeyDescriptor,
+        caller_uid: u32,
+        key_accessor: F,
+    ) -> Result<T>
+    where
+        F: Fn() -> Result<T>,
+    {
+        // Access the key and return on success.
+        match key_accessor() {
+            Ok(result) => return Ok(result),
+            Err(e) => match e.root_cause().downcast_ref::<Error>() {
+                Some(&Error::Rc(ResponseCode::KEY_NOT_FOUND)) => {}
+                _ => return Err(e),
+            },
+        }
+
+        // Filter inputs. We can only load legacy app domain keys and some special rules due
+        // to which we migrate keys transparently to an SELINUX domain.
+        let uid = match key {
+            KeyDescriptor { domain: Domain::APP, alias: Some(_), .. } => caller_uid,
+            KeyDescriptor { domain: Domain::SELINUX, nspace, alias: Some(_), .. } => {
+                match *nspace {
+                    Self::WIFI_NAMESPACE => Self::AID_WIFI,
+                    _ => {
+                        return Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
+                            .context(format!("No legacy keys for namespace {}", nspace))
+                    }
+                }
+            }
+            _ => {
+                return Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
+                    .context("No legacy keys for key descriptor.")
+            }
+        };
+
+        let key_clone = key.clone();
+        let result = self
+            .do_serialized(move |migrator_state| migrator_state.check_and_migrate(uid, key_clone));
+
+        if let Some(result) = result {
+            result?;
+            // After successful migration try again.
+            key_accessor()
+        } else {
+            Err(Error::Rc(ResponseCode::KEY_NOT_FOUND)).context("Legacy database is empty.")
+        }
+    }
+
+    /// Calls key_accessor and returns the result on success. In the case of a KEY_NOT_FOUND error
+    /// this function makes a migration request and on success retries the key_accessor.
+    pub fn with_try_migrate_super_key<F, T>(
+        &self,
+        user_id: u32,
+        pw: &[u8],
+        mut key_accessor: F,
+    ) -> Result<Option<T>>
+    where
+        F: FnMut() -> Result<Option<T>>,
+    {
+        match key_accessor() {
+            Ok(Some(result)) => return Ok(Some(result)),
+            Ok(None) => {}
+            Err(e) => return Err(e),
+        }
+
+        let pw: ZVec = pw
+            .try_into()
+            .context("In with_try_migrate_super_key: copying the password into a zvec.")?;
+        let result = self.do_serialized(move |migrator_state| {
+            migrator_state.check_and_migrate_super_key(user_id, pw)
+        });
+
+        if let Some(result) = result {
+            result?;
+            // After successful migration try again.
+            key_accessor()
+        } else {
+            Ok(None)
+        }
+    }
+
+    /// Queries the legacy database for the presence of a super key for the given user.
+    pub fn has_super_key(&self, user_id: u32) -> Result<bool> {
+        let result =
+            self.do_serialized(move |migrator_state| migrator_state.has_super_key(user_id));
+        result.unwrap_or(Ok(false))
+    }
+}
+
+impl LegacyMigratorState {
+    fn get_km_uuid(&self, is_strongbox: bool) -> Result<Uuid> {
+        let sec_level = if is_strongbox {
+            SecurityLevel::STRONGBOX
+        } else {
+            SecurityLevel::TRUSTED_ENVIRONMENT
+        };
+
+        self.sec_level_to_km_uuid.get(&sec_level).copied().ok_or_else(|| {
+            anyhow::anyhow!(Error::sys()).context("In get_km_uuid: No KM instance for blob.")
+        })
+    }
+
+    fn list_uid(&mut self, uid: u32) -> Result<Vec<String>> {
+        self.legacy_loader
+            .list_keystore_entries_for_uid(uid)
+            .context("In list_uid: Trying to list legacy entries.")
+    }
+
+    /// This is a key migration request that can run in the migrator thread. This should
+    /// 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(|| {
+            anyhow::anyhow!(Error::sys()).context(concat!(
+                "In check_and_migrate: Must be Some because ",
+                "our caller must not have called us otherwise."
+            ))
+        })?;
+
+        if self.recently_migrated.contains(&RecentMigration::new(uid, alias.clone())) {
+            return Ok(());
+        }
+
+        if key.domain == Domain::APP {
+            key.nspace = uid as i64;
+        }
+
+        // If the key is not found in the cache, try to load from the legacy database.
+        let (km_blob_params, user_cert, ca_cert) = self
+            .legacy_loader
+            .load_by_uid_alias(uid, &alias, None)
+            .context("In check_and_migrate: Trying to load legacy blob.")?;
+        let result = match km_blob_params {
+            Some((km_blob, params)) => {
+                let is_strongbox = km_blob.is_strongbox();
+                let (blob, mut blob_metadata) = match km_blob.take_value() {
+                    BlobValue::Encrypted { iv, tag, data } => {
+                        // Get super key id for user id.
+                        let user_id = uid_to_android_user(uid as u32);
+
+                        let super_key_id = match self
+                            .db
+                            .load_super_key(user_id)
+                            .context("In check_and_migrate: Failed to load super key")?
+                        {
+                            Some((_, entry)) => entry.id(),
+                            None => {
+                                // This might be the first time we access the super key,
+                                // and it may not have been migrated. We cannot import
+                                // the legacy super_key key now, because we need to reencrypt
+                                // it which we cannot do if we are not unlocked, which we are
+                                // not because otherwise the key would have been migrated.
+                                // We can check though if the key exists. If it does,
+                                // we can return Locked. Otherwise, we can delete the
+                                // key and return NotFound, because the key will never
+                                // be unlocked again.
+                                if self.legacy_loader.has_super_key(user_id) {
+                                    return Err(Error::Rc(ResponseCode::LOCKED)).context(concat!(
+                                        "In check_and_migrate: Cannot migrate super key of this ",
+                                        "key while user is locked."
+                                    ));
+                                } else {
+                                    self.legacy_loader.remove_keystore_entry(uid, &alias).context(
+                                        concat!(
+                                            "In check_and_migrate: ",
+                                            "Trying to remove obsolete key."
+                                        ),
+                                    )?;
+                                    return Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
+                                        .context("In check_and_migrate: Obsolete key.");
+                                }
+                            }
+                        };
+
+                        let mut blob_metadata = BlobMetaData::new();
+                        blob_metadata.add(BlobMetaEntry::Iv(iv.to_vec()));
+                        blob_metadata.add(BlobMetaEntry::AeadTag(tag.to_vec()));
+                        blob_metadata
+                            .add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(super_key_id)));
+                        (LegacyBlob::Vec(data), blob_metadata)
+                    }
+                    BlobValue::Decrypted(data) => (LegacyBlob::ZVec(data), BlobMetaData::new()),
+                    _ => {
+                        return Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
+                            .context("In check_and_migrate: Legacy key has unexpected type.")
+                    }
+                };
+
+                let km_uuid = self
+                    .get_km_uuid(is_strongbox)
+                    .context("In check_and_migrate: Trying to get KM UUID")?;
+                blob_metadata.add(BlobMetaEntry::KmUuid(km_uuid));
+
+                let mut metadata = KeyMetaData::new();
+                let creation_date = DateTime::now()
+                    .context("In check_and_migrate: Trying to make creation time.")?;
+                metadata.add(KeyMetaEntry::CreationDate(creation_date));
+
+                // Store legacy key in the database.
+                self.db
+                    .store_new_key(
+                        &key,
+                        &params,
+                        &(&blob, &blob_metadata),
+                        &CertificateInfo::new(user_cert, ca_cert),
+                        &metadata,
+                        &km_uuid,
+                    )
+                    .context("In check_and_migrate.")?;
+                Ok(())
+            }
+            None => {
+                if let Some(ca_cert) = ca_cert {
+                    self.db
+                        .store_new_certificate(&key, &ca_cert, &KEYSTORE_UUID)
+                        .context("In check_and_migrate: Failed to insert new certificate.")?;
+                    Ok(())
+                } else {
+                    Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
+                        .context("In check_and_migrate: Legacy key not found.")
+                }
+            }
+        };
+
+        match result {
+            Ok(()) => {
+                // Add the key to the migrated_keys list.
+                self.recently_migrated.insert(RecentMigration::new(uid, alias.clone()));
+                // Delete legacy key from the file system
+                self.legacy_loader
+                    .remove_keystore_entry(uid, &alias)
+                    .context("In check_and_migrate: Trying to remove migrated key.")?;
+                Ok(())
+            }
+            Err(e) => Err(e),
+        }
+    }
+
+    fn check_and_migrate_super_key(&mut self, user_id: u32, pw: ZVec) -> Result<()> {
+        if self.recently_migrated_super_key.contains(&user_id) {
+            return Ok(());
+        }
+
+        if let Some(super_key) = self
+            .legacy_loader
+            .load_super_key(user_id, &pw)
+            .context("In check_and_migrate_super_key: Trying to load legacy super key.")?
+        {
+            let (blob, blob_metadata) =
+                crate::super_key::SuperKeyManager::encrypt_with_password(&super_key, &pw)
+                    .context("In check_and_migrate_super_key: Trying to encrypt super key.")?;
+
+            self.db.store_super_key(user_id, &(&blob, &blob_metadata)).context(concat!(
+                "In check_and_migrate_super_key: ",
+                "Trying to insert legacy super_key into the database."
+            ))?;
+            self.legacy_loader.remove_super_key(user_id);
+            self.recently_migrated_super_key.insert(user_id);
+            Ok(())
+        } else {
+            Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
+                .context("In check_and_migrate_super_key: No key found do migrate.")
+        }
+    }
+
+    fn has_super_key(&mut self, user_id: u32) -> Result<bool> {
+        Ok(self.recently_migrated_super_key.contains(&user_id)
+            || self.legacy_loader.has_super_key(user_id))
+    }
+
+    fn check_empty(&self) -> u8 {
+        if self.legacy_loader.is_empty().unwrap_or(false) {
+            LegacyMigrator::STATE_EMPTY
+        } else {
+            LegacyMigrator::STATE_READY
+        }
+    }
+}
+
+enum LegacyBlob {
+    Vec(Vec<u8>),
+    ZVec(ZVec),
+}
+
+impl Deref for LegacyBlob {
+    type Target = [u8];
+
+    fn deref(&self) -> &Self::Target {
+        match self {
+            Self::Vec(v) => &v,
+            Self::ZVec(v) => &v,
+        }
+    }
+}
diff --git a/keystore2/src/lib.rs b/keystore2/src/lib.rs
index 445aef6..358fce8 100644
--- a/keystore2/src/lib.rs
+++ b/keystore2/src/lib.rs
@@ -24,6 +24,7 @@
 /// Internal Representation of Key Parameter and convenience functions.
 pub mod key_parameter;
 pub mod legacy_blob;
+pub mod legacy_migrator;
 pub mod operation;
 pub mod permission;
 pub mod remote_provisioning;
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 23a3c35..6b033f1 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -32,7 +32,7 @@
 };
 
 use crate::database::{CertificateInfo, KeyIdGuard};
-use crate::globals::{DB, ENFORCEMENTS, SUPER_KEY};
+use crate::globals::{DB, ENFORCEMENTS, LEGACY_MIGRATOR, SUPER_KEY};
 use crate::key_parameter::KeyParameter as KsKeyParam;
 use crate::key_parameter::KeyParameterValue as KsKeyParamValue;
 use crate::super_key::{KeyBlob, SuperKeyManager};
@@ -131,9 +131,9 @@
 
         let (key_blob, mut blob_metadata) = DB
             .with(|db| {
-                SuperKeyManager::handle_super_encryption_on_key_init(
+                SUPER_KEY.handle_super_encryption_on_key_init(
                     &mut db.borrow_mut(),
-                    &SUPER_KEY,
+                    &LEGACY_MIGRATOR,
                     &(key.domain),
                     &key_parameters,
                     flags,
@@ -218,13 +218,15 @@
             _ => {
                 let (key_id_guard, mut key_entry) = DB
                     .with::<_, Result<(KeyIdGuard, KeyEntry)>>(|db| {
-                        db.borrow_mut().load_key_entry(
-                            &key,
-                            KeyType::Client,
-                            KeyEntryLoadBits::KM,
-                            caller_uid,
-                            |k, av| check_key_permission(KeyPerm::use_(), k, &av),
-                        )
+                        LEGACY_MIGRATOR.with_try_migrate(&key, caller_uid, || {
+                            db.borrow_mut().load_key_entry(
+                                &key,
+                                KeyType::Client,
+                                KeyEntryLoadBits::KM,
+                                caller_uid,
+                                |k, av| check_key_permission(KeyPerm::use_(), k, &av),
+                            )
+                        })
                     })
                     .context("In create_operation: Failed to load key blob.")?;
 
@@ -523,13 +525,15 @@
 
         let (wrapping_key_id_guard, mut wrapping_key_entry) = DB
             .with(|db| {
-                db.borrow_mut().load_key_entry(
-                    &wrapping_key,
-                    KeyType::Client,
-                    KeyEntryLoadBits::KM,
-                    caller_uid,
-                    |k, av| check_key_permission(KeyPerm::use_(), k, &av),
-                )
+                LEGACY_MIGRATOR.with_try_migrate(&key, caller_uid, || {
+                    db.borrow_mut().load_key_entry(
+                        &wrapping_key,
+                        KeyType::Client,
+                        KeyEntryLoadBits::KM,
+                        caller_uid,
+                        |k, av| check_key_permission(KeyPerm::use_(), k, &av),
+                    )
+                })
             })
             .context("Failed to load wrapping key.")?;
 
diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs
index efd62e3..3a4bf82 100644
--- a/keystore2/src/service.rs
+++ b/keystore2/src/service.rs
@@ -27,7 +27,10 @@
     check_grant_permission, check_key_permission, check_keystore_permission,
     key_parameters_to_authorizations, Asp,
 };
-use crate::{database::Uuid, globals::DB};
+use crate::{
+    database::Uuid,
+    globals::{create_thread_local_db, DB, LEGACY_BLOB_LOADER, LEGACY_MIGRATOR},
+};
 use crate::{database::KEYSTORE_UUID, permission};
 use crate::{
     database::{KeyEntryLoadBits, KeyType, SubComponentType},
@@ -73,6 +76,15 @@
             result.uuid_by_sec_level.insert(SecurityLevel::STRONGBOX, uuid);
         }
 
+        let uuid_by_sec_level = result.uuid_by_sec_level.clone();
+        LEGACY_MIGRATOR
+            .set_init(move || {
+                (create_thread_local_db(), uuid_by_sec_level, LEGACY_BLOB_LOADER.clone())
+            })
+            .context(
+                "In KeystoreService::new_native_binder: Trying to initialize the legacy migrator.",
+            )?;
+
         let result = BnKeystoreService::new_binder(result);
         result.as_binder().set_requesting_sid(true);
         Ok(result)
@@ -112,15 +124,18 @@
     }
 
     fn get_key_entry(&self, key: &KeyDescriptor) -> Result<KeyEntryResponse> {
+        let caller_uid = ThreadState::get_calling_uid();
         let (key_id_guard, mut key_entry) = DB
             .with(|db| {
-                db.borrow_mut().load_key_entry(
-                    &key,
-                    KeyType::Client,
-                    KeyEntryLoadBits::PUBLIC,
-                    ThreadState::get_calling_uid(),
-                    |k, av| check_key_permission(KeyPerm::get_info(), k, &av),
-                )
+                LEGACY_MIGRATOR.with_try_migrate(&key, caller_uid, || {
+                    db.borrow_mut().load_key_entry(
+                        &key,
+                        KeyType::Client,
+                        KeyEntryLoadBits::PUBLIC,
+                        caller_uid,
+                        |k, av| check_key_permission(KeyPerm::get_info(), k, &av),
+                    )
+                })
             })
             .context("In get_key_entry, while trying to load key info.")?;
 
@@ -161,18 +176,20 @@
         public_cert: Option<&[u8]>,
         certificate_chain: Option<&[u8]>,
     ) -> Result<()> {
+        let caller_uid = ThreadState::get_calling_uid();
         DB.with::<_, Result<()>>(|db| {
-            let mut db = db.borrow_mut();
-            let entry = match db.load_key_entry(
-                &key,
-                KeyType::Client,
-                KeyEntryLoadBits::NONE,
-                ThreadState::get_calling_uid(),
-                |k, av| {
-                    check_key_permission(KeyPerm::update(), k, &av)
-                        .context("In update_subcomponent.")
-                },
-            ) {
+            let entry = match LEGACY_MIGRATOR.with_try_migrate(&key, caller_uid, || {
+                db.borrow_mut().load_key_entry(
+                    &key,
+                    KeyType::Client,
+                    KeyEntryLoadBits::NONE,
+                    caller_uid,
+                    |k, av| {
+                        check_key_permission(KeyPerm::update(), k, &av)
+                            .context("In update_subcomponent.")
+                    },
+                )
+            }) {
                 Err(e) => match e.root_cause().downcast_ref::<Error>() {
                     Some(Error::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
                     _ => Err(e),
@@ -181,6 +198,7 @@
             }
             .context("Failed to load key entry.")?;
 
+            let mut db = db.borrow_mut();
             if let Some((key_id_guard, key_entry)) = entry {
                 db.set_blob(&key_id_guard, SubComponentType::CERT, public_cert, None)
                     .context("Failed to update cert subcomponent.")?;
@@ -258,17 +276,31 @@
             Ok(()) => {}
         };
 
-        DB.with(|db| {
-            let mut db = db.borrow_mut();
-            db.list(k.domain, k.nspace)
-        })
+        let mut result = LEGACY_MIGRATOR
+            .list_uid(k.domain, k.nspace)
+            .context("In list_entries: Trying to list legacy keys.")?;
+
+        result.append(
+            &mut DB
+                .with(|db| {
+                    let mut db = db.borrow_mut();
+                    db.list(k.domain, k.nspace)
+                })
+                .context("In list_entries: Trying to list keystore database.")?,
+        );
+
+        result.sort_unstable();
+        result.dedup();
+        Ok(result)
     }
 
     fn delete_key(&self, key: &KeyDescriptor) -> Result<()> {
         let caller_uid = ThreadState::get_calling_uid();
         DB.with(|db| {
-            db.borrow_mut().unbind_key(&key, KeyType::Client, caller_uid, |k, av| {
-                check_key_permission(KeyPerm::delete(), k, &av).context("During delete_key.")
+            LEGACY_MIGRATOR.with_try_migrate(&key, caller_uid, || {
+                db.borrow_mut().unbind_key(&key, KeyType::Client, caller_uid, |k, av| {
+                    check_key_permission(KeyPerm::delete(), k, &av).context("During delete_key.")
+                })
             })
         })
         .context("In delete_key: Trying to unbind the key.")?;
@@ -281,14 +313,17 @@
         grantee_uid: i32,
         access_vector: permission::KeyPermSet,
     ) -> Result<KeyDescriptor> {
+        let caller_uid = ThreadState::get_calling_uid();
         DB.with(|db| {
-            db.borrow_mut().grant(
-                &key,
-                ThreadState::get_calling_uid(),
-                grantee_uid as u32,
-                access_vector,
-                |k, av| check_grant_permission(*av, k).context("During grant."),
-            )
+            LEGACY_MIGRATOR.with_try_migrate(&key, caller_uid, || {
+                db.borrow_mut().grant(
+                    &key,
+                    caller_uid,
+                    grantee_uid as u32,
+                    access_vector,
+                    |k, av| check_grant_permission(*av, k).context("During grant."),
+                )
+            })
         })
         .context("In KeystoreService::grant.")
     }
diff --git a/keystore2/src/super_key.rs b/keystore2/src/super_key.rs
index dd29d7e..156d20d 100644
--- a/keystore2/src/super_key.rs
+++ b/keystore2/src/super_key.rs
@@ -18,6 +18,7 @@
     database::BlobMetaData, database::BlobMetaEntry, database::EncryptedBy, database::KeyEntry,
     database::KeyType, database::KeystoreDB, enforcements::Enforcements, error::Error,
     error::ResponseCode, key_parameter::KeyParameter, legacy_blob::LegacyBlobLoader,
+    legacy_migrator::LegacyMigrator,
 };
 use android_system_keystore2::aidl::android::system::keystore2::Domain::Domain;
 use anyhow::{Context, Result};
@@ -201,7 +202,11 @@
     }
 
     /// Checks if user has setup LSKF, even when super key cache is empty for the user.
-    pub fn super_key_exists_in_db_for_user(db: &mut KeystoreDB, user_id: u32) -> Result<bool> {
+    pub fn super_key_exists_in_db_for_user(
+        db: &mut KeystoreDB,
+        legacy_migrator: &LegacyMigrator,
+        user_id: u32,
+    ) -> Result<bool> {
         let key_in_db = db
             .key_exists(
                 Domain::APP,
@@ -214,9 +219,9 @@
         if key_in_db {
             Ok(key_in_db)
         } else {
-            //TODO (b/159371296): add a function to legacy blob loader to check if super key exists
-            //given user id
-            Ok(false)
+            legacy_migrator
+                .has_super_key(user_id)
+                .context("In super_key_exists_in_db_for_user: Trying to query legacy db.")
         }
     }
 
@@ -226,11 +231,12 @@
     pub fn check_and_unlock_super_key(
         &self,
         db: &mut KeystoreDB,
+        legacy_migrator: &LegacyMigrator,
         user_id: u32,
         pw: &[u8],
     ) -> Result<UserState> {
-        let result = db
-            .load_super_key(user_id)
+        let result = legacy_migrator
+            .with_try_migrate_super_key(user_id, pw, || db.load_super_key(user_id))
             .context("In check_and_unlock_super_key. Failed to load super key")?;
 
         match result {
@@ -240,11 +246,7 @@
                     .context("In check_and_unlock_super_key.")?;
                 Ok(UserState::LskfUnlocked(super_key))
             }
-            None =>
-            //TODO: 159371296. Try to load and populate super key from legacy key database.
-            {
-                Ok(UserState::Uninitialized)
-            }
+            None => Ok(UserState::Uninitialized),
         }
     }
 
@@ -257,38 +259,35 @@
     pub fn check_and_initialize_super_key(
         &self,
         db: &mut KeystoreDB,
+        legacy_migrator: &LegacyMigrator,
         user_id: u32,
         pw: Option<&[u8]>,
     ) -> Result<UserState> {
-        let super_key_exists_in_db = Self::super_key_exists_in_db_for_user(db, user_id)
-            .context("In check_and_initialize_super_key. Failed to check if super key exists.")?;
+        let super_key_exists_in_db =
+            Self::super_key_exists_in_db_for_user(db, legacy_migrator, user_id).context(
+                "In check_and_initialize_super_key. Failed to check if super key exists.",
+            )?;
         if super_key_exists_in_db {
             Ok(UserState::LskfLocked)
+        } else if let Some(pw) = pw {
+            //generate a new super key.
+            let super_key = generate_aes256_key()
+                .context("In check_and_initialize_super_key: Failed to generate AES 256 key.")?;
+            //derive an AES256 key from the password and re-encrypt the super key
+            //before we insert it in the database.
+            let (encrypted_super_key, blob_metadata) = Self::encrypt_with_password(&super_key, pw)
+                .context("In check_and_initialize_super_key.")?;
+
+            let key_entry = db
+                .store_super_key(user_id, &(&encrypted_super_key, &blob_metadata))
+                .context("In check_and_initialize_super_key. Failed to store super key.")?;
+
+            let super_key = self
+                .populate_cache_from_super_key_blob(user_id, key_entry, pw)
+                .context("In check_and_initialize_super_key.")?;
+            Ok(UserState::LskfUnlocked(super_key))
         } else {
-            //TODO: 159371296. check if super key exists in legacy key database. If so, return
-            //LskfLocked. Otherwise, if pw is provided, initialize the super key.
-            if let Some(pw) = pw {
-                //generate a new super key.
-                let super_key = generate_aes256_key().context(
-                    "In check_and_initialize_super_key: Failed to generate AES 256 key.",
-                )?;
-                //derive an AES256 key from the password and re-encrypt the super key
-                //before we insert it in the database.
-                let (encrypted_super_key, blob_metadata) =
-                    Self::encrypt_with_password(&super_key, pw)
-                        .context("In check_and_initialize_super_key.")?;
-
-                let key_entry = db
-                    .store_super_key(user_id as u64 as i64, &(&encrypted_super_key, &blob_metadata))
-                    .context("In check_and_initialize_super_key. Failed to store super key.")?;
-
-                let super_key = self
-                    .populate_cache_from_super_key_blob(user_id, key_entry, pw)
-                    .context("In check_and_initialize_super_key.")?;
-                Ok(UserState::LskfUnlocked(super_key))
-            } else {
-                Ok(UserState::Uninitialized)
-            }
+            Ok(UserState::Uninitialized)
         }
     }
 
@@ -364,12 +363,13 @@
     // return error. Note that it is out of the scope of this function to check if super encryption
     // is required. Such check should be performed before calling this function.
     fn super_encrypt_on_key_init(
+        &self,
         db: &mut KeystoreDB,
-        skm: &SuperKeyManager,
+        legacy_migrator: &LegacyMigrator,
         user_id: u32,
         key_blob: &[u8],
     ) -> Result<(Vec<u8>, BlobMetaData)> {
-        match UserState::get(db, skm, user_id)
+        match UserState::get(db, legacy_migrator, self, user_id)
             .context("In super_encrypt. Failed to get user state.")?
         {
             UserState::LskfUnlocked(super_key) => {
@@ -402,9 +402,11 @@
 
     /// Check if super encryption is required and if so, super-encrypt the key to be stored in
     /// the database.
+    #[allow(clippy::clippy::too_many_arguments)]
     pub fn handle_super_encryption_on_key_init(
+        &self,
         db: &mut KeystoreDB,
-        skm: &SuperKeyManager,
+        legacy_migrator: &LegacyMigrator,
         domain: &Domain,
         key_parameters: &[KeyParameter],
         flags: Option<i32>,
@@ -412,11 +414,12 @@
         key_blob: &[u8],
     ) -> Result<(Vec<u8>, BlobMetaData)> {
         match (*domain, Enforcements::super_encryption_required(key_parameters, flags)) {
-            (Domain::APP, true) => Self::super_encrypt_on_key_init(db, skm, user_id, &key_blob)
-                .context(
+            (Domain::APP, true) => {
+                self.super_encrypt_on_key_init(db, legacy_migrator, user_id, &key_blob).context(
                     "In handle_super_encryption_on_key_init.
                          Failed to super encrypt the key.",
-                ),
+                )
+            }
             _ => Ok((key_blob.to_vec(), BlobMetaData::new())),
         }
     }
@@ -482,13 +485,18 @@
 }
 
 impl UserState {
-    pub fn get(db: &mut KeystoreDB, skm: &SuperKeyManager, user_id: u32) -> Result<UserState> {
+    pub fn get(
+        db: &mut KeystoreDB,
+        legacy_migrator: &LegacyMigrator,
+        skm: &SuperKeyManager,
+        user_id: u32,
+    ) -> Result<UserState> {
         match skm.get_per_boot_key_by_user_id(user_id) {
             Some(super_key) => Ok(UserState::LskfUnlocked(super_key)),
             None => {
                 //Check if a super key exists in the database or legacy database.
                 //If so, return locked user state.
-                if SuperKeyManager::super_key_exists_in_db_for_user(db, user_id)
+                if SuperKeyManager::super_key_exists_in_db_for_user(db, legacy_migrator, user_id)
                     .context("In get.")?
                 {
                     Ok(UserState::LskfLocked)
@@ -502,6 +510,7 @@
     /// Queries user state when serving password change requests.
     pub fn get_with_password_changed(
         db: &mut KeystoreDB,
+        legacy_migrator: &LegacyMigrator,
         skm: &SuperKeyManager,
         user_id: u32,
         password: Option<&[u8]>,
@@ -526,7 +535,7 @@
                 //If so, return LskfLocked state.
                 //Otherwise, i) if the password is provided, initialize the super key and return
                 //LskfUnlocked state ii) if password is not provided, return Uninitialized state.
-                skm.check_and_initialize_super_key(db, user_id, password)
+                skm.check_and_initialize_super_key(db, legacy_migrator, user_id, password)
             }
         }
     }
@@ -534,6 +543,7 @@
     /// Queries user state when serving password unlock requests.
     pub fn get_with_password_unlock(
         db: &mut KeystoreDB,
+        legacy_migrator: &LegacyMigrator,
         skm: &SuperKeyManager,
         user_id: u32,
         password: &[u8],
@@ -548,7 +558,7 @@
                 //If not, return Uninitialized state.
                 //Otherwise, try to unlock the super key and if successful,
                 //return LskfUnlocked state
-                skm.check_and_unlock_super_key(db, user_id, password)
+                skm.check_and_unlock_super_key(db, legacy_migrator, user_id, password)
                     .context("In get_with_password_unlock. Failed to unlock super key.")
             }
         }
diff --git a/keystore2/src/user_manager.rs b/keystore2/src/user_manager.rs
index 9ee6727..8b7aad9 100644
--- a/keystore2/src/user_manager.rs
+++ b/keystore2/src/user_manager.rs
@@ -16,7 +16,7 @@
 
 use crate::error::map_or_log_err;
 use crate::error::Error as KeystoreError;
-use crate::globals::{DB, SUPER_KEY};
+use crate::globals::{DB, LEGACY_MIGRATOR, SUPER_KEY};
 use crate::permission::KeystorePerm;
 use crate::super_key::UserState;
 use crate::utils::check_keystore_permission;
@@ -50,6 +50,7 @@
             .with(|db| {
                 UserState::get_with_password_changed(
                     &mut db.borrow_mut(),
+                    &LEGACY_MIGRATOR,
                     &SUPER_KEY,
                     user_id as u32,
                     password,