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
53using content::BrowserContext;
54using content::BrowserThread;
55
56namespace drive {
57namespace {
58
59// Name of the directory used to store metadata.
60const base::FilePath::CharType kMetadataDirectory[] = FILE_PATH_LITERAL("meta");
61
62// Name of the directory used to store cached files.
63const base::FilePath::CharType kCacheFileDirectory[] =
64    FILE_PATH_LITERAL("files");
65
66// Name of the directory used to store temporary files.
67const 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
77std::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|.
101FileError 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.
178class 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
211DriveIntegrationService::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
288DriveIntegrationService::~DriveIntegrationService() {
289  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
290}
291
292void 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
311void 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
350bool 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
363void DriveIntegrationService::AddObserver(
364    DriveIntegrationServiceObserver* observer) {
365  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
366  observers_.AddObserver(observer);
367}
368
369void DriveIntegrationService::RemoveObserver(
370    DriveIntegrationServiceObserver* observer) {
371  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
372  observers_.RemoveObserver(observer);
373}
374
375void DriveIntegrationService::OnNotificationReceived() {
376  file_system_->CheckForUpdates();
377  drive_app_registry_->Update();
378}
379
380void 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
388void 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
410void 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
428void 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
454void 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
472void 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
492void 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
558void 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
568void 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
584DriveIntegrationServiceFactory::FactoryCallback*
585    DriveIntegrationServiceFactory::factory_for_test_ = NULL;
586
587DriveIntegrationServiceFactory::ScopedFactoryForTest::ScopedFactoryForTest(
588    FactoryCallback* factory_for_test) {
589  factory_for_test_ = factory_for_test;
590}
591
592DriveIntegrationServiceFactory::ScopedFactoryForTest::~ScopedFactoryForTest() {
593  factory_for_test_ = NULL;
594}
595
596// static
597DriveIntegrationService* DriveIntegrationServiceFactory::GetForProfile(
598    Profile* profile) {
599  return static_cast<DriveIntegrationService*>(
600      GetInstance()->GetServiceForBrowserContext(profile, true));
601}
602
603// static
604DriveIntegrationService* DriveIntegrationServiceFactory::FindForProfile(
605    Profile* profile) {
606  return static_cast<DriveIntegrationService*>(
607      GetInstance()->GetServiceForBrowserContext(profile, false));
608}
609
610// static
611DriveIntegrationServiceFactory* DriveIntegrationServiceFactory::GetInstance() {
612  return Singleton<DriveIntegrationServiceFactory>::get();
613}
614
615DriveIntegrationServiceFactory::DriveIntegrationServiceFactory()
616    : BrowserContextKeyedServiceFactory(
617        "DriveIntegrationService",
618        BrowserContextDependencyManager::GetInstance()) {
619  DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
620  DependsOn(DriveNotificationManagerFactory::GetInstance());
621  DependsOn(DownloadServiceFactory::GetInstance());
622}
623
624DriveIntegrationServiceFactory::~DriveIntegrationServiceFactory() {
625}
626
627content::BrowserContext* DriveIntegrationServiceFactory::GetBrowserContextToUse(
628    content::BrowserContext* context) const {
629  return chrome::GetBrowserContextRedirectedInIncognito(context);
630}
631
632KeyedService* 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