Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(225)

Side by Side Diff: chrome/browser/win/jumplist.cc

Issue 2752063002: Remove JumpListIconsOld directory and set upper limit for delete attempts (Closed)
Patch Set: Add jumplist_util_file* and unit tests, plus address other comments. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 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/win/jumplist.h" 5 #include "chrome/browser/win/jumplist.h"
6 6
7 #include <Shlwapi.h> 7 #include <Shlwapi.h>
8 #include <windows.h>
9 8
10 #include "base/bind.h" 9 #include "base/bind.h"
11 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
12 #include "base/callback_helpers.h"
13 #include "base/command_line.h" 11 #include "base/command_line.h"
14 #include "base/files/file_util.h" 12 #include "base/files/file_util.h"
15 #include "base/macros.h" 13 #include "base/macros.h"
16 #include "base/metrics/histogram_macros.h" 14 #include "base/metrics/histogram_macros.h"
17 #include "base/path_service.h" 15 #include "base/path_service.h"
18 #include "base/strings/string_util.h" 16 #include "base/strings/string_util.h"
19 #include "base/strings/utf_string_conversions.h" 17 #include "base/strings/utf_string_conversions.h"
20 #include "base/threading/thread.h" 18 #include "base/threading/thread.h"
21 #include "base/threading/thread_restrictions.h" 19 #include "base/threading/thread_restrictions.h"
22 #include "base/trace_event/trace_event.h" 20 #include "base/trace_event/trace_event.h"
23 #include "chrome/browser/chrome_notification_types.h" 21 #include "chrome/browser/chrome_notification_types.h"
24 #include "chrome/browser/favicon/favicon_service_factory.h" 22 #include "chrome/browser/favicon/favicon_service_factory.h"
25 #include "chrome/browser/history/top_sites_factory.h" 23 #include "chrome/browser/history/top_sites_factory.h"
26 #include "chrome/browser/metrics/jumplist_metrics_win.h" 24 #include "chrome/browser/metrics/jumplist_metrics_win.h"
27 #include "chrome/browser/profiles/profile.h" 25 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/sessions/tab_restore_service_factory.h" 26 #include "chrome/browser/sessions/tab_restore_service_factory.h"
29 #include "chrome/browser/shell_integration_win.h" 27 #include "chrome/browser/shell_integration_win.h"
28 #include "chrome/browser/win/jumplist_file_util.h"
30 #include "chrome/common/chrome_constants.h" 29 #include "chrome/common/chrome_constants.h"
31 #include "chrome/common/chrome_switches.h" 30 #include "chrome/common/chrome_switches.h"
32 #include "chrome/common/pref_names.h" 31 #include "chrome/common/pref_names.h"
33 #include "chrome/common/url_constants.h" 32 #include "chrome/common/url_constants.h"
34 #include "chrome/grit/generated_resources.h" 33 #include "chrome/grit/generated_resources.h"
35 #include "chrome/installer/util/browser_distribution.h" 34 #include "chrome/installer/util/browser_distribution.h"
36 #include "components/favicon/core/favicon_service.h" 35 #include "components/favicon/core/favicon_service.h"
37 #include "components/favicon_base/favicon_types.h" 36 #include "components/favicon_base/favicon_types.h"
38 #include "components/history/core/browser/history_service.h" 37 #include "components/history/core/browser/history_service.h"
39 #include "components/history/core/browser/page_usage_data.h" 38 #include "components/history/core/browser/page_usage_data.h"
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) 221 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability))
223 return false; 222 return false;
224 223
225 // Commit this transaction and send the updated JumpList to Windows. 224 // Commit this transaction and send the updated JumpList to Windows.
226 if (!jumplist_updater.CommitUpdate()) 225 if (!jumplist_updater.CommitUpdate())
227 return false; 226 return false;
228 227
229 return true; 228 return true;
230 } 229 }
231 230
232 // Renames the directory |from_dir| to |to_path|. This method fails if any
233 // process has a handle open in |from_dir| or if |to_path| exists. Base::Move()
234 // tries to rename a file and if this fails, it tries copy-n-delete; This
235 // RenameDirectory method only does the rename part.
236 bool RenameDirectory(const base::FilePath& from_path,
237 const base::FilePath& to_path) {
238 base::ThreadRestrictions::AssertIOAllowed();
239 if (from_path.ReferencesParent() || to_path.ReferencesParent())
240 return false;
241 if (from_path.value().length() >= MAX_PATH ||
242 to_path.value().length() >= MAX_PATH) {
243 return false;
244 }
245 return MoveFileEx(from_path.value().c_str(), to_path.value().c_str(), 0) != 0;
246 }
247
248 // Updates the jumplist, once all the data has been fetched. 231 // Updates the jumplist, once all the data has been fetched.
249 void RunUpdateOnFileThread( 232 void RunUpdateOnFileThread(
250 IncognitoModePrefs::Availability incognito_availability, 233 IncognitoModePrefs::Availability incognito_availability,
251 const std::wstring& app_id, 234 const std::wstring& app_id,
252 const base::FilePath& icon_dir, 235 const base::FilePath& icon_dir,
253 base::RefCountedData<JumpListData>* ref_counted_data) { 236 base::RefCountedData<JumpListData>* ref_counted_data,
237 const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner) {
254 JumpListData* data = &ref_counted_data->data; 238 JumpListData* data = &ref_counted_data->data;
255 ShellLinkItemList local_most_visited_pages; 239 ShellLinkItemList local_most_visited_pages;
256 ShellLinkItemList local_recently_closed_pages; 240 ShellLinkItemList local_recently_closed_pages;
257 241
258 { 242 {
259 base::AutoLock auto_lock(data->list_lock_); 243 base::AutoLock auto_lock(data->list_lock_);
260 // Make sure we are not out of date: if icon_urls_ is not empty, then 244 // Make sure we are not out of date: if icon_urls_ is not empty, then
261 // another notification has been received since we processed this one 245 // another notification has been received since we processed this one
262 if (!data->icon_urls_.empty()) 246 if (!data->icon_urls_.empty())
263 return; 247 return;
264 248
265 // Make local copies of lists so we can release the lock. 249 // Make local copies of lists so we can release the lock.
266 local_most_visited_pages = data->most_visited_pages_; 250 local_most_visited_pages = data->most_visited_pages_;
267 local_recently_closed_pages = data->recently_closed_pages_; 251 local_recently_closed_pages = data->recently_closed_pages_;
268 } 252 }
269 253
270 // Delete the directory which contains old icon files, rename the current 254 // This variable records the delete status of JumpListIcons directory.
271 // icon directory, and create a new directory which contains new JumpList 255 FolderDeleteResult folder_delete_status = SUCCEED;
272 // icon files.
273 base::FilePath icon_dir_old = icon_dir.DirName().Append(
274 icon_dir.BaseName().value() + FILE_PATH_LITERAL("Old"));
275 256
276 enum FolderOperationResult { 257 // Delete the contents in JumpListIcons directory.
277 SUCCESS = 0, 258 DeleteDirectoryContent(icon_dir, true, &folder_delete_status);
278 DELETE_DEST_FAILED = 1 << 0,
279 RENAME_FAILED = 1 << 1,
280 DELETE_SRC_CONTENT_FAILED = 1 << 2,
281 DELETE_SRC_DIR_FAILED = 1 << 3,
282 CREATE_SRC_FAILED = 1 << 4,
283 // This value is beyond the sum of all bit fields above and
284 // should remain last (shifted by one more than the last value)
285 END = 1 << 5
286 };
287 259
288 // This variable records the status of three folder operations. 260 UMA_HISTOGRAM_ENUMERATION("WinJumplist.DeleteStatusJumpListIcons",
289 uint32_t folder_operation_status = FolderOperationResult::SUCCESS; 261 static_cast<int>(folder_delete_status), END);
290 262
291 base::ScopedClosureRunner log_operation_status_when_done(base::Bind( 263 // If JumpListIcons directory is not empty, skip jumplist update and return
292 [](uint32_t* folder_operation_status_ptr) { 264 // early. If the directory doesn't exist which shouldn't though, try to create
293 UMA_HISTOGRAM_ENUMERATION( 265 // a new JumpListIcons directory. If the creation fails, return early.
294 "WinJumplist.DetailedFolderResultsDeleteUpdated", 266 if (base::DirectoryExists(icon_dir)) {
295 *folder_operation_status_ptr, FolderOperationResult::END); 267 if (!::PathIsDirectoryEmpty(icon_dir.value().c_str()))
296 }, 268 return;
297 base::Unretained(&folder_operation_status))); 269 } else if (!base::CreateDirectory(icon_dir)) {
298
299 // If deletion of |icon_dir_old| fails, do not rename |icon_dir| to
300 // |icon_dir_old|, instead, delete |icon_dir| directly to avoid bloating
301 // |icon_dir_old| by moving more things to it.
302 if (!base::DeleteFile(icon_dir_old, true)) {
303 folder_operation_status |= FolderOperationResult::DELETE_DEST_FAILED;
304 // If deletion of any item in |icon_dir| fails, exit early. If deletion of
305 // all the items succeeds while only deletion of the dir fails, it is okay
306 // to proceed. This skips creating the same directory and updating jumplist
307 // icons to avoid bloating the JumplistIcons folder.
308 if (!base::DeleteFile(icon_dir, true)) {
309 if (!::PathIsDirectoryEmpty(icon_dir.value().c_str())) {
310 folder_operation_status |=
311 FolderOperationResult::DELETE_SRC_CONTENT_FAILED;
312 return;
313 }
314 folder_operation_status |= FolderOperationResult::DELETE_SRC_DIR_FAILED;
315 }
316 } else if (!RenameDirectory(icon_dir, icon_dir_old)) {
317 // If RenameDirectory() fails, delete |icon_dir| to avoid file accumulation
318 // in this directory, which can eventually lead the folder to be huge.
319 folder_operation_status |= FolderOperationResult::RENAME_FAILED;
320 // If deletion of any item in |icon_dir| fails, exit early. If deletion of
321 // all the items succeeds while only deletion of the dir fails, it is okay
322 // to proceed. This skips creating the same directory and updating jumplist
323 // icons to avoid bloating the JumplistIcons folder.
324 if (!base::DeleteFile(icon_dir, true)) {
325 if (!::PathIsDirectoryEmpty(icon_dir.value().c_str())) {
326 folder_operation_status |=
327 FolderOperationResult::DELETE_SRC_CONTENT_FAILED;
328 return;
329 }
330 folder_operation_status |= FolderOperationResult::DELETE_SRC_DIR_FAILED;
331 }
332 }
333
334 // If CreateDirectory() fails, exit early.
335 if (!base::CreateDirectory(icon_dir)) {
336 folder_operation_status |= FolderOperationResult::CREATE_SRC_FAILED;
337 return; 270 return;
338 } 271 }
339 272
340 // Create temporary icon files for shortcuts in the "Most Visited" category. 273 // Create temporary icon files for shortcuts in the "Most Visited" category.
341 CreateIconFiles(icon_dir, local_most_visited_pages); 274 CreateIconFiles(icon_dir, local_most_visited_pages);
342 275
343 // Create temporary icon files for shortcuts in the "Recently Closed" 276 // Create temporary icon files for shortcuts in the "Recently Closed"
344 // category. 277 // category.
345 CreateIconFiles(icon_dir, local_recently_closed_pages); 278 CreateIconFiles(icon_dir, local_recently_closed_pages);
346 279
347 // We finished collecting all resources needed for updating an application 280 // We finished collecting all resources needed for updating an application
348 // JumpList. So, create a new JumpList and replace the current JumpList 281 // JumpList. So, create a new JumpList and replace the current JumpList
349 // with it. 282 // with it.
350 UpdateJumpList(app_id.c_str(), local_most_visited_pages, 283 UpdateJumpList(app_id.c_str(), local_most_visited_pages,
351 local_recently_closed_pages, incognito_availability); 284 local_recently_closed_pages, incognito_availability);
285
286 // Post a background task to delete JumpListIconsOld folder if it exists and
287 // log the delete results to UMA.
288 base::FilePath icon_dir_old = icon_dir.DirName().Append(
289 icon_dir.BaseName().value() + FILE_PATH_LITERAL("Old"));
290
291 if (base::DirectoryExists(icon_dir_old)) {
292 sequenced_task_runner->PostTask(
293 FROM_HERE,
294 base::Bind(&DeleteDirectoryAndLogResults, icon_dir_old, true));
295 }
352 } 296 }
353 297
354 } // namespace 298 } // namespace
355 299
356 JumpList::JumpListData::JumpListData() {} 300 JumpList::JumpListData::JumpListData() {}
357 301
358 JumpList::JumpListData::~JumpListData() {} 302 JumpList::JumpListData::~JumpListData() {}
359 303
360 JumpList::JumpList(Profile* profile) 304 JumpList::JumpList(Profile* profile)
361 : RefcountedKeyedService(content::BrowserThread::GetTaskRunnerForThread( 305 : RefcountedKeyedService(content::BrowserThread::GetTaskRunnerForThread(
362 content::BrowserThread::UI)), 306 content::BrowserThread::UI)),
363 profile_(profile), 307 profile_(profile),
364 jumplist_data_(new base::RefCountedData<JumpListData>), 308 jumplist_data_(new base::RefCountedData<JumpListData>),
365 task_id_(base::CancelableTaskTracker::kBadTaskId), 309 task_id_(base::CancelableTaskTracker::kBadTaskId),
310 sequenced_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
311 base::TaskTraits()
312 .WithPriority(base::TaskPriority::BACKGROUND)
313 .WithShutdownBehavior(
314 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)
315 .MayBlock())),
366 weak_ptr_factory_(this) { 316 weak_ptr_factory_(this) {
367 DCHECK(Enabled()); 317 DCHECK(Enabled());
368 // To update JumpList when a tab is added or removed, we add this object to 318 // To update JumpList when a tab is added or removed, we add this object to
369 // the observer list of the TabRestoreService class. 319 // the observer list of the TabRestoreService class.
370 // When we add this object to the observer list, we save the pointer to this 320 // When we add this object to the observer list, we save the pointer to this
371 // TabRestoreService object. This pointer is used when we remove this object 321 // TabRestoreService object. This pointer is used when we remove this object
372 // from the observer list. 322 // from the observer list.
373 sessions::TabRestoreService* tab_restore_service = 323 sessions::TabRestoreService* tab_restore_service =
374 TabRestoreServiceFactory::GetForProfile(profile_); 324 TabRestoreServiceFactory::GetForProfile(profile_);
375 if (!tab_restore_service) 325 if (!tab_restore_service)
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after
654 DCHECK(CalledOnValidThread()); 604 DCHECK(CalledOnValidThread());
655 605
656 TRACE_EVENT0("browser", "JumpList::DeferredRunUpdate"); 606 TRACE_EVENT0("browser", "JumpList::DeferredRunUpdate");
657 // Check if incognito windows (or normal windows) are disabled by policy. 607 // Check if incognito windows (or normal windows) are disabled by policy.
658 IncognitoModePrefs::Availability incognito_availability = 608 IncognitoModePrefs::Availability incognito_availability =
659 profile_ ? IncognitoModePrefs::GetAvailability(profile_->GetPrefs()) 609 profile_ ? IncognitoModePrefs::GetAvailability(profile_->GetPrefs())
660 : IncognitoModePrefs::ENABLED; 610 : IncognitoModePrefs::ENABLED;
661 611
662 BrowserThread::PostTask( 612 BrowserThread::PostTask(
663 BrowserThread::FILE, FROM_HERE, 613 BrowserThread::FILE, FROM_HERE,
664 base::Bind(&RunUpdateOnFileThread, 614 base::Bind(&RunUpdateOnFileThread, incognito_availability, app_id_,
665 incognito_availability, 615 icon_dir_, base::RetainedRef(jumplist_data_),
666 app_id_, 616 sequenced_task_runner_));
667 icon_dir_,
668 base::RetainedRef(jumplist_data_)));
669 } 617 }
670 618
671 void JumpList::TopSitesLoaded(history::TopSites* top_sites) { 619 void JumpList::TopSitesLoaded(history::TopSites* top_sites) {
672 } 620 }
673 621
674 void JumpList::TopSitesChanged(history::TopSites* top_sites, 622 void JumpList::TopSitesChanged(history::TopSites* top_sites,
675 ChangeReason change_reason) { 623 ChangeReason change_reason) {
676 top_sites->GetMostVisitedURLs( 624 top_sites->GetMostVisitedURLs(
677 base::Bind(&JumpList::OnMostVisitedURLsAvailable, 625 base::Bind(&JumpList::OnMostVisitedURLsAvailable,
678 weak_ptr_factory_.GetWeakPtr()), 626 weak_ptr_factory_.GetWeakPtr()),
679 false); 627 false);
680 } 628 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698