1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/android/jank_metric_uma_recorder.h"
12 #include "base/android/jni_android.h"
13 #include "base/android/jni_array.h"
14 #include "base/android/jni_string.h"
15 #include "base/metrics/histogram.h"
16 #include "base/test/metrics/histogram_tester.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 using ::testing::ElementsAre;
21 using ::testing::IsEmpty;
23 namespace base::android {
26 jlongArray GenerateJavaLongArray(JNIEnv* env,
27 const int64_t long_array[],
28 const size_t array_length) {
29 ScopedJavaLocalRef<jlongArray> java_long_array =
30 ToJavaLongArray(env, long_array, array_length);
32 return java_long_array.Release();
35 // Durations are received in nanoseconds, but are recorded to UMA in
37 const int64_t kDurations[] = {
47 const size_t kDurationsLen = std::size(kDurations);
49 jbooleanArray GenerateJavaBooleanArray(JNIEnv* env,
50 const bool bool_array[],
51 const size_t array_length) {
52 ScopedJavaLocalRef<jbooleanArray> java_bool_array =
53 ToJavaBooleanArray(env, bool_array, array_length);
55 return java_bool_array.Release();
58 const bool kJankStatus[] = {
59 false, false, true, false, true, false, false, false,
61 const size_t kJankStatusLen = kDurationsLen;
65 TEST(JankMetricUMARecorder, TestUMARecording) {
67 JNIEnv* env = AttachCurrentThread();
69 jlongArray java_durations =
70 GenerateJavaLongArray(env, kDurations, kDurationsLen);
72 jbooleanArray java_jank_status =
73 GenerateJavaBooleanArray(env, kJankStatus, kJankStatusLen);
75 const int kMinScenario = static_cast<int>(JankScenario::PERIODIC_REPORTING);
76 const int kMaxScenario = static_cast<int>(JankScenario::MAX_VALUE);
77 // keep one histogram tester outside to ensure that each histogram is a
78 // different one rather than just the same string over and over.
79 HistogramTester complete_histogram_tester;
80 size_t total_histograms = 0;
81 for (int i = kMinScenario; i < kMaxScenario; ++i) {
82 // HistogramTester takes a snapshot of currently incremented counters so
83 // everything is scoped to just this iteration of the for loop.
84 HistogramTester histogram_tester;
88 /* java_durations_ns= */
89 base::android::JavaParamRef<jlongArray>(env, java_durations),
90 /* java_jank_status = */
91 base::android::JavaParamRef<jbooleanArray>(env, java_jank_status),
92 /* java_reporting_interval_start_time = */ 0,
93 /* java_reporting_interval_duration = */ 1000,
94 /* java_scenario_enum = */ i);
96 const std::string kDurationName =
97 GetAndroidFrameTimelineDurationHistogramName(
98 static_cast<JankScenario>(i));
99 const std::string kJankyName =
100 GetAndroidFrameTimelineJankHistogramName(static_cast<JankScenario>(i));
102 // Only one Duration and one Jank scenario should be incremented.
103 base::HistogramTester::CountsMap count_map =
104 histogram_tester.GetTotalCountsForPrefix("Android.FrameTimelineJank.");
105 EXPECT_EQ(count_map.size(), 2ul);
106 EXPECT_EQ(count_map[kDurationName], 8) << kDurationName;
107 EXPECT_EQ(count_map[kJankyName], 8) << kJankyName;
108 // And we should be two more then last iteration, but don't do any other
109 // verification because each iteration will do their own.
110 base::HistogramTester::CountsMap total_count_map =
111 complete_histogram_tester.GetTotalCountsForPrefix(
112 "Android.FrameTimelineJank.");
113 EXPECT_EQ(total_count_map.size(), total_histograms + 2);
114 total_histograms += 2;
116 EXPECT_THAT(histogram_tester.GetAllSamples(kDurationName),
117 ElementsAre(Bucket(1, 3), Bucket(2, 1), Bucket(10, 1),
118 Bucket(20, 1), Bucket(29, 1), Bucket(57, 1)))
120 EXPECT_THAT(histogram_tester.GetAllSamples(kJankyName),
121 ElementsAre(Bucket(FrameJankStatus::kJanky, 2),
122 Bucket(FrameJankStatus::kNonJanky, 6)))
126 } // namespace base::android