Fix emulator build error
[platform/framework/web/chromium-efl.git] / base / android / native_uma_recorder.cc
1 // Copyright 2019 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.
4
5 #include "base/android/callback_android.h"
6 #include "base/android/jni_android.h"
7 #include "base/android/jni_array.h"
8 #include "base/android/jni_string.h"
9 #include "base/base_jni/NativeUmaRecorder_jni.h"
10 #include "base/format_macros.h"
11 #include "base/metrics/histogram.h"
12 #include "base/metrics/histogram_base.h"
13 #include "base/metrics/sparse_histogram.h"
14 #include "base/metrics/statistics_recorder.h"
15 #include "base/metrics/user_metrics.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/time/time.h"
18
19 namespace base {
20 namespace android {
21
22 namespace {
23
24 using HistogramsSnapshot =
25     std::map<std::string, std::unique_ptr<HistogramSamples>>;
26
27 std::string HistogramConstructionParamsToString(HistogramBase* histogram) {
28   std::string params_str = histogram->histogram_name();
29   switch (histogram->GetHistogramType()) {
30     case HISTOGRAM:
31     case LINEAR_HISTOGRAM:
32     case BOOLEAN_HISTOGRAM:
33     case CUSTOM_HISTOGRAM: {
34       Histogram* hist = static_cast<Histogram*>(histogram);
35       params_str += StringPrintf("/%d/%d/%" PRIuS, hist->declared_min(),
36                                  hist->declared_max(), hist->bucket_count());
37       break;
38     }
39     case SPARSE_HISTOGRAM:
40     case DUMMY_HISTOGRAM:
41       break;
42   }
43   return params_str;
44 }
45
46 // Convert a jlong |histogram_hint| from Java to a HistogramBase* via a cast.
47 // The Java side caches these in a map (see NativeUmaRecorder.java), which is
48 // safe to do since C++ Histogram objects are never freed.
49 static HistogramBase* HistogramFromHint(jlong j_histogram_hint) {
50   return reinterpret_cast<HistogramBase*>(j_histogram_hint);
51 }
52
53 void CheckHistogramArgs(JNIEnv* env,
54                         jstring j_histogram_name,
55                         int32_t expected_min,
56                         int32_t expected_max,
57                         size_t expected_bucket_count,
58                         HistogramBase* histogram) {
59   std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
60   bool valid_arguments = Histogram::InspectConstructionArguments(
61       histogram_name, &expected_min, &expected_max, &expected_bucket_count);
62   DCHECK(valid_arguments);
63   DCHECK(histogram->HasConstructionArguments(expected_min, expected_max,
64                                              expected_bucket_count))
65       << histogram_name << "/" << expected_min << "/" << expected_max << "/"
66       << expected_bucket_count << " vs. "
67       << HistogramConstructionParamsToString(histogram);
68 }
69
70 HistogramBase* BooleanHistogram(JNIEnv* env,
71                                 jstring j_histogram_name,
72                                 jlong j_histogram_hint) {
73   DCHECK(j_histogram_name);
74   HistogramBase* histogram = HistogramFromHint(j_histogram_hint);
75   if (histogram)
76     return histogram;
77
78   std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
79   histogram = BooleanHistogram::FactoryGet(
80       histogram_name, HistogramBase::kUmaTargetedHistogramFlag);
81   return histogram;
82 }
83
84 HistogramBase* ExponentialHistogram(JNIEnv* env,
85                                     jstring j_histogram_name,
86                                     jlong j_histogram_hint,
87                                     jint j_min,
88                                     jint j_max,
89                                     jint j_num_buckets) {
90   DCHECK(j_histogram_name);
91   int32_t min = static_cast<int32_t>(j_min);
92   int32_t max = static_cast<int32_t>(j_max);
93   size_t num_buckets = static_cast<size_t>(j_num_buckets);
94   HistogramBase* histogram = HistogramFromHint(j_histogram_hint);
95   if (histogram) {
96     CheckHistogramArgs(env, j_histogram_name, min, max, num_buckets, histogram);
97     return histogram;
98   }
99
100   DCHECK_GE(min, 1) << "The min expected sample must be >= 1";
101
102   std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
103   histogram = Histogram::FactoryGet(histogram_name, min, max, num_buckets,
104                                     HistogramBase::kUmaTargetedHistogramFlag);
105   return histogram;
106 }
107
108 HistogramBase* LinearHistogram(JNIEnv* env,
109                                jstring j_histogram_name,
110                                jlong j_histogram_hint,
111                                jint j_min,
112                                jint j_max,
113                                jint j_num_buckets) {
114   DCHECK(j_histogram_name);
115   int32_t min = static_cast<int32_t>(j_min);
116   int32_t max = static_cast<int32_t>(j_max);
117   size_t num_buckets = static_cast<size_t>(j_num_buckets);
118   HistogramBase* histogram = HistogramFromHint(j_histogram_hint);
119   if (histogram) {
120     CheckHistogramArgs(env, j_histogram_name, min, max, num_buckets, histogram);
121     return histogram;
122   }
123
124   std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
125   histogram =
126       LinearHistogram::FactoryGet(histogram_name, min, max, num_buckets,
127                                   HistogramBase::kUmaTargetedHistogramFlag);
128   return histogram;
129 }
130
131 HistogramBase* SparseHistogram(JNIEnv* env,
132                                jstring j_histogram_name,
133                                jlong j_histogram_hint) {
134   DCHECK(j_histogram_name);
135   HistogramBase* histogram = HistogramFromHint(j_histogram_hint);
136   if (histogram)
137     return histogram;
138
139   std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
140   histogram = SparseHistogram::FactoryGet(
141       histogram_name, HistogramBase::kUmaTargetedHistogramFlag);
142   return histogram;
143 }
144
145 struct ActionCallbackWrapper {
146   base::ActionCallback action_callback;
147 };
148
149 static void OnActionRecorded(const JavaRef<jobject>& callback,
150                              const std::string& action,
151                              TimeTicks action_time) {
152   RunStringCallbackAndroid(callback, action);
153 }
154
155 }  // namespace
156
157 jlong JNI_NativeUmaRecorder_RecordBooleanHistogram(
158     JNIEnv* env,
159     const JavaParamRef<jstring>& j_histogram_name,
160     jlong j_histogram_hint,
161     jboolean j_sample) {
162   bool sample = static_cast<bool>(j_sample);
163   HistogramBase* histogram =
164       BooleanHistogram(env, j_histogram_name, j_histogram_hint);
165   histogram->AddBoolean(sample);
166   return reinterpret_cast<jlong>(histogram);
167 }
168
169 jlong JNI_NativeUmaRecorder_RecordExponentialHistogram(
170     JNIEnv* env,
171     const JavaParamRef<jstring>& j_histogram_name,
172     jlong j_histogram_hint,
173     jint j_sample,
174     jint j_min,
175     jint j_max,
176     jint j_num_buckets) {
177   int sample = static_cast<int>(j_sample);
178   HistogramBase* histogram = ExponentialHistogram(
179       env, j_histogram_name, j_histogram_hint, j_min, j_max, j_num_buckets);
180   histogram->Add(sample);
181   return reinterpret_cast<jlong>(histogram);
182 }
183
184 jlong JNI_NativeUmaRecorder_RecordLinearHistogram(
185     JNIEnv* env,
186     const JavaParamRef<jstring>& j_histogram_name,
187     jlong j_histogram_hint,
188     jint j_sample,
189     jint j_min,
190     jint j_max,
191     jint j_num_buckets) {
192   int sample = static_cast<int>(j_sample);
193   HistogramBase* histogram = LinearHistogram(
194       env, j_histogram_name, j_histogram_hint, j_min, j_max, j_num_buckets);
195   histogram->Add(sample);
196   return reinterpret_cast<jlong>(histogram);
197 }
198
199 jlong JNI_NativeUmaRecorder_RecordSparseHistogram(
200     JNIEnv* env,
201     const JavaParamRef<jstring>& j_histogram_name,
202     jlong j_histogram_hint,
203     jint j_sample) {
204   int sample = static_cast<int>(j_sample);
205   HistogramBase* histogram =
206       SparseHistogram(env, j_histogram_name, j_histogram_hint);
207   histogram->Add(sample);
208   return reinterpret_cast<jlong>(histogram);
209 }
210
211 void JNI_NativeUmaRecorder_RecordUserAction(
212     JNIEnv* env,
213     const JavaParamRef<jstring>& j_user_action_name,
214     jlong j_millis_since_event) {
215   // Time values coming from Java need to be synchronized with TimeTick clock.
216   RecordComputedActionSince(ConvertJavaStringToUTF8(env, j_user_action_name),
217                             Milliseconds(j_millis_since_event));
218 }
219
220 // This backs a Java test util for testing histograms -
221 // MetricsUtils.HistogramDelta. It should live in a test-specific file, but we
222 // currently can't have test-specific native code packaged in test-specific Java
223 // targets - see http://crbug.com/415945.
224 jint JNI_NativeUmaRecorder_GetHistogramValueCountForTesting(
225     JNIEnv* env,
226     const JavaParamRef<jstring>& histogram_name,
227     jint sample,
228     jlong snapshot_ptr) {
229   std::string name = android::ConvertJavaStringToUTF8(env, histogram_name);
230   HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
231   if (histogram == nullptr) {
232     // No samples have been recorded for this histogram (yet?).
233     return 0;
234   }
235
236   int actual_count = histogram->SnapshotSamples()->GetCount(sample);
237   if (snapshot_ptr) {
238     auto* snapshot = reinterpret_cast<HistogramsSnapshot*>(snapshot_ptr);
239     auto snapshot_data = snapshot->find(name);
240     if (snapshot_data != snapshot->end())
241       actual_count -= snapshot_data->second->GetCount(sample);
242   }
243
244   return actual_count;
245 }
246
247 jint JNI_NativeUmaRecorder_GetHistogramTotalCountForTesting(
248     JNIEnv* env,
249     const JavaParamRef<jstring>& histogram_name,
250     jlong snapshot_ptr) {
251   std::string name = android::ConvertJavaStringToUTF8(env, histogram_name);
252   HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
253   if (histogram == nullptr) {
254     // No samples have been recorded for this histogram.
255     return 0;
256   }
257
258   int actual_count = histogram->SnapshotSamples()->TotalCount();
259   if (snapshot_ptr) {
260     auto* snapshot = reinterpret_cast<HistogramsSnapshot*>(snapshot_ptr);
261     auto snapshot_data = snapshot->find(name);
262     if (snapshot_data != snapshot->end())
263       actual_count -= snapshot_data->second->TotalCount();
264   }
265   return actual_count;
266 }
267
268 // Returns an array with 3 entries for each bucket, representing (min, max,
269 // count).
270 ScopedJavaLocalRef<jlongArray>
271 JNI_NativeUmaRecorder_GetHistogramSamplesForTesting(
272     JNIEnv* env,
273     const JavaParamRef<jstring>& histogram_name) {
274   std::string name = android::ConvertJavaStringToUTF8(env, histogram_name);
275   HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
276   std::vector<int64_t> buckets;
277
278   if (histogram == nullptr) {
279     // No samples have been recorded for this histogram.
280     return base::android::ToJavaLongArray(env, buckets);
281   }
282
283   std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
284   for (auto sampleCountIterator = samples->Iterator();
285        !sampleCountIterator->Done(); sampleCountIterator->Next()) {
286     HistogramBase::Sample min;
287     int64_t max;
288     HistogramBase::Count count;
289     sampleCountIterator->Get(&min, &max, &count);
290     buckets.push_back(min);
291     buckets.push_back(max);
292     buckets.push_back(count);
293   }
294
295   return base::android::ToJavaLongArray(env, buckets);
296 }
297
298 jlong JNI_NativeUmaRecorder_CreateHistogramSnapshotForTesting(JNIEnv* env) {
299   HistogramsSnapshot* snapshot = new HistogramsSnapshot();
300   for (const auto* const histogram : StatisticsRecorder::GetHistograms()) {
301     (*snapshot)[histogram->histogram_name()] = histogram->SnapshotSamples();
302   }
303   return reinterpret_cast<intptr_t>(snapshot);
304 }
305
306 void JNI_NativeUmaRecorder_DestroyHistogramSnapshotForTesting(
307     JNIEnv* env,
308     jlong snapshot_ptr) {
309   delete reinterpret_cast<HistogramsSnapshot*>(snapshot_ptr);
310 }
311
312 static jlong JNI_NativeUmaRecorder_AddActionCallbackForTesting(
313     JNIEnv* env,
314     const JavaParamRef<jobject>& callback) {
315   // Create a wrapper for the ActionCallback, so it can life on the heap until
316   // RemoveActionCallbackForTesting() is called.
317   auto* wrapper = new ActionCallbackWrapper{base::BindRepeating(
318       &OnActionRecorded, ScopedJavaGlobalRef<jobject>(env, callback))};
319   base::AddActionCallback(wrapper->action_callback);
320   return reinterpret_cast<intptr_t>(wrapper);
321 }
322
323 static void JNI_NativeUmaRecorder_RemoveActionCallbackForTesting(
324     JNIEnv* env,
325     jlong callback_id) {
326   DCHECK(callback_id);
327   auto* wrapper = reinterpret_cast<ActionCallbackWrapper*>(callback_id);
328   base::RemoveActionCallback(wrapper->action_callback);
329   delete wrapper;
330 }
331
332 }  // namespace android
333 }  // namespace base