blob: 98caa0ebe4ad1df224c596443551dfec32d40327 [file] [log] [blame]
// Copyright 2016 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 "remoting/base/chromoting_event.h"
#include "base/strings/string_util.h"
#include "base/strings/stringize_macros.h"
#include "base/system/sys_info.h"
#include "build/chromeos_buildflags.h"
#include "remoting/base/name_value_map.h"
namespace remoting {
namespace {
const NameMapElement<ChromotingEvent::AuthMethod> kAuthMethodNames[]{
{ChromotingEvent::AuthMethod::PIN, "pin"},
{ChromotingEvent::AuthMethod::ACCESS_CODE, "access-code"},
{ChromotingEvent::AuthMethod::PINLESS, "pinless"},
{ChromotingEvent::AuthMethod::THIRD_PARTY, "third-party"},
};
const NameMapElement<ChromotingEvent::ConnectionError> kConnectionErrorNames[]{
{ChromotingEvent::ConnectionError::NONE, "none"},
{ChromotingEvent::ConnectionError::HOST_OFFLINE, "host-offline"},
{ChromotingEvent::ConnectionError::SESSION_REJECTED, "session-rejected"},
{ChromotingEvent::ConnectionError::INCOMPATIBLE_PROTOCOL,
"incompatible-protocol"},
{ChromotingEvent::ConnectionError::NETWORK_FAILURE, "network-failure"},
{ChromotingEvent::ConnectionError::UNKNOWN_ERROR, "unknown-error"},
{ChromotingEvent::ConnectionError::INVALID_ACCESS_CODE,
"invalid-access-code"},
{ChromotingEvent::ConnectionError::MISSING_PLUGIN, "missing-plugin"},
{ChromotingEvent::ConnectionError::AUTHENTICATION_FAILED,
"authentication-failed"},
{ChromotingEvent::ConnectionError::BAD_VERSION, "bad-version"},
{ChromotingEvent::ConnectionError::HOST_OVERLOAD, "host-overload"},
{ChromotingEvent::ConnectionError::P2P_FAILURE, "p2p-failure"},
{ChromotingEvent::ConnectionError::UNEXPECTED, "unexpected"},
{ChromotingEvent::ConnectionError::CLIENT_SUSPENDED, "client-suspended"},
{ChromotingEvent::ConnectionError::NACL_DISABLED, "nacl-disabled"},
{ChromotingEvent::ConnectionError::MAX_SESSION_LENGTH,
"max-session-length"},
{ChromotingEvent::ConnectionError::HOST_CONFIGURATION_ERROR,
"host-configuration-error"},
{ChromotingEvent::ConnectionError::NACL_PLUGIN_CRASHED,
"nacl-plugin-crashed"},
{ChromotingEvent::ConnectionError::INVALID_ACCOUNT, "invalid-account"},
};
const NameMapElement<ChromotingEvent::ConnectionType> kConnectionTypeNames[]{
{ChromotingEvent::ConnectionType::DIRECT, "direct"},
{ChromotingEvent::ConnectionType::STUN, "stun"},
{ChromotingEvent::ConnectionType::RELAY, "relay"},
};
const NameMapElement<ChromotingEvent::Mode> kModeNames[]{
{ChromotingEvent::Mode::IT2ME, "it2me"},
{ChromotingEvent::Mode::ME2ME, "me2me"},
};
const NameMapElement<ChromotingEvent::Os> kOsNames[] = {
{ChromotingEvent::Os::CHROMOTING_LINUX, "linux"},
{ChromotingEvent::Os::CHROMOTING_CHROMEOS, "chromeos"},
{ChromotingEvent::Os::CHROMOTING_MAC, "mac"},
{ChromotingEvent::Os::CHROMOTING_WINDOWS, "windows"},
{ChromotingEvent::Os::OTHER, "other"},
{ChromotingEvent::Os::CHROMOTING_ANDROID, "android"},
{ChromotingEvent::Os::CHROMOTING_IOS, "ios"},
};
const NameMapElement<ChromotingEvent::SessionState> kSessionStateNames[]{
{ChromotingEvent::SessionState::UNKNOWN, "unknown"},
{ChromotingEvent::SessionState::CREATED, "created"},
{ChromotingEvent::SessionState::BAD_PLUGIN_VERSION, "bad-plugin-version"},
{ChromotingEvent::SessionState::UNKNOWN_PLUGIN_ERROR,
"unknown-plugin-error"},
{ChromotingEvent::SessionState::CONNECTING, "connecting"},
{ChromotingEvent::SessionState::INITIALIZING, "initializing"},
{ChromotingEvent::SessionState::CONNECTED, "connected"},
{ChromotingEvent::SessionState::CLOSED, "closed"},
{ChromotingEvent::SessionState::CONNECTION_FAILED, "connection-failed"},
{ChromotingEvent::SessionState::UNDEFINED, "undefined"},
{ChromotingEvent::SessionState::PLUGIN_DISABLED, "plugin-disabled"},
{ChromotingEvent::SessionState::CONNECTION_DROPPED, "connection-dropped"},
{ChromotingEvent::SessionState::CONNECTION_CANCELED, "connection-canceled"},
{ChromotingEvent::SessionState::AUTHENTICATED, "authenticated"},
{ChromotingEvent::SessionState::STARTED, "started"},
{ChromotingEvent::SessionState::SIGNALING, "signaling"},
{ChromotingEvent::SessionState::CREATING_PLUGIN, "creating-plugin"},
};
} // namespace
const char ChromotingEvent::kAuthMethodKey[] = "auth_method";
const char ChromotingEvent::kCaptureLatencyKey[] = "capture_latency";
const char ChromotingEvent::kConnectionErrorKey[] = "connection_error";
const char ChromotingEvent::kConnectionTypeKey[] = "connection_type";
const char ChromotingEvent::kCpuKey[] = "cpu";
const char ChromotingEvent::kDecodeLatencyKey[] = "decode_latency";
const char ChromotingEvent::kEncodeLatencyKey[] = "encode_latency";
const char ChromotingEvent::kHostOsKey[] = "host_os";
const char ChromotingEvent::kHostOsVersionKey[] = "host_os_version";
const char ChromotingEvent::kHostVersionKey[] = "host_version";
const char ChromotingEvent::kMaxCaptureLatencyKey[] = "max_capture_latency";
const char ChromotingEvent::kMaxDecodeLatencyKey[] = "max_decode_latency";
const char ChromotingEvent::kMaxEncodeLatencyKey[] = "max_encode_latency";
const char ChromotingEvent::kMaxRenderLatencyKey[] = "max_render_latency";
const char ChromotingEvent::kMaxRoundtripLatencyKey[] = "max_roundtrip_latency";
const char ChromotingEvent::kModeKey[] = "mode";
const char ChromotingEvent::kOsKey[] = "os";
const char ChromotingEvent::kOsVersionKey[] = "os_version";
const char ChromotingEvent::kPreviousSessionStateKey[] =
"previous_session_state";
const char ChromotingEvent::kRenderLatencyKey[] = "render_latency";
const char ChromotingEvent::kRoleKey[] = "role";
const char ChromotingEvent::kRoundtripLatencyKey[] = "roundtrip_latency";
const char ChromotingEvent::kSessionDurationKey[] = "session_duration";
const char ChromotingEvent::kSessionEntryPointKey[] = "session_entry_point";
const char ChromotingEvent::kSessionIdKey[] = "session_id";
const char ChromotingEvent::kSessionStateKey[] = "session_state";
const char ChromotingEvent::kSignalStrategyTypeKey[] = "signal_strategy_type";
const char ChromotingEvent::kTypeKey[] = "type";
const char ChromotingEvent::kVideoBandwidthKey[] = "video_bandwidth";
const char ChromotingEvent::kWebAppVersionKey[] = "webapp_version";
ChromotingEvent::ChromotingEvent() : values_map_(new base::DictionaryValue()) {}
ChromotingEvent::ChromotingEvent(Type type) : ChromotingEvent() {
SetEnum(kTypeKey, type);
}
ChromotingEvent::ChromotingEvent(const ChromotingEvent& other) {
send_attempts_ = other.send_attempts_;
values_map_ = other.values_map_->CreateDeepCopy();
}
ChromotingEvent::ChromotingEvent(ChromotingEvent&& other) {
send_attempts_ = other.send_attempts_;
values_map_ = std::move(other.values_map_);
}
ChromotingEvent::~ChromotingEvent() = default;
ChromotingEvent& ChromotingEvent::operator=(const ChromotingEvent& other) {
if (this != &other) {
send_attempts_ = other.send_attempts_;
values_map_ = other.values_map_->CreateDeepCopy();
}
return *this;
}
ChromotingEvent& ChromotingEvent::operator=(ChromotingEvent&& other) {
send_attempts_ = other.send_attempts_;
values_map_ = std::move(other.values_map_);
return *this;
}
void ChromotingEvent::SetString(const std::string& key,
const std::string& value) {
values_map_->SetString(key, value);
}
void ChromotingEvent::SetInteger(const std::string& key, int value) {
values_map_->SetInteger(key, value);
}
void ChromotingEvent::SetBoolean(const std::string& key, bool value) {
values_map_->SetBoolean(key, value);
}
void ChromotingEvent::SetDouble(const std::string& key, double value) {
values_map_->SetDouble(key, value);
}
bool ChromotingEvent::IsDataValid() {
const base::Value* auth_method = values_map_->FindKey(kAuthMethodKey);
if (auth_method &&
auth_method->GetInt() == static_cast<int>(AuthMethod::NOT_SET)) {
return false;
}
// TODO(yuweih): We may add other checks.
return true;
}
void ChromotingEvent::AddSystemInfo() {
SetString(kCpuKey, base::SysInfo::OperatingSystemArchitecture());
SetString(kOsVersionKey, base::SysInfo::OperatingSystemVersion());
SetString(kWebAppVersionKey, STRINGIZE(VERSION));
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
Os os = Os::CHROMOTING_LINUX;
#elif BUILDFLAG(IS_CHROMEOS_ASH)
Os os = Os::CHROMOTING_CHROMEOS;
#elif defined(OS_IOS)
Os os = Os::CHROMOTING_IOS;
#elif defined(OS_MAC)
Os os = Os::CHROMOTING_MAC;
#elif defined(OS_WIN)
Os os = Os::CHROMOTING_WINDOWS;
#elif defined(OS_ANDROID)
Os os = Os::CHROMOTING_ANDROID;
#else
Os os = Os::OTHER;
#endif
SetEnum(kOsKey, os);
}
void ChromotingEvent::IncrementSendAttempts() {
send_attempts_++;
}
const base::Value* ChromotingEvent::GetValue(const std::string& key) const {
return values_map_->FindKey(key);
}
std::unique_ptr<base::DictionaryValue> ChromotingEvent::CopyDictionaryValue()
const {
return values_map_->CreateDeepCopy();
}
// TODO(rkjnsn): Ideally we'd use the protobuf directly instead of storing
// everything in a DictionaryValue that needs to be converted.
apis::v1::ChromotingEvent ChromotingEvent::CreateProto() const {
apis::v1::ChromotingEvent event_proto;
if (values_map_->FindKey(kAuthMethodKey)) {
event_proto.set_auth_method(
static_cast<apis::v1::ChromotingEvent_AuthMethod>(
values_map_->FindKey(kAuthMethodKey)->GetInt()));
}
if (values_map_->FindKey(kCaptureLatencyKey)) {
event_proto.set_capture_latency(
values_map_->FindKey(kCaptureLatencyKey)->GetDouble());
}
if (values_map_->FindKey(kConnectionErrorKey)) {
event_proto.set_connection_error(
static_cast<apis::v1::ChromotingEvent_ConnectionError>(
values_map_->FindKey(kConnectionErrorKey)->GetInt()));
}
if (values_map_->FindKey(kConnectionTypeKey)) {
event_proto.set_connection_type(
static_cast<apis::v1::ChromotingEvent_ConnectionType>(
values_map_->FindKey(kConnectionTypeKey)->GetInt()));
}
if (values_map_->FindKey(kCpuKey)) {
event_proto.set_cpu(values_map_->FindKey(kCpuKey)->GetString());
}
if (values_map_->FindKey(kDecodeLatencyKey)) {
event_proto.set_decode_latency(
values_map_->FindKey(kDecodeLatencyKey)->GetDouble());
}
if (values_map_->FindKey(kEncodeLatencyKey)) {
event_proto.set_encode_latency(
values_map_->FindKey(kEncodeLatencyKey)->GetDouble());
}
if (values_map_->FindKey(kHostOsKey)) {
event_proto.set_host_os(static_cast<apis::v1::ChromotingEvent_Os>(
values_map_->FindKey(kHostOsKey)->GetInt()));
}
if (values_map_->FindKey(kHostOsVersionKey)) {
event_proto.set_host_os_version(
values_map_->FindKey(kHostOsVersionKey)->GetString());
}
if (values_map_->FindKey(kHostVersionKey)) {
event_proto.set_host_version(
values_map_->FindKey(kHostVersionKey)->GetString());
}
if (values_map_->FindKey(kMaxCaptureLatencyKey)) {
event_proto.set_max_capture_latency(
values_map_->FindKey(kMaxCaptureLatencyKey)->GetDouble());
}
if (values_map_->FindKey(kMaxDecodeLatencyKey)) {
event_proto.set_max_decode_latency(
values_map_->FindKey(kMaxDecodeLatencyKey)->GetDouble());
}
if (values_map_->FindKey(kMaxEncodeLatencyKey)) {
event_proto.set_max_encode_latency(
values_map_->FindKey(kMaxEncodeLatencyKey)->GetDouble());
}
if (values_map_->FindKey(kMaxRenderLatencyKey)) {
event_proto.set_max_render_latency(
values_map_->FindKey(kMaxRenderLatencyKey)->GetDouble());
}
if (values_map_->FindKey(kMaxRoundtripLatencyKey)) {
event_proto.set_max_roundtrip_latency(
values_map_->FindKey(kMaxRoundtripLatencyKey)->GetDouble());
}
if (values_map_->FindKey(kModeKey)) {
event_proto.set_mode(static_cast<apis::v1::ChromotingEvent_Mode>(
values_map_->FindKey(kModeKey)->GetInt()));
}
if (values_map_->FindKey(kOsKey)) {
event_proto.set_os(static_cast<apis::v1::ChromotingEvent_Os>(
values_map_->FindKey(kOsKey)->GetInt()));
}
if (values_map_->FindKey(kOsVersionKey)) {
event_proto.set_os_version(
values_map_->FindKey(kOsVersionKey)->GetString());
}
if (values_map_->FindKey(kPreviousSessionStateKey)) {
event_proto.set_previous_session_state(
static_cast<apis::v1::ChromotingEvent_SessionState>(
values_map_->FindKey(kPreviousSessionStateKey)->GetInt()));
}
if (values_map_->FindKey(kRenderLatencyKey)) {
event_proto.set_render_latency(
values_map_->FindKey(kRenderLatencyKey)->GetDouble());
}
if (values_map_->FindKey(kRoleKey)) {
event_proto.set_role(static_cast<apis::v1::ChromotingEvent_Role>(
values_map_->FindKey(kRoleKey)->GetInt()));
}
if (values_map_->FindKey(kRoundtripLatencyKey)) {
event_proto.set_roundtrip_latency(
values_map_->FindKey(kRoundtripLatencyKey)->GetDouble());
}
if (values_map_->FindKey(kSessionDurationKey)) {
event_proto.set_session_duration(
values_map_->FindKey(kSessionDurationKey)->GetDouble());
}
if (values_map_->FindKey(kSessionEntryPointKey)) {
event_proto.set_session_entry_point(
static_cast<apis::v1::ChromotingEvent_SessionEntryPoint>(
values_map_->FindKey(kSessionEntryPointKey)->GetInt()));
}
if (values_map_->FindKey(kSessionIdKey)) {
event_proto.set_session_id(
values_map_->FindKey(kSessionIdKey)->GetString());
}
if (values_map_->FindKey(kSessionStateKey)) {
event_proto.set_session_state(
static_cast<apis::v1::ChromotingEvent_SessionState>(
values_map_->FindKey(kSessionStateKey)->GetInt()));
}
if (values_map_->FindKey(kSignalStrategyTypeKey)) {
event_proto.set_signal_strategy_type(
static_cast<apis::v1::ChromotingEvent_SignalStrategyType>(
values_map_->FindKey(kSignalStrategyTypeKey)->GetInt()));
}
if (values_map_->FindKey(kTypeKey)) {
event_proto.set_type(static_cast<apis::v1::ChromotingEvent_Type>(
values_map_->FindKey(kTypeKey)->GetInt()));
}
if (values_map_->FindKey(kVideoBandwidthKey)) {
event_proto.set_video_bandwidth(
values_map_->FindKey(kVideoBandwidthKey)->GetDouble());
}
if (values_map_->FindKey(kWebAppVersionKey)) {
event_proto.set_webapp_version(
values_map_->FindKey(kWebAppVersionKey)->GetString());
}
return event_proto;
}
// static
bool ChromotingEvent::IsEndOfSession(SessionState state) {
return state == SessionState::CLOSED ||
state == SessionState::CONNECTION_DROPPED ||
state == SessionState::CONNECTION_FAILED ||
state == SessionState::CONNECTION_CANCELED;
}
// static
ChromotingEvent::Os ChromotingEvent::ParseOsFromString(const std::string& os) {
ChromotingEvent::Os result;
if (!NameToValue(kOsNames, base::ToLowerASCII(os), &result)) {
return Os::OTHER;
}
return result;
}
// static
template <>
const char* ChromotingEvent::EnumToString(AuthMethod value) {
return ValueToName(kAuthMethodNames, value);
}
// static
template <>
const char* ChromotingEvent::EnumToString(ConnectionError value) {
return ValueToName(kConnectionErrorNames, value);
}
// static
template <>
const char* ChromotingEvent::EnumToString(ConnectionType value) {
return ValueToName(kConnectionTypeNames, value);
}
// static
template <>
const char* ChromotingEvent::EnumToString(Mode value) {
return ValueToName(kModeNames, value);
}
// static
template <>
const char* ChromotingEvent::EnumToString(Os value) {
return ValueToName(kOsNames, value);
}
// static
template <>
const char* ChromotingEvent::EnumToString(SessionState value) {
return ValueToName(kSessionStateNames, value);
}
} // namespace remoting