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
* SparseHistogram(JNIEnv
* env
,
89 jstring j_histogram_name
,
90 jint j_histogram_key
) {
91 DCHECK(j_histogram_name
);
92 DCHECK(j_histogram_key
);
93 HistogramBase
* histogram
= FindLocked(j_histogram_key
);
97 std::string histogram_name
= ConvertJavaStringToUTF8(env
, j_histogram_name
);
98 histogram
= SparseHistogram::FactoryGet(
99 histogram_name
, HistogramBase::kUmaTargetedHistogramFlag
);
100 return InsertLocked(j_histogram_key
, histogram
);
103 HistogramBase
* CustomTimesHistogram(JNIEnv
* env
,
104 jstring j_histogram_name
,
105 jint j_histogram_key
,
108 jint j_bucket_count
) {
109 DCHECK(j_histogram_name
);
110 DCHECK(j_histogram_key
);
111 HistogramBase
* histogram
= FindLocked(j_histogram_key
);
112 int64 min
= static_cast<int64
>(j_min
);
113 int64 max
= static_cast<int64
>(j_max
);
114 int bucket_count
= static_cast<int>(j_bucket_count
);
116 DCHECK(histogram
->HasConstructionArguments(min
, max
, bucket_count
));
120 std::string histogram_name
= ConvertJavaStringToUTF8(env
, j_histogram_name
);
121 // This intentionally uses FactoryGet and not FactoryTimeGet. FactoryTimeGet
122 // is just a convenience for constructing the underlying Histogram with
123 // TimeDelta arguments.
124 histogram
= Histogram::FactoryGet(histogram_name
, min
, max
, bucket_count
,
125 HistogramBase::kUmaTargetedHistogramFlag
);
126 return InsertLocked(j_histogram_key
, histogram
);
130 HistogramBase
* FindLocked(jint j_histogram_key
) {
131 base::AutoLock
locked(lock_
);
132 auto histogram_it
= histograms_
.find(j_histogram_key
);
133 return histogram_it
!= histograms_
.end() ? histogram_it
->second
: nullptr;
136 HistogramBase
* InsertLocked(jint j_histogram_key
, HistogramBase
* histogram
) {
137 base::AutoLock
locked(lock_
);
138 histograms_
.insert(std::make_pair(j_histogram_key
, histogram
));
143 std::map
<jint
, HistogramBase
*> histograms_
;
145 DISALLOW_COPY_AND_ASSIGN(HistogramCache
);
148 base::LazyInstance
<HistogramCache
>::Leaky g_histograms
;
152 void RecordBooleanHistogram(JNIEnv
* env
,
154 jstring j_histogram_name
,
155 jint j_histogram_key
,
157 bool sample
= static_cast<bool>(j_sample
);
159 .BooleanHistogram(env
, j_histogram_name
, j_histogram_key
)
160 ->AddBoolean(sample
);
163 void RecordEnumeratedHistogram(JNIEnv
* env
,
165 jstring j_histogram_name
,
166 jint j_histogram_key
,
169 int sample
= static_cast<int>(j_sample
);
172 .EnumeratedHistogram(env
, j_histogram_name
, j_histogram_key
, j_boundary
)
176 void RecordCustomCountHistogram(JNIEnv
* env
,
178 jstring j_histogram_name
,
179 jint j_histogram_key
,
183 jint j_num_buckets
) {
184 int sample
= static_cast<int>(j_sample
);
187 .CustomCountHistogram(env
, j_histogram_name
, j_histogram_key
, j_min
,
188 j_max
, j_num_buckets
)
192 void RecordSparseHistogram(JNIEnv
* env
,
194 jstring j_histogram_name
,
195 jint j_histogram_key
,
197 int sample
= static_cast<int>(j_sample
);
199 .SparseHistogram(env
, j_histogram_name
, j_histogram_key
)
203 void RecordCustomTimesHistogramMilliseconds(JNIEnv
* env
,
205 jstring j_histogram_name
,
206 jint j_histogram_key
,
210 jint j_num_buckets
) {
212 .CustomTimesHistogram(env
, j_histogram_name
, j_histogram_key
, j_min
,
213 j_max
, j_num_buckets
)
214 ->AddTime(TimeDelta::FromMilliseconds(static_cast<int64
>(j_duration
)));
217 void Initialize(JNIEnv
* env
, jclass
) {
218 StatisticsRecorder::Initialize();
221 // This backs a Java test util for testing histograms -
222 // MetricsUtils.HistogramDelta. It should live in a test-specific file, but we
223 // currently can't have test-specific native code packaged in test-specific Java
224 // targets - see http://crbug.com/415945.
225 jint
GetHistogramValueCountForTesting(JNIEnv
* env
,
227 jstring histogram_name
,
229 HistogramBase
* histogram
= StatisticsRecorder::FindHistogram(
230 android::ConvertJavaStringToUTF8(env
, histogram_name
));
231 if (histogram
== nullptr) {
232 // No samples have been recorded for this histogram (yet?).
236 scoped_ptr
<HistogramSamples
> samples
= histogram
->SnapshotSamples();
237 return samples
->GetCount(static_cast<int>(sample
));
240 bool RegisterRecordHistogram(JNIEnv
* env
) {
241 return RegisterNativesImpl(env
);
244 } // namespace android