Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / sync_file_system / drive_backend / sync_engine_initializer.cc
blob1bf319519e653e6cde3fb3ae8e6a318f08f5914e
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.
5 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/logging.h"
10 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
11 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
12 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
13 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
14 #include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
15 #include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h"
16 #include "chrome/browser/sync_file_system/logger.h"
17 #include "components/drive/service/drive_api_service.h"
18 #include "google_apis/drive/drive_api_parser.h"
20 namespace sync_file_system {
21 namespace drive_backend {
23 namespace {
25 ////////////////////////////////////////////////////////////////////////////////
26 // Functions below are for wrapping the access to legacy GData WAPI classes.
28 bool HasNoParents(const google_apis::FileResource& entry) {
29 return entry.parents().empty();
32 bool HasFolderAsParent(const google_apis::FileResource& entry,
33 const std::string& parent_id) {
34 for (size_t i = 0; i < entry.parents().size(); ++i) {
35 if (entry.parents()[i].file_id() == parent_id)
36 return true;
38 return false;
41 bool LessOnCreationTime(const google_apis::FileResource& left,
42 const google_apis::FileResource& right) {
43 return left.created_date() < right.created_date();
46 // Functions above are for wrapping the access to legacy GData WAPI classes.
47 ////////////////////////////////////////////////////////////////////////////////
49 } // namespace
51 SyncEngineInitializer::SyncEngineInitializer(
52 SyncEngineContext* sync_context,
53 const base::FilePath& database_path,
54 leveldb::Env* env_override)
55 : sync_context_(sync_context),
56 env_override_(env_override),
57 database_path_(database_path),
58 find_sync_root_retry_count_(0),
59 largest_change_id_(0),
60 weak_ptr_factory_(this) {
61 DCHECK(sync_context);
64 SyncEngineInitializer::~SyncEngineInitializer() {
65 if (!cancel_callback_.is_null())
66 cancel_callback_.Run();
69 void SyncEngineInitializer::RunPreflight(scoped_ptr<SyncTaskToken> token) {
70 util::Log(logging::LOG_VERBOSE, FROM_HERE, "[Initialize] Start.");
71 DCHECK(sync_context_);
72 DCHECK(sync_context_->GetDriveService());
74 // The metadata seems to have been already initialized. Just return with OK.
75 if (sync_context_->GetMetadataDatabase()) {
76 util::Log(logging::LOG_VERBOSE, FROM_HERE,
77 "[Initialize] Already initialized.");
78 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK);
79 return;
82 SyncStatusCode status = SYNC_STATUS_FAILED;
83 scoped_ptr<MetadataDatabase> metadata_database =
84 MetadataDatabase::Create(database_path_, env_override_, &status);
86 if (status != SYNC_STATUS_OK) {
87 util::Log(logging::LOG_VERBOSE, FROM_HERE,
88 "[Initialize] Failed to initialize MetadataDatabase.");
89 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
90 return;
93 DCHECK(metadata_database);
94 metadata_database_ = metadata_database.Pass();
95 if (metadata_database_->HasSyncRoot()) {
96 util::Log(logging::LOG_VERBOSE, FROM_HERE,
97 "[Initialize] Found local cache of sync-root.");
98 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK);
99 return;
102 GetAboutResource(token.Pass());
105 scoped_ptr<MetadataDatabase> SyncEngineInitializer::PassMetadataDatabase() {
106 return metadata_database_.Pass();
109 void SyncEngineInitializer::GetAboutResource(
110 scoped_ptr<SyncTaskToken> token) {
111 set_used_network(true);
112 sync_context_->GetDriveService()->GetAboutResource(
113 base::Bind(&SyncEngineInitializer::DidGetAboutResource,
114 weak_ptr_factory_.GetWeakPtr(), base::Passed(&token)));
117 void SyncEngineInitializer::DidGetAboutResource(
118 scoped_ptr<SyncTaskToken> token,
119 google_apis::DriveApiErrorCode error,
120 scoped_ptr<google_apis::AboutResource> about_resource) {
121 cancel_callback_.Reset();
123 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error);
124 if (status != SYNC_STATUS_OK) {
125 util::Log(logging::LOG_VERBOSE, FROM_HERE,
126 "[Initialize] Failed to get AboutResource.");
127 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
128 return;
131 DCHECK(about_resource);
132 root_folder_id_ = about_resource->root_folder_id();
133 largest_change_id_ = about_resource->largest_change_id();
135 DCHECK(!root_folder_id_.empty());
136 FindSyncRoot(token.Pass());
139 void SyncEngineInitializer::FindSyncRoot(scoped_ptr<SyncTaskToken> token) {
140 if (find_sync_root_retry_count_++ >= kMaxRetry) {
141 util::Log(logging::LOG_VERBOSE, FROM_HERE,
142 "[Initialize] Reached max retry count.");
143 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED);
144 return;
147 set_used_network(true);
148 cancel_callback_ = sync_context_->GetDriveService()->SearchByTitle(
149 kSyncRootFolderTitle,
150 std::string(), // parent_folder_id
151 base::Bind(&SyncEngineInitializer::DidFindSyncRoot,
152 weak_ptr_factory_.GetWeakPtr(),
153 base::Passed(&token)));
156 void SyncEngineInitializer::DidFindSyncRoot(
157 scoped_ptr<SyncTaskToken> token,
158 google_apis::DriveApiErrorCode error,
159 scoped_ptr<google_apis::FileList> file_list) {
160 cancel_callback_.Reset();
162 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error);
163 if (status != SYNC_STATUS_OK) {
164 util::Log(logging::LOG_VERBOSE, FROM_HERE,
165 "[Initialize] Failed to find sync root.");
166 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
167 return;
170 if (!file_list) {
171 NOTREACHED();
172 util::Log(logging::LOG_VERBOSE, FROM_HERE,
173 "[Initialize] Got invalid resource list.");
174 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED);
175 return;
178 ScopedVector<google_apis::FileResource>* items = file_list->mutable_items();
179 for (ScopedVector<google_apis::FileResource>::iterator itr = items->begin();
180 itr != items->end(); ++itr) {
181 google_apis::FileResource* entry = *itr;
183 // Ignore deleted folder.
184 if (entry->labels().is_trashed())
185 continue;
187 // Pick an orphaned folder or a direct child of the root folder and
188 // ignore others.
189 DCHECK(!root_folder_id_.empty());
190 if (!HasNoParents(*entry) && !HasFolderAsParent(*entry, root_folder_id_))
191 continue;
193 if (!sync_root_folder_ || LessOnCreationTime(*entry, *sync_root_folder_)) {
194 sync_root_folder_.reset(entry);
195 *itr = nullptr;
199 set_used_network(true);
200 // If there are more results, retrieve them.
201 if (!file_list->next_link().is_empty()) {
202 cancel_callback_ = sync_context_->GetDriveService()->GetRemainingFileList(
203 file_list->next_link(),
204 base::Bind(&SyncEngineInitializer::DidFindSyncRoot,
205 weak_ptr_factory_.GetWeakPtr(),
206 base::Passed(&token)));
207 return;
210 if (!sync_root_folder_) {
211 CreateSyncRoot(token.Pass());
212 return;
215 if (!HasNoParents(*sync_root_folder_)) {
216 DetachSyncRoot(token.Pass());
217 return;
220 ListAppRootFolders(token.Pass());
223 void SyncEngineInitializer::CreateSyncRoot(scoped_ptr<SyncTaskToken> token) {
224 DCHECK(!sync_root_folder_);
225 set_used_network(true);
226 cancel_callback_ = sync_context_->GetDriveService()->AddNewDirectory(
227 root_folder_id_, kSyncRootFolderTitle, drive::AddNewDirectoryOptions(),
228 base::Bind(&SyncEngineInitializer::DidCreateSyncRoot,
229 weak_ptr_factory_.GetWeakPtr(), base::Passed(&token)));
232 void SyncEngineInitializer::DidCreateSyncRoot(
233 scoped_ptr<SyncTaskToken> token,
234 google_apis::DriveApiErrorCode error,
235 scoped_ptr<google_apis::FileResource> entry) {
236 DCHECK(!sync_root_folder_);
237 cancel_callback_.Reset();
239 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error);
240 if (status != SYNC_STATUS_OK) {
241 util::Log(logging::LOG_VERBOSE, FROM_HERE,
242 "[Initialize] Failed to create sync root.");
243 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
244 return;
247 FindSyncRoot(token.Pass());
250 void SyncEngineInitializer::DetachSyncRoot(scoped_ptr<SyncTaskToken> token) {
251 DCHECK(sync_root_folder_);
252 set_used_network(true);
253 cancel_callback_ =
254 sync_context_->GetDriveService()->RemoveResourceFromDirectory(
255 root_folder_id_,
256 sync_root_folder_->file_id(),
257 base::Bind(&SyncEngineInitializer::DidDetachSyncRoot,
258 weak_ptr_factory_.GetWeakPtr(),
259 base::Passed(&token)));
262 void SyncEngineInitializer::DidDetachSyncRoot(
263 scoped_ptr<SyncTaskToken> token,
264 google_apis::DriveApiErrorCode error) {
265 cancel_callback_.Reset();
267 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error);
268 if (status != SYNC_STATUS_OK) {
269 util::Log(logging::LOG_VERBOSE, FROM_HERE,
270 "[Initialize] Failed to detach sync root.");
271 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
272 return;
275 ListAppRootFolders(token.Pass());
278 void SyncEngineInitializer::ListAppRootFolders(
279 scoped_ptr<SyncTaskToken> token) {
280 DCHECK(sync_root_folder_);
281 set_used_network(true);
282 cancel_callback_ =
283 sync_context_->GetDriveService()->GetFileListInDirectory(
284 sync_root_folder_->file_id(),
285 base::Bind(&SyncEngineInitializer::DidListAppRootFolders,
286 weak_ptr_factory_.GetWeakPtr(),
287 base::Passed(&token)));
290 void SyncEngineInitializer::DidListAppRootFolders(
291 scoped_ptr<SyncTaskToken> token,
292 google_apis::DriveApiErrorCode error,
293 scoped_ptr<google_apis::FileList> file_list) {
294 cancel_callback_.Reset();
296 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error);
297 if (status != SYNC_STATUS_OK) {
298 util::Log(logging::LOG_VERBOSE, FROM_HERE,
299 "[Initialize] Failed to get initial app-root folders.");
300 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
301 return;
304 if (!file_list) {
305 NOTREACHED();
306 util::Log(logging::LOG_VERBOSE, FROM_HERE,
307 "[Initialize] Got invalid initial app-root list.");
308 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED);
309 return;
312 ScopedVector<google_apis::FileResource>* new_entries =
313 file_list->mutable_items();
314 app_root_folders_.insert(app_root_folders_.end(),
315 new_entries->begin(), new_entries->end());
316 new_entries->weak_clear();
318 set_used_network(true);
319 if (!file_list->next_link().is_empty()) {
320 cancel_callback_ =
321 sync_context_->GetDriveService()->GetRemainingFileList(
322 file_list->next_link(),
323 base::Bind(&SyncEngineInitializer::DidListAppRootFolders,
324 weak_ptr_factory_.GetWeakPtr(), base::Passed(&token)));
325 return;
328 PopulateDatabase(token.Pass());
331 void SyncEngineInitializer::PopulateDatabase(
332 scoped_ptr<SyncTaskToken> token) {
333 DCHECK(sync_root_folder_);
334 SyncStatusCode status = metadata_database_->PopulateInitialData(
335 largest_change_id_, *sync_root_folder_, app_root_folders_);
336 if (status != SYNC_STATUS_OK) {
337 util::Log(logging::LOG_VERBOSE, FROM_HERE,
338 "[Initialize] Failed to populate initial data"
339 " to MetadataDatabase.");
340 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
341 return;
344 util::Log(logging::LOG_VERBOSE, FROM_HERE,
345 "[Initialize] Completed successfully.");
346 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK);
349 } // namespace drive_backend
350 } // namespace sync_file_system