Open the LoginDatabase on the DB thread, not the UI thread.

PasswordStoreFactory::BuildServiceInstanceFor() used to open the LoginDatabase directly, on the UI thread. As the operation takes ~100 ms on average, this had led to significant UI jankiness.

This CL now changes this behavior so that the DB is opened in a deferred manner by PasswordStoreDefault on the DB thread. Furthermore, this CL refactors LoginDatabase to take the path to the DB in the constructor, and starts using scoped_ptr-s when PasswordStore implementations take ownership of passed-in components.

BUG=138903

Review URL: https://codereview.chromium.org/838453003

Cr-Commit-Position: refs/heads/master@{#312607}
diff --git a/chrome/browser/password_manager/password_store_factory.cc b/chrome/browser/password_manager/password_store_factory.cc
index a23c2354..f3c0b9ce 100644
--- a/chrome/browser/password_manager/password_store_factory.cc
+++ b/chrome/browser/password_manager/password_store_factory.cc
@@ -146,19 +146,12 @@
   DelayReportOsPassword();
   Profile* profile = static_cast<Profile*>(context);
 
+  // Given that LoginDatabase::Init() takes ~100ms on average; it will be called
+  // by PasswordStore::Init() on the background thread to avoid UI jank.
   base::FilePath login_db_file_path = profile->GetPath();
   login_db_file_path = login_db_file_path.Append(chrome::kLoginDataFileName);
   scoped_ptr<password_manager::LoginDatabase> login_db(
-      new password_manager::LoginDatabase());
-  {
-    // TODO(paivanof@gmail.com): execution of login_db->Init() should go
-    // to DB thread. http://crbug.com/138903
-    base::ThreadRestrictions::ScopedAllowIO allow_io;
-    if (!login_db->Init(login_db_file_path)) {
-      LOG(ERROR) << "Could not initialize login database.";
-      return NULL;
-    }
-  }
+      new password_manager::LoginDatabase(login_db_file_path));
 
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner(
       base::MessageLoopProxy::current());
@@ -168,24 +161,23 @@
 
   scoped_refptr<PasswordStore> ps;
 #if defined(OS_WIN)
-  ps = new PasswordStoreWin(main_thread_runner,
-                            db_thread_runner,
-                            login_db.release(),
+  ps = new PasswordStoreWin(main_thread_runner, db_thread_runner,
+                            login_db.Pass(),
                             WebDataServiceFactory::GetPasswordWebDataForProfile(
                                 profile, ServiceAccessType::EXPLICIT_ACCESS));
 #elif defined(OS_MACOSX)
-  crypto::AppleKeychain* keychain =
+  scoped_ptr<crypto::AppleKeychain> keychain(
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           os_crypt::switches::kUseMockKeychain)
           ? new crypto::MockAppleKeychain()
-          : new crypto::AppleKeychain();
-  ps = new PasswordStoreMac(
-      main_thread_runner, db_thread_runner, keychain, login_db.release());
+          : new crypto::AppleKeychain());
+  ps = new PasswordStoreMac(main_thread_runner, db_thread_runner,
+                            keychain.Pass(), login_db.Pass());
 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
   // For now, we use PasswordStoreDefault. We might want to make a native
   // backend for PasswordStoreX (see below) in the future though.
   ps = new password_manager::PasswordStoreDefault(
-      main_thread_runner, db_thread_runner, login_db.release());
+      main_thread_runner, db_thread_runner, login_db.Pass());
 #elif defined(USE_X11)
   // On POSIX systems, we try to use the "native" password management system of
   // the desktop environment currently running, allowing GNOME Keyring in XFCE.
@@ -240,13 +232,11 @@
         "more information about password storage options.";
   }
 
-  ps = new PasswordStoreX(main_thread_runner,
-                          db_thread_runner,
-                          login_db.release(),
+  ps = new PasswordStoreX(main_thread_runner, db_thread_runner, login_db.Pass(),
                           backend.release());
 #elif defined(USE_OZONE)
   ps = new password_manager::PasswordStoreDefault(
-      main_thread_runner, db_thread_runner, login_db.release());
+      main_thread_runner, db_thread_runner, login_db.Pass());
 #else
   NOTIMPLEMENTED();
 #endif
diff --git a/chrome/browser/password_manager/password_store_mac.cc b/chrome/browser/password_manager/password_store_mac.cc
index 416bab5..bb50c74 100644
--- a/chrome/browser/password_manager/password_store_mac.cc
+++ b/chrome/browser/password_manager/password_store_mac.cc
@@ -863,11 +863,11 @@
 PasswordStoreMac::PasswordStoreMac(
     scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
     scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
-    AppleKeychain* keychain,
-    password_manager::LoginDatabase* login_db)
+    scoped_ptr<AppleKeychain> keychain,
+    scoped_ptr<password_manager::LoginDatabase> login_db)
     : password_manager::PasswordStore(main_thread_runner, db_thread_runner),
-      keychain_(keychain),
-      login_metadata_db_(login_db) {
+      keychain_(keychain.Pass()),
+      login_metadata_db_(login_db.Pass()) {
   DCHECK(keychain_.get());
   DCHECK(login_metadata_db_.get());
 }
@@ -883,9 +883,20 @@
     thread_.reset(NULL);
     return false;
   }
+
+  ScheduleTask(base::Bind(&PasswordStoreMac::InitOnBackgroundThread, this));
   return password_manager::PasswordStore::Init(flare);
 }
 
+void PasswordStoreMac::InitOnBackgroundThread() {
+  DCHECK(thread_->message_loop() == base::MessageLoop::current());
+  DCHECK(login_metadata_db_);
+  if (!login_metadata_db_->Init()) {
+    login_metadata_db_.reset();
+    LOG(ERROR) << "Could not create/open login database.";
+  }
+}
+
 void PasswordStoreMac::Shutdown() {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   password_manager::PasswordStore::Shutdown();
@@ -903,6 +914,8 @@
 
 void PasswordStoreMac::ReportMetricsImpl(const std::string& sync_username,
                                          bool custom_passphrase_sync_enabled) {
+  if (!login_metadata_db_)
+    return;
   login_metadata_db_->ReportMetrics(sync_username,
                                     custom_passphrase_sync_enabled);
 }
@@ -910,16 +923,17 @@
 PasswordStoreChangeList PasswordStoreMac::AddLoginImpl(
     const PasswordForm& form) {
   DCHECK(thread_->message_loop() == base::MessageLoop::current());
-  PasswordStoreChangeList changes;
-  if (AddToKeychainIfNecessary(form)) {
-    changes = login_metadata_db_->AddLogin(form);
-  }
-  return changes;
+  if (login_metadata_db_ && AddToKeychainIfNecessary(form))
+    return login_metadata_db_->AddLogin(form);
+  return PasswordStoreChangeList();
 }
 
 PasswordStoreChangeList PasswordStoreMac::UpdateLoginImpl(
     const PasswordForm& form) {
   DCHECK(thread_->message_loop() == base::MessageLoop::current());
+  if (!login_metadata_db_)
+    return PasswordStoreChangeList();
+
   PasswordStoreChangeList changes = login_metadata_db_->UpdateLogin(form);
 
   MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get());
@@ -942,7 +956,7 @@
     const PasswordForm& form) {
   DCHECK(thread_->message_loop() == base::MessageLoop::current());
   PasswordStoreChangeList changes;
-  if (login_metadata_db_->RemoveLogin(form)) {
+  if (login_metadata_db_ && login_metadata_db_->RemoveLogin(form)) {
     // See if we own a Keychain item associated with this item. We can do an
     // exact search rather than messing around with trying to do fuzzy matching
     // because passwords that we created will always have an exact-match
@@ -970,15 +984,15 @@
     base::Time delete_end) {
   PasswordStoreChangeList changes;
   ScopedVector<PasswordForm> forms;
-  if (login_metadata_db_->GetLoginsCreatedBetween(delete_begin, delete_end,
-                                                  &forms.get())) {
-    if (login_metadata_db_->RemoveLoginsCreatedBetween(delete_begin,
-                                                       delete_end)) {
-      RemoveKeychainForms(forms.get());
-      CleanOrphanedForms(&forms.get());
-      changes = FormsToRemoveChangeList(forms.get());
-      LogStatsForBulkDeletion(changes.size());
-    }
+  if (login_metadata_db_ &&
+      login_metadata_db_->GetLoginsCreatedBetween(delete_begin, delete_end,
+                                                  &forms.get()) &&
+      login_metadata_db_->RemoveLoginsCreatedBetween(delete_begin,
+                                                     delete_end)) {
+    RemoveKeychainForms(forms.get());
+    CleanOrphanedForms(&forms.get());
+    changes = FormsToRemoveChangeList(forms.get());
+    LogStatsForBulkDeletion(changes.size());
   }
   return changes;
 }
@@ -988,15 +1002,14 @@
     base::Time delete_end) {
   PasswordStoreChangeList changes;
   ScopedVector<PasswordForm> forms;
-  if (login_metadata_db_->GetLoginsSyncedBetween(
-          delete_begin, delete_end, &forms.get())) {
-    if (login_metadata_db_->RemoveLoginsSyncedBetween(delete_begin,
-                                                      delete_end)) {
-      RemoveKeychainForms(forms.get());
-      CleanOrphanedForms(&forms.get());
-      changes = FormsToRemoveChangeList(forms.get());
-      LogStatsForBulkDeletionDuringRollback(changes.size());
-    }
+  if (login_metadata_db_ &&
+      login_metadata_db_->GetLoginsSyncedBetween(delete_begin, delete_end,
+                                                 &forms.get()) &&
+      login_metadata_db_->RemoveLoginsSyncedBetween(delete_begin, delete_end)) {
+    RemoveKeychainForms(forms.get());
+    CleanOrphanedForms(&forms.get());
+    changes = FormsToRemoveChangeList(forms.get());
+    LogStatsForBulkDeletionDuringRollback(changes.size());
   }
   return changes;
 }
@@ -1008,6 +1021,11 @@
   chrome::ScopedSecKeychainSetUserInteractionAllowed user_interaction_allowed(
       prompt_policy == ALLOW_PROMPT);
 
+  if (!login_metadata_db_) {
+    callback_runner.Run(std::vector<PasswordForm*>());
+    return;
+  }
+
   ScopedVector<PasswordForm> database_forms;
   login_metadata_db_->GetLogins(form, &database_forms.get());
 
@@ -1076,7 +1094,8 @@
   DCHECK(thread_->message_loop() == base::MessageLoop::current());
 
   ScopedVector<PasswordForm> database_forms;
-  if (!login_metadata_db_->GetAutofillableLogins(&database_forms.get()))
+  if (!login_metadata_db_ ||
+      !login_metadata_db_->GetAutofillableLogins(&database_forms.get()))
     return false;
 
   std::vector<PasswordForm*> merged_forms =
@@ -1095,7 +1114,7 @@
 bool PasswordStoreMac::FillBlacklistLogins(
          std::vector<PasswordForm*>* forms) {
   DCHECK(thread_->message_loop() == base::MessageLoop::current());
-  return login_metadata_db_->GetBlacklistLogins(forms);
+  return login_metadata_db_ && login_metadata_db_->GetBlacklistLogins(forms);
 }
 
 bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) {
@@ -1108,6 +1127,7 @@
 
 bool PasswordStoreMac::DatabaseHasFormMatchingKeychainForm(
     const autofill::PasswordForm& form) {
+  DCHECK(login_metadata_db_);
   bool has_match = false;
   std::vector<PasswordForm*> database_forms;
   login_metadata_db_->GetLogins(form, &database_forms);
@@ -1129,6 +1149,7 @@
 
 void PasswordStoreMac::RemoveDatabaseForms(
     const std::vector<PasswordForm*>& forms) {
+  DCHECK(login_metadata_db_);
   for (std::vector<PasswordForm*>::const_iterator i = forms.begin();
        i != forms.end(); ++i) {
     login_metadata_db_->RemoveLogin(**i);
@@ -1147,6 +1168,8 @@
 
 void PasswordStoreMac::CleanOrphanedForms(std::vector<PasswordForm*>* forms) {
   DCHECK(forms);
+  DCHECK(login_metadata_db_);
+
   std::vector<PasswordForm*> database_forms;
   login_metadata_db_->GetAutofillableLogins(&database_forms);
 
diff --git a/chrome/browser/password_manager/password_store_mac.h b/chrome/browser/password_manager/password_store_mac.h
index ecde485..394ab9e 100644
--- a/chrome/browser/password_manager/password_store_mac.h
+++ b/chrome/browser/password_manager/password_store_mac.h
@@ -28,13 +28,13 @@
 // http://dev.chromium.org/developers/design-documents/os-x-password-manager-keychain-integration
 class PasswordStoreMac : public password_manager::PasswordStore {
  public:
-  // Takes ownership of |keychain| and |login_db|, both of which must be
-  // non-NULL.
+  // The |login_db| must not have been Init()-ed yet. It will be initialized in
+  // a deferred manner on the background thread.
   PasswordStoreMac(
       scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
       scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
-      crypto::AppleKeychain* keychain,
-      password_manager::LoginDatabase* login_db);
+      scoped_ptr<crypto::AppleKeychain> keychain,
+      scoped_ptr<password_manager::LoginDatabase> login_db);
 
   // Initializes |thread_|.
   bool Init(const syncer::SyncableService::StartSyncFlare& flare) override;
@@ -42,9 +42,20 @@
   // Stops |thread_|.
   void Shutdown() override;
 
+  // To be used for testing.
+  password_manager::LoginDatabase* login_metadata_db() const {
+    return login_metadata_db_.get();
+  }
+
+  // To be used for testing.
+  crypto::AppleKeychain* keychain() const { return keychain_.get(); }
+
  protected:
   ~PasswordStoreMac() override;
 
+  // Opens |login_metadata_db_| on the background |thread_|.
+  void InitOnBackgroundThread();
+
   scoped_refptr<base::SingleThreadTaskRunner> GetBackgroundTaskRunner()
       override;
 
@@ -97,6 +108,11 @@
   void CleanOrphanedForms(std::vector<autofill::PasswordForm*>* forms);
 
   scoped_ptr<crypto::AppleKeychain> keychain_;
+
+  // The login metadata SQL database. The LoginDatabase instance is received via
+  // the in an uninitialized state, so as to allow injecting mocks, then Init()
+  // is called on the DB thread in a deferred manner. If opening the DB fails,
+  // |login_metadata_db_| will be reset to NULL for the lifetime of |this|.
   scoped_ptr<password_manager::LoginDatabase> login_metadata_db_;
 
   // Thread that the synchronous methods are run on.
diff --git a/chrome/browser/password_manager/password_store_mac_unittest.cc b/chrome/browser/password_manager/password_store_mac_unittest.cc
index a3e8810..a90341a 100644
--- a/chrome/browser/password_manager/password_store_mac_unittest.cc
+++ b/chrome/browser/password_manager/password_store_mac_unittest.cc
@@ -11,8 +11,10 @@
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/waitable_event.h"
 #include "chrome/browser/password_manager/password_store_mac_internal.h"
 #include "chrome/common/chrome_paths.h"
+#include "components/password_manager/core/browser/login_database.h"
 #include "components/password_manager/core/browser/password_store_consumer.h"
 #include "content/public/test/test_browser_thread.h"
 #include "crypto/mock_apple_keychain.h"
@@ -36,6 +38,15 @@
 
 namespace {
 
+ACTION(STLDeleteElements0) {
+  STLDeleteContainerPointers(arg0.begin(), arg0.end());
+}
+
+ACTION(QuitUIMessageLoop) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  base::MessageLoop::current()->Quit();
+}
+
 class MockPasswordStoreConsumer : public PasswordStoreConsumer {
  public:
   MOCK_METHOD1(OnGetPasswordStoreResults,
@@ -48,30 +59,72 @@
     }
   }
 
+  // Runs the current thread's message loop until OnGetPasswordStoreResults()
+  // is posted to it. This method should be called immediately after GetLogins,
+  // without pumping the message loop in-between.
+  void WaitOnGetPasswordStoreResults() {
+    EXPECT_CALL(*this, OnGetPasswordStoreResults(_)).WillOnce(DoAll(
+        WithArg<0>(Invoke(this, &MockPasswordStoreConsumer::CopyElements)),
+        WithArg<0>(STLDeleteElements0()),
+        QuitUIMessageLoop()));
+    base::MessageLoop::current()->Run();
+  }
+
   std::vector<PasswordForm> last_result;
 };
 
-ACTION(STLDeleteElements0) {
-  STLDeleteContainerPointers(arg0.begin(), arg0.end());
-}
+class MockPasswordStoreObserver : public PasswordStore::Observer {
+ public:
+  MOCK_METHOD1(OnLoginsChanged,
+               void(const password_manager::PasswordStoreChangeList& changes));
+};
 
-ACTION(QuitUIMessageLoop) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  base::MessageLoop::current()->Quit();
-}
+// A mock LoginDatabase that simulates a failing Init() method.
+class BadLoginDatabase : public password_manager::LoginDatabase {
+ public:
+  BadLoginDatabase() : password_manager::LoginDatabase(base::FilePath()) {}
+  ~BadLoginDatabase() override {}
+
+  // LoginDatabase:
+  bool Init() override { return false; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BadLoginDatabase);
+};
+
+// A LoginDatabase that simulates an Init() method that takes a long time.
+class SlowToInitLoginDatabase : public password_manager::LoginDatabase {
+ public:
+  // Creates an instance whose Init() method will block until |event| is
+  // signaled. |event| must outlive |this|.
+  SlowToInitLoginDatabase(const base::FilePath& db_path,
+                          base::WaitableEvent* event)
+      : password_manager::LoginDatabase(db_path), event_(event) {}
+  ~SlowToInitLoginDatabase() override {}
+
+  // LoginDatabase:
+  bool Init() override {
+    event_->Wait();
+    return password_manager::LoginDatabase::Init();
+  }
+
+ private:
+  base::WaitableEvent* event_;
+
+  DISALLOW_COPY_AND_ASSIGN(SlowToInitLoginDatabase);
+};
 
 class TestPasswordStoreMac : public PasswordStoreMac {
  public:
   TestPasswordStoreMac(
       scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
       scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
-      crypto::AppleKeychain* keychain,
-      LoginDatabase* login_db)
+      scoped_ptr<crypto::AppleKeychain> keychain,
+      scoped_ptr<password_manager::LoginDatabase> login_db)
       : PasswordStoreMac(main_thread_runner,
                          db_thread_runner,
-                         keychain,
-                         login_db) {
-  }
+                         keychain.Pass(),
+                         login_db.Pass()) {}
 
   using PasswordStoreMac::GetBackgroundTaskRunner;
 
@@ -1052,47 +1105,64 @@
   PasswordStoreMacTest() : ui_thread_(BrowserThread::UI, &message_loop_) {}
 
   void SetUp() override {
-    login_db_ = new LoginDatabase();
     ASSERT_TRUE(db_dir_.CreateUniqueTempDir());
-    base::FilePath db_file = db_dir_.path().AppendASCII("login.db");
-    ASSERT_TRUE(login_db_->Init(db_file));
 
-    keychain_ = new MockAppleKeychain();
+    scoped_ptr<password_manager::LoginDatabase> login_db(
+        new password_manager::LoginDatabase(test_login_db_file_path()));
+    CreateAndInitPasswordStore(login_db.Pass());
+    // Make sure deferred initialization is performed before some tests start
+    // accessing the |login_db| directly.
+    FinishAsyncProcessing();
+  }
 
+  void TearDown() override { ClosePasswordStore(); }
+
+  void CreateAndInitPasswordStore(
+      scoped_ptr<password_manager::LoginDatabase> login_db) {
     store_ = new TestPasswordStoreMac(
-        base::MessageLoopProxy::current(),
-        base::MessageLoopProxy::current(),
-        keychain_,
-        login_db_);
+        base::MessageLoopProxy::current(), base::MessageLoopProxy::current(),
+        make_scoped_ptr<AppleKeychain>(new MockAppleKeychain), login_db.Pass());
     ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
   }
 
-  void TearDown() override {
+  void ClosePasswordStore() {
+    if (!store_)
+      return;
+
     store_->Shutdown();
-    EXPECT_FALSE(store_->GetBackgroundTaskRunner().get());
+    EXPECT_FALSE(store_->GetBackgroundTaskRunner());
+    base::MessageLoop::current()->RunUntilIdle();
+    store_ = nullptr;
   }
 
-  void WaitForStoreUpdate() {
-    // Do a store-level query to wait for all the operations above to be done.
+  base::FilePath test_login_db_file_path() const {
+    return db_dir_.path().Append(FILE_PATH_LITERAL("login.db"));
+  }
+
+  password_manager::LoginDatabase* login_db() const {
+    return store_->login_metadata_db();
+  }
+
+  MockAppleKeychain* keychain() {
+    return static_cast<MockAppleKeychain*>(store_->keychain());
+  }
+
+  void FinishAsyncProcessing() {
+    // Do a store-level query to wait for all the previously enqueued operations
+    // to finish.
     MockPasswordStoreConsumer consumer;
-    EXPECT_CALL(consumer, OnGetPasswordStoreResults(_))
-        .WillOnce(DoAll(WithArg<0>(STLDeleteElements0()), QuitUIMessageLoop()));
     store_->GetLogins(PasswordForm(), PasswordStore::ALLOW_PROMPT, &consumer);
-    base::MessageLoop::current()->Run();
+    consumer.WaitOnGetPasswordStoreResults();
   }
 
   TestPasswordStoreMac* store() { return store_.get(); }
 
-  MockAppleKeychain* keychain() { return keychain_; }
-
  protected:
   base::MessageLoopForUI message_loop_;
   content::TestBrowserThread ui_thread_;
 
-  MockAppleKeychain* keychain_;  // Owned by store_.
-  LoginDatabase* login_db_;  // Owned by store_.
-  scoped_refptr<TestPasswordStoreMac> store_;
   base::ScopedTempDir db_dir_;
+  scoped_refptr<TestPasswordStoreMac> store_;
 };
 
 TEST_F(PasswordStoreMacTest, TestStoreUpdate) {
@@ -1107,12 +1177,12 @@
     L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1
   };
   scoped_ptr<PasswordForm> joint_form(CreatePasswordFormFromData(joint_data));
-  login_db_->AddLogin(*joint_form);
+  login_db()->AddLogin(*joint_form);
   MockAppleKeychain::KeychainTestData joint_keychain_data = {
     kSecAuthenticationTypeHTMLForm, "some.domain.com",
     kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z",
     "joe_user", "sekrit", false };
-  keychain_->AddTestItem(joint_keychain_data);
+  keychain()->AddTestItem(joint_keychain_data);
 
   // Insert a password into the keychain only.
   MockAppleKeychain::KeychainTestData keychain_only_data = {
@@ -1120,7 +1190,7 @@
     kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z",
     "keychain", "only", false
   };
-  keychain_->AddTestItem(keychain_only_data);
+  keychain()->AddTestItem(keychain_only_data);
 
   struct UpdateData {
     PasswordFormData form_data;
@@ -1160,9 +1230,9 @@
     store_->UpdateLogin(*form);
   }
 
-  WaitForStoreUpdate();
+  FinishAsyncProcessing();
 
-  MacKeychainPasswordFormAdapter keychain_adapter(keychain_);
+  MacKeychainPasswordFormAdapter keychain_adapter(keychain());
   for (unsigned int i = 0; i < arraysize(updates); ++i) {
     scoped_ptr<PasswordForm> query_form(
         CreatePasswordFormFromData(updates[i].form_data));
@@ -1180,7 +1250,7 @@
     }
     STLDeleteElements(&matching_items);
 
-    login_db_->GetLogins(*query_form, &matching_items);
+    login_db()->GetLogins(*query_form, &matching_items);
     EXPECT_EQ(updates[i].password ? 1U : 0U, matching_items.size())
         << "iteration " << i;
     STLDeleteElements(&matching_items);
@@ -1210,8 +1280,8 @@
     L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1
   };
   scoped_ptr<PasswordForm> www_form(CreatePasswordFormFromData(www_form_data));
-  login_db_->AddLogin(*www_form);
-  MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_);
+  login_db()->AddLogin(*www_form);
+  MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain());
   owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
   owned_keychain_adapter.AddPassword(*www_form);
 
@@ -1219,36 +1289,33 @@
   PasswordForm m_form(*www_form);
   m_form.signon_realm = "http://m.facebook.com";
   m_form.origin = GURL("http://m.facebook.com/index.html");
+
   MockPasswordStoreConsumer consumer;
-  EXPECT_CALL(consumer, OnGetPasswordStoreResults(_)).WillOnce(DoAll(
-      WithArg<0>(Invoke(&consumer, &MockPasswordStoreConsumer::CopyElements)),
-      WithArg<0>(STLDeleteElements0()),
-      QuitUIMessageLoop()));
   store_->GetLogins(m_form, PasswordStore::ALLOW_PROMPT, &consumer);
-  base::MessageLoop::current()->Run();
+  consumer.WaitOnGetPasswordStoreResults();
   EXPECT_EQ(1u, consumer.last_result.size());
 
   // 3. Add the returned password for m.facebook.com.
-  login_db_->AddLogin(consumer.last_result[0]);
+  login_db()->AddLogin(consumer.last_result[0]);
   owned_keychain_adapter.AddPassword(m_form);
 
   // 4. Remove both passwords.
   store_->RemoveLogin(*www_form);
   store_->RemoveLogin(m_form);
-  WaitForStoreUpdate();
+  FinishAsyncProcessing();
 
   std::vector<PasswordForm*> matching_items;
   // No trace of www.facebook.com.
   matching_items = owned_keychain_adapter.PasswordsFillingForm(
       www_form->signon_realm, www_form->scheme);
   EXPECT_EQ(0u, matching_items.size());
-  login_db_->GetLogins(*www_form, &matching_items);
+  login_db()->GetLogins(*www_form, &matching_items);
   EXPECT_EQ(0u, matching_items.size());
   // No trace of m.facebook.com.
   matching_items = owned_keychain_adapter.PasswordsFillingForm(
       m_form.signon_realm, m_form.scheme);
   EXPECT_EQ(0u, matching_items.size());
-  login_db_->GetLogins(m_form, &matching_items);
+  login_db()->GetLogins(m_form, &matching_items);
   EXPECT_EQ(0u, matching_items.size());
 }
 
@@ -1262,7 +1329,7 @@
   }
 
   void WaitAndVerify(PasswordStoreMacTest* test) {
-    test->WaitForStoreUpdate();
+    test->FinishAsyncProcessing();
     ::testing::Mock::VerifyAndClearExpectations(this);
   }
 
@@ -1395,11 +1462,11 @@
       kSecAuthenticationTypeHTMLForm, "some.domain.com",
       kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z",
       "joe_user", "sekrit", false };
-  keychain_->AddTestItem(keychain_data);
+  keychain()->AddTestItem(keychain_data);
 
   // Add a password through the adapter. It has the "Chrome" creator tag.
   // However, it's not referenced by the password database.
-  MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_);
+  MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain());
   owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
   PasswordFormData www_form_data1 = {
       PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
@@ -1415,18 +1482,18 @@
       L"submit", L"not_joe_user", L"12345", true, false, 1 };
   www_form.reset(CreatePasswordFormFromData(www_form_data2));
   store_->AddLogin(*www_form);
-  WaitForStoreUpdate();
+  FinishAsyncProcessing();
 
   ScopedVector<PasswordForm> matching_items;
-  login_db_->GetLogins(*www_form, &matching_items.get());
+  login_db()->GetLogins(*www_form, &matching_items.get());
   EXPECT_EQ(1u, matching_items.size());
   matching_items.clear();
 
   store_->RemoveLoginsCreatedBetween(base::Time(), base::Time());
-  WaitForStoreUpdate();
+  FinishAsyncProcessing();
 
   // Check the second facebook form is gone.
-  login_db_->GetLogins(*www_form, &matching_items.get());
+  login_db()->GetLogins(*www_form, &matching_items.get());
   EXPECT_EQ(0u, matching_items.size());
 
   // Check the first facebook form is still there.
@@ -1442,3 +1509,91 @@
       "http://some.domain.com/insecure.html", PasswordForm::SCHEME_HTML);
   ASSERT_EQ(1u, matching_items.size());
 }
+
+// Open the store and immediately write to it and try to read it back, without
+// first waiting for the initialization to finish. If tasks are processed in
+// order, read/write operations will correctly be performed only after the
+// initialization has finished.
+TEST_F(PasswordStoreMacTest, StoreIsUsableImmediatelyAfterConstruction) {
+  ClosePasswordStore();
+
+  base::WaitableEvent event(false, false);
+  CreateAndInitPasswordStore(make_scoped_ptr<password_manager::LoginDatabase>(
+      new SlowToInitLoginDatabase(test_login_db_file_path(), &event)));
+
+  PasswordFormData www_form_data = {
+      PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
+      "http://www.facebook.com/index.html", "login", L"username", L"password",
+      L"submit", L"not_joe_user", L"12345", true, false, 1};
+  scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(www_form_data));
+  store()->AddLogin(*form);
+
+  MockPasswordStoreConsumer mock_consumer;
+  store()->GetLogins(*form, PasswordStore::ALLOW_PROMPT, &mock_consumer);
+
+  // Now the read/write tasks are scheduled, let the DB initialization proceed.
+  event.Signal();
+
+  mock_consumer.WaitOnGetPasswordStoreResults();
+  EXPECT_EQ(1u, mock_consumer.last_result.size());
+  EXPECT_TRUE(login_db());
+}
+
+// Verify that operations on a PasswordStore with a bad database cause no
+// explosions, but fail without side effect, return no data and trigger no
+// notifications.
+TEST_F(PasswordStoreMacTest, OperationsOnABadDatabaseSilentlyFail) {
+  ClosePasswordStore();
+  CreateAndInitPasswordStore(
+      make_scoped_ptr<password_manager::LoginDatabase>(new BadLoginDatabase));
+  FinishAsyncProcessing();
+  EXPECT_FALSE(login_db());
+
+  testing::StrictMock<MockPasswordStoreObserver> mock_observer;
+  store()->AddObserver(&mock_observer);
+
+  // Add a new autofillable login + a blacklisted login.
+  PasswordFormData www_form_data = {
+      PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
+      "http://www.facebook.com/index.html", "login", L"username", L"password",
+      L"submit", L"not_joe_user", L"12345", true, false, 1};
+  scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(www_form_data));
+  scoped_ptr<PasswordForm> blacklisted_form(new PasswordForm(*form));
+  blacklisted_form->signon_realm = "http://foo.example.com";
+  blacklisted_form->origin = GURL("http://foo.example.com/origin");
+  blacklisted_form->action = GURL("http://foo.example.com/action");
+  blacklisted_form->blacklisted_by_user = true;
+  store()->AddLogin(*form);
+  store()->AddLogin(*blacklisted_form);
+  FinishAsyncProcessing();
+
+  // Get all logins; autofillable logins; blacklisted logins.
+  MockPasswordStoreConsumer mock_consumer;
+  store()->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &mock_consumer);
+  mock_consumer.WaitOnGetPasswordStoreResults();
+  EXPECT_TRUE(mock_consumer.last_result.empty());
+  store()->GetAutofillableLogins(&mock_consumer);
+  mock_consumer.WaitOnGetPasswordStoreResults();
+  EXPECT_TRUE(mock_consumer.last_result.empty());
+  store()->GetBlacklistLogins(&mock_consumer);
+  mock_consumer.WaitOnGetPasswordStoreResults();
+  EXPECT_TRUE(mock_consumer.last_result.empty());
+
+  // Report metrics.
+  store()->ReportMetrics("Test Username", true);
+  FinishAsyncProcessing();
+
+  // Change the login.
+  form->password_value = base::ASCIIToUTF16("a different password");
+  store()->UpdateLogin(*form);
+  FinishAsyncProcessing();
+
+  // Delete one login; a range of logins.
+  store()->RemoveLogin(*form);
+  store()->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max());
+  store()->RemoveLoginsSyncedBetween(base::Time(), base::Time::Max());
+  FinishAsyncProcessing();
+
+  // Verify no notifications are fired during shutdown either.
+  ClosePasswordStore();
+}
diff --git a/chrome/browser/password_manager/password_store_win.cc b/chrome/browser/password_manager/password_store_win.cc
index 8f706d9..5d67daf 100644
--- a/chrome/browser/password_manager/password_store_win.cc
+++ b/chrome/browser/password_manager/password_store_win.cc
@@ -167,11 +167,11 @@
 PasswordStoreWin::PasswordStoreWin(
     scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
     scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
-    password_manager::LoginDatabase* login_database,
+    scoped_ptr<password_manager::LoginDatabase> login_db,
     const scoped_refptr<PasswordWebDataService>& web_data_service)
     : PasswordStoreDefault(main_thread_runner,
                            db_thread_runner,
-                           login_database) {
+                           login_db.Pass()) {
   db_handler_.reset(new DBHandler(web_data_service, this));
 }
 
diff --git a/chrome/browser/password_manager/password_store_win.h b/chrome/browser/password_manager/password_store_win.h
index 9ef4944..e3fcace 100644
--- a/chrome/browser/password_manager/password_store_win.h
+++ b/chrome/browser/password_manager/password_store_win.h
@@ -22,11 +22,13 @@
 // but also uses IE7 passwords if no others found.
 class PasswordStoreWin : public password_manager::PasswordStoreDefault {
  public:
-  // PasswordWebDataService is only used for IE7 password fetching.
+  // The |login_db| must not have been Init()-ed yet. It will be initialized in
+  // a deferred manner on the DB thread. The |web_data_service| is only used for
+  // IE7 password fetching.
   PasswordStoreWin(
       scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
       scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
-      password_manager::LoginDatabase* login_database,
+      scoped_ptr<password_manager::LoginDatabase> login_db,
       const scoped_refptr<PasswordWebDataService>& web_data_service);
 
   // PasswordStore:
diff --git a/chrome/browser/password_manager/password_store_win_unittest.cc b/chrome/browser/password_manager/password_store_win_unittest.cc
index f0849e7..7947243 100644
--- a/chrome/browser/password_manager/password_store_win_unittest.cc
+++ b/chrome/browser/password_manager/password_store_win_unittest.cc
@@ -116,9 +116,6 @@
 
     profile_.reset(new TestingProfile());
 
-    login_db_.reset(new LoginDatabase());
-    ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append(
-        FILE_PATH_LITERAL("login_test"))));
     base::FilePath path = temp_dir_.path().AppendASCII("web_data_test");
     wdbs_ = new WebDatabaseService(path,
         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
@@ -150,11 +147,15 @@
     db_thread_.Stop();
   }
 
+  base::FilePath test_login_db_file_path() const {
+    return temp_dir_.path().Append(FILE_PATH_LITERAL("login_test"));
+  }
+
   PasswordStoreWin* CreatePasswordStore() {
     return new PasswordStoreWin(
         base::MessageLoopProxy::current(),
         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB),
-        login_db_.release(),
+        make_scoped_ptr(new LoginDatabase(test_login_db_file_path())),
         wds_.get());
   }
 
@@ -165,7 +166,6 @@
 
   base::ScopedTempDir temp_dir_;
   scoped_ptr<TestingProfile> profile_;
-  scoped_ptr<LoginDatabase> login_db_;
   scoped_refptr<PasswordWebDataService> wds_;
   scoped_refptr<WebDatabaseService> wdbs_;
   scoped_refptr<PasswordStore> store_;
diff --git a/chrome/browser/password_manager/password_store_x.cc b/chrome/browser/password_manager/password_store_x.cc
index b5eb148..ab4df822 100644
--- a/chrome/browser/password_manager/password_store_x.cc
+++ b/chrome/browser/password_manager/password_store_x.cc
@@ -41,12 +41,15 @@
 PasswordStoreX::PasswordStoreX(
     scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
     scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
-    password_manager::LoginDatabase* login_db,
+    scoped_ptr<password_manager::LoginDatabase> login_db,
     NativeBackend* backend)
-    : PasswordStoreDefault(main_thread_runner, db_thread_runner, login_db),
+    : PasswordStoreDefault(main_thread_runner,
+                           db_thread_runner,
+                           login_db.Pass()),
       backend_(backend),
       migration_checked_(!backend),
-      allow_fallback_(false) {}
+      allow_fallback_(false) {
+}
 
 PasswordStoreX::~PasswordStoreX() {}
 
diff --git a/chrome/browser/password_manager/password_store_x.h b/chrome/browser/password_manager/password_store_x.h
index c28ad049..2907e0b 100644
--- a/chrome/browser/password_manager/password_store_x.h
+++ b/chrome/browser/password_manager/password_store_x.h
@@ -69,7 +69,7 @@
   // case this PasswordStoreX will act the same as PasswordStoreDefault.
   PasswordStoreX(scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
                  scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
-                 password_manager::LoginDatabase* login_db,
+                 scoped_ptr<password_manager::LoginDatabase> login_db,
                  NativeBackend* backend);
 
  private:
diff --git a/chrome/browser/password_manager/password_store_x_unittest.cc b/chrome/browser/password_manager/password_store_x_unittest.cc
index 45e81ff..c541847 100644
--- a/chrome/browser/password_manager/password_store_x_unittest.cc
+++ b/chrome/browser/password_manager/password_store_x_unittest.cc
@@ -239,13 +239,14 @@
  protected:
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-
-    login_db_.reset(new password_manager::LoginDatabase());
-    ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append("login_test")));
   }
 
   void TearDown() override { base::RunLoop().RunUntilIdle(); }
 
+  base::FilePath test_login_db_file_path() const {
+    return temp_dir_.path().Append(FILE_PATH_LITERAL("login_test"));
+  }
+
   PasswordStoreX::NativeBackend* GetBackend() {
     switch (GetParam()) {
       case FAILING_BACKEND:
@@ -259,7 +260,6 @@
 
   content::TestBrowserThreadBundle thread_bundle_;
 
-  scoped_ptr<password_manager::LoginDatabase> login_db_;
   base::ScopedTempDir temp_dir_;
 };
 
@@ -268,11 +268,11 @@
 }
 
 TEST_P(PasswordStoreXTest, Notifications) {
-  scoped_refptr<PasswordStoreX> store(
-      new PasswordStoreX(base::MessageLoopProxy::current(),
-                         base::MessageLoopProxy::current(),
-                         login_db_.release(),
-                         GetBackend()));
+  scoped_ptr<password_manager::LoginDatabase> login_db(
+      new password_manager::LoginDatabase(test_login_db_file_path()));
+  scoped_refptr<PasswordStoreX> store(new PasswordStoreX(
+      base::MessageLoopProxy::current(), base::MessageLoopProxy::current(),
+      login_db.Pass(), GetBackend()));
   store->Init(syncer::SyncableService::StartSyncFlare());
 
   password_manager::PasswordFormData form_data = {
@@ -345,14 +345,16 @@
   VectorOfForms expected_blacklisted;
   InitExpectedForms(false, 50, &expected_blacklisted);
 
+  const base::FilePath login_db_file = test_login_db_file_path();
+  scoped_ptr<password_manager::LoginDatabase> login_db(
+      new password_manager::LoginDatabase(login_db_file));
+  ASSERT_TRUE(login_db->Init());
+
   // Get the initial size of the login DB file, before we populate it.
   // This will be used later to make sure it gets back to this size.
-  const base::FilePath login_db_file = temp_dir_.path().Append("login_test");
   base::File::Info db_file_start_info;
   ASSERT_TRUE(base::GetFileInfo(login_db_file, &db_file_start_info));
 
-  password_manager::LoginDatabase* login_db = login_db_.get();
-
   // Populate the login DB with logins that should be migrated.
   for (VectorOfForms::iterator it = expected_autofillable.begin();
        it != expected_autofillable.end(); ++it) {
@@ -369,11 +371,10 @@
   EXPECT_GT(db_file_full_info.size, db_file_start_info.size);
 
   // Initializing the PasswordStore shouldn't trigger a native migration (yet).
-  scoped_refptr<PasswordStoreX> store(
-      new PasswordStoreX(base::MessageLoopProxy::current(),
-                         base::MessageLoopProxy::current(),
-                         login_db_.release(),
-                         GetBackend()));
+  login_db.reset(new password_manager::LoginDatabase(login_db_file));
+  scoped_refptr<PasswordStoreX> store(new PasswordStoreX(
+      base::MessageLoopProxy::current(), base::MessageLoopProxy::current(),
+      login_db.Pass(), GetBackend()));
   store->Init(syncer::SyncableService::StartSyncFlare());
 
   MockPasswordStoreConsumer consumer;
@@ -410,7 +411,7 @@
         .WillOnce(WithArg<0>(STLDeleteElements0()));
   }
 
-  LoginDatabaseQueryCallback(login_db, true, &ld_return);
+  LoginDatabaseQueryCallback(store->login_db(), true, &ld_return);
 
   // Wait for the login DB methods to execute.
   base::RunLoop().RunUntilIdle();
@@ -427,7 +428,7 @@
         .WillOnce(WithArg<0>(STLDeleteElements0()));
   }
 
-  LoginDatabaseQueryCallback(login_db, false, &ld_return);
+  LoginDatabaseQueryCallback(store->login_db(), false, &ld_return);
 
   // Wait for the login DB methods to execute.
   base::RunLoop().RunUntilIdle();
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc
index a9bf8a7..c70e650 100644
--- a/components/password_manager/core/browser/login_database.cc
+++ b/components/password_manager/core/browser/login_database.cc
@@ -153,13 +153,14 @@
 
 }  // namespace
 
-LoginDatabase::LoginDatabase() {
+LoginDatabase::LoginDatabase(const base::FilePath& db_path)
+    : db_path_(db_path) {
 }
 
 LoginDatabase::~LoginDatabase() {
 }
 
-bool LoginDatabase::Init(const base::FilePath& db_path) {
+bool LoginDatabase::Init() {
   // Set pragmas for a small, private database (based on WebDatabase).
   db_.set_page_size(2048);
   db_.set_cache_size(32);
@@ -171,7 +172,7 @@
     tracked_objects::ScopedTracker tracking_profile(
         FROM_HERE_WITH_EXPLICIT_FUNCTION("138903 LoginDatabase::Init db init"));
 
-    if (!db_.Open(db_path)) {
+    if (!db_.Open(db_path_)) {
       LOG(WARNING) << "Unable to open the password store database.";
       return false;
     }
@@ -199,9 +200,6 @@
     return false;
   }
 
-  // Save the path for DeleteDatabaseFile().
-  db_path_ = db_path;
-
   // If the file on disk is an older database version, bring it up to date.
   if (!MigrateOldVersionsAsNeeded()) {
     LOG(WARNING) << "Unable to migrate database";
@@ -891,7 +889,7 @@
   meta_table_.Reset();
   db_.Close();
   sql::Connection::Delete(db_path_);
-  return Init(db_path_);
+  return Init();
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/login_database.h b/components/password_manager/core/browser/login_database.h
index 7019338e..c3e83cf 100644
--- a/components/password_manager/core/browser/login_database.h
+++ b/components/password_manager/core/browser/login_database.h
@@ -25,12 +25,12 @@
 // the login information.
 class LoginDatabase {
  public:
-  LoginDatabase();
+  LoginDatabase(const base::FilePath& db_path);
   virtual ~LoginDatabase();
 
-  // Initialize the database with an sqlite file at the given path.
-  // If false is returned, no other method should be called.
-  bool Init(const base::FilePath& db_path);
+  // Actually creates/opens the database. If false is returned, no other method
+  // should be called.
+  virtual bool Init();
 
   // Reports usage metrics to UMA.
   void ReportMetrics(const std::string& sync_username,
diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc
index 9c3b6b9..110355d 100644
--- a/components/password_manager/core/browser/login_database_unittest.cc
+++ b/components/password_manager/core/browser/login_database_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/basictypes.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
@@ -79,9 +80,12 @@
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     file_ = temp_dir_.path().AppendASCII("TestMetadataStoreMacDatabase");
 
-    ASSERT_TRUE(db_.Init(file_));
+    db_.reset(new LoginDatabase(file_));
+    ASSERT_TRUE(db_->Init());
   }
 
+  LoginDatabase& db() { return *db_; }
+
   void TestNonHTMLFormPSLMatching(const PasswordForm::Scheme& scheme) {
     ScopedVector<PasswordForm> result;
 
@@ -108,9 +112,9 @@
     html_form.date_created = now;
 
     // Add them and make sure they are there.
-    EXPECT_EQ(AddChangeForForm(non_html_auth), db_.AddLogin(non_html_auth));
-    EXPECT_EQ(AddChangeForForm(html_form), db_.AddLogin(html_form));
-    EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
+    EXPECT_EQ(AddChangeForForm(non_html_auth), db().AddLogin(non_html_auth));
+    EXPECT_EQ(AddChangeForForm(html_form), db().AddLogin(html_form));
+    EXPECT_TRUE(db().GetAutofillableLogins(&result.get()));
     EXPECT_EQ(2U, result.size());
     result.clear();
 
@@ -119,16 +123,16 @@
     second_non_html_auth.signon_realm = "http://second.example.com/Realm";
 
     // This shouldn't match anything.
-    EXPECT_TRUE(db_.GetLogins(second_non_html_auth, &result.get()));
+    EXPECT_TRUE(db().GetLogins(second_non_html_auth, &result.get()));
     EXPECT_EQ(0U, result.size());
 
     // non-html auth still matches against itself.
-    EXPECT_TRUE(db_.GetLogins(non_html_auth, &result.get()));
+    EXPECT_TRUE(db().GetLogins(non_html_auth, &result.get()));
     ASSERT_EQ(1U, result.size());
     EXPECT_EQ(result[0]->signon_realm, "http://example.com/Realm");
 
     // Clear state.
-    db_.RemoveLoginsCreatedBetween(now, base::Time());
+    db().RemoveLoginsCreatedBetween(now, base::Time());
   }
 
   // Checks that a form of a given |scheme|, once stored, can be successfully
@@ -148,25 +152,25 @@
     ip_form.scheme = scheme;
     ip_form.date_created = now;
 
-    EXPECT_EQ(AddChangeForForm(ip_form), db_.AddLogin(ip_form));
-    EXPECT_TRUE(db_.GetLogins(ip_form, &result.get()));
+    EXPECT_EQ(AddChangeForForm(ip_form), db().AddLogin(ip_form));
+    EXPECT_TRUE(db().GetLogins(ip_form, &result.get()));
     ASSERT_EQ(1U, result.size());
     EXPECT_EQ(result[0]->signon_realm, origin);
 
     // Clear state.
-    db_.RemoveLoginsCreatedBetween(now, base::Time());
+    db().RemoveLoginsCreatedBetween(now, base::Time());
   }
 
   base::ScopedTempDir temp_dir_;
   base::FilePath file_;
-  LoginDatabase db_;
+  scoped_ptr<LoginDatabase> db_;
 };
 
 TEST_F(LoginDatabaseTest, Logins) {
   std::vector<PasswordForm*> result;
 
   // Verify the database is empty.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(0U, result.size());
 
   // Example password form.
@@ -175,15 +179,15 @@
 
   // Add it and make sure it is there and that all the fields were retrieved
   // correctly.
-  EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   ASSERT_EQ(1U, result.size());
   FormsAreEqual(form, *result[0]);
   delete result[0];
   result.clear();
 
   // Match against an exact copy.
-  EXPECT_TRUE(db_.GetLogins(form, &result));
+  EXPECT_TRUE(db().GetLogins(form, &result));
   ASSERT_EQ(1U, result.size());
   FormsAreEqual(form, *result[0]);
   delete result[0];
@@ -195,7 +199,7 @@
   form2.submit_element = ASCIIToUTF16("reallySignIn");
 
   // Match against an inexact copy
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
@@ -205,7 +209,7 @@
   form3.action = GURL("http://www.google.com/new/accounts/Login");
 
   // signon_realm is the same, should match.
-  EXPECT_TRUE(db_.GetLogins(form3, &result));
+  EXPECT_TRUE(db().GetLogins(form3, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
@@ -216,32 +220,32 @@
   form4.ssl_valid = true;
 
   // We have only an http record, so no match for this.
-  EXPECT_TRUE(db_.GetLogins(form4, &result));
+  EXPECT_TRUE(db().GetLogins(form4, &result));
   EXPECT_EQ(0U, result.size());
 
   // Let's imagine the user logs into the secure site.
-  EXPECT_EQ(AddChangeForForm(form4), db_.AddLogin(form4));
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(AddChangeForForm(form4), db().AddLogin(form4));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(2U, result.size());
   delete result[0];
   delete result[1];
   result.clear();
 
   // Now the match works
-  EXPECT_TRUE(db_.GetLogins(form4, &result));
+  EXPECT_TRUE(db().GetLogins(form4, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
 
   // The user chose to forget the original but not the new.
-  EXPECT_TRUE(db_.RemoveLogin(form));
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_TRUE(db().RemoveLogin(form));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
 
   // The old form wont match the new site (http vs https).
-  EXPECT_TRUE(db_.GetLogins(form, &result));
+  EXPECT_TRUE(db().GetLogins(form, &result));
   EXPECT_EQ(0U, result.size());
 
   // The user's request for the HTTPS site is intercepted
@@ -250,7 +254,7 @@
   form5.ssl_valid = 0;
 
   // It will match in this case.
-  EXPECT_TRUE(db_.GetLogins(form5, &result));
+  EXPECT_TRUE(db().GetLogins(form5, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
@@ -262,14 +266,14 @@
 
   // We update, and check to make sure it matches the
   // old form, and there is only one record.
-  EXPECT_EQ(UpdateChangeForForm(form6), db_.UpdateLogin(form6));
+  EXPECT_EQ(UpdateChangeForForm(form6), db().UpdateLogin(form6));
   // matches
-  EXPECT_TRUE(db_.GetLogins(form5, &result));
+  EXPECT_TRUE(db().GetLogins(form5, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
   // Only one record.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(1U, result.size());
   // Password element was updated.
 #if defined(OS_MACOSX) && !defined(OS_IOS)
@@ -284,8 +288,8 @@
   result.clear();
 
   // Make sure everything can disappear.
-  EXPECT_TRUE(db_.RemoveLogin(form4));
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_TRUE(db().RemoveLogin(form4));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(0U, result.size());
 }
 
@@ -293,7 +297,7 @@
   std::vector<PasswordForm*> result;
 
   // Verify the database is empty.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(0U, result.size());
 
   // Example password form.
@@ -311,14 +315,14 @@
   form.scheme = PasswordForm::SCHEME_HTML;
 
   // Add it and make sure it is there.
-  EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
 
   // Match against an exact copy.
-  EXPECT_TRUE(db_.GetLogins(form, &result));
+  EXPECT_TRUE(db().GetLogins(form, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
@@ -330,17 +334,17 @@
   form2.signon_realm = "https://mobile.foo.com/";
 
   // Match against the mobile site.
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(1U, result.size());
   EXPECT_EQ("https://mobile.foo.com/", result[0]->signon_realm);
   EXPECT_EQ("https://foo.com/", result[0]->original_signon_realm);
 
   // Try to remove PSL matched form
-  EXPECT_FALSE(db_.RemoveLogin(*result[0]));
+  EXPECT_FALSE(db().RemoveLogin(*result[0]));
   delete result[0];
   result.clear();
   // Ensure that the original form is still there
-  EXPECT_TRUE(db_.GetLogins(form, &result));
+  EXPECT_TRUE(db().GetLogins(form, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
@@ -372,7 +376,7 @@
   std::vector<PasswordForm*> result;
 
   // Verify the database is empty.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(0U, result.size());
 
   // Example password form.
@@ -390,14 +394,14 @@
   form.scheme = PasswordForm::SCHEME_HTML;
 
   // Add it and make sure it is there.
-  EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
 
   // Match against an exact copy.
-  EXPECT_TRUE(db_.GetLogins(form, &result));
+  EXPECT_TRUE(db().GetLogins(form, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
@@ -410,7 +414,7 @@
 
   // Match against the other site. Should not match since feature should not be
   // enabled for this domain.
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(0U, result.size());
 }
 
@@ -421,7 +425,7 @@
   std::vector<PasswordForm*> result;
 
   // Verify the database is empty.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(0U, result.size());
 
   // Example password form.
@@ -439,14 +443,14 @@
   form.scheme = PasswordForm::SCHEME_HTML;
 
   // Add it and make sure it is there.
-  EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
 
   // Match against an exact copy.
-  EXPECT_TRUE(db_.GetLogins(form, &result));
+  EXPECT_TRUE(db().GetLogins(form, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
@@ -458,7 +462,7 @@
   form2.signon_realm = "https://mobile.foo.com/";
 
   // Match against the mobile site.
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(1U, result.size());
   EXPECT_EQ("https://mobile.foo.com/", result[0]->signon_realm);
   EXPECT_EQ("https://foo.com/", result[0]->original_signon_realm);
@@ -479,8 +483,8 @@
   form.scheme = PasswordForm::SCHEME_HTML;
 
   // Add it and make sure it is there.
-  EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(2U, result.size());
   delete result[0];
   delete result[1];
@@ -493,7 +497,7 @@
   form3.signon_realm = "https://m.baz.com/";
 
   // Match against the mobile site of baz.com.
-  EXPECT_TRUE(db_.GetLogins(form3, &result));
+  EXPECT_TRUE(db().GetLogins(form3, &result));
   EXPECT_EQ(1U, result.size());
   EXPECT_EQ("https://m.baz.com/", result[0]->signon_realm);
   EXPECT_EQ("https://baz.com/", result[0]->original_signon_realm);
@@ -514,7 +518,7 @@
   std::vector<PasswordForm*> result;
 
   // Verify the database is empty.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(0U, result.size());
 
   // Example password form.
@@ -532,8 +536,8 @@
   form.scheme = PasswordForm::SCHEME_HTML;
 
   // Add it and make sure it is there.
-  EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
@@ -543,91 +547,91 @@
       GetFormWithNewSignonRealm(form, "http://www.foo-bar.com/");
 
   // Add it and make sure it is there.
-  EXPECT_EQ(AddChangeForForm(form_dash), db_.AddLogin(form_dash));
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(AddChangeForForm(form_dash), db().AddLogin(form_dash));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(2U, result.size());
   delete result[0];
   delete result[1];
   result.clear();
 
   // Match against an exact copy.
-  EXPECT_TRUE(db_.GetLogins(form, &result));
+  EXPECT_TRUE(db().GetLogins(form, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
 
   // www.foo.com should match.
   PasswordForm form2 = GetFormWithNewSignonRealm(form, "http://www.foo.com/");
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
 
   // a.b.foo.com should match.
   form2 = GetFormWithNewSignonRealm(form, "http://a.b.foo.com/");
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
 
   // a-b.foo.com should match.
   form2 = GetFormWithNewSignonRealm(form, "http://a-b.foo.com/");
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
 
   // foo-bar.com should match.
   form2 = GetFormWithNewSignonRealm(form, "http://foo-bar.com/");
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
 
   // www.foo-bar.com should match.
   form2 = GetFormWithNewSignonRealm(form, "http://www.foo-bar.com/");
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
 
   // a.b.foo-bar.com should match.
   form2 = GetFormWithNewSignonRealm(form, "http://a.b.foo-bar.com/");
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
 
   // a-b.foo-bar.com should match.
   form2 = GetFormWithNewSignonRealm(form, "http://a-b.foo-bar.com/");
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(1U, result.size());
   delete result[0];
   result.clear();
 
   // foo.com with port 1337 should not match.
   form2 = GetFormWithNewSignonRealm(form, "http://foo.com:1337/");
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(0U, result.size());
 
   // http://foo.com should not match since the scheme is wrong.
   form2 = GetFormWithNewSignonRealm(form, "https://foo.com/");
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(0U, result.size());
 
   // notfoo.com should not match.
   form2 = GetFormWithNewSignonRealm(form, "http://notfoo.com/");
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(0U, result.size());
 
   // baz.com should not match.
   form2 = GetFormWithNewSignonRealm(form, "http://baz.com/");
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(0U, result.size());
 
   // foo-baz.com should not match.
   form2 = GetFormWithNewSignonRealm(form, "http://foo-baz.com/");
-  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_TRUE(db().GetLogins(form2, &result));
   EXPECT_EQ(0U, result.size());
 }
 
@@ -667,7 +671,7 @@
   std::vector<PasswordForm*> result;
 
   // Verify the database is empty.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(0U, result.size());
 
   base::Time now = base::Time::Now();
@@ -675,37 +679,37 @@
 
   // Create one with a 0 time.
   EXPECT_TRUE(
-      AddTimestampedLogin(&db_, "http://1.com", "foo1", base::Time(), true));
+      AddTimestampedLogin(&db(), "http://1.com", "foo1", base::Time(), true));
   // Create one for now and +/- 1 day.
   EXPECT_TRUE(
-      AddTimestampedLogin(&db_, "http://2.com", "foo2", now - one_day, true));
-  EXPECT_TRUE(AddTimestampedLogin(&db_, "http://3.com", "foo3", now, true));
+      AddTimestampedLogin(&db(), "http://2.com", "foo2", now - one_day, true));
+  EXPECT_TRUE(AddTimestampedLogin(&db(), "http://3.com", "foo3", now, true));
   EXPECT_TRUE(
-      AddTimestampedLogin(&db_, "http://4.com", "foo4", now + one_day, true));
+      AddTimestampedLogin(&db(), "http://4.com", "foo4", now + one_day, true));
 
   // Verify inserts worked.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(4U, result.size());
   ClearResults(&result);
 
   // Get everything from today's date and on.
-  EXPECT_TRUE(db_.GetLoginsCreatedBetween(now, base::Time(), &result));
+  EXPECT_TRUE(db().GetLoginsCreatedBetween(now, base::Time(), &result));
   EXPECT_EQ(2U, result.size());
   ClearResults(&result);
 
   // Delete everything from today's date and on.
-  db_.RemoveLoginsCreatedBetween(now, base::Time());
+  db().RemoveLoginsCreatedBetween(now, base::Time());
 
   // Should have deleted half of what we inserted.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(2U, result.size());
   ClearResults(&result);
 
   // Delete with 0 date (should delete all).
-  db_.RemoveLoginsCreatedBetween(base::Time(), base::Time());
+  db().RemoveLoginsCreatedBetween(base::Time(), base::Time());
 
   // Verify nothing is left.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   EXPECT_EQ(0U, result.size());
 }
 
@@ -717,41 +721,41 @@
 
   // Create one with a 0 time.
   EXPECT_TRUE(
-      AddTimestampedLogin(&db_, "http://1.com", "foo1", base::Time(), false));
+      AddTimestampedLogin(&db(), "http://1.com", "foo1", base::Time(), false));
   // Create one for now and +/- 1 day.
   EXPECT_TRUE(
-      AddTimestampedLogin(&db_, "http://2.com", "foo2", now - one_day, false));
-  EXPECT_TRUE(AddTimestampedLogin(&db_, "http://3.com", "foo3", now, false));
+      AddTimestampedLogin(&db(), "http://2.com", "foo2", now - one_day, false));
+  EXPECT_TRUE(AddTimestampedLogin(&db(), "http://3.com", "foo3", now, false));
   EXPECT_TRUE(
-      AddTimestampedLogin(&db_, "http://4.com", "foo4", now + one_day, false));
+      AddTimestampedLogin(&db(), "http://4.com", "foo4", now + one_day, false));
 
   // Verify inserts worked.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result.get()));
   EXPECT_EQ(4U, result.size());
   result.clear();
 
   // Get everything from today's date and on.
-  EXPECT_TRUE(db_.GetLoginsSyncedBetween(now, base::Time(), &result.get()));
+  EXPECT_TRUE(db().GetLoginsSyncedBetween(now, base::Time(), &result.get()));
   ASSERT_EQ(2U, result.size());
   EXPECT_EQ("http://3.com", result[0]->signon_realm);
   EXPECT_EQ("http://4.com", result[1]->signon_realm);
   result.clear();
 
   // Delete everything from today's date and on.
-  db_.RemoveLoginsSyncedBetween(now, base::Time());
+  db().RemoveLoginsSyncedBetween(now, base::Time());
 
   // Should have deleted half of what we inserted.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result.get()));
   ASSERT_EQ(2U, result.size());
   EXPECT_EQ("http://1.com", result[0]->signon_realm);
   EXPECT_EQ("http://2.com", result[1]->signon_realm);
   result.clear();
 
   // Delete with 0 date (should delete all).
-  db_.RemoveLoginsSyncedBetween(base::Time(), now);
+  db().RemoveLoginsSyncedBetween(base::Time(), now);
 
   // Verify nothing is left.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result.get()));
   EXPECT_EQ(0U, result.size());
 }
 
@@ -759,7 +763,7 @@
   std::vector<PasswordForm*> result;
 
   // Verify the database is empty.
-  EXPECT_TRUE(db_.GetBlacklistLogins(&result));
+  EXPECT_TRUE(db().GetBlacklistLogins(&result));
   ASSERT_EQ(0U, result.size());
 
   // Save a form as blacklisted.
@@ -779,20 +783,20 @@
   form.avatar_url = GURL("https://accounts.google.com/Avatar");
   form.federation_url = GURL("https://accounts.google.com/federation");
   form.is_zero_click = true;
-  EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
+  EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
 
   // Get all non-blacklisted logins (should be none).
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   ASSERT_EQ(0U, result.size());
 
   // GetLogins should give the blacklisted result.
-  EXPECT_TRUE(db_.GetLogins(form, &result));
+  EXPECT_TRUE(db().GetLogins(form, &result));
   ASSERT_EQ(1U, result.size());
   FormsAreEqual(form, *result[0]);
   ClearResults(&result);
 
   // So should GetAllBlacklistedLogins.
-  EXPECT_TRUE(db_.GetBlacklistLogins(&result));
+  EXPECT_TRUE(db().GetBlacklistLogins(&result));
   ASSERT_EQ(1U, result.size());
   FormsAreEqual(form, *result[0]);
   ClearResults(&result);
@@ -818,7 +822,7 @@
 TEST_F(LoginDatabaseTest, UpdateIncompleteCredentials) {
   std::vector<autofill::PasswordForm*> result;
   // Verify the database is empty.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result));
   ASSERT_EQ(0U, result.size());
 
   // Save an incomplete form. Note that it only has a few fields set, ex. it's
@@ -834,7 +838,7 @@
   incomplete_form.preferred = true;
   incomplete_form.blacklisted_by_user = false;
   incomplete_form.scheme = PasswordForm::SCHEME_HTML;
-  EXPECT_EQ(AddChangeForForm(incomplete_form), db_.AddLogin(incomplete_form));
+  EXPECT_EQ(AddChangeForForm(incomplete_form), db().AddLogin(incomplete_form));
 
   // A form on some website. It should trigger a match with the stored one.
   PasswordForm encountered_form;
@@ -846,7 +850,7 @@
   encountered_form.submit_element = ASCIIToUTF16("signIn");
 
   // Get matches for encountered_form.
-  EXPECT_TRUE(db_.GetLogins(encountered_form, &result));
+  EXPECT_TRUE(db().GetLogins(encountered_form, &result));
   ASSERT_EQ(1U, result.size());
   EXPECT_EQ(incomplete_form.origin, result[0]->origin);
   EXPECT_EQ(incomplete_form.signon_realm, result[0]->signon_realm);
@@ -878,11 +882,11 @@
   completed_form.username_element = encountered_form.username_element;
   completed_form.password_element = encountered_form.password_element;
   completed_form.submit_element = encountered_form.submit_element;
-  EXPECT_EQ(AddChangeForForm(completed_form), db_.AddLogin(completed_form));
-  EXPECT_TRUE(db_.RemoveLogin(incomplete_form));
+  EXPECT_EQ(AddChangeForForm(completed_form), db().AddLogin(completed_form));
+  EXPECT_TRUE(db().RemoveLogin(incomplete_form));
 
   // Get matches for encountered_form again.
-  EXPECT_TRUE(db_.GetLogins(encountered_form, &result));
+  EXPECT_TRUE(db().GetLogins(encountered_form, &result));
   ASSERT_EQ(1U, result.size());
 
   // This time we should have all the info available.
@@ -908,7 +912,7 @@
   incomplete_form.preferred = true;
   incomplete_form.blacklisted_by_user = false;
   incomplete_form.scheme = PasswordForm::SCHEME_HTML;
-  EXPECT_EQ(AddChangeForForm(incomplete_form), db_.AddLogin(incomplete_form));
+  EXPECT_EQ(AddChangeForForm(incomplete_form), db().AddLogin(incomplete_form));
 
   // Save a complete version of the previous form. Both forms could exist if
   // the user created the complete version before importing the incomplete
@@ -920,22 +924,23 @@
   complete_form.submit_element = ASCIIToUTF16("submit");
 
   // An update fails because the primary key for |complete_form| is different.
-  EXPECT_EQ(PasswordStoreChangeList(), db_.UpdateLogin(complete_form));
-  EXPECT_EQ(AddChangeForForm(complete_form), db_.AddLogin(complete_form));
+  EXPECT_EQ(PasswordStoreChangeList(), db().UpdateLogin(complete_form));
+  EXPECT_EQ(AddChangeForForm(complete_form), db().AddLogin(complete_form));
 
   // Make sure both passwords exist.
   ScopedVector<autofill::PasswordForm> result;
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result.get()));
   ASSERT_EQ(2U, result.size());
   result.clear();
 
   // Simulate the user changing their password.
   complete_form.password_value = ASCIIToUTF16("new_password");
   complete_form.date_synced = base::Time::Now();
-  EXPECT_EQ(UpdateChangeForForm(complete_form), db_.UpdateLogin(complete_form));
+  EXPECT_EQ(UpdateChangeForForm(complete_form),
+            db().UpdateLogin(complete_form));
 
   // Both still exist now.
-  EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
+  EXPECT_TRUE(db().GetAutofillableLogins(&result.get()));
   ASSERT_EQ(2U, result.size());
 
 #if defined(OS_MACOSX) && !defined(OS_IOS)
@@ -960,14 +965,14 @@
   form.preferred = true;
   form.blacklisted_by_user = false;
   form.scheme = PasswordForm::SCHEME_HTML;
-  EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
+  EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
 
   // Add almost the same form again.
   form.times_used++;
   PasswordStoreChangeList list;
   list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
   list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
-  EXPECT_EQ(list, db_.AddLogin(form));
+  EXPECT_EQ(list, db().AddLogin(form));
 }
 
 TEST_F(LoginDatabaseTest, AddWrongForm) {
@@ -981,12 +986,12 @@
   form.preferred = true;
   form.blacklisted_by_user = false;
   form.scheme = PasswordForm::SCHEME_HTML;
-  EXPECT_EQ(PasswordStoreChangeList(), db_.AddLogin(form));
+  EXPECT_EQ(PasswordStoreChangeList(), db().AddLogin(form));
 
   // |signon_realm| shouldn't be empty.
   form.origin = GURL("http://accounts.google.com/LoginAuth");
   form.signon_realm.clear();
-  EXPECT_EQ(PasswordStoreChangeList(), db_.AddLogin(form));
+  EXPECT_EQ(PasswordStoreChangeList(), db().AddLogin(form));
 }
 
 TEST_F(LoginDatabaseTest, UpdateLogin) {
@@ -999,7 +1004,7 @@
   form.preferred = true;
   form.blacklisted_by_user = false;
   form.scheme = PasswordForm::SCHEME_HTML;
-  EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
+  EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
 
   form.action = GURL("http://accounts.google.com/login");
   form.password_value = ASCIIToUTF16("my_new_password");
@@ -1017,10 +1022,10 @@
   form.avatar_url = GURL("https://accounts.google.com/Avatar");
   form.federation_url = GURL("https://accounts.google.com/federation");
   form.is_zero_click = true;
-  EXPECT_EQ(UpdateChangeForForm(form), db_.UpdateLogin(form));
+  EXPECT_EQ(UpdateChangeForForm(form), db().UpdateLogin(form));
 
   ScopedVector<autofill::PasswordForm> result;
-  EXPECT_TRUE(db_.GetLogins(form, &result.get()));
+  EXPECT_TRUE(db().GetLogins(form, &result.get()));
   ASSERT_EQ(1U, result.size());
 #if defined(OS_MACOSX) && !defined(OS_IOS)
   // On Mac, passwords are not stored in login database, instead they're in
@@ -1037,29 +1042,29 @@
   password_form.password_value = ASCIIToUTF16("test");
   password_form.signon_realm = "http://example.com/";
   password_form.times_used = 0;
-  EXPECT_EQ(AddChangeForForm(password_form), db_.AddLogin(password_form));
+  EXPECT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
 
   password_form.username_value = ASCIIToUTF16("test2@gmail.com");
   password_form.times_used = 1;
-  EXPECT_EQ(AddChangeForForm(password_form), db_.AddLogin(password_form));
+  EXPECT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
 
   password_form.origin = GURL("http://second.example.com");
   password_form.signon_realm = "http://second.example.com";
   password_form.times_used = 3;
-  EXPECT_EQ(AddChangeForForm(password_form), db_.AddLogin(password_form));
+  EXPECT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
 
   password_form.username_value = ASCIIToUTF16("test3@gmail.com");
   password_form.type = PasswordForm::TYPE_GENERATED;
   password_form.times_used = 2;
-  EXPECT_EQ(AddChangeForForm(password_form), db_.AddLogin(password_form));
+  EXPECT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
 
   password_form.origin = GURL("http://third.example.com/");
   password_form.signon_realm = "http://third.example.com/";
   password_form.times_used = 4;
-  EXPECT_EQ(AddChangeForForm(password_form), db_.AddLogin(password_form));
+  EXPECT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
 
   base::HistogramTester histogram_tester;
-  db_.ReportMetrics("", false);
+  db().ReportMetrics("", false);
 
   histogram_tester.ExpectUniqueSample(
       "PasswordManager.TotalAccounts.UserCreated.WithoutCustomPassphrase",
@@ -1205,8 +1210,8 @@
     {
       // Assert that the database was successfully opened and updated
       // to current version.
-      LoginDatabase db;
-      ASSERT_TRUE(db.Init(database_path_));
+      LoginDatabase db(database_path_);
+      ASSERT_TRUE(db.Init());
       // Verifies that the final version can save all the appropriate fields.
       std::vector<PasswordForm*> result;
       PasswordForm form;
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index 0844acc..977c2d3 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -51,6 +51,11 @@
 // Interface for storing form passwords in a platform-specific secure way.
 // The login request/manipulation API is not threadsafe and must be used
 // from the UI thread.
+// Implementations, however, should carry out most tasks asynchronously on a
+// background thread: the base class provides functionality to facilitate this.
+// I/O heavy initialization should also be performed asynchronously in this
+// manner. If this deferred initialization fails, all subsequent method calls
+// should fail without side effects, return no data, and send no notifications.
 // PasswordStoreSync is a hidden base class because only PasswordSyncableService
 // needs to access these methods.
 class PasswordStore : protected PasswordStoreSync,
diff --git a/components/password_manager/core/browser/password_store_default.cc b/components/password_manager/core/browser/password_store_default.cc
index 627472d..abebed9a 100644
--- a/components/password_manager/core/browser/password_store_default.cc
+++ b/components/password_manager/core/browser/password_store_default.cc
@@ -18,17 +18,34 @@
 PasswordStoreDefault::PasswordStoreDefault(
     scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
     scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
-    LoginDatabase* login_db)
-    : PasswordStore(main_thread_runner, db_thread_runner), login_db_(login_db) {
-  DCHECK(login_db);
+    scoped_ptr<LoginDatabase> login_db)
+    : PasswordStore(main_thread_runner, db_thread_runner),
+      login_db_(login_db.Pass()) {
 }
 
 PasswordStoreDefault::~PasswordStoreDefault() {
 }
 
+bool PasswordStoreDefault::Init(
+    const syncer::SyncableService::StartSyncFlare& flare) {
+  ScheduleTask(base::Bind(&PasswordStoreDefault::InitOnDBThread, this));
+  return PasswordStore::Init(flare);
+}
+
+void PasswordStoreDefault::InitOnDBThread() {
+  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(login_db_);
+  if (!login_db_->Init()) {
+    login_db_.reset();
+    LOG(ERROR) << "Could not create/open login database.";
+  }
+}
+
 void PasswordStoreDefault::ReportMetricsImpl(
     const std::string& sync_username,
     bool custom_passphrase_sync_enabled) {
+  if (!login_db_)
+    return;
   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
   login_db_->ReportMetrics(sync_username, custom_passphrase_sync_enabled);
 }
@@ -36,12 +53,16 @@
 PasswordStoreChangeList PasswordStoreDefault::AddLoginImpl(
     const PasswordForm& form) {
   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  if (!login_db_)
+    return PasswordStoreChangeList();
   return login_db_->AddLogin(form);
 }
 
 PasswordStoreChangeList PasswordStoreDefault::UpdateLoginImpl(
     const PasswordForm& form) {
   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  if (!login_db_)
+    return PasswordStoreChangeList();
   return login_db_->UpdateLogin(form);
 }
 
@@ -49,7 +70,7 @@
     const PasswordForm& form) {
   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
   PasswordStoreChangeList changes;
-  if (login_db_->RemoveLogin(form))
+  if (login_db_ && login_db_->RemoveLogin(form))
     changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
   return changes;
 }
@@ -59,7 +80,8 @@
     base::Time delete_end) {
   std::vector<PasswordForm*> forms;
   PasswordStoreChangeList changes;
-  if (login_db_->GetLoginsCreatedBetween(delete_begin, delete_end, &forms)) {
+  if (login_db_ &&
+      login_db_->GetLoginsCreatedBetween(delete_begin, delete_end, &forms)) {
     if (login_db_->RemoveLoginsCreatedBetween(delete_begin, delete_end)) {
       for (std::vector<PasswordForm*>::const_iterator it = forms.begin();
            it != forms.end(); ++it) {
@@ -78,7 +100,8 @@
     base::Time delete_end) {
   std::vector<PasswordForm*> forms;
   PasswordStoreChangeList changes;
-  if (login_db_->GetLoginsSyncedBetween(delete_begin, delete_end, &forms)) {
+  if (login_db_ &&
+      login_db_->GetLoginsSyncedBetween(delete_begin, delete_end, &forms)) {
     if (login_db_->RemoveLoginsSyncedBetween(delete_begin, delete_end)) {
       for (std::vector<PasswordForm*>::const_iterator it = forms.begin();
            it != forms.end(); ++it) {
@@ -97,7 +120,8 @@
     AuthorizationPromptPolicy prompt_policy,
     const ConsumerCallbackRunner& callback_runner) {
   std::vector<PasswordForm*> matched_forms;
-  login_db_->GetLogins(form, &matched_forms);
+  if (login_db_)
+    login_db_->GetLogins(form, &matched_forms);
   callback_runner.Run(matched_forms);
 }
 
@@ -115,13 +139,13 @@
 bool PasswordStoreDefault::FillAutofillableLogins(
     std::vector<PasswordForm*>* forms) {
   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
-  return login_db_->GetAutofillableLogins(forms);
+  return login_db_ && login_db_->GetAutofillableLogins(forms);
 }
 
 bool PasswordStoreDefault::FillBlacklistLogins(
     std::vector<PasswordForm*>* forms) {
   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
-  return login_db_->GetBlacklistLogins(forms);
+  return login_db_ && login_db_->GetBlacklistLogins(forms);
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_default.h b/components/password_manager/core/browser/password_store_default.h
index 7f42c19..faaebec 100644
--- a/components/password_manager/core/browser/password_store_default.h
+++ b/components/password_manager/core/browser/password_store_default.h
@@ -17,15 +17,24 @@
 // the LoginDatabase.
 class PasswordStoreDefault : public PasswordStore {
  public:
-  // Takes ownership of |login_db|.
+  // The |login_db| must not have been Init()-ed yet. It will be initialized in
+  // a deferred manner on the DB thread.
   PasswordStoreDefault(
       scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
       scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
-      LoginDatabase* login_db);
+      scoped_ptr<LoginDatabase> login_db);
+
+  bool Init(const syncer::SyncableService::StartSyncFlare& flare) override;
+
+  // To be used only for testing.
+  LoginDatabase* login_db() const { return login_db_.get(); }
 
  protected:
   ~PasswordStoreDefault() override;
 
+  // Opens |login_db_| on the DB thread.
+  void InitOnDBThread();
+
   // Implements PasswordStore interface.
   void ReportMetricsImpl(const std::string& sync_username,
                          bool custom_passphrase_sync_enabled) override;
@@ -57,6 +66,10 @@
   }
 
  private:
+  // The login SQL database. The LoginDatabase instance is received via the
+  // in an uninitialized state, so as to allow injecting mocks, then Init() is
+  // called on the DB thread in a deferred manner. If opening the DB fails,
+  // |login_db_| will be reset and stay NULL for the lifetime of |this|.
   scoped_ptr<LoginDatabase> login_db_;
 
   DISALLOW_COPY_AND_ASSIGN(PasswordStoreDefault);
diff --git a/components/password_manager/core/browser/password_store_default_unittest.cc b/components/password_manager/core/browser/password_store_default_unittest.cc
index 7b3bcd263..b4d87c3 100644
--- a/components/password_manager/core/browser/password_store_default_unittest.cc
+++ b/components/password_manager/core/browser/password_store_default_unittest.cc
@@ -5,12 +5,14 @@
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/prefs/pref_service.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "components/password_manager/core/browser/login_database.h"
 #include "components/password_manager/core/browser/password_form_data.h"
 #include "components/password_manager/core/browser/password_store_change.h"
 #include "components/password_manager/core/browser/password_store_consumer.h"
@@ -38,21 +40,52 @@
   MOCK_METHOD1(OnLoginsChanged, void(const PasswordStoreChangeList& changes));
 };
 
+// A mock LoginDatabase that simulates a failing Init() method.
+class BadLoginDatabase : public LoginDatabase {
+ public:
+  BadLoginDatabase() : LoginDatabase(base::FilePath()) {}
+  ~BadLoginDatabase() override {}
+
+  // LoginDatabase:
+  bool Init() override { return false; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BadLoginDatabase);
+};
+
+PasswordFormData CreateTestPasswordFormData() {
+  PasswordFormData data = {
+    PasswordForm::SCHEME_HTML,
+    "http://bar.example.com",
+    "http://bar.example.com/origin",
+    "http://bar.example.com/action",
+    L"submit_element",
+    L"username_element",
+    L"password_element",
+    L"username_value",
+    L"password_value",
+    true,
+    false,
+    1
+  };
+  return data;
+}
+
 }  // anonymous namespace
 
 class PasswordStoreDefaultTest : public testing::Test {
  protected:
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    login_db_.reset(new LoginDatabase());
-    ASSERT_TRUE(login_db_->Init(
-        temp_dir_.path().Append(FILE_PATH_LITERAL("login_test"))));
   }
 
   void TearDown() override { ASSERT_TRUE(temp_dir_.Delete()); }
 
+  base::FilePath test_login_db_file_path() const {
+    return temp_dir_.path().Append(FILE_PATH_LITERAL("login_test"));
+  }
+
   base::MessageLoopForUI message_loop_;
-  scoped_ptr<LoginDatabase> login_db_;
   base::ScopedTempDir temp_dir_;
 };
 
@@ -62,9 +95,8 @@
 
 TEST_F(PasswordStoreDefaultTest, NonASCIIData) {
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::MessageLoopProxy::current(),
-      base::MessageLoopProxy::current(),
-      login_db_.release()));
+      base::MessageLoopProxy::current(), base::MessageLoopProxy::current(),
+      make_scoped_ptr(new LoginDatabase(test_login_db_file_path()))));
   store->Init(syncer::SyncableService::StartSyncFlare());
 
   // Some non-ASCII password form data.
@@ -108,23 +140,12 @@
 
 TEST_F(PasswordStoreDefaultTest, Notifications) {
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::MessageLoopProxy::current(),
-      base::MessageLoopProxy::current(),
-      login_db_.release()));
+      base::MessageLoopProxy::current(), base::MessageLoopProxy::current(),
+      make_scoped_ptr(new LoginDatabase(test_login_db_file_path()))));
   store->Init(syncer::SyncableService::StartSyncFlare());
 
-  PasswordFormData form_data =
-  { PasswordForm::SCHEME_HTML,
-    "http://bar.example.com",
-    "http://bar.example.com/origin",
-    "http://bar.example.com/action",
-    L"submit_element",
-    L"username_element",
-    L"password_element",
-    L"username_value",
-    L"password_value",
-    true, false, 1 };
-  scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
+  scoped_ptr<PasswordForm> form(
+      CreatePasswordFormFromData(CreateTestPasswordFormData()));
 
   MockPasswordStoreObserver observer;
   store->AddObserver(&observer);
@@ -170,4 +191,68 @@
   base::MessageLoop::current()->RunUntilIdle();
 }
 
+// Verify that operations on a PasswordStore with a bad database cause no
+// explosions, but fail without side effect, return no data and trigger no
+// notifications.
+TEST_F(PasswordStoreDefaultTest, OperationsOnABadDatabaseSilentlyFail) {
+  scoped_refptr<PasswordStoreDefault> bad_store(new PasswordStoreDefault(
+      base::MessageLoopProxy::current(), base::MessageLoopProxy::current(),
+      make_scoped_ptr<LoginDatabase>(new BadLoginDatabase)));
+
+  bad_store->Init(syncer::SyncableService::StartSyncFlare());
+  base::MessageLoop::current()->RunUntilIdle();
+  ASSERT_EQ(nullptr, bad_store->login_db());
+
+  testing::StrictMock<MockPasswordStoreObserver> mock_observer;
+  bad_store->AddObserver(&mock_observer);
+
+  // Add a new autofillable login + a blacklisted login.
+  scoped_ptr<PasswordForm> form(
+      CreatePasswordFormFromData(CreateTestPasswordFormData()));
+  scoped_ptr<PasswordForm> blacklisted_form(new PasswordForm(*form));
+  blacklisted_form->signon_realm = "http://foo.example.com";
+  blacklisted_form->origin = GURL("http://foo.example.com/origin");
+  blacklisted_form->action = GURL("http://foo.example.com/action");
+  blacklisted_form->blacklisted_by_user = true;
+  bad_store->AddLogin(*form);
+  bad_store->AddLogin(*blacklisted_form);
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // Get all logins; autofillable logins; blacklisted logins.
+  testing::StrictMock<MockPasswordStoreConsumer> mock_consumer;
+  EXPECT_CALL(mock_consumer, OnGetPasswordStoreResults(testing::ElementsAre()));
+  bad_store->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &mock_consumer);
+  base::MessageLoop::current()->RunUntilIdle();
+  testing::Mock::VerifyAndClearExpectations(&mock_consumer);
+  EXPECT_CALL(mock_consumer, OnGetPasswordStoreResults(testing::ElementsAre()));
+  bad_store->GetAutofillableLogins(&mock_consumer);
+  base::MessageLoop::current()->RunUntilIdle();
+  testing::Mock::VerifyAndClearExpectations(&mock_consumer);
+  EXPECT_CALL(mock_consumer, OnGetPasswordStoreResults(testing::ElementsAre()));
+  bad_store->GetBlacklistLogins(&mock_consumer);
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // Report metrics.
+  bad_store->ReportMetrics("Test Username", true);
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // Change the login.
+  form->password_value = base::ASCIIToUTF16("a different password");
+  bad_store->UpdateLogin(*form);
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // Delete one login; a range of logins.
+  bad_store->RemoveLogin(*form);
+  base::MessageLoop::current()->RunUntilIdle();
+  bad_store->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max());
+  base::MessageLoop::current()->RunUntilIdle();
+  bad_store->RemoveLoginsSyncedBetween(base::Time(), base::Time::Max());
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // Ensure no notifications and no explosions during shutdown either.
+  bad_store->RemoveObserver(&mock_observer);
+  bad_store->Shutdown();
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc
index ec6e068..41fa46b 100644
--- a/components/password_manager/core/browser/password_store_unittest.cc
+++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -45,15 +45,15 @@
  protected:
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    login_db_.reset(new LoginDatabase());
-    ASSERT_TRUE(login_db_->Init(
-        temp_dir_.path().Append(FILE_PATH_LITERAL("login_test"))));
   }
 
   void TearDown() override { ASSERT_TRUE(temp_dir_.Delete()); }
 
+  base::FilePath test_login_db_file_path() const {
+    return temp_dir_.path().Append(FILE_PATH_LITERAL("login_test"));
+  }
+
   base::MessageLoopForUI message_loop_;
-  scoped_ptr<LoginDatabase> login_db_;
   base::ScopedTempDir temp_dir_;
 };
 
@@ -63,9 +63,8 @@
 
 TEST_F(PasswordStoreTest, IgnoreOldWwwGoogleLogins) {
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::MessageLoopProxy::current(),
-      base::MessageLoopProxy::current(),
-      login_db_.release()));
+      base::MessageLoopProxy::current(), base::MessageLoopProxy::current(),
+      make_scoped_ptr(new LoginDatabase(test_login_db_file_path()))));
   store->Init(syncer::SyncableService::StartSyncFlare());
 
   const time_t cutoff = 1325376000;  // 00:00 Jan 1 2012 UTC
@@ -193,9 +192,8 @@
 
 TEST_F(PasswordStoreTest, StartSyncFlare) {
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::MessageLoopProxy::current(),
-      base::MessageLoopProxy::current(),
-      login_db_.release()));
+      base::MessageLoopProxy::current(), base::MessageLoopProxy::current(),
+      make_scoped_ptr(new LoginDatabase(test_login_db_file_path()))));
   StartSyncFlareMock mock;
   store->Init(
       base::Bind(&StartSyncFlareMock::StartSyncFlare, base::Unretained(&mock)));