summaryrefslogtreecommitdiff
path: root/chromium/components/gcm_driver/gcm_stats_recorder_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/gcm_driver/gcm_stats_recorder_impl.cc')
-rw-r--r--chromium/components/gcm_driver/gcm_stats_recorder_impl.cc514
1 files changed, 514 insertions, 0 deletions
diff --git a/chromium/components/gcm_driver/gcm_stats_recorder_impl.cc b/chromium/components/gcm_driver/gcm_stats_recorder_impl.cc
new file mode 100644
index 00000000000..d7af543792e
--- /dev/null
+++ b/chromium/components/gcm_driver/gcm_stats_recorder_impl.cc
@@ -0,0 +1,514 @@
+// Copyright 2014 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/gcm_driver/gcm_stats_recorder_impl.h"
+
+
+#include "base/containers/circular_deque.h"
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "components/gcm_driver/crypto/gcm_decryption_result.h"
+#include "components/gcm_driver/crypto/gcm_encryption_provider.h"
+
+namespace gcm {
+
+const uint32_t MAX_LOGGED_ACTIVITY_COUNT = 100;
+
+namespace {
+
+// Insert an item to the front of deque while maintaining the size of the deque.
+// Overflow item is discarded.
+//
+// DANGER: the returned pointer will not be valind if the queue is modified.
+template <typename T>
+T* InsertCircularBuffer(base::circular_deque<T>* q, const T& item) {
+ DCHECK(q);
+ if (q->size() > MAX_LOGGED_ACTIVITY_COUNT - 1) {
+ q->pop_back();
+ }
+ q->push_front(item);
+ return &q->front();
+}
+
+// Helper for getting string representation of the MessageSendStatus enum.
+std::string GetMessageSendStatusString(
+ gcm::MCSClient::MessageSendStatus status) {
+ switch (status) {
+ case gcm::MCSClient::QUEUED:
+ return "QUEUED";
+ case gcm::MCSClient::SENT:
+ return "SENT";
+ case gcm::MCSClient::QUEUE_SIZE_LIMIT_REACHED:
+ return "QUEUE_SIZE_LIMIT_REACHED";
+ case gcm::MCSClient::APP_QUEUE_SIZE_LIMIT_REACHED:
+ return "APP_QUEUE_SIZE_LIMIT_REACHED";
+ case gcm::MCSClient::MESSAGE_TOO_LARGE:
+ return "MESSAGE_TOO_LARGE";
+ case gcm::MCSClient::NO_CONNECTION_ON_ZERO_TTL:
+ return "NO_CONNECTION_ON_ZERO_TTL";
+ case gcm::MCSClient::TTL_EXCEEDED:
+ return "TTL_EXCEEDED";
+ case gcm::MCSClient::SEND_STATUS_COUNT:
+ NOTREACHED();
+ break;
+ }
+ return "UNKNOWN";
+}
+
+// Helper for getting string representation of the
+// ConnectionFactory::ConnectionResetReason enum.
+std::string GetConnectionResetReasonString(
+ gcm::ConnectionFactory::ConnectionResetReason reason) {
+ switch (reason) {
+ case gcm::ConnectionFactory::LOGIN_FAILURE:
+ return "LOGIN_FAILURE";
+ case gcm::ConnectionFactory::CLOSE_COMMAND:
+ return "CLOSE_COMMAND";
+ case gcm::ConnectionFactory::HEARTBEAT_FAILURE:
+ return "HEARTBEAT_FAILURE";
+ case gcm::ConnectionFactory::SOCKET_FAILURE:
+ return "SOCKET_FAILURE";
+ case gcm::ConnectionFactory::NETWORK_CHANGE:
+ return "NETWORK_CHANGE";
+ case gcm::ConnectionFactory::NEW_HEARTBEAT_INTERVAL:
+ return "NEW_HEARTBEAT_INTERVAL";
+ case gcm::ConnectionFactory::CONNECTION_RESET_COUNT:
+ NOTREACHED();
+ break;
+ }
+ return "UNKNOWN_REASON";
+}
+
+// Helper for getting string representation of the RegistrationRequest::Status
+// enum.
+std::string GetRegistrationStatusString(
+ gcm::RegistrationRequest::Status status) {
+ switch (status) {
+ case gcm::RegistrationRequest::SUCCESS:
+ return "SUCCESS";
+ case gcm::RegistrationRequest::INVALID_PARAMETERS:
+ return "INVALID_PARAMETERS";
+ case gcm::RegistrationRequest::INVALID_SENDER:
+ return "INVALID_SENDER";
+ case gcm::RegistrationRequest::AUTHENTICATION_FAILED:
+ return "AUTHENTICATION_FAILED";
+ case gcm::RegistrationRequest::DEVICE_REGISTRATION_ERROR:
+ return "DEVICE_REGISTRATION_ERROR";
+ case gcm::RegistrationRequest::UNKNOWN_ERROR:
+ return "UNKNOWN_ERROR";
+ case gcm::RegistrationRequest::URL_FETCHING_FAILED:
+ return "URL_FETCHING_FAILED";
+ case gcm::RegistrationRequest::HTTP_NOT_OK:
+ return "HTTP_NOT_OK";
+ case gcm::RegistrationRequest::NO_RESPONSE_BODY:
+ return "NO_RESPONSE_BODY";
+ case gcm::RegistrationRequest::REACHED_MAX_RETRIES:
+ return "REACHED_MAX_RETRIES";
+ case gcm::RegistrationRequest::RESPONSE_PARSING_FAILED:
+ return "RESPONSE_PARSING_FAILED";
+ case gcm::RegistrationRequest::INTERNAL_SERVER_ERROR:
+ return "INTERNAL_SERVER_ERROR";
+ case gcm::RegistrationRequest::QUOTA_EXCEEDED:
+ return "QUOTA_EXCEEDED";
+ case gcm::RegistrationRequest::TOO_MANY_REGISTRATIONS:
+ return "TOO_MANY_REGISTRATIONS";
+ case gcm::RegistrationRequest::STATUS_COUNT:
+ NOTREACHED();
+ break;
+ }
+ return "UNKNOWN_STATUS";
+}
+
+// Helper for getting string representation of the RegistrationRequest::Status
+// enum.
+std::string GetUnregistrationStatusString(
+ gcm::UnregistrationRequest::Status status) {
+ switch (status) {
+ case gcm::UnregistrationRequest::SUCCESS:
+ return "SUCCESS";
+ case gcm::UnregistrationRequest::URL_FETCHING_FAILED:
+ return "URL_FETCHING_FAILED";
+ case gcm::UnregistrationRequest::NO_RESPONSE_BODY:
+ return "NO_RESPONSE_BODY";
+ case gcm::UnregistrationRequest::RESPONSE_PARSING_FAILED:
+ return "RESPONSE_PARSING_FAILED";
+ case gcm::UnregistrationRequest::INCORRECT_APP_ID:
+ return "INCORRECT_APP_ID";
+ case gcm::UnregistrationRequest::INVALID_PARAMETERS:
+ return "INVALID_PARAMETERS";
+ case gcm::UnregistrationRequest::SERVICE_UNAVAILABLE:
+ return "SERVICE_UNAVAILABLE";
+ case gcm::UnregistrationRequest::INTERNAL_SERVER_ERROR:
+ return "INTERNAL_SERVER_ERROR";
+ case gcm::UnregistrationRequest::HTTP_NOT_OK:
+ return "HTTP_NOT_OK";
+ case gcm::UnregistrationRequest::UNKNOWN_ERROR:
+ return "UNKNOWN_ERROR";
+ case gcm::UnregistrationRequest::REACHED_MAX_RETRIES:
+ return "REACHED_MAX_RETRIES";
+ case gcm::UnregistrationRequest::DEVICE_REGISTRATION_ERROR:
+ return "DEVICE_REGISTRATION_ERROR";
+ case gcm::UnregistrationRequest::UNREGISTRATION_STATUS_COUNT:
+ NOTREACHED();
+ break;
+ }
+ return "UNKNOWN_STATUS";
+}
+
+} // namespace
+
+GCMStatsRecorderImpl::GCMStatsRecorderImpl()
+ : is_recording_(false), delegate_(nullptr) {}
+
+GCMStatsRecorderImpl::~GCMStatsRecorderImpl() = default;
+
+void GCMStatsRecorderImpl::SetDelegate(Delegate* delegate) {
+ delegate_ = delegate;
+}
+
+void GCMStatsRecorderImpl::Clear() {
+ checkin_activities_.clear();
+ connection_activities_.clear();
+ registration_activities_.clear();
+ receiving_activities_.clear();
+ sending_activities_.clear();
+ decryption_failure_activities_.clear();
+}
+
+void GCMStatsRecorderImpl::NotifyActivityRecorded() {
+ if (delegate_)
+ delegate_->OnActivityRecorded();
+}
+
+void GCMStatsRecorderImpl::RecordDecryptionFailure(const std::string& app_id,
+ GCMDecryptionResult result) {
+ DCHECK_NE(result, GCMDecryptionResult::UNENCRYPTED);
+ DCHECK_NE(result, GCMDecryptionResult::DECRYPTED_DRAFT_03);
+ DCHECK_NE(result, GCMDecryptionResult::DECRYPTED_DRAFT_08);
+ if (!is_recording_)
+ return;
+
+ DecryptionFailureActivity data;
+ DecryptionFailureActivity* inserted_data = InsertCircularBuffer(
+ &decryption_failure_activities_, data);
+ inserted_data->app_id = app_id;
+ inserted_data->details = ToGCMDecryptionResultDetailsString(result);
+
+ NotifyActivityRecorded();
+}
+
+void GCMStatsRecorderImpl::RecordCheckin(
+ const std::string& event,
+ const std::string& details) {
+ CheckinActivity data;
+ CheckinActivity* inserted_data = InsertCircularBuffer(
+ &checkin_activities_, data);
+ inserted_data->event = event;
+ inserted_data->details = details;
+ NotifyActivityRecorded();
+}
+
+void GCMStatsRecorderImpl::RecordCheckinInitiated(uint64_t android_id) {
+ if (!is_recording_)
+ return;
+ RecordCheckin("Checkin initiated",
+ base::StringPrintf("Android Id: %" PRIu64, android_id));
+}
+
+void GCMStatsRecorderImpl::RecordCheckinDelayedDueToBackoff(
+ int64_t delay_msec) {
+ if (!is_recording_)
+ return;
+ RecordCheckin("Checkin backoff",
+ base::StringPrintf("Delayed for %" PRId64 " msec",
+ delay_msec));
+}
+
+void GCMStatsRecorderImpl::RecordCheckinSuccess() {
+ if (!is_recording_)
+ return;
+ RecordCheckin("Checkin succeeded", std::string());
+}
+
+void GCMStatsRecorderImpl::RecordCheckinFailure(const std::string& status,
+ bool will_retry) {
+ if (!is_recording_)
+ return;
+ RecordCheckin("Checkin failed", base::StringPrintf(
+ "%s.%s",
+ status.c_str(),
+ will_retry ? " Will retry." : "Will not retry."));
+}
+
+void GCMStatsRecorderImpl::RecordConnection(
+ const std::string& event,
+ const std::string& details) {
+ ConnectionActivity data;
+ ConnectionActivity* inserted_data = InsertCircularBuffer(
+ &connection_activities_, data);
+ inserted_data->event = event;
+ inserted_data->details = details;
+ NotifyActivityRecorded();
+}
+
+void GCMStatsRecorderImpl::RecordConnectionInitiated(const std::string& host) {
+ last_connection_initiation_time_ = base::TimeTicks::Now();
+ if (!is_recording_)
+ return;
+
+ RecordConnection("Connection initiated", host);
+}
+
+void GCMStatsRecorderImpl::RecordConnectionDelayedDueToBackoff(
+ int64_t delay_msec) {
+ if (!is_recording_)
+ return;
+
+ RecordConnection("Connection backoff",
+ base::StringPrintf("Delayed for %" PRId64 " msec",
+ delay_msec));
+}
+
+void GCMStatsRecorderImpl::RecordConnectionSuccess() {
+ DCHECK(!last_connection_initiation_time_.is_null());
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "GCM.ConnectionLatency",
+ (base::TimeTicks::Now() - last_connection_initiation_time_));
+ last_connection_initiation_time_ = base::TimeTicks();
+ if (!is_recording_)
+ return;
+ RecordConnection("Connection succeeded", std::string());
+}
+
+void GCMStatsRecorderImpl::RecordConnectionFailure(int network_error) {
+ if (!is_recording_)
+ return;
+ RecordConnection("Connection failed",
+ base::StringPrintf("With network error %d", network_error));
+}
+
+void GCMStatsRecorderImpl::RecordConnectionResetSignaled(
+ ConnectionFactory::ConnectionResetReason reason) {
+ if (!is_recording_)
+ return;
+ RecordConnection("Connection reset",
+ GetConnectionResetReasonString(reason));
+}
+
+void GCMStatsRecorderImpl::RecordRegistration(
+ const std::string& app_id,
+ const std::string& source,
+ const std::string& event,
+ const std::string& details) {
+ RegistrationActivity data;
+ RegistrationActivity* inserted_data = InsertCircularBuffer(
+ &registration_activities_, data);
+ inserted_data->app_id = app_id;
+ inserted_data->source = source;
+ inserted_data->event = event;
+ inserted_data->details = details;
+ NotifyActivityRecorded();
+}
+
+void GCMStatsRecorderImpl::RecordRegistrationSent(
+ const std::string& app_id,
+ const std::string& sender_ids) {
+ UMA_HISTOGRAM_COUNTS_1M("GCM.RegistrationRequest", 1);
+ if (!is_recording_)
+ return;
+ RecordRegistration(app_id, sender_ids,
+ "Registration request sent", std::string());
+}
+
+void GCMStatsRecorderImpl::RecordRegistrationResponse(
+ const std::string& app_id,
+ const std::string& source,
+ RegistrationRequest::Status status) {
+ if (!is_recording_)
+ return;
+ RecordRegistration(app_id, source,
+ "Registration response received",
+ GetRegistrationStatusString(status));
+}
+
+void GCMStatsRecorderImpl::RecordRegistrationRetryDelayed(
+ const std::string& app_id,
+ const std::string& source,
+ int64_t delay_msec,
+ int retries_left) {
+ if (!is_recording_)
+ return;
+ RecordRegistration(
+ app_id,
+ source,
+ "Registration retry delayed",
+ base::StringPrintf("Delayed for %" PRId64 " msec, retries left: %d",
+ delay_msec,
+ retries_left));
+}
+
+void GCMStatsRecorderImpl::RecordUnregistrationSent(
+ const std::string& app_id, const std::string& source) {
+ UMA_HISTOGRAM_COUNTS_1M("GCM.UnregistrationRequest", 1);
+ if (!is_recording_)
+ return;
+ RecordRegistration(app_id, source, "Unregistration request sent",
+ std::string());
+}
+
+void GCMStatsRecorderImpl::RecordUnregistrationResponse(
+ const std::string& app_id,
+ const std::string& source,
+ UnregistrationRequest::Status status) {
+ if (!is_recording_)
+ return;
+ RecordRegistration(app_id,
+ source,
+ "Unregistration response received",
+ GetUnregistrationStatusString(status));
+}
+
+void GCMStatsRecorderImpl::RecordUnregistrationRetryDelayed(
+ const std::string& app_id,
+ const std::string& source,
+ int64_t delay_msec,
+ int retries_left) {
+ if (!is_recording_)
+ return;
+ RecordRegistration(
+ app_id,
+ source,
+ "Unregistration retry delayed",
+ base::StringPrintf("Delayed for %" PRId64 " msec, retries left: %d",
+ delay_msec,
+ retries_left));
+}
+
+void GCMStatsRecorderImpl::RecordReceiving(
+ const std::string& app_id,
+ const std::string& from,
+ int message_byte_size,
+ const std::string& event,
+ const std::string& details) {
+ ReceivingActivity data;
+ ReceivingActivity* inserted_data = InsertCircularBuffer(
+ &receiving_activities_, data);
+ inserted_data->app_id = app_id;
+ inserted_data->from = from;
+ inserted_data->message_byte_size = message_byte_size;
+ inserted_data->event = event;
+ inserted_data->details = details;
+ NotifyActivityRecorded();
+}
+
+void GCMStatsRecorderImpl::RecordDataMessageReceived(
+ const std::string& app_id,
+ const std::string& from,
+ int message_byte_size,
+ ReceivedMessageType message_type) {
+ if (!is_recording_)
+ return;
+
+ switch (message_type) {
+ case GCMStatsRecorderImpl::DATA_MESSAGE:
+ RecordReceiving(app_id, from, message_byte_size, "Data msg received",
+ std::string());
+ break;
+ case GCMStatsRecorderImpl::DELETED_MESSAGES:
+ RecordReceiving(app_id, from, message_byte_size, "Data msg received",
+ "Message has been deleted on server");
+ break;
+ }
+}
+
+void GCMStatsRecorderImpl::CollectActivities(
+ RecordedActivities* recorded_activities) const {
+ recorded_activities->checkin_activities.insert(
+ recorded_activities->checkin_activities.begin(),
+ checkin_activities_.begin(),
+ checkin_activities_.end());
+ recorded_activities->connection_activities.insert(
+ recorded_activities->connection_activities.begin(),
+ connection_activities_.begin(),
+ connection_activities_.end());
+ recorded_activities->registration_activities.insert(
+ recorded_activities->registration_activities.begin(),
+ registration_activities_.begin(),
+ registration_activities_.end());
+ recorded_activities->receiving_activities.insert(
+ recorded_activities->receiving_activities.begin(),
+ receiving_activities_.begin(),
+ receiving_activities_.end());
+ recorded_activities->sending_activities.insert(
+ recorded_activities->sending_activities.begin(),
+ sending_activities_.begin(),
+ sending_activities_.end());
+ recorded_activities->decryption_failure_activities.insert(
+ recorded_activities->decryption_failure_activities.begin(),
+ decryption_failure_activities_.begin(),
+ decryption_failure_activities_.end());
+}
+
+void GCMStatsRecorderImpl::RecordSending(const std::string& app_id,
+ const std::string& receiver_id,
+ const std::string& message_id,
+ const std::string& event,
+ const std::string& details) {
+ SendingActivity data;
+ SendingActivity* inserted_data = InsertCircularBuffer(
+ &sending_activities_, data);
+ inserted_data->app_id = app_id;
+ inserted_data->receiver_id = receiver_id;
+ inserted_data->message_id = message_id;
+ inserted_data->event = event;
+ inserted_data->details = details;
+ NotifyActivityRecorded();
+}
+
+void GCMStatsRecorderImpl::RecordDataSentToWire(
+ const std::string& app_id,
+ const std::string& receiver_id,
+ const std::string& message_id,
+ int queued) {
+ if (!is_recording_)
+ return;
+ RecordSending(app_id, receiver_id, message_id, "Data msg sent to wire",
+ base::StringPrintf("Msg queued for %d seconds", queued));
+}
+
+void GCMStatsRecorderImpl::RecordNotifySendStatus(
+ const std::string& app_id,
+ const std::string& receiver_id,
+ const std::string& message_id,
+ gcm::MCSClient::MessageSendStatus status,
+ int byte_size,
+ int ttl) {
+ UMA_HISTOGRAM_ENUMERATION("GCM.SendMessageStatus", status,
+ gcm::MCSClient::SEND_STATUS_COUNT);
+ if (!is_recording_)
+ return;
+ RecordSending(
+ app_id,
+ receiver_id,
+ message_id,
+ base::StringPrintf("SEND status: %s",
+ GetMessageSendStatusString(status).c_str()),
+ base::StringPrintf("Msg size: %d bytes, TTL: %d", byte_size, ttl));
+}
+
+void GCMStatsRecorderImpl::RecordIncomingSendError(
+ const std::string& app_id,
+ const std::string& receiver_id,
+ const std::string& message_id) {
+ UMA_HISTOGRAM_COUNTS_1M("GCM.IncomingSendErrors", 1);
+ if (!is_recording_)
+ return;
+ RecordSending(app_id, receiver_id, message_id, "Received 'send error' msg",
+ std::string());
+}
+
+} // namespace gcm