blob: bd4a1bb668045a90c5eeff0161fcd4cfb564ee0c [file] [log] [blame]
// Copyright 2019 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 "chrome/browser/sharing/sharing_metrics.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/sharing/sharing_device_registration_result.h"
#include "components/version_info/version_info.h"
namespace {
const char* GetEnumStringValue(SharingFeatureName feature) {
DCHECK(feature != SharingFeatureName::kUnknown)
<< "Feature needs to be specified for metrics logging.";
switch (feature) {
case SharingFeatureName::kUnknown:
return "Unknown";
case SharingFeatureName::kClickToCall:
return "ClickToCall";
case SharingFeatureName::kSharedClipboard:
return "SharedClipboard";
}
}
// Maps SharingDevicePlatform enum values to strings used as histogram
// suffixes. Keep in sync with "SharingDevicePlatform" in histograms.xml.
std::string DevicePlatformToString(SharingDevicePlatform device_platform) {
switch (device_platform) {
case SharingDevicePlatform::kAndroid:
return "Android";
case SharingDevicePlatform::kChromeOS:
return "ChromeOS";
case SharingDevicePlatform::kIOS:
return "iOS";
case SharingDevicePlatform::kLinux:
return "Linux";
case SharingDevicePlatform::kMac:
return "Mac";
case SharingDevicePlatform::kWindows:
return "Windows";
case SharingDevicePlatform::kUnknown:
return "Unknown";
}
}
// Maps SharingSendMessageResult enum values to strings used as histogram
// suffixes. Keep in sync with "SharingSendMessageResult" in histograms.xml.
std::string SharingSendMessageResultToSuffix(SharingSendMessageResult result) {
switch (result) {
case SharingSendMessageResult::kSuccessful:
return "Successful";
case SharingSendMessageResult::kDeviceNotFound:
return "DeviceNotFound";
case SharingSendMessageResult::kNetworkError:
return "NetworkError";
case SharingSendMessageResult::kPayloadTooLarge:
return "PayloadTooLarge";
case SharingSendMessageResult::kAckTimeout:
return "AckTimeout";
case SharingSendMessageResult::kInternalError:
return "InternalError";
}
}
const std::string& MessageTypeToMessageSuffix(
chrome_browser_sharing::MessageType message_type) {
// For proto3 enums unrecognized enum values are kept when parsing and their
// name is an empty string. We don't want to use that as a histogram suffix.
// The returned values must match the values of the SharingMessage suffixes
// defined in histograms.xml.
if (!chrome_browser_sharing::MessageType_IsValid(message_type)) {
return chrome_browser_sharing::MessageType_Name(
chrome_browser_sharing::UNKNOWN_MESSAGE);
}
return chrome_browser_sharing::MessageType_Name(message_type);
}
// Major Chrome version comparison with the receiver device.
// These values are logged to UMA. Entries should not be renumbered and numeric
// values should never be reused. Please keep in sync with
// "SharingMajorVersionComparison" in enums.xml.
enum class SharingMajorVersionComparison {
kUnknown = 0,
kSenderIsLower = 1,
kSame = 2,
kSenderIsHigher = 3,
kMaxValue = kSenderIsHigher,
};
} // namespace
chrome_browser_sharing::MessageType SharingPayloadCaseToMessageType(
chrome_browser_sharing::SharingMessage::PayloadCase payload_case) {
switch (payload_case) {
case chrome_browser_sharing::SharingMessage::PAYLOAD_NOT_SET:
return chrome_browser_sharing::UNKNOWN_MESSAGE;
case chrome_browser_sharing::SharingMessage::kPingMessage:
return chrome_browser_sharing::PING_MESSAGE;
case chrome_browser_sharing::SharingMessage::kAckMessage:
return chrome_browser_sharing::ACK_MESSAGE;
case chrome_browser_sharing::SharingMessage::kClickToCallMessage:
return chrome_browser_sharing::CLICK_TO_CALL_MESSAGE;
case chrome_browser_sharing::SharingMessage::kSharedClipboardMessage:
return chrome_browser_sharing::SHARED_CLIPBOARD_MESSAGE;
case chrome_browser_sharing::SharingMessage::kSmsFetchRequest:
return chrome_browser_sharing::SMS_FETCH_REQUEST;
case chrome_browser_sharing::SharingMessage::kRemoteCopyMessage:
return chrome_browser_sharing::REMOTE_COPY_MESSAGE;
case chrome_browser_sharing::SharingMessage::kSignallingMessage:
return chrome_browser_sharing::SIGNALLING_MESSAGE;
case chrome_browser_sharing::SharingMessage::kIceCandidateMessage:
return chrome_browser_sharing::ICE_CANDIDATE_MESSAGE;
}
// For proto3 enums unrecognized enum values are kept when parsing, and a new
// payload case received over the network would not default to
// PAYLOAD_NOT_SET. Explicitly return UNKNOWN_MESSAGE here to handle this
// case.
return chrome_browser_sharing::UNKNOWN_MESSAGE;
}
void LogSharingMessageReceived(
chrome_browser_sharing::MessageType original_message_type,
chrome_browser_sharing::SharingMessage::PayloadCase payload_case) {
chrome_browser_sharing::MessageType actual_message_type =
SharingPayloadCaseToMessageType(payload_case);
base::UmaHistogramExactLinear("Sharing.MessageReceivedType",
actual_message_type,
chrome_browser_sharing::MessageType_ARRAYSIZE);
base::UmaHistogramExactLinear(
base::StrCat({"Sharing.MessageReceivedType.",
MessageTypeToMessageSuffix(original_message_type)}),
actual_message_type, chrome_browser_sharing::MessageType_ARRAYSIZE);
}
void LogSharingRegistrationResult(SharingDeviceRegistrationResult result) {
base::UmaHistogramEnumeration("Sharing.DeviceRegistrationResult", result);
}
void LogSharingUnegistrationResult(SharingDeviceRegistrationResult result) {
base::UmaHistogramEnumeration("Sharing.DeviceUnregistrationResult", result);
}
void LogSharingVapidKeyCreationResult(SharingVapidKeyCreationResult result) {
base::UmaHistogramEnumeration("Sharing.VapidKeyCreationResult", result);
}
void LogSharingDevicesToShow(SharingFeatureName feature,
const char* histogram_suffix,
int count) {
auto* feature_str = GetEnumStringValue(feature);
// Explicitly log both the base and the suffixed histogram because the base
// aggregation is not automatically generated.
base::UmaHistogramExactLinear(
base::StrCat({"Sharing.", feature_str, "DevicesToShow"}), count,
/*value_max=*/20);
if (!histogram_suffix)
return;
base::UmaHistogramExactLinear(
base::StrCat(
{"Sharing.", feature_str, "DevicesToShow.", histogram_suffix}),
count,
/*value_max=*/20);
}
void LogSharingAppsToShow(SharingFeatureName feature,
const char* histogram_suffix,
int count) {
auto* feature_str = GetEnumStringValue(feature);
// Explicitly log both the base and the suffixed histogram because the base
// aggregation is not automatically generated.
base::UmaHistogramExactLinear(
base::StrCat({"Sharing.", feature_str, "AppsToShow"}), count,
/*value_max=*/20);
if (!histogram_suffix)
return;
base::UmaHistogramExactLinear(
base::StrCat({"Sharing.", feature_str, "AppsToShow.", histogram_suffix}),
count,
/*value_max=*/20);
}
void LogSharingSelectedDeviceIndex(SharingFeatureName feature,
const char* histogram_suffix,
int index) {
auto* feature_str = GetEnumStringValue(feature);
// Explicitly log both the base and the suffixed histogram because the base
// aggregation is not automatically generated.
base::UmaHistogramExactLinear(
base::StrCat({"Sharing.", feature_str, "SelectedDeviceIndex"}), index,
/*value_max=*/20);
if (!histogram_suffix)
return;
base::UmaHistogramExactLinear(
base::StrCat(
{"Sharing.", feature_str, "SelectedDeviceIndex.", histogram_suffix}),
index,
/*value_max=*/20);
}
void LogSharingSelectedAppIndex(SharingFeatureName feature,
const char* histogram_suffix,
int index) {
auto* feature_str = GetEnumStringValue(feature);
// Explicitly log both the base and the suffixed histogram because the base
// aggregation is not automatically generated.
base::UmaHistogramExactLinear(
base::StrCat({"Sharing.", feature_str, "SelectedAppIndex"}), index,
/*value_max=*/20);
if (!histogram_suffix)
return;
base::UmaHistogramExactLinear(
base::StrCat(
{"Sharing.", feature_str, "SelectedAppIndex.", histogram_suffix}),
index,
/*value_max=*/20);
}
void LogSharingMessageAckTime(chrome_browser_sharing::MessageType message_type,
SharingDevicePlatform receiver_device_platform,
base::TimeDelta time) {
std::string suffixed_name = base::StrCat(
{"Sharing.MessageAckTime.", MessageTypeToMessageSuffix(message_type)});
std::string platform_suffixed_name =
base::StrCat({"Sharing.MessageAckTime.",
DevicePlatformToString(receiver_device_platform), ".",
MessageTypeToMessageSuffix(message_type)});
switch (message_type) {
case chrome_browser_sharing::MessageType::UNKNOWN_MESSAGE:
case chrome_browser_sharing::MessageType::PING_MESSAGE:
case chrome_browser_sharing::MessageType::CLICK_TO_CALL_MESSAGE:
case chrome_browser_sharing::MessageType::SHARED_CLIPBOARD_MESSAGE:
base::UmaHistogramMediumTimes(suffixed_name, time);
base::UmaHistogramMediumTimes(platform_suffixed_name, time);
break;
case chrome_browser_sharing::MessageType::SMS_FETCH_REQUEST:
base::UmaHistogramCustomTimes(
suffixed_name, time, /*min=*/base::TimeDelta::FromMilliseconds(1),
/*max=*/base::TimeDelta::FromMinutes(10), /*buckets=*/50);
break;
case chrome_browser_sharing::MessageType::ACK_MESSAGE:
default:
// For proto3 enums unrecognized enum values are kept, so message_type may
// not fall into any switch case. However, as an ack message, original
// message type should always be known.
NOTREACHED();
}
}
void LogSharingDeviceLastUpdatedAge(
chrome_browser_sharing::MessageType message_type,
base::TimeDelta age) {
constexpr char kBase[] = "Sharing.DeviceLastUpdatedAge";
int hours = age.InHours();
base::UmaHistogramCounts1000(kBase, hours);
base::UmaHistogramCounts1000(
base::StrCat({kBase, ".", MessageTypeToMessageSuffix(message_type)}),
hours);
}
void LogSharingDeviceLastUpdatedAgeWithResult(SharingSendMessageResult result,
base::TimeDelta age) {
base::UmaHistogramCounts1000(
base::StrCat({"Sharing.DeviceLastUpdatedAgeWithResult.",
SharingSendMessageResultToSuffix(result)}),
age.InHours());
}
void LogSharingVersionComparison(
chrome_browser_sharing::MessageType message_type,
const std::string& receiver_version) {
int sender_major = 0;
base::StringToInt(version_info::GetMajorVersionNumber(), &sender_major);
// The |receiver_version| has optional modifiers e.g. "1.2.3.4 canary" so we
// do not parse it with base::Version.
int receiver_major = 0;
base::StringToInt(receiver_version, &receiver_major);
SharingMajorVersionComparison result;
if (sender_major == 0 || sender_major == INT_MIN || sender_major == INT_MAX ||
receiver_major == 0 || receiver_major == INT_MIN ||
receiver_major == INT_MAX) {
result = SharingMajorVersionComparison::kUnknown;
} else if (sender_major < receiver_major) {
result = SharingMajorVersionComparison::kSenderIsLower;
} else if (sender_major == receiver_major) {
result = SharingMajorVersionComparison::kSame;
} else {
result = SharingMajorVersionComparison::kSenderIsHigher;
}
constexpr char kBase[] = "Sharing.MajorVersionComparison";
base::UmaHistogramEnumeration(kBase, result);
base::UmaHistogramEnumeration(
base::StrCat({kBase, ".", MessageTypeToMessageSuffix(message_type)}),
result);
}
void LogSharingDialogShown(SharingFeatureName feature, SharingDialogType type) {
base::UmaHistogramEnumeration(
base::StrCat({"Sharing.", GetEnumStringValue(feature), "DialogShown"}),
type);
}
void LogSendSharingMessageResult(
chrome_browser_sharing::MessageType message_type,
SharingDevicePlatform receiving_device_platform,
SharingSendMessageResult result) {
const std::string metric_prefix = "Sharing.SendMessageResult";
base::UmaHistogramEnumeration(metric_prefix, result);
base::UmaHistogramEnumeration(
base::StrCat(
{metric_prefix, ".", MessageTypeToMessageSuffix(message_type)}),
result);
base::UmaHistogramEnumeration(
base::StrCat({metric_prefix, ".",
DevicePlatformToString(receiving_device_platform)}),
result);
base::UmaHistogramEnumeration(
base::StrCat({metric_prefix, ".",
DevicePlatformToString(receiving_device_platform), ".",
MessageTypeToMessageSuffix(message_type)}),
result);
}
void LogSendSharingAckMessageResult(
chrome_browser_sharing::MessageType message_type,
SharingDevicePlatform ack_receiver_device_type,
SharingSendMessageResult result) {
const std::string metric_prefix = "Sharing.SendAckMessageResult";
base::UmaHistogramEnumeration(metric_prefix, result);
base::UmaHistogramEnumeration(
base::StrCat(
{metric_prefix, ".", MessageTypeToMessageSuffix(message_type)}),
result);
base::UmaHistogramEnumeration(
base::StrCat({metric_prefix, ".",
DevicePlatformToString(ack_receiver_device_type)}),
result);
base::UmaHistogramEnumeration(
base::StrCat({metric_prefix, ".",
DevicePlatformToString(ack_receiver_device_type), ".",
MessageTypeToMessageSuffix(message_type)}),
result);
}
void LogSharedClipboardSelectedTextSize(size_t size) {
base::UmaHistogramCounts100000("Sharing.SharedClipboardSelectedTextSize",
size);
}
void LogRemoteCopyHandleMessageResult(RemoteCopyHandleMessageResult result) {
base::UmaHistogramEnumeration("Sharing.RemoteCopyHandleMessageResult",
result);
}
void LogRemoteCopyReceivedTextSize(size_t size) {
base::UmaHistogramCounts100000("Sharing.RemoteCopyReceivedTextSize", size);
}
void LogRemoteCopyReceivedImageSizeBeforeDecode(size_t size) {
base::UmaHistogramCounts10M("Sharing.RemoteCopyReceivedImageSizeBeforeDecode",
size);
}
void LogRemoteCopyReceivedImageSizeAfterDecode(size_t size) {
base::UmaHistogramCustomCounts(
"Sharing.RemoteCopyReceivedImageSizeAfterDecode", size, 1, 100000000, 50);
}
void LogRemoteCopyLoadImageStatusCode(int code) {
base::UmaHistogramSparse("Sharing.RemoteCopyLoadImageStatusCode", code);
}
void LogRemoteCopyLoadImageTime(base::TimeDelta time) {
base::UmaHistogramMediumTimes("Sharing.RemoteCopyLoadImageTime", time);
}
void LogRemoteCopyDecodeImageTime(base::TimeDelta time) {
base::UmaHistogramMediumTimes("Sharing.RemoteCopyDecodeImageTime", time);
}
void LogRemoteCopyResizeImageTime(base::TimeDelta time) {
base::UmaHistogramMediumTimes("Sharing.RemoteCopyResizeImageTime", time);
}