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