Home | History | Annotate | Download | only in drive
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/file_util.h"
      9 #include "base/prefs/pref_change_registrar.h"
     10 #include "base/prefs/pref_service.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "base/threading/sequenced_worker_pool.h"
     13 #include "chrome/browser/browser_process.h"
     14 #include "chrome/browser/chrome_notification_types.h"
     15 #include "chrome/browser/chromeos/drive/debug_info_collector.h"
     16 #include "chrome/browser/chromeos/drive/download_handler.h"
     17 #include "chrome/browser/chromeos/drive/file_cache.h"
     18 #include "chrome/browser/chromeos/drive/file_system.h"
     19 #include "chrome/browser/chromeos/drive/file_system_util.h"
     20 #include "chrome/browser/chromeos/drive/job_scheduler.h"
     21 #include "chrome/browser/chromeos/drive/resource_metadata.h"
     22 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
     23 #include "chrome/browser/chromeos/file_manager/path_util.h"
     24 #include "chrome/browser/chromeos/profiles/profile_util.h"
     25 #include "chrome/browser/download/download_prefs.h"
     26 #include "chrome/browser/download/download_service.h"
     27 #include "chrome/browser/download/download_service_factory.h"
     28 #include "chrome/browser/drive/drive_api_service.h"
     29 #include "chrome/browser/drive/drive_api_util.h"
     30 #include "chrome/browser/drive/drive_app_registry.h"
     31 #include "chrome/browser/drive/drive_notification_manager.h"
     32 #include "chrome/browser/drive/drive_notification_manager_factory.h"
     33 #include "chrome/browser/drive/event_logger.h"
     34 #include "chrome/browser/profiles/incognito_helpers.h"
     35 #include "chrome/browser/profiles/profile.h"
     36 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
     37 #include "chrome/browser/signin/signin_manager_factory.h"
     38 #include "chrome/common/chrome_version_info.h"
     39 #include "chrome/common/pref_names.h"
     40 #include "components/keyed_service/content/browser_context_dependency_manager.h"
     41 #include "components/signin/core/browser/profile_oauth2_token_service.h"
     42 #include "components/signin/core/browser/signin_manager.h"
     43 #include "content/public/browser/browser_context.h"
     44 #include "content/public/browser/browser_thread.h"
     45 #include "content/public/browser/notification_service.h"
     46 #include "content/public/common/user_agent.h"
     47 #include "google_apis/drive/auth_service.h"
     48 #include "google_apis/drive/gdata_wapi_url_generator.h"
     49 #include "grit/generated_resources.h"
     50 #include "ui/base/l10n/l10n_util.h"
     51 #include "webkit/browser/fileapi/external_mount_points.h"
     52 
     53 using content::BrowserContext;
     54 using content::BrowserThread;
     55 
     56 namespace drive {
     57 namespace {
     58 
     59 // Name of the directory used to store metadata.
     60 const base::FilePath::CharType kMetadataDirectory[] = FILE_PATH_LITERAL("meta");
     61 
     62 // Name of the directory used to store cached files.
     63 const base::FilePath::CharType kCacheFileDirectory[] =
     64     FILE_PATH_LITERAL("files");
     65 
     66 // Name of the directory used to store temporary files.
     67 const base::FilePath::CharType kTemporaryFileDirectory[] =
     68     FILE_PATH_LITERAL("tmp");
     69 
     70 // Returns a user agent string used for communicating with the Drive backend,
     71 // both WAPI and Drive API.  The user agent looks like:
     72 //
     73 // chromedrive-<VERSION> chrome-cc/none (<OS_CPU_INFO>)
     74 // chromedrive-24.0.1274.0 chrome-cc/none (CrOS x86_64 0.4.0)
     75 //
     76 // TODO(satorux): Move this function to somewhere else: crbug.com/151605
     77 std::string GetDriveUserAgent() {
     78   const char kDriveClientName[] = "chromedrive";
     79 
     80   chrome::VersionInfo version_info;
     81   const std::string version = (version_info.is_valid() ?
     82                                version_info.Version() :
     83                                std::string("unknown"));
     84 
     85   // This part is <client_name>/<version>.
     86   const char kLibraryInfo[] = "chrome-cc/none";
     87 
     88   const std::string os_cpu_info = content::BuildOSCpuInfo();
     89 
     90   // Add "gzip" to receive compressed data from the server.
     91   // (see https://developers.google.com/drive/performance)
     92   return base::StringPrintf("%s-%s %s (%s) (gzip)",
     93                             kDriveClientName,
     94                             version.c_str(),
     95                             kLibraryInfo,
     96                             os_cpu_info.c_str());
     97 }
     98 
     99 // Initializes FileCache and ResourceMetadata.
    100 // Must be run on the same task runner used by |cache| and |resource_metadata|.
    101 FileError InitializeMetadata(
    102     const base::FilePath& cache_root_directory,
    103     internal::ResourceMetadataStorage* metadata_storage,
    104     internal::FileCache* cache,
    105     internal::ResourceMetadata* resource_metadata,
    106     const ResourceIdCanonicalizer& id_canonicalizer,
    107     const base::FilePath& downloads_directory) {
    108   // Files in temporary directory need not persist across sessions. Clean up
    109   // the directory content while initialization.
    110   base::DeleteFile(cache_root_directory.Append(kTemporaryFileDirectory),
    111                    true);  // recursive
    112   if (!base::CreateDirectory(cache_root_directory.Append(
    113           kMetadataDirectory)) ||
    114       !base::CreateDirectory(cache_root_directory.Append(
    115           kCacheFileDirectory)) ||
    116       !base::CreateDirectory(cache_root_directory.Append(
    117           kTemporaryFileDirectory))) {
    118     LOG(WARNING) << "Failed to create directories.";
    119     return FILE_ERROR_FAILED;
    120   }
    121 
    122   // Change permissions of cache file directory to u+rwx,og+x (711) in order to
    123   // allow archive files in that directory to be mounted by cros-disks.
    124   base::SetPosixFilePermissions(
    125       cache_root_directory.Append(kCacheFileDirectory),
    126       base::FILE_PERMISSION_USER_MASK |
    127       base::FILE_PERMISSION_EXECUTE_BY_GROUP |
    128       base::FILE_PERMISSION_EXECUTE_BY_OTHERS);
    129 
    130   internal::ResourceMetadataStorage::UpgradeOldDB(
    131       metadata_storage->directory_path(), id_canonicalizer);
    132 
    133   if (!metadata_storage->Initialize()) {
    134     LOG(WARNING) << "Failed to initialize the metadata storage.";
    135     return FILE_ERROR_FAILED;
    136   }
    137 
    138   if (!cache->Initialize()) {
    139     LOG(WARNING) << "Failed to initialize the cache.";
    140     return FILE_ERROR_FAILED;
    141   }
    142 
    143   if (metadata_storage->cache_file_scan_is_needed()) {
    144     // Generate unique directory name.
    145     const std::string& dest_directory_name = l10n_util::GetStringUTF8(
    146         IDS_FILE_BROWSER_RECOVERED_FILES_FROM_GOOGLE_DRIVE_DIRECTORY_NAME);
    147     base::FilePath dest_directory = downloads_directory.Append(
    148         base::FilePath::FromUTF8Unsafe(dest_directory_name));
    149     for (int uniquifier = 1; base::PathExists(dest_directory); ++uniquifier) {
    150       dest_directory = downloads_directory.Append(
    151           base::FilePath::FromUTF8Unsafe(dest_directory_name))
    152           .InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", uniquifier));
    153     }
    154 
    155     internal::ResourceMetadataStorage::RecoveredCacheInfoMap
    156         recovered_cache_info;
    157     metadata_storage->RecoverCacheInfoFromTrashedResourceMap(
    158         &recovered_cache_info);
    159 
    160     LOG_IF(WARNING, !recovered_cache_info.empty())
    161         << "DB could not be opened for some reasons. "
    162         << "Recovering cache files to " << dest_directory.value();
    163     if (!cache->RecoverFilesFromCacheDirectory(dest_directory,
    164                                                recovered_cache_info)) {
    165       LOG(WARNING) << "Failed to recover cache files.";
    166       return FILE_ERROR_FAILED;
    167     }
    168   }
    169 
    170   FileError error = resource_metadata->Initialize();
    171   LOG_IF(WARNING, error != FILE_ERROR_OK)
    172       << "Failed to initialize resource metadata. " << FileErrorToString(error);
    173   return error;
    174 }
    175 
    176 }  // namespace
    177 
    178 // Observes drive disable Preference's change.
    179 class DriveIntegrationService::PreferenceWatcher {
    180  public:
    181   explicit PreferenceWatcher(PrefService* pref_service)
    182       : pref_service_(pref_service),
    183         integration_service_(NULL),
    184         weak_ptr_factory_(this) {
    185     DCHECK(pref_service);
    186     pref_change_registrar_.Init(pref_service);
    187     pref_change_registrar_.Add(
    188         prefs::kDisableDrive,
    189         base::Bind(&PreferenceWatcher::OnPreferenceChanged,
    190                    weak_ptr_factory_.GetWeakPtr()));
    191   }
    192 
    193   void set_integration_service(DriveIntegrationService* integration_service) {
    194     integration_service_ = integration_service;
    195   }
    196 
    197  private:
    198   void OnPreferenceChanged() {
    199     DCHECK(integration_service_);
    200     integration_service_->SetEnabled(
    201         !pref_service_->GetBoolean(prefs::kDisableDrive));
    202   }
    203 
    204   PrefService* pref_service_;
    205   PrefChangeRegistrar pref_change_registrar_;
    206   DriveIntegrationService* integration_service_;
    207 
    208   base::WeakPtrFactory<PreferenceWatcher> weak_ptr_factory_;
    209   DISALLOW_COPY_AND_ASSIGN(PreferenceWatcher);
    210 };
    211 
    212 DriveIntegrationService::DriveIntegrationService(
    213     Profile* profile,
    214     PreferenceWatcher* preference_watcher,
    215     DriveServiceInterface* test_drive_service,
    216     const std::string& test_mount_point_name,
    217     const base::FilePath& test_cache_root,
    218     FileSystemInterface* test_file_system)
    219     : profile_(profile),
    220       state_(NOT_INITIALIZED),
    221       enabled_(false),
    222       mount_point_name_(test_mount_point_name),
    223       cache_root_directory_(!test_cache_root.empty() ?
    224                             test_cache_root : util::GetCacheRootPath(profile)),
    225       weak_ptr_factory_(this) {
    226   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    227   DCHECK(profile && !profile->IsOffTheRecord());
    228 
    229   logger_.reset(new EventLogger);
    230   base::SequencedWorkerPool* blocking_pool = BrowserThread::GetBlockingPool();
    231   blocking_task_runner_ = blocking_pool->GetSequencedTaskRunner(
    232       blocking_pool->GetSequenceToken());
    233 
    234   ProfileOAuth2TokenService* oauth_service =
    235       ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
    236 
    237   if (test_drive_service) {
    238     drive_service_.reset(test_drive_service);
    239   } else {
    240     drive_service_.reset(new DriveAPIService(
    241         oauth_service,
    242         g_browser_process->system_request_context(),
    243         blocking_task_runner_.get(),
    244         GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction),
    245         GURL(google_apis::DriveApiUrlGenerator::kBaseDownloadUrlForProduction),
    246         GURL(google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction),
    247         GetDriveUserAgent()));
    248   }
    249   scheduler_.reset(new JobScheduler(
    250       profile_->GetPrefs(),
    251       logger_.get(),
    252       drive_service_.get(),
    253       blocking_task_runner_.get()));
    254   metadata_storage_.reset(new internal::ResourceMetadataStorage(
    255       cache_root_directory_.Append(kMetadataDirectory),
    256       blocking_task_runner_.get()));
    257   cache_.reset(new internal::FileCache(
    258       metadata_storage_.get(),
    259       cache_root_directory_.Append(kCacheFileDirectory),
    260       blocking_task_runner_.get(),
    261       NULL /* free_disk_space_getter */));
    262   drive_app_registry_.reset(new DriveAppRegistry(drive_service_.get()));
    263 
    264   resource_metadata_.reset(new internal::ResourceMetadata(
    265       metadata_storage_.get(), cache_.get(), blocking_task_runner_));
    266 
    267   file_system_.reset(
    268       test_file_system ? test_file_system : new FileSystem(
    269           profile_->GetPrefs(),
    270           logger_.get(),
    271           cache_.get(),
    272           drive_service_.get(),
    273           scheduler_.get(),
    274           resource_metadata_.get(),
    275           blocking_task_runner_.get(),
    276           cache_root_directory_.Append(kTemporaryFileDirectory)));
    277   download_handler_.reset(new DownloadHandler(file_system()));
    278   debug_info_collector_.reset(new DebugInfoCollector(
    279       resource_metadata_.get(), file_system(), blocking_task_runner_.get()));
    280 
    281   if (preference_watcher) {
    282     preference_watcher_.reset(preference_watcher);
    283     preference_watcher->set_integration_service(this);
    284   }
    285 
    286   SetEnabled(drive::util::IsDriveEnabledForProfile(profile));
    287 }
    288 
    289 DriveIntegrationService::~DriveIntegrationService() {
    290   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    291 }
    292 
    293 void DriveIntegrationService::Shutdown() {
    294   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    295 
    296   weak_ptr_factory_.InvalidateWeakPtrs();
    297 
    298   DriveNotificationManager* drive_notification_manager =
    299       DriveNotificationManagerFactory::FindForBrowserContext(profile_);
    300   if (drive_notification_manager)
    301     drive_notification_manager->RemoveObserver(this);
    302 
    303   RemoveDriveMountPoint();
    304   debug_info_collector_.reset();
    305   download_handler_.reset();
    306   file_system_.reset();
    307   drive_app_registry_.reset();
    308   scheduler_.reset();
    309   drive_service_.reset();
    310 }
    311 
    312 void DriveIntegrationService::SetEnabled(bool enabled) {
    313   // If Drive is being disabled, ensure the download destination preference to
    314   // be out of Drive. Do this before "Do nothing if not changed." because we
    315   // want to run the check for the first SetEnabled() called in the constructor,
    316   // which may be a change from false to false.
    317   if (!enabled)
    318     AvoidDriveAsDownloadDirecotryPreference();
    319 
    320   // Do nothing if not changed.
    321   if (enabled_ == enabled)
    322     return;
    323 
    324   if (enabled) {
    325     enabled_ = true;
    326     switch (state_) {
    327       case NOT_INITIALIZED:
    328         // If the initialization is not yet done, trigger it.
    329         Initialize();
    330         return;
    331 
    332       case INITIALIZING:
    333       case REMOUNTING:
    334         // If the state is INITIALIZING or REMOUNTING, at the end of the
    335         // process, it tries to mounting (with re-checking enabled state).
    336         // Do nothing for now.
    337         return;
    338 
    339       case INITIALIZED:
    340         // The integration service is already initialized. Add the mount point.
    341         AddDriveMountPoint();
    342         return;
    343     }
    344     NOTREACHED();
    345   } else {
    346     RemoveDriveMountPoint();
    347     enabled_ = false;
    348   }
    349 }
    350 
    351 bool DriveIntegrationService::IsMounted() const {
    352   if (mount_point_name_.empty())
    353     return false;
    354 
    355   // Look up the registered path, and just discard it.
    356   // GetRegisteredPath() returns true if the path is available.
    357   base::FilePath unused;
    358   fileapi::ExternalMountPoints* const mount_points =
    359       fileapi::ExternalMountPoints::GetSystemInstance();
    360   DCHECK(mount_points);
    361   return mount_points->GetRegisteredPath(mount_point_name_, &unused);
    362 }
    363 
    364 void DriveIntegrationService::AddObserver(
    365     DriveIntegrationServiceObserver* observer) {
    366   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    367   observers_.AddObserver(observer);
    368 }
    369 
    370 void DriveIntegrationService::RemoveObserver(
    371     DriveIntegrationServiceObserver* observer) {
    372   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    373   observers_.RemoveObserver(observer);
    374 }
    375 
    376 void DriveIntegrationService::OnNotificationReceived() {
    377   file_system_->CheckForUpdates();
    378   drive_app_registry_->Update();
    379 }
    380 
    381 void DriveIntegrationService::OnPushNotificationEnabled(bool enabled) {
    382   if (enabled)
    383     drive_app_registry_->Update();
    384 
    385   const char* status = (enabled ? "enabled" : "disabled");
    386   logger_->Log(logging::LOG_INFO, "Push notification is %s", status);
    387 }
    388 
    389 void DriveIntegrationService::ClearCacheAndRemountFileSystem(
    390     const base::Callback<void(bool)>& callback) {
    391   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    392   DCHECK(!callback.is_null());
    393 
    394   if (state_ != INITIALIZED) {
    395     callback.Run(false);
    396     return;
    397   }
    398 
    399   RemoveDriveMountPoint();
    400 
    401   state_ = REMOUNTING;
    402   // Reloads the Drive app registry.
    403   drive_app_registry_->Update();
    404   // Resetting the file system clears resource metadata and cache.
    405   file_system_->Reset(base::Bind(
    406       &DriveIntegrationService::AddBackDriveMountPoint,
    407       weak_ptr_factory_.GetWeakPtr(),
    408       callback));
    409 }
    410 
    411 void DriveIntegrationService::AddBackDriveMountPoint(
    412     const base::Callback<void(bool)>& callback,
    413     FileError error) {
    414   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    415   DCHECK(!callback.is_null());
    416 
    417   state_ = error == FILE_ERROR_OK ? INITIALIZED : NOT_INITIALIZED;
    418 
    419   if (error != FILE_ERROR_OK || !enabled_) {
    420     // Failed to reset, or Drive was disabled during the reset.
    421     callback.Run(false);
    422     return;
    423   }
    424 
    425   AddDriveMountPoint();
    426   callback.Run(true);
    427 }
    428 
    429 void DriveIntegrationService::AddDriveMountPoint() {
    430   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    431   DCHECK_EQ(INITIALIZED, state_);
    432   DCHECK(enabled_);
    433 
    434   const base::FilePath& drive_mount_point =
    435       util::GetDriveMountPointPath(profile_);
    436   if (mount_point_name_.empty())
    437     mount_point_name_ = drive_mount_point.BaseName().AsUTF8Unsafe();
    438   fileapi::ExternalMountPoints* const mount_points =
    439       fileapi::ExternalMountPoints::GetSystemInstance();
    440   DCHECK(mount_points);
    441 
    442   bool success = mount_points->RegisterFileSystem(
    443       mount_point_name_,
    444       fileapi::kFileSystemTypeDrive,
    445       fileapi::FileSystemMountOption(),
    446       drive_mount_point);
    447 
    448   if (success) {
    449     logger_->Log(logging::LOG_INFO, "Drive mount point is added");
    450     FOR_EACH_OBSERVER(DriveIntegrationServiceObserver, observers_,
    451                       OnFileSystemMounted());
    452   }
    453 }
    454 
    455 void DriveIntegrationService::RemoveDriveMountPoint() {
    456   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    457 
    458   if (!mount_point_name_.empty()) {
    459     job_list()->CancelAllJobs();
    460 
    461     FOR_EACH_OBSERVER(DriveIntegrationServiceObserver, observers_,
    462                       OnFileSystemBeingUnmounted());
    463 
    464     fileapi::ExternalMountPoints* const mount_points =
    465         fileapi::ExternalMountPoints::GetSystemInstance();
    466     DCHECK(mount_points);
    467 
    468     mount_points->RevokeFileSystem(mount_point_name_);
    469     logger_->Log(logging::LOG_INFO, "Drive mount point is removed");
    470   }
    471 }
    472 
    473 void DriveIntegrationService::Initialize() {
    474   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    475   DCHECK_EQ(NOT_INITIALIZED, state_);
    476   DCHECK(enabled_);
    477 
    478   state_ = INITIALIZING;
    479 
    480   base::PostTaskAndReplyWithResult(
    481       blocking_task_runner_.get(),
    482       FROM_HERE,
    483       base::Bind(&InitializeMetadata,
    484                  cache_root_directory_,
    485                  metadata_storage_.get(),
    486                  cache_.get(),
    487                  resource_metadata_.get(),
    488                  drive_service_->GetResourceIdCanonicalizer(),
    489                  file_manager::util::GetDownloadsFolderForProfile(profile_)),
    490       base::Bind(&DriveIntegrationService::InitializeAfterMetadataInitialized,
    491                  weak_ptr_factory_.GetWeakPtr()));
    492 }
    493 
    494 void DriveIntegrationService::InitializeAfterMetadataInitialized(
    495     FileError error) {
    496   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    497   DCHECK_EQ(INITIALIZING, state_);
    498 
    499   SigninManagerBase* signin_manager =
    500       SigninManagerFactory::GetForProfile(profile_);
    501   drive_service_->Initialize(signin_manager->GetAuthenticatedAccountId());
    502 
    503   if (error != FILE_ERROR_OK) {
    504     LOG(WARNING) << "Failed to initialize: " << FileErrorToString(error);
    505 
    506     // Cannot used Drive. Set the download destination preference out of Drive.
    507     AvoidDriveAsDownloadDirecotryPreference();
    508 
    509     // Back to NOT_INITIALIZED state. Then, re-running Initialize() should
    510     // work if the error is recoverable manually (such as out of disk space).
    511     state_ = NOT_INITIALIZED;
    512     return;
    513   }
    514 
    515   // Initialize Download Handler for hooking downloads to the Drive folder.
    516   content::DownloadManager* download_manager =
    517       g_browser_process->download_status_updater() ?
    518       BrowserContext::GetDownloadManager(profile_) : NULL;
    519   download_handler_->Initialize(
    520       download_manager,
    521       cache_root_directory_.Append(kTemporaryFileDirectory));
    522 
    523   // Install the handler also to incognito profile.
    524   if (g_browser_process->download_status_updater()) {
    525     if (profile_->HasOffTheRecordProfile()) {
    526       download_handler_->ObserveIncognitoDownloadManager(
    527           BrowserContext::GetDownloadManager(
    528               profile_->GetOffTheRecordProfile()));
    529     }
    530     profile_notification_registrar_.reset(new content::NotificationRegistrar);
    531     profile_notification_registrar_->Add(
    532         this,
    533         chrome::NOTIFICATION_PROFILE_CREATED,
    534         content::NotificationService::AllSources());
    535   }
    536 
    537   // Register for Google Drive invalidation notifications.
    538   DriveNotificationManager* drive_notification_manager =
    539       DriveNotificationManagerFactory::GetForBrowserContext(profile_);
    540   if (drive_notification_manager) {
    541     drive_notification_manager->AddObserver(this);
    542     const bool registered =
    543         drive_notification_manager->push_notification_registered();
    544     const char* status = (registered ? "registered" : "not registered");
    545     logger_->Log(logging::LOG_INFO, "Push notification is %s", status);
    546 
    547     if (drive_notification_manager->push_notification_enabled())
    548       drive_app_registry_->Update();
    549   }
    550 
    551   state_ = INITIALIZED;
    552 
    553   // Mount only when the drive is enabled. Initialize is triggered by
    554   // SetEnabled(true), but there is a change to disable it again during
    555   // the metadata initialization, so we need to look this up again here.
    556   if (enabled_)
    557     AddDriveMountPoint();
    558 }
    559 
    560 void DriveIntegrationService::AvoidDriveAsDownloadDirecotryPreference() {
    561   PrefService* pref_service = profile_->GetPrefs();
    562   if (util::IsUnderDriveMountPoint(
    563           pref_service->GetFilePath(prefs::kDownloadDefaultDirectory))) {
    564     pref_service->SetFilePath(
    565         prefs::kDownloadDefaultDirectory,
    566         file_manager::util::GetDownloadsFolderForProfile(profile_));
    567   }
    568 }
    569 
    570 void DriveIntegrationService::Observe(
    571     int type,
    572     const content::NotificationSource& source,
    573     const content::NotificationDetails& details) {
    574   if (type == chrome::NOTIFICATION_PROFILE_CREATED) {
    575     Profile* created_profile = content::Source<Profile>(source).ptr();
    576     if (created_profile->IsOffTheRecord() &&
    577         created_profile->IsSameProfile(profile_)) {
    578       download_handler_->ObserveIncognitoDownloadManager(
    579           BrowserContext::GetDownloadManager(created_profile));
    580     }
    581   }
    582 }
    583 
    584 //===================== DriveIntegrationServiceFactory =======================
    585 
    586 DriveIntegrationServiceFactory::FactoryCallback*
    587     DriveIntegrationServiceFactory::factory_for_test_ = NULL;
    588 
    589 DriveIntegrationServiceFactory::ScopedFactoryForTest::ScopedFactoryForTest(
    590     FactoryCallback* factory_for_test) {
    591   factory_for_test_ = factory_for_test;
    592 }
    593 
    594 DriveIntegrationServiceFactory::ScopedFactoryForTest::~ScopedFactoryForTest() {
    595   factory_for_test_ = NULL;
    596 }
    597 
    598 // static
    599 DriveIntegrationService* DriveIntegrationServiceFactory::GetForProfile(
    600     Profile* profile) {
    601   return GetForProfileRegardlessOfStates(profile);
    602 }
    603 
    604 // static
    605 DriveIntegrationService*
    606 DriveIntegrationServiceFactory::GetForProfileRegardlessOfStates(
    607     Profile* profile) {
    608   return static_cast<DriveIntegrationService*>(
    609       GetInstance()->GetServiceForBrowserContext(profile, true));
    610 }
    611 
    612 // static
    613 DriveIntegrationService* DriveIntegrationServiceFactory::FindForProfile(
    614     Profile* profile) {
    615   return FindForProfileRegardlessOfStates(profile);
    616 }
    617 
    618 // static
    619 DriveIntegrationService*
    620 DriveIntegrationServiceFactory::FindForProfileRegardlessOfStates(
    621     Profile* profile) {
    622   return static_cast<DriveIntegrationService*>(
    623       GetInstance()->GetServiceForBrowserContext(profile, false));
    624 }
    625 
    626 // static
    627 DriveIntegrationServiceFactory* DriveIntegrationServiceFactory::GetInstance() {
    628   return Singleton<DriveIntegrationServiceFactory>::get();
    629 }
    630 
    631 DriveIntegrationServiceFactory::DriveIntegrationServiceFactory()
    632     : BrowserContextKeyedServiceFactory(
    633         "DriveIntegrationService",
    634         BrowserContextDependencyManager::GetInstance()) {
    635   DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
    636   DependsOn(DriveNotificationManagerFactory::GetInstance());
    637   DependsOn(DownloadServiceFactory::GetInstance());
    638 }
    639 
    640 DriveIntegrationServiceFactory::~DriveIntegrationServiceFactory() {
    641 }
    642 
    643 content::BrowserContext* DriveIntegrationServiceFactory::GetBrowserContextToUse(
    644     content::BrowserContext* context) const {
    645   return chrome::GetBrowserContextRedirectedInIncognito(context);
    646 }
    647 
    648 KeyedService* DriveIntegrationServiceFactory::BuildServiceInstanceFor(
    649     content::BrowserContext* context) const {
    650   Profile* profile = Profile::FromBrowserContext(context);
    651 
    652   DriveIntegrationService* service = NULL;
    653   if (!factory_for_test_) {
    654     DriveIntegrationService::PreferenceWatcher* preference_watcher = NULL;
    655     if (chromeos::IsProfileAssociatedWithGaiaAccount(profile)) {
    656       // Drive File System can be enabled.
    657       preference_watcher =
    658           new DriveIntegrationService::PreferenceWatcher(profile->GetPrefs());
    659     }
    660 
    661     service = new DriveIntegrationService(
    662         profile, preference_watcher,
    663         NULL, std::string(), base::FilePath(), NULL);
    664   } else {
    665     service = factory_for_test_->Run(profile);
    666   }
    667 
    668   return service;
    669 }
    670 
    671 }  // namespace drive
    672