diff --git a/ash/public/interfaces/wallpaper.mojom b/ash/public/interfaces/wallpaper.mojom
index 3db509c..3b3dbed 100644
--- a/ash/public/interfaces/wallpaper.mojom
+++ b/ash/public/interfaces/wallpaper.mojom
@@ -63,8 +63,19 @@
 
 // Used by Chrome to set the wallpaper displayed by ash.
 interface WallpaperController {
-  // Sets the client interface.
-  SetClient(WallpaperControllerClient client);
+  // Sets the client interface and the paths of wallpaper directories. The paths
+  // must be sent over IPC because chrome owns the concept of user data
+  // directory.
+  // |client|: The client interface.
+  // |user_data_path|: Directory where user data can be written.
+  // |chromeos_wallpapers_path|: Directory where downloaded chromeos wallpapers
+  //                             reside.
+  // |chromeos_custom_wallpapers_path|: Directory where custom wallpapers
+  //                                    reside.
+  SetClientAndPaths(WallpaperControllerClient client,
+                    mojo.common.mojom.FilePath user_data_path,
+                    mojo.common.mojom.FilePath chromeos_wallpapers_path,
+                    mojo.common.mojom.FilePath chromeos_custom_wallpapers_path);
 
   // Sets wallpaper from policy or from a local file. Saves the custom wallpaper
   // to file, posts task to generate thumbnail and updates local state.
@@ -128,7 +139,8 @@
   ShowSigninWallpaper();
 
   // Removes all of the user's saved wallpapers and related info.
-  RemoveUserWallpaper(WallpaperUserInfo user_info);
+  // |wallpaper_files_id|: The unique id of each wallpaper file.
+  RemoveUserWallpaper(WallpaperUserInfo user_info, string wallpaper_files_id);
 
   // TODO(crbug.com/776464): This is only used by WallpaperManager. Remove this
   // after WallpaperManager is removed.
diff --git a/ash/shelf/shelf_context_menu_model_unittest.cc b/ash/shelf/shelf_context_menu_model_unittest.cc
index f32eb0e4..9786f25 100644
--- a/ash/shelf/shelf_context_menu_model_unittest.cc
+++ b/ash/shelf/shelf_context_menu_model_unittest.cc
@@ -142,7 +142,8 @@
   submenu = menu3.GetSubmenuModelAt(1);
   EXPECT_TRUE(submenu->IsItemCheckedAt(0));
   TestWallpaperControllerClient client;
-  Shell::Get()->wallpaper_controller()->SetClient(client.CreateInterfacePtr());
+  Shell::Get()->wallpaper_controller()->SetClientForTesting(
+      client.CreateInterfacePtr());
   EXPECT_EQ(0u, client.open_count());
   menu3.ActivatedAt(2);
   Shell::Get()->wallpaper_controller()->FlushForTesting();
diff --git a/ash/wallpaper/wallpaper_controller.cc b/ash/wallpaper/wallpaper_controller.cc
index 3783dd1..5feac6a 100644
--- a/ash/wallpaper/wallpaper_controller.cc
+++ b/ash/wallpaper/wallpaper_controller.cc
@@ -24,6 +24,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "base/path_service.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task_scheduler/post_task.h"
@@ -160,10 +161,27 @@
   return ColorProfileType::DARK_MUTED;
 }
 
+// Deletes a list of wallpaper files in |file_list|.
+void DeleteWallpaperInList(const std::vector<base::FilePath>& file_list) {
+  for (const base::FilePath& path : file_list) {
+    if (!base::DeleteFile(path, true))
+      LOG(ERROR) << "Failed to remove user wallpaper at " << path.value();
+  }
+}
+
 }  // namespace
 
 const SkColor WallpaperController::kInvalidColor = SK_ColorTRANSPARENT;
 
+base::FilePath WallpaperController::dir_user_data_path_;
+base::FilePath WallpaperController::dir_chrome_os_wallpapers_path_;
+base::FilePath WallpaperController::dir_chrome_os_custom_wallpapers_path_;
+
+const char WallpaperController::kSmallWallpaperSubDir[] = "small";
+const char WallpaperController::kLargeWallpaperSubDir[] = "large";
+const char WallpaperController::kOriginalWallpaperSubDir[] = "original";
+const char WallpaperController::kThumbnailWallpaperSubDir[] = "thumb";
+
 WallpaperController::WallpaperController()
     : locked_(false),
       wallpaper_mode_(WALLPAPER_NONE),
@@ -196,6 +214,35 @@
   registry->RegisterDictionaryPref(prefs::kWallpaperColors);
 }
 
+// static
+gfx::Size WallpaperController::GetMaxDisplaySizeInNative() {
+  // Return an empty size for test environments where the screen is null.
+  if (!display::Screen::GetScreen())
+    return gfx::Size();
+
+  gfx::Size max;
+  for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) {
+    // Use the native size, not ManagedDisplayInfo::size_in_pixel or
+    // Display::size.
+    // TODO(msw): Avoid using Display::size here; see http://crbug.com/613657.
+    gfx::Size size = display.size();
+    if (Shell::HasInstance()) {
+      display::ManagedDisplayInfo info =
+          Shell::Get()->display_manager()->GetDisplayInfo(display.id());
+      // TODO(mash): Mash returns a fake ManagedDisplayInfo. crbug.com/622480
+      if (info.id() == display.id())
+        size = info.bounds_in_native().size();
+    }
+    if (display.rotation() == display::Display::ROTATE_90 ||
+        display.rotation() == display::Display::ROTATE_270) {
+      size = gfx::Size(size.height(), size.width());
+    }
+    max.SetToMax(size);
+  }
+
+  return max;
+}
+
 void WallpaperController::BindRequest(
     mojom::WallpaperControllerRequest request) {
   bindings_.AddBinding(this, std::move(request));
@@ -272,6 +319,12 @@
   InstallDesktopControllerForAllWindows();
 }
 
+base::FilePath WallpaperController::GetCustomWallpaperDir(
+    const std::string& sub_dir) {
+  DCHECK(!dir_chrome_os_custom_wallpapers_path_.empty());
+  return dir_chrome_os_custom_wallpapers_path_.Append(sub_dir);
+}
+
 void WallpaperController::OnDisplayConfigurationChanged() {
   gfx::Size max_display_size = GetMaxDisplaySizeInNative();
   if (current_max_display_size_ != max_display_size) {
@@ -331,35 +384,6 @@
     MoveToLockedContainer();
 }
 
-// static
-gfx::Size WallpaperController::GetMaxDisplaySizeInNative() {
-  // Return an empty size for test environments where the screen is null.
-  if (!display::Screen::GetScreen())
-    return gfx::Size();
-
-  gfx::Size max;
-  for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) {
-    // Use the native size, not ManagedDisplayInfo::size_in_pixel or
-    // Display::size.
-    // TODO(msw): Avoid using Display::size here; see http://crbug.com/613657.
-    gfx::Size size = display.size();
-    if (Shell::HasInstance()) {
-      display::ManagedDisplayInfo info =
-          Shell::Get()->display_manager()->GetDisplayInfo(display.id());
-      // TODO(mash): Mash returns a fake ManagedDisplayInfo. crbug.com/622480
-      if (info.id() == display.id())
-        size = info.bounds_in_native().size();
-    }
-    if (display.rotation() == display::Display::ROTATE_90 ||
-        display.rotation() == display::Display::ROTATE_270) {
-      size = gfx::Size(size.height(), size.width());
-    }
-    max.SetToMax(size);
-  }
-
-  return max;
-}
-
 bool WallpaperController::WallpaperIsAlreadyLoaded(
     const gfx::ImageSkia& image,
     bool compare_layouts,
@@ -414,8 +438,8 @@
     wallpaper_colors_update->RemoveWithoutPathExpansion(old_info.location,
                                                         nullptr);
   }
-  DictionaryPrefUpdate wallpaper_update(local_state, prefs::kUserWallpaperInfo);
 
+  DictionaryPrefUpdate wallpaper_update(local_state, prefs::kUserWallpaperInfo);
   auto wallpaper_info_dict = std::make_unique<base::DictionaryValue>();
   wallpaper_info_dict->SetString(
       kNewWallpaperDateNodeName,
@@ -474,27 +498,6 @@
   return true;
 }
 
-void WallpaperController::RemoveUserWallpaperInfo(const AccountId& account_id,
-                                                  bool is_persistent) {
-  if (wallpaper_cache_map_.find(account_id) != wallpaper_cache_map_.end())
-    wallpaper_cache_map_.erase(account_id);
-
-  PrefService* local_state = Shell::Get()->GetLocalStatePrefService();
-  // Local state can be null in tests.
-  if (!local_state)
-    return;
-  WallpaperInfo info;
-  GetUserWallpaperInfo(account_id, &info, is_persistent);
-  DictionaryPrefUpdate prefs_wallpapers_info_update(local_state,
-                                                    prefs::kUserWallpaperInfo);
-  prefs_wallpapers_info_update->RemoveWithoutPathExpansion(
-      account_id.GetUserEmail(), nullptr);
-  // Remove the color cache of the previous wallpaper if it exists.
-  DictionaryPrefUpdate wallpaper_colors_update(local_state,
-                                               prefs::kWallpaperColors);
-  wallpaper_colors_update->RemoveWithoutPathExpansion(info.location, nullptr);
-}
-
 bool WallpaperController::GetWallpaperFromCache(const AccountId& account_id,
                                                 gfx::ImageSkia* image) {
   CustomWallpaperMap::const_iterator it = wallpaper_cache_map_.find(account_id);
@@ -523,9 +526,15 @@
   return &wallpaper_cache_map_;
 }
 
-void WallpaperController::SetClient(
-    mojom::WallpaperControllerClientPtr client) {
+void WallpaperController::SetClientAndPaths(
+    mojom::WallpaperControllerClientPtr client,
+    const base::FilePath& user_data_path,
+    const base::FilePath& chromeos_wallpapers_path,
+    const base::FilePath& chromeos_custom_wallpapers_path) {
   wallpaper_controller_client_ = std::move(client);
+  dir_user_data_path_ = user_data_path;
+  dir_chrome_os_wallpapers_path_ = chromeos_wallpapers_path;
+  dir_chrome_os_custom_wallpapers_path_ = chromeos_custom_wallpapers_path;
 }
 
 void WallpaperController::SetCustomWallpaper(
@@ -592,8 +601,10 @@
 }
 
 void WallpaperController::RemoveUserWallpaper(
-    mojom::WallpaperUserInfoPtr user_info) {
-  NOTIMPLEMENTED();
+    mojom::WallpaperUserInfoPtr user_info,
+    const std::string& wallpaper_files_id) {
+  RemoveUserWallpaperInfo(user_info->account_id, !user_info->is_ephemeral);
+  RemoveUserWallpaperImpl(user_info->account_id, wallpaper_files_id);
 }
 
 void WallpaperController::SetWallpaper(const SkBitmap& wallpaper,
@@ -631,6 +642,12 @@
   SetProminentColors(colors);
 }
 
+void WallpaperController::SetClientForTesting(
+    mojom::WallpaperControllerClientPtr client) {
+  SetClientAndPaths(std::move(client), base::FilePath(), base::FilePath(),
+                    base::FilePath());
+}
+
 void WallpaperController::FlushForTesting() {
   if (wallpaper_controller_client_)
     wallpaper_controller_client_.FlushForTesting();
@@ -720,6 +737,57 @@
   Shell::Get()->wallpaper_delegate()->UpdateWallpaper(clear_cache);
 }
 
+void WallpaperController::RemoveUserWallpaperInfo(const AccountId& account_id,
+                                                  bool is_persistent) {
+  if (wallpaper_cache_map_.find(account_id) != wallpaper_cache_map_.end())
+    wallpaper_cache_map_.erase(account_id);
+
+  PrefService* local_state = Shell::Get()->GetLocalStatePrefService();
+  // Local state can be null in tests.
+  if (!local_state)
+    return;
+  WallpaperInfo info;
+  GetUserWallpaperInfo(account_id, &info, is_persistent);
+  DictionaryPrefUpdate prefs_wallpapers_info_update(local_state,
+                                                    prefs::kUserWallpaperInfo);
+  prefs_wallpapers_info_update->RemoveWithoutPathExpansion(
+      account_id.GetUserEmail(), nullptr);
+  // Remove the color cache of the previous wallpaper if it exists.
+  DictionaryPrefUpdate wallpaper_colors_update(local_state,
+                                               prefs::kWallpaperColors);
+  wallpaper_colors_update->RemoveWithoutPathExpansion(info.location, nullptr);
+}
+
+void WallpaperController::RemoveUserWallpaperImpl(
+    const AccountId& account_id,
+    const std::string& wallpaper_files_id) {
+  if (wallpaper_files_id.empty())
+    return;
+
+  std::vector<base::FilePath> file_to_remove;
+
+  // Remove small user wallpapers.
+  base::FilePath wallpaper_path = GetCustomWallpaperDir(kSmallWallpaperSubDir);
+  file_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id));
+
+  // Remove large user wallpapers.
+  wallpaper_path = GetCustomWallpaperDir(kLargeWallpaperSubDir);
+  file_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id));
+
+  // Remove user wallpaper thumbnails.
+  wallpaper_path = GetCustomWallpaperDir(kThumbnailWallpaperSubDir);
+  file_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id));
+
+  // Remove original user wallpapers.
+  wallpaper_path = GetCustomWallpaperDir(kOriginalWallpaperSubDir);
+  file_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id));
+
+  base::PostTaskWithTraits(FROM_HERE,
+                           {base::MayBlock(), base::TaskPriority::BACKGROUND,
+                            base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+                           base::Bind(&DeleteWallpaperInList, file_to_remove));
+}
+
 void WallpaperController::SetProminentColors(
     const std::vector<SkColor>& colors) {
   if (prominent_colors_ == colors)
diff --git a/ash/wallpaper/wallpaper_controller.h b/ash/wallpaper/wallpaper_controller.h
index e225fb5..50d5dcc3 100644
--- a/ash/wallpaper/wallpaper_controller.h
+++ b/ash/wallpaper/wallpaper_controller.h
@@ -71,11 +71,31 @@
   // command line, lock/login screens).
   static const SkColor kInvalidColor;
 
+  // The paths of wallpaper directories.
+  // TODO(crbug.com/776464): Make these private and remove the static qualifier
+  // after |WallpaperManager::LoadWallpaper| and
+  // |WallpaperManager::GetDeviceWallpaperDir| are migrated.
+  static base::FilePath dir_user_data_path_;
+  static base::FilePath dir_chrome_os_wallpapers_path_;
+  static base::FilePath dir_chrome_os_custom_wallpapers_path_;
+
+  // Directory names of custom wallpapers.
+  static const char kSmallWallpaperSubDir[];
+  static const char kLargeWallpaperSubDir[];
+  static const char kOriginalWallpaperSubDir[];
+  static const char kThumbnailWallpaperSubDir[];
+
   WallpaperController();
   ~WallpaperController() override;
 
   static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
 
+  // Returns the maximum size of all displays combined in native
+  // resolutions.  Note that this isn't the bounds of the display who
+  // has maximum resolutions. Instead, this returns the size of the
+  // maximum width of all displays, and the maximum height of all displays.
+  static gfx::Size GetMaxDisplaySizeInNative();
+
   // Binds the mojom::WallpaperController interface request to this object.
   void BindRequest(mojom::WallpaperControllerRequest request);
 
@@ -105,6 +125,9 @@
   // crashes. An example test is SystemGestureEventFilterTest.ThreeFingerSwipe.
   void CreateEmptyWallpaper();
 
+  // Returns custom wallpaper directory by appending corresponding |sub_dir|.
+  base::FilePath GetCustomWallpaperDir(const std::string& sub_dir);
+
   // WindowTreeHostManager::Observer:
   void OnDisplayConfigurationChanged() override;
 
@@ -115,12 +138,6 @@
   // SessionObserver:
   void OnSessionStateChanged(session_manager::SessionState state) override;
 
-  // Returns the maximum size of all displays combined in native
-  // resolutions.  Note that this isn't the bounds of the display who
-  // has maximum resolutions. Instead, this returns the size of the
-  // maximum width of all displays, and the maximum height of all displays.
-  static gfx::Size GetMaxDisplaySizeInNative();
-
   // Returns true if the specified wallpaper is already stored
   // in |current_wallpaper_|.
   // If |compare_layouts| is false, layout is ignored.
@@ -160,9 +177,6 @@
                             wallpaper::WallpaperInfo* info,
                             bool is_persistent);
 
-  // Removes |account_id|'s wallpaper info and color cache if it exists.
-  void RemoveUserWallpaperInfo(const AccountId& account_id, bool is_persistent);
-
   // Gets encoded wallpaper from cache. Returns true if success.
   bool GetWallpaperFromCache(const AccountId& account_id,
                              gfx::ImageSkia* image);
@@ -179,7 +193,11 @@
   CustomWallpaperMap* GetWallpaperCacheMap();
 
   // mojom::WallpaperController overrides:
-  void SetClient(mojom::WallpaperControllerClientPtr client) override;
+  void SetClientAndPaths(
+      mojom::WallpaperControllerClientPtr client,
+      const base::FilePath& user_data_path,
+      const base::FilePath& chromeos_wallpapers_path,
+      const base::FilePath& chromeos_custom_wallpapers_path) override;
   void SetCustomWallpaper(mojom::WallpaperUserInfoPtr user_info,
                           const std::string& wallpaper_files_id,
                           const std::string& file_name,
@@ -200,7 +218,8 @@
       const base::FilePath& resized_directory) override;
   void ShowUserWallpaper(mojom::WallpaperUserInfoPtr user_info) override;
   void ShowSigninWallpaper() override;
-  void RemoveUserWallpaper(mojom::WallpaperUserInfoPtr user_info) override;
+  void RemoveUserWallpaper(mojom::WallpaperUserInfoPtr user_info,
+                           const std::string& wallpaper_files_id) override;
   void SetWallpaper(const SkBitmap& wallpaper,
                     const wallpaper::WallpaperInfo& wallpaper_info) override;
   void AddObserver(mojom::WallpaperObserverAssociatedPtrInfo observer) override;
@@ -212,6 +231,9 @@
   // WallpaperColorCalculatorObserver:
   void OnColorCalculationComplete() override;
 
+  // Sets a test client interface with empty file paths.
+  void SetClientForTesting(mojom::WallpaperControllerClientPtr client);
+
   // Flushes the mojo message pipe to chrome.
   void FlushForTesting();
 
@@ -238,6 +260,14 @@
   // wallpaper cahce or not.
   void UpdateWallpaper(bool clear_cache);
 
+  // Removes |account_id|'s wallpaper info and color cache if it exists.
+  void RemoveUserWallpaperInfo(const AccountId& account_id, bool is_persistent);
+
+  // Implementation of |RemoveUserWallpaper|, which deletes |account_id|'s
+  // custom wallpapers and directories.
+  void RemoveUserWallpaperImpl(const AccountId& account_id,
+                               const std::string& wallpaper_files_id);
+
   // Sets |prominent_colors_| and notifies the observers if there is a change.
   void SetProminentColors(const std::vector<SkColor>& prominent_colors);
 
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc
index ee12d9a..e6ecc31 100644
--- a/ash/wallpaper/wallpaper_controller_unittest.cc
+++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -676,37 +676,42 @@
 TEST_F(WallpaperControllerTest, VerifyWallpaperCache) {
   gfx::ImageSkia image = CreateImage(640, 480, kCustomWallpaperColor);
   const std::string user1 = "user1@test.com";
+  const AccountId account_id1 = AccountId::FromUserEmail(user1);
 
   SimulateUserLogin(user1);
 
   // |user1| doesn't have wallpaper cache in the beginning.
   gfx::ImageSkia cached_wallpaper;
-  EXPECT_FALSE(controller_->GetWallpaperFromCache(
-      AccountId::FromUserEmail(user1), &cached_wallpaper));
-  base::FilePath path;
   EXPECT_FALSE(
-      controller_->GetPathFromCache(AccountId::FromUserEmail(user1), &path));
+      controller_->GetWallpaperFromCache(account_id1, &cached_wallpaper));
+  base::FilePath path;
+  EXPECT_FALSE(controller_->GetPathFromCache(account_id1, &path));
 
   // Verify |SetOnlineWallpaper| updates wallpaper cache for |user1|.
-  mojom::WallpaperUserInfoPtr wallpaper_user_info =
-      InitializeUser(AccountId::FromUserEmail(user1));
+  mojom::WallpaperUserInfoPtr wallpaper_user_info = InitializeUser(account_id1);
   controller_->SetOnlineWallpaper(
       std::move(wallpaper_user_info), *image.bitmap(), "dummy_file_location",
       WALLPAPER_LAYOUT_CENTER, true /* show_wallpaper */);
   RunAllTasksUntilIdle();
-  EXPECT_TRUE(controller_->GetWallpaperFromCache(
-      AccountId::FromUserEmail(user1), &cached_wallpaper));
   EXPECT_TRUE(
-      controller_->GetPathFromCache(AccountId::FromUserEmail(user1), &path));
+      controller_->GetWallpaperFromCache(account_id1, &cached_wallpaper));
+  EXPECT_TRUE(controller_->GetPathFromCache(account_id1, &path));
 
   // After |user2| is logged in, |user1|'s wallpaper cache should still be kept
   // (crbug.com/339576). Note the active user is still |user1|.
   TestSessionControllerClient* session = GetSessionControllerClient();
   session->AddUserSession("user2@test.com");
-  EXPECT_TRUE(controller_->GetWallpaperFromCache(
-      AccountId::FromUserEmail(user1), &cached_wallpaper));
   EXPECT_TRUE(
-      controller_->GetPathFromCache(AccountId::FromUserEmail(user1), &path));
+      controller_->GetWallpaperFromCache(account_id1, &cached_wallpaper));
+  EXPECT_TRUE(controller_->GetPathFromCache(account_id1, &path));
+
+  // Verify |RemoveUserWallpaper| clears wallpaper cache.
+  wallpaper_user_info = InitializeUser(account_id1);
+  controller_->RemoveUserWallpaper(std::move(wallpaper_user_info),
+                                   std::string() /* wallpaper_files_id */);
+  EXPECT_FALSE(
+      controller_->GetWallpaperFromCache(account_id1, &cached_wallpaper));
+  EXPECT_FALSE(controller_->GetPathFromCache(account_id1, &path));
 }
 
 }  // namespace ash
diff --git a/chrome/browser/chromeos/arc/arc_util_unittest.cc b/chrome/browser/chromeos/arc/arc_util_unittest.cc
index c9520fb..a6af9eb 100644
--- a/chrome/browser/chromeos/arc/arc_util_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_util_unittest.cc
@@ -23,6 +23,8 @@
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/policy/profile_policy_connector_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/ash/test_wallpaper_controller.h"
+#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/chromeos_switches.h"
 #include "components/arc/arc_prefs.h"
@@ -151,7 +153,13 @@
 
     user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
         std::make_unique<FakeUserManagerWithLocalState>());
+    // Used by FakeChromeUserManager.
     chromeos::WallpaperManager::Initialize();
+    wallpaper_controller_client_ =
+        std::make_unique<WallpaperControllerClient>();
+    wallpaper_controller_client_->InitForTesting(
+        test_wallpaper_controller_.CreateInterfacePtr());
+
     profile_ = std::make_unique<TestingProfile>();
     profile_->set_profile_name(kTestProfileName);
   }
@@ -161,6 +169,7 @@
     chromeos::WallpaperManager::Shutdown();
     user_manager_enabler_.reset();
     command_line_.reset();
+    wallpaper_controller_client_.reset();
   }
 
   TestingProfile* profile() { return profile_.get(); }
@@ -178,6 +187,8 @@
   }
 
  private:
+  std::unique_ptr<WallpaperControllerClient> wallpaper_controller_client_;
+  TestWallpaperController test_wallpaper_controller_;
   std::unique_ptr<base::test::ScopedCommandLine> command_line_;
   content::TestBrowserThreadBundle thread_bundle_;
   std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
@@ -612,42 +623,7 @@
   EXPECT_TRUE(IsActiveDirectoryUserForProfile(profile()));
 }
 
-class ArcMigrationTest : public testing::Test {
- protected:
-  ArcMigrationTest() {}
-  ~ArcMigrationTest() override {}
-
-  void SetUp() override {
-    user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
-        std::make_unique<FakeUserManagerWithLocalState>());
-    // Used by FakeChromeUserManager.
-    chromeos::WallpaperManager::Initialize();
-    profile_ = std::make_unique<TestingProfile>();
-    profile_->set_profile_name(kTestProfileName);
-  }
-
-  void TearDown() override {
-    profile_.reset();
-    chromeos::WallpaperManager::Shutdown();
-    user_manager_enabler_.reset();
-    command_line_.reset();
-  }
-
-  TestingProfile* profile() { return profile_.get(); }
-
-  chromeos::FakeChromeUserManager* GetFakeUserManager() const {
-    return static_cast<chromeos::FakeChromeUserManager*>(
-        user_manager::UserManager::Get());
-  }
-
- private:
-  std::unique_ptr<base::test::ScopedCommandLine> command_line_;
-  content::TestBrowserThreadBundle thread_bundle_;
-  std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
-  std::unique_ptr<TestingProfile> profile_;
-
-  DISALLOW_COPY_AND_ASSIGN(ArcMigrationTest);
-};
+using ArcMigrationTest = ChromeArcUtilTest;
 
 TEST_F(ArcMigrationTest, IsMigrationAllowedUnmanagedUser) {
   ScopedLogIn login(GetFakeUserManager(),
diff --git a/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.cc b/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.cc
index 9be2d0c..5ae4d81c 100644
--- a/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.cc
+++ b/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.cc
@@ -14,6 +14,7 @@
 #include "base/memory/singleton.h"
 #include "base/task_scheduler/post_task.h"
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
+#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
 #include "components/signin/core/account_id/account_id.h"
@@ -130,7 +131,7 @@
         chromeos::WallpaperManager::Get();
     const PrimaryAccount& account = GetPrimaryAccount();
     wallpaper::WallpaperFilesId wallpaper_files_id =
-        wallpaper_manager->GetFilesId(account.id);
+        WallpaperControllerClient::Get()->GetFilesId(account.id);
     // TODO(crbug.com/618922): Allow specifying layout.
     wallpaper_manager->SetCustomWallpaper(
         account.id, wallpaper_files_id, kAndroidWallpaperFilename,
diff --git a/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service_unittest.cc b/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service_unittest.cc
index f765447..2d430fa 100644
--- a/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service_unittest.cc
+++ b/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service_unittest.cc
@@ -14,11 +14,15 @@
 #include "ash/test/ash_test_base.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/path_service.h"
 #include "base/run_loop.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.h"
 #include "chrome/browser/image_decoder.h"
+#include "chrome/browser/ui/ash/test_wallpaper_controller.h"
+#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
@@ -37,6 +41,26 @@
 
 namespace {
 
+// TODO(crbug.com/776464): Remove this after |SetCustomWallpaper| is migrated
+// to |WallpaperController|.
+void InitializeWallpaperPaths() {
+  base::FilePath user_data_path;
+  CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_path));
+  ash::WallpaperController::dir_user_data_path_ = user_data_path;
+
+  base::FilePath chromeos_wallpapers_path;
+  CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS,
+                         &chromeos_wallpapers_path));
+  ash::WallpaperController::dir_chrome_os_wallpapers_path_ =
+      chromeos_wallpapers_path;
+
+  base::FilePath chromeos_custom_wallpapers_path;
+  CHECK(PathService::Get(chrome::DIR_CHROMEOS_CUSTOM_WALLPAPERS,
+                         &chromeos_custom_wallpapers_path));
+  ash::WallpaperController::dir_chrome_os_custom_wallpapers_path_ =
+      chromeos_custom_wallpapers_path;
+}
+
 class SuccessDecodeRequestSender
     : public arc::ArcWallpaperService::DecodeRequestSender {
  public:
@@ -83,8 +107,12 @@
     user_manager_->LoginUser(user_manager::StubAccountId());
     ASSERT_TRUE(user_manager_->GetPrimaryUser());
 
-    // Wallpaper maanger
+    // Wallpaper manager
     chromeos::WallpaperManager::Initialize();
+    wallpaper_controller_client_ =
+        std::make_unique<WallpaperControllerClient>();
+    wallpaper_controller_client_->InitForTesting(
+        test_wallpaper_controller_.CreateInterfacePtr());
 
     // Arc services
     arc_service_manager_.set_browser_context(&testing_profile_);
@@ -107,6 +135,7 @@
         nullptr);
     wallpaper_instance_.reset();
 
+    wallpaper_controller_client_.reset();
     chromeos::WallpaperManager::Shutdown();
     TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
     AshTestBase::TearDown();
@@ -117,6 +146,8 @@
   std::unique_ptr<arc::FakeWallpaperInstance> wallpaper_instance_ = nullptr;
 
  private:
+  std::unique_ptr<WallpaperControllerClient> wallpaper_controller_client_;
+  TestWallpaperController test_wallpaper_controller_;
   chromeos::FakeChromeUserManager* const user_manager_ = nullptr;
   user_manager::ScopedUserManager user_manager_enabler_;
   arc::ArcServiceManager arc_service_manager_;
@@ -139,6 +170,10 @@
 }
 
 TEST_F(ArcWallpaperServiceTest, SetAndGetWallpaper) {
+  // TODO(crbug.com/776464): This test is supposed to call the mock method, but
+  // currently it's still calling the real method which relies on the paths.
+  InitializeWallpaperPaths();
+
   service_->SetDecodeRequestSenderForTesting(
       std::make_unique<SuccessDecodeRequestSender>());
   std::vector<uint8_t> bytes;
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index c132b66..3880caf 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -814,10 +814,6 @@
 
   // TODO(crbug.com/776464): Remove WallpaperManager after everything is
   // migrated to WallpaperController.
-  WallpaperManager::SetPathIds(chrome::DIR_USER_DATA,
-                               chrome::DIR_CHROMEOS_WALLPAPERS,
-                               chrome::DIR_CHROMEOS_CUSTOM_WALLPAPERS);
-
   // Add observers for WallpaperManager. This depends on PowerManagerClient,
   // TimezoneSettings and CrosSettings.
   WallpaperManager::Initialize();
diff --git a/chrome/browser/chromeos/extensions/wallpaper_api.cc b/chrome/browser/chromeos/extensions/wallpaper_api.cc
index d14f68a..7170990 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_api.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_api.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/pref_names.h"
@@ -124,9 +125,8 @@
   // Gets account id from the caller, ensuring multiprofile compatibility.
   const user_manager::User* user = GetUserFromBrowserContext(browser_context());
   account_id_ = user->GetAccountId();
-  chromeos::WallpaperManager* wallpaper_manager =
-      chromeos::WallpaperManager::Get();
-  wallpaper_files_id_ = wallpaper_manager->GetFilesId(account_id_);
+  wallpaper_files_id_ =
+      WallpaperControllerClient::Get()->GetFilesId(account_id_);
 
   if (params_->details.data) {
     StartDecode(*params_->details.data);
@@ -152,7 +152,7 @@
   chromeos::WallpaperManager* wallpaper_manager =
       chromeos::WallpaperManager::Get();
   base::FilePath thumbnail_path = wallpaper_manager->GetCustomWallpaperPath(
-      chromeos::kThumbnailWallpaperSubDir, wallpaper_files_id_,
+      ash::WallpaperController::kThumbnailWallpaperSubDir, wallpaper_files_id_,
       params_->details.filename);
 
   wallpaper::WallpaperLayout layout = wallpaper_api_util::GetLayoutEnum(
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
index d052a65..a96c326 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
@@ -489,9 +489,8 @@
   // Gets account id from the caller, ensuring multiprofile compatibility.
   const user_manager::User* user = GetUserFromBrowserContext(browser_context());
   account_id_ = user->GetAccountId();
-  chromeos::WallpaperManager* wallpaper_manager =
-      chromeos::WallpaperManager::Get();
-  wallpaper_files_id_ = wallpaper_manager->GetFilesId(account_id_);
+  wallpaper_files_id_ =
+      WallpaperControllerClient::Get()->GetFilesId(account_id_);
 
   StartDecode(params->wallpaper);
 
@@ -503,7 +502,7 @@
   chromeos::WallpaperManager* wallpaper_manager =
       chromeos::WallpaperManager::Get();
   base::FilePath thumbnail_path = wallpaper_manager->GetCustomWallpaperPath(
-      chromeos::kThumbnailWallpaperSubDir, wallpaper_files_id_,
+      ash::WallpaperController::kThumbnailWallpaperSubDir, wallpaper_files_id_,
       params->file_name);
 
   wallpaper::WallpaperLayout layout = wallpaper_api_util::GetLayoutEnum(
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 d645ffe..3653363 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -61,6 +61,7 @@
 #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"
+#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_switches.h"
@@ -997,7 +998,7 @@
     const AccountId& account_id) {
   ChromeUserManager::RemoveNonCryptohomeData(account_id);
 
-  WallpaperManager::Get()->RemoveUserWallpaper(account_id);
+  WallpaperControllerClient::Get()->RemoveUserWallpaper(account_id);
   GetUserImageManager(account_id)->DeleteUserImage();
 
   supervised_user_manager_->RemoveNonCryptohomeData(account_id.GetUserEmail());
diff --git a/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc b/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc
index 84f2c39..7c622c2f 100644
--- a/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc
+++ b/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc
@@ -14,10 +14,10 @@
 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/chrome_user_manager_util.h"
 #include "chrome/browser/chromeos/login/users/fake_supervised_user_manager.h"
-#include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/login/login_state.h"
 #include "components/user_manager/known_user.h"
@@ -227,7 +227,7 @@
     user_manager::RemoveUserDelegate* delegate) {}
 
 void FakeChromeUserManager::RemoveUserFromList(const AccountId& account_id) {
-  WallpaperManager::Get()->RemoveUserWallpaper(account_id);
+  WallpaperControllerClient::Get()->RemoveUserWallpaper(account_id);
   chromeos::ProfileHelper::Get()->RemoveUserFromListForTesting(account_id);
 
   const user_manager::UserList::iterator it =
diff --git a/chrome/browser/chromeos/login/users/user_manager_unittest.cc b/chrome/browser/chromeos/login/users/user_manager_unittest.cc
index 47bf69c..2fe119a 100644
--- a/chrome/browser/chromeos/login/users/user_manager_unittest.cc
+++ b/chrome/browser/chromeos/login/users/user_manager_unittest.cc
@@ -17,6 +17,8 @@
 #include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/ash/test_wallpaper_controller.h"
+#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
@@ -78,12 +80,19 @@
 
     ResetUserManager();
     WallpaperManager::Initialize();
+
+    wallpaper_controller_client_ =
+        std::make_unique<WallpaperControllerClient>();
+    wallpaper_controller_client_->InitForTesting(
+        test_wallpaper_controller_.CreateInterfacePtr());
   }
 
   void TearDown() override {
     // Unregister the in-memory local settings instance.
     local_state_.reset();
 
+    wallpaper_controller_client_.reset();
+
     // Shut down the DeviceSettingsService.
     DeviceSettingsService::Get()->UnsetSessionManager();
     TestingBrowserProcess::GetGlobal()->SetProfileManager(NULL);
@@ -148,6 +157,9 @@
       AccountId::FromUserEmail("user1@invalid.domain");
 
  protected:
+  std::unique_ptr<WallpaperControllerClient> wallpaper_controller_client_;
+  TestWallpaperController test_wallpaper_controller_;
+
   content::TestBrowserThreadBundle thread_bundle_;
 
   ScopedCrosSettingsTestHelper settings_helper_;
@@ -190,6 +202,7 @@
   EXPECT_EQ((*users)[1]->GetAccountId(), account_id0_at_invalid_domain_);
   EXPECT_EQ((*users)[2]->GetAccountId(), owner_account_id_at_invalid_domain_);
 
+  test_wallpaper_controller_.ClearCounts();
   SetDeviceSettings(true, owner_account_id_at_invalid_domain_.GetUserEmail(),
                     false);
   RetrieveTrustedDevicePolicies();
@@ -197,6 +210,9 @@
   users = &user_manager::UserManager::Get()->GetUsers();
   EXPECT_EQ(1U, users->size());
   EXPECT_EQ((*users)[0]->GetAccountId(), owner_account_id_at_invalid_domain_);
+  // Verify that the wallpaper is removed when user is removed.
+  wallpaper_controller_client_->FlushForTesting();
+  EXPECT_EQ(2, test_wallpaper_controller_.remove_user_wallpaper_count());
 }
 
 TEST_F(UserManagerTest, RegularUserLoggedInAsEphemeral) {
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
index fa60c08..b089fb04 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -21,9 +21,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/path_service.h"
 #include "base/sequenced_task_runner.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -45,14 +43,13 @@
 #include "chrome/browser/image_decoder.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/ash/ash_util.h"
-#include "chrome/common/chrome_paths.h"
+#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/account_id/account_id.h"
-#include "components/user_manager/known_user.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_image/user_image.h"
 #include "components/user_manager/user_names.h"
@@ -86,9 +83,6 @@
 
 const int kCacheWallpaperDelayMs = 500;
 
-// Known user keys.
-const char kWallpaperFilesId[] = "wallpaper-files-id";
-
 // The directory and file name to save the downloaded device policy controlled
 // wallpaper.
 const char kDeviceWallpaperDir[] = "device_wallpaper";
@@ -116,12 +110,6 @@
 // color.
 const SkColor kDefaultWallpaperColor = SK_ColorGRAY;
 
-// The path ids for directories.
-int dir_user_data_path_id = -1;            // chrome::DIR_USER_DATA
-int dir_chromeos_wallpapers_path_id = -1;  // chrome::DIR_CHROMEOS_WALLPAPERS
-int dir_chromeos_custom_wallpapers_path_id =
-    -1;  // chrome::DIR_CHROMEOS_CUSTOM_WALLPAPERS
-
 // The Wallpaper App that the user is using right now on Chrome OS. It's the
 // app that is used when the user right clicks on desktop and selects "Set
 // wallpaper" or when the user selects "Set wallpaper" from chrome://settings
@@ -182,54 +170,11 @@
   return false;
 }
 
-// This has once been copied from
-// brillo::cryptohome::home::SanitizeUserName(username) to be used for
-// wallpaper identification purpose only.
-//
-// Historic note: We need some way to identify users wallpaper files in
-// the device filesystem. Historically User::username_hash() was used for this
-// purpose, but it has two caveats:
-// 1. username_hash() is defined only after user has logged in.
-// 2. If cryptohome identifier changes, username_hash() will also change,
-//    and we may lose user => wallpaper files mapping at that point.
-// So this function gives WallpaperManager independent hashing method to break
-// this dependency.
-//
-wallpaper::WallpaperFilesId HashWallpaperFilesIdStr(
-    const std::string& files_id_unhashed) {
-  SystemSaltGetter* salt_getter = SystemSaltGetter::Get();
-  DCHECK(salt_getter);
-
-  // System salt must be defined at this point.
-  const SystemSaltGetter::RawSalt* salt = salt_getter->GetRawSalt();
-  if (!salt)
-    LOG(FATAL) << "WallpaperManager HashWallpaperFilesIdStr(): no salt!";
-
-  unsigned char binmd[base::kSHA1Length];
-  std::string lowercase(files_id_unhashed);
-  std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(),
-                 ::tolower);
-  std::vector<uint8_t> data = *salt;
-  std::copy(files_id_unhashed.begin(), files_id_unhashed.end(),
-            std::back_inserter(data));
-  base::SHA1HashBytes(data.data(), data.size(), binmd);
-  std::string result = base::HexEncode(binmd, sizeof(binmd));
-  std::transform(result.begin(), result.end(), result.begin(), ::tolower);
-  return wallpaper::WallpaperFilesId::FromString(result);
-}
-
 // Call |closure| when HashWallpaperFilesIdStr will not assert().
 void CallWhenCanGetFilesId(const base::Closure& closure) {
   SystemSaltGetter::Get()->AddOnSystemSaltReady(closure);
 }
 
-void SetKnownUserWallpaperFilesId(
-    const AccountId& account_id,
-    const wallpaper::WallpaperFilesId& wallpaper_files_id) {
-  user_manager::known_user::SetStringPref(account_id, kWallpaperFilesId,
-                                          wallpaper_files_id.id());
-}
-
 // A helper to set the wallpaper image for Classic Ash and Mash.
 void SetWallpaper(const gfx::ImageSkia& image, wallpaper::WallpaperInfo info) {
   if (ash_util::IsRunningInMash()) {
@@ -277,34 +222,28 @@
   return false;
 }
 
-// Deletes a list of wallpaper files in |file_list|.
-void DeleteWallpaperInList(const std::vector<base::FilePath>& file_list) {
-  for (std::vector<base::FilePath>::const_iterator it = file_list.begin();
-       it != file_list.end(); ++it) {
-    base::FilePath path = *it;
-    if (!base::DeleteFile(path, true))
-      LOG(ERROR) << "Failed to remove user wallpaper at " << path.value();
-  }
-}
-
 // Creates all new custom wallpaper directories for |wallpaper_files_id| if not
 // exist.
 void EnsureCustomWallpaperDirectories(
     const wallpaper::WallpaperFilesId& wallpaper_files_id) {
   base::FilePath dir;
-  dir = WallpaperManager::GetCustomWallpaperDir(kSmallWallpaperSubDir);
+  dir = WallpaperManager::GetCustomWallpaperDir(
+      ash::WallpaperController::kSmallWallpaperSubDir);
   dir = dir.Append(wallpaper_files_id.id());
   if (!base::PathExists(dir))
     base::CreateDirectory(dir);
-  dir = WallpaperManager::GetCustomWallpaperDir(kLargeWallpaperSubDir);
+  dir = WallpaperManager::GetCustomWallpaperDir(
+      ash::WallpaperController::kLargeWallpaperSubDir);
   dir = dir.Append(wallpaper_files_id.id());
   if (!base::PathExists(dir))
     base::CreateDirectory(dir);
-  dir = WallpaperManager::GetCustomWallpaperDir(kOriginalWallpaperSubDir);
+  dir = WallpaperManager::GetCustomWallpaperDir(
+      ash::WallpaperController::kOriginalWallpaperSubDir);
   dir = dir.Append(wallpaper_files_id.id());
   if (!base::PathExists(dir))
     base::CreateDirectory(dir);
-  dir = WallpaperManager::GetCustomWallpaperDir(kThumbnailWallpaperSubDir);
+  dir = WallpaperManager::GetCustomWallpaperDir(
+      ash::WallpaperController::kThumbnailWallpaperSubDir);
   dir = dir.Append(wallpaper_files_id.id());
   if (!base::PathExists(dir))
     base::CreateDirectory(dir);
@@ -332,11 +271,6 @@
 const char kSmallWallpaperSuffix[] = "_small";
 const char kLargeWallpaperSuffix[] = "_large";
 
-const char kSmallWallpaperSubDir[] = "small";
-const char kLargeWallpaperSubDir[] = "large";
-const char kOriginalWallpaperSubDir[] = "original";
-const char kThumbnailWallpaperSubDir[] = "thumb";
-
 const int kSmallWallpaperMaxWidth = 1366;
 const int kSmallWallpaperMaxHeight = 800;
 const int kLargeWallpaperMaxWidth = 2560;
@@ -353,7 +287,7 @@
 // PendingWallpaper is owned by WallpaperManager.
 class WallpaperManager::PendingWallpaper {
  public:
-  PendingWallpaper(const base::TimeDelta delay) : weak_factory_(this) {
+  explicit PendingWallpaper(const base::TimeDelta delay) : weak_factory_(this) {
     timer.Start(FROM_HERE, delay,
                 base::Bind(&WallpaperManager::PendingWallpaper::ProcessRequest,
                            weak_factory_.GetWeakPtr()));
@@ -632,21 +566,16 @@
 }
 
 // static
-void WallpaperManager::SetPathIds(int dir_user_data_enum,
-                                  int dir_chromeos_wallpapers_enum,
-                                  int dir_chromeos_custom_wallpapers_enum) {
-  dir_user_data_path_id = dir_user_data_enum;
-  dir_chromeos_wallpapers_path_id = dir_chromeos_wallpapers_enum;
-  dir_chromeos_custom_wallpapers_path_id = dir_chromeos_custom_wallpapers_enum;
-}
-
-// static
-base::FilePath WallpaperManager::GetCustomWallpaperDir(const char* sub_dir) {
-  base::FilePath custom_wallpaper_dir;
-  DCHECK(dir_chromeos_custom_wallpapers_path_id != -1);
-  CHECK(PathService::Get(dir_chromeos_custom_wallpapers_path_id,
-                         &custom_wallpaper_dir));
-  return custom_wallpaper_dir.Append(sub_dir);
+base::FilePath WallpaperManager::GetCustomWallpaperDir(
+    const std::string& sub_dir) {
+  if (!ash::Shell::HasInstance() || ash_util::IsRunningInMash()) {
+    // Some unit tests come here without a Shell instance.
+    // TODO(crbug.com/776464): This is intended not to work under mash. Make it
+    // work again after WallpaperManager is removed.
+    return base::FilePath();
+  }
+  return ash::Shell::Get()->wallpaper_controller()->GetCustomWallpaperDir(
+      sub_dir);
 }
 
 // static
@@ -725,7 +654,7 @@
 
 // static
 base::FilePath WallpaperManager::GetCustomWallpaperPath(
-    const char* sub_dir,
+    const std::string& sub_dir,
     const wallpaper::WallpaperFilesId& wallpaper_files_id,
     const std::string& file_name) {
   base::FilePath custom_wallpaper_path = GetCustomWallpaperDir(sub_dir);
@@ -758,8 +687,9 @@
     return;
   }
 
-  base::FilePath wallpaper_path = GetCustomWallpaperPath(
-      kOriginalWallpaperSubDir, wallpaper_files_id, file_name);
+  base::FilePath wallpaper_path =
+      GetCustomWallpaperPath(ash::WallpaperController::kOriginalWallpaperSubDir,
+                             wallpaper_files_id, file_name);
 
   const user_manager::User* user =
       user_manager::UserManager::Get()->FindUser(account_id);
@@ -802,7 +732,7 @@
 
 void WallpaperManager::SetDefaultWallpaper(const AccountId& account_id,
                                            bool show_wallpaper) {
-  RemoveUserWallpaper(account_id);
+  WallpaperControllerClient::Get()->RemoveUserWallpaper(account_id);
   InitializeUserWallpaperInfo(account_id);
   if (show_wallpaper)
     GetPendingWallpaper()->SetDefaultWallpaper(account_id);
@@ -910,7 +840,7 @@
         // Original wallpaper should be used in this case.
         // TODO(bshe): Generates cropped custom wallpaper for CENTER layout.
         if (info.layout == wallpaper::WALLPAPER_LAYOUT_CENTER)
-          sub_dir = kOriginalWallpaperSubDir;
+          sub_dir = ash::WallpaperController::kOriginalWallpaperSubDir;
         wallpaper_path = GetCustomWallpaperDir(sub_dir);
         wallpaper_path = wallpaper_path.Append(info.location);
       } else {
@@ -950,20 +880,6 @@
   GetPendingWallpaper()->SetDefaultWallpaper(user_manager::SignInAccountId());
 }
 
-void WallpaperManager::RemoveUserWallpaper(const AccountId& account_id) {
-  if (ash::Shell::HasInstance() && !ash_util::IsRunningInMash()) {
-    // Some unit tests come here without a Shell instance.
-    // TODO(crbug.com/776464): This is intended not to work under mash. Make it
-    // work again after WallpaperManager is removed.
-    bool is_persistent =
-        !user_manager::UserManager::Get()->IsUserNonCryptohomeDataEphemeral(
-            account_id);
-    ash::Shell::Get()->wallpaper_controller()->RemoveUserWallpaperInfo(
-        account_id, is_persistent);
-  }
-  DeleteUserWallpapers(account_id);
-}
-
 void WallpaperManager::SetUserWallpaperInfo(const AccountId& account_id,
                                             const WallpaperInfo& info,
                                             bool is_persistent) {
@@ -980,7 +896,6 @@
 
 void WallpaperManager::InitializeWallpaper() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  user_manager::UserManager* user_manager = user_manager::UserManager::Get();
 
   // Apply device customization.
   if (ShouldUseCustomizedDefaultWallpaper()) {
@@ -1009,6 +924,7 @@
     return;
   }
 
+  user_manager::UserManager* user_manager = user_manager::UserManager::Get();
   if (!user_manager->IsUserLoggedIn()) {
     if (!StartupUtils::IsDeviceRegistered())
       GetPendingWallpaper()->SetDefaultWallpaper(
@@ -1124,19 +1040,6 @@
   return loading_.size();
 }
 
-wallpaper::WallpaperFilesId WallpaperManager::GetFilesId(
-    const AccountId& account_id) const {
-  std::string stored_value;
-  if (user_manager::known_user::GetStringPref(account_id, kWallpaperFilesId,
-                                              &stored_value)) {
-    return wallpaper::WallpaperFilesId::FromString(stored_value);
-  }
-  const std::string& old_id = account_id.GetUserEmail();  // Migrated
-  const wallpaper::WallpaperFilesId files_id = HashWallpaperFilesIdStr(old_id);
-  SetKnownUserWallpaperFilesId(account_id, files_id);
-  return files_id;
-}
-
 bool WallpaperManager::IsPolicyControlled(const AccountId& account_id) const {
   WallpaperInfo info;
   if (!GetUserWallpaperInfo(account_id, &info))
@@ -1272,8 +1175,6 @@
       window_observer_(this),
       weak_factory_(this) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  SetPathIds(chrome::DIR_USER_DATA, chrome::DIR_CHROMEOS_WALLPAPERS,
-             chrome::DIR_CHROMEOS_CUSTOM_WALLPAPERS);
   SetDefaultWallpaperPathsFromCommandLine(
       base::CommandLine::ForCurrentProcess());
   registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_CHANGED,
@@ -1295,21 +1196,26 @@
     const base::FilePath& original_path,
     wallpaper::WallpaperLayout layout,
     std::unique_ptr<gfx::ImageSkia> image) {
-  base::DeleteFile(GetCustomWallpaperDir(kOriginalWallpaperSubDir)
-                       .Append(wallpaper_files_id.id()),
-                   true /* recursive */);
-  base::DeleteFile(GetCustomWallpaperDir(kSmallWallpaperSubDir)
-                       .Append(wallpaper_files_id.id()),
-                   true /* recursive */);
-  base::DeleteFile(GetCustomWallpaperDir(kLargeWallpaperSubDir)
-                       .Append(wallpaper_files_id.id()),
-                   true /* recursive */);
+  base::DeleteFile(
+      GetCustomWallpaperDir(ash::WallpaperController::kOriginalWallpaperSubDir)
+          .Append(wallpaper_files_id.id()),
+      true /* recursive */);
+  base::DeleteFile(
+      GetCustomWallpaperDir(ash::WallpaperController::kSmallWallpaperSubDir)
+          .Append(wallpaper_files_id.id()),
+      true /* recursive */);
+  base::DeleteFile(
+      GetCustomWallpaperDir(ash::WallpaperController::kLargeWallpaperSubDir)
+          .Append(wallpaper_files_id.id()),
+      true /* recursive */);
   EnsureCustomWallpaperDirectories(wallpaper_files_id);
   std::string file_name = original_path.BaseName().value();
-  base::FilePath small_wallpaper_path = GetCustomWallpaperPath(
-      kSmallWallpaperSubDir, wallpaper_files_id, file_name);
-  base::FilePath large_wallpaper_path = GetCustomWallpaperPath(
-      kLargeWallpaperSubDir, wallpaper_files_id, file_name);
+  base::FilePath small_wallpaper_path =
+      GetCustomWallpaperPath(ash::WallpaperController::kSmallWallpaperSubDir,
+                             wallpaper_files_id, file_name);
+  base::FilePath large_wallpaper_path =
+      GetCustomWallpaperPath(ash::WallpaperController::kLargeWallpaperSubDir,
+                             wallpaper_files_id, file_name);
 
   // Re-encode orginal file to jpeg format and saves the result in case that
   // resized wallpaper is not generated (i.e. chrome shutdown before resized
@@ -1333,9 +1239,9 @@
     base::WeakPtr<WallpaperManager> weak_ptr) {
   const std::string& temporary_wallpaper_dir =
       account_id.GetUserEmail();  // Migrated
-  if (MoveCustomWallpaperDirectory(kOriginalWallpaperSubDir,
-                                   temporary_wallpaper_dir,
-                                   wallpaper_files_id.id())) {
+  if (MoveCustomWallpaperDirectory(
+          ash::WallpaperController::kOriginalWallpaperSubDir,
+          temporary_wallpaper_dir, wallpaper_files_id.id())) {
     // Consider success if the original wallpaper is moved to the new directory.
     // Original wallpaper is the fallback if the correct resolution wallpaper
     // can not be found.
@@ -1343,13 +1249,15 @@
         FROM_HERE, base::Bind(&WallpaperManager::MoveCustomWallpapersSuccess,
                               weak_ptr, account_id, wallpaper_files_id));
   }
-  MoveCustomWallpaperDirectory(kLargeWallpaperSubDir, temporary_wallpaper_dir,
-                               wallpaper_files_id.id());
-  MoveCustomWallpaperDirectory(kSmallWallpaperSubDir, temporary_wallpaper_dir,
-                               wallpaper_files_id.id());
-  MoveCustomWallpaperDirectory(kThumbnailWallpaperSubDir,
+  MoveCustomWallpaperDirectory(ash::WallpaperController::kLargeWallpaperSubDir,
                                temporary_wallpaper_dir,
                                wallpaper_files_id.id());
+  MoveCustomWallpaperDirectory(ash::WallpaperController::kSmallWallpaperSubDir,
+                               temporary_wallpaper_dir,
+                               wallpaper_files_id.id());
+  MoveCustomWallpaperDirectory(
+      ash::WallpaperController::kThumbnailWallpaperSubDir,
+      temporary_wallpaper_dir, wallpaper_files_id.id());
 }
 
 // static
@@ -1366,7 +1274,8 @@
     // Falls back on original file if the correct resolution file does not
     // exist. This may happen when the original custom wallpaper is small or
     // browser shutdown before resized wallpaper saved.
-    valid_path = GetCustomWallpaperDir(kOriginalWallpaperSubDir);
+    valid_path = GetCustomWallpaperDir(
+        ash::WallpaperController::kOriginalWallpaperSubDir);
     valid_path = valid_path.Append(info.location);
   }
 
@@ -1376,7 +1285,7 @@
     // Note that account id is used instead of wallpaper_files_id here.
     const std::string& old_path = account_id.GetUserEmail();  // Migrated
     valid_path = GetCustomWallpaperPath(
-        kOriginalWallpaperSubDir,
+        ash::WallpaperController::kOriginalWallpaperSubDir,
         wallpaper::WallpaperFilesId::FromString(old_path), info.location);
   }
 
@@ -1498,8 +1407,6 @@
     if (info.location.empty())
       return;
 
-    base::FilePath wallpaper_dir;
-    base::FilePath wallpaper_path;
     if (info.type == wallpaper::CUSTOMIZED || info.type == wallpaper::POLICY ||
         info.type == wallpaper::DEVICE) {
       base::FilePath wallpaper_path;
@@ -1550,37 +1457,6 @@
   *wallpaper_cache_map = logged_in_users_cache;
 }
 
-void WallpaperManager::DeleteUserWallpapers(const AccountId& account_id) {
-  // System salt might not be ready in tests. Thus we don't have a valid
-  // wallpaper files id here.
-  if (!CanGetWallpaperFilesId())
-    return;
-
-  std::vector<base::FilePath> file_to_remove;
-  wallpaper::WallpaperFilesId wallpaper_files_id = GetFilesId(account_id);
-
-  // Remove small user wallpapers.
-  base::FilePath wallpaper_path = GetCustomWallpaperDir(kSmallWallpaperSubDir);
-  file_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id.id()));
-
-  // Remove large user wallpapers.
-  wallpaper_path = GetCustomWallpaperDir(kLargeWallpaperSubDir);
-  file_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id.id()));
-
-  // Remove user wallpaper thumbnails.
-  wallpaper_path = GetCustomWallpaperDir(kThumbnailWallpaperSubDir);
-  file_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id.id()));
-
-  // Remove original user wallpapers.
-  wallpaper_path = GetCustomWallpaperDir(kOriginalWallpaperSubDir);
-  file_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id.id()));
-
-  base::PostTaskWithTraits(FROM_HERE,
-                           {base::MayBlock(), base::TaskPriority::BACKGROUND,
-                            base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-                           base::Bind(&DeleteWallpaperInList, file_to_remove));
-}
-
 base::CommandLine* WallpaperManager::GetCommandLine() {
   base::CommandLine* command_line =
       command_line_for_testing_ ? command_line_for_testing_
@@ -1624,7 +1500,6 @@
                                      const WallpaperInfo& info,
                                      bool update_wallpaper,
                                      MovableOnDestroyCallbackHolder on_finish) {
-  base::FilePath wallpaper_dir;
   base::FilePath wallpaper_path;
 
   // Do a sanity check that file path information is not empty.
@@ -1657,9 +1532,10 @@
                       .InsertBeforeExtension(kSmallWallpaperSuffix)
                       .value();
     }
-    DCHECK(dir_chromeos_wallpapers_path_id != -1);
-    CHECK(PathService::Get(dir_chromeos_wallpapers_path_id, &wallpaper_dir));
-    wallpaper_path = wallpaper_dir.Append(file_name);
+    DCHECK(!ash::WallpaperController::dir_chrome_os_wallpapers_path_.empty());
+    wallpaper_path =
+        ash::WallpaperController::dir_chrome_os_wallpapers_path_.Append(
+            file_name);
 
     // If the wallpaper exists and it contains already the correct image we can
     // return immediately.
@@ -1678,10 +1554,9 @@
     // overlooked that case and caused these wallpapers not being loaded at all.
     // On some slow devices, it caused login webui not visible after upgrade to
     // M26 from M21. See crosbug.com/38429 for details.
-    base::FilePath user_data_dir;
-    DCHECK(dir_user_data_path_id != -1);
-    PathService::Get(dir_user_data_path_id, &user_data_dir);
-    wallpaper_path = user_data_dir.Append(info.location);
+    DCHECK(!ash::WallpaperController::dir_user_data_path_.empty());
+    wallpaper_path =
+        ash::WallpaperController::dir_user_data_path_.Append(info.location);
     StartLoad(account_id, info, update_wallpaper, wallpaper_path,
               std::move(on_finish));
   } else {
@@ -1718,7 +1593,8 @@
     task_runner_->PostTask(
         FROM_HERE, base::Bind(&WallpaperManager::MoveCustomWallpapersOnWorker,
                               logged_in_user->GetAccountId(),
-                              GetFilesId(logged_in_user->GetAccountId()),
+                              WallpaperControllerClient::Get()->GetFilesId(
+                                  logged_in_user->GetAccountId()),
                               base::ThreadTaskRunnerHandle::Get(),
                               weak_factory_.GetWeakPtr()));
   }
@@ -1765,12 +1641,9 @@
 }
 
 base::FilePath WallpaperManager::GetDeviceWallpaperDir() {
-  base::FilePath wallpaper_dir;
-  if (!PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS, &wallpaper_dir)) {
-    LOG(ERROR) << "Unable to get wallpaper dir.";
-    return base::FilePath();
-  }
-  return wallpaper_dir.Append(kDeviceWallpaperDir);
+  DCHECK(!ash::WallpaperController::dir_chrome_os_wallpapers_path_.empty());
+  return ash::WallpaperController::dir_chrome_os_wallpapers_path_.Append(
+      kDeviceWallpaperDir);
 }
 
 base::FilePath WallpaperManager::GetDeviceWallpaperFilePath() {
@@ -2079,15 +1952,11 @@
       WALLPAPERS_APPS_NUM);
 }
 
-bool WallpaperManager::CanGetWallpaperFilesId() const {
-  return SystemSaltGetter::IsInitialized() &&
-         SystemSaltGetter::Get()->GetRawSalt();
-}
-
 const char* WallpaperManager::GetCustomWallpaperSubdirForCurrentResolution() {
   WallpaperResolution resolution = GetAppropriateResolution();
-  return resolution == WALLPAPER_RESOLUTION_SMALL ? kSmallWallpaperSubDir
-                                                  : kLargeWallpaperSubDir;
+  return resolution == WALLPAPER_RESOLUTION_SMALL
+             ? ash::WallpaperController::kSmallWallpaperSubDir
+             : ash::WallpaperController::kLargeWallpaperSubDir;
 }
 
 void WallpaperManager::CreateSolidDefaultWallpaper() {
@@ -2152,7 +2021,7 @@
 void WallpaperManager::SetPolicyControlledWallpaper(
     const AccountId& account_id,
     std::unique_ptr<user_manager::UserImage> user_image) {
-  if (!CanGetWallpaperFilesId()) {
+  if (!WallpaperControllerClient::Get()->CanGetWallpaperFilesId()) {
     CallWhenCanGetFilesId(
         base::Bind(&WallpaperManager::SetPolicyControlledWallpaper,
                    weak_factory_.GetWeakPtr(), account_id,
@@ -2160,7 +2029,8 @@
     return;
   }
 
-  const wallpaper::WallpaperFilesId wallpaper_files_id = GetFilesId(account_id);
+  const wallpaper::WallpaperFilesId wallpaper_files_id =
+      WallpaperControllerClient::Get()->GetFilesId(account_id);
 
   if (!wallpaper_files_id.is_valid())
     LOG(FATAL) << "Wallpaper flies id if invalid!";
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
index ee4b384..6eb4a07 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
@@ -71,12 +71,6 @@
 extern const char kSmallWallpaperSuffix[];
 extern const char kLargeWallpaperSuffix[];
 
-// Directory names of custom wallpapers.
-extern const char kSmallWallpaperSubDir[];
-extern const char kLargeWallpaperSubDir[];
-extern const char kOriginalWallpaperSubDir[];
-extern const char kThumbnailWallpaperSubDir[];
-
 // The width and height of small/large resolution wallpaper. When screen size is
 // smaller than |kSmallWallpaperMaxWidth| and |kSmallWallpaperMaxHeight|, the
 // small resolution wallpaper should be used. Otherwise, use the large
@@ -200,13 +194,8 @@
   // WallpaperManager to remove any observers it has registered.
   static void Shutdown();
 
-  // Set path IDs for used directories
-  static void SetPathIds(int dir_user_data_enum,
-                         int dir_chromeos_wallpapers_enum,
-                         int dir_chromeos_custom_wallpapers_enum);
-
-  // Returns custom wallpaper directory by appending corresponding |sub_dir|.
-  static base::FilePath GetCustomWallpaperDir(const char* sub_dir);
+  // A wrapper of |WallpaperController::GetCustomWallpaperDir|.
+  static base::FilePath GetCustomWallpaperDir(const std::string& sub_dir);
 
   // Resizes |image| to a resolution which is nearest to |preferred_width| and
   // |preferred_height| while respecting the |layout| choice. |output_skia| is
@@ -232,7 +221,7 @@
   // Returns custom wallpaper path. Append |sub_dir|, |wallpaper_files_id| and
   // |file_name| to custom wallpaper directory.
   static base::FilePath GetCustomWallpaperPath(
-      const char* sub_dir,
+      const std::string& sub_dir,
       const wallpaper::WallpaperFilesId& wallpaper_files_id,
       const std::string& file_name);
 
@@ -282,9 +271,6 @@
   // device policy wallpaper or the default wallpaper.
   void ShowSigninWallpaper();
 
-  // Removes all of |account_id|'s saved wallpapers and related info.
-  void RemoveUserWallpaper(const AccountId& account_id);
-
   // A wrapper of |WallpaperController::SetUserWallpaperInfo|.
   void SetUserWallpaperInfo(const AccountId& account_id,
                             const wallpaper::WallpaperInfo& info,
@@ -328,9 +314,6 @@
   // Returns queue size.
   size_t GetPendingListSizeForTesting() const;
 
-  // Ruturns files identifier for the |account_id|.
-  wallpaper::WallpaperFilesId GetFilesId(const AccountId& account_id) const;
-
   // Returns whether a wallpaper policy is enforced for |account_id|.
   bool IsPolicyControlled(const AccountId& account_id) const;
 
@@ -450,9 +433,6 @@
   // world, logged in users' wallpaper cache is not disposable.
   void ClearDisposableWallpaperCache();
 
-  // Deletes all |account_id| related custom wallpapers and directories.
-  void DeleteUserWallpapers(const AccountId& account_id);
-
   // Gets the CommandLine representing the current process's command line.
   base::CommandLine* GetCommandLine();
 
@@ -574,9 +554,6 @@
   // Record the Wallpaper App that the user is using right now on Chrome OS.
   void RecordWallpaperAppType();
 
-  // Returns true if wallpaper files id can be returned successfully.
-  bool CanGetWallpaperFilesId() const;
-
   // Returns wallpaper subdirectory name for current resolution.
   const char* GetCustomWallpaperSubdirForCurrentResolution();
 
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
index 9eb8c2ea..dabd2a8 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
@@ -22,6 +22,7 @@
 #include "base/values.h"
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.h"
 #include "chrome/browser/ui/ash/session_controller_client.h"
+#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_browser_process.h"
@@ -63,6 +64,17 @@
 const char kTestUser2[] = "test2@domain.com";
 const char kTestUser2Hash[] = "test2@domain.com-hash";
 
+// Helper function to get wallpaper files id.
+wallpaper::WallpaperFilesId GetFilesId(const AccountId& account_id) {
+  return WallpaperControllerClient::Get()->GetFilesId(account_id);
+}
+
+// Helper function to remove user wallpaper.
+void RemoveUserWallpaper(const AccountId& account_id) {
+  WallpaperControllerClient::Get()->RemoveUserWallpaper(account_id);
+  WallpaperControllerClient::Get()->FlushForTesting();
+}
+
 }  // namespace
 
 class WallpaperManagerBrowserTest : public InProcessBrowserTest {
@@ -95,23 +107,23 @@
   void WaitAsyncWallpaperLoadStarted() { base::RunLoop().RunUntilIdle(); }
 
   void WaitUntilCustomWallpapersDeleted(const AccountId& account_id) {
-    WallpaperManager* wallpaper_manager = WallpaperManager::Get();
-    wallpaper::WallpaperFilesId wallpaper_file_id =
-        wallpaper_manager->GetFilesId(account_id);
+    wallpaper::WallpaperFilesId wallpaper_file_id = GetFilesId(account_id);
 
     base::FilePath small_wallpaper_dir =
-        WallpaperManager::GetCustomWallpaperDir(chromeos::kSmallWallpaperSubDir)
+        WallpaperManager::GetCustomWallpaperDir(
+            ash::WallpaperController::kSmallWallpaperSubDir)
             .Append(wallpaper_file_id.id());
     base::FilePath large_wallpaper_dir =
-        WallpaperManager::GetCustomWallpaperDir(chromeos::kLargeWallpaperSubDir)
+        WallpaperManager::GetCustomWallpaperDir(
+            ash::WallpaperController::kLargeWallpaperSubDir)
             .Append(wallpaper_file_id.id());
     base::FilePath original_wallpaper_dir =
         WallpaperManager::GetCustomWallpaperDir(
-            chromeos::kOriginalWallpaperSubDir)
+            ash::WallpaperController::kOriginalWallpaperSubDir)
             .Append(wallpaper_file_id.id());
     base::FilePath thumbnail_wallpaper_dir =
         WallpaperManager::GetCustomWallpaperDir(
-            chromeos::kThumbnailWallpaperSubDir)
+            ash::WallpaperController::kThumbnailWallpaperSubDir)
             .Append(wallpaper_file_id.id());
 
     while (base::PathExists(small_wallpaper_dir) ||
@@ -213,10 +225,12 @@
   WallpaperManager* wallpaper_manager = WallpaperManager::Get();
   LogIn(test_account_id1_, kTestUser1Hash);
   std::string id = base::Int64ToString(base::Time::Now().ToInternalValue());
-  base::FilePath small_wallpaper_path = GetCustomWallpaperPath(
-      chromeos::kSmallWallpaperSubDir, test_account1_wallpaper_files_id_, id);
-  base::FilePath large_wallpaper_path = GetCustomWallpaperPath(
-      chromeos::kLargeWallpaperSubDir, test_account1_wallpaper_files_id_, id);
+  base::FilePath small_wallpaper_path =
+      GetCustomWallpaperPath(ash::WallpaperController::kSmallWallpaperSubDir,
+                             test_account1_wallpaper_files_id_, id);
+  base::FilePath large_wallpaper_path =
+      GetCustomWallpaperPath(ash::WallpaperController::kLargeWallpaperSubDir,
+                             test_account1_wallpaper_files_id_, id);
 
   // Saves the small/large resolution wallpapers to small/large custom
   // wallpaper paths.
@@ -301,8 +315,9 @@
 
   // Change wallpaper to a custom wallpaper.
   std::string id = base::Int64ToString(base::Time::Now().ToInternalValue());
-  base::FilePath small_wallpaper_path = GetCustomWallpaperPath(
-      chromeos::kSmallWallpaperSubDir, test_account1_wallpaper_files_id_, id);
+  base::FilePath small_wallpaper_path =
+      GetCustomWallpaperPath(ash::WallpaperController::kSmallWallpaperSubDir,
+                             test_account1_wallpaper_files_id_, id);
   ASSERT_TRUE(wallpaper_manager_test_utils::WriteJPEGFile(
       small_wallpaper_path, kSmallWallpaperWidth, kSmallWallpaperHeight,
       wallpaper_manager_test_utils::kSmallDefaultWallpaperColor));
@@ -358,6 +373,8 @@
   // wallpaper is not loaded at login screen. One example is: crosbug.com/38429.
 }
 
+// TODO(crbug.com/776464): This test implicitly calls |InitializeWallpaper|.
+// Move it to |WallpaperControllerTest| after |InitializeWallpaper| is migrated.
 // Some users have old user profiles which may never get a chance to migrate.
 // This tests make sure we compatible with these profiles.
 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
@@ -367,7 +384,7 @@
   // Old wallpaper migration code doesn't exist in codebase anymore. So if
   // user's profile is not migrated, it is the same as no wallpaper info. To
   // simulate this, we remove user's wallpaper info here.
-  WallpaperManager::Get()->RemoveUserWallpaper(test_account_id1_);
+  RemoveUserWallpaper(test_account_id1_);
 }
 
 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
@@ -444,7 +461,7 @@
   // Old wallpaper migration code doesn't exist in codebase anymore. So if
   // user's profile is not migrated, it is the same as no wallpaper info. To
   // simulate this, we remove user's wallpaper info here.
-  WallpaperManager::Get()->RemoveUserWallpaper(test_account_id1_);
+  RemoveUserWallpaper(test_account_id1_);
 }
 
 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation,
@@ -505,10 +522,12 @@
 
   std::string id = base::Int64ToString(base::Time::Now().ToInternalValue());
   WallpaperManager* wallpaper_manager = WallpaperManager::Get();
-  base::FilePath small_wallpaper_path = GetCustomWallpaperPath(
-      chromeos::kSmallWallpaperSubDir, test_account1_wallpaper_files_id_, id);
-  base::FilePath large_wallpaper_path = GetCustomWallpaperPath(
-      chromeos::kLargeWallpaperSubDir, test_account1_wallpaper_files_id_, id);
+  base::FilePath small_wallpaper_path =
+      GetCustomWallpaperPath(ash::WallpaperController::kSmallWallpaperSubDir,
+                             test_account1_wallpaper_files_id_, id);
+  base::FilePath large_wallpaper_path =
+      GetCustomWallpaperPath(ash::WallpaperController::kLargeWallpaperSubDir,
+                             test_account1_wallpaper_files_id_, id);
 
   // Saves the small/large resolution wallpapers to small/large custom
   // wallpaper paths.
@@ -878,8 +897,9 @@
   std::string id = std::to_string(
       std::abs((base::Time::Now() - base::Time::Now().LocalMidnight())
                    .InMilliseconds()));
-  base::FilePath small_wallpaper_path = GetCustomWallpaperPath(
-      chromeos::kSmallWallpaperSubDir, test_account2_wallpaper_files_id_, id);
+  base::FilePath small_wallpaper_path =
+      GetCustomWallpaperPath(ash::WallpaperController::kSmallWallpaperSubDir,
+                             test_account2_wallpaper_files_id_, id);
   ASSERT_TRUE(wallpaper_manager_test_utils::WriteJPEGFile(
       small_wallpaper_path, kSmallWallpaperWidth, kSmallWallpaperHeight,
       wallpaper_manager_test_utils::kCustomWallpaperColor));
@@ -915,6 +935,8 @@
       wallpaper_manager_test_utils::kCustomWallpaperColor));
 }
 
+// TODO(crbug.com/776464): Move this test to |WallpaperControllerTest| after
+// |ShowUserWallpaper| is migrated.
 // Tests that if a user who has a custom wallpaper is removed from the device,
 // only the directory that contains the user's custom wallpapers gets removed.
 // The other user's custom wallpaper is not affected.
@@ -927,12 +949,12 @@
   // exists.
   LogIn(test_account_id1_, kTestUser1Hash);
   wallpaper::WallpaperFilesId wallpaper_file_id1 =
-      wallpaper_manager->GetFilesId(test_account_id1_);
+      GetFilesId(test_account_id1_);
   const std::string id = std::to_string(
       std::abs((base::Time::Now() - base::Time::Now().LocalMidnight())
                    .InMilliseconds()));
   base::FilePath small_wallpaper_path = GetCustomWallpaperPath(
-      chromeos::kSmallWallpaperSubDir, wallpaper_file_id1, id);
+      ash::WallpaperController::kSmallWallpaperSubDir, wallpaper_file_id1, id);
   ASSERT_TRUE(wallpaper_manager_test_utils::WriteJPEGFile(
       small_wallpaper_path, kSmallWallpaperWidth, kSmallWallpaperHeight,
       wallpaper_manager_test_utils::kSmallDefaultWallpaperColor));
@@ -950,9 +972,9 @@
   // Now login another user and set a custom wallpaper for it.
   LogIn(test_account_id2_, kTestUser2Hash);
   wallpaper::WallpaperFilesId wallpaper_file_id2 =
-      wallpaper_manager->GetFilesId(test_account_id2_);
+      GetFilesId(test_account_id2_);
   base::FilePath small_wallpaper_path2 = GetCustomWallpaperPath(
-      chromeos::kSmallWallpaperSubDir, wallpaper_file_id2, id);
+      ash::WallpaperController::kSmallWallpaperSubDir, wallpaper_file_id2, id);
   ASSERT_TRUE(wallpaper_manager_test_utils::WriteJPEGFile(
       small_wallpaper_path2, kSmallWallpaperWidth, kSmallWallpaperHeight,
       wallpaper_manager_test_utils::kSmallDefaultWallpaperColor));
@@ -968,7 +990,7 @@
   EXPECT_TRUE(base::PathExists(small_wallpaper_path2));
 
   // Simulate the removal of |test_account_id2_|.
-  wallpaper_manager->RemoveUserWallpaper(test_account_id2_);
+  RemoveUserWallpaper(test_account_id2_);
   // Wait until all files under the user's custom_wallpapers directory are
   // removed.
   WaitUntilCustomWallpapersDeleted(test_account_id2_);
@@ -977,6 +999,8 @@
   EXPECT_TRUE(base::PathExists(small_wallpaper_path));
 }
 
+// TODO(crbug.com/776464): Move this test to |WallpaperControllerTest| after
+// |ShowUserWallpaper| is migrated.
 // Tests that if a user who has a default wallpaper is removed from the device,
 // the other user's custom wallpaper is not affected.
 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
@@ -988,12 +1012,12 @@
   // wallpaper exists.
   LogIn(test_account_id1_, kTestUser1Hash);
   wallpaper::WallpaperFilesId wallpaper_file_id1 =
-      wallpaper_manager->GetFilesId(test_account_id1_);
+      GetFilesId(test_account_id1_);
   std::string id = std::to_string(
       std::abs((base::Time::Now() - base::Time::Now().LocalMidnight())
                    .InMilliseconds()));
   base::FilePath small_wallpaper_path = GetCustomWallpaperPath(
-      chromeos::kSmallWallpaperSubDir, wallpaper_file_id1, id);
+      ash::WallpaperController::kSmallWallpaperSubDir, wallpaper_file_id1, id);
   ASSERT_TRUE(wallpaper_manager_test_utils::WriteJPEGFile(
       small_wallpaper_path, kSmallWallpaperWidth, kSmallWallpaperHeight,
       wallpaper_manager_test_utils::kSmallDefaultWallpaperColor));
@@ -1011,7 +1035,7 @@
   // Now login another user and set a default wallpaper.
   LogIn(test_account_id2_, kTestUser2Hash);
   wallpaper::WallpaperFilesId wallpaper_file_id2 =
-      wallpaper_manager->GetFilesId(test_account_id2_);
+      GetFilesId(test_account_id2_);
   WallpaperInfo info2 = {"", WALLPAPER_LAYOUT_CENTER_CROPPED,
                          wallpaper::DEFAULT, base::Time::Now().LocalMidnight()};
   wallpaper_manager->SetUserWallpaperInfo(test_account_id2_, info2, true);
@@ -1020,7 +1044,7 @@
   wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
 
   // Simulate the removal of |test_account_id2_|.
-  wallpaper_manager->RemoveUserWallpaper(test_account_id2_);
+  RemoveUserWallpaper(test_account_id2_);
   WaitUntilCustomWallpapersDeleted(test_account_id2_);
 
   // Test that the other user's wallpaper is not affected.
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_unittest.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_unittest.cc
index 5ce7ee4..87b24a5 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_unittest.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_unittest.cc
@@ -119,40 +119,4 @@
   EXPECT_FALSE(test_api->GetPathFromCache(test_account_id_3, &path));
 }
 
-// Test that the user's wallpaper cache is cleared after the user is removed.
-TEST_F(WallpaperManagerCacheTest, CacheClearedOnUserRemoval) {
-  const AccountId test_account_id_1 =
-      AccountId::FromUserEmail("test1@example.com");
-  const AccountId test_account_id_2 =
-      AccountId::FromUserEmail("test2@example.com");
-  const base::FilePath path1("user1_custom_path");
-  const base::FilePath path2("user2_custom_path");
-  fake_user_manager()->AddUser(test_account_id_1);
-  fake_user_manager()->AddUser(test_account_id_2);
-
-  std::unique_ptr<WallpaperManager::TestApi> test_api(
-      new WallpaperManager::TestApi(WallpaperManager::Get()));
-
-  const gfx::ImageSkia test_user_1_wallpaper = CreateTestImage(SK_ColorRED);
-  const gfx::ImageSkia test_user_2_wallpaper = CreateTestImage(SK_ColorGREEN);
-  test_api->SetWallpaperCache(test_account_id_1, path1, test_user_1_wallpaper);
-  test_api->SetWallpaperCache(test_account_id_2, path2, test_user_2_wallpaper);
-
-  gfx::ImageSkia cached_wallpaper;
-  // Test that both user1 and user2's wallpaper can be found in cache.
-  EXPECT_TRUE(
-      test_api->GetWallpaperFromCache(test_account_id_1, &cached_wallpaper));
-  EXPECT_TRUE(
-      test_api->GetWallpaperFromCache(test_account_id_2, &cached_wallpaper));
-
-  // Remove user2.
-  fake_user_manager()->RemoveUserFromList(test_account_id_2);
-
-  // Test that only user1's wallpaper can be found in cache.
-  EXPECT_TRUE(
-      test_api->GetWallpaperFromCache(test_account_id_1, &cached_wallpaper));
-  EXPECT_FALSE(
-      test_api->GetWallpaperFromCache(test_account_id_2, &cached_wallpaper));
-}
-
 }  // namespace chromeos
diff --git a/chrome/browser/ui/ash/test_wallpaper_controller.cc b/chrome/browser/ui/ash/test_wallpaper_controller.cc
index 2323147..fd41f42 100644
--- a/chrome/browser/ui/ash/test_wallpaper_controller.cc
+++ b/chrome/browser/ui/ash/test_wallpaper_controller.cc
@@ -8,6 +8,10 @@
 
 TestWallpaperController::~TestWallpaperController() = default;
 
+void TestWallpaperController::ClearCounts() {
+  remove_user_wallpaper_count_ = 0;
+}
+
 ash::mojom::WallpaperControllerPtr
 TestWallpaperController::CreateInterfacePtr() {
   ash::mojom::WallpaperControllerPtr ptr;
@@ -15,8 +19,11 @@
   return ptr;
 }
 
-void TestWallpaperController::SetClient(
-    ash::mojom::WallpaperControllerClientPtr client) {
+void TestWallpaperController::SetClientAndPaths(
+    ash::mojom::WallpaperControllerClientPtr client,
+    const base::FilePath& user_data_path,
+    const base::FilePath& chromeos_wallpapers_path,
+    const base::FilePath& chromeos_custom_wallpapers_path) {
   was_client_set_ = true;
 }
 
@@ -63,8 +70,9 @@
 }
 
 void TestWallpaperController::RemoveUserWallpaper(
-    ash::mojom::WallpaperUserInfoPtr user_info) {
-  NOTIMPLEMENTED();
+    ash::mojom::WallpaperUserInfoPtr user_info,
+    const std::string& wallpaper_files_id) {
+  remove_user_wallpaper_count_++;
 }
 
 void TestWallpaperController::SetWallpaper(
@@ -81,4 +89,4 @@
 void TestWallpaperController::GetWallpaperColors(
     GetWallpaperColorsCallback callback) {
   NOTIMPLEMENTED();
-}
\ No newline at end of file
+}
diff --git a/chrome/browser/ui/ash/test_wallpaper_controller.h b/chrome/browser/ui/ash/test_wallpaper_controller.h
index 6b3f8fa4..a6d150c 100644
--- a/chrome/browser/ui/ash/test_wallpaper_controller.h
+++ b/chrome/browser/ui/ash/test_wallpaper_controller.h
@@ -18,13 +18,21 @@
 
   ~TestWallpaperController() override;
 
+  void ClearCounts();
+
   bool was_client_set() const { return was_client_set_; }
 
+  int remove_user_wallpaper_count() { return remove_user_wallpaper_count_; }
+
   // Returns a mojo interface pointer bound to this object.
   ash::mojom::WallpaperControllerPtr CreateInterfacePtr();
 
   // ash::mojom::WallpaperController:
-  void SetClient(ash::mojom::WallpaperControllerClientPtr client) override;
+  void SetClientAndPaths(
+      ash::mojom::WallpaperControllerClientPtr client,
+      const base::FilePath& user_data_path,
+      const base::FilePath& chromeos_wallpapers_path,
+      const base::FilePath& chromeos_custom_wallpapers_path) override;
   void SetCustomWallpaper(ash::mojom::WallpaperUserInfoPtr user_info,
                           const std::string& wallpaper_files_id,
                           const std::string& file_name,
@@ -45,7 +53,8 @@
       const base::FilePath& resized_directory) override;
   void ShowUserWallpaper(ash::mojom::WallpaperUserInfoPtr user_info) override;
   void ShowSigninWallpaper() override;
-  void RemoveUserWallpaper(ash::mojom::WallpaperUserInfoPtr user_info) override;
+  void RemoveUserWallpaper(ash::mojom::WallpaperUserInfoPtr user_info,
+                           const std::string& wallpaper_files_id) override;
   void SetWallpaper(const SkBitmap& wallpaper,
                     const wallpaper::WallpaperInfo& wallpaper_info) override;
   void AddObserver(
@@ -57,7 +66,9 @@
 
   bool was_client_set_ = false;
 
+  int remove_user_wallpaper_count_ = 0;
+
   DISALLOW_COPY_AND_ASSIGN(TestWallpaperController);
 };
 
-#endif  // CHROME_BROWSER_UI_ASH_TEST_WALLPAPER_CONTROLLER_H_
\ No newline at end of file
+#endif  // CHROME_BROWSER_UI_ASH_TEST_WALLPAPER_CONTROLLER_H_
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client.cc b/chrome/browser/ui/ash/wallpaper_controller_client.cc
index 9fe8f0e..56ef3bb3 100644
--- a/chrome/browser/ui/ash/wallpaper_controller_client.cc
+++ b/chrome/browser/ui/ash/wallpaper_controller_client.cc
@@ -5,19 +5,32 @@
 #include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 
 #include "ash/public/interfaces/constants.mojom.h"
+#include "base/path_service.h"
+#include "base/sha1.h"
+#include "base/strings/string_number_conversions.h"
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
+#include "chrome/common/chrome_paths.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
+#include "components/user_manager/known_user.h"
 #include "components/wallpaper/wallpaper_files_id.h"
 #include "content/public/common/service_manager_connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 namespace {
 
+// Known user keys.
+const char kWallpaperFilesId[] = "wallpaper-files-id";
+
 WallpaperControllerClient* g_instance = nullptr;
 
 // Creates a mojom::WallpaperUserInfo for the account id. Returns nullptr if
 // user manager cannot find the user.
 ash::mojom::WallpaperUserInfoPtr AccountIdToWallpaperUserInfo(
     const AccountId& account_id) {
+  if (!account_id.is_valid()) {
+    // |account_id| may be invalid in tests.
+    return nullptr;
+  }
   const user_manager::User* user =
       user_manager::UserManager::Get()->FindUser(account_id);
   if (!user)
@@ -35,6 +48,41 @@
   return wallpaper_user_info;
 }
 
+// This has once been copied from
+// brillo::cryptohome::home::SanitizeUserName(username) to be used for
+// wallpaper identification purpose only.
+//
+// Historic note: We need some way to identify users wallpaper files in
+// the device filesystem. Historically User::username_hash() was used for this
+// purpose, but it has two caveats:
+// 1. username_hash() is defined only after user has logged in.
+// 2. If cryptohome identifier changes, username_hash() will also change,
+//    and we may lose user => wallpaper files mapping at that point.
+// So this function gives WallpaperManager independent hashing method to break
+// this dependency.
+wallpaper::WallpaperFilesId HashWallpaperFilesIdStr(
+    const std::string& files_id_unhashed) {
+  chromeos::SystemSaltGetter* salt_getter = chromeos::SystemSaltGetter::Get();
+  DCHECK(salt_getter);
+
+  // System salt must be defined at this point.
+  const chromeos::SystemSaltGetter::RawSalt* salt = salt_getter->GetRawSalt();
+  if (!salt)
+    LOG(FATAL) << "WallpaperManager HashWallpaperFilesIdStr(): no salt!";
+
+  unsigned char binmd[base::kSHA1Length];
+  std::string lowercase(files_id_unhashed);
+  std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(),
+                 ::tolower);
+  std::vector<uint8_t> data = *salt;
+  std::copy(files_id_unhashed.begin(), files_id_unhashed.end(),
+            std::back_inserter(data));
+  base::SHA1HashBytes(data.data(), data.size(), binmd);
+  std::string result = base::HexEncode(binmd, sizeof(binmd));
+  std::transform(result.begin(), result.end(), result.begin(), ::tolower);
+  return wallpaper::WallpaperFilesId::FromString(result);
+}
+
 }  // namespace
 
 WallpaperControllerClient::WallpaperControllerClient() : binding_(this) {
@@ -65,6 +113,33 @@
   return g_instance;
 }
 
+bool WallpaperControllerClient::CanGetWallpaperFilesId() const {
+  return chromeos::SystemSaltGetter::IsInitialized() &&
+         chromeos::SystemSaltGetter::Get()->GetRawSalt();
+}
+
+wallpaper::WallpaperFilesId WallpaperControllerClient::GetFilesId(
+    const AccountId& account_id) const {
+  // System salt might not be ready in tests. Thus we don't have a valid
+  // wallpaper files id here.
+  if (!CanGetWallpaperFilesId())
+    return wallpaper::WallpaperFilesId();
+
+  std::string stored_value;
+  if (user_manager::known_user::GetStringPref(account_id, kWallpaperFilesId,
+                                              &stored_value)) {
+    return wallpaper::WallpaperFilesId::FromString(stored_value);
+  }
+
+  // Migrated.
+  const std::string& old_id = account_id.GetUserEmail();
+  const wallpaper::WallpaperFilesId wallpaper_files_id =
+      HashWallpaperFilesIdStr(old_id);
+  user_manager::known_user::SetStringPref(account_id, kWallpaperFilesId,
+                                          wallpaper_files_id.id());
+  return wallpaper_files_id;
+}
+
 void WallpaperControllerClient::SetCustomWallpaper(
     const AccountId& account_id,
     const wallpaper::WallpaperFilesId& wallpaper_files_id,
@@ -132,7 +207,8 @@
       AccountIdToWallpaperUserInfo(account_id);
   if (!user_info)
     return;
-  wallpaper_controller_->RemoveUserWallpaper(std::move(user_info));
+  wallpaper_controller_->RemoveUserWallpaper(std::move(user_info),
+                                             GetFilesId(account_id).id());
 }
 
 void WallpaperControllerClient::OpenWallpaperPicker() {
@@ -148,5 +224,18 @@
 void WallpaperControllerClient::BindAndSetClient() {
   ash::mojom::WallpaperControllerClientPtr client;
   binding_.Bind(mojo::MakeRequest(&client));
-  wallpaper_controller_->SetClient(std::move(client));
+
+  // Get the paths of wallpaper directories.
+  base::FilePath user_data_path;
+  CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_path));
+  base::FilePath chromeos_wallpapers_path;
+  CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS,
+                         &chromeos_wallpapers_path));
+  base::FilePath chromeos_custom_wallpapers_path;
+  CHECK(PathService::Get(chrome::DIR_CHROMEOS_CUSTOM_WALLPAPERS,
+                         &chromeos_custom_wallpapers_path));
+
+  wallpaper_controller_->SetClientAndPaths(std::move(client), user_data_path,
+                                           chromeos_wallpapers_path,
+                                           chromeos_custom_wallpapers_path);
 }
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client.h b/chrome/browser/ui/ash/wallpaper_controller_client.h
index f9a0af2..3b9d5bdf 100644
--- a/chrome/browser/ui/ash/wallpaper_controller_client.h
+++ b/chrome/browser/ui/ash/wallpaper_controller_client.h
@@ -30,6 +30,13 @@
 
   static WallpaperControllerClient* Get();
 
+  // TODO(crbug.com/776464): Move this to anonymous namesapce.
+  // Returns true if wallpaper files id can be returned successfully.
+  bool CanGetWallpaperFilesId() const;
+
+  // Returns files identifier for the |account_id|.
+  wallpaper::WallpaperFilesId GetFilesId(const AccountId& account_id) const;
+
   // Wrappers around the ash::mojom::WallpaperController interface.
   void SetCustomWallpaper(const AccountId& account_id,
                           const wallpaper::WallpaperFilesId& wallpaper_files_id,
@@ -70,4 +77,4 @@
   DISALLOW_COPY_AND_ASSIGN(WallpaperControllerClient);
 };
 
-#endif  // CHROME_BROWSER_UI_ASH_WALLPAPER_CONTROLLER_CLIENT_H_
\ No newline at end of file
+#endif  // CHROME_BROWSER_UI_ASH_WALLPAPER_CONTROLLER_CLIENT_H_
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_userlist_unittest.cc b/chrome/browser/ui/webui/chromeos/login/signin_userlist_unittest.cc
index 7c91558..7a3af9af 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_userlist_unittest.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_userlist_unittest.cc
@@ -13,6 +13,8 @@
 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h"
 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller_delegate.h"
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
+#include "chrome/browser/ui/ash/test_wallpaper_controller.h"
+#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "components/proximity_auth/screenlock_bridge.h"
@@ -65,12 +67,17 @@
     fake_user_manager_->set_owner_id(AccountId::FromUserEmail(kOwner));
 
     chromeos::WallpaperManager::Initialize();
+    wallpaper_controller_client_ =
+        std::make_unique<WallpaperControllerClient>();
+    wallpaper_controller_client_->InitForTesting(
+        test_wallpaper_controller_.CreateInterfacePtr());
   }
 
   void TearDown() override {
     chromeos::WallpaperManager::Shutdown();
     controller_.reset();
     profile_manager_.reset();
+    wallpaper_controller_client_.reset();
     ash::AshTestBase::TearDown();
   }
 
@@ -82,6 +89,8 @@
   std::unique_ptr<TestingProfileManager> profile_manager_;
   std::map<std::string, proximity_auth::mojom::AuthType> user_auth_type_map;
   std::unique_ptr<MultiProfileUserController> controller_;
+  std::unique_ptr<WallpaperControllerClient> wallpaper_controller_client_;
+  TestWallpaperController test_wallpaper_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(SigninPrepareUserListTest);
 };
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index 55195316..c11ce06 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -2005,7 +2005,11 @@
 // ------------------------------------------------------------------------
 // QuicConnectionMigration
 // ------------------------------------------------------------------------
-
+// Records the QUIC connection migration mode.
+//  {
+//     "connection_migration_mode": <The connection migration mode>
+//  }
+EVENT_TYPE(QUIC_CONNECTION_MIGRATION_MODE)
 // Records that QUIC connection migration has been triggered.
 //  {
 //     "trigger": <The reason for the migration attempt>
diff --git a/net/quic/chromium/quic_chromium_client_session.cc b/net/quic/chromium/quic_chromium_client_session.cc
index 1d30aba2..5e5935d 100644
--- a/net/quic/chromium/quic_chromium_client_session.cc
+++ b/net/quic/chromium/quic_chromium_client_session.cc
@@ -891,6 +891,25 @@
   handles_.erase(handle);
 }
 
+// TODO(zhongyi): replace migration_session_* booleans with
+// ConnectionMigrationMode.
+ConnectionMigrationMode QuicChromiumClientSession::connection_migration_mode()
+    const {
+  if (migrate_session_early_v2_)
+    return ConnectionMigrationMode::FULL_MIGRATION_V2;
+
+  if (migrate_session_on_network_change_v2_)
+    return ConnectionMigrationMode::NO_MIGRATION_ON_PATH_DEGRADING_V2;
+
+  if (migrate_session_early_)
+    return ConnectionMigrationMode::FULL_MIGRATION_V1;
+
+  if (migrate_session_on_network_change_)
+    return ConnectionMigrationMode::NO_MIGRATION_ON_PATH_DEGRADING_V1;
+
+  return ConnectionMigrationMode::NO_MIGRATION;
+}
+
 int QuicChromiumClientSession::WaitForHandshakeConfirmation(
     const CompletionCallback& callback) {
   if (!connection()->connected())
diff --git a/net/quic/chromium/quic_chromium_client_session.h b/net/quic/chromium/quic_chromium_client_session.h
index 886a9b8..588b968 100644
--- a/net/quic/chromium/quic_chromium_client_session.h
+++ b/net/quic/chromium/quic_chromium_client_session.h
@@ -69,6 +69,15 @@
   FAILURE          // Migration failed for other reasons.
 };
 
+// Mode of connection migration.
+enum class ConnectionMigrationMode {
+  NO_MIGRATION,
+  NO_MIGRATION_ON_PATH_DEGRADING_V1,
+  FULL_MIGRATION_V1,
+  NO_MIGRATION_ON_PATH_DEGRADING_V2,
+  FULL_MIGRATION_V2
+};
+
 // Result of a connectivity probing attempt.
 enum class ProbingResult {
   PENDING,                          // Probing started, pending result.
@@ -172,6 +181,11 @@
     // Returns the session's net log.
     const NetLogWithSource& net_log() const { return net_log_; }
 
+    // Returns the session's connection migration mode.
+    ConnectionMigrationMode connection_migration_mode() const {
+      return session_->connection_migration_mode();
+    }
+
     // QuicClientPushPromiseIndex::Delegate implementation
     bool CheckVary(const SpdyHeaderBlock& client_request,
                    const SpdyHeaderBlock& promise_request,
@@ -338,6 +352,9 @@
   void AddHandle(Handle* handle);
   void RemoveHandle(Handle* handle);
 
+  // Returns the session's connection migration mode.
+  ConnectionMigrationMode connection_migration_mode() const;
+
   // Waits for the handshake to be confirmed and invokes |callback| when
   // that happens. If the handshake has already been confirmed, returns OK.
   // If the connection has already been closed, returns a net error. If the
diff --git a/net/quic/chromium/quic_http_stream.cc b/net/quic/chromium/quic_http_stream.cc
index f0d4f17..30d86aa 100644
--- a/net/quic/chromium/quic_http_stream.cc
+++ b/net/quic/chromium/quic_http_stream.cc
@@ -114,6 +114,11 @@
   stream_net_log.AddEvent(
       NetLogEventType::HTTP_STREAM_REQUEST_BOUND_TO_QUIC_SESSION,
       quic_session()->net_log().source().ToEventParametersCallback());
+  stream_net_log.AddEvent(
+      NetLogEventType::QUIC_CONNECTION_MIGRATION_MODE,
+      NetLog::IntCallback(
+          "connection_migration_mode",
+          static_cast<int>(quic_session()->connection_migration_mode())));
 
   stream_net_log_ = stream_net_log;
   request_info_ = request_info;
diff --git a/third_party/WebKit/Source/bindings/core/v8/custom/V8DevToolsHostCustom.cpp b/third_party/WebKit/Source/bindings/core/v8/custom/V8DevToolsHostCustom.cpp
index f6736cb9..ffa3252 100644
--- a/third_party/WebKit/Source/bindings/core/v8/custom/V8DevToolsHostCustom.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/custom/V8DevToolsHostCustom.cpp
@@ -135,7 +135,7 @@
   if (exception_state.HadException())
     return;
 
-  v8::Local<v8::Value> array = v8::Local<v8::Value>::Cast(info[2]);
+  v8::Local<v8::Value> array = info[2];
   if (!array->IsArray())
     return;
   ContextMenu menu;
@@ -144,13 +144,8 @@
     return;
 
   Document* document = nullptr;
-  if (info.Length() >= 4 && v8::Local<v8::Value>::Cast(info[3])->IsObject()) {
-    v8::Local<v8::Object> document_wrapper =
-        v8::Local<v8::Object>::Cast(info[3]);
-    if (!V8HTMLDocument::wrapperTypeInfo.Equals(
-            ToWrapperTypeInfo(document_wrapper)))
-      return;
-    document = V8HTMLDocument::ToImpl(document_wrapper);
+  if (info.Length() >= 4 && info[3]->IsObject()) {
+    document = V8HTMLDocument::ToImplWithTypeCheck(isolate, info[3]);
   } else {
     v8::Local<v8::Object> window_wrapper =
         V8Window::findInstanceInPrototypeChain(
diff --git a/third_party/WebKit/Source/bindings/modules/v8/wasm/WasmResponseExtensions.cpp b/third_party/WebKit/Source/bindings/modules/v8/wasm/WasmResponseExtensions.cpp
index a57fa980..cfc8d63 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/wasm/WasmResponseExtensions.cpp
+++ b/third_party/WebKit/Source/bindings/modules/v8/wasm/WasmResponseExtensions.cpp
@@ -135,54 +135,37 @@
     return;
   }
 
-  if (args.Length() < 1 || !args[0]->IsObject() ||
-      !V8Response::hasInstance(args[0], args.GetIsolate())) {
-    V8SetReturnValue(
-        args,
-        ScriptPromise::Reject(
-            script_state, V8ThrowException::CreateTypeError(
-                              script_state->GetIsolate(),
-                              "An argument must be provided, which must be a "
-                              "Response or Promise<Response> object"))
-            .V8Value());
+  Response* response =
+      V8Response::ToImplWithTypeCheck(args.GetIsolate(), args[0]);
+  if (!response) {
+    exception_state.ThrowTypeError(
+        "An argument must be provided, which must be a "
+        "Response or Promise<Response> object");
     return;
   }
 
-  Response* response = V8Response::ToImpl(v8::Local<v8::Object>::Cast(args[0]));
   if (response->MimeType() != "application/wasm") {
-    V8SetReturnValue(
-        args,
-        ScriptPromise::Reject(
-            script_state,
-            V8ThrowException::CreateTypeError(
-                script_state->GetIsolate(),
-                "Incorrect response MIME type. Expected 'application/wasm'."))
-            .V8Value());
+    exception_state.ThrowTypeError(
+        "Incorrect response MIME type. Expected 'application/wasm'.");
     return;
   }
-  v8::Local<v8::Value> promise;
-  if (response->IsBodyLocked() || response->bodyUsed()) {
-    promise = ScriptPromise::Reject(script_state,
-                                    V8ThrowException::CreateTypeError(
-                                        script_state->GetIsolate(),
-                                        "Cannot compile WebAssembly.Module "
-                                        "from an already read Response"))
-                  .V8Value();
-  } else {
-    if (response->BodyBuffer()) {
-      FetchDataLoaderAsWasmModule* loader =
-          new FetchDataLoaderAsWasmModule(script_state);
 
-      promise = loader->GetPromise();
-      response->BodyBuffer()->StartLoading(loader, new WasmDataLoaderClient());
-    } else {
-      promise = ScriptPromise::Reject(script_state,
-                                      V8ThrowException::CreateTypeError(
-                                          script_state->GetIsolate(),
-                                          "Response object has a null body."))
-                    .V8Value();
-    }
+  if (response->IsBodyLocked() || response->bodyUsed()) {
+    exception_state.ThrowTypeError(
+        "Cannot compile WebAssembly.Module from an already read Response");
+    return;
   }
+
+  if (!response->BodyBuffer()) {
+    exception_state.ThrowTypeError("Response object has a null body.");
+    return;
+  }
+
+  FetchDataLoaderAsWasmModule* loader =
+      new FetchDataLoaderAsWasmModule(script_state);
+  v8::Local<v8::Value> promise = loader->GetPromise();
+  response->BodyBuffer()->StartLoading(loader, new WasmDataLoaderClient());
+
   V8SetReturnValue(args, promise);
 }
 
@@ -191,6 +174,8 @@
   v8::Isolate* isolate = args.GetIsolate();
   ScriptState* script_state = ScriptState::ForCurrentRealm(args);
 
+  // TODO(yukishiino): The following code creates a new v8::FunctionTemplate
+  // for every call, and leaks it.  Should reuse the same v8::FunctionTemplate.
   v8::Local<v8::Function> compile_callback =
       v8::Function::New(isolate, CompileFromResponseCallback);
 
@@ -203,7 +188,6 @@
   V8SetReturnValue(args, ScriptPromise::Cast(script_state, args[0])
                              .Then(compile_callback)
                              .V8Value());
-
 }
 
 }  // namespace