| Index: chrome/browser/win/jumplist.cc
|
| diff --git a/chrome/browser/win/jumplist.cc b/chrome/browser/win/jumplist.cc
|
| index bbca037062d132ddc5c693646170827aee422cee..db4727778a734fc7279af763454085a4913ba86b 100644
|
| --- a/chrome/browser/win/jumplist.cc
|
| +++ b/chrome/browser/win/jumplist.cc
|
| @@ -194,9 +194,9 @@ base::FilePath GenerateJumplistIconDirName(
|
|
|
| } // namespace
|
|
|
| -JumpList::UpdateResults::UpdateResults() {}
|
| +JumpList::UpdateTransaction::UpdateTransaction() {}
|
|
|
| -JumpList::UpdateResults::~UpdateResults() {}
|
| +JumpList::UpdateTransaction::~UpdateTransaction() {}
|
|
|
| // static
|
| bool JumpList::Enabled() {
|
| @@ -306,6 +306,8 @@ void JumpList::OnIncognitoAvailabilityChanged() {
|
| }
|
|
|
| void JumpList::InitializeTimerForUpdate() {
|
| + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
| +
|
| if (timer_.IsRunning()) {
|
| timer_.Reset();
|
| } else {
|
| @@ -317,6 +319,7 @@ void JumpList::InitializeTimerForUpdate() {
|
|
|
| void JumpList::OnDelayTimer() {
|
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
| + DCHECK(!update_in_progress_);
|
|
|
| if (updates_to_skip_ > 0) {
|
| --updates_to_skip_;
|
| @@ -340,6 +343,7 @@ void JumpList::OnDelayTimer() {
|
|
|
| void JumpList::ProcessTopSitesNotification() {
|
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
| + DCHECK(!update_in_progress_);
|
|
|
| // Opening the first tab in one session triggers a TopSite history sync.
|
| // Delay this sync till the first tab is closed to allow the "recently closed"
|
| @@ -362,6 +366,7 @@ void JumpList::ProcessTopSitesNotification() {
|
|
|
| void JumpList::ProcessTabRestoreServiceNotification() {
|
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
| + DCHECK(!update_in_progress_);
|
|
|
| // Create a list of ShellLinkItems from the "Recently Closed" pages.
|
| // As noted above, we create a ShellLinkItem objects with the following
|
| @@ -549,51 +554,53 @@ void JumpList::PostRunUpdate() {
|
| IncognitoModePrefs::Availability incognito_availability =
|
| IncognitoModePrefs::GetAvailability(profile_->GetPrefs());
|
|
|
| - // Make local copies of JumpList member variables and use them for an update.
|
| - ShellLinkItemList local_most_visited_pages = most_visited_pages_;
|
| - ShellLinkItemList local_recently_closed_pages = recently_closed_pages_;
|
| -
|
| - bool most_visited_should_update = most_visited_should_update_;
|
| - bool recently_closed_should_update = recently_closed_should_update_;
|
| -
|
| - auto update_results = base::MakeUnique<UpdateResults>();
|
| - update_results->most_visited_icons_in_update = most_visited_icons_;
|
| - update_results->recently_closed_icons_in_update = recently_closed_icons_;
|
| + auto update_transaction = base::MakeUnique<UpdateTransaction>();
|
| + if (most_visited_should_update_)
|
| + update_transaction->most_visited_icons = std::move(most_visited_icons_);
|
| + if (recently_closed_should_update_) {
|
| + update_transaction->recently_closed_icons =
|
| + std::move(recently_closed_icons_);
|
| + }
|
|
|
| - // Parameter evaluation order is unspecified in C++. Ensure the pointer value
|
| - // is obtained before base::Passed() is called.
|
| - auto* update_results_raw = update_results.get();
|
| + // Parameter evaluation order is unspecified in C++. Do the first bind and
|
| + // then move it into PostTaskAndReply to ensure the pointer value is obtained
|
| + // before base::Passed() is called.
|
| + auto run_update =
|
| + base::Bind(&JumpList::RunUpdateJumpList, app_id_, profile_dir,
|
| + most_visited_pages_, recently_closed_pages_,
|
| + most_visited_should_update_, recently_closed_should_update_,
|
| + incognito_availability, update_transaction.get());
|
|
|
| // Post a task to update the JumpList, which consists of 1) create new icons,
|
| - // 2) delete old icons, 3) notify the OS.
|
| + // 2) notify the OS, 3) delete old icons.
|
| if (!update_jumplist_task_runner_->PostTaskAndReply(
|
| - FROM_HERE,
|
| - base::Bind(&JumpList::RunUpdateJumpList, app_id_, profile_dir,
|
| - local_most_visited_pages, local_recently_closed_pages,
|
| - most_visited_should_update, recently_closed_should_update,
|
| - incognito_availability, update_results_raw),
|
| + FROM_HERE, std::move(run_update),
|
| base::Bind(&JumpList::OnRunUpdateCompletion,
|
| weak_ptr_factory_.GetWeakPtr(),
|
| - base::Passed(std::move(update_results))))) {
|
| - OnRunUpdateCompletion(base::MakeUnique<UpdateResults>());
|
| + base::Passed(std::move(update_transaction))))) {
|
| + OnRunUpdateCompletion(base::MakeUnique<UpdateTransaction>());
|
| }
|
| }
|
|
|
| void JumpList::OnRunUpdateCompletion(
|
| - std::unique_ptr<UpdateResults> update_results) {
|
| + std::unique_ptr<UpdateTransaction> update_transaction) {
|
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
| // Update JumpList member variables based on the results from the update run
|
| // just finished.
|
| - if (update_results->update_timeout)
|
| + if (update_transaction->update_timeout)
|
| updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad;
|
|
|
| - if (update_results->update_success) {
|
| - most_visited_icons_.swap(update_results->most_visited_icons_in_update);
|
| - recently_closed_icons_.swap(
|
| - update_results->recently_closed_icons_in_update);
|
| - most_visited_should_update_ = false;
|
| - recently_closed_should_update_ = false;
|
| + if (update_transaction->update_success) {
|
| + if (most_visited_should_update_) {
|
| + most_visited_icons_ = std::move(update_transaction->most_visited_icons);
|
| + most_visited_should_update_ = false;
|
| + }
|
| + if (recently_closed_should_update_) {
|
| + recently_closed_icons_ =
|
| + std::move(update_transaction->recently_closed_icons);
|
| + recently_closed_should_update_ = false;
|
| + }
|
| }
|
|
|
| update_in_progress_ = false;
|
| @@ -663,11 +670,46 @@ void JumpList::RunUpdateJumpList(
|
| bool most_visited_should_update,
|
| bool recently_closed_should_update,
|
| IncognitoModePrefs::Availability incognito_availability,
|
| - UpdateResults* update_results) {
|
| + UpdateTransaction* update_transaction) {
|
| if (!JumpListUpdater::IsEnabled())
|
| return;
|
|
|
| - DCHECK(update_results);
|
| + DCHECK(update_transaction);
|
| +
|
| + base::FilePath most_visited_icon_dir = GenerateJumplistIconDirName(
|
| + profile_dir, FILE_PATH_LITERAL("MostVisited"));
|
| + base::FilePath recently_closed_icon_dir = GenerateJumplistIconDirName(
|
| + profile_dir, FILE_PATH_LITERAL("RecentClosed"));
|
| +
|
| + CreateNewJumpListAndNotifyOS(
|
| + app_id, most_visited_icon_dir, recently_closed_icon_dir,
|
| + most_visited_pages, recently_closed_pages, most_visited_should_update,
|
| + recently_closed_should_update, incognito_availability,
|
| + update_transaction);
|
| +
|
| + // Delete any obsolete icon files.
|
| + if (most_visited_should_update) {
|
| + DeleteIconFiles(most_visited_icon_dir,
|
| + update_transaction->most_visited_icons);
|
| + }
|
| + if (recently_closed_should_update) {
|
| + DeleteIconFiles(recently_closed_icon_dir,
|
| + update_transaction->recently_closed_icons);
|
| + }
|
| +}
|
| +
|
| +// static
|
| +void JumpList::CreateNewJumpListAndNotifyOS(
|
| + const base::string16& app_id,
|
| + const base::FilePath& most_visited_icon_dir,
|
| + const base::FilePath& recently_closed_icon_dir,
|
| + const ShellLinkItemList& most_visited_pages,
|
| + const ShellLinkItemList& recently_closed_pages,
|
| + bool most_visited_should_update,
|
| + bool recently_closed_should_update,
|
| + IncognitoModePrefs::Availability incognito_availability,
|
| + UpdateTransaction* update_transaction) {
|
| + DCHECK(update_transaction);
|
|
|
| JumpListUpdater jumplist_updater(app_id);
|
|
|
| @@ -678,34 +720,31 @@ void JumpList::RunUpdateJumpList(
|
|
|
| // Discard this JumpList update if JumpListUpdater::BeginUpdate takes longer
|
| // than the maximum allowed time, as it's very likely the following update
|
| - // steps will also take a long time. As we've not updated the icons on the
|
| - // disk, discarding this update wont't affect the current JumpList used by OS.
|
| + // steps will also take a long time.
|
| if (begin_update_timer.Elapsed() >= kTimeOutForJumplistBeginUpdate) {
|
| - update_results->update_timeout = true;
|
| + update_transaction->update_timeout = true;
|
| return;
|
| }
|
|
|
| // Record the desired number of icons created in this JumpList update.
|
| int icons_created = 0;
|
|
|
| + URLIconCache most_visited_icons_next;
|
| + URLIconCache recently_closed_icons_next;
|
| +
|
| // Update the icons for "Most Visisted" category of the JumpList if needed.
|
| if (most_visited_should_update) {
|
| - base::FilePath icon_dir_most_visited = GenerateJumplistIconDirName(
|
| - profile_dir, FILE_PATH_LITERAL("MostVisited"));
|
| -
|
| icons_created += UpdateIconFiles(
|
| - icon_dir_most_visited, most_visited_pages, kMostVisitedItems,
|
| - &update_results->most_visited_icons_in_update);
|
| + most_visited_icon_dir, most_visited_pages, kMostVisitedItems,
|
| + &update_transaction->most_visited_icons, &most_visited_icons_next);
|
| }
|
|
|
| // Update the icons for "Recently Closed" category of the JumpList if needed.
|
| if (recently_closed_should_update) {
|
| - base::FilePath icon_dir_recent_closed = GenerateJumplistIconDirName(
|
| - profile_dir, FILE_PATH_LITERAL("RecentClosed"));
|
| -
|
| icons_created += UpdateIconFiles(
|
| - icon_dir_recent_closed, recently_closed_pages, kRecentlyClosedItems,
|
| - &update_results->recently_closed_icons_in_update);
|
| + recently_closed_icon_dir, recently_closed_pages, kRecentlyClosedItems,
|
| + &update_transaction->recently_closed_icons,
|
| + &recently_closed_icons_next);
|
| }
|
|
|
| // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407.
|
| @@ -732,16 +771,12 @@ void JumpList::RunUpdateJumpList(
|
| return;
|
| }
|
|
|
| - // If JumpListUpdater::AddCustomCategory or JumpListUpdater::CommitUpdate
|
| - // takes longer than the maximum allowed time, skip the next
|
| - // |kUpdatesToSkipUnderHeavyLoad| updates. This update should be finished
|
| - // because we've already updated the icons on the disk. If discarding this
|
| - // update from here, some items in the current JumpList may not have icons
|
| - // as they've been delete from the disk. In this case, the background color of
|
| - // the JumpList panel is used instead, which doesn't look nice.
|
| -
|
| - if (add_custom_category_timer.Elapsed() >= kTimeOutForAddCustomCategory)
|
| - update_results->update_timeout = true;
|
| + // If AddCustomCategory takes longer than the maximum allowed time, abort the
|
| + // current update and skip the next |kUpdatesToSkipUnderHeavyLoad| updates.
|
| + if (add_custom_category_timer.Elapsed() >= kTimeOutForAddCustomCategory) {
|
| + update_transaction->update_timeout = true;
|
| + return;
|
| + }
|
|
|
| // Update the "Tasks" category of the JumpList.
|
| if (!UpdateTaskCategory(&jumplist_updater, incognito_availability))
|
| @@ -750,81 +785,98 @@ void JumpList::RunUpdateJumpList(
|
| base::ElapsedTimer commit_update_timer;
|
|
|
| // Commit this transaction and send the updated JumpList to Windows.
|
| - if (jumplist_updater.CommitUpdate())
|
| - update_results->update_success = true;
|
| + bool commit_success = jumplist_updater.CommitUpdate();
|
|
|
| + // If CommitUpdate call takes longer than the maximum allowed time, skip the
|
| + // next |kUpdatesToSkipUnderHeavyLoad| updates.
|
| if (commit_update_timer.Elapsed() >= kTimeOutForJumplistCommitUpdate)
|
| - update_results->update_timeout = true;
|
| + update_transaction->update_timeout = true;
|
| +
|
| + if (commit_success) {
|
| + update_transaction->update_success = true;
|
| +
|
| + // The move assignments below ensure update_transaction always has the icons
|
| + // to keep.
|
| + if (most_visited_should_update) {
|
| + update_transaction->most_visited_icons =
|
| + std::move(most_visited_icons_next);
|
| + }
|
| + if (recently_closed_should_update) {
|
| + update_transaction->recently_closed_icons =
|
| + std::move(recently_closed_icons_next);
|
| + }
|
| + }
|
| }
|
|
|
| // static
|
| int JumpList::UpdateIconFiles(const base::FilePath& icon_dir,
|
| - const ShellLinkItemList& page_list,
|
| - size_t slot_limit,
|
| - URLIconCache* icon_cache) {
|
| - int icons_created = 0;
|
| + const ShellLinkItemList& item_list,
|
| + size_t max_items,
|
| + URLIconCache* icon_cur,
|
| + URLIconCache* icon_next) {
|
| + DCHECK(icon_cur);
|
| + DCHECK(icon_next);
|
|
|
| - // Clear the JumpList icon folder at |icon_dir| and the cache when
|
| - // 1) |icon_cache| is empty. This happens when "Most visited" or "Recently
|
| + // Clear the JumpList icon folder at |icon_dir| and the caches when
|
| + // 1) |icon_cur| is empty. This happens when "Most visited" or "Recently
|
| // closed" category updates for the 1st time after Chrome is launched.
|
| // 2) The number of icons in |icon_dir| has exceeded the limit.
|
| - if (icon_cache->empty() || FilesExceedLimitInDir(icon_dir, slot_limit * 2)) {
|
| + if (icon_cur->empty() || FilesExceedLimitInDir(icon_dir, max_items * 2)) {
|
| DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit);
|
| - icon_cache->clear();
|
| + icon_cur->clear();
|
| + icon_next->clear();
|
| // Create new icons only when the directory exists and is empty.
|
| - if (base::CreateDirectory(icon_dir) && base::IsDirectoryEmpty(icon_dir))
|
| - icons_created +=
|
| - CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache);
|
| - } else if (base::CreateDirectory(icon_dir)) {
|
| - icons_created +=
|
| - CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache);
|
| - DeleteIconFiles(icon_dir, icon_cache);
|
| + if (!base::CreateDirectory(icon_dir) || !base::IsDirectoryEmpty(icon_dir))
|
| + return 0;
|
| + } else if (!base::CreateDirectory(icon_dir)) {
|
| + return 0;
|
| }
|
|
|
| - return icons_created;
|
| + return CreateIconFiles(icon_dir, item_list, max_items, *icon_cur, icon_next);
|
| }
|
|
|
| // static
|
| int JumpList::CreateIconFiles(const base::FilePath& icon_dir,
|
| const ShellLinkItemList& item_list,
|
| size_t max_items,
|
| - URLIconCache* icon_cache) {
|
| + const URLIconCache& icon_cur,
|
| + URLIconCache* icon_next) {
|
| + DCHECK(icon_next);
|
| +
|
| // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407.
|
| SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration");
|
|
|
| int icons_created = 0;
|
|
|
| // Reuse icons for urls that already present in the current JumpList.
|
| - URLIconCache updated_map;
|
| for (ShellLinkItemList::const_iterator iter = item_list.begin();
|
| iter != item_list.end() && max_items > 0; ++iter, --max_items) {
|
| ShellLinkItem* item = iter->get();
|
| - auto cache_iter = icon_cache->find(item->url());
|
| - if (cache_iter != icon_cache->end()) {
|
| + auto cache_iter = icon_cur.find(item->url());
|
| + if (cache_iter != icon_cur.end()) {
|
| item->set_icon(cache_iter->second.value(), 0);
|
| - updated_map[item->url()] = cache_iter->second;
|
| + (*icon_next)[item->url()] = cache_iter->second;
|
| } else {
|
| base::FilePath icon_path;
|
| if (CreateIconFile(item->icon_image(), icon_dir, &icon_path)) {
|
| ++icons_created;
|
| item->set_icon(icon_path.value(), 0);
|
| - updated_map[item->url()] = icon_path;
|
| + (*icon_next)[item->url()] = icon_path;
|
| }
|
| }
|
| }
|
| - icon_cache->swap(updated_map);
|
|
|
| return icons_created;
|
| }
|
|
|
| // static
|
| void JumpList::DeleteIconFiles(const base::FilePath& icon_dir,
|
| - URLIconCache* icon_cache) {
|
| + const URLIconCache& icons_cache) {
|
| // Put all cached icon file paths into a set.
|
| base::flat_set<base::FilePath> cached_files;
|
| - cached_files.reserve(icon_cache->size());
|
| + cached_files.reserve(icons_cache.size());
|
|
|
| - for (const auto& url_path_pair : *icon_cache)
|
| + for (const auto& url_path_pair : icons_cache)
|
| cached_files.insert(url_path_pair.second);
|
|
|
| DeleteNonCachedFiles(icon_dir, cached_files);
|
|
|