gcm_stats_recorder_impl.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/gcm_driver/gcm_stats_recorder_impl.h"
  5. #include "base/containers/circular_deque.h"
  6. #include "base/format_macros.h"
  7. #include "base/logging.h"
  8. #include "base/metrics/histogram_macros.h"
  9. #include "base/strings/string_util.h"
  10. #include "base/strings/stringprintf.h"
  11. #include "components/gcm_driver/crypto/gcm_decryption_result.h"
  12. #include "components/gcm_driver/crypto/gcm_encryption_provider.h"
  13. namespace gcm {
  14. const uint32_t MAX_LOGGED_ACTIVITY_COUNT = 100;
  15. namespace {
  16. // Insert an item to the front of deque while maintaining the size of the deque.
  17. // Overflow item is discarded.
  18. //
  19. // DANGER: the returned pointer will not be valind if the queue is modified.
  20. template <typename T>
  21. T* InsertCircularBuffer(base::circular_deque<T>* q, const T& item) {
  22. DCHECK(q);
  23. if (q->size() > MAX_LOGGED_ACTIVITY_COUNT - 1) {
  24. q->pop_back();
  25. }
  26. q->push_front(item);
  27. return &q->front();
  28. }
  29. // Helper for getting string representation of the MessageSendStatus enum.
  30. std::string GetMessageSendStatusString(
  31. gcm::MCSClient::MessageSendStatus status) {
  32. switch (status) {
  33. case gcm::MCSClient::QUEUED:
  34. return "QUEUED";
  35. case gcm::MCSClient::SENT:
  36. return "SENT";
  37. case gcm::MCSClient::QUEUE_SIZE_LIMIT_REACHED:
  38. return "QUEUE_SIZE_LIMIT_REACHED";
  39. case gcm::MCSClient::APP_QUEUE_SIZE_LIMIT_REACHED:
  40. return "APP_QUEUE_SIZE_LIMIT_REACHED";
  41. case gcm::MCSClient::MESSAGE_TOO_LARGE:
  42. return "MESSAGE_TOO_LARGE";
  43. case gcm::MCSClient::NO_CONNECTION_ON_ZERO_TTL:
  44. return "NO_CONNECTION_ON_ZERO_TTL";
  45. case gcm::MCSClient::TTL_EXCEEDED:
  46. return "TTL_EXCEEDED";
  47. case gcm::MCSClient::SEND_STATUS_COUNT:
  48. NOTREACHED();
  49. break;
  50. }
  51. return "UNKNOWN";
  52. }
  53. // Helper for getting string representation of the
  54. // ConnectionFactory::ConnectionResetReason enum.
  55. std::string GetConnectionResetReasonString(
  56. gcm::ConnectionFactory::ConnectionResetReason reason) {
  57. switch (reason) {
  58. case gcm::ConnectionFactory::LOGIN_FAILURE:
  59. return "LOGIN_FAILURE";
  60. case gcm::ConnectionFactory::CLOSE_COMMAND:
  61. return "CLOSE_COMMAND";
  62. case gcm::ConnectionFactory::HEARTBEAT_FAILURE:
  63. return "HEARTBEAT_FAILURE";
  64. case gcm::ConnectionFactory::SOCKET_FAILURE:
  65. return "SOCKET_FAILURE";
  66. case gcm::ConnectionFactory::NETWORK_CHANGE:
  67. return "NETWORK_CHANGE";
  68. case gcm::ConnectionFactory::NEW_HEARTBEAT_INTERVAL:
  69. return "NEW_HEARTBEAT_INTERVAL";
  70. case gcm::ConnectionFactory::CONNECTION_RESET_COUNT:
  71. NOTREACHED();
  72. break;
  73. }
  74. return "UNKNOWN_REASON";
  75. }
  76. // Helper for getting string representation of the RegistrationRequest::Status
  77. // enum.
  78. std::string GetRegistrationStatusString(
  79. gcm::RegistrationRequest::Status status) {
  80. switch (status) {
  81. case gcm::RegistrationRequest::SUCCESS:
  82. return "SUCCESS";
  83. case gcm::RegistrationRequest::INVALID_PARAMETERS:
  84. return "INVALID_PARAMETERS";
  85. case gcm::RegistrationRequest::INVALID_SENDER:
  86. return "INVALID_SENDER";
  87. case gcm::RegistrationRequest::AUTHENTICATION_FAILED:
  88. return "AUTHENTICATION_FAILED";
  89. case gcm::RegistrationRequest::DEVICE_REGISTRATION_ERROR:
  90. return "DEVICE_REGISTRATION_ERROR";
  91. case gcm::RegistrationRequest::UNKNOWN_ERROR:
  92. return "UNKNOWN_ERROR";
  93. case gcm::RegistrationRequest::URL_FETCHING_FAILED:
  94. return "URL_FETCHING_FAILED";
  95. case gcm::RegistrationRequest::HTTP_NOT_OK:
  96. return "HTTP_NOT_OK";
  97. case gcm::RegistrationRequest::NO_RESPONSE_BODY:
  98. return "NO_RESPONSE_BODY";
  99. case gcm::RegistrationRequest::REACHED_MAX_RETRIES:
  100. return "REACHED_MAX_RETRIES";
  101. case gcm::RegistrationRequest::RESPONSE_PARSING_FAILED:
  102. return "RESPONSE_PARSING_FAILED";
  103. case gcm::RegistrationRequest::INTERNAL_SERVER_ERROR:
  104. return "INTERNAL_SERVER_ERROR";
  105. case gcm::RegistrationRequest::QUOTA_EXCEEDED:
  106. return "QUOTA_EXCEEDED";
  107. case gcm::RegistrationRequest::TOO_MANY_REGISTRATIONS:
  108. return "TOO_MANY_REGISTRATIONS";
  109. case gcm::RegistrationRequest::STATUS_COUNT:
  110. NOTREACHED();
  111. break;
  112. }
  113. return "UNKNOWN_STATUS";
  114. }
  115. // Helper for getting string representation of the RegistrationRequest::Status
  116. // enum.
  117. std::string GetUnregistrationStatusString(
  118. gcm::UnregistrationRequest::Status status) {
  119. switch (status) {
  120. case gcm::UnregistrationRequest::SUCCESS:
  121. return "SUCCESS";
  122. case gcm::UnregistrationRequest::URL_FETCHING_FAILED:
  123. return "URL_FETCHING_FAILED";
  124. case gcm::UnregistrationRequest::NO_RESPONSE_BODY:
  125. return "NO_RESPONSE_BODY";
  126. case gcm::UnregistrationRequest::RESPONSE_PARSING_FAILED:
  127. return "RESPONSE_PARSING_FAILED";
  128. case gcm::UnregistrationRequest::INCORRECT_APP_ID:
  129. return "INCORRECT_APP_ID";
  130. case gcm::UnregistrationRequest::INVALID_PARAMETERS:
  131. return "INVALID_PARAMETERS";
  132. case gcm::UnregistrationRequest::SERVICE_UNAVAILABLE:
  133. return "SERVICE_UNAVAILABLE";
  134. case gcm::UnregistrationRequest::INTERNAL_SERVER_ERROR:
  135. return "INTERNAL_SERVER_ERROR";
  136. case gcm::UnregistrationRequest::HTTP_NOT_OK:
  137. return "HTTP_NOT_OK";
  138. case gcm::UnregistrationRequest::UNKNOWN_ERROR:
  139. return "UNKNOWN_ERROR";
  140. case gcm::UnregistrationRequest::REACHED_MAX_RETRIES:
  141. return "REACHED_MAX_RETRIES";
  142. case gcm::UnregistrationRequest::DEVICE_REGISTRATION_ERROR:
  143. return "DEVICE_REGISTRATION_ERROR";
  144. case gcm::UnregistrationRequest::UNREGISTRATION_STATUS_COUNT:
  145. NOTREACHED();
  146. break;
  147. }
  148. return "UNKNOWN_STATUS";
  149. }
  150. } // namespace
  151. GCMStatsRecorderImpl::GCMStatsRecorderImpl()
  152. : is_recording_(false), delegate_(nullptr) {}
  153. GCMStatsRecorderImpl::~GCMStatsRecorderImpl() = default;
  154. void GCMStatsRecorderImpl::SetDelegate(Delegate* delegate) {
  155. delegate_ = delegate;
  156. }
  157. void GCMStatsRecorderImpl::Clear() {
  158. checkin_activities_.clear();
  159. connection_activities_.clear();
  160. registration_activities_.clear();
  161. receiving_activities_.clear();
  162. sending_activities_.clear();
  163. decryption_failure_activities_.clear();
  164. }
  165. void GCMStatsRecorderImpl::NotifyActivityRecorded() {
  166. if (delegate_)
  167. delegate_->OnActivityRecorded();
  168. }
  169. void GCMStatsRecorderImpl::RecordDecryptionFailure(const std::string& app_id,
  170. GCMDecryptionResult result) {
  171. DCHECK_NE(result, GCMDecryptionResult::UNENCRYPTED);
  172. DCHECK_NE(result, GCMDecryptionResult::DECRYPTED_DRAFT_03);
  173. DCHECK_NE(result, GCMDecryptionResult::DECRYPTED_DRAFT_08);
  174. if (!is_recording_)
  175. return;
  176. DecryptionFailureActivity data;
  177. DecryptionFailureActivity* inserted_data = InsertCircularBuffer(
  178. &decryption_failure_activities_, data);
  179. inserted_data->app_id = app_id;
  180. inserted_data->details = ToGCMDecryptionResultDetailsString(result);
  181. NotifyActivityRecorded();
  182. }
  183. void GCMStatsRecorderImpl::RecordCheckin(
  184. const std::string& event,
  185. const std::string& details) {
  186. CheckinActivity data;
  187. CheckinActivity* inserted_data = InsertCircularBuffer(
  188. &checkin_activities_, data);
  189. inserted_data->event = event;
  190. inserted_data->details = details;
  191. NotifyActivityRecorded();
  192. }
  193. void GCMStatsRecorderImpl::RecordCheckinInitiated(uint64_t android_id) {
  194. if (!is_recording_)
  195. return;
  196. RecordCheckin("Checkin initiated",
  197. base::StringPrintf("Android Id: %" PRIu64, android_id));
  198. }
  199. void GCMStatsRecorderImpl::RecordCheckinDelayedDueToBackoff(
  200. int64_t delay_msec) {
  201. if (!is_recording_)
  202. return;
  203. RecordCheckin("Checkin backoff",
  204. base::StringPrintf("Delayed for %" PRId64 " msec",
  205. delay_msec));
  206. }
  207. void GCMStatsRecorderImpl::RecordCheckinSuccess() {
  208. if (!is_recording_)
  209. return;
  210. RecordCheckin("Checkin succeeded", std::string());
  211. }
  212. void GCMStatsRecorderImpl::RecordCheckinFailure(const std::string& status,
  213. bool will_retry) {
  214. if (!is_recording_)
  215. return;
  216. RecordCheckin("Checkin failed", base::StringPrintf(
  217. "%s.%s",
  218. status.c_str(),
  219. will_retry ? " Will retry." : "Will not retry."));
  220. }
  221. void GCMStatsRecorderImpl::RecordConnection(
  222. const std::string& event,
  223. const std::string& details) {
  224. ConnectionActivity data;
  225. ConnectionActivity* inserted_data = InsertCircularBuffer(
  226. &connection_activities_, data);
  227. inserted_data->event = event;
  228. inserted_data->details = details;
  229. NotifyActivityRecorded();
  230. }
  231. void GCMStatsRecorderImpl::RecordConnectionInitiated(const std::string& host) {
  232. last_connection_initiation_time_ = base::TimeTicks::Now();
  233. if (!is_recording_)
  234. return;
  235. RecordConnection("Connection initiated", host);
  236. }
  237. void GCMStatsRecorderImpl::RecordConnectionDelayedDueToBackoff(
  238. int64_t delay_msec) {
  239. if (!is_recording_)
  240. return;
  241. RecordConnection("Connection backoff",
  242. base::StringPrintf("Delayed for %" PRId64 " msec",
  243. delay_msec));
  244. }
  245. void GCMStatsRecorderImpl::RecordConnectionSuccess() {
  246. DCHECK(!last_connection_initiation_time_.is_null());
  247. UMA_HISTOGRAM_MEDIUM_TIMES(
  248. "GCM.ConnectionLatency",
  249. (base::TimeTicks::Now() - last_connection_initiation_time_));
  250. last_connection_initiation_time_ = base::TimeTicks();
  251. if (!is_recording_)
  252. return;
  253. RecordConnection("Connection succeeded", std::string());
  254. }
  255. void GCMStatsRecorderImpl::RecordConnectionFailure(int network_error) {
  256. if (!is_recording_)
  257. return;
  258. RecordConnection("Connection failed",
  259. base::StringPrintf("With network error %d", network_error));
  260. }
  261. void GCMStatsRecorderImpl::RecordConnectionResetSignaled(
  262. ConnectionFactory::ConnectionResetReason reason) {
  263. if (!is_recording_)
  264. return;
  265. RecordConnection("Connection reset",
  266. GetConnectionResetReasonString(reason));
  267. }
  268. void GCMStatsRecorderImpl::RecordRegistration(
  269. const std::string& app_id,
  270. const std::string& source,
  271. const std::string& event,
  272. const std::string& details) {
  273. RegistrationActivity data;
  274. RegistrationActivity* inserted_data = InsertCircularBuffer(
  275. &registration_activities_, data);
  276. inserted_data->app_id = app_id;
  277. inserted_data->source = source;
  278. inserted_data->event = event;
  279. inserted_data->details = details;
  280. NotifyActivityRecorded();
  281. }
  282. void GCMStatsRecorderImpl::RecordRegistrationSent(
  283. const std::string& app_id,
  284. const std::string& sender_ids) {
  285. UMA_HISTOGRAM_COUNTS_1M("GCM.RegistrationRequest", 1);
  286. if (!is_recording_)
  287. return;
  288. RecordRegistration(app_id, sender_ids,
  289. "Registration request sent", std::string());
  290. }
  291. void GCMStatsRecorderImpl::RecordRegistrationResponse(
  292. const std::string& app_id,
  293. const std::string& source,
  294. RegistrationRequest::Status status) {
  295. if (!is_recording_)
  296. return;
  297. RecordRegistration(app_id, source,
  298. "Registration response received",
  299. GetRegistrationStatusString(status));
  300. }
  301. void GCMStatsRecorderImpl::RecordRegistrationRetryDelayed(
  302. const std::string& app_id,
  303. const std::string& source,
  304. int64_t delay_msec,
  305. int retries_left) {
  306. if (!is_recording_)
  307. return;
  308. RecordRegistration(
  309. app_id,
  310. source,
  311. "Registration retry delayed",
  312. base::StringPrintf("Delayed for %" PRId64 " msec, retries left: %d",
  313. delay_msec,
  314. retries_left));
  315. }
  316. void GCMStatsRecorderImpl::RecordUnregistrationSent(
  317. const std::string& app_id, const std::string& source) {
  318. UMA_HISTOGRAM_COUNTS_1M("GCM.UnregistrationRequest", 1);
  319. if (!is_recording_)
  320. return;
  321. RecordRegistration(app_id, source, "Unregistration request sent",
  322. std::string());
  323. }
  324. void GCMStatsRecorderImpl::RecordUnregistrationResponse(
  325. const std::string& app_id,
  326. const std::string& source,
  327. UnregistrationRequest::Status status) {
  328. if (!is_recording_)
  329. return;
  330. RecordRegistration(app_id,
  331. source,
  332. "Unregistration response received",
  333. GetUnregistrationStatusString(status));
  334. }
  335. void GCMStatsRecorderImpl::RecordUnregistrationRetryDelayed(
  336. const std::string& app_id,
  337. const std::string& source,
  338. int64_t delay_msec,
  339. int retries_left) {
  340. if (!is_recording_)
  341. return;
  342. RecordRegistration(
  343. app_id,
  344. source,
  345. "Unregistration retry delayed",
  346. base::StringPrintf("Delayed for %" PRId64 " msec, retries left: %d",
  347. delay_msec,
  348. retries_left));
  349. }
  350. void GCMStatsRecorderImpl::RecordReceiving(
  351. const std::string& app_id,
  352. const std::string& from,
  353. int message_byte_size,
  354. const std::string& event,
  355. const std::string& details) {
  356. ReceivingActivity data;
  357. ReceivingActivity* inserted_data = InsertCircularBuffer(
  358. &receiving_activities_, data);
  359. inserted_data->app_id = app_id;
  360. inserted_data->from = from;
  361. inserted_data->message_byte_size = message_byte_size;
  362. inserted_data->event = event;
  363. inserted_data->details = details;
  364. NotifyActivityRecorded();
  365. }
  366. void GCMStatsRecorderImpl::RecordDataMessageReceived(
  367. const std::string& app_id,
  368. const std::string& from,
  369. int message_byte_size,
  370. ReceivedMessageType message_type) {
  371. if (!is_recording_)
  372. return;
  373. switch (message_type) {
  374. case GCMStatsRecorderImpl::DATA_MESSAGE:
  375. RecordReceiving(app_id, from, message_byte_size, "Data msg received",
  376. std::string());
  377. break;
  378. case GCMStatsRecorderImpl::DELETED_MESSAGES:
  379. RecordReceiving(app_id, from, message_byte_size, "Data msg received",
  380. "Message has been deleted on server");
  381. break;
  382. }
  383. }
  384. void GCMStatsRecorderImpl::CollectActivities(
  385. RecordedActivities* recorded_activities) const {
  386. recorded_activities->checkin_activities.insert(
  387. recorded_activities->checkin_activities.begin(),
  388. checkin_activities_.begin(),
  389. checkin_activities_.end());
  390. recorded_activities->connection_activities.insert(
  391. recorded_activities->connection_activities.begin(),
  392. connection_activities_.begin(),
  393. connection_activities_.end());
  394. recorded_activities->registration_activities.insert(
  395. recorded_activities->registration_activities.begin(),
  396. registration_activities_.begin(),
  397. registration_activities_.end());
  398. recorded_activities->receiving_activities.insert(
  399. recorded_activities->receiving_activities.begin(),
  400. receiving_activities_.begin(),
  401. receiving_activities_.end());
  402. recorded_activities->sending_activities.insert(
  403. recorded_activities->sending_activities.begin(),
  404. sending_activities_.begin(),
  405. sending_activities_.end());
  406. recorded_activities->decryption_failure_activities.insert(
  407. recorded_activities->decryption_failure_activities.begin(),
  408. decryption_failure_activities_.begin(),
  409. decryption_failure_activities_.end());
  410. }
  411. void GCMStatsRecorderImpl::RecordSending(const std::string& app_id,
  412. const std::string& receiver_id,
  413. const std::string& message_id,
  414. const std::string& event,
  415. const std::string& details) {
  416. SendingActivity data;
  417. SendingActivity* inserted_data = InsertCircularBuffer(
  418. &sending_activities_, data);
  419. inserted_data->app_id = app_id;
  420. inserted_data->receiver_id = receiver_id;
  421. inserted_data->message_id = message_id;
  422. inserted_data->event = event;
  423. inserted_data->details = details;
  424. NotifyActivityRecorded();
  425. }
  426. void GCMStatsRecorderImpl::RecordDataSentToWire(
  427. const std::string& app_id,
  428. const std::string& receiver_id,
  429. const std::string& message_id,
  430. int queued) {
  431. if (!is_recording_)
  432. return;
  433. RecordSending(app_id, receiver_id, message_id, "Data msg sent to wire",
  434. base::StringPrintf("Msg queued for %d seconds", queued));
  435. }
  436. void GCMStatsRecorderImpl::RecordNotifySendStatus(
  437. const std::string& app_id,
  438. const std::string& receiver_id,
  439. const std::string& message_id,
  440. gcm::MCSClient::MessageSendStatus status,
  441. int byte_size,
  442. int ttl) {
  443. UMA_HISTOGRAM_ENUMERATION("GCM.SendMessageStatus", status,
  444. gcm::MCSClient::SEND_STATUS_COUNT);
  445. if (!is_recording_)
  446. return;
  447. RecordSending(
  448. app_id,
  449. receiver_id,
  450. message_id,
  451. base::StringPrintf("SEND status: %s",
  452. GetMessageSendStatusString(status).c_str()),
  453. base::StringPrintf("Msg size: %d bytes, TTL: %d", byte_size, ttl));
  454. }
  455. void GCMStatsRecorderImpl::RecordIncomingSendError(
  456. const std::string& app_id,
  457. const std::string& receiver_id,
  458. const std::string& message_id) {
  459. UMA_HISTOGRAM_COUNTS_1M("GCM.IncomingSendErrors", 1);
  460. if (!is_recording_)
  461. return;
  462. RecordSending(app_id, receiver_id, message_id, "Received 'send error' msg",
  463. std::string());
  464. }
  465. } // namespace gcm