blob: e27afc3b57ae8dfdd5a6f6dd99f5ec17f06ccf43 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/download/public/common//download_stats.h"
#include <map>
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
#include "components/download/public/common/download_interrupt_reasons.h"
#include "net/http/http_content_disposition.h"
#include "net/http/http_util.h"
namespace download {
namespace {
// The maximium value for download deletion retention time histogram.
const int kMaxDeletionRetentionHours = 720;
// All possible error codes from the network module. Note that the error codes
// are all positive (since histograms expect positive sample values).
const int kAllInterruptReasonCodes[] = {
#define INTERRUPT_REASON(label, value) (value),
#include "components/download/public/common/download_interrupt_reason_values.h"
#undef INTERRUPT_REASON
};
// These values are based on net::HttpContentDisposition::ParseResult values.
// Values other than HEADER_PRESENT and IS_VALID are only measured if |IS_VALID|
// is true.
enum ContentDispositionCountTypes {
// Count of downloads which had a Content-Disposition headers. The total
// number of downloads is measured by UNTHROTTLED_COUNT.
CONTENT_DISPOSITION_HEADER_PRESENT = 0,
// Either 'filename' or 'filename*' attributes were valid and
// yielded a non-empty filename.
CONTENT_DISPOSITION_IS_VALID,
// The following enum values correspond to
// net::HttpContentDisposition::ParseResult.
CONTENT_DISPOSITION_HAS_DISPOSITION_TYPE,
CONTENT_DISPOSITION_HAS_UNKNOWN_TYPE,
CONTENT_DISPOSITION_HAS_NAME, // Obsolete; kept for UMA compatiblity.
CONTENT_DISPOSITION_HAS_FILENAME,
CONTENT_DISPOSITION_HAS_EXT_FILENAME,
CONTENT_DISPOSITION_HAS_NON_ASCII_STRINGS,
CONTENT_DISPOSITION_HAS_PERCENT_ENCODED_STRINGS,
CONTENT_DISPOSITION_HAS_RFC2047_ENCODED_STRINGS,
CONTENT_DISPOSITION_HAS_NAME_ONLY, // Obsolete; kept for UMA compatiblity.
CONTENT_DISPOSITION_LAST_ENTRY
};
void RecordContentDispositionCount(ContentDispositionCountTypes type,
bool record) {
if (!record)
return;
UMA_HISTOGRAM_ENUMERATION("Download.ContentDisposition", type,
CONTENT_DISPOSITION_LAST_ENTRY);
}
void RecordContentDispositionCountFlag(
ContentDispositionCountTypes type,
int flags_to_test,
net::HttpContentDisposition::ParseResultFlags flag) {
RecordContentDispositionCount(type, (flags_to_test & flag) == flag);
}
// Do not insert, delete, or reorder; this is being histogrammed. Append only.
// All of the download_file_types.asciipb entries should be in this list.
// TODO(asanka): Replace this enum with calls to FileTypePolicies and move the
// UMA metrics for dangerous/malicious downloads to //chrome/browser/download.
constexpr const base::FilePath::CharType* kDangerousFileTypes[] = {
FILE_PATH_LITERAL(".ad"), FILE_PATH_LITERAL(".ade"),
FILE_PATH_LITERAL(".adp"), FILE_PATH_LITERAL(".ah"),
FILE_PATH_LITERAL(".apk"), FILE_PATH_LITERAL(".app"),
FILE_PATH_LITERAL(".application"), FILE_PATH_LITERAL(".asp"),
FILE_PATH_LITERAL(".asx"), FILE_PATH_LITERAL(".bas"),
FILE_PATH_LITERAL(".bash"), FILE_PATH_LITERAL(".bat"),
FILE_PATH_LITERAL(".cfg"), FILE_PATH_LITERAL(".chi"),
FILE_PATH_LITERAL(".chm"), FILE_PATH_LITERAL(".class"),
FILE_PATH_LITERAL(".cmd"), FILE_PATH_LITERAL(".com"),
FILE_PATH_LITERAL(".command"), FILE_PATH_LITERAL(".crt"),
FILE_PATH_LITERAL(".crx"), FILE_PATH_LITERAL(".csh"),
FILE_PATH_LITERAL(".deb"), FILE_PATH_LITERAL(".dex"),
FILE_PATH_LITERAL(".dll"), FILE_PATH_LITERAL(".drv"),
FILE_PATH_LITERAL(".exe"), FILE_PATH_LITERAL(".fxp"),
FILE_PATH_LITERAL(".grp"), FILE_PATH_LITERAL(".hlp"),
FILE_PATH_LITERAL(".hta"), FILE_PATH_LITERAL(".htm"),
FILE_PATH_LITERAL(".html"), FILE_PATH_LITERAL(".htt"),
FILE_PATH_LITERAL(".inf"), FILE_PATH_LITERAL(".ini"),
FILE_PATH_LITERAL(".ins"), FILE_PATH_LITERAL(".isp"),
FILE_PATH_LITERAL(".jar"), FILE_PATH_LITERAL(".jnlp"),
FILE_PATH_LITERAL(".user.js"), FILE_PATH_LITERAL(".js"),
FILE_PATH_LITERAL(".jse"), FILE_PATH_LITERAL(".ksh"),
FILE_PATH_LITERAL(".lnk"), FILE_PATH_LITERAL(".local"),
FILE_PATH_LITERAL(".mad"), FILE_PATH_LITERAL(".maf"),
FILE_PATH_LITERAL(".mag"), FILE_PATH_LITERAL(".mam"),
FILE_PATH_LITERAL(".manifest"), FILE_PATH_LITERAL(".maq"),
FILE_PATH_LITERAL(".mar"), FILE_PATH_LITERAL(".mas"),
FILE_PATH_LITERAL(".mat"), FILE_PATH_LITERAL(".mau"),
FILE_PATH_LITERAL(".mav"), FILE_PATH_LITERAL(".maw"),
FILE_PATH_LITERAL(".mda"), FILE_PATH_LITERAL(".mdb"),
FILE_PATH_LITERAL(".mde"), FILE_PATH_LITERAL(".mdt"),
FILE_PATH_LITERAL(".mdw"), FILE_PATH_LITERAL(".mdz"),
FILE_PATH_LITERAL(".mht"), FILE_PATH_LITERAL(".mhtml"),
FILE_PATH_LITERAL(".mmc"), FILE_PATH_LITERAL(".mof"),
FILE_PATH_LITERAL(".msc"), FILE_PATH_LITERAL(".msh"),
FILE_PATH_LITERAL(".mshxml"), FILE_PATH_LITERAL(".msi"),
FILE_PATH_LITERAL(".msp"), FILE_PATH_LITERAL(".mst"),
FILE_PATH_LITERAL(".ocx"), FILE_PATH_LITERAL(".ops"),
FILE_PATH_LITERAL(".pcd"), FILE_PATH_LITERAL(".pif"),
FILE_PATH_LITERAL(".pkg"), FILE_PATH_LITERAL(".pl"),
FILE_PATH_LITERAL(".plg"), FILE_PATH_LITERAL(".prf"),
FILE_PATH_LITERAL(".prg"), FILE_PATH_LITERAL(".pst"),
FILE_PATH_LITERAL(".py"), FILE_PATH_LITERAL(".pyc"),
FILE_PATH_LITERAL(".pyw"), FILE_PATH_LITERAL(".rb"),
FILE_PATH_LITERAL(".reg"), FILE_PATH_LITERAL(".rpm"),
FILE_PATH_LITERAL(".scf"), FILE_PATH_LITERAL(".scr"),
FILE_PATH_LITERAL(".sct"), FILE_PATH_LITERAL(".sh"),
FILE_PATH_LITERAL(".shar"), FILE_PATH_LITERAL(".shb"),
FILE_PATH_LITERAL(".shs"), FILE_PATH_LITERAL(".shtm"),
FILE_PATH_LITERAL(".shtml"), FILE_PATH_LITERAL(".spl"),
FILE_PATH_LITERAL(".svg"), FILE_PATH_LITERAL(".swf"),
FILE_PATH_LITERAL(".sys"), FILE_PATH_LITERAL(".tcsh"),
FILE_PATH_LITERAL(".url"), FILE_PATH_LITERAL(".vb"),
FILE_PATH_LITERAL(".vbe"), FILE_PATH_LITERAL(".vbs"),
FILE_PATH_LITERAL(".vsd"), FILE_PATH_LITERAL(".vsmacros"),
FILE_PATH_LITERAL(".vss"), FILE_PATH_LITERAL(".vst"),
FILE_PATH_LITERAL(".vsw"), FILE_PATH_LITERAL(".ws"),
FILE_PATH_LITERAL(".wsc"), FILE_PATH_LITERAL(".wsf"),
FILE_PATH_LITERAL(".wsh"), FILE_PATH_LITERAL(".xbap"),
FILE_PATH_LITERAL(".xht"), FILE_PATH_LITERAL(".xhtm"),
FILE_PATH_LITERAL(".xhtml"), FILE_PATH_LITERAL(".xml"),
FILE_PATH_LITERAL(".xsl"), FILE_PATH_LITERAL(".xslt"),
FILE_PATH_LITERAL(".website"), FILE_PATH_LITERAL(".msh1"),
FILE_PATH_LITERAL(".msh2"), FILE_PATH_LITERAL(".msh1xml"),
FILE_PATH_LITERAL(".msh2xml"), FILE_PATH_LITERAL(".ps1"),
FILE_PATH_LITERAL(".ps1xml"), FILE_PATH_LITERAL(".ps2"),
FILE_PATH_LITERAL(".ps2xml"), FILE_PATH_LITERAL(".psc1"),
FILE_PATH_LITERAL(".psc2"), FILE_PATH_LITERAL(".xnk"),
FILE_PATH_LITERAL(".appref-ms"), FILE_PATH_LITERAL(".gadget"),
FILE_PATH_LITERAL(".efi"), FILE_PATH_LITERAL(".fon"),
FILE_PATH_LITERAL(".partial"), FILE_PATH_LITERAL(".svg"),
FILE_PATH_LITERAL(".xml"), FILE_PATH_LITERAL(".xrm_ms"),
FILE_PATH_LITERAL(".xsl"), FILE_PATH_LITERAL(".action"),
FILE_PATH_LITERAL(".bin"), FILE_PATH_LITERAL(".inx"),
FILE_PATH_LITERAL(".ipa"), FILE_PATH_LITERAL(".isu"),
FILE_PATH_LITERAL(".job"), FILE_PATH_LITERAL(".out"),
FILE_PATH_LITERAL(".pad"), FILE_PATH_LITERAL(".paf"),
FILE_PATH_LITERAL(".rgs"), FILE_PATH_LITERAL(".u3p"),
FILE_PATH_LITERAL(".vbscript"), FILE_PATH_LITERAL(".workflow"),
FILE_PATH_LITERAL(".001"), FILE_PATH_LITERAL(".7z"),
FILE_PATH_LITERAL(".ace"), FILE_PATH_LITERAL(".arc"),
FILE_PATH_LITERAL(".arj"), FILE_PATH_LITERAL(".b64"),
FILE_PATH_LITERAL(".balz"), FILE_PATH_LITERAL(".bhx"),
FILE_PATH_LITERAL(".bz"), FILE_PATH_LITERAL(".bz2"),
FILE_PATH_LITERAL(".bzip2"), FILE_PATH_LITERAL(".cab"),
FILE_PATH_LITERAL(".cpio"), FILE_PATH_LITERAL(".fat"),
FILE_PATH_LITERAL(".gz"), FILE_PATH_LITERAL(".gzip"),
FILE_PATH_LITERAL(".hfs"), FILE_PATH_LITERAL(".hqx"),
FILE_PATH_LITERAL(".iso"), FILE_PATH_LITERAL(".lha"),
FILE_PATH_LITERAL(".lpaq1"), FILE_PATH_LITERAL(".lpaq5"),
FILE_PATH_LITERAL(".lpaq8"), FILE_PATH_LITERAL(".lzh"),
FILE_PATH_LITERAL(".lzma"), FILE_PATH_LITERAL(".mim"),
FILE_PATH_LITERAL(".ntfs"), FILE_PATH_LITERAL(".paq8f"),
FILE_PATH_LITERAL(".paq8jd"), FILE_PATH_LITERAL(".paq8l"),
FILE_PATH_LITERAL(".paq8o"), FILE_PATH_LITERAL(".pea"),
FILE_PATH_LITERAL(".quad"), FILE_PATH_LITERAL(".r00"),
FILE_PATH_LITERAL(".r01"), FILE_PATH_LITERAL(".r02"),
FILE_PATH_LITERAL(".r03"), FILE_PATH_LITERAL(".r04"),
FILE_PATH_LITERAL(".r05"), FILE_PATH_LITERAL(".r06"),
FILE_PATH_LITERAL(".r07"), FILE_PATH_LITERAL(".r08"),
FILE_PATH_LITERAL(".r09"), FILE_PATH_LITERAL(".r10"),
FILE_PATH_LITERAL(".r11"), FILE_PATH_LITERAL(".r12"),
FILE_PATH_LITERAL(".r13"), FILE_PATH_LITERAL(".r14"),
FILE_PATH_LITERAL(".r15"), FILE_PATH_LITERAL(".r16"),
FILE_PATH_LITERAL(".r17"), FILE_PATH_LITERAL(".r18"),
FILE_PATH_LITERAL(".r19"), FILE_PATH_LITERAL(".r20"),
FILE_PATH_LITERAL(".r21"), FILE_PATH_LITERAL(".r22"),
FILE_PATH_LITERAL(".r23"), FILE_PATH_LITERAL(".r24"),
FILE_PATH_LITERAL(".r25"), FILE_PATH_LITERAL(".r26"),
FILE_PATH_LITERAL(".r27"), FILE_PATH_LITERAL(".r28"),
FILE_PATH_LITERAL(".r29"), FILE_PATH_LITERAL(".rar"),
FILE_PATH_LITERAL(".squashfs"), FILE_PATH_LITERAL(".swm"),
FILE_PATH_LITERAL(".tar"), FILE_PATH_LITERAL(".taz"),
FILE_PATH_LITERAL(".tbz"), FILE_PATH_LITERAL(".tbz2"),
FILE_PATH_LITERAL(".tgz"), FILE_PATH_LITERAL(".tpz"),
FILE_PATH_LITERAL(".txz"), FILE_PATH_LITERAL(".tz"),
FILE_PATH_LITERAL(".udf"), FILE_PATH_LITERAL(".uu"),
FILE_PATH_LITERAL(".uue"), FILE_PATH_LITERAL(".vhd"),
FILE_PATH_LITERAL(".vmdk"), FILE_PATH_LITERAL(".wim"),
FILE_PATH_LITERAL(".wrc"), FILE_PATH_LITERAL(".xar"),
FILE_PATH_LITERAL(".xxe"), FILE_PATH_LITERAL(".xz"),
FILE_PATH_LITERAL(".z"), FILE_PATH_LITERAL(".zip"),
FILE_PATH_LITERAL(".zipx"), FILE_PATH_LITERAL(".zpaq"),
FILE_PATH_LITERAL(".cdr"), FILE_PATH_LITERAL(".dart"),
FILE_PATH_LITERAL(".dc42"), FILE_PATH_LITERAL(".diskcopy42"),
FILE_PATH_LITERAL(".dmg"), FILE_PATH_LITERAL(".dmgpart"),
FILE_PATH_LITERAL(".dvdr"), FILE_PATH_LITERAL(".img"),
FILE_PATH_LITERAL(".imgpart"), FILE_PATH_LITERAL(".ndif"),
FILE_PATH_LITERAL(".smi"), FILE_PATH_LITERAL(".sparsebundle"),
FILE_PATH_LITERAL(".sparseimage"), FILE_PATH_LITERAL(".toast"),
FILE_PATH_LITERAL(".udif"), FILE_PATH_LITERAL(".run"), // 262
FILE_PATH_LITERAL(".mpkg"), FILE_PATH_LITERAL(".as"), // 264
FILE_PATH_LITERAL(".cpgz"), FILE_PATH_LITERAL(".pax"), // 266
FILE_PATH_LITERAL(".xip"), FILE_PATH_LITERAL(".docx"), // 268
FILE_PATH_LITERAL(".docm"), FILE_PATH_LITERAL(".dott"), // 270
FILE_PATH_LITERAL(".dotm"), FILE_PATH_LITERAL(".docb"), // 272
FILE_PATH_LITERAL(".xlsx"), FILE_PATH_LITERAL(".xlsm"), // 274
FILE_PATH_LITERAL(".xltx"), FILE_PATH_LITERAL(".xltm"), // 276
FILE_PATH_LITERAL(".pptx"), FILE_PATH_LITERAL(".pptm"), // 278
FILE_PATH_LITERAL(".potx"), FILE_PATH_LITERAL(".ppam"), // 280
FILE_PATH_LITERAL(".ppsx"), FILE_PATH_LITERAL(".sldx"), // 282
FILE_PATH_LITERAL(".sldm"), FILE_PATH_LITERAL(".htm"), // 284
FILE_PATH_LITERAL(".html"), FILE_PATH_LITERAL(".xht"), // 286
FILE_PATH_LITERAL(".xhtm"), FILE_PATH_LITERAL(".xhtml"), // 288
FILE_PATH_LITERAL(".vdx"), FILE_PATH_LITERAL(".vsx"), // 290
FILE_PATH_LITERAL(".vtx"), FILE_PATH_LITERAL(".vsdx"), // 292
FILE_PATH_LITERAL(".vssx"), FILE_PATH_LITERAL(".vstx"), // 294
FILE_PATH_LITERAL(".vsdm"), FILE_PATH_LITERAL(".vssm"), // 296
FILE_PATH_LITERAL(".vstm"), FILE_PATH_LITERAL(".btapp"), // 298
FILE_PATH_LITERAL(".btskin"), FILE_PATH_LITERAL(".btinstall"), // 300
FILE_PATH_LITERAL(".btkey"), FILE_PATH_LITERAL(".btsearch"), // 302
FILE_PATH_LITERAL(".dhtml"), FILE_PATH_LITERAL(".dhtm"), // 304
FILE_PATH_LITERAL(".dht"), FILE_PATH_LITERAL(".shtml"), // 306
FILE_PATH_LITERAL(".shtm"), FILE_PATH_LITERAL(".sht"), // 308
FILE_PATH_LITERAL(".slk"), // 309
FILE_PATH_LITERAL(".applescript"), FILE_PATH_LITERAL(".scpt"), // 311
FILE_PATH_LITERAL(".scptd"), FILE_PATH_LITERAL(".seplugin"), // 313
FILE_PATH_LITERAL(".osas"), FILE_PATH_LITERAL(".osax"), // 315
FILE_PATH_LITERAL(".settingcontent-ms"), // 316
// NOTE! When you add a type here, please add the UMA value as a comment.
// These must all match DownloadItem.DangerousFileType in
// enums.xml. From 263 onward, they should also match
// SBClientDownloadExtensions.
};
// The maximum size in KB for the file size metric, file size larger than this
// will be kept in overflow bucket.
const int64_t kMaxFileSizeKb = 4 * 1024 * 1024; /* 4GB. */
const int64_t kHighBandwidthBytesPerSecond = 30 * 1024 * 1024;
// Maps extensions to their matching UMA histogram int value.
int GetDangerousFileType(const base::FilePath& file_path) {
for (size_t i = 0; i < arraysize(kDangerousFileTypes); ++i) {
if (file_path.MatchesExtension(kDangerousFileTypes[i]))
return i + 1;
}
return 0; // Unknown extension.
}
// Helper method to calculate the bandwidth given the data length and time.
int64_t CalculateBandwidthBytesPerSecond(size_t length,
base::TimeDelta elapsed_time) {
int64_t elapsed_time_ms = elapsed_time.InMilliseconds();
if (0 == elapsed_time_ms)
elapsed_time_ms = 1;
return 1000 * static_cast<int64_t>(length) / elapsed_time_ms;
}
// Helper method to record the bandwidth for a given metric.
void RecordBandwidthMetric(const std::string& metric, int bandwidth) {
base::UmaHistogramCustomCounts(metric, bandwidth, 1, 50 * 1000 * 1000, 50);
}
// Records a histogram with download source suffix.
std::string CreateHistogramNameWithSuffix(const std::string& name,
DownloadSource download_source) {
std::string suffix;
switch (download_source) {
case DownloadSource::UNKNOWN:
suffix = "UnknownSource";
break;
case DownloadSource::NAVIGATION:
suffix = "Navigation";
break;
case DownloadSource::DRAG_AND_DROP:
suffix = "DragAndDrop";
break;
case DownloadSource::FROM_RENDERER:
suffix = "FromRenderer";
break;
case DownloadSource::EXTENSION_API:
suffix = "ExtensionAPI";
break;
case DownloadSource::EXTENSION_INSTALLER:
suffix = "ExtensionInstaller";
break;
case DownloadSource::INTERNAL_API:
suffix = "InternalAPI";
break;
case DownloadSource::WEB_CONTENTS_API:
suffix = "WebContentsAPI";
break;
case DownloadSource::OFFLINE_PAGE:
suffix = "OfflinePage";
break;
case DownloadSource::CONTEXT_MENU:
suffix = "ContextMenu";
break;
}
return name + "." + suffix;
}
} // namespace
void RecordDownloadCount(DownloadCountTypes type) {
UMA_HISTOGRAM_ENUMERATION("Download.Counts", type,
DOWNLOAD_COUNT_TYPES_LAST_ENTRY);
}
void RecordDownloadCountWithSource(DownloadCountTypes type,
DownloadSource download_source) {
RecordDownloadCount(type);
std::string name =
CreateHistogramNameWithSuffix("Download.Counts", download_source);
base::UmaHistogramEnumeration(name, type, DOWNLOAD_COUNT_TYPES_LAST_ENTRY);
}
void RecordDownloadCompleted(const base::TimeTicks& start,
int64_t download_len,
bool is_parallelizable,
DownloadSource download_source) {
RecordDownloadCountWithSource(COMPLETED_COUNT, download_source);
UMA_HISTOGRAM_LONG_TIMES("Download.Time", (base::TimeTicks::Now() - start));
int64_t max = 1024 * 1024 * 1024; // One Terabyte.
download_len /= 1024; // In Kilobytes
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.DownloadSize", download_len, 1, max,
256);
if (is_parallelizable) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.DownloadSize.Parallelizable",
download_len, 1, max, 256);
}
}
void RecordDownloadDeletion(base::Time completion_time,
const std::string& mime_type) {
if (completion_time == base::Time())
return;
// Records how long the user keeps media files on disk.
base::TimeDelta retention_time = base::Time::Now() - completion_time;
int retention_hours = retention_time.InHours();
DownloadContent type = DownloadContentFromMimeType(mime_type, false);
if (type == DownloadContent::VIDEO) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.DeleteRetentionTime.Video",
retention_hours, 1, kMaxDeletionRetentionHours,
50);
}
if (type == DownloadContent::AUDIO) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.DeleteRetentionTime.Audio",
retention_hours, 1, kMaxDeletionRetentionHours,
50);
}
}
void RecordDownloadInterrupted(DownloadInterruptReason reason,
int64_t received,
int64_t total,
bool is_parallelizable,
bool is_parallel_download_enabled,
DownloadSource download_source) {
RecordDownloadCountWithSource(INTERRUPTED_COUNT, download_source);
if (is_parallelizable) {
RecordParallelizableDownloadCount(INTERRUPTED_COUNT,
is_parallel_download_enabled);
}
std::vector<base::HistogramBase::Sample> samples =
base::CustomHistogram::ArrayToCustomEnumRanges(kAllInterruptReasonCodes);
UMA_HISTOGRAM_CUSTOM_ENUMERATION("Download.InterruptedReason", reason,
samples);
std::string name = CreateHistogramNameWithSuffix("Download.InterruptedReason",
download_source);
base::HistogramBase* counter = base::CustomHistogram::FactoryGet(
name, samples, base::HistogramBase::kUmaTargetedHistogramFlag);
counter->Add(reason);
if (is_parallel_download_enabled) {
UMA_HISTOGRAM_CUSTOM_ENUMERATION(
"Download.InterruptedReason.ParallelDownload", reason, samples);
}
// The maximum should be 2^kBuckets, to have the logarithmic bucket
// boundaries fall on powers of 2.
static const int kBuckets = 30;
static const int64_t kMaxKb = 1 << kBuckets; // One Terabyte, in Kilobytes.
int64_t delta_bytes = total - received;
bool unknown_size = total <= 0;
int64_t received_kb = received / 1024;
int64_t total_kb = total / 1024;
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.InterruptedReceivedSizeK", received_kb,
1, kMaxKb, kBuckets);
if (is_parallel_download_enabled) {
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Download.InterruptedReceivedSizeK.ParallelDownload", received_kb, 1,
kMaxKb, kBuckets);
}
if (!unknown_size) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.InterruptedTotalSizeK", total_kb, 1,
kMaxKb, kBuckets);
if (is_parallel_download_enabled) {
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Download.InterruptedTotalSizeK.ParallelDownload", total_kb, 1,
kMaxKb, kBuckets);
}
if (delta_bytes == 0) {
RecordDownloadCountWithSource(INTERRUPTED_AT_END_COUNT, download_source);
UMA_HISTOGRAM_CUSTOM_ENUMERATION("Download.InterruptedAtEndReason",
reason, samples);
if (is_parallelizable) {
RecordParallelizableDownloadCount(INTERRUPTED_AT_END_COUNT,
is_parallel_download_enabled);
UMA_HISTOGRAM_CUSTOM_ENUMERATION(
"Download.InterruptedAtEndReason.ParallelDownload", reason,
samples);
}
} else if (delta_bytes > 0) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.InterruptedOverrunBytes",
delta_bytes, 1, kMaxKb, kBuckets);
if (is_parallel_download_enabled) {
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Download.InterruptedOverrunBytes.ParallelDownload", delta_bytes, 1,
kMaxKb, kBuckets);
}
} else {
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.InterruptedUnderrunBytes",
-delta_bytes, 1, kMaxKb, kBuckets);
if (is_parallel_download_enabled) {
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Download.InterruptedUnderrunBytes.ParallelDownload", -delta_bytes,
1, kMaxKb, kBuckets);
}
}
}
UMA_HISTOGRAM_BOOLEAN("Download.InterruptedUnknownSize", unknown_size);
}
void RecordMaliciousDownloadClassified(DownloadDangerType danger_type) {
UMA_HISTOGRAM_ENUMERATION("Download.MaliciousDownloadClassified", danger_type,
DOWNLOAD_DANGER_TYPE_MAX);
}
void RecordDangerousDownloadAccept(DownloadDangerType danger_type,
const base::FilePath& file_path) {
UMA_HISTOGRAM_ENUMERATION("Download.DangerousDownloadValidated", danger_type,
DOWNLOAD_DANGER_TYPE_MAX);
if (danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE) {
base::UmaHistogramSparse(
"Download.DangerousFile.DangerousDownloadValidated",
GetDangerousFileType(file_path));
}
}
void RecordDangerousDownloadDiscard(DownloadDiscardReason reason,
DownloadDangerType danger_type,
const base::FilePath& file_path) {
switch (reason) {
case DOWNLOAD_DISCARD_DUE_TO_USER_ACTION:
UMA_HISTOGRAM_ENUMERATION("Download.UserDiscard", danger_type,
DOWNLOAD_DANGER_TYPE_MAX);
if (danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE) {
base::UmaHistogramSparse("Download.DangerousFile.UserDiscard",
GetDangerousFileType(file_path));
}
break;
case DOWNLOAD_DISCARD_DUE_TO_SHUTDOWN:
UMA_HISTOGRAM_ENUMERATION("Download.Discard", danger_type,
DOWNLOAD_DANGER_TYPE_MAX);
if (danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE) {
base::UmaHistogramSparse("Download.DangerousFile.Discard",
GetDangerousFileType(file_path));
}
break;
default:
NOTREACHED();
}
}
void RecordAcceptsRanges(const std::string& accepts_ranges,
int64_t download_len,
bool has_strong_validator) {
int64_t max = 1024 * 1024 * 1024; // One Terabyte.
download_len /= 1024; // In Kilobytes
static const int kBuckets = 50;
if (base::LowerCaseEqualsASCII(accepts_ranges, "none")) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.AcceptRangesNone.KBytes",
download_len, 1, max, kBuckets);
} else if (base::LowerCaseEqualsASCII(accepts_ranges, "bytes")) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.AcceptRangesBytes.KBytes",
download_len, 1, max, kBuckets);
if (has_strong_validator)
RecordDownloadCount(STRONG_VALIDATOR_AND_ACCEPTS_RANGES);
} else {
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.AcceptRangesMissingOrInvalid.KBytes",
download_len, 1, max, kBuckets);
}
}
namespace {
int GetMimeTypeMatch(const std::string& mime_type_string,
std::map<std::string, int> mime_type_map) {
for (const auto& entry : mime_type_map) {
if (entry.first == mime_type_string) {
return entry.second;
}
}
return 0;
}
static std::map<std::string, DownloadContent>
getMimeTypeToDownloadContentMap() {
return {
{"application/octet-stream", DownloadContent::OCTET_STREAM},
{"binary/octet-stream", DownloadContent::OCTET_STREAM},
{"application/pdf", DownloadContent::PDF},
{"application/msword", DownloadContent::DOCUMENT},
{"application/"
"vnd.openxmlformats-officedocument.wordprocessingml.document",
DownloadContent::DOCUMENT},
{"application/rtf", DownloadContent::DOCUMENT},
{"application/vnd.oasis.opendocument.text", DownloadContent::DOCUMENT},
{"application/vnd.google-apps.document", DownloadContent::DOCUMENT},
{"application/vnd.ms-excel", DownloadContent::SPREADSHEET},
{"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
DownloadContent::SPREADSHEET},
{"application/vnd.oasis.opendocument.spreadsheet",
DownloadContent::SPREADSHEET},
{"application/vnd.google-apps.spreadsheet", DownloadContent::SPREADSHEET},
{"application/vns.ms-powerpoint", DownloadContent::PRESENTATION},
{"application/"
"vnd.openxmlformats-officedocument.presentationml.presentation",
DownloadContent::PRESENTATION},
{"application/vnd.oasis.opendocument.presentation",
DownloadContent::PRESENTATION},
{"application/vnd.google-apps.presentation",
DownloadContent::PRESENTATION},
{"application/zip", DownloadContent::ARCHIVE},
{"application/x-gzip", DownloadContent::ARCHIVE},
{"application/x-rar-compressed", DownloadContent::ARCHIVE},
{"application/x-tar", DownloadContent::ARCHIVE},
{"application/x-bzip", DownloadContent::ARCHIVE},
{"application/x-bzip2", DownloadContent::ARCHIVE},
{"application/x-7z-compressed", DownloadContent::ARCHIVE},
{"application/x-exe", DownloadContent::EXECUTABLE},
{"application/java-archive", DownloadContent::EXECUTABLE},
{"application/vnd.apple.installer+xml", DownloadContent::EXECUTABLE},
{"application/x-csh", DownloadContent::EXECUTABLE},
{"application/x-sh", DownloadContent::EXECUTABLE},
{"application/x-apple-diskimage", DownloadContent::DMG},
{"application/x-chrome-extension", DownloadContent::CRX},
{"application/xhtml+xml", DownloadContent::WEB},
{"application/xml", DownloadContent::WEB},
{"application/javascript", DownloadContent::WEB},
{"application/json", DownloadContent::WEB},
{"application/typescript", DownloadContent::WEB},
{"application/vnd.mozilla.xul+xml", DownloadContent::WEB},
{"application/vnd.amazon.ebook", DownloadContent::EBOOK},
{"application/epub+zip", DownloadContent::EBOOK},
{"application/vnd.android.package-archive", DownloadContent::APK}};
}
// NOTE: Keep in sync with DownloadImageType in
// tools/metrics/histograms/enums.xml.
enum DownloadImage {
DOWNLOAD_IMAGE_UNRECOGNIZED = 0,
DOWNLOAD_IMAGE_GIF = 1,
DOWNLOAD_IMAGE_JPEG = 2,
DOWNLOAD_IMAGE_PNG = 3,
DOWNLOAD_IMAGE_TIFF = 4,
DOWNLOAD_IMAGE_ICON = 5,
DOWNLOAD_IMAGE_WEBP = 6,
DOWNLOAD_IMAGE_PSD = 7,
DOWNLOAD_IMAGE_SVG = 8,
DOWNLOAD_IMAGE_MAX = 9,
};
static std::map<std::string, int> getMimeTypeToDownloadImageMap() {
return {{"image/gif", DOWNLOAD_IMAGE_GIF},
{"image/jpeg", DOWNLOAD_IMAGE_JPEG},
{"image/png", DOWNLOAD_IMAGE_PNG},
{"image/tiff", DOWNLOAD_IMAGE_TIFF},
{"image/vnd.microsoft.icon", DOWNLOAD_IMAGE_ICON},
{"image/x-icon", DOWNLOAD_IMAGE_ICON},
{"image/webp", DOWNLOAD_IMAGE_WEBP},
{"image/vnd.adobe.photoshop", DOWNLOAD_IMAGE_PSD},
{"image/svg+xml", DOWNLOAD_IMAGE_SVG}};
}
void RecordDownloadImageType(const std::string& mime_type_string) {
DownloadImage download_image = DownloadImage(
GetMimeTypeMatch(mime_type_string, getMimeTypeToDownloadImageMap()));
UMA_HISTOGRAM_ENUMERATION("Download.ContentType.Image", download_image,
DOWNLOAD_IMAGE_MAX);
}
/** Text categories **/
// NOTE: Keep in sync with DownloadTextType in
// tools/metrics/histograms/enums.xml.
enum DownloadText {
DOWNLOAD_TEXT_UNRECOGNIZED = 0,
DOWNLOAD_TEXT_PLAIN = 1,
DOWNLOAD_TEXT_CSS = 2,
DOWNLOAD_TEXT_CSV = 3,
DOWNLOAD_TEXT_HTML = 4,
DOWNLOAD_TEXT_CALENDAR = 5,
DOWNLOAD_TEXT_MAX = 6,
};
static std::map<std::string, int> getMimeTypeToDownloadTextMap() {
return {{"text/plain", DOWNLOAD_TEXT_PLAIN},
{"text/css", DOWNLOAD_TEXT_CSS},
{"text/csv", DOWNLOAD_TEXT_CSV},
{"text/html", DOWNLOAD_TEXT_HTML},
{"text/calendar", DOWNLOAD_TEXT_CALENDAR}};
}
void RecordDownloadTextType(const std::string& mime_type_string) {
DownloadText download_text = DownloadText(
GetMimeTypeMatch(mime_type_string, getMimeTypeToDownloadTextMap()));
UMA_HISTOGRAM_ENUMERATION("Download.ContentType.Text", download_text,
DOWNLOAD_TEXT_MAX);
}
/* Audio categories */
// NOTE: Keep in sync with DownloadAudioType in
// tools/metrics/histograms/enums.xml.
enum DownloadAudio {
DOWNLOAD_AUDIO_UNRECOGNIZED = 0,
DOWNLOAD_AUDIO_AAC = 1,
DOWNLOAD_AUDIO_MIDI = 2,
DOWNLOAD_AUDIO_OGA = 3,
DOWNLOAD_AUDIO_WAV = 4,
DOWNLOAD_AUDIO_WEBA = 5,
DOWNLOAD_AUDIO_3GP = 6,
DOWNLOAD_AUDIO_3G2 = 7,
DOWNLOAD_AUDIO_MP3 = 8,
DOWNLOAD_AUDIO_MAX = 9,
};
static std::map<std::string, int> getMimeTypeToDownloadAudioMap() {
return {
{"audio/aac", DOWNLOAD_AUDIO_AAC}, {"audio/midi", DOWNLOAD_AUDIO_MIDI},
{"audio/ogg", DOWNLOAD_AUDIO_OGA}, {"audio/x-wav", DOWNLOAD_AUDIO_WAV},
{"audio/webm", DOWNLOAD_AUDIO_WEBA}, {"audio/3gpp", DOWNLOAD_AUDIO_3GP},
{"audio/3gpp2", DOWNLOAD_AUDIO_3G2}, {"audio/mp3", DOWNLOAD_AUDIO_MP3}};
}
void RecordDownloadAudioType(const std::string& mime_type_string) {
DownloadAudio download_audio = DownloadAudio(
GetMimeTypeMatch(mime_type_string, getMimeTypeToDownloadAudioMap()));
UMA_HISTOGRAM_ENUMERATION("Download.ContentType.Audio", download_audio,
DOWNLOAD_AUDIO_MAX);
}
/* Video categories */
// NOTE: Keep in sync with DownloadVideoType in
// tools/metrics/histograms/enums.xml.
enum DownloadVideo {
DOWNLOAD_VIDEO_UNRECOGNIZED = 0,
DOWNLOAD_VIDEO_AVI = 1,
DOWNLOAD_VIDEO_MPEG = 2,
DOWNLOAD_VIDEO_OGV = 3,
DOWNLOAD_VIDEO_WEBM = 4,
DOWNLOAD_VIDEO_3GP = 5,
DOWNLOAD_VIDEO_3G2 = 6,
DOWNLOAD_VIDEO_MP4 = 7,
DOWNLOAD_VIDEO_MOV = 8,
DOWNLOAD_VIDEO_WMV = 9,
DOWNLOAD_VIDEO_MAX = 10,
};
static std::map<std::string, int> getMimeTypeToDownloadVideoMap() {
return {{"video/x-msvideo", DOWNLOAD_VIDEO_AVI},
{"video/mpeg", DOWNLOAD_VIDEO_MPEG},
{"video/ogg", DOWNLOAD_VIDEO_OGV},
{"video/webm", DOWNLOAD_VIDEO_WEBM},
{"video/3gpp", DOWNLOAD_VIDEO_3GP},
{"video/3ggp2", DOWNLOAD_VIDEO_3G2},
{"video/mp4", DOWNLOAD_VIDEO_MP4},
{"video/quicktime", DOWNLOAD_VIDEO_MOV},
{"video/x-ms-wmv", DOWNLOAD_VIDEO_WMV}};
}
void RecordDownloadVideoType(const std::string& mime_type_string) {
DownloadVideo download_video = DownloadVideo(
GetMimeTypeMatch(mime_type_string, getMimeTypeToDownloadVideoMap()));
UMA_HISTOGRAM_ENUMERATION("Download.ContentType.Video", download_video,
DOWNLOAD_VIDEO_MAX);
}
} // namespace
DownloadContent DownloadContentFromMimeType(const std::string& mime_type_string,
bool record_content_subcategory) {
DownloadContent download_content = DownloadContent::UNRECOGNIZED;
for (const auto& entry : getMimeTypeToDownloadContentMap()) {
if (entry.first == mime_type_string) {
download_content = entry.second;
}
}
// Do partial matches.
if (download_content == DownloadContent::UNRECOGNIZED) {
if (base::StartsWith(mime_type_string, "text/",
base::CompareCase::SENSITIVE)) {
download_content = DownloadContent::TEXT;
if (record_content_subcategory)
RecordDownloadTextType(mime_type_string);
} else if (base::StartsWith(mime_type_string, "image/",
base::CompareCase::SENSITIVE)) {
download_content = DownloadContent::IMAGE;
if (record_content_subcategory)
RecordDownloadImageType(mime_type_string);
} else if (base::StartsWith(mime_type_string, "audio/",
base::CompareCase::SENSITIVE)) {
download_content = DownloadContent::AUDIO;
if (record_content_subcategory)
RecordDownloadAudioType(mime_type_string);
} else if (base::StartsWith(mime_type_string, "video/",
base::CompareCase::SENSITIVE)) {
download_content = DownloadContent::VIDEO;
if (record_content_subcategory)
RecordDownloadVideoType(mime_type_string);
} else if (base::StartsWith(mime_type_string, "font/",
base::CompareCase::SENSITIVE)) {
download_content = DownloadContent::FONT;
}
}
return download_content;
}
void RecordDownloadMimeType(const std::string& mime_type_string) {
DownloadContent download_content =
DownloadContentFromMimeType(mime_type_string, true);
UMA_HISTOGRAM_ENUMERATION("Download.Start.ContentType", download_content,
DownloadContent::MAX);
}
void RecordDownloadMimeTypeForNormalProfile(
const std::string& mime_type_string) {
UMA_HISTOGRAM_ENUMERATION(
"Download.Start.ContentType.NormalProfile",
DownloadContentFromMimeType(mime_type_string, false),
DownloadContent::MAX);
}
void RecordDownloadContentDisposition(
const std::string& content_disposition_string) {
if (content_disposition_string.empty())
return;
net::HttpContentDisposition content_disposition(content_disposition_string,
std::string());
int result = content_disposition.parse_result_flags();
bool is_valid = !content_disposition.filename().empty();
RecordContentDispositionCount(CONTENT_DISPOSITION_HEADER_PRESENT, true);
RecordContentDispositionCount(CONTENT_DISPOSITION_IS_VALID, is_valid);
if (!is_valid)
return;
RecordContentDispositionCountFlag(
CONTENT_DISPOSITION_HAS_DISPOSITION_TYPE, result,
net::HttpContentDisposition::HAS_DISPOSITION_TYPE);
RecordContentDispositionCountFlag(
CONTENT_DISPOSITION_HAS_UNKNOWN_TYPE, result,
net::HttpContentDisposition::HAS_UNKNOWN_DISPOSITION_TYPE);
RecordContentDispositionCountFlag(CONTENT_DISPOSITION_HAS_FILENAME, result,
net::HttpContentDisposition::HAS_FILENAME);
RecordContentDispositionCountFlag(
CONTENT_DISPOSITION_HAS_EXT_FILENAME, result,
net::HttpContentDisposition::HAS_EXT_FILENAME);
RecordContentDispositionCountFlag(
CONTENT_DISPOSITION_HAS_NON_ASCII_STRINGS, result,
net::HttpContentDisposition::HAS_NON_ASCII_STRINGS);
RecordContentDispositionCountFlag(
CONTENT_DISPOSITION_HAS_PERCENT_ENCODED_STRINGS, result,
net::HttpContentDisposition::HAS_PERCENT_ENCODED_STRINGS);
RecordContentDispositionCountFlag(
CONTENT_DISPOSITION_HAS_RFC2047_ENCODED_STRINGS, result,
net::HttpContentDisposition::HAS_RFC2047_ENCODED_STRINGS);
}
void RecordFileThreadReceiveBuffers(size_t num_buffers) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.FileThreadReceiveBuffers", num_buffers,
1, 100, 100);
}
void RecordOpen(const base::Time& end, bool first) {
if (!end.is_null()) {
UMA_HISTOGRAM_LONG_TIMES("Download.OpenTime", (base::Time::Now() - end));
if (first) {
UMA_HISTOGRAM_LONG_TIMES("Download.FirstOpenTime",
(base::Time::Now() - end));
}
}
}
void RecordOpensOutstanding(int size) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.OpensOutstanding", size, 1 /*min*/,
(1 << 10) /*max*/, 64 /*num_buckets*/);
}
void RecordContiguousWriteTime(base::TimeDelta time_blocked) {
UMA_HISTOGRAM_TIMES("Download.FileThreadBlockedTime", time_blocked);
}
// Record what percentage of the time we have the network flow controlled.
void RecordNetworkBlockage(base::TimeDelta resource_handler_lifetime,
base::TimeDelta resource_handler_blocked_time) {
int percentage = 0;
// Avoid division by zero errors.
if (!resource_handler_blocked_time.is_zero()) {
percentage =
resource_handler_blocked_time * 100 / resource_handler_lifetime;
}
UMA_HISTOGRAM_COUNTS_100("Download.ResourceHandlerBlockedPercentage",
percentage);
}
void RecordFileBandwidth(size_t length,
base::TimeDelta disk_write_time,
base::TimeDelta elapsed_time) {
RecordBandwidthMetric("Download.BandwidthOverallBytesPerSecond",
CalculateBandwidthBytesPerSecond(length, elapsed_time));
RecordBandwidthMetric(
"Download.BandwidthDiskBytesPerSecond",
CalculateBandwidthBytesPerSecond(length, disk_write_time));
}
void RecordParallelizableDownloadCount(DownloadCountTypes type,
bool is_parallel_download_enabled) {
std::string histogram_name = is_parallel_download_enabled
? "Download.Counts.ParallelDownload"
: "Download.Counts.ParallelizableDownload";
base::UmaHistogramEnumeration(histogram_name, type,
DOWNLOAD_COUNT_TYPES_LAST_ENTRY);
}
void RecordParallelDownloadRequestCount(int request_count) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.ParallelDownloadRequestCount",
request_count, 1, 10, 11);
}
void RecordParallelDownloadAddStreamSuccess(bool success) {
UMA_HISTOGRAM_BOOLEAN("Download.ParallelDownloadAddStreamSuccess", success);
}
void RecordParallelizableContentLength(int64_t content_length) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.ContentLength.Parallelizable",
content_length / 1024, 1, kMaxFileSizeKb, 50);
}
void RecordParallelizableDownloadStats(
size_t bytes_downloaded_with_parallel_streams,
base::TimeDelta time_with_parallel_streams,
size_t bytes_downloaded_without_parallel_streams,
base::TimeDelta time_without_parallel_streams,
bool uses_parallel_requests) {
RecordParallelizableDownloadAverageStats(
bytes_downloaded_with_parallel_streams +
bytes_downloaded_without_parallel_streams,
time_with_parallel_streams + time_without_parallel_streams);
int64_t bandwidth_without_parallel_streams = 0;
if (bytes_downloaded_without_parallel_streams > 0) {
bandwidth_without_parallel_streams = CalculateBandwidthBytesPerSecond(
bytes_downloaded_without_parallel_streams,
time_without_parallel_streams);
if (uses_parallel_requests) {
RecordBandwidthMetric(
"Download.ParallelizableDownloadBandwidth."
"WithParallelRequestsSingleStream",
bandwidth_without_parallel_streams);
} else {
RecordBandwidthMetric(
"Download.ParallelizableDownloadBandwidth."
"WithoutParallelRequests",
bandwidth_without_parallel_streams);
}
}
if (!uses_parallel_requests)
return;
base::TimeDelta time_saved;
if (bytes_downloaded_with_parallel_streams > 0) {
int64_t bandwidth_with_parallel_streams = CalculateBandwidthBytesPerSecond(
bytes_downloaded_with_parallel_streams, time_with_parallel_streams);
RecordBandwidthMetric(
"Download.ParallelizableDownloadBandwidth."
"WithParallelRequestsMultipleStreams",
bandwidth_with_parallel_streams);
if (bandwidth_without_parallel_streams > 0) {
time_saved = base::TimeDelta::FromMilliseconds(
1000.0 * bytes_downloaded_with_parallel_streams /
bandwidth_without_parallel_streams) -
time_with_parallel_streams;
int bandwidth_ratio_percentage =
(100.0 * bandwidth_with_parallel_streams) /
bandwidth_without_parallel_streams;
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Download.ParallelDownload.BandwidthRatioPercentage",
bandwidth_ratio_percentage, 0, 400, 101);
base::TimeDelta total_time =
time_with_parallel_streams + time_without_parallel_streams;
size_t total_size = bytes_downloaded_with_parallel_streams +
bytes_downloaded_without_parallel_streams;
base::TimeDelta non_parallel_time = base::TimeDelta::FromSecondsD(
static_cast<double>(total_size) / bandwidth_without_parallel_streams);
int time_ratio_percentage =
100.0 * total_time.InSecondsF() / non_parallel_time.InSecondsF();
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Download.ParallelDownload.TotalTimeRatioPercentage",
time_ratio_percentage, 0, 200, 101);
}
}
int kMillisecondsPerHour =
base::checked_cast<int>(base::Time::kMillisecondsPerSecond * 60 * 60);
if (time_saved >= base::TimeDelta()) {
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Download.EstimatedTimeSavedWithParallelDownload",
time_saved.InMilliseconds(), 0, kMillisecondsPerHour, 50);
} else {
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Download.EstimatedTimeWastedWithParallelDownload",
-time_saved.InMilliseconds(), 0, kMillisecondsPerHour, 50);
}
}
void RecordParallelizableDownloadAverageStats(
int64_t bytes_downloaded,
const base::TimeDelta& time_span) {
if (time_span.is_zero() || bytes_downloaded <= 0)
return;
int64_t average_bandwidth =
CalculateBandwidthBytesPerSecond(bytes_downloaded, time_span);
int64_t file_size_kb = bytes_downloaded / 1024;
RecordBandwidthMetric("Download.ParallelizableDownloadBandwidth",
average_bandwidth);
UMA_HISTOGRAM_LONG_TIMES("Download.Parallelizable.DownloadTime", time_span);
UMA_HISTOGRAM_CUSTOM_COUNTS("Download.Parallelizable.FileSize", file_size_kb,
1, kMaxFileSizeKb, 50);
if (average_bandwidth > kHighBandwidthBytesPerSecond) {
UMA_HISTOGRAM_LONG_TIMES(
"Download.Parallelizable.DownloadTime.HighDownloadBandwidth",
time_span);
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Download.Parallelizable.FileSize.HighDownloadBandwidth", file_size_kb,
1, kMaxFileSizeKb, 50);
}
}
void RecordParallelDownloadCreationEvent(ParallelDownloadCreationEvent event) {
UMA_HISTOGRAM_ENUMERATION("Download.ParallelDownload.CreationEvent", event,
ParallelDownloadCreationEvent::COUNT);
}
void RecordDownloadFileRenameResultAfterRetry(
base::TimeDelta time_since_first_failure,
DownloadInterruptReason interrupt_reason) {
if (interrupt_reason == DOWNLOAD_INTERRUPT_REASON_NONE) {
UMA_HISTOGRAM_TIMES("Download.TimeToRenameSuccessAfterInitialFailure",
time_since_first_failure);
} else {
UMA_HISTOGRAM_TIMES("Download.TimeToRenameFailureAfterInitialFailure",
time_since_first_failure);
}
}
void RecordSavePackageEvent(SavePackageEvent event) {
UMA_HISTOGRAM_ENUMERATION("Download.SavePackage", event,
SAVE_PACKAGE_LAST_ENTRY);
}
void RecordOriginStateOnResumption(bool is_partial,
OriginStateOnResumption state) {
if (is_partial)
UMA_HISTOGRAM_ENUMERATION("Download.OriginStateOnPartialResumption", state,
ORIGIN_STATE_ON_RESUMPTION_MAX);
else
UMA_HISTOGRAM_ENUMERATION("Download.OriginStateOnFullResumption", state,
ORIGIN_STATE_ON_RESUMPTION_MAX);
}
namespace {
// Enumeration for histogramming purposes.
// These values are written to logs. New enum values can be added, but existing
// enums must never be renumbered or deleted and reused.
enum DownloadConnectionSecurity {
DOWNLOAD_SECURE = 0, // Final download url and its redirects all use https
DOWNLOAD_TARGET_INSECURE =
1, // Final download url uses http, redirects are all
// https
DOWNLOAD_REDIRECT_INSECURE =
2, // Final download url uses https, but at least
// one redirect uses http
DOWNLOAD_REDIRECT_TARGET_INSECURE =
3, // Final download url uses http, and at
// least one redirect uses http
DOWNLOAD_TARGET_OTHER = 4, // Final download url uses a scheme not present in
// this enumeration
DOWNLOAD_TARGET_BLOB = 5, // Final download url uses blob scheme
DOWNLOAD_TARGET_DATA = 6, // Final download url uses data scheme
DOWNLOAD_TARGET_FILE = 7, // Final download url uses file scheme
DOWNLOAD_TARGET_FILESYSTEM = 8, // Final download url uses filesystem scheme
DOWNLOAD_TARGET_FTP = 9, // Final download url uses ftp scheme
DOWNLOAD_CONNECTION_SECURITY_MAX
};
} // namespace
void RecordDownloadConnectionSecurity(const GURL& download_url,
const std::vector<GURL>& url_chain) {
DownloadConnectionSecurity state = DOWNLOAD_TARGET_OTHER;
if (download_url.SchemeIsHTTPOrHTTPS()) {
bool is_final_download_secure = download_url.SchemeIsCryptographic();
bool is_redirect_chain_secure = true;
if (url_chain.size() > std::size_t(1)) {
for (std::size_t i = std::size_t(0); i < url_chain.size() - 1; i++) {
if (!url_chain[i].SchemeIsCryptographic()) {
is_redirect_chain_secure = false;
break;
}
}
}
state = is_final_download_secure
? is_redirect_chain_secure ? DOWNLOAD_SECURE
: DOWNLOAD_REDIRECT_INSECURE
: is_redirect_chain_secure ? DOWNLOAD_TARGET_INSECURE
: DOWNLOAD_REDIRECT_TARGET_INSECURE;
} else if (download_url.SchemeIsBlob()) {
state = DOWNLOAD_TARGET_BLOB;
} else if (download_url.SchemeIs(url::kDataScheme)) {
state = DOWNLOAD_TARGET_DATA;
} else if (download_url.SchemeIsFile()) {
state = DOWNLOAD_TARGET_FILE;
} else if (download_url.SchemeIsFileSystem()) {
state = DOWNLOAD_TARGET_FILESYSTEM;
} else if (download_url.SchemeIs(url::kFtpScheme)) {
state = DOWNLOAD_TARGET_FTP;
}
UMA_HISTOGRAM_ENUMERATION("Download.TargetConnectionSecurity", state,
DOWNLOAD_CONNECTION_SECURITY_MAX);
}
void RecordDownloadContentTypeSecurity(
const GURL& download_url,
const std::vector<GURL>& url_chain,
const std::string& mime_type,
const base::RepeatingCallback<bool(const GURL&)>&
is_origin_secure_callback) {
bool is_final_download_secure = is_origin_secure_callback.Run(download_url);
bool is_redirect_chain_secure = true;
for (const auto& url : url_chain) {
if (!is_origin_secure_callback.Run(url)) {
is_redirect_chain_secure = false;
break;
}
}
DownloadContent download_content =
download::DownloadContentFromMimeType(mime_type, false);
if (is_final_download_secure && is_redirect_chain_secure) {
UMA_HISTOGRAM_ENUMERATION("Download.Start.ContentType.SecureChain",
download_content, DownloadContent::MAX);
} else {
UMA_HISTOGRAM_ENUMERATION("Download.Start.ContentType.InsecureChain",
download_content, DownloadContent::MAX);
}
}
void RecordDownloadSourcePageTransitionType(
const base::Optional<ui::PageTransition>& page_transition) {
if (!page_transition)
return;
UMA_HISTOGRAM_ENUMERATION(
"Download.PageTransition",
ui::PageTransitionStripQualifier(page_transition.value()),
ui::PAGE_TRANSITION_LAST_CORE + 1);
}
void RecordDownloadHttpResponseCode(int response_code) {
UMA_HISTOGRAM_CUSTOM_ENUMERATION(
"Download.HttpResponseCode",
net::HttpUtil::MapStatusCodeForHistogram(response_code),
net::HttpUtil::GetStatusCodesForHistogram());
}
} // namespace download