diagnostics_metrics_message_handler.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Copyright 2021 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 "ash/webui/diagnostics_ui/diagnostics_metrics_message_handler.h"
  5. #include "base/bind.h"
  6. #include "base/check.h"
  7. #include "base/check_op.h"
  8. #include "base/containers/fixed_flat_map.h"
  9. #include "base/containers/flat_map.h"
  10. #include "base/metrics/histogram_functions.h"
  11. #include "base/notreached.h"
  12. #include "base/strings/string_piece_forward.h"
  13. #include "base/time/time.h"
  14. #include "content/public/browser/web_ui.h"
  15. namespace ash {
  16. namespace diagnostics {
  17. namespace metrics {
  18. namespace {
  19. // Handler names:
  20. const char kRecordNavigation[] = "recordNavigation";
  21. // Checks Javascript input integrity before parsing.
  22. bool IsValidNavigationViewValue(const base::Value& value) {
  23. return value.is_int() && value.GetInt() >= 0 &&
  24. value.GetInt() <= static_cast<int>(NavigationView::kMaxValue);
  25. }
  26. // Converts base::Value<int> to NavigationView based on enum values.
  27. NavigationView ConvertToNavigationView(const base::Value& value) {
  28. DCHECK(IsValidNavigationViewValue(value));
  29. return static_cast<NavigationView>(value.GetInt());
  30. }
  31. void EmitScreenOpenDuration(const NavigationView screen,
  32. const base::TimeDelta& time_elapsed) {
  33. // Map of screens within Diagnostics app to matching duration metric name.
  34. constexpr auto kOpenDurationMetrics =
  35. base::MakeFixedFlatMap<NavigationView, base::StringPiece>({
  36. {NavigationView::kConnectivity,
  37. "ChromeOS.DiagnosticsUi.Connectivity.OpenDuration"},
  38. {NavigationView::kInput, "ChromeOS.DiagnosticsUi.Input.OpenDuration"},
  39. {NavigationView::kSystem,
  40. "ChromeOS.DiagnosticsUi.System.OpenDuration"},
  41. });
  42. auto* iter = kOpenDurationMetrics.find(screen);
  43. if (iter == kOpenDurationMetrics.end()) {
  44. NOTREACHED() << "Unknown NavigationView requested";
  45. return;
  46. }
  47. base::UmaHistogramLongTimes100(std::string(iter->second), time_elapsed);
  48. }
  49. } // namespace
  50. DiagnosticsMetricsMessageHandler::DiagnosticsMetricsMessageHandler(
  51. NavigationView initial_view)
  52. : current_view_(initial_view) {
  53. navigation_started_ = base::Time::Now();
  54. }
  55. DiagnosticsMetricsMessageHandler::~DiagnosticsMetricsMessageHandler() {
  56. // Emit final navigation event.
  57. EmitScreenOpenDuration(current_view_,
  58. base::Time::Now() - navigation_started_);
  59. }
  60. // content::WebUIMessageHandler:
  61. void DiagnosticsMetricsMessageHandler::RegisterMessages() {
  62. DCHECK(web_ui());
  63. web_ui()->RegisterMessageCallback(
  64. kRecordNavigation,
  65. base::BindRepeating(
  66. &DiagnosticsMetricsMessageHandler::HandleRecordNavigation,
  67. base::Unretained(this)));
  68. }
  69. // Test helpers:
  70. NavigationView DiagnosticsMetricsMessageHandler::GetCurrentViewForTesting() {
  71. return current_view_;
  72. }
  73. base::TimeDelta
  74. DiagnosticsMetricsMessageHandler::GetElapsedNavigationTimeDeltaForTesting() {
  75. return base::Time::Now() - navigation_started_;
  76. }
  77. void DiagnosticsMetricsMessageHandler::SetWebUiForTesting(
  78. content::WebUI* web_ui) {
  79. DCHECK(web_ui);
  80. set_web_ui(web_ui);
  81. }
  82. // Private:
  83. // Message Handlers:
  84. void DiagnosticsMetricsMessageHandler::HandleRecordNavigation(
  85. const base::Value::List& args) {
  86. // Ensure JS arguments received are valid before using in calls to metrics.
  87. if (args.size() != 2u || !IsValidNavigationViewValue(args[0]) ||
  88. !IsValidNavigationViewValue(args[1]) || args[0] == args[1]) {
  89. return;
  90. }
  91. const NavigationView from_view = ConvertToNavigationView(args[0]);
  92. const NavigationView to_view = ConvertToNavigationView(args[1]);
  93. const base::Time updated_start_time = base::Time::Now();
  94. // Recordable navigation event occurred.
  95. EmitScreenOpenDuration(from_view, updated_start_time - navigation_started_);
  96. // `current_view_` updated to recorded `to_view` and reset timer.
  97. current_view_ = to_view;
  98. navigation_started_ = updated_start_time;
  99. }
  100. } // namespace metrics
  101. } // namespace diagnostics
  102. } // namespace ash