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.
5 #include "base/android/record_histogram.h"
9 #include "base/android/jni_android.h"
10 #include "base/android/jni_string.h"
11 #include "base/lazy_instance.h"
12 #include "base/metrics/histogram.h"
13 #include "base/metrics/statistics_recorder.h"
14 #include "base/synchronization/lock.h"
15 #include "base/time/time.h"
16 #include "jni/RecordHistogram_jni.h"
22 // Simple thread-safe wrapper for caching histograms. This avoids
23 // relatively expensive JNI string translation for each recording.
24 class HistogramCache
{
28 HistogramBase
* BooleanHistogram(JNIEnv
* env
,
29 jstring j_histogram_name
,
30 jint j_histogram_key
) {
31 DCHECK(j_histogram_name
);
32 DCHECK(j_histogram_key
);
33 HistogramBase
* histogram
= FindLocked(j_histogram_key
);
37 std::string histogram_name
= ConvertJavaStringToUTF8(env
, j_histogram_name
);
38 histogram
= BooleanHistogram::FactoryGet(
39 histogram_name
, HistogramBase::kUmaTargetedHistogramFlag
);
40 return InsertLocked(j_histogram_key
, histogram
);
43 HistogramBase
* EnumeratedHistogram(JNIEnv
* env
,
44 jstring j_histogram_name
,
47 DCHECK(j_histogram_name
);
48 DCHECK(j_histogram_key
);
49 HistogramBase
* histogram
= FindLocked(j_histogram_key
);
50 int boundary
= static_cast<int>(j_boundary
);
52 DCHECK(histogram
->HasConstructionArguments(1, boundary
, boundary
+ 1));
56 std::string histogram_name
= ConvertJavaStringToUTF8(env
, j_histogram_name
);
58 LinearHistogram::FactoryGet(histogram_name
, 1, boundary
, boundary
+ 1,
59 HistogramBase::kUmaTargetedHistogramFlag
);
60 return InsertLocked(j_histogram_key
, histogram
);
63 HistogramBase
* CountHistogram(JNIEnv
* env
,
64 jstring j_histogram_name
,
65 jint j_histogram_key
) {
66 // These values are based on the hard-coded constants in the
67 // UMA_HISTOGRAM_COUNTS macro from base/metrics/histogram_macros.h.
68 const int histogram_min
= 1;
69 const int histogram_max
= 1000000;
70 const int histogram_num_buckets
= 50;
72 DCHECK(j_histogram_name
);
73 DCHECK(j_histogram_key
);
74 HistogramBase
* histogram
= FindLocked(j_histogram_key
);
76 DCHECK(histogram
->HasConstructionArguments(histogram_min
, histogram_max
,
77 histogram_num_buckets
));
81 std::string histogram_name
= ConvertJavaStringToUTF8(env
, j_histogram_name
);
82 histogram
= Histogram::FactoryGet(histogram_name
, histogram_min
,
83 histogram_max
, histogram_num_buckets
,
84 HistogramBase::kUmaTargetedHistogramFlag
);
85 return InsertLocked(j_histogram_key
, histogram
);
88 HistogramBase
* CustomTimesHistogram(JNIEnv
* env
,
89 jstring j_histogram_name
,
93 jint j_bucket_count
) {
94 DCHECK(j_histogram_name
);
95 DCHECK(j_histogram_key
);
96 HistogramBase
* histogram
= FindLocked(j_histogram_key
);
97 int64 min
= static_cast<int64
>(j_min
);
98 int64 max
= static_cast<int64
>(j_max
);
99 int bucket_count
= static_cast<int>(j_bucket_count
);
101 DCHECK(histogram
->HasConstructionArguments(min
, max
, bucket_count
));
105 std::string histogram_name
= ConvertJavaStringToUTF8(env
, j_histogram_name
);
106 // This intentionally uses FactoryGet and not FactoryTimeGet. FactoryTimeGet
107 // is just a convenience for constructing the underlying Histogram with
108 // TimeDelta arguments.
109 histogram
= Histogram::FactoryGet(histogram_name
, min
, max
, bucket_count
,
110 HistogramBase::kUmaTargetedHistogramFlag
);
111 return InsertLocked(j_histogram_key
, histogram
);
115 HistogramBase
* FindLocked(jint j_histogram_key
) {
116 base::AutoLock
locked(lock_
);
117 auto histogram_it
= histograms_
.find(j_histogram_key
);
118 return histogram_it
!= histograms_
.end() ? histogram_it
->second
: nullptr;
121 HistogramBase
* InsertLocked(jint j_histogram_key
, HistogramBase
* histogram
) {
122 base::AutoLock
locked(lock_
);
123 histograms_
.insert(std::make_pair(j_histogram_key
, histogram
));
128 std::map
<jint
, HistogramBase
*> histograms_
;
130 DISALLOW_COPY_AND_ASSIGN(HistogramCache
);
133 base::LazyInstance
<HistogramCache
>::Leaky g_histograms
;
137 void RecordBooleanHistogram(JNIEnv
* env
,
139 jstring j_histogram_name
,
140 jint j_histogram_key
,
142 bool sample
= static_cast<bool>(j_sample
);
144 .BooleanHistogram(env
, j_histogram_name
, j_histogram_key
)
145 ->AddBoolean(sample
);
148 void RecordEnumeratedHistogram(JNIEnv
* env
,
150 jstring j_histogram_name
,
151 jint j_histogram_key
,
154 int sample
= static_cast<int>(j_sample
);
157 .EnumeratedHistogram(env
, j_histogram_name
, j_histogram_key
, j_boundary
)
161 void RecordCountHistogram(JNIEnv
* env
,
163 jstring j_histogram_name
,
164 jint j_histogram_key
,
166 int sample
= static_cast<int>(j_sample
);
169 .CountHistogram(env
, j_histogram_name
, j_histogram_key
)
173 void RecordCustomTimesHistogramMilliseconds(JNIEnv
* env
,
175 jstring j_histogram_name
,
176 jint j_histogram_key
,
180 jint j_num_buckets
) {
182 .CustomTimesHistogram(env
, j_histogram_name
, j_histogram_key
, j_min
,
183 j_max
, j_num_buckets
)
184 ->AddTime(TimeDelta::FromMilliseconds(static_cast<int64
>(j_duration
)));
187 void Initialize(JNIEnv
* env
, jclass
) {
188 StatisticsRecorder::Initialize();
191 // This backs a Java test util for testing histograms -
192 // MetricsUtils.HistogramDelta. It should live in a test-specific file, but we
193 // currently can't have test-specific native code packaged in test-specific Java
194 // targets - see http://crbug.com/415945.
195 jint
GetHistogramValueCountForTesting(JNIEnv
* env
,
197 jstring histogram_name
,
199 HistogramBase
* histogram
= StatisticsRecorder::FindHistogram(
200 android::ConvertJavaStringToUTF8(env
, histogram_name
));
201 if (histogram
== nullptr) {
202 // No samples have been recorded for this histogram (yet?).
206 scoped_ptr
<HistogramSamples
> samples
= histogram
->SnapshotSamples();
207 return samples
->GetCount(static_cast<int>(sample
));
210 bool RegisterRecordHistogram(JNIEnv
* env
) {
211 return RegisterNativesImpl(env
);
214 } // namespace android