Revert "Disable unmount-on-suspend for FUSE"

This reverts commit 436c119d042f7298482f189956d3bc0c7a3b336c.

Reason for revert: An edge case for platforms without ARC++ was not handled correctly.

Original change's description:
> Disable unmount-on-suspend for FUSE
>
> This removes the code for unmounting the FUSEs (filesystem in userspace)
> on suspend. Instead of unmounting to resolve the FUSE/freeze on suspend
> race condition, we will be using powerd code that orders freeze using
> freezer cgroups.
>
> Crostini still has some work left to do before this can be done for it,
> so unmount on suspend for its FUSE, sshfs, will be done in a later
> patch.
>
> Test: "suspend_stress_test -c 2500" on device
> Bug: b/134792837
> Change-Id: Icb8f9e309f6780e6f935be550c6c4e048a44b1fd
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2336869
> Commit-Queue: Derek Basehore <[email protected]>
> Reviewed-by: Joel Hockey <[email protected]>
> Reviewed-by: Sergei Datsenko <[email protected]>
> Reviewed-by: James Cook <[email protected]>
> Reviewed-by: David Munro <[email protected]>
> Cr-Commit-Position: refs/heads/master@{#811950}

[email protected],[email protected],[email protected],[email protected],[email protected],[email protected]

# Not skipping CQ checks because original CL landed > 1 day ago.

(cherry picked from commit d0312acf02335caec3670ea6f22244173da276e0)

Bug: b/134792837
Change-Id: Ia50e43dceeb0eea448d6fdf7232af328a9a1fd1f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2451400
Reviewed-by: David Munro <[email protected]>
Reviewed-by: Sergei Datsenko <[email protected]>
Reviewed-by: Joel Hockey <[email protected]>
Reviewed-by: James Cook <[email protected]>
Commit-Queue: Derek Basehore <[email protected]>
Cr-Original-Commit-Position: refs/heads/master@{#814910}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2462232
Cr-Commit-Position: refs/branch-heads/4280@{#215}
Cr-Branched-From: ea420fb963f9658c9969b6513c56b8f47efa1a2a-refs/heads/master@{#812852}
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index 089f77e..7c36d9d0 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -566,7 +566,8 @@
       drivefs_holder_(std::make_unique<DriveFsHolder>(
           profile_,
           this,
-          std::move(test_drivefs_mojo_listener_factory))) {
+          std::move(test_drivefs_mojo_listener_factory))),
+      power_manager_observer_(this) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(profile && !profile->IsOffTheRecord());
 
@@ -591,6 +592,10 @@
         blocking_task_runner_.get()));
   }
 
+  // PowerManagerClient is unset in unit tests.
+  if (chromeos::PowerManagerClient::Get()) {
+    power_manager_observer_.Add(chromeos::PowerManagerClient::Get());
+  }
   SetEnabled(drive::util::IsDriveEnabledForProfile(profile));
 }
 
@@ -1023,6 +1028,21 @@
   profile_->GetPrefs()->SetBoolean(prefs::kDriveFsPinnedMigrated, true);
 }
 
+void DriveIntegrationService::SuspendImminent(
+    power_manager::SuspendImminent::Reason reason) {
+  // This may a bit racy since it doesn't prevent suspend until the unmount is
+  // completed, instead relying on something else to defer suspending long
+  // enough.
+  RemoveDriveMountPoint();
+}
+
+void DriveIntegrationService::SuspendDone(
+    const base::TimeDelta& sleep_duration) {
+  if (is_enabled()) {
+    AddDriveMountPoint();
+  }
+}
+
 void DriveIntegrationService::GetQuickAccessItems(
     int max_number,
     GetQuickAccessItemsCallback callback) {
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.h b/chrome/browser/chromeos/drive/drive_integration_service.h
index e325a95..b7a826a 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.h
+++ b/chrome/browser/chromeos/drive/drive_integration_service.h
@@ -18,6 +18,7 @@
 #include "base/observer_list_types.h"
 #include "base/scoped_observer.h"
 #include "chromeos/components/drivefs/drivefs_host.h"
+#include "chromeos/dbus/power/power_manager_client.h"
 #include "components/drive/drive_notification_observer.h"
 #include "components/drive/file_errors.h"
 #include "components/drive/file_system_core_util.h"
@@ -90,7 +91,8 @@
 // that are used to integrate Drive to Chrome. The object of this class is
 // created per-profile.
 class DriveIntegrationService : public KeyedService,
-                                public drivefs::DriveFsHost::MountObserver {
+                                public drivefs::DriveFsHost::MountObserver,
+                                public chromeos::PowerManagerClient::Observer {
  public:
   class PreferenceWatcher;
   using DriveFsMojoListenerFactory = base::RepeatingCallback<
@@ -269,6 +271,10 @@
   // Pin all the files in |files_to_pin| with DriveFS.
   void PinFiles(const std::vector<base::FilePath>& files_to_pin);
 
+  // chromeos::PowerManagerClient::Observer overrides:
+  void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
+  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+
   void OnGetQuickAccessItems(
       GetQuickAccessItemsCallback callback,
       drive::FileError error,
@@ -300,6 +306,10 @@
 
   base::TimeTicks mount_start_;
 
+  ScopedObserver<chromeos::PowerManagerClient,
+                 chromeos::PowerManagerClient::Observer>
+      power_manager_observer_{this};
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<DriveIntegrationService> weak_ptr_factory_{this};
diff --git a/chrome/browser/chromeos/smb_client/smb_service.cc b/chrome/browser/chromeos/smb_client/smb_service.cc
index 32a8fa3..f86c9885a 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.cc
+++ b/chrome/browser/chromeos/smb_client/smb_service.cc
@@ -182,6 +182,9 @@
 
 SmbService::~SmbService() {
   net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
+  if (chromeos::PowerManagerClient::Get()) {
+    chromeos::PowerManagerClient::Get()->RemoveObserver(this);
+  }
 }
 
 void SmbService::Shutdown() {
@@ -814,6 +817,9 @@
                           base::Unretained(this))));
   RestoreMounts();
   net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
+  if (chromeos::PowerManagerClient::Get()) {
+    chromeos::PowerManagerClient::Get()->AddObserver(this);
+  }
 
   if (setup_complete_callback_) {
     std::move(setup_complete_callback_).Run();
@@ -1017,5 +1023,53 @@
                            file_systems.size() + smbfs_shares_.size());
 }
 
+void SmbService::SuspendImminent(
+    power_manager::SuspendImminent::Reason reason) {
+  for (auto it = smbfs_shares_.begin(); it != smbfs_shares_.end(); ++it) {
+    SmbFsShare* share = it->second.get();
+
+    // For each share, block suspend until the unmount has completed, to ensure
+    // that no smbfs instances are active when the system goes to sleep.
+    auto token = base::UnguessableToken::Create();
+    chromeos::PowerManagerClient::Get()->BlockSuspend(token, "SmbService");
+    share->Unmount(
+        base::BindOnce(&SmbService::OnSuspendUnmountDone, AsWeakPtr(), token));
+  }
+}
+
+void SmbService::OnSuspendUnmountDone(
+    base::UnguessableToken power_manager_suspend_token,
+    chromeos::MountError result) {
+  LOG_IF(ERROR, result != chromeos::MountError::MOUNT_ERROR_NONE)
+      << "Could not unmount smbfs share during suspension: "
+      << static_cast<int>(result);
+  // Regardless of the outcome, unblock suspension for this share.
+  chromeos::PowerManagerClient::Get()->UnblockSuspend(
+      power_manager_suspend_token);
+}
+
+void SmbService::SuspendDone(const base::TimeDelta& sleep_duration) {
+  for (auto it = smbfs_shares_.begin(); it != smbfs_shares_.end(); ++it) {
+    SmbFsShare* share = it->second.get();
+    const std::string mount_id = share->mount_id();
+
+    // Don't try to reconnect as we race the network stack in getting an IP
+    // address.
+    SmbFsShare::MountOptions options = share->options();
+    options.skip_connect = true;
+    // Observing power management changes from SmbService allows us to remove
+    // the share in OnSmbfsMountDone if remount fails.
+    share->Remount(
+        options, base::BindOnce(
+                     &SmbService::OnSmbfsMountDone, AsWeakPtr(), mount_id,
+                     base::BindOnce([](SmbMountResult result,
+                                       const base::FilePath& mount_path) {
+                       LOG_IF(ERROR, result != SmbMountResult::kSuccess)
+                           << "Error remounting smbfs share after suspension: "
+                           << static_cast<int>(result);
+                     })));
+  }
+}
+
 }  // namespace smb_client
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/smb_client/smb_service.h b/chrome/browser/chromeos/smb_client/smb_service.h
index 22c0fe62..acac449 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.h
+++ b/chrome/browser/chromeos/smb_client/smb_service.h
@@ -25,6 +25,7 @@
 #include "chrome/browser/chromeos/smb_client/smb_task_queue.h"
 #include "chrome/browser/chromeos/smb_client/smbfs_share.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chromeos/dbus/power/power_manager_client.h"
 #include "chromeos/dbus/smb_provider_client.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "net/base/network_change_notifier.h"
@@ -48,6 +49,7 @@
 // Creates and manages an smb file system.
 class SmbService : public KeyedService,
                    public net::NetworkChangeNotifier::NetworkChangeObserver,
+                   public chromeos::PowerManagerClient::Observer,
                    public base::SupportsWeakPtr<SmbService> {
  public:
   using MountResponse = base::OnceCallback<void(SmbMountResult result)>;
@@ -124,6 +126,10 @@
   void SetSmbFsMounterCreationCallbackForTesting(
       SmbFsShare::MounterCreationCallback callback);
 
+  // chromeos::PowerManagerClient::Observer overrides
+  void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
+  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+
  private:
   friend class SmbServiceTest;
 
@@ -164,6 +170,11 @@
                         MountInternalCallback callback,
                         SmbMountResult result);
 
+  // Callback passed to SmbFsShare::Unmount() during a power management
+  // suspension. Ensures that suspension is blocked until the unmount completes.
+  void OnSuspendUnmountDone(base::UnguessableToken power_manager_suspend_token,
+                            chromeos::MountError result);
+
   // Retrieves the mount_id for |file_system_info|.
   int32_t GetMountId(const ProvidedFileSystemInfo& info) const;