Remove profile info cache entry on user removal on Chrome OS.

Chrome OS removes users when profiles are not loaded, and Chrome does not know
the exact profile path until it is mounted. So we need to be able to remove
entries from ProfileInfoCache based solely on AccountId.

This Cl implements removal of cache entries given the AccountId and engages it
on Chrome OS.

TBR=alemate@chromium.org

(cherry picked from commit 4084f503be1913290db968dc81f6ceb9fe796fbc)

Bug: 808125
Change-Id: I9f8e3a5f1004d119425b92a4bdc3d8011a526dd5
Reviewed-on: https://chromium-review.googlesource.com/905751
Reviewed-by: anthonyvd <anthonyvd@chromium.org>
Reviewed-by: Bernhard Bauer <bauerb@chromium.org>
Commit-Queue: Alexander Alekseev <alemate@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#537905}
Reviewed-on: https://chromium-review.googlesource.com/938571
Reviewed-by: Alexander Alekseev <alemate@chromium.org>
Cr-Commit-Position: refs/branch-heads/3325@{#603}
Cr-Branched-From: bc084a8b5afa3744a74927344e304c02ae54189f-refs/heads/master@{#530369}
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index 70584b4..975d36c 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -60,6 +60,8 @@
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/permissions_updater.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/easy_unlock_service.h"
 #include "chrome/browser/supervised_user/chromeos/manager_password_service_factory.h"
 #include "chrome/browser/supervised_user/chromeos/supervised_user_password_service_factory.h"
@@ -475,6 +477,9 @@
     // Owner is not allowed to be removed from the device.
     return;
   }
+  g_browser_process->profile_manager()
+      ->GetProfileAttributesStorage()
+      .RemoveProfileByAccountId(account_id);
   RemoveNonOwnerUserInternal(account_id, delegate);
 }
 
diff --git a/chrome/browser/profiles/profile_attributes_storage.h b/chrome/browser/profiles/profile_attributes_storage.h
index 9c88220..425b345 100644
--- a/chrome/browser/profiles/profile_attributes_storage.h
+++ b/chrome/browser/profiles/profile_attributes_storage.h
@@ -30,6 +30,7 @@
 class Image;
 }
 
+class AccountId;
 class PrefService;
 class ProfileAttributesEntry;
 class ProfileAvatarDownloader;
@@ -54,6 +55,11 @@
                           const base::string16& user_name,
                           size_t icon_index,
                           const std::string& supervised_user_id) = 0;
+
+  // Removes the profile matching given |account_id| from this storage.
+  // Calculates profile path and calls RemoveProfile() on it.
+  virtual void RemoveProfileByAccountId(const AccountId& account_id) = 0;
+
   // Removes the profile at |profile_path| from this storage. Does not delete or
   // affect the actual profile's data.
   virtual void RemoveProfile(const base::FilePath& profile_path) = 0;
diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc
index e8ff463..9547261 100644
--- a/chrome/browser/profiles/profile_info_cache.cc
+++ b/chrome/browser/profiles/profile_info_cache.cc
@@ -27,6 +27,7 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "components/signin/core/browser/profile_management_switches.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -740,6 +741,31 @@
       profile_path, name, gaia_id, user_name, icon_index, supervised_user_id);
 }
 
+void ProfileInfoCache::RemoveProfileByAccountId(const AccountId& account_id) {
+  // TODO(rsorokin): https://crbug.com/810167 profile.info_cache entries for
+  // AD accounts should have enough information to be deletable.
+  if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY) {
+    LOG(ERROR)
+        << "Removing of AD profile.info_cache entries is NOTIMPLEMENTED.";
+  }
+
+  for (size_t i = 0; i < GetNumberOfProfiles(); i++) {
+    std::string gaia_id;
+    std::string user_name;
+    const base::DictionaryValue* info = GetInfoForProfileAtIndex(i);
+    if ((info->GetString(kGAIAIdKey, &gaia_id) && !gaia_id.empty() &&
+         account_id.GetGaiaId() == gaia_id) ||
+        (info->GetString(ProfileAttributesEntry::kUserNameKey, &user_name) &&
+         !user_name.empty() && account_id.GetUserEmail() == user_name)) {
+      RemoveProfile(GetPathOfProfileAtIndex(i));
+      return;
+    }
+  }
+  LOG(ERROR) << "Failed to remove profile.info_cache entry for account type "
+             << static_cast<int>(account_id.GetAccountType())
+             << ": matching entry not found.";
+}
+
 void ProfileInfoCache::RemoveProfile(const base::FilePath& profile_path) {
   DeleteProfileFromCache(profile_path);
 }
diff --git a/chrome/browser/profiles/profile_info_cache.h b/chrome/browser/profiles/profile_info_cache.h
index 023ba92..19a8246b 100644
--- a/chrome/browser/profiles/profile_info_cache.h
+++ b/chrome/browser/profiles/profile_info_cache.h
@@ -144,6 +144,7 @@
                   const base::string16& user_name,
                   size_t icon_index,
                   const std::string& supervised_user_id) override;
+  void RemoveProfileByAccountId(const AccountId& account_id) override;
   void RemoveProfile(const base::FilePath& profile_path) override;
 
   bool GetProfileAttributesWithPath(const base::FilePath& path,
diff --git a/chrome/browser/profiles/profile_info_cache_unittest.cc b/chrome/browser/profiles/profile_info_cache_unittest.cc
index 60edb57..d271f04 100644
--- a/chrome/browser/profiles/profile_info_cache_unittest.cc
+++ b/chrome/browser/profiles/profile_info_cache_unittest.cc
@@ -27,6 +27,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "components/prefs/testing_pref_service.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "components/signin/core/browser/profile_management_switches.h"
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -767,3 +768,66 @@
       GetCache()->GetIndexOfProfileWithPath(path_4)));
 }
 #endif
+
+TEST_F(ProfileInfoCacheTest, RemoveProfileByAccountId) {
+  EXPECT_EQ(0u, GetCache()->GetNumberOfProfiles());
+
+  base::FilePath path_1 = GetProfilePath("path_1");
+  const AccountId account_id_1(
+      AccountId::FromUserEmailGaiaId("email1", "111111"));
+  base::string16 name_1 = ASCIIToUTF16("name_1");
+  GetCache()->AddProfileToCache(path_1, name_1, account_id_1.GetGaiaId(),
+                                UTF8ToUTF16(account_id_1.GetUserEmail()), 0,
+                                std::string());
+  EXPECT_EQ(1u, GetCache()->GetNumberOfProfiles());
+
+  base::FilePath path_2 = GetProfilePath("path_2");
+  base::string16 name_2 = ASCIIToUTF16("name_2");
+  const AccountId account_id_2(
+      AccountId::FromUserEmailGaiaId("email2", "222222"));
+  GetCache()->AddProfileToCache(path_2, name_2, account_id_2.GetGaiaId(),
+                                UTF8ToUTF16(account_id_2.GetUserEmail()), 0,
+                                std::string());
+  EXPECT_EQ(2u, GetCache()->GetNumberOfProfiles());
+
+  base::FilePath path_3 = GetProfilePath("path_3");
+  base::string16 name_3 = ASCIIToUTF16("name_3");
+  const AccountId account_id_3(
+      AccountId::FromUserEmailGaiaId("email3", "333333"));
+  GetCache()->AddProfileToCache(path_3, name_3, account_id_3.GetGaiaId(),
+                                UTF8ToUTF16(account_id_3.GetUserEmail()), 0,
+                                std::string());
+  EXPECT_EQ(3u, GetCache()->GetNumberOfProfiles());
+
+  base::FilePath path_4 = GetProfilePath("path_4");
+  base::string16 name_4 = ASCIIToUTF16("name_4");
+  const AccountId account_id_4(
+      AccountId::FromUserEmailGaiaId("email4", "444444"));
+  GetCache()->AddProfileToCache(path_4, name_4, account_id_4.GetGaiaId(),
+                                UTF8ToUTF16(account_id_4.GetUserEmail()), 0,
+                                std::string());
+  EXPECT_EQ(4u, GetCache()->GetNumberOfProfiles());
+
+  GetCache()->RemoveProfileByAccountId(account_id_3);
+  EXPECT_EQ(3u, GetCache()->GetNumberOfProfiles());
+  EXPECT_EQ(name_1, GetCache()->GetNameOfProfileAtIndex(0));
+
+  GetCache()->RemoveProfileByAccountId(account_id_1);
+  EXPECT_EQ(2u, GetCache()->GetNumberOfProfiles());
+  EXPECT_EQ(name_2, GetCache()->GetNameOfProfileAtIndex(0));
+
+  // this profile is already deleted.
+  GetCache()->RemoveProfileByAccountId(account_id_3);
+  EXPECT_EQ(2u, GetCache()->GetNumberOfProfiles());
+  EXPECT_EQ(name_2, GetCache()->GetNameOfProfileAtIndex(0));
+
+  // Remove profile by partial match
+  GetCache()->RemoveProfileByAccountId(
+      AccountId::FromUserEmail(account_id_2.GetUserEmail()));
+  EXPECT_EQ(1u, GetCache()->GetNumberOfProfiles());
+  EXPECT_EQ(name_4, GetCache()->GetNameOfProfileAtIndex(0));
+
+  // Remove last profile
+  GetCache()->RemoveProfileByAccountId(account_id_4);
+  EXPECT_EQ(0u, GetCache()->GetNumberOfProfiles());
+}