| Index: base/android/record_histogram.cc
 | 
| diff --git a/base/android/record_histogram.cc b/base/android/record_histogram.cc
 | 
| index 9a72460fe550b42a584c95d2b30bcda133a71e4b..9549adc274a4fd53e519f1c4c8c1bfa4a09408eb 100644
 | 
| --- a/base/android/record_histogram.cc
 | 
| +++ b/base/android/record_histogram.cc
 | 
| @@ -2,39 +2,108 @@
 | 
|  // Use of this source code is governed by a BSD-style license that can be
 | 
|  // found in the LICENSE file.
 | 
|  
 | 
| +#include "base/android/record_histogram.h"
 | 
| +
 | 
| +#include <map>
 | 
| +
 | 
|  #include "base/android/jni_android.h"
 | 
|  #include "base/android/jni_string.h"
 | 
| -#include "base/android/record_histogram.h"
 | 
| +#include "base/lazy_instance.h"
 | 
|  #include "base/metrics/histogram.h"
 | 
|  #include "base/metrics/statistics_recorder.h"
 | 
| +#include "base/synchronization/lock.h"
 | 
|  #include "jni/RecordHistogram_jni.h"
 | 
|  
 | 
|  namespace base {
 | 
|  namespace android {
 | 
| +namespace {
 | 
| +
 | 
| +// Simple thread-safe wrapper for caching histograms. This avoids
 | 
| +// relatively expensive JNI string translation for each recording.
 | 
| +class HistogramCache {
 | 
| + public:
 | 
| +  HistogramCache() {}
 | 
| +
 | 
| +  HistogramBase* BooleanHistogram(JNIEnv* env,
 | 
| +                                  jstring j_histogram_name,
 | 
| +                                  jint j_histogram_key) {
 | 
| +    DCHECK(j_histogram_name);
 | 
| +    DCHECK(j_histogram_key);
 | 
| +    HistogramBase* histogram = FindLocked(j_histogram_key);
 | 
| +    if (histogram)
 | 
| +      return histogram;
 | 
| +
 | 
| +    std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
 | 
| +    histogram = BooleanHistogram::FactoryGet(
 | 
| +        histogram_name, HistogramBase::kUmaTargetedHistogramFlag);
 | 
| +    return InsertLocked(j_histogram_key, histogram);
 | 
| +  }
 | 
| +
 | 
| +  HistogramBase* EnumeratedHistogram(JNIEnv* env,
 | 
| +                                     jstring j_histogram_name,
 | 
| +                                     jint j_histogram_key,
 | 
| +                                     jint j_boundary) {
 | 
| +    DCHECK(j_histogram_name);
 | 
| +    DCHECK(j_histogram_key);
 | 
| +    HistogramBase* histogram = FindLocked(j_histogram_key);
 | 
| +    if (histogram)
 | 
| +      return histogram;
 | 
| +
 | 
| +    std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
 | 
| +    // Note: This caching bypasses the boundary validation that occurs between
 | 
| +    // repeated lookups by the same name. It is up to the caller to ensure that
 | 
| +    // the provided boundary remains consistent.
 | 
| +    int boundary = static_cast<int>(j_boundary);
 | 
| +    histogram =
 | 
| +        LinearHistogram::FactoryGet(histogram_name, 1, boundary, boundary + 1,
 | 
| +                                    HistogramBase::kUmaTargetedHistogramFlag);
 | 
| +    return InsertLocked(j_histogram_key, histogram);
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  HistogramBase* FindLocked(jint j_histogram_key) {
 | 
| +    base::AutoLock locked(lock_);
 | 
| +    auto histogram_it = histograms_.find(j_histogram_key);
 | 
| +    return histogram_it != histograms_.end() ? histogram_it->second : nullptr;
 | 
| +  }
 | 
| +
 | 
| +  HistogramBase* InsertLocked(jint j_histogram_key, HistogramBase* histogram) {
 | 
| +    base::AutoLock locked(lock_);
 | 
| +    histograms_.insert(std::make_pair(j_histogram_key, histogram));
 | 
| +    return histogram;
 | 
| +  }
 | 
| +
 | 
| +  base::Lock lock_;
 | 
| +  std::map<jint, HistogramBase*> histograms_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(HistogramCache);
 | 
| +};
 | 
| +
 | 
| +base::LazyInstance<HistogramCache>::Leaky g_histograms;
 | 
| +
 | 
| +}  // namespace
 | 
|  
 | 
|  void RecordBooleanHistogram(JNIEnv* env,
 | 
|                              jclass clazz,
 | 
|                              jstring j_histogram_name,
 | 
| +                            jint j_histogram_key,
 | 
|                              jboolean j_sample) {
 | 
| -  std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
 | 
|    bool sample = static_cast<bool>(j_sample);
 | 
| -
 | 
| -  BooleanHistogram::FactoryGet(histogram_name,
 | 
| -                               HistogramBase::kUmaTargetedHistogramFlag)
 | 
| +  g_histograms.Get()
 | 
| +      .BooleanHistogram(env, j_histogram_name, j_histogram_key)
 | 
|        ->AddBoolean(sample);
 | 
|  }
 | 
|  
 | 
|  void RecordEnumeratedHistogram(JNIEnv* env,
 | 
|                                 jclass clazz,
 | 
|                                 jstring j_histogram_name,
 | 
| +                               jint j_histogram_key,
 | 
|                                 jint j_sample,
 | 
|                                 jint j_boundary) {
 | 
| -  std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
 | 
|    int sample = static_cast<int>(j_sample);
 | 
| -  int boundary = static_cast<int>(j_boundary);
 | 
|  
 | 
| -  LinearHistogram::FactoryGet(histogram_name, 1, boundary, boundary + 1,
 | 
| -                              HistogramBase::kUmaTargetedHistogramFlag)
 | 
| +  g_histograms.Get()
 | 
| +      .EnumeratedHistogram(env, j_histogram_name, j_histogram_key, j_boundary)
 | 
|        ->Add(sample);
 | 
|  }
 | 
|  
 | 
| 
 |