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

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

Issue 2563483004: Add more detailed JumpListIcons folder's move operation metric to UMA (Closed)
Patch Set: Mark the old histogram as <obselete> Created 4 years 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
« no previous file with comments | « chrome/browser/win/jumplist.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | 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/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/files/file_util.h" 10 #include "base/files/file_util.h"
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 using JumpListData = JumpList::JumpListData; 52 using JumpListData = JumpList::JumpListData;
53 53
54 namespace { 54 namespace {
55 55
56 // Delay jumplist updates to allow collapsing of redundant update requests. 56 // Delay jumplist updates to allow collapsing of redundant update requests.
57 const int kDelayForJumplistUpdateInMS = 3500; 57 const int kDelayForJumplistUpdateInMS = 3500;
58 58
59 // JumpList folder's move operation status. 59 // JumpList folder's move operation status.
60 enum MoveOperationResult { 60 enum MoveOperationResult {
61 SUCCESS = 0, 61 SUCCESS = 0,
62 MAX_PATH_CHECK_FAILED = 1 << 0, 62 MOVE_FILE_EX_FAILED = 1 << 0,
63 MOVE_FILE_EX_FAILED = 1 << 1, 63 COPY_FILE_FAILED = 1 << 1,
64 COPY_AND_DELETE_DIR_FAILED = 1 << 2, 64 DELETE_FILE_RECURSIVE_FAILED = 1 << 2,
65 DELETE_FAILED = 1 << 3, 65 DELETE_SOURCE_FOLDER_FAILED = 1 << 3,
66 END = 1 << 4 66 DELETE_TARGET_FOLDER_FAILED = 1 << 4,
67 END = 1 << 5
67 }; 68 };
68 69
69 // Append the common switches to each shell link. 70 // Append the common switches to each shell link.
70 void AppendCommonSwitches(ShellLinkItem* shell_link) { 71 void AppendCommonSwitches(ShellLinkItem* shell_link) {
71 const char* kSwitchNames[] = { switches::kUserDataDir }; 72 const char* kSwitchNames[] = { switches::kUserDataDir };
72 const base::CommandLine& command_line = 73 const base::CommandLine& command_line =
73 *base::CommandLine::ForCurrentProcess(); 74 *base::CommandLine::ForCurrentProcess();
74 shell_link->GetCommandLine()->CopySwitchesFrom(command_line, 75 shell_link->GetCommandLine()->CopySwitchesFrom(command_line,
75 kSwitchNames, 76 kSwitchNames,
76 arraysize(kSwitchNames)); 77 arraysize(kSwitchNames));
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 219
219 // Commit this transaction and send the updated JumpList to Windows. 220 // Commit this transaction and send the updated JumpList to Windows.
220 if (!jumplist_updater.CommitUpdate()) 221 if (!jumplist_updater.CommitUpdate())
221 return false; 222 return false;
222 223
223 return true; 224 return true;
224 } 225 }
225 226
226 // A wrapper function for recording UMA histogram. 227 // A wrapper function for recording UMA histogram.
227 void RecordFolderMoveResult(int move_operation_status) { 228 void RecordFolderMoveResult(int move_operation_status) {
228 UMA_HISTOGRAM_ENUMERATION("WinJumplist.FolderMoveResults", 229 UMA_HISTOGRAM_ENUMERATION("WinJumplist.DetailedFolderMoveResults",
229 move_operation_status, MoveOperationResult::END); 230 move_operation_status, MoveOperationResult::END);
230 } 231 }
231 232
233 // This function is mostly copied from //base for UMA debugging purpose.
gab 2016/12/09 19:12:12 // This function is an exact copy of the one in //
chengx 2016/12/09 21:36:30 Yes, you are right. It is an exact copy. I copy it
234 // Deletes all files and directories in a path.
235 // Returns false on the first failure it encounters.
236 bool DeleteFileRecursive(const base::FilePath& path,
237 const base::FilePath::StringType& pattern,
238 bool recursive) {
239 base::FileEnumerator traversal(
240 path, false,
241 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES, pattern);
242 for (base::FilePath current = traversal.Next(); !current.empty();
243 current = traversal.Next()) {
244 // Try to clear the read-only bit if we find it.
245 base::FileEnumerator::FileInfo info = traversal.GetInfo();
246 if ((info.find_data().dwFileAttributes & FILE_ATTRIBUTE_READONLY) &&
247 (recursive || !info.IsDirectory())) {
248 SetFileAttributes(
249 current.value().c_str(),
250 info.find_data().dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
251 }
252
253 if (info.IsDirectory()) {
254 if (recursive && (!DeleteFileRecursive(current, pattern, true) ||
255 !RemoveDirectory(current.value().c_str())))
256 return false;
257 } else if (!::DeleteFile(current.value().c_str())) {
258 return false;
259 }
260 }
261 return true;
262 }
263
264 // This function is mostly copied from //base for UMA debugging purpose.
gab 2016/12/09 19:12:12 // This function is a copy of the one in //base au
chengx 2016/12/09 21:36:31 Done.
265 // Deletes all files and directories in a path.
266 // Returns false on the first failure it encounters.
267 bool DeleteFileTemp(const base::FilePath& path,
gab 2016/12/09 19:12:12 naming this "DeleteFile" is fine IMO, it won't be
chengx 2016/12/09 21:36:30 Done.
268 bool recursive,
269 int* move_operation_status) {
270 base::ThreadRestrictions::AssertIOAllowed();
271
272 if (path.empty())
273 return true;
274
275 if (path.value().length() >= MAX_PATH)
276 return false;
277
278 // Handle any path with wildcards.
279 if (path.BaseName().value().find_first_of(L"*?") !=
280 base::FilePath::StringType::npos) {
281 return DeleteFileRecursive(path.DirName(), path.BaseName().value(),
gab 2016/12/09 19:12:12 Not worried about this failing?
chengx 2016/12/09 21:36:31 I don't think it will be hit in my case. But I add
282 recursive);
283 }
284 DWORD attr = GetFileAttributes(path.value().c_str());
285 // We're done if we can't find the path.
286 if (attr == INVALID_FILE_ATTRIBUTES)
287 return true;
288 // We may need to clear the read-only bit.
289 if ((attr & FILE_ATTRIBUTE_READONLY) &&
290 !SetFileAttributes(path.value().c_str(),
gab 2016/12/09 19:12:12 Since we now have methods in file scope, some in b
chengx 2016/12/09 21:36:31 Done.
291 attr & ~FILE_ATTRIBUTE_READONLY)) {
292 return false;
gab 2016/12/09 19:12:12 Not worried about this failing?
chengx 2016/12/09 21:36:30 Just added UMA for this. Thanks for reminder.
293 }
294 // Directories are handled differently if they're recursive.
295 if (!(attr & FILE_ATTRIBUTE_DIRECTORY))
296 return !!::DeleteFile(path.value().c_str());
gab 2016/12/09 19:12:12 #include <windows.h> for ::DeleteFile() and other
chengx 2016/12/09 21:36:31 Done.
297 // Handle a simple, single file delete.
298 if (!recursive || DeleteFileRecursive(path, L"*", true)) {
299 bool ret = !!RemoveDirectory(path.value().c_str());
300 if (!ret)
301 *move_operation_status |=
302 MoveOperationResult::DELETE_SOURCE_FOLDER_FAILED;
303 return ret;
304 }
305
306 *move_operation_status |= MoveOperationResult::DELETE_FILE_RECURSIVE_FAILED;
307 *move_operation_status |= MoveOperationResult::DELETE_SOURCE_FOLDER_FAILED;
308 return false;
309 }
310
232 // This function is a temporary fork of Move() and MoveUnsafe() in 311 // This function is a temporary fork of Move() and MoveUnsafe() in
233 // base/files/file_util.h, where UMA functions are added to gather user data. 312 // base/files/file_util.h, where UMA functions are added to gather user data.
234 // As //base is highly mature, we tend not to add this temporary function 313 // As //base is highly mature, we tend not to add this temporary function
235 // in it. This change will be reverted after user data gathered. 314 // in it. This change will be reverted after user data gathered.
236 bool MoveDebugWithUMA(const base::FilePath& from_path, 315 bool MoveDebugWithUMA(const base::FilePath& from_path,
237 const base::FilePath& to_path, 316 const base::FilePath& to_path,
238 int folder_delete_fail) { 317 int folder_delete_fail) {
239 if (from_path.ReferencesParent() || to_path.ReferencesParent()) 318 if (from_path.ReferencesParent() || to_path.ReferencesParent())
240 return false; 319 return false;
241 320
242 base::ThreadRestrictions::AssertIOAllowed(); 321 base::ThreadRestrictions::AssertIOAllowed();
243 322
244 // This variable records the status of move operations. 323 // This variable records the status of move operations.
245 int move_operation_status = MoveOperationResult::SUCCESS; 324 int move_operation_status = MoveOperationResult::SUCCESS;
246 if (folder_delete_fail) 325 if (folder_delete_fail)
247 move_operation_status |= MoveOperationResult::DELETE_FAILED; 326 move_operation_status |= MoveOperationResult::DELETE_TARGET_FOLDER_FAILED;
248 327
249 // NOTE: I suspect we could support longer paths, but that would involve 328 // NOTE: I suspect we could support longer paths, but that would involve
250 // analyzing all our usage of files. 329 // analyzing all our usage of files.
251 if (from_path.value().length() >= MAX_PATH || 330 if (from_path.value().length() >= MAX_PATH ||
252 to_path.value().length() >= MAX_PATH) { 331 to_path.value().length() >= MAX_PATH) {
253 move_operation_status |= MoveOperationResult::MAX_PATH_CHECK_FAILED;
254 RecordFolderMoveResult(move_operation_status);
255 return false; 332 return false;
256 } 333 }
257 if (MoveFileEx(from_path.value().c_str(), to_path.value().c_str(), 334 if (MoveFileEx(from_path.value().c_str(), to_path.value().c_str(),
258 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) != 0) { 335 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) != 0) {
259 RecordFolderMoveResult(move_operation_status); 336 RecordFolderMoveResult(move_operation_status);
260 return true; 337 return true;
261 } 338 }
262 339
263 move_operation_status |= MoveOperationResult::MOVE_FILE_EX_FAILED; 340 move_operation_status |= MoveOperationResult::MOVE_FILE_EX_FAILED;
264 341
265 // Keep the last error value from MoveFileEx around in case the below 342 // Keep the last error value from MoveFileEx around in case the below
266 // fails. 343 // fails.
267 bool ret = false; 344 bool ret = false;
268 DWORD last_error = ::GetLastError(); 345 DWORD last_error = ::GetLastError();
269 346
270 if (base::DirectoryExists(from_path)) { 347 if (base::DirectoryExists(from_path)) {
271 // MoveFileEx fails if moving directory across volumes. We will simulate 348 // MoveFileEx fails if moving directory across volumes. We will simulate
272 // the move by using Copy and Delete. Ideally we could check whether 349 // the move by using Copy and Delete. Ideally we could check whether
273 // from_path and to_path are indeed in different volumes. 350 // from_path and to_path are indeed in different volumes.
274 ret = base::internal::CopyAndDeleteDirectory(from_path, to_path); 351 if (base::CopyDirectory(from_path, to_path, true)) {
352 if (DeleteFileTemp(from_path, true, &move_operation_status))
353 ret = true;
354 } else {
355 move_operation_status |= MoveOperationResult::COPY_FILE_FAILED;
gab 2016/12/09 19:12:13 This is copying a directory, not a "file", right?
chengx 2016/12/09 21:36:31 Yes, you are right.
356 move_operation_status |=
357 MoveOperationResult::DELETE_FILE_RECURSIVE_FAILED;
358 move_operation_status |= MoveOperationResult::DELETE_SOURCE_FOLDER_FAILED;
359 }
275 } 360 }
276 361
277 if (!ret) { 362 if (!ret) {
278 // Leave a clue about what went wrong so that it can be (at least) picked 363 // Leave a clue about what went wrong so that it can be (at least) picked
279 // up by a PLOG entry. 364 // up by a PLOG entry.
280 ::SetLastError(last_error); 365 ::SetLastError(last_error);
281 move_operation_status |= MoveOperationResult::COPY_AND_DELETE_DIR_FAILED;
282 } 366 }
283 367
284 RecordFolderMoveResult(move_operation_status); 368 RecordFolderMoveResult(move_operation_status);
285 369
286 return ret; 370 return ret;
287 } 371 }
288 372
289 // Updates the jumplist, once all the data has been fetched. 373 // Updates the jumplist, once all the data has been fetched.
290 void RunUpdateOnFileThread( 374 void RunUpdateOnFileThread(
291 IncognitoModePrefs::Availability incognito_availability, 375 IncognitoModePrefs::Availability incognito_availability,
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after
671 void JumpList::TopSitesLoaded(history::TopSites* top_sites) { 755 void JumpList::TopSitesLoaded(history::TopSites* top_sites) {
672 } 756 }
673 757
674 void JumpList::TopSitesChanged(history::TopSites* top_sites, 758 void JumpList::TopSitesChanged(history::TopSites* top_sites,
675 ChangeReason change_reason) { 759 ChangeReason change_reason) {
676 top_sites->GetMostVisitedURLs( 760 top_sites->GetMostVisitedURLs(
677 base::Bind(&JumpList::OnMostVisitedURLsAvailable, 761 base::Bind(&JumpList::OnMostVisitedURLsAvailable,
678 weak_ptr_factory_.GetWeakPtr()), 762 weak_ptr_factory_.GetWeakPtr()),
679 false); 763 false);
680 } 764 }
OLDNEW
« no previous file with comments | « chrome/browser/win/jumplist.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698