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