OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/sync_file_system/drive_backend/sync_engine.h" | 5 #include "chrome/browser/sync_file_system/drive_backend/sync_engine.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/threading/sequenced_worker_pool.h" | 10 #include "base/threading/sequenced_worker_pool.h" |
11 #include "base/values.h" | 11 #include "base/values.h" |
12 #include "chrome/browser/drive/drive_api_service.h" | 12 #include "chrome/browser/drive/drive_api_service.h" |
13 #include "chrome/browser/drive/drive_notification_manager.h" | 13 #include "chrome/browser/drive/drive_notification_manager.h" |
14 #include "chrome/browser/drive/drive_notification_manager_factory.h" | 14 #include "chrome/browser/drive/drive_notification_manager_factory.h" |
15 #include "chrome/browser/drive/drive_service_interface.h" | 15 #include "chrome/browser/drive/drive_service_interface.h" |
16 #include "chrome/browser/drive/drive_uploader.h" | 16 #include "chrome/browser/drive/drive_uploader.h" |
17 #include "chrome/browser/extensions/extension_service.h" | 17 #include "chrome/browser/extensions/extension_service.h" |
18 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
19 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" | 19 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" |
20 #include "chrome/browser/signin/signin_manager.h" | 20 #include "chrome/browser/signin/signin_manager.h" |
21 #include "chrome/browser/signin/signin_manager_factory.h" | 21 #include "chrome/browser/signin/signin_manager_factory.h" |
22 #include "chrome/browser/sync_file_system/drive_backend/conflict_resolver.h" | 22 #include "chrome/browser/sync_file_system/drive_backend/conflict_resolver.h" |
23 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.
h" | 23 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.
h" |
24 #include "chrome/browser/sync_file_system/drive_backend/list_changes_task.h" | 24 #include "chrome/browser/sync_file_system/drive_backend/list_changes_task.h" |
25 #include "chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer.h
" | 25 #include "chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer.h
" |
26 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h" | 26 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h" |
27 #include "chrome/browser/sync_file_system/drive_backend/register_app_task.h" | 27 #include "chrome/browser/sync_file_system/drive_backend/register_app_task.h" |
28 #include "chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.h
" | 28 #include "chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.h
" |
| 29 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h" |
29 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.
h" | 30 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.
h" |
30 #include "chrome/browser/sync_file_system/drive_backend/sync_task.h" | 31 #include "chrome/browser/sync_file_system/drive_backend/sync_task.h" |
31 #include "chrome/browser/sync_file_system/drive_backend/uninstall_app_task.h" | 32 #include "chrome/browser/sync_file_system/drive_backend/uninstall_app_task.h" |
32 #include "chrome/browser/sync_file_system/file_status_observer.h" | 33 #include "chrome/browser/sync_file_system/file_status_observer.h" |
33 #include "chrome/browser/sync_file_system/logger.h" | 34 #include "chrome/browser/sync_file_system/logger.h" |
34 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" | 35 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" |
35 #include "components/signin/core/browser/profile_oauth2_token_service.h" | 36 #include "components/signin/core/browser/profile_oauth2_token_service.h" |
36 #include "content/public/browser/browser_thread.h" | 37 #include "content/public/browser/browser_thread.h" |
37 #include "extensions/browser/extension_system.h" | 38 #include "extensions/browser/extension_system.h" |
38 #include "extensions/browser/extension_system_provider.h" | 39 #include "extensions/browser/extension_system_provider.h" |
39 #include "extensions/browser/extensions_browser_client.h" | 40 #include "extensions/browser/extensions_browser_client.h" |
40 #include "extensions/common/extension.h" | 41 #include "extensions/common/extension.h" |
41 #include "google_apis/drive/drive_api_url_generator.h" | 42 #include "google_apis/drive/drive_api_url_generator.h" |
42 #include "google_apis/drive/gdata_wapi_url_generator.h" | 43 #include "google_apis/drive/gdata_wapi_url_generator.h" |
43 #include "webkit/common/blob/scoped_file.h" | 44 #include "webkit/common/blob/scoped_file.h" |
44 #include "webkit/common/fileapi/file_system_util.h" | 45 #include "webkit/common/fileapi/file_system_util.h" |
45 | 46 |
46 namespace sync_file_system { | 47 namespace sync_file_system { |
| 48 |
| 49 class RemoteChangeProcessor; |
| 50 |
47 namespace drive_backend { | 51 namespace drive_backend { |
48 | 52 |
49 namespace { | 53 namespace { |
50 | 54 |
51 void EmptyStatusCallback(SyncStatusCode status) {} | 55 void EmptyStatusCallback(SyncStatusCode status) {} |
52 | 56 |
53 } // namespace | 57 } // namespace |
54 | 58 |
55 scoped_ptr<SyncEngine> SyncEngine::CreateForBrowserContext( | 59 scoped_ptr<SyncEngine> SyncEngine::CreateForBrowserContext( |
56 content::BrowserContext* context) { | 60 content::BrowserContext* context) { |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 std::set<BrowserContextKeyedServiceFactory*>* factories) { | 118 std::set<BrowserContextKeyedServiceFactory*>* factories) { |
115 DCHECK(factories); | 119 DCHECK(factories); |
116 factories->insert(drive::DriveNotificationManagerFactory::GetInstance()); | 120 factories->insert(drive::DriveNotificationManagerFactory::GetInstance()); |
117 factories->insert(SigninManagerFactory::GetInstance()); | 121 factories->insert(SigninManagerFactory::GetInstance()); |
118 factories->insert( | 122 factories->insert( |
119 extensions::ExtensionsBrowserClient::Get()->GetExtensionSystemFactory()); | 123 extensions::ExtensionsBrowserClient::Get()->GetExtensionSystemFactory()); |
120 } | 124 } |
121 | 125 |
122 SyncEngine::~SyncEngine() { | 126 SyncEngine::~SyncEngine() { |
123 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); | 127 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); |
124 drive_service_->RemoveObserver(this); | 128 context_->GetDriveService()->RemoveObserver(this); |
125 if (notification_manager_) | 129 if (notification_manager_) |
126 notification_manager_->RemoveObserver(this); | 130 notification_manager_->RemoveObserver(this); |
127 } | 131 } |
128 | 132 |
129 void SyncEngine::Initialize() { | 133 void SyncEngine::Initialize() { |
130 DCHECK(!task_manager_); | 134 DCHECK(!task_manager_); |
131 task_manager_.reset(new SyncTaskManager( | 135 task_manager_.reset(new SyncTaskManager( |
132 weak_ptr_factory_.GetWeakPtr(), | 136 weak_ptr_factory_.GetWeakPtr(), |
133 0 /* maximum_background_task */)); | 137 0 /* maximum_background_task */)); |
134 task_manager_->Initialize(SYNC_STATUS_OK); | 138 task_manager_->Initialize(SYNC_STATUS_OK); |
135 | 139 |
136 PostInitializeTask(); | 140 PostInitializeTask(); |
137 | 141 |
138 if (notification_manager_) | 142 if (notification_manager_) |
139 notification_manager_->AddObserver(this); | 143 notification_manager_->AddObserver(this); |
140 drive_service_->AddObserver(this); | 144 context_->GetDriveService()->AddObserver(this); |
141 net::NetworkChangeNotifier::AddNetworkChangeObserver(this); | 145 net::NetworkChangeNotifier::AddNetworkChangeObserver(this); |
142 | 146 |
143 net::NetworkChangeNotifier::ConnectionType type = | 147 net::NetworkChangeNotifier::ConnectionType type = |
144 net::NetworkChangeNotifier::GetConnectionType(); | 148 net::NetworkChangeNotifier::GetConnectionType(); |
145 network_available_ = | 149 network_available_ = |
146 type != net::NetworkChangeNotifier::CONNECTION_NONE; | 150 type != net::NetworkChangeNotifier::CONNECTION_NONE; |
147 } | 151 } |
148 | 152 |
149 void SyncEngine::AddServiceObserver(SyncServiceObserver* observer) { | 153 void SyncEngine::AddServiceObserver(SyncServiceObserver* observer) { |
150 service_observers_.AddObserver(observer); | 154 service_observers_.AddObserver(observer); |
151 } | 155 } |
152 | 156 |
153 void SyncEngine::AddFileStatusObserver(FileStatusObserver* observer) { | 157 void SyncEngine::AddFileStatusObserver(FileStatusObserver* observer) { |
154 file_status_observers_.AddObserver(observer); | 158 file_status_observers_.AddObserver(observer); |
155 } | 159 } |
156 | 160 |
157 void SyncEngine::RegisterOrigin( | 161 void SyncEngine::RegisterOrigin( |
158 const GURL& origin, | 162 const GURL& origin, |
159 const SyncStatusCallback& callback) { | 163 const SyncStatusCallback& callback) { |
160 if (!metadata_database_ && drive_service_->HasRefreshToken()) | 164 if (!context_->GetMetadataDatabase() && |
| 165 context_->GetDriveService()->HasRefreshToken()) |
161 PostInitializeTask(); | 166 PostInitializeTask(); |
162 | 167 |
163 scoped_ptr<RegisterAppTask> task(new RegisterAppTask(this, origin.host())); | 168 scoped_ptr<RegisterAppTask> task( |
| 169 new RegisterAppTask(context_.get(), origin.host())); |
164 if (task->CanFinishImmediately()) { | 170 if (task->CanFinishImmediately()) { |
165 callback.Run(SYNC_STATUS_OK); | 171 callback.Run(SYNC_STATUS_OK); |
166 return; | 172 return; |
167 } | 173 } |
168 | 174 |
169 task_manager_->ScheduleSyncTask( | 175 task_manager_->ScheduleSyncTask( |
170 FROM_HERE, | 176 FROM_HERE, |
171 task.PassAs<SyncTask>(), | 177 task.PassAs<SyncTask>(), |
172 SyncTaskManager::PRIORITY_HIGH, | 178 SyncTaskManager::PRIORITY_HIGH, |
173 callback); | 179 callback); |
(...skipping 22 matching lines...) Expand all Loading... |
196 SyncTaskManager::PRIORITY_HIGH, | 202 SyncTaskManager::PRIORITY_HIGH, |
197 callback); | 203 callback); |
198 } | 204 } |
199 | 205 |
200 void SyncEngine::UninstallOrigin( | 206 void SyncEngine::UninstallOrigin( |
201 const GURL& origin, | 207 const GURL& origin, |
202 UninstallFlag flag, | 208 UninstallFlag flag, |
203 const SyncStatusCallback& callback) { | 209 const SyncStatusCallback& callback) { |
204 task_manager_->ScheduleSyncTask( | 210 task_manager_->ScheduleSyncTask( |
205 FROM_HERE, | 211 FROM_HERE, |
206 scoped_ptr<SyncTask>(new UninstallAppTask(this, origin.host(), flag)), | 212 scoped_ptr<SyncTask>( |
| 213 new UninstallAppTask(context_.get(), origin.host(), flag)), |
207 SyncTaskManager::PRIORITY_HIGH, | 214 SyncTaskManager::PRIORITY_HIGH, |
208 callback); | 215 callback); |
209 } | 216 } |
210 | 217 |
211 void SyncEngine::ProcessRemoteChange( | 218 void SyncEngine::ProcessRemoteChange( |
212 const SyncFileCallback& callback) { | 219 const SyncFileCallback& callback) { |
213 RemoteToLocalSyncer* syncer = new RemoteToLocalSyncer(this); | 220 RemoteToLocalSyncer* syncer = new RemoteToLocalSyncer(context_.get()); |
214 task_manager_->ScheduleSyncTask( | 221 task_manager_->ScheduleSyncTask( |
215 FROM_HERE, | 222 FROM_HERE, |
216 scoped_ptr<SyncTask>(syncer), | 223 scoped_ptr<SyncTask>(syncer), |
217 SyncTaskManager::PRIORITY_MED, | 224 SyncTaskManager::PRIORITY_MED, |
218 base::Bind(&SyncEngine::DidProcessRemoteChange, | 225 base::Bind(&SyncEngine::DidProcessRemoteChange, |
219 weak_ptr_factory_.GetWeakPtr(), | 226 weak_ptr_factory_.GetWeakPtr(), |
220 syncer, callback)); | 227 syncer, callback)); |
221 } | 228 } |
222 | 229 |
223 void SyncEngine::SetRemoteChangeProcessor( | 230 void SyncEngine::SetRemoteChangeProcessor( |
224 RemoteChangeProcessor* processor) { | 231 RemoteChangeProcessor* processor) { |
225 remote_change_processor_ = processor; | 232 context_->SetRemoteChangeProcessor(processor); |
226 } | 233 } |
227 | 234 |
228 LocalChangeProcessor* SyncEngine::GetLocalChangeProcessor() { | 235 LocalChangeProcessor* SyncEngine::GetLocalChangeProcessor() { |
229 return this; | 236 return this; |
230 } | 237 } |
231 | 238 |
232 bool SyncEngine::IsConflicting(const fileapi::FileSystemURL& url) { | 239 bool SyncEngine::IsConflicting(const fileapi::FileSystemURL& url) { |
233 // TODO(tzik): Implement this before we support manual conflict resolution. | 240 // TODO(tzik): Implement this before we support manual conflict resolution. |
234 return false; | 241 return false; |
235 } | 242 } |
236 | 243 |
237 RemoteServiceState SyncEngine::GetCurrentState() const { | 244 RemoteServiceState SyncEngine::GetCurrentState() const { |
238 if (!sync_enabled_) | 245 if (!sync_enabled_) |
239 return REMOTE_SERVICE_DISABLED; | 246 return REMOTE_SERVICE_DISABLED; |
240 return service_state_; | 247 return service_state_; |
241 } | 248 } |
242 | 249 |
243 void SyncEngine::GetOriginStatusMap(OriginStatusMap* status_map) { | 250 void SyncEngine::GetOriginStatusMap(OriginStatusMap* status_map) { |
244 DCHECK(status_map); | 251 DCHECK(status_map); |
245 if (!extension_service_ || !metadata_database_) | 252 if (!extension_service_ || !context_->GetMetadataDatabase()) |
246 return; | 253 return; |
247 | 254 |
248 std::vector<std::string> app_ids; | 255 std::vector<std::string> app_ids; |
249 metadata_database_->GetRegisteredAppIDs(&app_ids); | 256 context_->GetMetadataDatabase()->GetRegisteredAppIDs(&app_ids); |
250 | 257 |
251 for (std::vector<std::string>::const_iterator itr = app_ids.begin(); | 258 for (std::vector<std::string>::const_iterator itr = app_ids.begin(); |
252 itr != app_ids.end(); ++itr) { | 259 itr != app_ids.end(); ++itr) { |
253 const std::string& app_id = *itr; | 260 const std::string& app_id = *itr; |
254 GURL origin = | 261 GURL origin = |
255 extensions::Extension::GetBaseURLFromExtensionId(app_id); | 262 extensions::Extension::GetBaseURLFromExtensionId(app_id); |
256 (*status_map)[origin] = | 263 (*status_map)[origin] = |
257 metadata_database_->IsAppEnabled(app_id) ? "Enabled" : "Disabled"; | 264 context_->GetMetadataDatabase()->IsAppEnabled(app_id) ? |
| 265 "Enabled" : "Disabled"; |
258 } | 266 } |
259 } | 267 } |
260 | 268 |
261 scoped_ptr<base::ListValue> SyncEngine::DumpFiles(const GURL& origin) { | 269 scoped_ptr<base::ListValue> SyncEngine::DumpFiles(const GURL& origin) { |
262 if (!metadata_database_) | 270 if (!context_->GetMetadataDatabase()) |
263 return scoped_ptr<base::ListValue>(); | 271 return scoped_ptr<base::ListValue>(); |
264 return metadata_database_->DumpFiles(origin.host()); | 272 return context_->GetMetadataDatabase()->DumpFiles(origin.host()); |
265 } | 273 } |
266 | 274 |
267 scoped_ptr<base::ListValue> SyncEngine::DumpDatabase() { | 275 scoped_ptr<base::ListValue> SyncEngine::DumpDatabase() { |
268 if (!metadata_database_) | 276 if (!context_->GetMetadataDatabase()) |
269 return scoped_ptr<base::ListValue>(); | 277 return scoped_ptr<base::ListValue>(); |
270 return metadata_database_->DumpDatabase(); | 278 return context_->GetMetadataDatabase()->DumpDatabase(); |
271 } | 279 } |
272 | 280 |
273 void SyncEngine::SetSyncEnabled(bool enabled) { | 281 void SyncEngine::SetSyncEnabled(bool enabled) { |
274 if (sync_enabled_ == enabled) | 282 if (sync_enabled_ == enabled) |
275 return; | 283 return; |
276 | 284 |
277 RemoteServiceState old_state = GetCurrentState(); | 285 RemoteServiceState old_state = GetCurrentState(); |
278 sync_enabled_ = enabled; | 286 sync_enabled_ = enabled; |
279 if (old_state == GetCurrentState()) | 287 if (old_state == GetCurrentState()) |
280 return; | 288 return; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 | 327 |
320 void SyncEngine::DownloadRemoteVersion( | 328 void SyncEngine::DownloadRemoteVersion( |
321 const fileapi::FileSystemURL& url, | 329 const fileapi::FileSystemURL& url, |
322 const std::string& version_id, | 330 const std::string& version_id, |
323 const DownloadVersionCallback& callback) { | 331 const DownloadVersionCallback& callback) { |
324 // TODO(tzik): Implement this before we support manual conflict resolution. | 332 // TODO(tzik): Implement this before we support manual conflict resolution. |
325 callback.Run(SYNC_STATUS_FAILED, webkit_blob::ScopedFile()); | 333 callback.Run(SYNC_STATUS_FAILED, webkit_blob::ScopedFile()); |
326 } | 334 } |
327 | 335 |
328 void SyncEngine::PromoteDemotedChanges() { | 336 void SyncEngine::PromoteDemotedChanges() { |
329 if (metadata_database_ && metadata_database_->HasLowPriorityDirtyTracker()) { | 337 if (context_->GetMetadataDatabase() && |
330 metadata_database_->PromoteLowerPriorityTrackersToNormal(); | 338 context_->GetMetadataDatabase()->HasLowPriorityDirtyTracker()) { |
| 339 context_->GetMetadataDatabase()->PromoteLowerPriorityTrackersToNormal(); |
331 FOR_EACH_OBSERVER( | 340 FOR_EACH_OBSERVER( |
332 Observer, | 341 Observer, |
333 service_observers_, | 342 service_observers_, |
334 OnRemoteChangeQueueUpdated( | 343 OnRemoteChangeQueueUpdated( |
335 metadata_database_->CountDirtyTracker())); | 344 context_->GetMetadataDatabase()->CountDirtyTracker())); |
336 } | 345 } |
337 } | 346 } |
338 | 347 |
339 void SyncEngine::ApplyLocalChange( | 348 void SyncEngine::ApplyLocalChange( |
340 const FileChange& local_change, | 349 const FileChange& local_change, |
341 const base::FilePath& local_path, | 350 const base::FilePath& local_path, |
342 const SyncFileMetadata& local_metadata, | 351 const SyncFileMetadata& local_metadata, |
343 const fileapi::FileSystemURL& url, | 352 const fileapi::FileSystemURL& url, |
344 const SyncStatusCallback& callback) { | 353 const SyncStatusCallback& callback) { |
345 LocalToRemoteSyncer* syncer = new LocalToRemoteSyncer( | 354 LocalToRemoteSyncer* syncer = new LocalToRemoteSyncer( |
346 this, local_metadata, local_change, local_path, url); | 355 context_.get(), local_metadata, local_change, local_path, url); |
347 task_manager_->ScheduleSyncTask( | 356 task_manager_->ScheduleSyncTask( |
348 FROM_HERE, | 357 FROM_HERE, |
349 scoped_ptr<SyncTask>(syncer), | 358 scoped_ptr<SyncTask>(syncer), |
350 SyncTaskManager::PRIORITY_MED, | 359 SyncTaskManager::PRIORITY_MED, |
351 base::Bind(&SyncEngine::DidApplyLocalChange, | 360 base::Bind(&SyncEngine::DidApplyLocalChange, |
352 weak_ptr_factory_.GetWeakPtr(), | 361 weak_ptr_factory_.GetWeakPtr(), |
353 syncer, callback)); | 362 syncer, callback)); |
354 } | 363 } |
355 | 364 |
356 void SyncEngine::MaybeScheduleNextTask() { | 365 void SyncEngine::MaybeScheduleNextTask() { |
357 if (GetCurrentState() == REMOTE_SERVICE_DISABLED) | 366 if (GetCurrentState() == REMOTE_SERVICE_DISABLED) |
358 return; | 367 return; |
359 | 368 |
360 // TODO(tzik): Notify observer of OnRemoteChangeQueueUpdated. | 369 // TODO(tzik): Notify observer of OnRemoteChangeQueueUpdated. |
361 // TODO(tzik): Add an interface to get the number of dirty trackers to | 370 // TODO(tzik): Add an interface to get the number of dirty trackers to |
362 // MetadataDatabase. | 371 // MetadataDatabase. |
363 | 372 |
364 MaybeStartFetchChanges(); | 373 MaybeStartFetchChanges(); |
365 } | 374 } |
366 | 375 |
367 void SyncEngine::NotifyLastOperationStatus( | 376 void SyncEngine::NotifyLastOperationStatus( |
368 SyncStatusCode sync_status, | 377 SyncStatusCode sync_status, |
369 bool used_network) { | 378 bool used_network) { |
370 UpdateServiceStateFromSyncStatusCode(sync_status, used_network); | 379 UpdateServiceStateFromSyncStatusCode(sync_status, used_network); |
371 if (metadata_database_) { | 380 if (context_->GetMetadataDatabase()) { |
372 FOR_EACH_OBSERVER( | 381 FOR_EACH_OBSERVER( |
373 Observer, | 382 Observer, |
374 service_observers_, | 383 service_observers_, |
375 OnRemoteChangeQueueUpdated( | 384 OnRemoteChangeQueueUpdated( |
376 metadata_database_->CountDirtyTracker())); | 385 context_->GetMetadataDatabase()->CountDirtyTracker())); |
377 } | 386 } |
378 } | 387 } |
379 | 388 |
380 void SyncEngine::OnNotificationReceived() { | 389 void SyncEngine::OnNotificationReceived() { |
381 if (service_state_ == REMOTE_SERVICE_TEMPORARY_UNAVAILABLE) | 390 if (service_state_ == REMOTE_SERVICE_TEMPORARY_UNAVAILABLE) |
382 UpdateServiceState(REMOTE_SERVICE_OK, "Got push notification for Drive."); | 391 UpdateServiceState(REMOTE_SERVICE_OK, "Got push notification for Drive."); |
383 | 392 |
384 should_check_remote_change_ = true; | 393 should_check_remote_change_ = true; |
385 MaybeScheduleNextTask(); | 394 MaybeScheduleNextTask(); |
386 } | 395 } |
387 | 396 |
388 void SyncEngine::OnPushNotificationEnabled(bool enabled) {} | 397 void SyncEngine::OnPushNotificationEnabled(bool enabled) {} |
389 | 398 |
390 void SyncEngine::OnReadyToSendRequests() { | 399 void SyncEngine::OnReadyToSendRequests() { |
391 if (service_state_ == REMOTE_SERVICE_OK) | 400 if (service_state_ == REMOTE_SERVICE_OK) |
392 return; | 401 return; |
393 UpdateServiceState(REMOTE_SERVICE_OK, "Authenticated"); | 402 UpdateServiceState(REMOTE_SERVICE_OK, "Authenticated"); |
394 | 403 |
395 if (!metadata_database_ && signin_manager_) { | 404 if (!context_->GetMetadataDatabase() && signin_manager_) { |
396 drive_service_->Initialize(signin_manager_->GetAuthenticatedAccountId()); | 405 context_->GetDriveService()->Initialize( |
| 406 signin_manager_->GetAuthenticatedAccountId()); |
397 PostInitializeTask(); | 407 PostInitializeTask(); |
398 return; | 408 return; |
399 } | 409 } |
400 | 410 |
401 should_check_remote_change_ = true; | 411 should_check_remote_change_ = true; |
402 MaybeScheduleNextTask(); | 412 MaybeScheduleNextTask(); |
403 } | 413 } |
404 | 414 |
405 void SyncEngine::OnRefreshTokenInvalid() { | 415 void SyncEngine::OnRefreshTokenInvalid() { |
406 UpdateServiceState( | 416 UpdateServiceState( |
(...skipping 10 matching lines...) Expand all Loading... |
417 UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE, "Disconnected"); | 427 UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE, "Disconnected"); |
418 } else if (!network_available_ && new_network_availability) { | 428 } else if (!network_available_ && new_network_availability) { |
419 UpdateServiceState(REMOTE_SERVICE_OK, "Connected"); | 429 UpdateServiceState(REMOTE_SERVICE_OK, "Connected"); |
420 should_check_remote_change_ = true; | 430 should_check_remote_change_ = true; |
421 MaybeStartFetchChanges(); | 431 MaybeStartFetchChanges(); |
422 } | 432 } |
423 network_available_ = new_network_availability; | 433 network_available_ = new_network_availability; |
424 } | 434 } |
425 | 435 |
426 drive::DriveServiceInterface* SyncEngine::GetDriveService() { | 436 drive::DriveServiceInterface* SyncEngine::GetDriveService() { |
427 return drive_service_.get(); | 437 return context_->GetDriveService(); |
428 } | 438 } |
429 | 439 |
430 drive::DriveUploaderInterface* SyncEngine::GetDriveUploader() { | 440 drive::DriveUploaderInterface* SyncEngine::GetDriveUploader() { |
431 return drive_uploader_.get(); | 441 return context_->GetDriveUploader(); |
432 } | 442 } |
433 | 443 |
434 MetadataDatabase* SyncEngine::GetMetadataDatabase() { | 444 MetadataDatabase* SyncEngine::GetMetadataDatabase() { |
435 return metadata_database_.get(); | 445 return context_->GetMetadataDatabase(); |
436 } | 446 } |
437 | 447 |
438 RemoteChangeProcessor* SyncEngine::GetRemoteChangeProcessor() { | 448 RemoteChangeProcessor* SyncEngine::GetRemoteChangeProcessor() { |
439 return remote_change_processor_; | 449 return context_->GetRemoteChangeProcessor(); |
440 } | 450 } |
441 | 451 |
442 base::SequencedTaskRunner* SyncEngine::GetBlockingTaskRunner() { | 452 base::SequencedTaskRunner* SyncEngine::GetBlockingTaskRunner() { |
443 return task_runner_.get(); | 453 return context_->GetBlockingTaskRunner(); |
444 } | 454 } |
445 | 455 |
446 SyncEngine::SyncEngine(const base::FilePath& base_dir, | 456 SyncEngine::SyncEngine(const base::FilePath& base_dir, |
447 base::SequencedTaskRunner* task_runner, | 457 base::SequencedTaskRunner* task_runner, |
448 scoped_ptr<drive::DriveServiceInterface> drive_service, | 458 scoped_ptr<drive::DriveServiceInterface> drive_service, |
449 scoped_ptr<drive::DriveUploaderInterface> drive_uploader, | 459 scoped_ptr<drive::DriveUploaderInterface> drive_uploader, |
450 drive::DriveNotificationManager* notification_manager, | 460 drive::DriveNotificationManager* notification_manager, |
451 ExtensionServiceInterface* extension_service, | 461 ExtensionServiceInterface* extension_service, |
452 SigninManagerBase* signin_manager, | 462 SigninManagerBase* signin_manager, |
453 leveldb::Env* env_override) | 463 leveldb::Env* env_override) |
454 : base_dir_(base_dir), | 464 : base_dir_(base_dir), |
455 task_runner_(task_runner), | |
456 env_override_(env_override), | 465 env_override_(env_override), |
457 drive_service_(drive_service.Pass()), | |
458 drive_uploader_(drive_uploader.Pass()), | |
459 notification_manager_(notification_manager), | 466 notification_manager_(notification_manager), |
460 extension_service_(extension_service), | 467 extension_service_(extension_service), |
461 signin_manager_(signin_manager), | 468 signin_manager_(signin_manager), |
462 remote_change_processor_(NULL), | |
463 service_state_(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE), | 469 service_state_(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE), |
464 should_check_conflict_(true), | 470 should_check_conflict_(true), |
465 should_check_remote_change_(true), | 471 should_check_remote_change_(true), |
466 listing_remote_changes_(false), | 472 listing_remote_changes_(false), |
467 sync_enabled_(false), | 473 sync_enabled_(false), |
468 default_conflict_resolution_policy_( | 474 default_conflict_resolution_policy_( |
469 CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN), | 475 CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN), |
470 network_available_(false), | 476 network_available_(false), |
471 weak_ptr_factory_(this) {} | 477 context_(new SyncEngineContext(drive_service.Pass(), |
| 478 drive_uploader.Pass(), |
| 479 task_runner)), |
| 480 weak_ptr_factory_(this) { |
| 481 } |
472 | 482 |
473 void SyncEngine::DoDisableApp(const std::string& app_id, | 483 void SyncEngine::DoDisableApp(const std::string& app_id, |
474 const SyncStatusCallback& callback) { | 484 const SyncStatusCallback& callback) { |
475 if (metadata_database_) | 485 if (context_->GetMetadataDatabase()) |
476 metadata_database_->DisableApp(app_id, callback); | 486 context_->GetMetadataDatabase()->DisableApp(app_id, callback); |
477 else | 487 else |
478 callback.Run(SYNC_STATUS_OK); | 488 callback.Run(SYNC_STATUS_OK); |
479 } | 489 } |
480 | 490 |
481 void SyncEngine::DoEnableApp(const std::string& app_id, | 491 void SyncEngine::DoEnableApp(const std::string& app_id, |
482 const SyncStatusCallback& callback) { | 492 const SyncStatusCallback& callback) { |
483 if (metadata_database_) | 493 if (context_->GetMetadataDatabase()) |
484 metadata_database_->EnableApp(app_id, callback); | 494 context_->GetMetadataDatabase()->EnableApp(app_id, callback); |
485 else | 495 else |
486 callback.Run(SYNC_STATUS_OK); | 496 callback.Run(SYNC_STATUS_OK); |
487 } | 497 } |
488 | 498 |
489 void SyncEngine::PostInitializeTask() { | 499 void SyncEngine::PostInitializeTask() { |
490 DCHECK(!metadata_database_); | 500 DCHECK(!context_->GetMetadataDatabase()); |
491 | 501 |
492 // This initializer task may not run if metadata_database_ is already | 502 // This initializer task may not run if MetadataDatabase in context_ is |
493 // initialized when it runs. | 503 // already initialized when it runs. |
494 SyncEngineInitializer* initializer = | 504 SyncEngineInitializer* initializer = |
495 new SyncEngineInitializer(this, | 505 new SyncEngineInitializer(context_.get(), |
496 task_runner_.get(), | 506 context_->GetBlockingTaskRunner(), |
497 drive_service_.get(), | 507 context_->GetDriveService(), |
498 base_dir_.Append(kDatabaseName), | 508 base_dir_.Append(kDatabaseName), |
499 env_override_); | 509 env_override_); |
500 task_manager_->ScheduleSyncTask( | 510 task_manager_->ScheduleSyncTask( |
501 FROM_HERE, | 511 FROM_HERE, |
502 scoped_ptr<SyncTask>(initializer), | 512 scoped_ptr<SyncTask>(initializer), |
503 SyncTaskManager::PRIORITY_HIGH, | 513 SyncTaskManager::PRIORITY_HIGH, |
504 base::Bind(&SyncEngine::DidInitialize, weak_ptr_factory_.GetWeakPtr(), | 514 base::Bind(&SyncEngine::DidInitialize, weak_ptr_factory_.GetWeakPtr(), |
505 initializer)); | 515 initializer)); |
506 } | 516 } |
507 | 517 |
508 void SyncEngine::DidInitialize(SyncEngineInitializer* initializer, | 518 void SyncEngine::DidInitialize(SyncEngineInitializer* initializer, |
509 SyncStatusCode status) { | 519 SyncStatusCode status) { |
510 if (status != SYNC_STATUS_OK) { | 520 if (status != SYNC_STATUS_OK) { |
511 if (drive_service_->HasRefreshToken()) { | 521 if (context_->GetDriveService()->HasRefreshToken()) { |
512 UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE, | 522 UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE, |
513 "Could not initialize remote service"); | 523 "Could not initialize remote service"); |
514 } else { | 524 } else { |
515 UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED, | 525 UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED, |
516 "Authentication required."); | 526 "Authentication required."); |
517 } | 527 } |
518 return; | 528 return; |
519 } | 529 } |
520 | 530 |
521 scoped_ptr<MetadataDatabase> metadata_database = | 531 scoped_ptr<MetadataDatabase> metadata_database = |
522 initializer->PassMetadataDatabase(); | 532 initializer->PassMetadataDatabase(); |
523 if (metadata_database) | 533 if (metadata_database) |
524 metadata_database_ = metadata_database.Pass(); | 534 context_->SetMetadataDatabase(metadata_database.Pass()); |
525 | 535 |
526 DCHECK(metadata_database_); | |
527 UpdateRegisteredApps(); | 536 UpdateRegisteredApps(); |
528 } | 537 } |
529 | 538 |
530 void SyncEngine::DidProcessRemoteChange(RemoteToLocalSyncer* syncer, | 539 void SyncEngine::DidProcessRemoteChange(RemoteToLocalSyncer* syncer, |
531 const SyncFileCallback& callback, | 540 const SyncFileCallback& callback, |
532 SyncStatusCode status) { | 541 SyncStatusCode status) { |
533 if (syncer->is_sync_root_deletion()) { | 542 if (syncer->is_sync_root_deletion()) { |
534 MetadataDatabase::ClearDatabase(metadata_database_.Pass()); | 543 MetadataDatabase::ClearDatabase(context_->PassMetadataDatabase()); |
535 PostInitializeTask(); | 544 PostInitializeTask(); |
536 callback.Run(status, syncer->url()); | 545 callback.Run(status, syncer->url()); |
537 return; | 546 return; |
538 } | 547 } |
539 | 548 |
540 if (status == SYNC_STATUS_OK) { | 549 if (status == SYNC_STATUS_OK) { |
541 if (syncer->sync_action() != SYNC_ACTION_NONE && | 550 if (syncer->sync_action() != SYNC_ACTION_NONE && |
542 syncer->url().is_valid()) { | 551 syncer->url().is_valid()) { |
543 FOR_EACH_OBSERVER(FileStatusObserver, | 552 FOR_EACH_OBSERVER(FileStatusObserver, |
544 file_status_observers_, | 553 file_status_observers_, |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
579 | 588 |
580 if (status == SYNC_STATUS_UNKNOWN_ORIGIN && syncer->url().is_valid()) { | 589 if (status == SYNC_STATUS_UNKNOWN_ORIGIN && syncer->url().is_valid()) { |
581 RegisterOrigin(syncer->url().origin(), | 590 RegisterOrigin(syncer->url().origin(), |
582 base::Bind(&EmptyStatusCallback)); | 591 base::Bind(&EmptyStatusCallback)); |
583 } | 592 } |
584 | 593 |
585 if (syncer->needs_remote_change_listing() && | 594 if (syncer->needs_remote_change_listing() && |
586 !listing_remote_changes_) { | 595 !listing_remote_changes_) { |
587 task_manager_->ScheduleSyncTask( | 596 task_manager_->ScheduleSyncTask( |
588 FROM_HERE, | 597 FROM_HERE, |
589 scoped_ptr<SyncTask>(new ListChangesTask(this)), | 598 scoped_ptr<SyncTask>(new ListChangesTask(context_.get())), |
590 SyncTaskManager::PRIORITY_HIGH, | 599 SyncTaskManager::PRIORITY_HIGH, |
591 base::Bind(&SyncEngine::DidFetchChanges, | 600 base::Bind(&SyncEngine::DidFetchChanges, |
592 weak_ptr_factory_.GetWeakPtr())); | 601 weak_ptr_factory_.GetWeakPtr())); |
593 should_check_remote_change_ = false; | 602 should_check_remote_change_ = false; |
594 listing_remote_changes_ = true; | 603 listing_remote_changes_ = true; |
595 time_to_check_changes_ = | 604 time_to_check_changes_ = |
596 base::TimeTicks::Now() + | 605 base::TimeTicks::Now() + |
597 base::TimeDelta::FromSeconds(kListChangesRetryDelaySeconds); | 606 base::TimeDelta::FromSeconds(kListChangesRetryDelaySeconds); |
598 } | 607 } |
599 | 608 |
600 if (status != SYNC_STATUS_OK && | 609 if (status != SYNC_STATUS_OK && |
601 status != SYNC_STATUS_NO_CHANGE_TO_SYNC) { | 610 status != SYNC_STATUS_NO_CHANGE_TO_SYNC) { |
602 callback.Run(status); | 611 callback.Run(status); |
603 return; | 612 return; |
604 } | 613 } |
605 | 614 |
606 if (status == SYNC_STATUS_OK) | 615 if (status == SYNC_STATUS_OK) |
607 should_check_conflict_ = true; | 616 should_check_conflict_ = true; |
608 | 617 |
609 callback.Run(status); | 618 callback.Run(status); |
610 } | 619 } |
611 | 620 |
612 void SyncEngine::MaybeStartFetchChanges() { | 621 void SyncEngine::MaybeStartFetchChanges() { |
613 if (GetCurrentState() == REMOTE_SERVICE_DISABLED) | 622 if (GetCurrentState() == REMOTE_SERVICE_DISABLED) |
614 return; | 623 return; |
615 | 624 |
616 if (!metadata_database_) | 625 if (!context_->GetMetadataDatabase()) |
617 return; | 626 return; |
618 | 627 |
619 if (listing_remote_changes_) | 628 if (listing_remote_changes_) |
620 return; | 629 return; |
621 | 630 |
622 base::TimeTicks now = base::TimeTicks::Now(); | 631 base::TimeTicks now = base::TimeTicks::Now(); |
623 if (!should_check_remote_change_ && now < time_to_check_changes_) { | 632 if (!should_check_remote_change_ && now < time_to_check_changes_) { |
624 if (!metadata_database_->HasDirtyTracker() && should_check_conflict_) { | 633 if (!context_->GetMetadataDatabase()->HasDirtyTracker() && |
| 634 should_check_conflict_) { |
625 should_check_conflict_ = false; | 635 should_check_conflict_ = false; |
626 task_manager_->ScheduleSyncTaskIfIdle( | 636 task_manager_->ScheduleSyncTaskIfIdle( |
627 FROM_HERE, | 637 FROM_HERE, |
628 scoped_ptr<SyncTask>(new ConflictResolver(this)), | 638 scoped_ptr<SyncTask>(new ConflictResolver(context_.get())), |
629 base::Bind(&SyncEngine::DidResolveConflict, | 639 base::Bind(&SyncEngine::DidResolveConflict, |
630 weak_ptr_factory_.GetWeakPtr())); | 640 weak_ptr_factory_.GetWeakPtr())); |
631 } | 641 } |
632 return; | 642 return; |
633 } | 643 } |
634 | 644 |
635 if (task_manager_->ScheduleSyncTaskIfIdle( | 645 if (task_manager_->ScheduleSyncTaskIfIdle( |
636 FROM_HERE, | 646 FROM_HERE, |
637 scoped_ptr<SyncTask>(new ListChangesTask(this)), | 647 scoped_ptr<SyncTask>(new ListChangesTask(context_.get())), |
638 base::Bind(&SyncEngine::DidFetchChanges, | 648 base::Bind(&SyncEngine::DidFetchChanges, |
639 weak_ptr_factory_.GetWeakPtr()))) { | 649 weak_ptr_factory_.GetWeakPtr()))) { |
640 should_check_remote_change_ = false; | 650 should_check_remote_change_ = false; |
641 listing_remote_changes_ = true; | 651 listing_remote_changes_ = true; |
642 time_to_check_changes_ = | 652 time_to_check_changes_ = |
643 now + base::TimeDelta::FromSeconds(kListChangesRetryDelaySeconds); | 653 now + base::TimeDelta::FromSeconds(kListChangesRetryDelaySeconds); |
644 } | 654 } |
645 } | 655 } |
646 | 656 |
647 void SyncEngine::DidResolveConflict(SyncStatusCode status) { | 657 void SyncEngine::DidResolveConflict(SyncStatusCode status) { |
(...skipping 26 matching lines...) Expand all Loading... |
674 case SYNC_STATUS_ACCESS_FORBIDDEN: | 684 case SYNC_STATUS_ACCESS_FORBIDDEN: |
675 UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED, | 685 UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED, |
676 "Access forbidden"); | 686 "Access forbidden"); |
677 break; | 687 break; |
678 | 688 |
679 // Errors which could make the service temporarily unavailable. | 689 // Errors which could make the service temporarily unavailable. |
680 case SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE: | 690 case SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE: |
681 case SYNC_STATUS_NETWORK_ERROR: | 691 case SYNC_STATUS_NETWORK_ERROR: |
682 case SYNC_STATUS_ABORT: | 692 case SYNC_STATUS_ABORT: |
683 case SYNC_STATUS_FAILED: | 693 case SYNC_STATUS_FAILED: |
684 if (drive_service_->HasRefreshToken()) { | 694 if (context_->GetDriveService()->HasRefreshToken()) { |
685 UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE, | 695 UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE, |
686 "Network or temporary service error."); | 696 "Network or temporary service error."); |
687 } else { | 697 } else { |
688 UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED, | 698 UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED, |
689 "Authentication required"); | 699 "Authentication required"); |
690 } | 700 } |
691 break; | 701 break; |
692 | 702 |
693 // Errors which would require manual user intervention to resolve. | 703 // Errors which would require manual user intervention to resolve. |
694 case SYNC_DATABASE_ERROR_CORRUPTION: | 704 case SYNC_DATABASE_ERROR_CORRUPTION: |
(...skipping 22 matching lines...) Expand all Loading... |
717 old_state, GetCurrentState(), description.c_str()); | 727 old_state, GetCurrentState(), description.c_str()); |
718 FOR_EACH_OBSERVER( | 728 FOR_EACH_OBSERVER( |
719 Observer, service_observers_, | 729 Observer, service_observers_, |
720 OnRemoteServiceStateUpdated(GetCurrentState(), description)); | 730 OnRemoteServiceStateUpdated(GetCurrentState(), description)); |
721 } | 731 } |
722 | 732 |
723 void SyncEngine::UpdateRegisteredApps() { | 733 void SyncEngine::UpdateRegisteredApps() { |
724 if (!extension_service_) | 734 if (!extension_service_) |
725 return; | 735 return; |
726 | 736 |
727 DCHECK(metadata_database_); | 737 DCHECK(context_->GetMetadataDatabase()); |
728 std::vector<std::string> app_ids; | 738 std::vector<std::string> app_ids; |
729 metadata_database_->GetRegisteredAppIDs(&app_ids); | 739 context_->GetMetadataDatabase()->GetRegisteredAppIDs(&app_ids); |
730 | 740 |
731 // Update the status of every origin using status from ExtensionService. | 741 // Update the status of every origin using status from ExtensionService. |
732 for (std::vector<std::string>::const_iterator itr = app_ids.begin(); | 742 for (std::vector<std::string>::const_iterator itr = app_ids.begin(); |
733 itr != app_ids.end(); ++itr) { | 743 itr != app_ids.end(); ++itr) { |
734 const std::string& app_id = *itr; | 744 const std::string& app_id = *itr; |
735 GURL origin = | 745 GURL origin = |
736 extensions::Extension::GetBaseURLFromExtensionId(app_id); | 746 extensions::Extension::GetBaseURLFromExtensionId(app_id); |
737 if (!extension_service_->GetInstalledExtension(app_id)) { | 747 if (!extension_service_->GetInstalledExtension(app_id)) { |
738 // Extension has been uninstalled. | 748 // Extension has been uninstalled. |
739 // (At this stage we can't know if it was unpacked extension or not, | 749 // (At this stage we can't know if it was unpacked extension or not, |
740 // so just purge the remote folder.) | 750 // so just purge the remote folder.) |
741 UninstallOrigin(origin, | 751 UninstallOrigin(origin, |
742 RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE, | 752 RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE, |
743 base::Bind(&EmptyStatusCallback)); | 753 base::Bind(&EmptyStatusCallback)); |
744 continue; | 754 continue; |
745 } | 755 } |
746 FileTracker tracker; | 756 FileTracker tracker; |
747 if (!metadata_database_->FindAppRootTracker(app_id, &tracker)) { | 757 if (!context_->GetMetadataDatabase()->FindAppRootTracker(app_id, |
| 758 &tracker)) { |
748 // App will register itself on first run. | 759 // App will register itself on first run. |
749 continue; | 760 continue; |
750 } | 761 } |
751 bool is_app_enabled = extension_service_->IsExtensionEnabled(app_id); | 762 bool is_app_enabled = extension_service_->IsExtensionEnabled(app_id); |
752 bool is_app_root_tracker_enabled = | 763 bool is_app_root_tracker_enabled = |
753 tracker.tracker_kind() == TRACKER_KIND_APP_ROOT; | 764 tracker.tracker_kind() == TRACKER_KIND_APP_ROOT; |
754 if (is_app_enabled && !is_app_root_tracker_enabled) | 765 if (is_app_enabled && !is_app_root_tracker_enabled) |
755 EnableOrigin(origin, base::Bind(&EmptyStatusCallback)); | 766 EnableOrigin(origin, base::Bind(&EmptyStatusCallback)); |
756 else if (!is_app_enabled && is_app_root_tracker_enabled) | 767 else if (!is_app_enabled && is_app_root_tracker_enabled) |
757 DisableOrigin(origin, base::Bind(&EmptyStatusCallback)); | 768 DisableOrigin(origin, base::Bind(&EmptyStatusCallback)); |
758 } | 769 } |
759 } | 770 } |
760 | 771 |
761 } // namespace drive_backend | 772 } // namespace drive_backend |
762 } // namespace sync_file_system | 773 } // namespace sync_file_system |
OLD | NEW |