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/sparse_histogram.h"
14 #include "base/metrics/statistics_recorder.h"
15 #include "base/synchronization/lock.h"
16 #include "base/time/time.h"
17 #include "jni/RecordHistogram_jni.h"
23 // Simple thread-safe wrapper for caching histograms. This avoids
24 // relatively expensive JNI string translation for each recording.
25 class HistogramCache
{
29 HistogramBase
* BooleanHistogram(JNIEnv
* env
,
30 jstring j_histogram_name
,
31 jint j_histogram_key
) {
32 DCHECK(j_histogram_name
);
33 DCHECK(j_histogram_key
);
34 HistogramBase
* histogram
= FindLocked(j_histogram_key
);
38 std::string histogram_name
= ConvertJavaStringToUTF8(env
, j_histogram_name
);
39 histogram
= BooleanHistogram::FactoryGet(
40 histogram_name
, HistogramBase::kUmaTargetedHistogramFlag
);
41 return InsertLocked(j_histogram_key
, histogram
);
44 HistogramBase
* EnumeratedHistogram(JNIEnv
* env
,
45 jstring j_histogram_name
,
48 DCHECK(j_histogram_name
);
49 DCHECK(j_histogram_key
);
50 HistogramBase
* histogram
= FindLocked(j_histogram_key
);
51 int boundary
= static_cast<int>(j_boundary
);
53 DCHECK(histogram
->HasConstructionArguments(1, boundary
, boundary
+ 1));
57 std::string histogram_name
= ConvertJavaStringToUTF8(env
, j_histogram_name
);
59 LinearHistogram::FactoryGet(histogram_name
, 1, boundary
, boundary
+ 1,
60 HistogramBase::kUmaTargetedHistogramFlag
);
61 return InsertLocked(j_histogram_key
, histogram
);
64 HistogramBase
* CustomCountHistogram(JNIEnv
* env
,
65 jstring j_histogram_name
,
70 DCHECK(j_histogram_name
);
71 DCHECK(j_histogram_key
);
72 int64 min
= static_cast<int64
>(j_min
);
73 int64 max
= static_cast<int64
>(j_max
);
74 int num_buckets
= static_cast<int>(j_num_buckets
);
75 HistogramBase
* histogram
= FindLocked(j_histogram_key
);
77 DCHECK(histogram
->HasConstructionArguments(min
, max
, num_buckets
));
81 std::string histogram_name
= ConvertJavaStringToUTF8(env
, j_histogram_name
);
83 Histogram::FactoryGet(histogram_name
, min
, max
, num_buckets
,
84 HistogramBase::kUmaTargetedHistogramFlag
);
85 return InsertLocked(j_histogram_key
, histogram
);
88 HistogramBase
* LinearCountHistogram(JNIEnv
* env
,
89 jstring j_histogram_name
,
94 DCHECK(j_histogram_name
);
95 DCHECK(j_histogram_key
);
96 int64 min
= static_cast<int64
>(j_min
);
97 int64 max
= static_cast<int64
>(j_max
);
98 int num_buckets
= static_cast<int>(j_num_buckets
);
99 HistogramBase
* histogram
= FindLocked(j_histogram_key
);
101 DCHECK(histogram
->HasConstructionArguments(min
, max
, num_buckets
));
105 std::string histogram_name
= ConvertJavaStringToUTF8(env
, j_histogram_name
);
107 LinearHistogram::FactoryGet(histogram_name
, min
, max
, num_buckets
,
108 HistogramBase::kUmaTargetedHistogramFlag
);
109 return InsertLocked(j_histogram_key
, histogram
);
112 HistogramBase
* SparseHistogram(JNIEnv
* env
,
113 jstring j_histogram_name
,
114 jint j_histogram_key
) {
115 DCHECK(j_histogram_name
);
116 DCHECK(j_histogram_key
);
117 HistogramBase
* histogram
= FindLocked(j_histogram_key
);
121 std::string histogram_name
= ConvertJavaStringToUTF8(env
, j_histogram_name
);
122 histogram
= SparseHistogram::FactoryGet(
123 histogram_name
, HistogramBase::kUmaTargetedHistogramFlag
);
124 return InsertLocked(j_histogram_key
, histogram
);
127 HistogramBase
* CustomTimesHistogram(JNIEnv
* env
,
128 jstring j_histogram_name
,
129 jint j_histogram_key
,
132 jint j_bucket_count
) {
133 DCHECK(j_histogram_name
);
134 DCHECK(j_histogram_key
);
135 HistogramBase
* histogram
= FindLocked(j_histogram_key
);
136 int64 min
= static_cast<int64
>(j_min
);
137 int64 max
= static_cast<int64
>(j_max
);
138 int bucket_count
= static_cast<int>(j_bucket_count
);
140 DCHECK(histogram
->HasConstructionArguments(min
, max
, bucket_count
));
144 std::string histogram_name
= ConvertJavaStringToUTF8(env
, j_histogram_name
);
145 // This intentionally uses FactoryGet and not FactoryTimeGet. FactoryTimeGet
146 // is just a convenience for constructing the underlying Histogram with
147 // TimeDelta arguments.
148 histogram
= Histogram::FactoryGet(histogram_name
, min
, max
, bucket_count
,
149 HistogramBase::kUmaTargetedHistogramFlag
);
150 return InsertLocked(j_histogram_key
, histogram
);
154 HistogramBase
* FindLocked(jint j_histogram_key
) {
155 base::AutoLock
locked(lock_
);
156 auto histogram_it
= histograms_
.find(j_histogram_key
);
157 return histogram_it
!= histograms_
.end() ? histogram_it
->second
: nullptr;
160 HistogramBase
* InsertLocked(jint j_histogram_key
, HistogramBase
* histogram
) {
161 base::AutoLock
locked(lock_
);
162 histograms_
.insert(std::make_pair(j_histogram_key
, histogram
));
167 std::map
<jint
, HistogramBase
*> histograms_
;
169 DISALLOW_COPY_AND_ASSIGN(HistogramCache
);
172 base::LazyInstance
<HistogramCache
>::Leaky g_histograms
;
176 void RecordBooleanHistogram(JNIEnv
* env
,
177 const JavaParamRef
<jclass
>& clazz
,
178 const JavaParamRef
<jstring
>& j_histogram_name
,
179 jint j_histogram_key
,
181 bool sample
= static_cast<bool>(j_sample
);
183 .BooleanHistogram(env
, j_histogram_name
, j_histogram_key
)
184 ->AddBoolean(sample
);
187 void RecordEnumeratedHistogram(JNIEnv
* env
,
188 const JavaParamRef
<jclass
>& clazz
,
189 const JavaParamRef
<jstring
>& j_histogram_name
,
190 jint j_histogram_key
,
193 int sample
= static_cast<int>(j_sample
);
196 .EnumeratedHistogram(env
, j_histogram_name
, j_histogram_key
, j_boundary
)
200 void RecordCustomCountHistogram(JNIEnv
* env
,
201 const JavaParamRef
<jclass
>& clazz
,
202 const JavaParamRef
<jstring
>& j_histogram_name
,
203 jint j_histogram_key
,
207 jint j_num_buckets
) {
208 int sample
= static_cast<int>(j_sample
);
211 .CustomCountHistogram(env
, j_histogram_name
, j_histogram_key
, j_min
,
212 j_max
, j_num_buckets
)
216 void RecordLinearCountHistogram(JNIEnv
* env
,
217 const JavaParamRef
<jclass
>& clazz
,
218 const JavaParamRef
<jstring
>& j_histogram_name
,
219 jint j_histogram_key
,
223 jint j_num_buckets
) {
224 int sample
= static_cast<int>(j_sample
);
227 .LinearCountHistogram(env
, j_histogram_name
, j_histogram_key
, j_min
,
228 j_max
, j_num_buckets
)
232 void RecordSparseHistogram(JNIEnv
* env
,
233 const JavaParamRef
<jclass
>& clazz
,
234 const JavaParamRef
<jstring
>& j_histogram_name
,
235 jint j_histogram_key
,
237 int sample
= static_cast<int>(j_sample
);
239 .SparseHistogram(env
, j_histogram_name
, j_histogram_key
)
243 void RecordCustomTimesHistogramMilliseconds(
245 const JavaParamRef
<jclass
>& clazz
,
246 const JavaParamRef
<jstring
>& j_histogram_name
,
247 jint j_histogram_key
,
251 jint j_num_buckets
) {
253 .CustomTimesHistogram(env
, j_histogram_name
, j_histogram_key
, j_min
,
254 j_max
, j_num_buckets
)
255 ->AddTime(TimeDelta::FromMilliseconds(static_cast<int64
>(j_duration
)));
258 void Initialize(JNIEnv
* env
, const JavaParamRef
<jclass
>&) {
259 StatisticsRecorder::Initialize();
262 // This backs a Java test util for testing histograms -
263 // MetricsUtils.HistogramDelta. It should live in a test-specific file, but we
264 // currently can't have test-specific native code packaged in test-specific Java
265 // targets - see http://crbug.com/415945.
266 jint
GetHistogramValueCountForTesting(
268 const JavaParamRef
<jclass
>& clazz
,
269 const JavaParamRef
<jstring
>& histogram_name
,
271 HistogramBase
* histogram
= StatisticsRecorder::FindHistogram(
272 android::ConvertJavaStringToUTF8(env
, histogram_name
));
273 if (histogram
== nullptr) {
274 // No samples have been recorded for this histogram (yet?).
278 scoped_ptr
<HistogramSamples
> samples
= histogram
->SnapshotSamples();
279 return samples
->GetCount(static_cast<int>(sample
));
282 bool RegisterRecordHistogram(JNIEnv
* env
) {
283 return RegisterNativesImpl(env
);
286 } // namespace android