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

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

Issue 2931573003: Fix stability and data racing issues, coalesce more updates for JumpList (Closed)
Patch Set: Created 3 years, 6 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
« chrome/browser/win/jumplist.h ('K') | « chrome/browser/win/jumplist.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "base/base_paths.h" 7 #include "base/base_paths.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/bind_helpers.h" 9 #include "base/bind_helpers.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 #include "ui/gfx/codec/png_codec.h" 46 #include "ui/gfx/codec/png_codec.h"
47 #include "ui/gfx/favicon_size.h" 47 #include "ui/gfx/favicon_size.h"
48 #include "ui/gfx/icon_util.h" 48 #include "ui/gfx/icon_util.h"
49 #include "ui/gfx/image/image.h" 49 #include "ui/gfx/image/image.h"
50 #include "ui/gfx/image/image_family.h" 50 #include "ui/gfx/image/image_family.h"
51 #include "ui/gfx/image/image_skia.h" 51 #include "ui/gfx/image/image_skia.h"
52 #include "ui/gfx/image/image_skia_rep.h" 52 #include "ui/gfx/image/image_skia_rep.h"
53 #include "url/gurl.h" 53 #include "url/gurl.h"
54 54
55 using content::BrowserThread; 55 using content::BrowserThread;
56 using JumpListData = JumpList::JumpListData;
57 56
58 namespace { 57 namespace {
59 58
60 // The default maximum number of items to display in JumpList is 10. 59 // The default maximum number of items to display in JumpList is 10.
61 // https://msdn.microsoft.com/library/windows/desktop/dd378398.aspx 60 // https://msdn.microsoft.com/library/windows/desktop/dd378398.aspx
62 // The "Most visited" and "Recently closed" category titles always take 2 slots. 61 // The "Most visited" and "Recently closed" category titles always take 2 slots.
63 // For the remaining 8 slots, we allocate 5 slots to "most-visited" items and 3 62 // For the remaining 8 slots, we allocate 5 slots to "most-visited" items and 3
64 // slots to "recently-closed" items, respectively. 63 // slots to "recently-closed" items, respectively.
65 constexpr size_t kMostVisitedItems = 5; 64 constexpr size_t kMostVisitedItems = 5;
66 constexpr size_t kRecentlyClosedItems = 3; 65 constexpr size_t kRecentlyClosedItems = 3;
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 base::FilePath GenerateJumplistIconDirName( 188 base::FilePath GenerateJumplistIconDirName(
190 const base::FilePath& profile_dir, 189 const base::FilePath& profile_dir,
191 const base::FilePath::StringPieceType& suffix) { 190 const base::FilePath::StringPieceType& suffix) {
192 base::FilePath::StringType dir_name(chrome::kJumpListIconDirname); 191 base::FilePath::StringType dir_name(chrome::kJumpListIconDirname);
193 suffix.AppendToString(&dir_name); 192 suffix.AppendToString(&dir_name);
194 return profile_dir.Append(dir_name); 193 return profile_dir.Append(dir_name);
195 } 194 }
196 195
197 } // namespace 196 } // namespace
198 197
199 JumpList::JumpListData::JumpListData() {} 198 JumpList::JumpListUpdateResults::JumpListUpdateResults() {}
200 199
201 JumpList::JumpListData::~JumpListData() {} 200 JumpList::JumpListUpdateResults::~JumpListUpdateResults() {}
202 201
203 JumpList::JumpList(Profile* profile) 202 JumpList::JumpList(Profile* profile)
204 : RefcountedKeyedService(content::BrowserThread::GetTaskRunnerForThread( 203 : RefcountedKeyedService(content::BrowserThread::GetTaskRunnerForThread(
205 content::BrowserThread::UI)), 204 content::BrowserThread::UI)),
206 profile_(profile), 205 profile_(profile),
207 jumplist_data_(new base::RefCountedData<JumpListData>),
208 task_id_(base::CancelableTaskTracker::kBadTaskId), 206 task_id_(base::CancelableTaskTracker::kBadTaskId),
209 update_jumplist_task_runner_(base::CreateCOMSTATaskRunnerWithTraits( 207 update_jumplist_task_runner_(base::CreateCOMSTATaskRunnerWithTraits(
210 {base::MayBlock(), base::TaskPriority::USER_VISIBLE, 208 {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
211 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})), 209 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})),
212 delete_jumplisticons_task_runner_( 210 delete_jumplisticons_task_runner_(
213 base::CreateSequencedTaskRunnerWithTraits( 211 base::CreateSequencedTaskRunnerWithTraits(
214 {base::MayBlock(), base::TaskPriority::BACKGROUND, 212 {base::MayBlock(), base::TaskPriority::BACKGROUND,
215 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})), 213 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})),
216 weak_ptr_factory_(this) { 214 weak_ptr_factory_(this) {
217 DCHECK(Enabled()); 215 DCHECK(Enabled());
218 // To update JumpList when a tab is added or removed, we add this object to 216 // To update JumpList when a tab is added or removed, we add this object to
219 // the observer list of the TabRestoreService class. 217 // the observer list of the TabRestoreService class.
220 // When we add this object to the observer list, we save the pointer to this 218 // When we add this object to the observer list, we save the pointer to this
221 // TabRestoreService object. This pointer is used when we remove this object 219 // TabRestoreService object. This pointer is used when we remove this object
222 // from the observer list. 220 // from the observer list.
223 sessions::TabRestoreService* tab_restore_service = 221 sessions::TabRestoreService* tab_restore_service =
224 TabRestoreServiceFactory::GetForProfile(profile_); 222 TabRestoreServiceFactory::GetForProfile(profile_);
225 if (!tab_restore_service) 223 if (!tab_restore_service)
226 return; 224 return;
227 225
228 app_id_ = 226 app_id_ =
229 shell_integration::win::GetChromiumModelIdForProfile(profile_->GetPath()); 227 shell_integration::win::GetChromiumModelIdForProfile(profile_->GetPath());
230 228
231 scoped_refptr<history::TopSites> top_sites = 229 scoped_refptr<history::TopSites> top_sites =
grt (UTC plus 2) 2017/06/09 10:42:57 nit: move this down just after the comment below w
chengx 2017/06/10 05:56:17 Done.
232 TopSitesFactory::GetForProfile(profile_); 230 TopSitesFactory::GetForProfile(profile_);
233 if (top_sites) { 231
234 // Register as TopSitesObserver so that we can update ourselves when the 232 // Register as TopSitesObserver so that we can update ourselves when the
235 // TopSites changes. TopSites updates itself after a delay. This is 233 // TopSites changes. TopSites updates itself after a delay. This is especially
236 // especially noticable when your profile is empty. 234 // noticable when your profile is empty.
235 if (top_sites)
237 top_sites->AddObserver(this); 236 top_sites->AddObserver(this);
238 } 237
239 tab_restore_service->AddObserver(this); 238 tab_restore_service->AddObserver(this);
grt (UTC plus 2) 2017/06/09 10:42:57 please add a doc comment explaining why the TRS is
chengx 2017/06/10 05:56:17 Done.
240 pref_change_registrar_.reset(new PrefChangeRegistrar); 239 pref_change_registrar_.reset(new PrefChangeRegistrar);
grt (UTC plus 2) 2017/06/09 10:42:56 please add a doc comment explaining why kIncognito
chengx 2017/06/10 05:56:17 Done.
241 pref_change_registrar_->Init(profile_->GetPrefs()); 240 pref_change_registrar_->Init(profile_->GetPrefs());
242 pref_change_registrar_->Add( 241 pref_change_registrar_->Add(
243 prefs::kIncognitoModeAvailability, 242 prefs::kIncognitoModeAvailability,
244 base::Bind(&JumpList::OnIncognitoAvailabilityChanged, this)); 243 base::Bind(&JumpList::OnIncognitoAvailabilityChanged, this));
grt (UTC plus 2) 2017/06/09 10:42:56 base::Unretained(this) since you're guaranteed tha
chengx 2017/06/10 05:56:17 Changed to base::Unretained(this) and comments add
245 } 244 }
246 245
247 JumpList::~JumpList() { 246 JumpList::~JumpList() {
248 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 247 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
249 Terminate(); 248 Terminate();
250 } 249 }
251 250
252 // static 251 // static
253 bool JumpList::Enabled() { 252 bool JumpList::Enabled() {
254 return JumpListUpdater::IsEnabled(); 253 return JumpListUpdater::IsEnabled();
255 } 254 }
256 255
257 void JumpList::CancelPendingUpdate() { 256 void JumpList::CancelPendingUpdate() {
grt (UTC plus 2) 2017/06/09 10:42:57 i think this should also cancel a pending MostVisi
chengx 2017/06/10 05:56:18 Thanks for the reminder! I've updated code to inva
258 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 257 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
259 if (task_id_ != base::CancelableTaskTracker::kBadTaskId) { 258 if (task_id_ != base::CancelableTaskTracker::kBadTaskId) {
260 cancelable_task_tracker_.TryCancel(task_id_); 259 cancelable_task_tracker_.TryCancel(task_id_);
261 task_id_ = base::CancelableTaskTracker::kBadTaskId; 260 task_id_ = base::CancelableTaskTracker::kBadTaskId;
262 } 261 }
263 } 262 }
264 263
265 void JumpList::Terminate() { 264 void JumpList::Terminate() {
266 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 265 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
267 timer_most_visited_.Stop(); 266 timer_.Stop();
268 timer_recently_closed_.Stop();
269 CancelPendingUpdate(); 267 CancelPendingUpdate();
270 if (profile_) { 268 if (profile_) {
grt (UTC plus 2) 2017/06/09 10:42:56 update_in_progress_ = false; just before this line
chengx 2017/06/10 05:56:16 Done.
271 sessions::TabRestoreService* tab_restore_service = 269 sessions::TabRestoreService* tab_restore_service =
272 TabRestoreServiceFactory::GetForProfile(profile_); 270 TabRestoreServiceFactory::GetForProfile(profile_);
273 if (tab_restore_service) 271 if (tab_restore_service)
274 tab_restore_service->RemoveObserver(this); 272 tab_restore_service->RemoveObserver(this);
275 scoped_refptr<history::TopSites> top_sites = 273 scoped_refptr<history::TopSites> top_sites =
276 TopSitesFactory::GetForProfile(profile_); 274 TopSitesFactory::GetForProfile(profile_);
277 if (top_sites) 275 if (top_sites)
278 top_sites->RemoveObserver(this); 276 top_sites->RemoveObserver(this);
279 pref_change_registrar_.reset(); 277 pref_change_registrar_.reset();
280 } 278 }
281 profile_ = NULL; 279 profile_ = NULL;
grt (UTC plus 2) 2017/06/09 10:42:56 nit: nullptr throughout
chengx 2017/06/10 05:56:17 Done.
282 } 280 }
283 281
284 void JumpList::ShutdownOnUIThread() { 282 void JumpList::ShutdownOnUIThread() {
285 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 283 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
286 Terminate(); 284 Terminate();
287 } 285 }
288 286
289 void JumpList::OnMostVisitedURLsAvailable( 287 void JumpList::OnMostVisitedURLsAvailable(
290 const history::MostVisitedURLList& urls) { 288 const history::MostVisitedURLList& urls) {
291 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 289 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
292 290
293 { 291 // There is no need to update the JumpList if the top most visited sites in
294 JumpListData* data = &jumplist_data_->data; 292 // display have not changed.
295 base::AutoLock auto_lock(data->list_lock_); 293 if (MostVisitedItemsUnchanged(most_visited_pages_, urls, kMostVisitedItems))
294 return;
296 295
297 // There is no need to update the JumpList if the top most visited sites in 296 most_visited_pages_.clear();
298 // display have not changed.
299 if (MostVisitedItemsUnchanged(data->most_visited_pages_, urls,
300 kMostVisitedItems)) {
301 return;
302 }
303 297
grt (UTC plus 2) 2017/06/09 10:42:56 const size_t num_items = std::min(urls.size(), kMo
chengx 2017/06/10 05:56:17 I introduced num_items to avoid duplicated value c
grt (UTC plus 2) 2017/06/12 07:15:32 :-)
chengx 2017/06/12 22:05:28 Acknowledged.
304 data->most_visited_pages_.clear(); 298 for (size_t i = 0; i < urls.size() && i < kMostVisitedItems; i++) {
grt (UTC plus 2) 2017/06/09 10:42:56 ...; i < num_items; ++i) { (note: always prefer p
chengx 2017/06/10 05:56:17 Done.
299 const history::MostVisitedURL& url = urls[i];
300 scoped_refptr<ShellLinkItem> link = CreateShellLink();
301 std::string url_string = url.url.spec();
302 base::string16 url_string_wide = base::UTF8ToUTF16(url_string);
303 link->GetCommandLine()->AppendArgNative(url_string_wide);
304 link->GetCommandLine()->AppendSwitchASCII(switches::kWinJumplistAction,
305 jumplist::kMostVisitedCategory);
306 link->set_title(!url.title.empty() ? url.title : url_string_wide);
307 link->set_url(url_string);
308 most_visited_pages_.push_back(link);
309 icon_urls_.push_back(std::make_pair(url_string, link));
grt (UTC plus 2) 2017/06/09 10:42:57 icon_urls_.emplace_back(std::move(url_string), std
chengx 2017/06/10 05:56:17 Done.
310 }
305 311
306 for (size_t i = 0; i < urls.size() && i < kMostVisitedItems; i++) { 312 most_visited_pages_have_updates_ = true;
307 const history::MostVisitedURL& url = urls[i];
308 scoped_refptr<ShellLinkItem> link = CreateShellLink();
309 std::string url_string = url.url.spec();
310 base::string16 url_string_wide = base::UTF8ToUTF16(url_string);
311 link->GetCommandLine()->AppendArgNative(url_string_wide);
312 link->GetCommandLine()->AppendSwitchASCII(
313 switches::kWinJumplistAction, jumplist::kMostVisitedCategory);
314 link->set_title(!url.title.empty() ? url.title : url_string_wide);
315 link->set_url(url_string);
316 data->most_visited_pages_.push_back(link);
317 data->icon_urls_.push_back(std::make_pair(url_string, link));
318 }
319 data->most_visited_pages_have_updates_ = true;
320 }
321 313
322 // Send a query that retrieves the first favicon. 314 // Send a query that retrieves the first favicon.
323 StartLoadingFavicon(); 315 StartLoadingFavicon();
324 } 316 }
325 317
326 void JumpList::TabRestoreServiceChanged(sessions::TabRestoreService* service) { 318 void JumpList::TabRestoreServiceChanged(sessions::TabRestoreService* service) {
327 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 319 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
328 320
329 // if we have a pending favicon request, cancel it here (it is out of date). 321 recently_closed_has_pending_notification_ = true;
322
323 if (update_in_progress_)
grt (UTC plus 2) 2017/06/09 10:42:56 please document this. for example: // Postpone h
chengx 2017/06/10 05:56:16 Done.
324 return;
325
326 // if we have a pending favicon request, cancel it here as it's out of date.
330 CancelPendingUpdate(); 327 CancelPendingUpdate();
331 328
332 // Initialize the one-shot timer to update the the "Recently Closed" category 329 // Initialize the one-shot timer to update the JumpList in a while. If there
333 // in a while. If there is already a request queued then cancel it and post 330 // is already a request queued then cancel it and post the new request. This
334 // the new request. This ensures that JumpList update of the "Recently Closed" 331 // ensures that JumpList update won't happen until there has been a brief
335 // category won't happen until there has been a brief quiet period, thus 332 // quiet period, thus avoiding update storms.
336 // avoiding update storms. 333 if (timer_.IsRunning()) {
grt (UTC plus 2) 2017/06/09 10:42:57 this block is repeated three times. please pull it
chengx 2017/06/10 05:56:18 I have added a new InitializeTimerForUpdate method
337 if (timer_recently_closed_.IsRunning()) { 334 timer_.Reset();
338 timer_recently_closed_.Reset();
339 } else { 335 } else {
340 timer_recently_closed_.Start( 336 timer_.Start(
341 FROM_HERE, kDelayForJumplistUpdate, 337 FROM_HERE, kDelayForJumplistUpdate,
342 base::Bind(&JumpList::DeferredTabRestoreServiceChanged, 338 base::Bind(&JumpList::DeferredChanged, base::Unretained(this)));
grt (UTC plus 2) 2017/06/09 10:42:57 please add a comment such as: // base::Unretaine
chengx 2017/06/10 05:56:17 Done.
343 base::Unretained(this)));
344 } 339 }
345 } 340 }
346 341
347 void JumpList::TabRestoreServiceDestroyed( 342 void JumpList::TabRestoreServiceDestroyed(
348 sessions::TabRestoreService* service) {} 343 sessions::TabRestoreService* service) {}
349 344
350 bool JumpList::AddTab(const sessions::TabRestoreService::Tab& tab, 345 bool JumpList::AddTab(const sessions::TabRestoreService::Tab& tab,
351 size_t max_items, 346 size_t max_items) {
352 JumpListData* data) {
353 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 347 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
354 data->list_lock_.AssertAcquired();
355 348
356 // This code adds the URL and the title strings of the given tab to |data|. 349 // This code adds the URL and the title strings of the given tab to the
357 if (data->recently_closed_pages_.size() >= max_items) 350 // JumpList variables.
351 if (recently_closed_pages_.size() >= max_items)
358 return false; 352 return false;
359 353
360 scoped_refptr<ShellLinkItem> link = CreateShellLink(); 354 scoped_refptr<ShellLinkItem> link = CreateShellLink();
361 const sessions::SerializedNavigationEntry& current_navigation = 355 const sessions::SerializedNavigationEntry& current_navigation =
362 tab.navigations.at(tab.current_navigation_index); 356 tab.navigations.at(tab.current_navigation_index);
363 std::string url = current_navigation.virtual_url().spec(); 357 std::string url = current_navigation.virtual_url().spec();
364 link->GetCommandLine()->AppendArgNative(base::UTF8ToUTF16(url)); 358 link->GetCommandLine()->AppendArgNative(base::UTF8ToUTF16(url));
365 link->GetCommandLine()->AppendSwitchASCII(switches::kWinJumplistAction, 359 link->GetCommandLine()->AppendSwitchASCII(switches::kWinJumplistAction,
366 jumplist::kRecentlyClosedCategory); 360 jumplist::kRecentlyClosedCategory);
367 link->set_title(current_navigation.title()); 361 link->set_title(current_navigation.title());
368 link->set_url(url); 362 link->set_url(url);
369 data->recently_closed_pages_.push_back(link); 363 recently_closed_pages_.push_back(link);
370 data->icon_urls_.push_back(std::make_pair(std::move(url), std::move(link))); 364 icon_urls_.push_back(std::make_pair(std::move(url), std::move(link)));
grt (UTC plus 2) 2017/06/09 10:42:56 icon_urls_.emplace_back(std::move(url), std::move(
chengx 2017/06/10 05:56:17 Done.
371 365
372 return true; 366 return true;
373 } 367 }
374 368
375 void JumpList::AddWindow(const sessions::TabRestoreService::Window& window, 369 void JumpList::AddWindow(const sessions::TabRestoreService::Window& window,
376 size_t max_items, 370 size_t max_items) {
377 JumpListData* data) {
378 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 371 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
379 data->list_lock_.AssertAcquired();
380 372
381 // This code enumerates all the tabs in the given window object and add their 373 // This code enumerates all the tabs in the given window object and add their
grt (UTC plus 2) 2017/06/09 10:42:57 this comment adds nothing over the doc comment in
chengx 2017/06/10 05:56:17 Done.
382 // URLs and titles to |data|. 374 // URLs and titles to the JumpList variables.
383 DCHECK(!window.tabs.empty()); 375 DCHECK(!window.tabs.empty());
384 376
385 for (const auto& tab : window.tabs) { 377 for (const auto& tab : window.tabs) {
386 if (!AddTab(*tab, max_items, data)) 378 if (!AddTab(*tab, max_items))
387 return; 379 return;
388 } 380 }
389 } 381 }
390 382
391 void JumpList::StartLoadingFavicon() { 383 void JumpList::StartLoadingFavicon() {
392 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 384 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
393 385
394 base::ElapsedTimer timer; 386 base::ElapsedTimer timer;
grt (UTC plus 2) 2017/06/09 10:42:57 do the early return before this line: if (icon_
chengx 2017/06/10 05:56:18 Done.
395 387
396 GURL url; 388 GURL url;
397 bool waiting_for_icons = true; 389
398 { 390 bool waiting_for_icons = !icon_urls_.empty();
399 JumpListData* data = &jumplist_data_->data; 391 if (waiting_for_icons) {
400 base::AutoLock auto_lock(data->list_lock_); 392 // Ask FaviconService if it has a favicon of a URL.
401 waiting_for_icons = !data->icon_urls_.empty(); 393 // When FaviconService has one, it will call OnFaviconDataAvailable().
402 if (waiting_for_icons) { 394 url = GURL(icon_urls_.front().first);
403 // Ask FaviconService if it has a favicon of a URL.
404 // When FaviconService has one, it will call OnFaviconDataAvailable().
405 url = GURL(data->icon_urls_.front().first);
406 }
407 } 395 }
408 396
409 if (!waiting_for_icons) { 397 if (!waiting_for_icons) {
410 // No more favicons are needed by the application JumpList. Schedule a 398 // No more favicons are needed by the application JumpList. Schedule a
411 // RunUpdateJumpList call. 399 // RunUpdateJumpList call.
412 PostRunUpdate(); 400 PostRunUpdate();
413 return; 401 return;
414 } 402 }
415 403
416 favicon::FaviconService* favicon_service = 404 favicon::FaviconService* favicon_service =
417 FaviconServiceFactory::GetForProfile(profile_, 405 FaviconServiceFactory::GetForProfile(profile_,
418 ServiceAccessType::EXPLICIT_ACCESS); 406 ServiceAccessType::EXPLICIT_ACCESS);
419 task_id_ = favicon_service->GetFaviconImageForPageURL( 407 task_id_ = favicon_service->GetFaviconImageForPageURL(
420 url, 408 url,
421 base::Bind(&JumpList::OnFaviconDataAvailable, base::Unretained(this)), 409 base::Bind(&JumpList::OnFaviconDataAvailable, base::Unretained(this)),
grt (UTC plus 2) 2017/06/09 10:42:56 please add a comment such as: // base::Unretaine
chengx 2017/06/10 05:56:18 Done.
422 &cancelable_task_tracker_); 410 &cancelable_task_tracker_);
423 411
424 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/717236 412 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/717236
425 UMA_HISTOGRAM_TIMES("WinJumplist.StartLoadingFaviconDuration", 413 UMA_HISTOGRAM_TIMES("WinJumplist.StartLoadingFaviconDuration",
426 timer.Elapsed()); 414 timer.Elapsed());
427 } 415 }
428 416
429 void JumpList::OnFaviconDataAvailable( 417 void JumpList::OnFaviconDataAvailable(
430 const favicon_base::FaviconImageResult& image_result) { 418 const favicon_base::FaviconImageResult& image_result) {
431 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 419 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
432 420
433 base::ElapsedTimer timer; 421 base::ElapsedTimer timer;
434 422
435 // If there is currently a favicon request in progress, it is now outdated, 423 // If there is currently a favicon request in progress, it is now outdated,
436 // as we have received another, so nullify the handle from the old request. 424 // as we have received another, so nullify the handle from the old request.
437 task_id_ = base::CancelableTaskTracker::kBadTaskId; 425 task_id_ = base::CancelableTaskTracker::kBadTaskId;
438 // Lock the list to set icon data and pop the url.
439 {
440 JumpListData* data = &jumplist_data_->data;
441 base::AutoLock auto_lock(data->list_lock_);
442 // Attach the received data to the ShellLinkItem object.
443 // This data will be decoded by the RunUpdateJumpList
444 // method.
445 if (!image_result.image.IsEmpty() && !data->icon_urls_.empty() &&
446 data->icon_urls_.front().second.get()) {
447 gfx::ImageSkia image_skia = image_result.image.AsImageSkia();
448 image_skia.EnsureRepsForSupportedScales();
449 std::unique_ptr<gfx::ImageSkia> deep_copy(image_skia.DeepCopy());
450 data->icon_urls_.front().second->set_icon_image(*deep_copy);
451 }
452 426
453 if (!data->icon_urls_.empty()) 427 // Attach the received data to the ShellLinkItem object. This data will be
454 data->icon_urls_.pop_front(); 428 // decoded by the RunUpdateJumpList method.
429 if (!image_result.image.IsEmpty() && !icon_urls_.empty() &&
430 icon_urls_.front().second.get()) {
431 gfx::ImageSkia image_skia = image_result.image.AsImageSkia();
432 image_skia.EnsureRepsForSupportedScales();
433 std::unique_ptr<gfx::ImageSkia> deep_copy(image_skia.DeepCopy());
434 icon_urls_.front().second->set_icon_image(*deep_copy);
455 } 435 }
456 436
437 if (!icon_urls_.empty())
grt (UTC plus 2) 2017/06/09 10:42:55 this condition is checked twice. how about: if (
chengx 2017/06/10 05:56:17 Agreed this is the right thing to do. Done.
438 icon_urls_.pop_front();
439
457 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/717236 440 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/717236
458 UMA_HISTOGRAM_TIMES("WinJumplist.OnFaviconDataAvailableDuration", 441 UMA_HISTOGRAM_TIMES("WinJumplist.OnFaviconDataAvailableDuration",
459 timer.Elapsed()); 442 timer.Elapsed());
460 443
461 // Check whether we need to load more favicons. 444 // Check whether we need to load more favicons.
462 StartLoadingFavicon(); 445 StartLoadingFavicon();
463 } 446 }
464 447
465 void JumpList::OnIncognitoAvailabilityChanged() { 448 void JumpList::OnIncognitoAvailabilityChanged() {
466 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 449 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
467 450
468 bool waiting_for_icons = true; 451 bool waiting_for_icons = !icon_urls_.empty();
469 {
470 JumpListData* data = &jumplist_data_->data;
471 base::AutoLock auto_lock(data->list_lock_);
472 waiting_for_icons = !data->icon_urls_.empty();
473 }
474 452
475 // Since neither the "Most Visited" category nor the "Recently Closed" 453 // Since neither the "Most Visited" category nor the "Recently Closed"
476 // category changes, mark the flags so that icon files for those categories 454 // category changes, mark the flags so that icon files for those categories
477 // won't be updated later on. 455 // won't be updated later on.
478 if (!waiting_for_icons) 456 if (!waiting_for_icons)
grt (UTC plus 2) 2017/06/09 10:42:56 if (icon_urls_.empty()))
chengx 2017/06/10 05:56:16 Done.
479 PostRunUpdate(); 457 PostRunUpdate();
480 } 458 }
481 459
482 void JumpList::PostRunUpdate() { 460 void JumpList::PostRunUpdate() {
483 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 461 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
484 462
485 TRACE_EVENT0("browser", "JumpList::PostRunUpdate"); 463 TRACE_EVENT0("browser", "JumpList::PostRunUpdate");
486 if (!profile_) 464 if (!profile_)
grt (UTC plus 2) 2017/06/09 10:42:55 can this ever be true? as long as Terminate() real
chengx 2017/06/10 05:56:17 I've removed it.
487 return; 465 return;
488 466
467 update_in_progress_ = true;
468
489 base::FilePath profile_dir = profile_->GetPath(); 469 base::FilePath profile_dir = profile_->GetPath();
490 470
491 // Check if incognito windows (or normal windows) are disabled by policy. 471 // Check if incognito windows (or normal windows) are disabled by policy.
492 IncognitoModePrefs::Availability incognito_availability = 472 IncognitoModePrefs::Availability incognito_availability =
493 IncognitoModePrefs::GetAvailability(profile_->GetPrefs()); 473 IncognitoModePrefs::GetAvailability(profile_->GetPrefs());
494 474
495 // Post a task to update the JumpList, which consists of 1) delete old icons, 475 // Make local copies of JumpList member variables and use them for an update.
496 // 2) create new icons, 3) notify the OS. 476 ShellLinkItemList local_most_visited_pages = most_visited_pages_;
497 update_jumplist_task_runner_->PostTask( 477 ShellLinkItemList local_recently_closed_pages = recently_closed_pages_;
478
479 bool most_visited_pages_have_updates = most_visited_pages_have_updates_;
480 bool recently_closed_pages_have_updates = recently_closed_pages_have_updates_;
481
482 JumpListUpdateResults* update_results = new JumpListUpdateResults();
grt (UTC plus 2) 2017/06/09 10:42:56 auto update_results = base::MakeUnique<JumpListUpd
chengx 2017/06/10 05:56:17 Done.
483 update_results->most_visited_icons_in_update_ = most_visited_icons_;
484 update_results->recently_closed_icons_in_update = recently_closed_icons_;
485
486 // Post a task to update the JumpList, which consists of 1) create new icons,
487 // 2) delete old icons, 3) notify the OS.
488 update_jumplist_task_runner_->PostTaskAndReply(
grt (UTC plus 2) 2017/06/09 10:42:56 PTAR returns a bool indicating whether or not the
chengx 2017/06/10 05:56:16 Thanks for the reminder! This is cool!
498 FROM_HERE, 489 FROM_HERE,
499 base::Bind(&JumpList::RunUpdateJumpList, this, incognito_availability, 490 base::Bind(&JumpList::RunUpdateJumpList, app_id_, profile_dir,
500 app_id_, profile_dir, base::RetainedRef(jumplist_data_))); 491 local_most_visited_pages, local_recently_closed_pages,
492 most_visited_pages_have_updates,
493 recently_closed_pages_have_updates, incognito_availability,
494 update_results),
495 base::Bind(&JumpList::OnRunUpdateCompletion, base::Unretained(this),
grt (UTC plus 2) 2017/06/09 10:42:56 base::Unretained -> weak_ptr_factory_.GetWeakPtr()
chengx 2017/06/10 05:56:17 Done.
496 base::Passed(base::WrapUnique(update_results))));
501 497
502 // Post a task to delete JumpListIcons folder as it's no longer needed. 498 // Post a task to delete folders JumpListIcons and JumpListIconsOld as they
grt (UTC plus 2) 2017/06/09 10:42:56 wdyt of moving this stuff down into OnRunUpdateCom
grt (UTC plus 2) 2017/06/09 10:42:57 nit: "...to delete the Foo and Bar folders as they
chengx 2017/06/10 05:56:17 Comments updated.
chengx 2017/06/10 05:56:17 SGTM. Done.
503 // Now we have JumpListIconsMostVisited folder and JumpListIconsRecentClosed 499 // are no longer needed. Now we have folders JumpListIcons{MostVisited,
504 // folder instead. 500 // RecentClosed} instead.
501
505 base::FilePath icon_dir = 502 base::FilePath icon_dir =
506 GenerateJumplistIconDirName(profile_dir, FILE_PATH_LITERAL("")); 503 GenerateJumplistIconDirName(profile_dir, FILE_PATH_LITERAL(""));
507
508 delete_jumplisticons_task_runner_->PostTask( 504 delete_jumplisticons_task_runner_->PostTask(
509 FROM_HERE, 505 FROM_HERE,
510 base::Bind(&DeleteDirectory, std::move(icon_dir), kFileDeleteLimit)); 506 base::Bind(&DeleteDirectory, std::move(icon_dir), kFileDeleteLimit));
511 507
512 // Post a task to delete JumpListIconsOld folder as it's no longer needed.
513 base::FilePath icon_dir_old = 508 base::FilePath icon_dir_old =
514 GenerateJumplistIconDirName(profile_dir, FILE_PATH_LITERAL("Old")); 509 GenerateJumplistIconDirName(profile_dir, FILE_PATH_LITERAL("Old"));
515
516 delete_jumplisticons_task_runner_->PostTask( 510 delete_jumplisticons_task_runner_->PostTask(
517 FROM_HERE, 511 FROM_HERE,
518 base::Bind(&DeleteDirectory, std::move(icon_dir_old), kFileDeleteLimit)); 512 base::Bind(&DeleteDirectory, std::move(icon_dir_old), kFileDeleteLimit));
519 } 513 }
520 514
521 void JumpList::TopSitesLoaded(history::TopSites* top_sites) { 515 void JumpList::TopSitesLoaded(history::TopSites* top_sites) {
522 } 516 }
523 517
524 void JumpList::TopSitesChanged(history::TopSites* top_sites, 518 void JumpList::TopSitesChanged(history::TopSites* top_sites,
525 ChangeReason change_reason) { 519 ChangeReason change_reason) {
526 // If we have a pending favicon request, cancel it here (it is out of date). 520 most_visited_has_pending_notification_ = true;
grt (UTC plus 2) 2017/06/09 10:42:56 "Most Visited" is the name of the jumplist section
grt (UTC plus 2) 2017/06/09 10:42:56 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_)
chengx 2017/06/10 05:56:17 Thanks for the suggestion. I prefer top_sites_has_
chengx 2017/06/10 05:56:18 DCHECK added.
521
522 if (update_in_progress_)
523 return;
524
525 // If we have a pending favicon request, cancel it here as it's out of date.
527 CancelPendingUpdate(); 526 CancelPendingUpdate();
528 527
529 // Initialize the one-shot timer to update the the "Most visited" category in 528 // Initialize the one-shot timer to update the JumpList in a while. If there
530 // a while. If there is already a request queued then cancel it and post the 529 // is already a request queued then cancel it and post the new request. This
531 // new request. This ensures that JumpList update of the "Most visited" 530 // ensures that JumpList update won't happen until there has been a brief
532 // category won't happen until there has been a brief quiet period, thus 531 // quiet period, thus avoiding update storms.
533 // avoiding update storms. 532 if (timer_.IsRunning()) {
534 if (timer_most_visited_.IsRunning()) { 533 timer_.Reset();
535 timer_most_visited_.Reset();
536 } else { 534 } else {
537 timer_most_visited_.Start( 535 timer_.Start(
538 FROM_HERE, kDelayForJumplistUpdate, 536 FROM_HERE, kDelayForJumplistUpdate,
539 base::Bind(&JumpList::DeferredTopSitesChanged, base::Unretained(this))); 537 base::Bind(&JumpList::DeferredChanged, base::Unretained(this)));
538 }
539 }
540
541 void JumpList::DeferredChanged() {
542 if (updates_to_skip_ > 0) {
grt (UTC plus 2) 2017/06/09 10:42:57 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_)
chengx 2017/06/10 05:56:16 Done.
543 --updates_to_skip_;
544 return;
545 }
546
547 // Retrieve the recently closed URLs synchronously.
548 if (recently_closed_has_pending_notification_) {
549 recently_closed_has_pending_notification_ = false;
550 DeferredTabRestoreServiceChanged();
551 }
552
553 // If TopSites has updates, retrieve the URLs asynchronously, and on its
554 // completion, trigger favicon loading.
555 // Otherwise, call StartLoadingFavicon directly to start favicon loading.
556 if (most_visited_has_pending_notification_) {
557 most_visited_has_pending_notification_ = false;
558 DeferredTopSitesChanged();
559 } else {
560 StartLoadingFavicon();
540 } 561 }
541 } 562 }
542 563
543 void JumpList::DeferredTopSitesChanged() { 564 void JumpList::DeferredTopSitesChanged() {
544 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 565 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
545 566
546 if (updates_to_skip_ > 0) {
547 --updates_to_skip_;
548 return;
549 }
550
551 // Opening the first tab in one session triggers a TopSite history sync. 567 // Opening the first tab in one session triggers a TopSite history sync.
552 // Delay this sync till the first tab is closed to allow the "recently closed" 568 // Delay this sync till the first tab is closed to allow the "recently closed"
553 // category from last session to stay longer. 569 // category from last session to stay longer.
554 if (!has_tab_closed_) 570 if (!has_tab_closed_)
555 return; 571 return;
556 572
557 scoped_refptr<history::TopSites> top_sites = 573 scoped_refptr<history::TopSites> top_sites =
558 TopSitesFactory::GetForProfile(profile_); 574 TopSitesFactory::GetForProfile(profile_);
559 if (top_sites) { 575 if (top_sites) {
560 top_sites->GetMostVisitedURLs( 576 top_sites->GetMostVisitedURLs(
grt (UTC plus 2) 2017/06/09 10:42:57 i think you need to do something to deal with an o
chengx 2017/06/10 05:56:18 Thanks for the detailed suggestions! I'll go with
561 base::Bind(&JumpList::OnMostVisitedURLsAvailable, 577 base::Bind(&JumpList::OnMostVisitedURLsAvailable,
562 weak_ptr_factory_.GetWeakPtr()), 578 weak_ptr_factory_.GetWeakPtr()),
563 false); 579 false);
564 } 580 }
565 } 581 }
566 582
567 void JumpList::DeferredTabRestoreServiceChanged() { 583 void JumpList::DeferredTabRestoreServiceChanged() {
568 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 584 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
569 585
570 if (updates_to_skip_ > 0) {
571 --updates_to_skip_;
572 return;
573 }
574
575 // Force a TopSite history sync when closing a first tab in one session.
576 if (!has_tab_closed_) {
577 has_tab_closed_ = true;
578 scoped_refptr<history::TopSites> top_sites =
579 TopSitesFactory::GetForProfile(profile_);
580 if (top_sites)
581 top_sites->SyncWithHistory();
582 }
583
584 // Create a list of ShellLinkItems from the "Recently Closed" pages. 586 // Create a list of ShellLinkItems from the "Recently Closed" pages.
585 // As noted above, we create a ShellLinkItem objects with the following 587 // As noted above, we create a ShellLinkItem objects with the following
586 // parameters. 588 // parameters.
587 // * arguments 589 // * arguments
588 // The last URL of the tab object. 590 // The last URL of the tab object.
589 // * title 591 // * title
590 // The title of the last URL. 592 // The title of the last URL.
591 // * icon 593 // * icon
592 // An empty string. This value is to be updated in OnFaviconDataAvailable(). 594 // An empty string. This value is to be updated in OnFaviconDataAvailable().
593 595
594 sessions::TabRestoreService* tab_restore_service = 596 sessions::TabRestoreService* tab_restore_service =
595 TabRestoreServiceFactory::GetForProfile(profile_); 597 TabRestoreServiceFactory::GetForProfile(profile_);
596 598
597 { 599 recently_closed_pages_.clear();
598 JumpListData* data = &jumplist_data_->data;
599 base::AutoLock auto_lock(data->list_lock_);
600 data->recently_closed_pages_.clear();
601 600
602 for (const auto& entry : tab_restore_service->entries()) { 601 for (const auto& entry : tab_restore_service->entries()) {
603 if (data->recently_closed_pages_.size() >= kRecentlyClosedItems) 602 if (recently_closed_pages_.size() >= kRecentlyClosedItems)
603 break;
604 switch (entry->type) {
605 case sessions::TabRestoreService::TAB:
606 AddTab(static_cast<const sessions::TabRestoreService::Tab&>(*entry),
607 kRecentlyClosedItems);
604 break; 608 break;
605 switch (entry->type) { 609 case sessions::TabRestoreService::WINDOW:
606 case sessions::TabRestoreService::TAB: 610 AddWindow(
607 AddTab(static_cast<const sessions::TabRestoreService::Tab&>(*entry), 611 static_cast<const sessions::TabRestoreService::Window&>(*entry),
608 kRecentlyClosedItems, data); 612 kRecentlyClosedItems);
609 break; 613 break;
610 case sessions::TabRestoreService::WINDOW:
611 AddWindow(
612 static_cast<const sessions::TabRestoreService::Window&>(*entry),
613 kRecentlyClosedItems, data);
614 break;
615 }
616 } 614 }
617
618 data->recently_closed_pages_have_updates_ = true;
619 } 615 }
620 616
621 // Send a query that retrieves the first favicon. 617 recently_closed_pages_have_updates_ = true;
622 StartLoadingFavicon(); 618
619 // Force a TopSite history sync when closing a first tab in one session.
620 if (!has_tab_closed_) {
621 has_tab_closed_ = true;
622 scoped_refptr<history::TopSites> top_sites =
623 TopSitesFactory::GetForProfile(profile_);
624 if (top_sites)
625 top_sites->SyncWithHistory();
626 }
623 } 627 }
624 628
629 // static
625 void JumpList::DeleteIconFiles(const base::FilePath& icon_dir, 630 void JumpList::DeleteIconFiles(const base::FilePath& icon_dir,
626 JumpListCategory category) { 631 URLIconCache* icon_cache) {
627 base::flat_map<std::string, base::FilePath>* source_map = nullptr;
628 switch (category) {
629 case JumpListCategory::kMostVisited:
630 source_map = &most_visited_icons_;
631 break;
632 case JumpListCategory::kRecentlyClosed:
633 source_map = &recently_closed_icons_;
634 break;
635 }
636
637 // Put all cached icon file paths into a set. 632 // Put all cached icon file paths into a set.
638 base::flat_set<base::FilePath> cached_files; 633 base::flat_set<base::FilePath> cached_files;
639 cached_files.reserve(source_map->size()); 634 cached_files.reserve(icon_cache->size());
640 635
641 for (const auto& url_path_pair : *source_map) 636 for (const auto& url_path_pair : *icon_cache)
642 cached_files.insert(url_path_pair.second); 637 cached_files.insert(url_path_pair.second);
643 638
644 DeleteNonCachedFiles(icon_dir, cached_files); 639 DeleteNonCachedFiles(icon_dir, cached_files);
645 } 640 }
646 641
642 // static
647 int JumpList::CreateIconFiles(const base::FilePath& icon_dir, 643 int JumpList::CreateIconFiles(const base::FilePath& icon_dir,
648 const ShellLinkItemList& item_list, 644 const ShellLinkItemList& item_list,
649 size_t max_items, 645 size_t max_items,
650 JumpListCategory category) { 646 URLIconCache* icon_cache) {
651 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. 647 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407.
652 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration"); 648 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration");
653 649
654 int icons_created = 0; 650 int icons_created = 0;
655 651
656 // Reuse icons for urls that were already present in the jumplist for this 652 // Reuse icons for urls that already present in the current JumpList.
657 // category. 653 URLIconCache updated_map;
658
659 base::flat_map<std::string, base::FilePath>* source_map = nullptr;
660 switch (category) {
661 case JumpListCategory::kMostVisited:
662 source_map = &most_visited_icons_;
663 break;
664 case JumpListCategory::kRecentlyClosed:
665 source_map = &recently_closed_icons_;
666 break;
667 }
668
669 base::flat_map<std::string, base::FilePath> updated_map;
670
671 for (ShellLinkItemList::const_iterator iter = item_list.begin(); 654 for (ShellLinkItemList::const_iterator iter = item_list.begin();
672 iter != item_list.end() && max_items > 0; ++iter, --max_items) { 655 iter != item_list.end() && max_items > 0; ++iter, --max_items) {
673 ShellLinkItem* item = iter->get(); 656 ShellLinkItem* item = iter->get();
674 auto cache_iter = source_map->find(item->url()); 657 auto cache_iter = icon_cache->find(item->url());
675 if (cache_iter != source_map->end()) { 658 if (cache_iter != icon_cache->end()) {
676 item->set_icon(cache_iter->second.value(), 0); 659 item->set_icon(cache_iter->second.value(), 0);
677 updated_map[item->url()] = cache_iter->second; 660 updated_map[item->url()] = cache_iter->second;
678 } else { 661 } else {
679 base::FilePath icon_path; 662 base::FilePath icon_path;
680 if (CreateIconFile(item->icon_image(), icon_dir, &icon_path)) { 663 if (CreateIconFile(item->icon_image(), icon_dir, &icon_path)) {
681 ++icons_created; 664 ++icons_created;
682 item->set_icon(icon_path.value(), 0); 665 item->set_icon(icon_path.value(), 0);
683 updated_map[item->url()] = icon_path; 666 updated_map[item->url()] = icon_path;
684 } 667 }
685 } 668 }
686 } 669 }
687 source_map->swap(updated_map); 670 icon_cache->swap(updated_map);
688 671
689 return icons_created; 672 return icons_created;
690 } 673 }
691 674
675 // static
692 int JumpList::UpdateIconFiles(const base::FilePath& icon_dir, 676 int JumpList::UpdateIconFiles(const base::FilePath& icon_dir,
693 const ShellLinkItemList& page_list, 677 const ShellLinkItemList& page_list,
694 size_t slot_limit, 678 size_t slot_limit,
695 JumpListCategory category) { 679 URLIconCache* icon_cache) {
696 int icons_created = 0; 680 int icons_created = 0;
697 681
698 // Maximum number of icon files that each JumpList icon folder may hold, which
699 // is set to 2 times the normal amount.
700 size_t icon_limit =
701 2 * ((category == JumpListCategory::kMostVisited) ? kMostVisitedItems
702 : kRecentlyClosedItems);
703
704 // Clear the JumpList icon folder at |icon_dir| and the cache when 682 // Clear the JumpList icon folder at |icon_dir| and the cache when
705 // 1) "Most visited" category updates for the 1st time after Chrome is 683 // 1) |icon_cache| is empty. This happens when "Most visited" or "Recently
706 // launched. This actually happens right after Chrome is launched. 684 // closed" category updates for the 1st time after Chrome is launched.
707 // 2) "Recently closed" category updates for the 1st time after Chrome is 685 // 2) The number of icons in |icon_dir| has exceeded the limit.
708 // launched. 686 if (icon_cache->empty() || FilesExceedLimitInDir(icon_dir, slot_limit * 2)) {
709 // 3) The number of icons in |icon_dir| has exceeded the limit.
710 if ((category == JumpListCategory::kMostVisited &&
711 most_visited_icons_.empty()) ||
712 (category == JumpListCategory::kRecentlyClosed &&
713 recently_closed_icons_.empty()) ||
714 FilesExceedLimitInDir(icon_dir, icon_limit)) {
715 DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit); 687 DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit);
716 most_visited_icons_.clear(); 688 icon_cache->clear();
717 recently_closed_icons_.clear();
718 // Create new icons only when the directory exists and is empty. 689 // Create new icons only when the directory exists and is empty.
719 if (base::CreateDirectory(icon_dir) && base::IsDirectoryEmpty(icon_dir)) 690 if (base::CreateDirectory(icon_dir) && base::IsDirectoryEmpty(icon_dir))
720 icons_created += 691 icons_created +=
721 CreateIconFiles(icon_dir, page_list, slot_limit, category); 692 CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache);
722 } else if (base::CreateDirectory(icon_dir)) { 693 } else if (base::CreateDirectory(icon_dir)) {
723 icons_created += CreateIconFiles(icon_dir, page_list, slot_limit, category); 694 icons_created +=
724 DeleteIconFiles(icon_dir, category); 695 CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache);
696 DeleteIconFiles(icon_dir, icon_cache);
725 } 697 }
726 698
727 return icons_created; 699 return icons_created;
728 } 700 }
729 701
730 bool JumpList::UpdateJumpList( 702 // static
703 void JumpList::RunUpdateJumpList(
731 const base::string16& app_id, 704 const base::string16& app_id,
732 const base::FilePath& profile_dir, 705 const base::FilePath& profile_dir,
733 const ShellLinkItemList& most_visited_pages, 706 const ShellLinkItemList& most_visited_pages,
734 const ShellLinkItemList& recently_closed_pages, 707 const ShellLinkItemList& recently_closed_pages,
735 bool most_visited_pages_have_updates, 708 bool most_visited_pages_have_updates,
736 bool recently_closed_pages_have_updates, 709 bool recently_closed_pages_have_updates,
737 IncognitoModePrefs::Availability incognito_availability) { 710 IncognitoModePrefs::Availability incognito_availability,
711 JumpListUpdateResults* update_results) {
738 if (!JumpListUpdater::IsEnabled()) 712 if (!JumpListUpdater::IsEnabled())
739 return true; 713 return;
714
715 DCHECK(update_results);
740 716
741 JumpListUpdater jumplist_updater(app_id); 717 JumpListUpdater jumplist_updater(app_id);
742 718
743 base::ElapsedTimer begin_update_timer; 719 base::ElapsedTimer begin_update_timer;
744 720
745 if (!jumplist_updater.BeginUpdate()) 721 if (!jumplist_updater.BeginUpdate()) {
746 return false; 722 update_results->update_success_ = false;
723 return;
724 }
747 725
748 // Discard this JumpList update if JumpListUpdater::BeginUpdate takes longer 726 // Discard this JumpList update if JumpListUpdater::BeginUpdate takes longer
749 // than the maximum allowed time, as it's very likely the following update 727 // than the maximum allowed time, as it's very likely the following update
750 // steps will also take a long time. As we've not updated the icons on the 728 // steps will also take a long time. As we've not updated the icons on the
751 // disk, discarding this update wont't affect the current JumpList used by OS. 729 // disk, discarding this update wont't affect the current JumpList used by OS.
752 if (begin_update_timer.Elapsed() >= kTimeOutForJumplistBeginUpdate) { 730 if (begin_update_timer.Elapsed() >= kTimeOutForJumplistBeginUpdate) {
753 updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad; 731 update_results->update_success_ = false;
754 return false; 732 update_results->update_timeout_ = true;
733 return;
755 } 734 }
756 735
757 // Record the desired number of icons created in this JumpList update. 736 // Record the desired number of icons created in this JumpList update.
758 int icons_created = 0; 737 int icons_created = 0;
759 738
760 // Update the icons for "Most Visisted" category of the JumpList if needed. 739 // Update the icons for "Most Visisted" category of the JumpList if needed.
761 if (most_visited_pages_have_updates) { 740 if (most_visited_pages_have_updates) {
762 base::FilePath icon_dir_most_visited = GenerateJumplistIconDirName( 741 base::FilePath icon_dir_most_visited = GenerateJumplistIconDirName(
763 profile_dir, FILE_PATH_LITERAL("MostVisited")); 742 profile_dir, FILE_PATH_LITERAL("MostVisited"));
764 743
765 icons_created += 744 icons_created += UpdateIconFiles(
766 UpdateIconFiles(icon_dir_most_visited, most_visited_pages, 745 icon_dir_most_visited, most_visited_pages, kMostVisitedItems,
767 kMostVisitedItems, JumpListCategory::kMostVisited); 746 &update_results->most_visited_icons_in_update_);
768 } 747 }
769 748
770 // Update the icons for "Recently Closed" category of the JumpList if needed. 749 // Update the icons for "Recently Closed" category of the JumpList if needed.
771 if (recently_closed_pages_have_updates) { 750 if (recently_closed_pages_have_updates) {
772 base::FilePath icon_dir_recent_closed = GenerateJumplistIconDirName( 751 base::FilePath icon_dir_recent_closed = GenerateJumplistIconDirName(
773 profile_dir, FILE_PATH_LITERAL("RecentClosed")); 752 profile_dir, FILE_PATH_LITERAL("RecentClosed"));
774 753
775 icons_created += UpdateIconFiles( 754 icons_created += UpdateIconFiles(
776 icon_dir_recent_closed, recently_closed_pages, kRecentlyClosedItems, 755 icon_dir_recent_closed, recently_closed_pages, kRecentlyClosedItems,
777 JumpListCategory::kRecentlyClosed); 756 &update_results->recently_closed_icons_in_update);
778 } 757 }
779 758
780 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. 759 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407.
781 UMA_HISTOGRAM_COUNTS_100("WinJumplist.CreateIconFilesCount", icons_created); 760 UMA_HISTOGRAM_COUNTS_100("WinJumplist.CreateIconFilesCount", icons_created);
782 761
783 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. 762 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407.
784 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.UpdateJumpListDuration"); 763 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.UpdateJumpListDuration");
785 764
786 base::ElapsedTimer add_custom_category_timer; 765 base::ElapsedTimer add_custom_category_timer;
787 766
788 // Update the "Most Visited" category of the JumpList if it exists. 767 // Update the "Most Visited" category of the JumpList if it exists.
789 // This update request is applied into the JumpList when we commit this 768 // This update request is applied into the JumpList when we commit this
790 // transaction. 769 // transaction.
791 if (!jumplist_updater.AddCustomCategory( 770 if (!jumplist_updater.AddCustomCategory(
792 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED), 771 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED),
793 most_visited_pages, kMostVisitedItems)) { 772 most_visited_pages, kMostVisitedItems)) {
794 return false; 773 update_results->update_success_ = false;
774 return;
795 } 775 }
796 776
797 // Update the "Recently Closed" category of the JumpList. 777 // Update the "Recently Closed" category of the JumpList.
798 if (!jumplist_updater.AddCustomCategory( 778 if (!jumplist_updater.AddCustomCategory(
799 l10n_util::GetStringUTF16(IDS_RECENTLY_CLOSED), recently_closed_pages, 779 l10n_util::GetStringUTF16(IDS_RECENTLY_CLOSED), recently_closed_pages,
800 kRecentlyClosedItems)) { 780 kRecentlyClosedItems)) {
801 return false; 781 update_results->update_success_ = false;
782 return;
802 } 783 }
803 784
804 // If JumpListUpdater::AddCustomCategory or JumpListUpdater::CommitUpdate 785 // If JumpListUpdater::AddCustomCategory or JumpListUpdater::CommitUpdate
805 // takes longer than the maximum allowed time, skip the next 786 // takes longer than the maximum allowed time, skip the next
806 // |kUpdatesToSkipUnderHeavyLoad| updates. This update should be finished 787 // |kUpdatesToSkipUnderHeavyLoad| updates. This update should be finished
807 // because we've already updated the icons on the disk. If discarding this 788 // because we've already updated the icons on the disk. If discarding this
808 // update from here, some items in the current JumpList may not have icons 789 // update from here, some items in the current JumpList may not have icons
809 // as they've been delete from the disk. In this case, the background color of 790 // as they've been delete from the disk. In this case, the background color of
810 // the JumpList panel is used instead, which doesn't look nice. 791 // the JumpList panel is used instead, which doesn't look nice.
811 792
812 if (add_custom_category_timer.Elapsed() >= kTimeOutForAddCustomCategory) 793 if (add_custom_category_timer.Elapsed() >= kTimeOutForAddCustomCategory)
813 updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad; 794 update_results->update_timeout_ = true;
814 795
815 // Update the "Tasks" category of the JumpList. 796 // Update the "Tasks" category of the JumpList.
816 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) 797 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) {
817 return false; 798 update_results->update_success_ = false;
799 return;
800 }
818 801
819 base::ElapsedTimer commit_update_timer; 802 base::ElapsedTimer commit_update_timer;
820 803
821 // Commit this transaction and send the updated JumpList to Windows. 804 // Commit this transaction and send the updated JumpList to Windows.
822 bool commit_result = jumplist_updater.CommitUpdate(); 805 if (!jumplist_updater.CommitUpdate())
806 update_results->update_success_ = false;
823 807
824 if (commit_update_timer.Elapsed() >= kTimeOutForJumplistCommitUpdate) 808 if (commit_update_timer.Elapsed() >= kTimeOutForJumplistCommitUpdate)
809 update_results->update_timeout_ = true;
810
811 return;
grt (UTC plus 2) 2017/06/09 10:42:57 omit
chengx 2017/06/10 05:56:17 Done.
812 }
813
814 void JumpList::OnRunUpdateCompletion(
815 std::unique_ptr<JumpListUpdateResults> update_results) {
816 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
817
818 // Update JumpList member variables based on the results from the update run
819 // just finished.
820 if (update_results->update_timeout_)
825 updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad; 821 updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad;
826 822
827 return commit_result; 823 if (update_results->update_success_) {
828 } 824 most_visited_icons_.swap(update_results->most_visited_icons_in_update_);
829 825 recently_closed_icons_.swap(
830 void JumpList::RunUpdateJumpList( 826 update_results->recently_closed_icons_in_update);
831 IncognitoModePrefs::Availability incognito_availability, 827 most_visited_pages_have_updates_ = false;
832 const base::string16& app_id, 828 recently_closed_pages_have_updates_ = false;
833 const base::FilePath& profile_dir,
834 base::RefCountedData<JumpListData>* ref_counted_data) {
835 JumpListData* data = &ref_counted_data->data;
836 ShellLinkItemList local_most_visited_pages;
837 ShellLinkItemList local_recently_closed_pages;
838 bool most_visited_pages_have_updates;
839 bool recently_closed_pages_have_updates;
840
841 {
842 base::AutoLock auto_lock(data->list_lock_);
843 // Make sure we are not out of date: if icon_urls_ is not empty, then
844 // another notification has been received since we processed this one
845 if (!data->icon_urls_.empty())
846 return;
847
848 // Make local copies of lists and flags so we can release the lock.
849 local_most_visited_pages = data->most_visited_pages_;
850 local_recently_closed_pages = data->recently_closed_pages_;
851
852 most_visited_pages_have_updates = data->most_visited_pages_have_updates_;
853 recently_closed_pages_have_updates =
854 data->recently_closed_pages_have_updates_;
855
856 // Clear the flags to reflect that we'll take actions on these updates.
857 data->most_visited_pages_have_updates_ = false;
858 data->recently_closed_pages_have_updates_ = false;
859 } 829 }
860 830
861 if (!most_visited_pages_have_updates && !recently_closed_pages_have_updates) 831 update_in_progress_ = false;
862 return;
863 832
864 // Update the application JumpList. If it fails, reset the flags to true if 833 // Start another JumpList update if there is any new notification during the
865 // they were so that the corresponding JumpList categories will be tried to 834 // update run just finished.
866 // update again in the next run. 835 if (most_visited_has_pending_notification_ ||
867 if (!UpdateJumpList( 836 recently_closed_has_pending_notification_) {
868 app_id, profile_dir, local_most_visited_pages, 837 if (timer_.IsRunning()) {
869 local_recently_closed_pages, most_visited_pages_have_updates, 838 timer_.Reset();
870 recently_closed_pages_have_updates, incognito_availability)) { 839 } else {
871 base::AutoLock auto_lock(data->list_lock_); 840 timer_.Start(
872 if (most_visited_pages_have_updates) 841 FROM_HERE, kDelayForJumplistUpdate,
873 data->most_visited_pages_have_updates_ = true; 842 base::Bind(&JumpList::DeferredChanged, base::Unretained(this)));
874 if (recently_closed_pages_have_updates) 843 }
875 data->recently_closed_pages_have_updates_ = true;
876 } 844 }
845
846 return;
877 } 847 }
OLDNEW
« chrome/browser/win/jumplist.h ('K') | « chrome/browser/win/jumplist.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698