blob: 45aa4cd3b3d1d651bc06298c828f14a5e8ad8d08 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_DRIVE_DRIVE_INTEGRATION_SERVICE_H_
#define CHROME_BROWSER_CHROMEOS_DRIVE_DRIVE_INTEGRATION_SERVICE_H_
#include <memory>
#include <set>
#include <string>
#include "base/callback.h"
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.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"
#include "components/drive/job_scheduler.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
class Profile;
namespace base {
class FilePath;
class SequencedTaskRunner;
}
namespace drivefs {
class DriveFsHost;
namespace mojom {
class DriveFs;
} // namespace mojom
} // namespace drivefs
namespace drive {
class DebugInfoCollector;
class DownloadHandler;
class DriveServiceInterface;
class EventLogger;
class FileSystemInterface;
class JobListInterface;
namespace internal {
class FileCache;
class ResourceMetadata;
class ResourceMetadataStorage;
} // namespace internal
// Mounting status. These values are persisted to logs. Entries should not be
// renumbered and numeric values should never be reused.
enum class DriveMountStatus {
kSuccess = 0,
kUnknownFailure = 1,
kTemporaryUnavailable = 2,
kInvocationFailure = 3,
kUnexpectedDisconnect = 4,
kTimeout = 5,
kMaxValue = kTimeout,
};
struct QuickAccessItem {
base::FilePath path;
double confidence;
};
// Interface for classes that need to observe events from
// DriveIntegrationService. All events are notified on UI thread.
class DriveIntegrationServiceObserver {
public:
// Triggered when the file system is mounted.
virtual void OnFileSystemMounted() {
}
// Triggered when the file system is being unmounted.
virtual void OnFileSystemBeingUnmounted() {
}
// Triggered when mounting the filesystem has failed in a fashion that will
// not be automatically retried.
virtual void OnFileSystemMountFailed() {}
protected:
virtual ~DriveIntegrationServiceObserver() {}
};
// DriveIntegrationService is used to integrate Drive to Chrome. This class
// exposes the file system representation built on top of Drive and some
// other Drive related objects to the file manager, and some other sub
// systems.
//
// The class is essentially a container that manages lifetime of the objects
// that are used to integrate Drive to Chrome. The object of this class is
// created per-profile.
class DriveIntegrationService : public KeyedService,
public DriveNotificationObserver,
public content::NotificationObserver,
public drivefs::DriveFsHost::MountObserver,
public chromeos::PowerManagerClient::Observer {
public:
class PreferenceWatcher;
using DriveFsMojoListenerFactory = base::RepeatingCallback<
std::unique_ptr<drivefs::DriveFsBootstrapListener>()>;
using GetQuickAccessItemsCallback =
base::OnceCallback<void(drive::FileError, std::vector<QuickAccessItem>)>;
// test_drive_service, test_mount_point_name, test_cache_root and
// test_file_system are used by tests to inject customized instances.
// Pass NULL or the empty value when not interested.
// |preference_watcher| observes the drive enable preference, and sets the
// enable state when changed. It can be NULL. The ownership is taken by
// the DriveIntegrationService.
DriveIntegrationService(
Profile* profile,
PreferenceWatcher* preference_watcher,
DriveServiceInterface* test_drive_service,
const std::string& test_mount_point_name,
const base::FilePath& test_cache_root,
FileSystemInterface* test_file_system,
DriveFsMojoListenerFactory test_drivefs_mojo_listener_factory = {});
~DriveIntegrationService() override;
// KeyedService override:
void Shutdown() override;
void SetEnabled(bool enabled);
bool is_enabled() const { return enabled_; }
bool IsMounted() const;
bool mount_failed() const { return mount_failed_; }
// Returns the path of the mount point for drive. It is only valid to call if
// |IsMounted()|.
base::FilePath GetMountPointPath() const;
// Returns the path of DriveFS log if enabled or empty path.
base::FilePath GetDriveFsLogPath() const;
// Returns true if |local_path| resides inside |GetMountPointPath()|.
// In this case |drive_path| will contain 'drive' path of this file, e.g.
// reparented to the mount point.
// It is only valid to call if |IsMounted()|.
bool GetRelativeDrivePath(const base::FilePath& local_path,
base::FilePath* drive_path) const;
// Adds and removes the observer.
void AddObserver(DriveIntegrationServiceObserver* observer);
void RemoveObserver(DriveIntegrationServiceObserver* observer);
// DriveNotificationObserver implementation.
void OnNotificationReceived(
const std::map<std::string, int64_t>& invalidations) override;
void OnNotificationTimerFired() override;
void OnPushNotificationEnabled(bool enabled) override;
// MountObserver implementation.
void OnMounted(const base::FilePath& mount_path) override;
void OnUnmounted(base::Optional<base::TimeDelta> remount_delay) override;
void OnMountFailed(MountFailure failure,
base::Optional<base::TimeDelta> remount_delay) override;
EventLogger* event_logger() { return logger_.get(); }
DriveServiceInterface* drive_service() { return drive_service_.get(); }
DebugInfoCollector* debug_info_collector() {
return debug_info_collector_.get();
}
FileSystemInterface* file_system() { return file_system_.get(); }
DownloadHandler* download_handler() { return download_handler_.get(); }
JobListInterface* job_list() { return scheduler_.get(); }
// Clears all the local cache file, the local resource metadata, and
// in-memory Drive app registry, and remounts the file system. |callback|
// is called with true when this operation is done successfully. Otherwise,
// |callback| is called with false. |callback| must not be null.
void ClearCacheAndRemountFileSystem(
const base::Callback<void(bool)>& callback);
// Returns the DriveFsHost if it is enabled.
drivefs::DriveFsHost* GetDriveFsHost() const;
// Returns the mojo interface to the DriveFs daemon if it is enabled and
// connected.
drivefs::mojom::DriveFs* GetDriveFsInterface() const;
void GetQuickAccessItems(int max_number,
GetQuickAccessItemsCallback callback);
private:
enum State {
NOT_INITIALIZED,
INITIALIZING,
INITIALIZED,
REMOUNTING,
};
class DriveFsHolder;
// Manages passing changes in team drives to the drive notification manager.
class NotificationManager;
// Returns true if Drive is enabled.
// Must be called on UI thread.
bool IsDriveEnabled();
// Registers remote file system for drive mount point. If DriveFS is enabled,
// but not yet mounted, this will start it mounting and wait for it to
// complete before adding the mount point.
void AddDriveMountPoint();
// Registers remote file system for drive mount point.
bool AddDriveMountPointAfterMounted();
// Unregisters drive mount point from File API.
void RemoveDriveMountPoint();
// Adds back the drive mount point.
// Used to implement ClearCacheAndRemountFileSystem().
void AddBackDriveMountPoint(const base::Callback<void(bool)>& callback,
FileError error);
// Unregisters drive mount point, and if |remount_delay| is specified
// then tries to add it back after that delay. If |remount_delay| isn't
// specified, |failed_to_mount| is true and the user is offline, schedules a
// retry when the user is online.
void MaybeRemountFileSystem(base::Optional<base::TimeDelta> remount_delay,
bool failed_to_mount);
// Initializes the object. This function should be called before any
// other functions.
void Initialize();
// Called when metadata initialization is done. Continues initialization if
// the metadata initialization is successful.
void InitializeAfterMetadataInitialized(FileError error);
// Change the download directory to the local "Downloads" if the download
// destination is set under Drive. This must be called when disabling Drive.
void AvoidDriveAsDownloadDirectoryPreference();
bool DownloadDirectoryPreferenceIsInDrive();
// content::NotificationObserver overrides.
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
// Migrate pinned files from the old Drive integration to DriveFS.
void MigratePinnedFiles();
// 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,
base::Optional<std::vector<drivefs::mojom::QueryItemPtr>> items);
friend class DriveIntegrationServiceFactory;
Profile* profile_;
State state_;
bool enabled_;
bool mount_failed_ = false;
// Custom mount point name that can be injected for testing in constructor.
std::string mount_point_name_;
base::FilePath cache_root_directory_;
std::unique_ptr<EventLogger> logger_;
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
std::unique_ptr<internal::ResourceMetadataStorage, util::DestroyHelper>
metadata_storage_;
std::unique_ptr<internal::FileCache, util::DestroyHelper> cache_;
std::unique_ptr<DriveServiceInterface> drive_service_;
std::unique_ptr<JobScheduler> scheduler_;
std::unique_ptr<internal::ResourceMetadata, util::DestroyHelper>
resource_metadata_;
std::unique_ptr<FileSystemInterface> file_system_;
std::unique_ptr<DownloadHandler> download_handler_;
std::unique_ptr<DebugInfoCollector> debug_info_collector_;
base::ObserverList<DriveIntegrationServiceObserver>::Unchecked observers_;
std::unique_ptr<content::NotificationRegistrar>
profile_notification_registrar_;
std::unique_ptr<DriveFsHolder> drivefs_holder_;
std::unique_ptr<PreferenceWatcher> preference_watcher_;
std::unique_ptr<NotificationManager> notification_manager_;
int drivefs_total_failures_count_ = 0;
int drivefs_consecutive_failures_count_ = 0;
bool remount_when_online_ = false;
base::TimeTicks mount_start_;
ScopedObserver<chromeos::PowerManagerClient, DriveIntegrationService>
power_manager_observer_;
// 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};
DISALLOW_COPY_AND_ASSIGN(DriveIntegrationService);
};
// Singleton that owns all instances of DriveIntegrationService and
// associates them with Profiles.
class DriveIntegrationServiceFactory
: public BrowserContextKeyedServiceFactory {
public:
// Factory function used by tests.
typedef base::Callback<DriveIntegrationService*(Profile* profile)>
FactoryCallback;
// Sets and resets a factory function for tests. See below for why we can't
// use BrowserContextKeyedServiceFactory::SetTestingFactory().
class ScopedFactoryForTest {
public:
explicit ScopedFactoryForTest(FactoryCallback* factory_for_test);
~ScopedFactoryForTest();
};
// Returns the DriveIntegrationService for |profile|, creating it if it is
// not yet created.
static DriveIntegrationService* GetForProfile(Profile* profile);
// Returns the DriveIntegrationService that is already associated with
// |profile|, if it is not yet created it will return NULL.
static DriveIntegrationService* FindForProfile(Profile* profile);
// Returns the DriveIntegrationServiceFactory instance.
static DriveIntegrationServiceFactory* GetInstance();
private:
friend struct base::DefaultSingletonTraits<DriveIntegrationServiceFactory>;
DriveIntegrationServiceFactory();
~DriveIntegrationServiceFactory() override;
// BrowserContextKeyedServiceFactory overrides.
content::BrowserContext* GetBrowserContextToUse(
content::BrowserContext* context) const override;
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* context) const override;
// This is static so it can be set without instantiating the factory. This
// allows factory creation to be delayed until it normally happens (on profile
// creation) rather than when tests are set up. DriveIntegrationServiceFactory
// transitively depends on ExtensionSystemFactory which crashes if created too
// soon (i.e. before the BrowserProcess exists).
static FactoryCallback* factory_for_test_;
};
} // namespace drive
#endif // CHROME_BROWSER_CHROMEOS_DRIVE_DRIVE_INTEGRATION_SERVICE_H_