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