[iOS] Add unload profile api in profile manager

Fixed: 335630301
Change-Id: I39a271044647169c21117a8cac62c78586f776a1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6049746
Commit-Queue: Aliona Dangla <alionadangla@chromium.org>
Reviewed-by: Sylvain Defresne <sdefresne@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1389369}
diff --git a/ios/chrome/browser/profile/model/profile_manager_ios_impl.h b/ios/chrome/browser/profile/model/profile_manager_ios_impl.h
index f892bf5..71da0be 100644
--- a/ios/chrome/browser/profile/model/profile_manager_ios_impl.h
+++ b/ios/chrome/browser/profile/model/profile_manager_ios_impl.h
@@ -60,6 +60,7 @@
                           ProfileLoadedCallback created_callback) override;
   ProfileIOS* LoadProfile(std::string_view name) override;
   ProfileIOS* CreateProfile(std::string_view name) override;
+  void UnloadProfile(std::string_view name) override;
   void UnloadAllProfiles() override;
   ProfileAttributesStorageIOS* GetProfileAttributesStorage() override;
 
diff --git a/ios/chrome/browser/profile/model/profile_manager_ios_impl.mm b/ios/chrome/browser/profile/model/profile_manager_ios_impl.mm
index 2c54b6f..5b42555 100644
--- a/ios/chrome/browser/profile/model/profile_manager_ios_impl.mm
+++ b/ios/chrome/browser/profile/model/profile_manager_ios_impl.mm
@@ -355,21 +355,30 @@
   return iter->second.profile();
 }
 
+void ProfileManagerIOSImpl::UnloadProfile(std::string_view name) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  auto iter = profiles_map_.find(name);
+  DCHECK(iter != profiles_map_.end());
+  ProfileInfo profile_info = std::move(iter->second);
+  profiles_map_.erase(iter);
+  if (!profile_info.is_loaded()) {
+    // The profile is unloaded before it could be fully loaded, notify
+    // any pending callback that the load has failed.
+    for (auto& callback : profile_info.TakeCallbacks()) {
+      std::move(callback).Run(nullptr);
+    }
+  } else {
+    for (auto& observer : observers_) {
+      observer.OnProfileUnloaded(this, profile_info.profile());
+    }
+  }
+}
+
 void ProfileManagerIOSImpl::UnloadAllProfiles() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  ProfileMap profiles_map = std::exchange(profiles_map_, {});
-  for (auto& [_, profile_info] : profiles_map) {
-    if (!profile_info.is_loaded()) {
-      // The profile is unloaded before it could be fully loaded, notify
-      // any pending callback that the load has failed.
-      for (auto& callback : profile_info.TakeCallbacks()) {
-        std::move(callback).Run(nullptr);
-      }
-    } else {
-      for (auto& observer : observers_) {
-        observer.OnProfileUnloaded(this, profile_info.profile());
-      }
-    }
+  while (!profiles_map_.empty()) {
+    const std::string& name = profiles_map_.begin()->first;
+    UnloadProfile(name);
   }
 }
 
diff --git a/ios/chrome/browser/profile/model/profile_manager_ios_impl_unittest.mm b/ios/chrome/browser/profile/model/profile_manager_ios_impl_unittest.mm
index 8854aae..ebe1781 100644
--- a/ios/chrome/browser/profile/model/profile_manager_ios_impl_unittest.mm
+++ b/ios/chrome/browser/profile/model/profile_manager_ios_impl_unittest.mm
@@ -750,6 +750,29 @@
             kIOSChromeInitialProfile);
 }
 
+// Tests that unloading a profile invoke OnProfileUnloaded(...) on the
+// observers.
+TEST_F(ProfileManagerIOSImplTest, UnloadProfile) {
+  // Create a few profiles synchronously.
+  ASSERT_TRUE(profile_manager().CreateProfile(kProfileName1));
+  ASSERT_TRUE(profile_manager().CreateProfile(kProfileName2));
+
+  ScopedTestProfileManagerObserverIOS observer(profile_manager());
+  EXPECT_FALSE(observer.on_profile_unloaded_called());
+
+  // Check that the profiles are accessible.
+  EXPECT_TRUE(profile_manager().GetProfileWithName(kProfileName1));
+  EXPECT_TRUE(profile_manager().GetProfileWithName(kProfileName2));
+
+  // Unload a profile, it should not longer be accessible and the
+  // observer must have been notified of that.
+  profile_manager().UnloadProfile(kProfileName1);
+
+  EXPECT_FALSE(profile_manager().GetProfileWithName(kProfileName1));
+  EXPECT_TRUE(profile_manager().GetProfileWithName(kProfileName2));
+  EXPECT_TRUE(observer.on_profile_unloaded_called());
+}
+
 // Tests that unloading all profiles invoke OnProfileUnloaded(...) on the
 // observers.
 TEST_F(ProfileManagerIOSImplTest, UnloadAllProfiles) {
diff --git a/ios/chrome/browser/shared/model/profile/profile_manager_ios.h b/ios/chrome/browser/shared/model/profile/profile_manager_ios.h
index 291f6a85..c6ef701d 100644
--- a/ios/chrome/browser/shared/model/profile/profile_manager_ios.h
+++ b/ios/chrome/browser/shared/model/profile/profile_manager_ios.h
@@ -89,6 +89,9 @@
   // null if loading or creating the Profile failed.
   virtual ProfileIOS* CreateProfile(std::string_view name) = 0;
 
+  // Unloads the given loaded Profile objects.
+  virtual void UnloadProfile(std::string_view name) = 0;
+
   // Unloads all loaded Profile objects. Meant to be called right before the
   // ProfileManagerIOS itself is destroyed.
   virtual void UnloadAllProfiles() = 0;
diff --git a/ios/chrome/browser/shared/model/profile/test/test_profile_manager_ios.h b/ios/chrome/browser/shared/model/profile/test/test_profile_manager_ios.h
index 3d520a1..df34708 100644
--- a/ios/chrome/browser/shared/model/profile/test/test_profile_manager_ios.h
+++ b/ios/chrome/browser/shared/model/profile/test/test_profile_manager_ios.h
@@ -46,6 +46,7 @@
                           ProfileLoadedCallback created_callback) override;
   ProfileIOS* LoadProfile(std::string_view name) override;
   ProfileIOS* CreateProfile(std::string_view name) override;
+  void UnloadProfile(std::string_view name) override;
   void UnloadAllProfiles() override;
   ProfileAttributesStorageIOS* GetProfileAttributesStorage() override;
 
diff --git a/ios/chrome/browser/shared/model/profile/test/test_profile_manager_ios.mm b/ios/chrome/browser/shared/model/profile/test/test_profile_manager_ios.mm
index aa15826..8ed28f3 100644
--- a/ios/chrome/browser/shared/model/profile/test/test_profile_manager_ios.mm
+++ b/ios/chrome/browser/shared/model/profile/test/test_profile_manager_ios.mm
@@ -124,6 +124,16 @@
   return GetProfileWithName(name);
 }
 
+void TestProfileManagerIOS::UnloadProfile(std::string_view name) {
+  auto iter = profiles_map_.find(name);
+  DCHECK(iter != profiles_map_.end());
+  std::unique_ptr<ProfileIOS> profile = std::move(iter->second);
+  profiles_map_.erase(iter);
+  for (auto& observer : observers_) {
+    observer.OnProfileUnloaded(this, profile.get());
+  }
+}
+
 void TestProfileManagerIOS::UnloadAllProfiles() {
   ProfileMap profiles_map = std::exchange(profiles_map_, {});
   for (auto& [_, profile] : profiles_map) {
diff --git a/ios/chrome/browser/signin/model/account_profile_mapper_unittest.mm b/ios/chrome/browser/signin/model/account_profile_mapper_unittest.mm
index db40574d..501a09c 100644
--- a/ios/chrome/browser/signin/model/account_profile_mapper_unittest.mm
+++ b/ios/chrome/browser/signin/model/account_profile_mapper_unittest.mm
@@ -177,6 +177,7 @@
   ProfileIOS* LoadProfile(std::string_view name) override { NOTREACHED(); }
   ProfileIOS* CreateProfile(std::string_view name) override { NOTREACHED(); }
 
+  void UnloadProfile(std::string_view name) override { NOTREACHED(); }
   void UnloadAllProfiles() override { NOTREACHED(); }
 
   ProfileAttributesStorageIOS* GetProfileAttributesStorage() override {