drive_integration_service.cc revision 558790d6acca3451cf3a6b497803a5f07d0bec58
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_service.h" 10#include "base/strings/stringprintf.h" 11#include "base/threading/sequenced_worker_pool.h" 12#include "chrome/browser/browser_process.h" 13#include "chrome/browser/chromeos/drive/debug_info_collector.h" 14#include "chrome/browser/chromeos/drive/download_handler.h" 15#include "chrome/browser/chromeos/drive/drive_app_registry.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/file_write_helper.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/download/download_service.h" 25#include "chrome/browser/download/download_service_factory.h" 26#include "chrome/browser/download/download_util.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_notification_manager.h" 30#include "chrome/browser/drive/drive_notification_manager_factory.h" 31#include "chrome/browser/drive/gdata_wapi_service.h" 32#include "chrome/browser/google_apis/auth_service.h" 33#include "chrome/browser/google_apis/gdata_wapi_url_generator.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 "webkit/browser/fileapi/external_mount_points.h" 43#include "webkit/common/user_agent/user_agent_util.h" 44 45using content::BrowserContext; 46using content::BrowserThread; 47 48namespace drive { 49namespace { 50 51// Returns true if Drive is enabled for the given Profile. 52bool IsDriveEnabledForProfile(Profile* profile) { 53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 54 55 if (!google_apis::AuthService::CanAuthenticate(profile)) 56 return false; 57 58 // Disable Drive if preference is set. This can happen with commandline flag 59 // --disable-gdata or enterprise policy, or probably with user settings too 60 // in the future. 61 if (profile->GetPrefs()->GetBoolean(prefs::kDisableDrive)) 62 return false; 63 64 return true; 65} 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 = webkit_glue::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 if (!file_util::CreateDirectory(cache_root_directory.Append( 104 util::kMetadataDirectory)) || 105 !file_util::CreateDirectory(cache_root_directory.Append( 106 util::kCacheFileDirectory)) || 107 !file_util::CreateDirectory(cache_root_directory.Append( 108 util::kTemporaryFileDirectory))) { 109 LOG(WARNING) << "Failed to create directories."; 110 return FILE_ERROR_FAILED; 111 } 112 113 // Change permissions of cache file directory to u+rwx,og+x (711) in order to 114 // allow archive files in that directory to be mounted by cros-disks. 115 file_util::SetPosixFilePermissions( 116 cache_root_directory.Append(util::kCacheFileDirectory), 117 file_util::FILE_PERMISSION_USER_MASK | 118 file_util::FILE_PERMISSION_EXECUTE_BY_GROUP | 119 file_util::FILE_PERMISSION_EXECUTE_BY_OTHERS); 120 121 util::MigrateCacheFilesFromOldDirectories(cache_root_directory); 122 123 if (!metadata_storage->Initialize()) { 124 LOG(WARNING) << "Failed to initialize the metadata storage."; 125 return FILE_ERROR_FAILED; 126 } 127 128 if (!cache->Initialize()) { 129 LOG(WARNING) << "Failed to initialize the cache."; 130 return FILE_ERROR_FAILED; 131 } 132 133 FileError error = resource_metadata->Initialize(); 134 LOG_IF(WARNING, error != FILE_ERROR_OK) 135 << "Failed to initialize resource metadata. " << FileErrorToString(error); 136 return error; 137} 138 139} // namespace 140 141DriveIntegrationService::DriveIntegrationService( 142 Profile* profile, 143 DriveServiceInterface* test_drive_service, 144 const base::FilePath& test_cache_root, 145 FileSystemInterface* test_file_system) 146 : profile_(profile), 147 drive_disabled_(false), 148 cache_root_directory_(!test_cache_root.empty() ? 149 test_cache_root : util::GetCacheRootPath(profile)), 150 weak_ptr_factory_(this) { 151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 152 153 base::SequencedWorkerPool* blocking_pool = BrowserThread::GetBlockingPool(); 154 blocking_task_runner_ = blocking_pool->GetSequencedTaskRunner( 155 blocking_pool->GetSequenceToken()); 156 157 OAuth2TokenService* oauth_service = 158 ProfileOAuth2TokenServiceFactory::GetForProfile(profile); 159 160 if (test_drive_service) { 161 drive_service_.reset(test_drive_service); 162 } else if (util::IsDriveV2ApiEnabled()) { 163 drive_service_.reset(new DriveAPIService( 164 oauth_service, 165 g_browser_process->system_request_context(), 166 blocking_task_runner_.get(), 167 GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction), 168 GURL(google_apis::DriveApiUrlGenerator::kBaseDownloadUrlForProduction), 169 GetDriveUserAgent())); 170 } else { 171 drive_service_.reset(new GDataWapiService( 172 oauth_service, 173 g_browser_process->system_request_context(), 174 blocking_task_runner_.get(), 175 GURL(google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction), 176 GURL(google_apis::GDataWapiUrlGenerator::kBaseDownloadUrlForProduction), 177 GetDriveUserAgent())); 178 } 179 scheduler_.reset(new JobScheduler( 180 profile_->GetPrefs(), 181 drive_service_.get(), 182 blocking_task_runner_.get())); 183 metadata_storage_.reset(new internal::ResourceMetadataStorage( 184 cache_root_directory_.Append(util::kMetadataDirectory), 185 blocking_task_runner_.get())); 186 cache_.reset(new internal::FileCache( 187 metadata_storage_.get(), 188 cache_root_directory_.Append(util::kCacheFileDirectory), 189 blocking_task_runner_.get(), 190 NULL /* free_disk_space_getter */)); 191 drive_app_registry_.reset(new DriveAppRegistry(scheduler_.get())); 192 193 resource_metadata_.reset(new internal::ResourceMetadata( 194 metadata_storage_.get(), blocking_task_runner_)); 195 196 file_system_.reset( 197 test_file_system ? test_file_system : new FileSystem( 198 profile_->GetPrefs(), 199 cache_.get(), 200 drive_service_.get(), 201 scheduler_.get(), 202 resource_metadata_.get(), 203 blocking_task_runner_.get(), 204 cache_root_directory_.Append(util::kTemporaryFileDirectory))); 205 file_write_helper_.reset(new FileWriteHelper(file_system())); 206 download_handler_.reset(new DownloadHandler(file_write_helper(), 207 file_system())); 208 debug_info_collector_.reset( 209 new DebugInfoCollector(file_system(), cache_.get())); 210} 211 212DriveIntegrationService::~DriveIntegrationService() { 213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 214} 215 216void DriveIntegrationService::Initialize() { 217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 218 drive_service_->Initialize(); 219 file_system_->Initialize(); 220 221 base::PostTaskAndReplyWithResult( 222 blocking_task_runner_.get(), 223 FROM_HERE, 224 base::Bind(&InitializeMetadata, 225 cache_root_directory_, 226 metadata_storage_.get(), 227 cache_.get(), 228 resource_metadata_.get()), 229 base::Bind(&DriveIntegrationService::InitializeAfterMetadataInitialized, 230 weak_ptr_factory_.GetWeakPtr())); 231} 232 233void DriveIntegrationService::Shutdown() { 234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 235 236 DriveNotificationManager* drive_notification_manager = 237 DriveNotificationManagerFactory::GetForProfile(profile_); 238 if (drive_notification_manager) 239 drive_notification_manager->RemoveObserver(this); 240 241 RemoveDriveMountPoint(); 242 debug_info_collector_.reset(); 243 download_handler_.reset(); 244 file_write_helper_.reset(); 245 file_system_.reset(); 246 drive_app_registry_.reset(); 247 scheduler_.reset(); 248 drive_service_.reset(); 249} 250 251void DriveIntegrationService::AddObserver( 252 DriveIntegrationServiceObserver* observer) { 253 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 254 observers_.AddObserver(observer); 255} 256 257void DriveIntegrationService::RemoveObserver( 258 DriveIntegrationServiceObserver* observer) { 259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 260 observers_.RemoveObserver(observer); 261} 262 263void DriveIntegrationService::OnNotificationReceived() { 264 file_system_->CheckForUpdates(); 265 drive_app_registry_->Update(); 266} 267 268void DriveIntegrationService::OnPushNotificationEnabled(bool enabled) { 269 if (enabled) 270 drive_app_registry_->Update(); 271 272 const char* status = (enabled ? "enabled" : "disabled"); 273 util::Log("Push notification is %s", status); 274} 275 276bool DriveIntegrationService::IsDriveEnabled() { 277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 278 279 if (!IsDriveEnabledForProfile(profile_)) 280 return false; 281 282 // Drive may be disabled for cache initialization failure, etc. 283 if (drive_disabled_) 284 return false; 285 286 return true; 287} 288 289void DriveIntegrationService::ClearCacheAndRemountFileSystem( 290 const base::Callback<void(bool)>& callback) { 291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 292 DCHECK(!callback.is_null()); 293 294 RemoveDriveMountPoint(); 295 // Reloading the file system will clear the resource metadata. 296 file_system_->Reload(); 297 // Reload the Drive app registry too. 298 drive_app_registry_->Update(); 299 300 cache_->ClearAllOnUIThread(base::Bind( 301 &DriveIntegrationService::AddBackDriveMountPoint, 302 weak_ptr_factory_.GetWeakPtr(), 303 callback)); 304} 305 306void DriveIntegrationService::AddBackDriveMountPoint( 307 const base::Callback<void(bool)>& callback, 308 bool success) { 309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 310 DCHECK(!callback.is_null()); 311 312 if (!success) { 313 callback.Run(false); 314 return; 315 } 316 317 file_system_->Initialize(); 318 drive_app_registry_->Update(); 319 AddDriveMountPoint(); 320 321 callback.Run(true); 322} 323 324void DriveIntegrationService::AddDriveMountPoint() { 325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 326 327 const base::FilePath drive_mount_point = util::GetDriveMountPointPath(); 328 fileapi::ExternalMountPoints* mount_points = 329 BrowserContext::GetMountPoints(profile_); 330 DCHECK(mount_points); 331 332 bool success = mount_points->RegisterFileSystem( 333 drive_mount_point.BaseName().AsUTF8Unsafe(), 334 fileapi::kFileSystemTypeDrive, 335 drive_mount_point); 336 337 if (success) { 338 util::Log("Drive mount point is added"); 339 FOR_EACH_OBSERVER(DriveIntegrationServiceObserver, observers_, 340 OnFileSystemMounted()); 341 } 342} 343 344void DriveIntegrationService::RemoveDriveMountPoint() { 345 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 346 347 job_list()->CancelAllJobs(); 348 349 FOR_EACH_OBSERVER(DriveIntegrationServiceObserver, observers_, 350 OnFileSystemBeingUnmounted()); 351 352 fileapi::ExternalMountPoints* mount_points = 353 BrowserContext::GetMountPoints(profile_); 354 DCHECK(mount_points); 355 356 mount_points->RevokeFileSystem( 357 util::GetDriveMountPointPath().BaseName().AsUTF8Unsafe()); 358 util::Log("Drive mount point is removed"); 359} 360 361void DriveIntegrationService::InitializeAfterMetadataInitialized( 362 FileError error) { 363 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 364 365 if (error != FILE_ERROR_OK) { 366 LOG(WARNING) << "Failed to initialize. Disabling Drive : " 367 << FileErrorToString(error); 368 DisableDrive(); 369 return; 370 } 371 372 content::DownloadManager* download_manager = 373 g_browser_process->download_status_updater() ? 374 BrowserContext::GetDownloadManager(profile_) : NULL; 375 download_handler_->Initialize( 376 download_manager, 377 cache_root_directory_.Append(util::kTemporaryFileDirectory)); 378 379 // Register for Google Drive invalidation notifications. 380 DriveNotificationManager* drive_notification_manager = 381 DriveNotificationManagerFactory::GetForProfile(profile_); 382 if (drive_notification_manager) { 383 drive_notification_manager->AddObserver(this); 384 const bool registered = 385 drive_notification_manager->push_notification_registered(); 386 const char* status = (registered ? "registered" : "not registered"); 387 util::Log("Push notification is %s", status); 388 389 if (drive_notification_manager->push_notification_enabled()) 390 drive_app_registry_->Update(); 391 } 392 393 AddDriveMountPoint(); 394} 395 396void DriveIntegrationService::DisableDrive() { 397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 398 399 drive_disabled_ = true; 400 // Change the download directory to the default value if the download 401 // destination is set to under Drive mount point. 402 PrefService* pref_service = profile_->GetPrefs(); 403 if (util::IsUnderDriveMountPoint( 404 pref_service->GetFilePath(prefs::kDownloadDefaultDirectory))) { 405 pref_service->SetFilePath(prefs::kDownloadDefaultDirectory, 406 download_util::GetDefaultDownloadDirectory()); 407 } 408} 409 410//===================== DriveIntegrationServiceFactory ======================= 411 412// static 413DriveIntegrationService* DriveIntegrationServiceFactory::GetForProfile( 414 Profile* profile) { 415 DriveIntegrationService* service = GetForProfileRegardlessOfStates(profile); 416 if (service && !service->IsDriveEnabled()) 417 return NULL; 418 419 return service; 420} 421 422// static 423DriveIntegrationService* 424DriveIntegrationServiceFactory::GetForProfileRegardlessOfStates( 425 Profile* profile) { 426 return static_cast<DriveIntegrationService*>( 427 GetInstance()->GetServiceForBrowserContext(profile, true)); 428} 429 430// static 431DriveIntegrationService* DriveIntegrationServiceFactory::FindForProfile( 432 Profile* profile) { 433 DriveIntegrationService* service = FindForProfileRegardlessOfStates(profile); 434 if (service && !service->IsDriveEnabled()) 435 return NULL; 436 437 return service; 438} 439 440// static 441DriveIntegrationService* 442DriveIntegrationServiceFactory::FindForProfileRegardlessOfStates( 443 Profile* profile) { 444 return static_cast<DriveIntegrationService*>( 445 GetInstance()->GetServiceForBrowserContext(profile, false)); 446} 447 448// static 449DriveIntegrationServiceFactory* DriveIntegrationServiceFactory::GetInstance() { 450 return Singleton<DriveIntegrationServiceFactory>::get(); 451} 452 453// static 454void DriveIntegrationServiceFactory::SetFactoryForTest( 455 const FactoryCallback& factory_for_test) { 456 GetInstance()->factory_for_test_ = factory_for_test; 457} 458 459DriveIntegrationServiceFactory::DriveIntegrationServiceFactory() 460 : BrowserContextKeyedServiceFactory( 461 "DriveIntegrationService", 462 BrowserContextDependencyManager::GetInstance()) { 463 DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance()); 464 DependsOn(DriveNotificationManagerFactory::GetInstance()); 465 DependsOn(DownloadServiceFactory::GetInstance()); 466} 467 468DriveIntegrationServiceFactory::~DriveIntegrationServiceFactory() { 469} 470 471BrowserContextKeyedService* 472DriveIntegrationServiceFactory::BuildServiceInstanceFor( 473 content::BrowserContext* context) const { 474 Profile* profile = static_cast<Profile*>(context); 475 476 DriveIntegrationService* service = NULL; 477 if (factory_for_test_.is_null()) { 478 service = new DriveIntegrationService( 479 profile, NULL, base::FilePath(), NULL); 480 } else { 481 service = factory_for_test_.Run(profile); 482 } 483 484 service->Initialize(); 485 return service; 486} 487 488} // namespace drive 489