sync_file_system_backend.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
1// Copyright 2013 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/sync_file_system/local/sync_file_system_backend.h" 6 7#include "base/logging.h" 8#include "chrome/browser/chrome_notification_types.h" 9#include "chrome/browser/sync_file_system/local/local_file_change_tracker.h" 10#include "chrome/browser/sync_file_system/local/local_file_sync_context.h" 11#include "chrome/browser/sync_file_system/local/syncable_file_system_operation.h" 12#include "chrome/browser/sync_file_system/sync_file_system_service.h" 13#include "chrome/browser/sync_file_system/sync_file_system_service_factory.h" 14#include "chrome/browser/sync_file_system/syncable_file_system_util.h" 15#include "content/public/browser/browser_thread.h" 16#include "content/public/browser/notification_service.h" 17#include "webkit/browser/blob/file_stream_reader.h" 18#include "webkit/browser/fileapi/file_stream_writer.h" 19#include "webkit/browser/fileapi/file_system_context.h" 20#include "webkit/browser/fileapi/file_system_operation.h" 21#include "webkit/browser/fileapi/sandbox_quota_observer.h" 22#include "webkit/common/fileapi/file_system_util.h" 23 24using content::BrowserThread; 25 26namespace sync_file_system { 27 28namespace { 29 30bool CalledOnUIThread() { 31 // Ensure that these methods are called on the UI thread, except for unittests 32 // where a UI thread might not have been created. 33 return BrowserThread::CurrentlyOn(BrowserThread::UI) || 34 !BrowserThread::IsMessageLoopValid(BrowserThread::UI); 35} 36 37} // namespace 38 39SyncFileSystemBackend::ProfileHolder::ProfileHolder(Profile* profile) 40 : profile_(profile) { 41 DCHECK(CalledOnUIThread()); 42 registrar_.Add(this, 43 chrome::NOTIFICATION_PROFILE_DESTROYED, 44 content::Source<Profile>(profile_)); 45} 46 47void SyncFileSystemBackend::ProfileHolder::Observe( 48 int type, 49 const content::NotificationSource& source, 50 const content::NotificationDetails& details) { 51 DCHECK(CalledOnUIThread()); 52 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type); 53 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr()); 54 profile_ = NULL; 55 registrar_.RemoveAll(); 56} 57 58Profile* SyncFileSystemBackend::ProfileHolder::GetProfile() { 59 DCHECK(CalledOnUIThread()); 60 return profile_; 61} 62 63SyncFileSystemBackend::SyncFileSystemBackend(Profile* profile) 64 : context_(NULL), 65 skip_initialize_syncfs_service_for_testing_(false) { 66 DCHECK(CalledOnUIThread()); 67 if (profile) 68 profile_holder_.reset(new ProfileHolder(profile)); 69 70 // Register the service name here to enable to crack an URL on SyncFileSystem 71 // even if SyncFileSystemService has not started yet. 72 RegisterSyncableFileSystem(); 73} 74 75SyncFileSystemBackend::~SyncFileSystemBackend() { 76 RevokeSyncableFileSystem(); 77 78 if (change_tracker_) { 79 GetDelegate()->file_task_runner()->DeleteSoon( 80 FROM_HERE, change_tracker_.release()); 81 } 82 83 if (profile_holder_ && !CalledOnUIThread()) { 84 BrowserThread::DeleteSoon( 85 BrowserThread::UI, FROM_HERE, profile_holder_.release()); 86 } 87} 88 89// static 90SyncFileSystemBackend* SyncFileSystemBackend::CreateForTesting() { 91 DCHECK(CalledOnUIThread()); 92 SyncFileSystemBackend* backend = new SyncFileSystemBackend(NULL); 93 backend->skip_initialize_syncfs_service_for_testing_ = true; 94 return backend; 95} 96 97bool SyncFileSystemBackend::CanHandleType( 98 fileapi::FileSystemType type) const { 99 return type == fileapi::kFileSystemTypeSyncable || 100 type == fileapi::kFileSystemTypeSyncableForInternalSync; 101} 102 103void SyncFileSystemBackend::Initialize(fileapi::FileSystemContext* context) { 104 DCHECK(context); 105 DCHECK(!context_); 106 context_ = context; 107 108 fileapi::SandboxFileSystemBackendDelegate* delegate = GetDelegate(); 109 delegate->AddFileUpdateObserver( 110 fileapi::kFileSystemTypeSyncable, 111 delegate->quota_observer(), 112 delegate->file_task_runner()); 113 delegate->AddFileUpdateObserver( 114 fileapi::kFileSystemTypeSyncableForInternalSync, 115 delegate->quota_observer(), 116 delegate->file_task_runner()); 117} 118 119void SyncFileSystemBackend::OpenFileSystem( 120 const GURL& origin_url, 121 fileapi::FileSystemType type, 122 fileapi::OpenFileSystemMode mode, 123 const OpenFileSystemCallback& callback) { 124 DCHECK(CanHandleType(type)); 125 126 if (skip_initialize_syncfs_service_for_testing_) { 127 GetDelegate()->OpenFileSystem(origin_url, type, mode, callback, 128 GetSyncableFileSystemRootURI(origin_url)); 129 return; 130 } 131 132 // It is safe to pass Unretained(this) since |context_| owns it. 133 SyncStatusCallback initialize_callback = 134 base::Bind(&SyncFileSystemBackend::DidInitializeSyncFileSystemService, 135 base::Unretained(this), make_scoped_refptr(context_), 136 origin_url, type, mode, callback); 137 InitializeSyncFileSystemService(origin_url, initialize_callback); 138} 139 140fileapi::AsyncFileUtil* SyncFileSystemBackend::GetAsyncFileUtil( 141 fileapi::FileSystemType type) { 142 return GetDelegate()->file_util(); 143} 144 145fileapi::CopyOrMoveFileValidatorFactory* 146SyncFileSystemBackend::GetCopyOrMoveFileValidatorFactory( 147 fileapi::FileSystemType type, 148 base::PlatformFileError* error_code) { 149 DCHECK(error_code); 150 *error_code = base::PLATFORM_FILE_OK; 151 return NULL; 152} 153 154fileapi::FileSystemOperation* 155SyncFileSystemBackend::CreateFileSystemOperation( 156 const fileapi::FileSystemURL& url, 157 fileapi::FileSystemContext* context, 158 base::PlatformFileError* error_code) const { 159 DCHECK(CanHandleType(url.type())); 160 DCHECK(context); 161 DCHECK(error_code); 162 163 scoped_ptr<fileapi::FileSystemOperationContext> operation_context = 164 GetDelegate()->CreateFileSystemOperationContext(url, context, error_code); 165 if (!operation_context) 166 return NULL; 167 168 if (url.type() == fileapi::kFileSystemTypeSyncableForInternalSync) { 169 return fileapi::FileSystemOperation::Create( 170 url, context, operation_context.Pass()); 171 } 172 173 return new SyncableFileSystemOperation( 174 url, context, operation_context.Pass()); 175} 176 177scoped_ptr<webkit_blob::FileStreamReader> 178SyncFileSystemBackend::CreateFileStreamReader( 179 const fileapi::FileSystemURL& url, 180 int64 offset, 181 const base::Time& expected_modification_time, 182 fileapi::FileSystemContext* context) const { 183 DCHECK(CanHandleType(url.type())); 184 return GetDelegate()->CreateFileStreamReader( 185 url, offset, expected_modification_time, context); 186} 187 188scoped_ptr<fileapi::FileStreamWriter> 189SyncFileSystemBackend::CreateFileStreamWriter( 190 const fileapi::FileSystemURL& url, 191 int64 offset, 192 fileapi::FileSystemContext* context) const { 193 DCHECK(CanHandleType(url.type())); 194 return GetDelegate()->CreateFileStreamWriter( 195 url, offset, context, fileapi::kFileSystemTypeSyncableForInternalSync); 196} 197 198fileapi::FileSystemQuotaUtil* SyncFileSystemBackend::GetQuotaUtil() { 199 return GetDelegate(); 200} 201 202// static 203SyncFileSystemBackend* SyncFileSystemBackend::GetBackend( 204 const fileapi::FileSystemContext* file_system_context) { 205 DCHECK(file_system_context); 206 return static_cast<SyncFileSystemBackend*>( 207 file_system_context->GetFileSystemBackend( 208 fileapi::kFileSystemTypeSyncable)); 209} 210 211void SyncFileSystemBackend::SetLocalFileChangeTracker( 212 scoped_ptr<LocalFileChangeTracker> tracker) { 213 DCHECK(!change_tracker_); 214 DCHECK(tracker); 215 change_tracker_ = tracker.Pass(); 216 217 fileapi::SandboxFileSystemBackendDelegate* delegate = GetDelegate(); 218 delegate->AddFileUpdateObserver( 219 fileapi::kFileSystemTypeSyncable, 220 change_tracker_.get(), 221 delegate->file_task_runner()); 222 delegate->AddFileChangeObserver( 223 fileapi::kFileSystemTypeSyncable, 224 change_tracker_.get(), 225 delegate->file_task_runner()); 226} 227 228void SyncFileSystemBackend::set_sync_context( 229 LocalFileSyncContext* sync_context) { 230 DCHECK(!sync_context_); 231 sync_context_ = sync_context; 232} 233 234fileapi::SandboxFileSystemBackendDelegate* 235SyncFileSystemBackend::GetDelegate() const { 236 DCHECK(context_); 237 DCHECK(context_->sandbox_delegate()); 238 return context_->sandbox_delegate(); 239} 240 241void SyncFileSystemBackend::InitializeSyncFileSystemService( 242 const GURL& origin_url, 243 const SyncStatusCallback& callback) { 244 // Repost to switch from IO thread to UI thread. 245 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 247 // It is safe to pass Unretained(this) (see comments in OpenFileSystem()). 248 BrowserThread::PostTask( 249 BrowserThread::UI, FROM_HERE, 250 base::Bind(&SyncFileSystemBackend::InitializeSyncFileSystemService, 251 base::Unretained(this), origin_url, callback)); 252 return; 253 } 254 255 if (!profile_holder_->GetProfile()) { 256 // Profile was destroyed. 257 callback.Run(SYNC_FILE_ERROR_FAILED); 258 return; 259 } 260 261 SyncFileSystemService* service = SyncFileSystemServiceFactory::GetForProfile( 262 profile_holder_->GetProfile()); 263 DCHECK(service); 264 service->InitializeForApp(context_, origin_url, callback); 265} 266 267void SyncFileSystemBackend::DidInitializeSyncFileSystemService( 268 fileapi::FileSystemContext* context, 269 const GURL& origin_url, 270 fileapi::FileSystemType type, 271 fileapi::OpenFileSystemMode mode, 272 const OpenFileSystemCallback& callback, 273 SyncStatusCode status) { 274 // Repost to switch from UI thread to IO thread. 275 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 277 // It is safe to pass Unretained(this) since |context| owns it. 278 BrowserThread::PostTask( 279 BrowserThread::IO, FROM_HERE, 280 base::Bind(&SyncFileSystemBackend::DidInitializeSyncFileSystemService, 281 base::Unretained(this), make_scoped_refptr(context), 282 origin_url, type, mode, callback, status)); 283 return; 284 } 285 286 if (status != sync_file_system::SYNC_STATUS_OK) { 287 callback.Run(GURL(), std::string(), 288 SyncStatusCodeToPlatformFileError(status)); 289 return; 290 } 291 292 GetDelegate()->OpenFileSystem(origin_url, type, mode, callback, 293 GetSyncableFileSystemRootURI(origin_url)); 294} 295 296} // namespace sync_file_system 297